From 26acee2902c519075bd3d5f98d2a1a498ee3d1a9 Mon Sep 17 00:00:00 2001 From: Peter Krull Date: Tue, 13 Feb 2024 14:50:26 +0100 Subject: [PATCH 0001/1217] Add initial implementation of `MultiSignal` sync primitive --- embassy-sync/src/lib.rs | 1 + embassy-sync/src/multi_signal.rs | 285 +++++++++++++++++++++++++++++++ 2 files changed, 286 insertions(+) create mode 100644 embassy-sync/src/multi_signal.rs diff --git a/embassy-sync/src/lib.rs b/embassy-sync/src/lib.rs index d88c76db5..f02985564 100644 --- a/embassy-sync/src/lib.rs +++ b/embassy-sync/src/lib.rs @@ -12,6 +12,7 @@ mod ring_buffer; pub mod blocking_mutex; pub mod channel; +pub mod multi_signal; pub mod mutex; pub mod pipe; pub mod priority_channel; diff --git a/embassy-sync/src/multi_signal.rs b/embassy-sync/src/multi_signal.rs new file mode 100644 index 000000000..db858f269 --- /dev/null +++ b/embassy-sync/src/multi_signal.rs @@ -0,0 +1,285 @@ +//! A synchronization primitive for passing the latest value to **multiple** tasks. +use core::{ + cell::RefCell, + marker::PhantomData, + ops::{Deref, DerefMut}, + pin::Pin, + task::{Context, Poll}, +}; + +use futures_util::Future; + +use crate::{ + blocking_mutex::{raw::RawMutex, Mutex}, + waitqueue::MultiWakerRegistration, +}; + +/// A `MultiSignal` is a single-slot signaling primitive, which can awake `N` separate [`Receiver`]s. +/// +/// Similar to a [`Signal`](crate::signal::Signal), except `MultiSignal` allows for multiple tasks to +/// `.await` the latest value, and all receive it. +/// +/// This is similar to a [`PubSubChannel`](crate::pubsub::PubSubChannel) with a buffer size of 1, except +/// "sending" to it (calling [`MultiSignal::write`]) will immediately overwrite the previous value instead +/// of waiting for the receivers to pop the previous value. +/// +/// `MultiSignal` is useful when a single task is responsible for updating a value or "state", which multiple other +/// tasks are interested in getting notified about changes to the latest value of. It is therefore fine for +/// [`Receiver`]s to "lose" stale values. +/// +/// Anyone with a reference to the MultiSignal can update or peek the value. MultiSignals are generally declared +/// as `static`s and then borrowed as required to either [`MultiSignal::peek`] the value or obtain a [`Receiver`] +/// with [`MultiSignal::receiver`] which has async methods. +/// ``` +/// +/// use futures_executor::block_on; +/// use embassy_sync::multi_signal::MultiSignal; +/// use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; +/// +/// let f = async { +/// +/// static SOME_SIGNAL: MultiSignal = MultiSignal::new(0); +/// +/// // Obtain Receivers +/// let mut rcv0 = SOME_SIGNAL.receiver().unwrap(); +/// let mut rcv1 = SOME_SIGNAL.receiver().unwrap(); +/// assert!(SOME_SIGNAL.receiver().is_err()); +/// +/// SOME_SIGNAL.write(10); +/// +/// // Receive the new value +/// assert_eq!(rcv0.changed().await, 10); +/// assert_eq!(rcv1.try_changed(), Some(10)); +/// +/// // No update +/// assert_eq!(rcv0.try_changed(), None); +/// assert_eq!(rcv1.try_changed(), None); +/// +/// SOME_SIGNAL.write(20); +/// +/// // Receive new value with predicate +/// assert_eq!(rcv0.changed_and(|x|x>&10).await, 20); +/// assert_eq!(rcv1.try_changed_and(|x|x>&30), None); +/// +/// // Anyone can peek the current value +/// assert_eq!(rcv0.peek(), 20); +/// assert_eq!(rcv1.peek(), 20); +/// assert_eq!(SOME_SIGNAL.peek(), 20); +/// assert_eq!(SOME_SIGNAL.peek_and(|x|x>&30), None); +/// }; +/// block_on(f); +/// ``` +pub struct MultiSignal<'a, M: RawMutex, T: Clone, const N: usize> { + mutex: Mutex>>, + _phantom: PhantomData<&'a ()>, +} + +struct MultiSignalState { + data: T, + current_id: u64, + wakers: MultiWakerRegistration, + receiver_count: usize, +} + +#[derive(Debug)] +/// An error that can occur when a `MultiSignal` returns a `Result`. +pub enum Error { + /// The maximum number of [`Receiver`](crate::multi_signal::Receiver) has been reached. + MaximumReceiversReached, +} + +impl<'a, M: RawMutex, T: Clone, const N: usize> MultiSignal<'a, M, T, N> { + /// Create a new `MultiSignal` initialized with the given value. + pub const fn new(init: T) -> Self { + Self { + mutex: Mutex::new(RefCell::new(MultiSignalState { + data: init, + current_id: 1, + wakers: MultiWakerRegistration::new(), + receiver_count: 0, + })), + _phantom: PhantomData, + } + } + + /// Get a [`Receiver`] for the `MultiSignal`. + pub fn receiver(&'a self) -> Result, Error> { + self.mutex.lock(|state| { + let mut s = state.borrow_mut(); + if s.receiver_count < N { + s.receiver_count += 1; + Ok(Receiver(Rcv::new(self))) + } else { + Err(Error::MaximumReceiversReached) + } + }) + } + + /// Update the value of the `MultiSignal`. + pub fn write(&self, data: T) { + self.mutex.lock(|state| { + let mut s = state.borrow_mut(); + s.data = data; + s.current_id += 1; + s.wakers.wake(); + }) + } + + /// Peek the current value of the `MultiSignal`. + pub fn peek(&self) -> T { + self.mutex.lock(|state| state.borrow().data.clone()) + } + + /// Peek the current value of the `MultiSignal` and check if it satisfies the predicate `f`. + pub fn peek_and(&self, f: fn(&T) -> bool) -> Option { + self.mutex.lock(|state| { + let s = state.borrow(); + if f(&s.data) { + Some(s.data.clone()) + } else { + None + } + }) + } + + /// Get the ID of the current value of the `MultiSignal`. + /// This method is mostly for testing purposes. + #[allow(dead_code)] + fn get_id(&self) -> u64 { + self.mutex.lock(|state| state.borrow().current_id) + } + + /// Poll the `MultiSignal` with an optional context. + fn get_with_context(&'a self, waker: &mut Rcv<'a, M, T, N>, cx: Option<&mut Context>) -> Poll { + self.mutex.lock(|state| { + let mut s = state.borrow_mut(); + match (s.current_id > waker.at_id, waker.predicate) { + (true, None) => { + waker.at_id = s.current_id; + Poll::Ready(s.data.clone()) + } + (true, Some(f)) if f(&s.data) => { + waker.at_id = s.current_id; + Poll::Ready(s.data.clone()) + } + _ => { + if let Some(cx) = cx { + s.wakers.register(cx.waker()); + } + Poll::Pending + } + } + }) + } +} + +/// A receiver is able to `.await` a changed `MultiSignal` value. +pub struct Rcv<'a, M: RawMutex, T: Clone, const N: usize> { + multi_sig: &'a MultiSignal<'a, M, T, N>, + predicate: Option bool>, + at_id: u64, +} + +// f: Option bool> +impl<'a, M: RawMutex, T: Clone, const N: usize> Rcv<'a, M, T, N> { + /// Create a new `Receiver` with a reference the given `MultiSignal`. + fn new(multi_sig: &'a MultiSignal<'a, M, T, N>) -> Self { + Self { + multi_sig, + predicate: None, + at_id: 0, + } + } + + /// Wait for a change to the value of the corresponding `MultiSignal`. + pub fn changed<'s>(&'s mut self) -> ReceiverFuture<'s, 'a, M, T, N> { + self.predicate = None; + ReceiverFuture { subscriber: self } + } + + /// Wait for a change to the value of the corresponding `MultiSignal` which matches the predicate `f`. + pub fn changed_and<'s>(&'s mut self, f: fn(&T) -> bool) -> ReceiverFuture<'s, 'a, M, T, N> { + self.predicate = Some(f); + ReceiverFuture { subscriber: self } + } + + /// Try to get a changed value of the corresponding `MultiSignal`. + pub fn try_changed(&mut self) -> Option { + self.multi_sig.mutex.lock(|state| { + let s = state.borrow(); + match s.current_id > self.at_id { + true => { + self.at_id = s.current_id; + Some(s.data.clone()) + } + false => None, + } + }) + } + + /// Try to get a changed value of the corresponding `MultiSignal` which matches the predicate `f`. + pub fn try_changed_and(&mut self, f: fn(&T) -> bool) -> Option { + self.multi_sig.mutex.lock(|state| { + let s = state.borrow(); + match s.current_id > self.at_id && f(&s.data) { + true => { + self.at_id = s.current_id; + Some(s.data.clone()) + } + false => None, + } + }) + } + + /// Peek the current value of the corresponding `MultiSignal`. + pub fn peek(&self) -> T { + self.multi_sig.peek() + } + + /// Peek the current value of the corresponding `MultiSignal` and check if it satisfies the predicate `f`. + pub fn peek_and(&self, f: fn(&T) -> bool) -> Option { + self.multi_sig.peek_and(f) + } + + /// Check if the value of the corresponding `MultiSignal` has changed. + pub fn has_changed(&mut self) -> bool { + self.multi_sig + .mutex + .lock(|state| state.borrow().current_id > self.at_id) + } +} + +/// A `Receiver` is able to `.await` a change to the corresponding [`MultiSignal`] value. +pub struct Receiver<'a, M: RawMutex, T: Clone, const N: usize>(Rcv<'a, M, T, N>); + +impl<'a, M: RawMutex, T: Clone, const N: usize> Deref for Receiver<'a, M, T, N> { + type Target = Rcv<'a, M, T, N>; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl<'a, M: RawMutex, T: Clone, const N: usize> DerefMut for Receiver<'a, M, T, N> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +/// Future for the `Receiver` wait action +#[must_use = "futures do nothing unless you `.await` or poll them"] +pub struct ReceiverFuture<'s, 'a, M: RawMutex, T: Clone, const N: usize> { + subscriber: &'s mut Rcv<'a, M, T, N>, +} + +impl<'s, 'a, M: RawMutex, T: Clone, const N: usize> Future for ReceiverFuture<'s, 'a, M, T, N> { + type Output = T; + + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + self.subscriber + .multi_sig + .get_with_context(&mut self.subscriber, Some(cx)) + } +} + +impl<'s, 'a, M: RawMutex, T: Clone, const N: usize> Unpin for ReceiverFuture<'s, 'a, M, T, N> {} From 410c2d440afa2a500ef1398b5b48e746f77815bd Mon Sep 17 00:00:00 2001 From: Peter Krull Date: Tue, 13 Feb 2024 15:37:07 +0100 Subject: [PATCH 0002/1217] Change import formatting --- embassy-sync/src/multi_signal.rs | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/embassy-sync/src/multi_signal.rs b/embassy-sync/src/multi_signal.rs index db858f269..bff7ad048 100644 --- a/embassy-sync/src/multi_signal.rs +++ b/embassy-sync/src/multi_signal.rs @@ -1,18 +1,15 @@ //! A synchronization primitive for passing the latest value to **multiple** tasks. -use core::{ - cell::RefCell, - marker::PhantomData, - ops::{Deref, DerefMut}, - pin::Pin, - task::{Context, Poll}, -}; +use core::cell::RefCell; +use core::marker::PhantomData; +use core::ops::{Deref, DerefMut}; +use core::pin::Pin; +use core::task::{Context, Poll}; use futures_util::Future; -use crate::{ - blocking_mutex::{raw::RawMutex, Mutex}, - waitqueue::MultiWakerRegistration, -}; +use crate::blocking_mutex::raw::RawMutex; +use crate::blocking_mutex::Mutex; +use crate::waitqueue::MultiWakerRegistration; /// A `MultiSignal` is a single-slot signaling primitive, which can awake `N` separate [`Receiver`]s. /// From 37f1c9ac27b0542fdf404392e9bb265fa8ec41d3 Mon Sep 17 00:00:00 2001 From: Peter Krull Date: Tue, 13 Feb 2024 23:14:16 +0100 Subject: [PATCH 0003/1217] Removed unused lifetime, change most fn -> FnMut --- embassy-sync/src/multi_signal.rs | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/embassy-sync/src/multi_signal.rs b/embassy-sync/src/multi_signal.rs index bff7ad048..5f724c76b 100644 --- a/embassy-sync/src/multi_signal.rs +++ b/embassy-sync/src/multi_signal.rs @@ -1,6 +1,5 @@ //! A synchronization primitive for passing the latest value to **multiple** tasks. use core::cell::RefCell; -use core::marker::PhantomData; use core::ops::{Deref, DerefMut}; use core::pin::Pin; use core::task::{Context, Poll}; @@ -66,9 +65,8 @@ use crate::waitqueue::MultiWakerRegistration; /// }; /// block_on(f); /// ``` -pub struct MultiSignal<'a, M: RawMutex, T: Clone, const N: usize> { +pub struct MultiSignal { mutex: Mutex>>, - _phantom: PhantomData<&'a ()>, } struct MultiSignalState { @@ -85,7 +83,7 @@ pub enum Error { MaximumReceiversReached, } -impl<'a, M: RawMutex, T: Clone, const N: usize> MultiSignal<'a, M, T, N> { +impl<'a, M: RawMutex, T: Clone, const N: usize> MultiSignal { /// Create a new `MultiSignal` initialized with the given value. pub const fn new(init: T) -> Self { Self { @@ -95,7 +93,6 @@ impl<'a, M: RawMutex, T: Clone, const N: usize> MultiSignal<'a, M, T, N> { wakers: MultiWakerRegistration::new(), receiver_count: 0, })), - _phantom: PhantomData, } } @@ -128,7 +125,7 @@ impl<'a, M: RawMutex, T: Clone, const N: usize> MultiSignal<'a, M, T, N> { } /// Peek the current value of the `MultiSignal` and check if it satisfies the predicate `f`. - pub fn peek_and(&self, f: fn(&T) -> bool) -> Option { + pub fn peek_and(&self, mut f: impl FnMut(&T) -> bool) -> Option { self.mutex.lock(|state| { let s = state.borrow(); if f(&s.data) { @@ -147,16 +144,16 @@ impl<'a, M: RawMutex, T: Clone, const N: usize> MultiSignal<'a, M, T, N> { } /// Poll the `MultiSignal` with an optional context. - fn get_with_context(&'a self, waker: &mut Rcv<'a, M, T, N>, cx: Option<&mut Context>) -> Poll { + fn get_with_context(&self, rcv: &mut Rcv<'a, M, T, N>, cx: Option<&mut Context>) -> Poll { self.mutex.lock(|state| { let mut s = state.borrow_mut(); - match (s.current_id > waker.at_id, waker.predicate) { + match (s.current_id > rcv.at_id, rcv.predicate) { (true, None) => { - waker.at_id = s.current_id; + rcv.at_id = s.current_id; Poll::Ready(s.data.clone()) } (true, Some(f)) if f(&s.data) => { - waker.at_id = s.current_id; + rcv.at_id = s.current_id; Poll::Ready(s.data.clone()) } _ => { @@ -172,7 +169,7 @@ impl<'a, M: RawMutex, T: Clone, const N: usize> MultiSignal<'a, M, T, N> { /// A receiver is able to `.await` a changed `MultiSignal` value. pub struct Rcv<'a, M: RawMutex, T: Clone, const N: usize> { - multi_sig: &'a MultiSignal<'a, M, T, N>, + multi_sig: &'a MultiSignal, predicate: Option bool>, at_id: u64, } @@ -180,7 +177,7 @@ pub struct Rcv<'a, M: RawMutex, T: Clone, const N: usize> { // f: Option bool> impl<'a, M: RawMutex, T: Clone, const N: usize> Rcv<'a, M, T, N> { /// Create a new `Receiver` with a reference the given `MultiSignal`. - fn new(multi_sig: &'a MultiSignal<'a, M, T, N>) -> Self { + fn new(multi_sig: &'a MultiSignal) -> Self { Self { multi_sig, predicate: None, @@ -195,6 +192,7 @@ impl<'a, M: RawMutex, T: Clone, const N: usize> Rcv<'a, M, T, N> { } /// Wait for a change to the value of the corresponding `MultiSignal` which matches the predicate `f`. + // TODO: How do we make this work with a FnMut closure? pub fn changed_and<'s>(&'s mut self, f: fn(&T) -> bool) -> ReceiverFuture<'s, 'a, M, T, N> { self.predicate = Some(f); ReceiverFuture { subscriber: self } @@ -215,7 +213,7 @@ impl<'a, M: RawMutex, T: Clone, const N: usize> Rcv<'a, M, T, N> { } /// Try to get a changed value of the corresponding `MultiSignal` which matches the predicate `f`. - pub fn try_changed_and(&mut self, f: fn(&T) -> bool) -> Option { + pub fn try_changed_and(&mut self, mut f: impl FnMut(&T) -> bool) -> Option { self.multi_sig.mutex.lock(|state| { let s = state.borrow(); match s.current_id > self.at_id && f(&s.data) { @@ -234,7 +232,7 @@ impl<'a, M: RawMutex, T: Clone, const N: usize> Rcv<'a, M, T, N> { } /// Peek the current value of the corresponding `MultiSignal` and check if it satisfies the predicate `f`. - pub fn peek_and(&self, f: fn(&T) -> bool) -> Option { + pub fn peek_and(&self, f: impl FnMut(&T) -> bool) -> Option { self.multi_sig.peek_and(f) } From 24a4379832d387754d407b77ff7aac5e55401eb3 Mon Sep 17 00:00:00 2001 From: Peter Krull Date: Wed, 14 Feb 2024 01:23:11 +0100 Subject: [PATCH 0004/1217] Got closures to work in async, added bunch of tests --- embassy-sync/src/multi_signal.rs | 340 ++++++++++++++++++++++++++----- 1 file changed, 292 insertions(+), 48 deletions(-) diff --git a/embassy-sync/src/multi_signal.rs b/embassy-sync/src/multi_signal.rs index 5f724c76b..1481dc8f8 100644 --- a/embassy-sync/src/multi_signal.rs +++ b/embassy-sync/src/multi_signal.rs @@ -97,7 +97,7 @@ impl<'a, M: RawMutex, T: Clone, const N: usize> MultiSignal { } /// Get a [`Receiver`] for the `MultiSignal`. - pub fn receiver(&'a self) -> Result, Error> { + pub fn receiver<'s>(&'a self) -> Result, Error> { self.mutex.lock(|state| { let mut s = state.borrow_mut(); if s.receiver_count < N { @@ -142,60 +142,36 @@ impl<'a, M: RawMutex, T: Clone, const N: usize> MultiSignal { fn get_id(&self) -> u64 { self.mutex.lock(|state| state.borrow().current_id) } - - /// Poll the `MultiSignal` with an optional context. - fn get_with_context(&self, rcv: &mut Rcv<'a, M, T, N>, cx: Option<&mut Context>) -> Poll { - self.mutex.lock(|state| { - let mut s = state.borrow_mut(); - match (s.current_id > rcv.at_id, rcv.predicate) { - (true, None) => { - rcv.at_id = s.current_id; - Poll::Ready(s.data.clone()) - } - (true, Some(f)) if f(&s.data) => { - rcv.at_id = s.current_id; - Poll::Ready(s.data.clone()) - } - _ => { - if let Some(cx) = cx { - s.wakers.register(cx.waker()); - } - Poll::Pending - } - } - }) - } } /// A receiver is able to `.await` a changed `MultiSignal` value. pub struct Rcv<'a, M: RawMutex, T: Clone, const N: usize> { multi_sig: &'a MultiSignal, - predicate: Option bool>, at_id: u64, } -// f: Option bool> -impl<'a, M: RawMutex, T: Clone, const N: usize> Rcv<'a, M, T, N> { +impl<'s, 'a, M: RawMutex, T: Clone, const N: usize> Rcv<'a, M, T, N> { /// Create a new `Receiver` with a reference the given `MultiSignal`. fn new(multi_sig: &'a MultiSignal) -> Self { - Self { - multi_sig, - predicate: None, - at_id: 0, - } + Self { multi_sig, at_id: 0 } } /// Wait for a change to the value of the corresponding `MultiSignal`. - pub fn changed<'s>(&'s mut self) -> ReceiverFuture<'s, 'a, M, T, N> { - self.predicate = None; - ReceiverFuture { subscriber: self } + pub async fn changed(&mut self) -> T { + ReceiverWaitFuture { subscriber: self }.await } /// Wait for a change to the value of the corresponding `MultiSignal` which matches the predicate `f`. // TODO: How do we make this work with a FnMut closure? - pub fn changed_and<'s>(&'s mut self, f: fn(&T) -> bool) -> ReceiverFuture<'s, 'a, M, T, N> { - self.predicate = Some(f); - ReceiverFuture { subscriber: self } + pub async fn changed_and(&mut self, f: F) -> T + where + F: FnMut(&T) -> bool, + { + ReceiverPredFuture { + subscriber: self, + predicate: f, + } + .await } /// Try to get a changed value of the corresponding `MultiSignal`. @@ -213,7 +189,10 @@ impl<'a, M: RawMutex, T: Clone, const N: usize> Rcv<'a, M, T, N> { } /// Try to get a changed value of the corresponding `MultiSignal` which matches the predicate `f`. - pub fn try_changed_and(&mut self, mut f: impl FnMut(&T) -> bool) -> Option { + pub fn try_changed_and(&mut self, mut f: F) -> Option + where + F: FnMut(&T) -> bool, + { self.multi_sig.mutex.lock(|state| { let s = state.borrow(); match s.current_id > self.at_id && f(&s.data) { @@ -232,7 +211,10 @@ impl<'a, M: RawMutex, T: Clone, const N: usize> Rcv<'a, M, T, N> { } /// Peek the current value of the corresponding `MultiSignal` and check if it satisfies the predicate `f`. - pub fn peek_and(&self, f: impl FnMut(&T) -> bool) -> Option { + pub fn peek_and(&self, f: F) -> Option + where + F: FnMut(&T) -> bool, + { self.multi_sig.peek_and(f) } @@ -247,7 +229,7 @@ impl<'a, M: RawMutex, T: Clone, const N: usize> Rcv<'a, M, T, N> { /// A `Receiver` is able to `.await` a change to the corresponding [`MultiSignal`] value. pub struct Receiver<'a, M: RawMutex, T: Clone, const N: usize>(Rcv<'a, M, T, N>); -impl<'a, M: RawMutex, T: Clone, const N: usize> Deref for Receiver<'a, M, T, N> { +impl<'s, 'a, M: RawMutex, T: Clone, const N: usize> Deref for Receiver<'a, M, T, N> { type Target = Rcv<'a, M, T, N>; fn deref(&self) -> &Self::Target { @@ -255,7 +237,7 @@ impl<'a, M: RawMutex, T: Clone, const N: usize> Deref for Receiver<'a, M, T, N> } } -impl<'a, M: RawMutex, T: Clone, const N: usize> DerefMut for Receiver<'a, M, T, N> { +impl<'s, 'a, M: RawMutex, T: Clone, const N: usize> DerefMut for Receiver<'a, M, T, N> { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } @@ -263,18 +245,280 @@ impl<'a, M: RawMutex, T: Clone, const N: usize> DerefMut for Receiver<'a, M, T, /// Future for the `Receiver` wait action #[must_use = "futures do nothing unless you `.await` or poll them"] -pub struct ReceiverFuture<'s, 'a, M: RawMutex, T: Clone, const N: usize> { +pub struct ReceiverWaitFuture<'s, 'a, M: RawMutex, T: Clone, const N: usize> { subscriber: &'s mut Rcv<'a, M, T, N>, } -impl<'s, 'a, M: RawMutex, T: Clone, const N: usize> Future for ReceiverFuture<'s, 'a, M, T, N> { +impl<'s, 'a, M: RawMutex, T: Clone, const N: usize> Unpin for ReceiverWaitFuture<'s, 'a, M, T, N> {} +impl<'s, 'a, M: RawMutex, T: Clone, const N: usize> Future for ReceiverWaitFuture<'s, 'a, M, T, N> { type Output = T; fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - self.subscriber - .multi_sig - .get_with_context(&mut self.subscriber, Some(cx)) + self.get_with_context(Some(cx)) } } -impl<'s, 'a, M: RawMutex, T: Clone, const N: usize> Unpin for ReceiverFuture<'s, 'a, M, T, N> {} +impl<'s, 'a, M: RawMutex, T: Clone, const N: usize> ReceiverWaitFuture<'s, 'a, M, T, N> { + /// Poll the `MultiSignal` with an optional context. + fn get_with_context(&mut self, cx: Option<&mut Context>) -> Poll { + self.subscriber.multi_sig.mutex.lock(|state| { + let mut s = state.borrow_mut(); + match s.current_id > self.subscriber.at_id { + true => { + self.subscriber.at_id = s.current_id; + Poll::Ready(s.data.clone()) + } + _ => { + if let Some(cx) = cx { + s.wakers.register(cx.waker()); + } + Poll::Pending + } + } + }) + } +} + +/// Future for the `Receiver` wait action, with the ability to filter the value with a predicate. +#[must_use = "futures do nothing unless you `.await` or poll them"] +pub struct ReceiverPredFuture<'s, 'a, M: RawMutex, T: Clone, F: FnMut(&'a T) -> bool, const N: usize> { + subscriber: &'s mut Rcv<'a, M, T, N>, + predicate: F, +} + +impl<'s, 'a, M: RawMutex, T: Clone, F: FnMut(&T) -> bool, const N: usize> Unpin for ReceiverPredFuture<'s, 'a, M, T, F, N> {} +impl<'s, 'a, M: RawMutex, T: Clone, F: FnMut(&T) -> bool, const N: usize> Future for ReceiverPredFuture<'s, 'a, M, T, F, N>{ + type Output = T; + + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + self.get_with_context_pred(Some(cx)) + } +} + +impl<'s, 'a, M: RawMutex, T: Clone, F: FnMut(&T) -> bool, const N: usize> ReceiverPredFuture<'s, 'a, M, T, F, N> { + /// Poll the `MultiSignal` with an optional context. + fn get_with_context_pred(&mut self, cx: Option<&mut Context>) -> Poll { + self.subscriber.multi_sig.mutex.lock(|state| { + let mut s = state.borrow_mut(); + match s.current_id > self.subscriber.at_id { + true if (self.predicate)(&s.data) => { + self.subscriber.at_id = s.current_id; + Poll::Ready(s.data.clone()) + } + _ => { + if let Some(cx) = cx { + s.wakers.register(cx.waker()); + } + Poll::Pending + } + } + }) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::blocking_mutex::raw::CriticalSectionRawMutex; + use futures_executor::block_on; + + #[test] + fn multiple_writes() { + let f = async { + static SOME_SIGNAL: MultiSignal = MultiSignal::new(0); + + // Obtain Receivers + let mut rcv0 = SOME_SIGNAL.receiver().unwrap(); + let mut rcv1 = SOME_SIGNAL.receiver().unwrap(); + + SOME_SIGNAL.write(10); + + // Receive the new value + assert_eq!(rcv0.changed().await, 10); + assert_eq!(rcv1.changed().await, 10); + + // No update + assert_eq!(rcv0.try_changed(), None); + assert_eq!(rcv1.try_changed(), None); + + SOME_SIGNAL.write(20); + + assert_eq!(rcv0.changed().await, 20); + assert_eq!(rcv1.changed().await, 20); + }; + block_on(f); + } + + #[test] + fn max_receivers() { + let f = async { + static SOME_SIGNAL: MultiSignal = MultiSignal::new(0); + + // Obtain Receivers + let _ = SOME_SIGNAL.receiver().unwrap(); + let _ = SOME_SIGNAL.receiver().unwrap(); + assert!(SOME_SIGNAL.receiver().is_err()); + }; + block_on(f); + } + + // Really weird edge case, but it's possible to have a receiver that never gets a value. + #[test] + fn receive_initial() { + let f = async { + static SOME_SIGNAL: MultiSignal = MultiSignal::new(0); + + // Obtain Receivers + let mut rcv0 = SOME_SIGNAL.receiver().unwrap(); + let mut rcv1 = SOME_SIGNAL.receiver().unwrap(); + + assert_eq!(rcv0.try_changed(), Some(0)); + assert_eq!(rcv1.try_changed(), Some(0)); + + assert_eq!(rcv0.try_changed(), None); + assert_eq!(rcv1.try_changed(), None); + }; + block_on(f); + } + + #[test] + fn count_ids() { + let f = async { + static SOME_SIGNAL: MultiSignal = MultiSignal::new(0); + + // Obtain Receivers + let mut rcv0 = SOME_SIGNAL.receiver().unwrap(); + let mut rcv1 = SOME_SIGNAL.receiver().unwrap(); + + SOME_SIGNAL.write(10); + + assert_eq!(rcv0.changed().await, 10); + assert_eq!(rcv1.changed().await, 10); + + assert_eq!(rcv0.try_changed(), None); + assert_eq!(rcv1.try_changed(), None); + + SOME_SIGNAL.write(20); + SOME_SIGNAL.write(20); + SOME_SIGNAL.write(20); + + assert_eq!(rcv0.changed().await, 20); + assert_eq!(rcv1.changed().await, 20); + + assert_eq!(rcv0.try_changed(), None); + assert_eq!(rcv1.try_changed(), None); + + assert_eq!(SOME_SIGNAL.get_id(), 5); + }; + block_on(f); + } + + #[test] + fn peek_still_await() { + let f = async { + static SOME_SIGNAL: MultiSignal = MultiSignal::new(0); + + // Obtain Receivers + let mut rcv0 = SOME_SIGNAL.receiver().unwrap(); + let mut rcv1 = SOME_SIGNAL.receiver().unwrap(); + + SOME_SIGNAL.write(10); + + assert_eq!(rcv0.peek(), 10); + assert_eq!(rcv1.peek(), 10); + + assert_eq!(rcv0.changed().await, 10); + assert_eq!(rcv1.changed().await, 10); + }; + block_on(f); + } + + #[test] + fn predicate() { + let f = async { + static SOME_SIGNAL: MultiSignal = MultiSignal::new(0); + + // Obtain Receivers + let mut rcv0 = SOME_SIGNAL.receiver().unwrap(); + let mut rcv1 = SOME_SIGNAL.receiver().unwrap(); + + SOME_SIGNAL.write(20); + + assert_eq!(rcv0.changed_and(|x| x > &10).await, 20); + assert_eq!(rcv1.try_changed_and(|x| x > &30), None); + }; + block_on(f); + } + + #[test] + fn mutable_predicate() { + let f = async { + static SOME_SIGNAL: MultiSignal = MultiSignal::new(0); + + // Obtain Receivers + let mut rcv = SOME_SIGNAL.receiver().unwrap(); + + SOME_SIGNAL.write(10); + + let mut largest = 0; + let mut predicate = |x: &u8| { + if *x > largest { + largest = *x; + } + true + }; + + assert_eq!(rcv.changed_and(&mut predicate).await, 10); + + SOME_SIGNAL.write(20); + + assert_eq!(rcv.changed_and(&mut predicate).await, 20); + + SOME_SIGNAL.write(5); + + assert_eq!(rcv.changed_and(&mut predicate).await, 5); + + assert_eq!(largest, 20) + }; + block_on(f); + } + + #[test] + fn peek_and() { + let f = async { + static SOME_SIGNAL: MultiSignal = MultiSignal::new(0); + + // Obtain Receivers + let mut rcv0 = SOME_SIGNAL.receiver().unwrap(); + let mut rcv1 = SOME_SIGNAL.receiver().unwrap(); + + SOME_SIGNAL.write(20); + + assert_eq!(rcv0.peek_and(|x| x > &10), Some(20)); + assert_eq!(rcv1.peek_and(|x| x > &30), None); + + assert_eq!(rcv0.changed().await, 20); + assert_eq!(rcv1.changed().await, 20); + }; + block_on(f); + } + + #[test] + fn peek_with_static() { + let f = async { + static SOME_SIGNAL: MultiSignal = MultiSignal::new(0); + + // Obtain Receivers + let rcv0 = SOME_SIGNAL.receiver().unwrap(); + let rcv1 = SOME_SIGNAL.receiver().unwrap(); + + SOME_SIGNAL.write(20); + + assert_eq!(rcv0.peek(), 20); + assert_eq!(rcv1.peek(), 20); + assert_eq!(SOME_SIGNAL.peek(), 20); + assert_eq!(SOME_SIGNAL.peek_and(|x| x > &30), None); + }; + block_on(f); + } +} From 2f58d1968a7310335a0dac4d947c6972a7707ed5 Mon Sep 17 00:00:00 2001 From: Peter Krull Date: Wed, 14 Feb 2024 01:27:48 +0100 Subject: [PATCH 0005/1217] Updated formatting --- embassy-sync/src/multi_signal.rs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/embassy-sync/src/multi_signal.rs b/embassy-sync/src/multi_signal.rs index 1481dc8f8..ff9f72f2e 100644 --- a/embassy-sync/src/multi_signal.rs +++ b/embassy-sync/src/multi_signal.rs @@ -162,7 +162,6 @@ impl<'s, 'a, M: RawMutex, T: Clone, const N: usize> Rcv<'a, M, T, N> { } /// Wait for a change to the value of the corresponding `MultiSignal` which matches the predicate `f`. - // TODO: How do we make this work with a FnMut closure? pub async fn changed_and(&mut self, f: F) -> T where F: FnMut(&T) -> bool, @@ -286,8 +285,13 @@ pub struct ReceiverPredFuture<'s, 'a, M: RawMutex, T: Clone, F: FnMut(&'a T) -> predicate: F, } -impl<'s, 'a, M: RawMutex, T: Clone, F: FnMut(&T) -> bool, const N: usize> Unpin for ReceiverPredFuture<'s, 'a, M, T, F, N> {} -impl<'s, 'a, M: RawMutex, T: Clone, F: FnMut(&T) -> bool, const N: usize> Future for ReceiverPredFuture<'s, 'a, M, T, F, N>{ +impl<'s, 'a, M: RawMutex, T: Clone, F: FnMut(&T) -> bool, const N: usize> Unpin + for ReceiverPredFuture<'s, 'a, M, T, F, N> +{ +} +impl<'s, 'a, M: RawMutex, T: Clone, F: FnMut(&T) -> bool, const N: usize> Future + for ReceiverPredFuture<'s, 'a, M, T, F, N> +{ type Output = T; fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { @@ -318,9 +322,10 @@ impl<'s, 'a, M: RawMutex, T: Clone, F: FnMut(&T) -> bool, const N: usize> Receiv #[cfg(test)] mod tests { + use futures_executor::block_on; + use super::*; use crate::blocking_mutex::raw::CriticalSectionRawMutex; - use futures_executor::block_on; #[test] fn multiple_writes() { From 6defb4fed98432dee948634f3b2001cb4ea7ec5b Mon Sep 17 00:00:00 2001 From: Peter Krull Date: Wed, 28 Feb 2024 20:59:38 +0100 Subject: [PATCH 0006/1217] Changed name to `Watch`, added `DynReceiver`, `get`-method and more reworks. --- embassy-sync/src/lib.rs | 2 +- embassy-sync/src/multi_signal.rs | 529 ------------------------------- embassy-sync/src/watch.rs | 515 ++++++++++++++++++++++++++++++ 3 files changed, 516 insertions(+), 530 deletions(-) delete mode 100644 embassy-sync/src/multi_signal.rs create mode 100644 embassy-sync/src/watch.rs diff --git a/embassy-sync/src/lib.rs b/embassy-sync/src/lib.rs index f02985564..8a69541a5 100644 --- a/embassy-sync/src/lib.rs +++ b/embassy-sync/src/lib.rs @@ -12,11 +12,11 @@ mod ring_buffer; pub mod blocking_mutex; pub mod channel; -pub mod multi_signal; pub mod mutex; pub mod pipe; pub mod priority_channel; pub mod pubsub; pub mod signal; pub mod waitqueue; +pub mod watch; pub mod zerocopy_channel; diff --git a/embassy-sync/src/multi_signal.rs b/embassy-sync/src/multi_signal.rs deleted file mode 100644 index ff9f72f2e..000000000 --- a/embassy-sync/src/multi_signal.rs +++ /dev/null @@ -1,529 +0,0 @@ -//! A synchronization primitive for passing the latest value to **multiple** tasks. -use core::cell::RefCell; -use core::ops::{Deref, DerefMut}; -use core::pin::Pin; -use core::task::{Context, Poll}; - -use futures_util::Future; - -use crate::blocking_mutex::raw::RawMutex; -use crate::blocking_mutex::Mutex; -use crate::waitqueue::MultiWakerRegistration; - -/// A `MultiSignal` is a single-slot signaling primitive, which can awake `N` separate [`Receiver`]s. -/// -/// Similar to a [`Signal`](crate::signal::Signal), except `MultiSignal` allows for multiple tasks to -/// `.await` the latest value, and all receive it. -/// -/// This is similar to a [`PubSubChannel`](crate::pubsub::PubSubChannel) with a buffer size of 1, except -/// "sending" to it (calling [`MultiSignal::write`]) will immediately overwrite the previous value instead -/// of waiting for the receivers to pop the previous value. -/// -/// `MultiSignal` is useful when a single task is responsible for updating a value or "state", which multiple other -/// tasks are interested in getting notified about changes to the latest value of. It is therefore fine for -/// [`Receiver`]s to "lose" stale values. -/// -/// Anyone with a reference to the MultiSignal can update or peek the value. MultiSignals are generally declared -/// as `static`s and then borrowed as required to either [`MultiSignal::peek`] the value or obtain a [`Receiver`] -/// with [`MultiSignal::receiver`] which has async methods. -/// ``` -/// -/// use futures_executor::block_on; -/// use embassy_sync::multi_signal::MultiSignal; -/// use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; -/// -/// let f = async { -/// -/// static SOME_SIGNAL: MultiSignal = MultiSignal::new(0); -/// -/// // Obtain Receivers -/// let mut rcv0 = SOME_SIGNAL.receiver().unwrap(); -/// let mut rcv1 = SOME_SIGNAL.receiver().unwrap(); -/// assert!(SOME_SIGNAL.receiver().is_err()); -/// -/// SOME_SIGNAL.write(10); -/// -/// // Receive the new value -/// assert_eq!(rcv0.changed().await, 10); -/// assert_eq!(rcv1.try_changed(), Some(10)); -/// -/// // No update -/// assert_eq!(rcv0.try_changed(), None); -/// assert_eq!(rcv1.try_changed(), None); -/// -/// SOME_SIGNAL.write(20); -/// -/// // Receive new value with predicate -/// assert_eq!(rcv0.changed_and(|x|x>&10).await, 20); -/// assert_eq!(rcv1.try_changed_and(|x|x>&30), None); -/// -/// // Anyone can peek the current value -/// assert_eq!(rcv0.peek(), 20); -/// assert_eq!(rcv1.peek(), 20); -/// assert_eq!(SOME_SIGNAL.peek(), 20); -/// assert_eq!(SOME_SIGNAL.peek_and(|x|x>&30), None); -/// }; -/// block_on(f); -/// ``` -pub struct MultiSignal { - mutex: Mutex>>, -} - -struct MultiSignalState { - data: T, - current_id: u64, - wakers: MultiWakerRegistration, - receiver_count: usize, -} - -#[derive(Debug)] -/// An error that can occur when a `MultiSignal` returns a `Result`. -pub enum Error { - /// The maximum number of [`Receiver`](crate::multi_signal::Receiver) has been reached. - MaximumReceiversReached, -} - -impl<'a, M: RawMutex, T: Clone, const N: usize> MultiSignal { - /// Create a new `MultiSignal` initialized with the given value. - pub const fn new(init: T) -> Self { - Self { - mutex: Mutex::new(RefCell::new(MultiSignalState { - data: init, - current_id: 1, - wakers: MultiWakerRegistration::new(), - receiver_count: 0, - })), - } - } - - /// Get a [`Receiver`] for the `MultiSignal`. - pub fn receiver<'s>(&'a self) -> Result, Error> { - self.mutex.lock(|state| { - let mut s = state.borrow_mut(); - if s.receiver_count < N { - s.receiver_count += 1; - Ok(Receiver(Rcv::new(self))) - } else { - Err(Error::MaximumReceiversReached) - } - }) - } - - /// Update the value of the `MultiSignal`. - pub fn write(&self, data: T) { - self.mutex.lock(|state| { - let mut s = state.borrow_mut(); - s.data = data; - s.current_id += 1; - s.wakers.wake(); - }) - } - - /// Peek the current value of the `MultiSignal`. - pub fn peek(&self) -> T { - self.mutex.lock(|state| state.borrow().data.clone()) - } - - /// Peek the current value of the `MultiSignal` and check if it satisfies the predicate `f`. - pub fn peek_and(&self, mut f: impl FnMut(&T) -> bool) -> Option { - self.mutex.lock(|state| { - let s = state.borrow(); - if f(&s.data) { - Some(s.data.clone()) - } else { - None - } - }) - } - - /// Get the ID of the current value of the `MultiSignal`. - /// This method is mostly for testing purposes. - #[allow(dead_code)] - fn get_id(&self) -> u64 { - self.mutex.lock(|state| state.borrow().current_id) - } -} - -/// A receiver is able to `.await` a changed `MultiSignal` value. -pub struct Rcv<'a, M: RawMutex, T: Clone, const N: usize> { - multi_sig: &'a MultiSignal, - at_id: u64, -} - -impl<'s, 'a, M: RawMutex, T: Clone, const N: usize> Rcv<'a, M, T, N> { - /// Create a new `Receiver` with a reference the given `MultiSignal`. - fn new(multi_sig: &'a MultiSignal) -> Self { - Self { multi_sig, at_id: 0 } - } - - /// Wait for a change to the value of the corresponding `MultiSignal`. - pub async fn changed(&mut self) -> T { - ReceiverWaitFuture { subscriber: self }.await - } - - /// Wait for a change to the value of the corresponding `MultiSignal` which matches the predicate `f`. - pub async fn changed_and(&mut self, f: F) -> T - where - F: FnMut(&T) -> bool, - { - ReceiverPredFuture { - subscriber: self, - predicate: f, - } - .await - } - - /// Try to get a changed value of the corresponding `MultiSignal`. - pub fn try_changed(&mut self) -> Option { - self.multi_sig.mutex.lock(|state| { - let s = state.borrow(); - match s.current_id > self.at_id { - true => { - self.at_id = s.current_id; - Some(s.data.clone()) - } - false => None, - } - }) - } - - /// Try to get a changed value of the corresponding `MultiSignal` which matches the predicate `f`. - pub fn try_changed_and(&mut self, mut f: F) -> Option - where - F: FnMut(&T) -> bool, - { - self.multi_sig.mutex.lock(|state| { - let s = state.borrow(); - match s.current_id > self.at_id && f(&s.data) { - true => { - self.at_id = s.current_id; - Some(s.data.clone()) - } - false => None, - } - }) - } - - /// Peek the current value of the corresponding `MultiSignal`. - pub fn peek(&self) -> T { - self.multi_sig.peek() - } - - /// Peek the current value of the corresponding `MultiSignal` and check if it satisfies the predicate `f`. - pub fn peek_and(&self, f: F) -> Option - where - F: FnMut(&T) -> bool, - { - self.multi_sig.peek_and(f) - } - - /// Check if the value of the corresponding `MultiSignal` has changed. - pub fn has_changed(&mut self) -> bool { - self.multi_sig - .mutex - .lock(|state| state.borrow().current_id > self.at_id) - } -} - -/// A `Receiver` is able to `.await` a change to the corresponding [`MultiSignal`] value. -pub struct Receiver<'a, M: RawMutex, T: Clone, const N: usize>(Rcv<'a, M, T, N>); - -impl<'s, 'a, M: RawMutex, T: Clone, const N: usize> Deref for Receiver<'a, M, T, N> { - type Target = Rcv<'a, M, T, N>; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl<'s, 'a, M: RawMutex, T: Clone, const N: usize> DerefMut for Receiver<'a, M, T, N> { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 - } -} - -/// Future for the `Receiver` wait action -#[must_use = "futures do nothing unless you `.await` or poll them"] -pub struct ReceiverWaitFuture<'s, 'a, M: RawMutex, T: Clone, const N: usize> { - subscriber: &'s mut Rcv<'a, M, T, N>, -} - -impl<'s, 'a, M: RawMutex, T: Clone, const N: usize> Unpin for ReceiverWaitFuture<'s, 'a, M, T, N> {} -impl<'s, 'a, M: RawMutex, T: Clone, const N: usize> Future for ReceiverWaitFuture<'s, 'a, M, T, N> { - type Output = T; - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - self.get_with_context(Some(cx)) - } -} - -impl<'s, 'a, M: RawMutex, T: Clone, const N: usize> ReceiverWaitFuture<'s, 'a, M, T, N> { - /// Poll the `MultiSignal` with an optional context. - fn get_with_context(&mut self, cx: Option<&mut Context>) -> Poll { - self.subscriber.multi_sig.mutex.lock(|state| { - let mut s = state.borrow_mut(); - match s.current_id > self.subscriber.at_id { - true => { - self.subscriber.at_id = s.current_id; - Poll::Ready(s.data.clone()) - } - _ => { - if let Some(cx) = cx { - s.wakers.register(cx.waker()); - } - Poll::Pending - } - } - }) - } -} - -/// Future for the `Receiver` wait action, with the ability to filter the value with a predicate. -#[must_use = "futures do nothing unless you `.await` or poll them"] -pub struct ReceiverPredFuture<'s, 'a, M: RawMutex, T: Clone, F: FnMut(&'a T) -> bool, const N: usize> { - subscriber: &'s mut Rcv<'a, M, T, N>, - predicate: F, -} - -impl<'s, 'a, M: RawMutex, T: Clone, F: FnMut(&T) -> bool, const N: usize> Unpin - for ReceiverPredFuture<'s, 'a, M, T, F, N> -{ -} -impl<'s, 'a, M: RawMutex, T: Clone, F: FnMut(&T) -> bool, const N: usize> Future - for ReceiverPredFuture<'s, 'a, M, T, F, N> -{ - type Output = T; - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - self.get_with_context_pred(Some(cx)) - } -} - -impl<'s, 'a, M: RawMutex, T: Clone, F: FnMut(&T) -> bool, const N: usize> ReceiverPredFuture<'s, 'a, M, T, F, N> { - /// Poll the `MultiSignal` with an optional context. - fn get_with_context_pred(&mut self, cx: Option<&mut Context>) -> Poll { - self.subscriber.multi_sig.mutex.lock(|state| { - let mut s = state.borrow_mut(); - match s.current_id > self.subscriber.at_id { - true if (self.predicate)(&s.data) => { - self.subscriber.at_id = s.current_id; - Poll::Ready(s.data.clone()) - } - _ => { - if let Some(cx) = cx { - s.wakers.register(cx.waker()); - } - Poll::Pending - } - } - }) - } -} - -#[cfg(test)] -mod tests { - use futures_executor::block_on; - - use super::*; - use crate::blocking_mutex::raw::CriticalSectionRawMutex; - - #[test] - fn multiple_writes() { - let f = async { - static SOME_SIGNAL: MultiSignal = MultiSignal::new(0); - - // Obtain Receivers - let mut rcv0 = SOME_SIGNAL.receiver().unwrap(); - let mut rcv1 = SOME_SIGNAL.receiver().unwrap(); - - SOME_SIGNAL.write(10); - - // Receive the new value - assert_eq!(rcv0.changed().await, 10); - assert_eq!(rcv1.changed().await, 10); - - // No update - assert_eq!(rcv0.try_changed(), None); - assert_eq!(rcv1.try_changed(), None); - - SOME_SIGNAL.write(20); - - assert_eq!(rcv0.changed().await, 20); - assert_eq!(rcv1.changed().await, 20); - }; - block_on(f); - } - - #[test] - fn max_receivers() { - let f = async { - static SOME_SIGNAL: MultiSignal = MultiSignal::new(0); - - // Obtain Receivers - let _ = SOME_SIGNAL.receiver().unwrap(); - let _ = SOME_SIGNAL.receiver().unwrap(); - assert!(SOME_SIGNAL.receiver().is_err()); - }; - block_on(f); - } - - // Really weird edge case, but it's possible to have a receiver that never gets a value. - #[test] - fn receive_initial() { - let f = async { - static SOME_SIGNAL: MultiSignal = MultiSignal::new(0); - - // Obtain Receivers - let mut rcv0 = SOME_SIGNAL.receiver().unwrap(); - let mut rcv1 = SOME_SIGNAL.receiver().unwrap(); - - assert_eq!(rcv0.try_changed(), Some(0)); - assert_eq!(rcv1.try_changed(), Some(0)); - - assert_eq!(rcv0.try_changed(), None); - assert_eq!(rcv1.try_changed(), None); - }; - block_on(f); - } - - #[test] - fn count_ids() { - let f = async { - static SOME_SIGNAL: MultiSignal = MultiSignal::new(0); - - // Obtain Receivers - let mut rcv0 = SOME_SIGNAL.receiver().unwrap(); - let mut rcv1 = SOME_SIGNAL.receiver().unwrap(); - - SOME_SIGNAL.write(10); - - assert_eq!(rcv0.changed().await, 10); - assert_eq!(rcv1.changed().await, 10); - - assert_eq!(rcv0.try_changed(), None); - assert_eq!(rcv1.try_changed(), None); - - SOME_SIGNAL.write(20); - SOME_SIGNAL.write(20); - SOME_SIGNAL.write(20); - - assert_eq!(rcv0.changed().await, 20); - assert_eq!(rcv1.changed().await, 20); - - assert_eq!(rcv0.try_changed(), None); - assert_eq!(rcv1.try_changed(), None); - - assert_eq!(SOME_SIGNAL.get_id(), 5); - }; - block_on(f); - } - - #[test] - fn peek_still_await() { - let f = async { - static SOME_SIGNAL: MultiSignal = MultiSignal::new(0); - - // Obtain Receivers - let mut rcv0 = SOME_SIGNAL.receiver().unwrap(); - let mut rcv1 = SOME_SIGNAL.receiver().unwrap(); - - SOME_SIGNAL.write(10); - - assert_eq!(rcv0.peek(), 10); - assert_eq!(rcv1.peek(), 10); - - assert_eq!(rcv0.changed().await, 10); - assert_eq!(rcv1.changed().await, 10); - }; - block_on(f); - } - - #[test] - fn predicate() { - let f = async { - static SOME_SIGNAL: MultiSignal = MultiSignal::new(0); - - // Obtain Receivers - let mut rcv0 = SOME_SIGNAL.receiver().unwrap(); - let mut rcv1 = SOME_SIGNAL.receiver().unwrap(); - - SOME_SIGNAL.write(20); - - assert_eq!(rcv0.changed_and(|x| x > &10).await, 20); - assert_eq!(rcv1.try_changed_and(|x| x > &30), None); - }; - block_on(f); - } - - #[test] - fn mutable_predicate() { - let f = async { - static SOME_SIGNAL: MultiSignal = MultiSignal::new(0); - - // Obtain Receivers - let mut rcv = SOME_SIGNAL.receiver().unwrap(); - - SOME_SIGNAL.write(10); - - let mut largest = 0; - let mut predicate = |x: &u8| { - if *x > largest { - largest = *x; - } - true - }; - - assert_eq!(rcv.changed_and(&mut predicate).await, 10); - - SOME_SIGNAL.write(20); - - assert_eq!(rcv.changed_and(&mut predicate).await, 20); - - SOME_SIGNAL.write(5); - - assert_eq!(rcv.changed_and(&mut predicate).await, 5); - - assert_eq!(largest, 20) - }; - block_on(f); - } - - #[test] - fn peek_and() { - let f = async { - static SOME_SIGNAL: MultiSignal = MultiSignal::new(0); - - // Obtain Receivers - let mut rcv0 = SOME_SIGNAL.receiver().unwrap(); - let mut rcv1 = SOME_SIGNAL.receiver().unwrap(); - - SOME_SIGNAL.write(20); - - assert_eq!(rcv0.peek_and(|x| x > &10), Some(20)); - assert_eq!(rcv1.peek_and(|x| x > &30), None); - - assert_eq!(rcv0.changed().await, 20); - assert_eq!(rcv1.changed().await, 20); - }; - block_on(f); - } - - #[test] - fn peek_with_static() { - let f = async { - static SOME_SIGNAL: MultiSignal = MultiSignal::new(0); - - // Obtain Receivers - let rcv0 = SOME_SIGNAL.receiver().unwrap(); - let rcv1 = SOME_SIGNAL.receiver().unwrap(); - - SOME_SIGNAL.write(20); - - assert_eq!(rcv0.peek(), 20); - assert_eq!(rcv1.peek(), 20); - assert_eq!(SOME_SIGNAL.peek(), 20); - assert_eq!(SOME_SIGNAL.peek_and(|x| x > &30), None); - }; - block_on(f); - } -} diff --git a/embassy-sync/src/watch.rs b/embassy-sync/src/watch.rs new file mode 100644 index 000000000..7e5e92741 --- /dev/null +++ b/embassy-sync/src/watch.rs @@ -0,0 +1,515 @@ +//! A synchronization primitive for passing the latest value to **multiple** tasks. + +use core::cell::RefCell; +use core::future::poll_fn; +use core::marker::PhantomData; +use core::ops::{Deref, DerefMut}; +use core::task::{Context, Poll}; + +use crate::blocking_mutex::raw::RawMutex; +use crate::blocking_mutex::Mutex; +use crate::waitqueue::MultiWakerRegistration; + +/// A `Watch` is a single-slot signaling primitive, which can awake `N` up to separate [`Receiver`]s. +/// +/// Similar to a [`Signal`](crate::signal::Signal), except `Watch` allows for multiple tasks to +/// `.await` the latest value, and all receive it. +/// +/// This is similar to a [`PubSubChannel`](crate::pubsub::PubSubChannel) with a buffer size of 1, except +/// "sending" to it (calling [`Watch::write`]) will immediately overwrite the previous value instead +/// of waiting for the receivers to pop the previous value. +/// +/// `Watch` is useful when a single task is responsible for updating a value or "state", which multiple other +/// tasks are interested in getting notified about changes to the latest value of. It is therefore fine for +/// [`Receiver`]s to "lose" stale values. +/// +/// Anyone with a reference to the Watch can update or peek the value. Watches are generally declared +/// as `static`s and then borrowed as required to either [`Watch::peek`] the value or obtain a [`Receiver`] +/// with [`Watch::receiver`] which has async methods. +/// ``` +/// +/// use futures_executor::block_on; +/// use embassy_sync::watch::Watch; +/// use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; +/// +/// let f = async { +/// +/// static WATCH: Watch = Watch::new(); +/// +/// // Obtain Receivers +/// let mut rcv0 = WATCH.receiver().unwrap(); +/// let mut rcv1 = WATCH.receiver().unwrap(); +/// assert!(WATCH.receiver().is_err()); +/// +/// assert_eq!(rcv1.try_changed(), None); +/// +/// WATCH.write(10); +/// assert_eq!(WATCH.try_peek(), Some(10)); +/// +/// +/// // Receive the new value +/// assert_eq!(rcv0.changed().await, 10); +/// assert_eq!(rcv1.try_changed(), Some(10)); +/// +/// // No update +/// assert_eq!(rcv0.try_changed(), None); +/// assert_eq!(rcv1.try_changed(), None); +/// +/// WATCH.write(20); +/// +/// // Defference `between` peek `get`. +/// assert_eq!(rcv0.peek().await, 20); +/// assert_eq!(rcv1.get().await, 20); +/// +/// assert_eq!(rcv0.try_changed(), Some(20)); +/// assert_eq!(rcv1.try_changed(), None); +/// +/// }; +/// block_on(f); +/// ``` +pub struct Watch { + mutex: Mutex>>, +} + +struct WatchState { + data: Option, + current_id: u64, + wakers: MultiWakerRegistration, + receiver_count: usize, +} + +/// A trait representing the 'inner' behavior of the `Watch`. +pub trait WatchBehavior { + /// Poll the `Watch` for the current value, **without** making it as seen. + fn inner_poll_peek(&self, cx: &mut Context<'_>) -> Poll; + + /// Tries to peek the value of the `Watch`, **without** marking it as seen. + fn inner_try_peek(&self) -> Option; + + /// Poll the `Watch` for the current value, making it as seen. + fn inner_poll_get(&self, id: &mut u64, cx: &mut Context<'_>) -> Poll; + + /// Tries to get the value of the `Watch`, marking it as seen. + fn inner_try_get(&self, id: &mut u64) -> Option; + + /// Poll the `Watch` for a changed value, marking it as seen. + fn inner_poll_changed(&self, id: &mut u64, cx: &mut Context<'_>) -> Poll; + + /// Tries to retrieve the value of the `Watch` if it has changed, marking it as seen. + fn inner_try_changed(&self, id: &mut u64) -> Option; + + /// Checks if the `Watch` is been initialized with a value. + fn inner_contains_value(&self) -> bool; +} + +impl WatchBehavior for Watch { + fn inner_poll_peek(&self, cx: &mut Context<'_>) -> Poll { + self.mutex.lock(|state| { + let mut s = state.borrow_mut(); + match &s.data { + Some(data) => Poll::Ready(data.clone()), + None => { + s.wakers.register(cx.waker()); + Poll::Pending + } + } + }) + } + + fn inner_try_peek(&self) -> Option { + self.mutex.lock(|state| state.borrow().data.clone()) + } + + fn inner_poll_get(&self, id: &mut u64, cx: &mut Context<'_>) -> Poll { + self.mutex.lock(|state| { + let mut s = state.borrow_mut(); + match &s.data { + Some(data) => { + *id = s.current_id; + Poll::Ready(data.clone()) + } + None => { + s.wakers.register(cx.waker()); + Poll::Pending + } + } + }) + } + + fn inner_try_get(&self, id: &mut u64) -> Option { + self.mutex.lock(|state| { + let s = state.borrow(); + *id = s.current_id; + state.borrow().data.clone() + }) + } + + fn inner_poll_changed(&self, id: &mut u64, cx: &mut Context<'_>) -> Poll { + self.mutex.lock(|state| { + let mut s = state.borrow_mut(); + match (&s.data, s.current_id > *id) { + (Some(data), true) => { + *id = s.current_id; + Poll::Ready(data.clone()) + } + _ => { + s.wakers.register(cx.waker()); + Poll::Pending + } + } + }) + } + + fn inner_try_changed(&self, id: &mut u64) -> Option { + self.mutex.lock(|state| { + let s = state.borrow(); + match s.current_id > *id { + true => { + *id = s.current_id; + state.borrow().data.clone() + } + false => None, + } + }) + } + + fn inner_contains_value(&self) -> bool { + self.mutex.lock(|state| state.borrow().data.is_some()) + } +} + +#[derive(Debug)] +/// An error that can occur when a `Watch` returns a `Result::Err(_)`. +pub enum Error { + /// The maximum number of [`Receiver`](crate::watch::Receiver)/[`DynReceiver`](crate::watch::DynReceiver) has been reached. + MaximumReceiversReached, +} + +impl<'a, M: RawMutex, T: Clone, const N: usize> Watch { + /// Create a new `Watch` channel. + pub const fn new() -> Self { + Self { + mutex: Mutex::new(RefCell::new(WatchState { + data: None, + current_id: 0, + wakers: MultiWakerRegistration::new(), + receiver_count: 0, + })), + } + } + + /// Write a new value to the `Watch`. + pub fn write(&self, val: T) { + self.mutex.lock(|state| { + let mut s = state.borrow_mut(); + s.data = Some(val); + s.current_id += 1; + s.wakers.wake(); + }) + } + + /// Create a new [`Receiver`] for the `Watch`. + pub fn receiver(&self) -> Result, Error> { + self.mutex.lock(|state| { + let mut s = state.borrow_mut(); + if s.receiver_count < N { + s.receiver_count += 1; + Ok(Receiver(Rcv::new(self))) + } else { + Err(Error::MaximumReceiversReached) + } + }) + } + + /// Create a new [`DynReceiver`] for the `Watch`. + pub fn dyn_receiver(&self) -> Result, Error> { + self.mutex.lock(|state| { + let mut s = state.borrow_mut(); + if s.receiver_count < N { + s.receiver_count += 1; + Ok(DynReceiver(Rcv::new(self))) + } else { + Err(Error::MaximumReceiversReached) + } + }) + } + + /// Tries to retrieve the value of the `Watch`. + pub fn try_peek(&self) -> Option { + self.inner_try_peek() + } + + /// Returns true if the `Watch` contains a value. + pub fn contains_value(&self) -> bool { + self.inner_contains_value() + } + + /// Clears the value of the `Watch`. This will cause calls to [`Rcv::get`] and [`Rcv::peek`] to be pending. + pub fn clear(&self) { + self.mutex.lock(|state| { + let mut s = state.borrow_mut(); + s.data = None; + }) + } +} + +/// A receiver can `.await` a change in the `Watch` value. +pub struct Rcv<'a, T: Clone, W: WatchBehavior + ?Sized> { + watch: &'a W, + at_id: u64, + _phantom: PhantomData, +} + +impl<'a, T: Clone, W: WatchBehavior + ?Sized> Rcv<'a, T, W> { + /// Creates a new `Receiver` with a reference to the `Watch`. + fn new(watch: &'a W) -> Self { + Self { + watch, + at_id: 0, + _phantom: PhantomData, + } + } + + /// Returns the current value of the `Watch` if it is initialized, **without** marking it as seen. + pub async fn peek(&self) -> T { + poll_fn(|cx| self.watch.inner_poll_peek(cx)).await + } + + /// Tries to peek the current value of the `Watch` without waiting, and **without** marking it as seen. + pub fn try_peek(&self) -> Option { + self.watch.inner_try_peek() + } + + /// Returns the current value of the `Watch` if it is initialized, marking it as seen. + pub async fn get(&mut self) -> T { + poll_fn(|cx| self.watch.inner_poll_get(&mut self.at_id, cx)).await + } + + /// Tries to get the current value of the `Watch` without waiting, marking it as seen. + pub fn try_get(&mut self) -> Option { + self.watch.inner_try_get(&mut self.at_id) + } + + /// Waits for the `Watch` to change and returns the new value, marking it as seen. + pub async fn changed(&mut self) -> T { + poll_fn(|cx| self.watch.inner_poll_changed(&mut self.at_id, cx)).await + } + + /// Tries to get the new value of the watch without waiting, marking it as seen. + pub fn try_changed(&mut self) -> Option { + self.watch.inner_try_changed(&mut self.at_id) + } + + /// Checks if the `Watch` contains a value. If this returns true, + /// then awaiting [`Rcv::get`] and [`Rcv::peek`] will return immediately. + pub fn contains_value(&self) -> bool { + self.watch.inner_contains_value() + } +} + +/// A receiver of a `Watch` channel. +pub struct Receiver<'a, M: RawMutex, T: Clone, const N: usize>(Rcv<'a, T, Watch>); + +/// A receiver which holds a **reference** to a `Watch` channel. +/// +/// This is an alternative to [`Receiver`] with a simpler type definition, at the expense of +/// some runtime performance due to dynamic dispatch. +pub struct DynReceiver<'a, T: Clone>(Rcv<'a, T, dyn WatchBehavior + 'a>); + +impl<'a, M: RawMutex, T: Clone, const N: usize> Deref for Receiver<'a, M, T, N> { + type Target = Rcv<'a, T, Watch>; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl<'a, M: RawMutex, T: Clone, const N: usize> DerefMut for Receiver<'a, M, T, N> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +impl<'a, T: Clone> Deref for DynReceiver<'a, T> { + type Target = Rcv<'a, T, dyn WatchBehavior + 'a>; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl<'a, T: Clone> DerefMut for DynReceiver<'a, T> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +#[cfg(test)] +mod tests { + use futures_executor::block_on; + + use super::*; + use crate::blocking_mutex::raw::CriticalSectionRawMutex; + + #[test] + fn multiple_writes() { + let f = async { + static WATCH: Watch = Watch::new(); + + // Obtain Receivers + let mut rcv0 = WATCH.receiver().unwrap(); + let mut rcv1 = WATCH.dyn_receiver().unwrap(); + + WATCH.write(10); + + // Receive the new value + assert_eq!(rcv0.changed().await, 10); + assert_eq!(rcv1.changed().await, 10); + + // No update + assert_eq!(rcv0.try_changed(), None); + assert_eq!(rcv1.try_changed(), None); + + WATCH.write(20); + + assert_eq!(rcv0.changed().await, 20); + assert_eq!(rcv1.changed().await, 20); + }; + block_on(f); + } + + #[test] + fn max_receivers() { + let f = async { + static WATCH: Watch = Watch::new(); + + // Obtain Receivers + let _ = WATCH.receiver().unwrap(); + let _ = WATCH.receiver().unwrap(); + assert!(WATCH.receiver().is_err()); + }; + block_on(f); + } + + #[test] + fn receive_initial() { + let f = async { + static WATCH: Watch = Watch::new(); + + // Obtain Receivers + let mut rcv0 = WATCH.receiver().unwrap(); + let mut rcv1 = WATCH.receiver().unwrap(); + + assert_eq!(rcv0.contains_value(), false); + + assert_eq!(rcv0.try_changed(), None); + assert_eq!(rcv1.try_changed(), None); + + WATCH.write(0); + + assert_eq!(rcv0.contains_value(), true); + + assert_eq!(rcv0.try_changed(), Some(0)); + assert_eq!(rcv1.try_changed(), Some(0)); + }; + block_on(f); + } + + #[test] + fn peek_get_changed() { + let f = async { + static WATCH: Watch = Watch::new(); + + // Obtain Receivers + let mut rcv0 = WATCH.receiver().unwrap(); + + WATCH.write(10); + + // Ensure peek does not mark as seen + assert_eq!(rcv0.peek().await, 10); + assert_eq!(rcv0.try_changed(), Some(10)); + assert_eq!(rcv0.try_changed(), None); + assert_eq!(rcv0.peek().await, 10); + + WATCH.write(20); + + // Ensure get does mark as seen + assert_eq!(rcv0.get().await, 20); + assert_eq!(rcv0.try_changed(), None); + assert_eq!(rcv0.try_get(), Some(20)); + }; + block_on(f); + } + + #[test] + fn count_ids() { + let f = async { + static WATCH: Watch = Watch::new(); + + // Obtain Receivers + let mut rcv0 = WATCH.receiver().unwrap(); + let mut rcv1 = WATCH.receiver().unwrap(); + + let get_id = || WATCH.mutex.lock(|state| state.borrow().current_id); + + WATCH.write(10); + + assert_eq!(rcv0.changed().await, 10); + assert_eq!(rcv1.changed().await, 10); + + assert_eq!(rcv0.try_changed(), None); + assert_eq!(rcv1.try_changed(), None); + + WATCH.write(20); + WATCH.write(20); + WATCH.write(20); + + assert_eq!(rcv0.changed().await, 20); + assert_eq!(rcv1.changed().await, 20); + + assert_eq!(rcv0.try_changed(), None); + assert_eq!(rcv1.try_changed(), None); + + assert_eq!(get_id(), 4); + }; + block_on(f); + } + + #[test] + fn peek_still_await() { + let f = async { + static WATCH: Watch = Watch::new(); + + // Obtain Receivers + let mut rcv0 = WATCH.receiver().unwrap(); + let mut rcv1 = WATCH.receiver().unwrap(); + + WATCH.write(10); + + assert_eq!(rcv0.peek().await, 10); + assert_eq!(rcv1.try_peek(), Some(10)); + + assert_eq!(rcv0.changed().await, 10); + assert_eq!(rcv1.changed().await, 10); + }; + block_on(f); + } + + #[test] + fn peek_with_static() { + let f = async { + static WATCH: Watch = Watch::new(); + + // Obtain Receivers + let rcv0 = WATCH.receiver().unwrap(); + let rcv1 = WATCH.receiver().unwrap(); + + WATCH.write(20); + + assert_eq!(rcv0.peek().await, 20); + assert_eq!(rcv1.peek().await, 20); + assert_eq!(WATCH.try_peek(), Some(20)); + }; + block_on(f); + } +} From ae2f10992149279884ea564b00eb18c8bf1f464e Mon Sep 17 00:00:00 2001 From: Peter Krull Date: Thu, 29 Feb 2024 16:45:44 +0100 Subject: [PATCH 0007/1217] Added sender types, support for dropping receivers, converting to dyn-types, revised tests. --- embassy-sync/src/watch.rs | 537 +++++++++++++++++++++++++++----------- 1 file changed, 382 insertions(+), 155 deletions(-) diff --git a/embassy-sync/src/watch.rs b/embassy-sync/src/watch.rs index 7e5e92741..3e22b1e7b 100644 --- a/embassy-sync/src/watch.rs +++ b/embassy-sync/src/watch.rs @@ -1,4 +1,4 @@ -//! A synchronization primitive for passing the latest value to **multiple** tasks. +//! A synchronization primitive for passing the latest value to **multiple** receivers. use core::cell::RefCell; use core::future::poll_fn; @@ -10,22 +10,17 @@ use crate::blocking_mutex::raw::RawMutex; use crate::blocking_mutex::Mutex; use crate::waitqueue::MultiWakerRegistration; -/// A `Watch` is a single-slot signaling primitive, which can awake `N` up to separate [`Receiver`]s. +/// The `Watch` is a single-slot signaling primitive that allows multiple receivers to concurrently await +/// changes to the value. Unlike a [`Signal`](crate::signal::Signal), `Watch` supports multiple receivers, +/// and unlike a [`PubSubChannel`](crate::pubsub::PubSubChannel), `Watch` immediately overwrites the previous +/// value when a new one is sent, without waiting for all receivers to read the previous value. /// -/// Similar to a [`Signal`](crate::signal::Signal), except `Watch` allows for multiple tasks to -/// `.await` the latest value, and all receive it. +/// This makes `Watch` particularly useful when a single task updates a value or "state", and multiple other tasks +/// need to be notified about changes to this value asynchronously. Receivers may "lose" stale values, as they are +/// always provided with the latest value. /// -/// This is similar to a [`PubSubChannel`](crate::pubsub::PubSubChannel) with a buffer size of 1, except -/// "sending" to it (calling [`Watch::write`]) will immediately overwrite the previous value instead -/// of waiting for the receivers to pop the previous value. -/// -/// `Watch` is useful when a single task is responsible for updating a value or "state", which multiple other -/// tasks are interested in getting notified about changes to the latest value of. It is therefore fine for -/// [`Receiver`]s to "lose" stale values. -/// -/// Anyone with a reference to the Watch can update or peek the value. Watches are generally declared -/// as `static`s and then borrowed as required to either [`Watch::peek`] the value or obtain a [`Receiver`] -/// with [`Watch::receiver`] which has async methods. +/// Typically, `Watch` instances are declared as `static`, and a [`Sender`] and [`Receiver`] +/// (or [`DynSender`] and/or [`DynReceiver`]) are obtained and passed to the relevant parts of the program. /// ``` /// /// use futures_executor::block_on; @@ -36,18 +31,18 @@ use crate::waitqueue::MultiWakerRegistration; /// /// static WATCH: Watch = Watch::new(); /// -/// // Obtain Receivers +/// // Obtain receivers and sender /// let mut rcv0 = WATCH.receiver().unwrap(); -/// let mut rcv1 = WATCH.receiver().unwrap(); -/// assert!(WATCH.receiver().is_err()); +/// let mut rcv1 = WATCH.dyn_receiver().unwrap(); +/// let mut snd = WATCH.sender(); /// +/// // No more receivers, and no update +/// assert!(WATCH.receiver().is_err()); /// assert_eq!(rcv1.try_changed(), None); /// -/// WATCH.write(10); -/// assert_eq!(WATCH.try_peek(), Some(10)); -/// +/// snd.send(10); /// -/// // Receive the new value +/// // Receive the new value (async or try) /// assert_eq!(rcv0.changed().await, 10); /// assert_eq!(rcv1.try_changed(), Some(10)); /// @@ -55,13 +50,14 @@ use crate::waitqueue::MultiWakerRegistration; /// assert_eq!(rcv0.try_changed(), None); /// assert_eq!(rcv1.try_changed(), None); /// -/// WATCH.write(20); +/// snd.send(20); /// -/// // Defference `between` peek `get`. +/// // Peek does not mark the value as seen /// assert_eq!(rcv0.peek().await, 20); -/// assert_eq!(rcv1.get().await, 20); -/// /// assert_eq!(rcv0.try_changed(), Some(20)); +/// +/// // Get marks the value as seen +/// assert_eq!(rcv1.get().await, 20); /// assert_eq!(rcv1.try_changed(), None); /// /// }; @@ -80,30 +76,57 @@ struct WatchState { /// A trait representing the 'inner' behavior of the `Watch`. pub trait WatchBehavior { + /// Sends a new value to the `Watch`. + fn send(&self, val: T); + + /// Clears the value of the `Watch`. + fn clear(&self); + /// Poll the `Watch` for the current value, **without** making it as seen. - fn inner_poll_peek(&self, cx: &mut Context<'_>) -> Poll; + fn poll_peek(&self, cx: &mut Context<'_>) -> Poll; /// Tries to peek the value of the `Watch`, **without** marking it as seen. - fn inner_try_peek(&self) -> Option; + fn try_peek(&self) -> Option; /// Poll the `Watch` for the current value, making it as seen. - fn inner_poll_get(&self, id: &mut u64, cx: &mut Context<'_>) -> Poll; + fn poll_get(&self, id: &mut u64, cx: &mut Context<'_>) -> Poll; /// Tries to get the value of the `Watch`, marking it as seen. - fn inner_try_get(&self, id: &mut u64) -> Option; + fn try_get(&self, id: &mut u64) -> Option; /// Poll the `Watch` for a changed value, marking it as seen. - fn inner_poll_changed(&self, id: &mut u64, cx: &mut Context<'_>) -> Poll; + fn poll_changed(&self, id: &mut u64, cx: &mut Context<'_>) -> Poll; /// Tries to retrieve the value of the `Watch` if it has changed, marking it as seen. - fn inner_try_changed(&self, id: &mut u64) -> Option; + fn try_changed(&self, id: &mut u64) -> Option; /// Checks if the `Watch` is been initialized with a value. - fn inner_contains_value(&self) -> bool; + fn contains_value(&self) -> bool; + + /// Used when a receiver is dropped to decrement the receiver count. + /// + /// ## This method should not be called by the user. + fn drop_receiver(&self); } impl WatchBehavior for Watch { - fn inner_poll_peek(&self, cx: &mut Context<'_>) -> Poll { + fn send(&self, val: T) { + self.mutex.lock(|state| { + let mut s = state.borrow_mut(); + s.data = Some(val); + s.current_id += 1; + s.wakers.wake(); + }) + } + + fn clear(&self) { + self.mutex.lock(|state| { + let mut s = state.borrow_mut(); + s.data = None; + }) + } + + fn poll_peek(&self, cx: &mut Context<'_>) -> Poll { self.mutex.lock(|state| { let mut s = state.borrow_mut(); match &s.data { @@ -116,11 +139,11 @@ impl WatchBehavior for Watch }) } - fn inner_try_peek(&self) -> Option { + fn try_peek(&self) -> Option { self.mutex.lock(|state| state.borrow().data.clone()) } - fn inner_poll_get(&self, id: &mut u64, cx: &mut Context<'_>) -> Poll { + fn poll_get(&self, id: &mut u64, cx: &mut Context<'_>) -> Poll { self.mutex.lock(|state| { let mut s = state.borrow_mut(); match &s.data { @@ -136,7 +159,7 @@ impl WatchBehavior for Watch }) } - fn inner_try_get(&self, id: &mut u64) -> Option { + fn try_get(&self, id: &mut u64) -> Option { self.mutex.lock(|state| { let s = state.borrow(); *id = s.current_id; @@ -144,7 +167,7 @@ impl WatchBehavior for Watch }) } - fn inner_poll_changed(&self, id: &mut u64, cx: &mut Context<'_>) -> Poll { + fn poll_changed(&self, id: &mut u64, cx: &mut Context<'_>) -> Poll { self.mutex.lock(|state| { let mut s = state.borrow_mut(); match (&s.data, s.current_id > *id) { @@ -160,7 +183,7 @@ impl WatchBehavior for Watch }) } - fn inner_try_changed(&self, id: &mut u64) -> Option { + fn try_changed(&self, id: &mut u64) -> Option { self.mutex.lock(|state| { let s = state.borrow(); match s.current_id > *id { @@ -173,9 +196,16 @@ impl WatchBehavior for Watch }) } - fn inner_contains_value(&self) -> bool { + fn contains_value(&self) -> bool { self.mutex.lock(|state| state.borrow().data.is_some()) } + + fn drop_receiver(&self) { + self.mutex.lock(|state| { + let mut s = state.borrow_mut(); + s.receiver_count -= 1; + }) + } } #[derive(Debug)] @@ -198,14 +228,14 @@ impl<'a, M: RawMutex, T: Clone, const N: usize> Watch { } } - /// Write a new value to the `Watch`. - pub fn write(&self, val: T) { - self.mutex.lock(|state| { - let mut s = state.borrow_mut(); - s.data = Some(val); - s.current_id += 1; - s.wakers.wake(); - }) + /// Create a new [`Receiver`] for the `Watch`. + pub fn sender(&self) -> Sender<'_, M, T, N> { + Sender(Snd::new(self)) + } + + /// Create a new [`DynReceiver`] for the `Watch`. + pub fn dyn_sender(&self) -> DynSender<'_, T> { + DynSender(Snd::new(self)) } /// Create a new [`Receiver`] for the `Watch`. @@ -214,7 +244,7 @@ impl<'a, M: RawMutex, T: Clone, const N: usize> Watch { let mut s = state.borrow_mut(); if s.receiver_count < N { s.receiver_count += 1; - Ok(Receiver(Rcv::new(self))) + Ok(Receiver(Rcv::new(self, 0))) } else { Err(Error::MaximumReceiversReached) } @@ -227,29 +257,121 @@ impl<'a, M: RawMutex, T: Clone, const N: usize> Watch { let mut s = state.borrow_mut(); if s.receiver_count < N { s.receiver_count += 1; - Ok(DynReceiver(Rcv::new(self))) + Ok(DynReceiver(Rcv::new(self, 0))) } else { Err(Error::MaximumReceiversReached) } }) } +} + +/// A receiver can `.await` a change in the `Watch` value. +pub struct Snd<'a, T: Clone, W: WatchBehavior + ?Sized> { + watch: &'a W, + _phantom: PhantomData, +} + +impl<'a, T: Clone, W: WatchBehavior + ?Sized> Clone for Snd<'a, T, W> { + fn clone(&self) -> Self { + Self { + watch: self.watch, + _phantom: PhantomData, + } + } +} + +impl<'a, T: Clone, W: WatchBehavior + ?Sized> Snd<'a, T, W> { + /// Creates a new `Receiver` with a reference to the `Watch`. + fn new(watch: &'a W) -> Self { + Self { + watch, + _phantom: PhantomData, + } + } + + /// Sends a new value to the `Watch`. + pub fn send(&self, val: T) { + self.watch.send(val) + } + + /// Clears the value of the `Watch`. + /// This will cause calls to [`Rcv::get`] and [`Rcv::peek`] to be pending. + pub fn clear(&self) { + self.watch.clear() + } /// Tries to retrieve the value of the `Watch`. pub fn try_peek(&self) -> Option { - self.inner_try_peek() + self.watch.try_peek() } /// Returns true if the `Watch` contains a value. pub fn contains_value(&self) -> bool { - self.inner_contains_value() + self.watch.contains_value() } +} - /// Clears the value of the `Watch`. This will cause calls to [`Rcv::get`] and [`Rcv::peek`] to be pending. - pub fn clear(&self) { - self.mutex.lock(|state| { - let mut s = state.borrow_mut(); - s.data = None; - }) +/// A sender of a `Watch` channel. +/// +/// For a simpler type definition, consider [`DynSender`] at the expense of +/// some runtime performance due to dynamic dispatch. +pub struct Sender<'a, M: RawMutex, T: Clone, const N: usize>(Snd<'a, T, Watch>); + +impl<'a, M: RawMutex, T: Clone, const N: usize> Clone for Sender<'a, M, T, N> { + fn clone(&self) -> Self { + Self(self.0.clone()) + } +} + +impl<'a, M: RawMutex, T: Clone, const N: usize> Sender<'a, M, T, N> { + /// Converts the `Sender` into a [`DynSender`]. + pub fn as_dyn(self) -> DynSender<'a, T> { + DynSender(Snd::new(self.watch)) + } +} + +impl<'a, M: RawMutex, T: Clone, const N: usize> Into> for Sender<'a, M, T, N> { + fn into(self) -> DynSender<'a, T> { + self.as_dyn() + } +} + +impl<'a, M: RawMutex, T: Clone, const N: usize> Deref for Sender<'a, M, T, N> { + type Target = Snd<'a, T, Watch>; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl<'a, M: RawMutex, T: Clone, const N: usize> DerefMut for Sender<'a, M, T, N> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +/// A sender which holds a **dynamic** reference to a `Watch` channel. +/// +/// This is an alternative to [`Sender`] with a simpler type definition, +pub struct DynSender<'a, T: Clone>(Snd<'a, T, dyn WatchBehavior + 'a>); + +impl<'a, T: Clone> Clone for DynSender<'a, T> { + fn clone(&self) -> Self { + Self(self.0.clone()) + } +} + +impl<'a, T: Clone> Deref for DynSender<'a, T> { + type Target = Snd<'a, T, dyn WatchBehavior + 'a>; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl<'a, T: Clone> DerefMut for DynSender<'a, T> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 } } @@ -262,59 +384,83 @@ pub struct Rcv<'a, T: Clone, W: WatchBehavior + ?Sized> { impl<'a, T: Clone, W: WatchBehavior + ?Sized> Rcv<'a, T, W> { /// Creates a new `Receiver` with a reference to the `Watch`. - fn new(watch: &'a W) -> Self { + fn new(watch: &'a W, at_id: u64) -> Self { Self { watch, - at_id: 0, + at_id, _phantom: PhantomData, } } - /// Returns the current value of the `Watch` if it is initialized, **without** marking it as seen. + /// Returns the current value of the `Watch` once it is initialized, **without** marking it as seen. + /// + /// **Note**: Futures do nothing unless you `.await` or poll them. pub async fn peek(&self) -> T { - poll_fn(|cx| self.watch.inner_poll_peek(cx)).await + poll_fn(|cx| self.watch.poll_peek(cx)).await } /// Tries to peek the current value of the `Watch` without waiting, and **without** marking it as seen. pub fn try_peek(&self) -> Option { - self.watch.inner_try_peek() + self.watch.try_peek() } - /// Returns the current value of the `Watch` if it is initialized, marking it as seen. + /// Returns the current value of the `Watch` once it is initialized, marking it as seen. + /// + /// **Note**: Futures do nothing unless you `.await` or poll them. pub async fn get(&mut self) -> T { - poll_fn(|cx| self.watch.inner_poll_get(&mut self.at_id, cx)).await + poll_fn(|cx| self.watch.poll_get(&mut self.at_id, cx)).await } /// Tries to get the current value of the `Watch` without waiting, marking it as seen. pub fn try_get(&mut self) -> Option { - self.watch.inner_try_get(&mut self.at_id) + self.watch.try_get(&mut self.at_id) } /// Waits for the `Watch` to change and returns the new value, marking it as seen. + /// + /// **Note**: Futures do nothing unless you `.await` or poll them. pub async fn changed(&mut self) -> T { - poll_fn(|cx| self.watch.inner_poll_changed(&mut self.at_id, cx)).await + poll_fn(|cx| self.watch.poll_changed(&mut self.at_id, cx)).await } /// Tries to get the new value of the watch without waiting, marking it as seen. pub fn try_changed(&mut self) -> Option { - self.watch.inner_try_changed(&mut self.at_id) + self.watch.try_changed(&mut self.at_id) } /// Checks if the `Watch` contains a value. If this returns true, /// then awaiting [`Rcv::get`] and [`Rcv::peek`] will return immediately. pub fn contains_value(&self) -> bool { - self.watch.inner_contains_value() + self.watch.contains_value() + } +} + +impl<'a, T: Clone, W: WatchBehavior + ?Sized> Drop for Rcv<'a, T, W> { + fn drop(&mut self) { + self.watch.drop_receiver(); } } /// A receiver of a `Watch` channel. pub struct Receiver<'a, M: RawMutex, T: Clone, const N: usize>(Rcv<'a, T, Watch>); -/// A receiver which holds a **reference** to a `Watch` channel. -/// -/// This is an alternative to [`Receiver`] with a simpler type definition, at the expense of -/// some runtime performance due to dynamic dispatch. -pub struct DynReceiver<'a, T: Clone>(Rcv<'a, T, dyn WatchBehavior + 'a>); +impl<'a, M: RawMutex, T: Clone, const N: usize> Receiver<'a, M, T, N> { + /// Converts the `Receiver` into a [`DynReceiver`]. + pub fn as_dyn(self) -> DynReceiver<'a, T> { + // We need to increment the receiver count since the original + // receiver is being dropped, which decrements the count. + self.watch.mutex.lock(|state| { + state.borrow_mut().receiver_count += 1; + }); + DynReceiver(Rcv::new(self.0.watch, self.at_id)) + } +} + +impl<'a, M: RawMutex, T: Clone, const N: usize> Into> for Receiver<'a, M, T, N> { + fn into(self) -> DynReceiver<'a, T> { + self.as_dyn() + } +} impl<'a, M: RawMutex, T: Clone, const N: usize> Deref for Receiver<'a, M, T, N> { type Target = Rcv<'a, T, Watch>; @@ -330,6 +476,12 @@ impl<'a, M: RawMutex, T: Clone, const N: usize> DerefMut for Receiver<'a, M, T, } } +/// A receiver which holds a **dynamic** reference to a `Watch` channel. +/// +/// This is an alternative to [`Receiver`] with a simpler type definition, at the expense of +/// some runtime performance due to dynamic dispatch. +pub struct DynReceiver<'a, T: Clone>(Rcv<'a, T, dyn WatchBehavior + 'a>); + impl<'a, T: Clone> Deref for DynReceiver<'a, T> { type Target = Rcv<'a, T, dyn WatchBehavior + 'a>; @@ -348,167 +500,242 @@ impl<'a, T: Clone> DerefMut for DynReceiver<'a, T> { mod tests { use futures_executor::block_on; - use super::*; + use super::Watch; use crate::blocking_mutex::raw::CriticalSectionRawMutex; #[test] - fn multiple_writes() { + fn multiple_sends() { let f = async { - static WATCH: Watch = Watch::new(); + static WATCH: Watch = Watch::new(); - // Obtain Receivers - let mut rcv0 = WATCH.receiver().unwrap(); - let mut rcv1 = WATCH.dyn_receiver().unwrap(); + // Obtain receiver and sender + let mut rcv = WATCH.receiver().unwrap(); + let snd = WATCH.sender(); - WATCH.write(10); + // Not initialized + assert_eq!(rcv.try_changed(), None); // Receive the new value - assert_eq!(rcv0.changed().await, 10); - assert_eq!(rcv1.changed().await, 10); + snd.send(10); + assert_eq!(rcv.changed().await, 10); + + // Receive another value + snd.send(20); + assert_eq!(rcv.try_changed(), Some(20)); // No update - assert_eq!(rcv0.try_changed(), None); - assert_eq!(rcv1.try_changed(), None); - - WATCH.write(20); - - assert_eq!(rcv0.changed().await, 20); - assert_eq!(rcv1.changed().await, 20); + assert_eq!(rcv.try_changed(), None); }; block_on(f); } #[test] - fn max_receivers() { + fn receive_after_create() { let f = async { - static WATCH: Watch = Watch::new(); + static WATCH: Watch = Watch::new(); - // Obtain Receivers - let _ = WATCH.receiver().unwrap(); - let _ = WATCH.receiver().unwrap(); - assert!(WATCH.receiver().is_err()); + // Obtain sender and send value + let snd = WATCH.sender(); + snd.send(10); + + // Obtain receiver and receive value + let mut rcv = WATCH.receiver().unwrap(); + assert_eq!(rcv.try_changed(), Some(10)); }; block_on(f); } #[test] - fn receive_initial() { + fn max_receivers_drop() { let f = async { static WATCH: Watch = Watch::new(); - // Obtain Receivers + // Try to create 3 receivers (only 2 can exist at once) + let rcv0 = WATCH.receiver(); + let rcv1 = WATCH.receiver(); + let rcv2 = WATCH.receiver(); + + // Ensure the first two are successful and the third is not + assert!(rcv0.is_ok()); + assert!(rcv1.is_ok()); + assert!(rcv2.is_err()); + + // Drop the first receiver + drop(rcv0); + + // Create another receiver and ensure it is successful + let rcv3 = WATCH.receiver(); + assert!(rcv3.is_ok()); + }; + block_on(f); + } + + #[test] + fn multiple_receivers() { + let f = async { + static WATCH: Watch = Watch::new(); + + // Obtain receivers and sender let mut rcv0 = WATCH.receiver().unwrap(); let mut rcv1 = WATCH.receiver().unwrap(); + let snd = WATCH.sender(); - assert_eq!(rcv0.contains_value(), false); - + // No update for both assert_eq!(rcv0.try_changed(), None); assert_eq!(rcv1.try_changed(), None); - WATCH.write(0); - - assert_eq!(rcv0.contains_value(), true); + // Send a new value + snd.send(0); + // Both receivers receive the new value assert_eq!(rcv0.try_changed(), Some(0)); assert_eq!(rcv1.try_changed(), Some(0)); }; block_on(f); } + #[test] + fn clone_senders() { + let f = async { + // Obtain different ways to send + static WATCH: Watch = Watch::new(); + let snd0 = WATCH.sender(); + let snd1 = snd0.clone(); + + // Obtain Receiver + let mut rcv = WATCH.receiver().unwrap().as_dyn(); + + // Send a value from first sender + snd0.send(10); + assert_eq!(rcv.try_changed(), Some(10)); + + // Send a value from second sender + snd1.send(20); + assert_eq!(rcv.try_changed(), Some(20)); + }; + block_on(f); + } + #[test] fn peek_get_changed() { let f = async { static WATCH: Watch = Watch::new(); - // Obtain Receivers - let mut rcv0 = WATCH.receiver().unwrap(); + // Obtain receiver and sender + let mut rcv = WATCH.receiver().unwrap(); + let snd = WATCH.sender(); - WATCH.write(10); + // Send a value + snd.send(10); // Ensure peek does not mark as seen - assert_eq!(rcv0.peek().await, 10); - assert_eq!(rcv0.try_changed(), Some(10)); - assert_eq!(rcv0.try_changed(), None); - assert_eq!(rcv0.peek().await, 10); + assert_eq!(rcv.peek().await, 10); + assert_eq!(rcv.try_changed(), Some(10)); + assert_eq!(rcv.try_changed(), None); + assert_eq!(rcv.try_peek(), Some(10)); - WATCH.write(20); + // Send a value + snd.send(20); // Ensure get does mark as seen - assert_eq!(rcv0.get().await, 20); - assert_eq!(rcv0.try_changed(), None); - assert_eq!(rcv0.try_get(), Some(20)); + assert_eq!(rcv.get().await, 20); + assert_eq!(rcv.try_changed(), None); + assert_eq!(rcv.try_get(), Some(20)); }; block_on(f); } #[test] - fn count_ids() { + fn use_dynamics() { let f = async { static WATCH: Watch = Watch::new(); - // Obtain Receivers - let mut rcv0 = WATCH.receiver().unwrap(); - let mut rcv1 = WATCH.receiver().unwrap(); + // Obtain receiver and sender + let mut dyn_rcv = WATCH.dyn_receiver().unwrap(); + let dyn_snd = WATCH.dyn_sender(); - let get_id = || WATCH.mutex.lock(|state| state.borrow().current_id); + // Send a value + dyn_snd.send(10); - WATCH.write(10); - - assert_eq!(rcv0.changed().await, 10); - assert_eq!(rcv1.changed().await, 10); - - assert_eq!(rcv0.try_changed(), None); - assert_eq!(rcv1.try_changed(), None); - - WATCH.write(20); - WATCH.write(20); - WATCH.write(20); - - assert_eq!(rcv0.changed().await, 20); - assert_eq!(rcv1.changed().await, 20); - - assert_eq!(rcv0.try_changed(), None); - assert_eq!(rcv1.try_changed(), None); - - assert_eq!(get_id(), 4); + // Ensure the dynamic receiver receives the value + assert_eq!(dyn_rcv.try_changed(), Some(10)); + assert_eq!(dyn_rcv.try_changed(), None); }; block_on(f); } #[test] - fn peek_still_await() { + fn convert_to_dyn() { let f = async { static WATCH: Watch = Watch::new(); - // Obtain Receivers - let mut rcv0 = WATCH.receiver().unwrap(); - let mut rcv1 = WATCH.receiver().unwrap(); + // Obtain receiver and sender + let rcv = WATCH.receiver().unwrap(); + let snd = WATCH.sender(); - WATCH.write(10); + // Convert to dynamic + let mut dyn_rcv = rcv.as_dyn(); + let dyn_snd = snd.as_dyn(); - assert_eq!(rcv0.peek().await, 10); - assert_eq!(rcv1.try_peek(), Some(10)); + // Send a value + dyn_snd.send(10); - assert_eq!(rcv0.changed().await, 10); - assert_eq!(rcv1.changed().await, 10); + // Ensure the dynamic receiver receives the value + assert_eq!(dyn_rcv.try_changed(), Some(10)); + assert_eq!(dyn_rcv.try_changed(), None); }; block_on(f); } #[test] - fn peek_with_static() { + fn dynamic_receiver_count() { let f = async { static WATCH: Watch = Watch::new(); - // Obtain Receivers - let rcv0 = WATCH.receiver().unwrap(); - let rcv1 = WATCH.receiver().unwrap(); + // Obtain receiver and sender + let rcv0 = WATCH.receiver(); + let rcv1 = WATCH.receiver(); + let rcv2 = WATCH.receiver(); - WATCH.write(20); + // Ensure the first two are successful and the third is not + assert!(rcv0.is_ok()); + assert!(rcv1.is_ok()); + assert!(rcv2.is_err()); - assert_eq!(rcv0.peek().await, 20); - assert_eq!(rcv1.peek().await, 20); - assert_eq!(WATCH.try_peek(), Some(20)); + // Convert to dynamic + let dyn_rcv0 = rcv0.unwrap().as_dyn(); + + // Drop the (now dynamic) receiver + drop(dyn_rcv0); + + // Create another receiver and ensure it is successful + let rcv3 = WATCH.receiver(); + let rcv4 = WATCH.receiver(); + assert!(rcv3.is_ok()); + assert!(rcv4.is_err()); + }; + block_on(f); + } + + #[test] + fn contains_value() { + let f = async { + static WATCH: Watch = Watch::new(); + + // Obtain receiver and sender + let rcv = WATCH.receiver().unwrap(); + let snd = WATCH.sender(); + + // check if the watch contains a value + assert_eq!(rcv.contains_value(), false); + assert_eq!(snd.contains_value(), false); + + // Send a value + snd.send(10); + + // check if the watch contains a value + assert_eq!(rcv.contains_value(), true); + assert_eq!(snd.contains_value(), true); }; block_on(f); } From 3208e0fec4717ff1580d1cc0cf93e18cbba2db91 Mon Sep 17 00:00:00 2001 From: Peter Krull Date: Thu, 29 Feb 2024 16:56:52 +0100 Subject: [PATCH 0008/1217] Use Option instead of Result for receiver creation since it is the only way it can fail. --- embassy-sync/src/watch.rs | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/embassy-sync/src/watch.rs b/embassy-sync/src/watch.rs index 3e22b1e7b..2bba93915 100644 --- a/embassy-sync/src/watch.rs +++ b/embassy-sync/src/watch.rs @@ -208,14 +208,7 @@ impl WatchBehavior for Watch } } -#[derive(Debug)] -/// An error that can occur when a `Watch` returns a `Result::Err(_)`. -pub enum Error { - /// The maximum number of [`Receiver`](crate::watch::Receiver)/[`DynReceiver`](crate::watch::DynReceiver) has been reached. - MaximumReceiversReached, -} - -impl<'a, M: RawMutex, T: Clone, const N: usize> Watch { +impl Watch { /// Create a new `Watch` channel. pub const fn new() -> Self { Self { @@ -238,28 +231,30 @@ impl<'a, M: RawMutex, T: Clone, const N: usize> Watch { DynSender(Snd::new(self)) } - /// Create a new [`Receiver`] for the `Watch`. - pub fn receiver(&self) -> Result, Error> { + /// Try to create a new [`Receiver`] for the `Watch`. If the + /// maximum number of receivers has been reached, `None` is returned. + pub fn receiver(&self) -> Option> { self.mutex.lock(|state| { let mut s = state.borrow_mut(); if s.receiver_count < N { s.receiver_count += 1; - Ok(Receiver(Rcv::new(self, 0))) + Some(Receiver(Rcv::new(self, 0))) } else { - Err(Error::MaximumReceiversReached) + None } }) } - /// Create a new [`DynReceiver`] for the `Watch`. - pub fn dyn_receiver(&self) -> Result, Error> { + /// Try to create a new [`DynReceiver`] for the `Watch`. If the + /// maximum number of receivers has been reached, `None` is returned. + pub fn dyn_receiver(&self) -> Option> { self.mutex.lock(|state| { let mut s = state.borrow_mut(); if s.receiver_count < N { s.receiver_count += 1; - Ok(DynReceiver(Rcv::new(self, 0))) + Some(DynReceiver(Rcv::new(self, 0))) } else { - Err(Error::MaximumReceiversReached) + None } }) } From c08e75057a4282a0dfee13a6e181a2077944c1b0 Mon Sep 17 00:00:00 2001 From: Peter Krull Date: Thu, 29 Feb 2024 16:58:21 +0100 Subject: [PATCH 0009/1217] Update tests to reflect changes in previous commit --- embassy-sync/src/watch.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/embassy-sync/src/watch.rs b/embassy-sync/src/watch.rs index 2bba93915..1301eb817 100644 --- a/embassy-sync/src/watch.rs +++ b/embassy-sync/src/watch.rs @@ -551,16 +551,16 @@ mod tests { let rcv2 = WATCH.receiver(); // Ensure the first two are successful and the third is not - assert!(rcv0.is_ok()); - assert!(rcv1.is_ok()); - assert!(rcv2.is_err()); + assert!(rcv0.is_some()); + assert!(rcv1.is_some()); + assert!(rcv2.is_none()); // Drop the first receiver drop(rcv0); // Create another receiver and ensure it is successful let rcv3 = WATCH.receiver(); - assert!(rcv3.is_ok()); + assert!(rcv3.is_some()); }; block_on(f); } @@ -693,9 +693,9 @@ mod tests { let rcv2 = WATCH.receiver(); // Ensure the first two are successful and the third is not - assert!(rcv0.is_ok()); - assert!(rcv1.is_ok()); - assert!(rcv2.is_err()); + assert!(rcv0.is_some()); + assert!(rcv1.is_some()); + assert!(rcv2.is_none()); // Convert to dynamic let dyn_rcv0 = rcv0.unwrap().as_dyn(); @@ -706,8 +706,8 @@ mod tests { // Create another receiver and ensure it is successful let rcv3 = WATCH.receiver(); let rcv4 = WATCH.receiver(); - assert!(rcv3.is_ok()); - assert!(rcv4.is_err()); + assert!(rcv3.is_some()); + assert!(rcv4.is_none()); }; block_on(f); } From df282aa23d00b2f3116081be2b07ba0c9f810fc3 Mon Sep 17 00:00:00 2001 From: Peter Krull Date: Thu, 29 Feb 2024 16:59:58 +0100 Subject: [PATCH 0010/1217] Forgot to update doc comment --- embassy-sync/src/watch.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-sync/src/watch.rs b/embassy-sync/src/watch.rs index 1301eb817..01d82def4 100644 --- a/embassy-sync/src/watch.rs +++ b/embassy-sync/src/watch.rs @@ -37,7 +37,7 @@ use crate::waitqueue::MultiWakerRegistration; /// let mut snd = WATCH.sender(); /// /// // No more receivers, and no update -/// assert!(WATCH.receiver().is_err()); +/// assert!(WATCH.receiver().is_none()); /// assert_eq!(rcv1.try_changed(), None); /// /// snd.send(10); From 311ab07a9af0029060813779038220481d1bf1c5 Mon Sep 17 00:00:00 2001 From: Peter Krull Date: Sat, 2 Mar 2024 00:14:11 +0100 Subject: [PATCH 0011/1217] Reintroduce predicate methods. Add ability for sender to modify value in-place. --- embassy-sync/src/watch.rs | 267 +++++++++++++++++++++++++++++++++++++- 1 file changed, 260 insertions(+), 7 deletions(-) diff --git a/embassy-sync/src/watch.rs b/embassy-sync/src/watch.rs index 01d82def4..520696f7d 100644 --- a/embassy-sync/src/watch.rs +++ b/embassy-sync/src/watch.rs @@ -88,21 +88,48 @@ pub trait WatchBehavior { /// Tries to peek the value of the `Watch`, **without** marking it as seen. fn try_peek(&self) -> Option; + /// Poll the `Watch` for the value if it matches the predicate function + /// `f`, **without** making it as seen. + fn poll_peek_and(&self, f: &mut dyn Fn(&T) -> bool, cx: &mut Context<'_>) -> Poll; + + /// Tries to peek the value of the `Watch` if it matches the predicate function `f`, **without** marking it as seen. + fn try_peek_and(&self, f: &mut dyn Fn(&T) -> bool) -> Option; + /// Poll the `Watch` for the current value, making it as seen. fn poll_get(&self, id: &mut u64, cx: &mut Context<'_>) -> Poll; /// Tries to get the value of the `Watch`, marking it as seen. fn try_get(&self, id: &mut u64) -> Option; + /// Poll the `Watch` for the value if it matches the predicate function + /// `f`, making it as seen. + fn poll_get_and(&self, id: &mut u64, f: &mut dyn Fn(&T) -> bool, cx: &mut Context<'_>) -> Poll; + + /// Tries to get the value of the `Watch` if it matches the predicate function + /// `f`, marking it as seen. + fn try_get_and(&self, id: &mut u64, f: &mut dyn Fn(&T) -> bool) -> Option; + /// Poll the `Watch` for a changed value, marking it as seen. fn poll_changed(&self, id: &mut u64, cx: &mut Context<'_>) -> Poll; /// Tries to retrieve the value of the `Watch` if it has changed, marking it as seen. fn try_changed(&self, id: &mut u64) -> Option; + /// Poll the `Watch` for a changed value that matches the predicate function + /// `f`, marking it as seen. + fn poll_changed_and(&self, id: &mut u64, f: &mut dyn Fn(&T) -> bool, cx: &mut Context<'_>) -> Poll; + + /// Tries to retrieve the value of the `Watch` if it has changed and matches the + /// predicate function `f`, marking it as seen. + fn try_changed_and(&self, id: &mut u64, f: &mut dyn Fn(&T) -> bool) -> Option; + /// Checks if the `Watch` is been initialized with a value. fn contains_value(&self) -> bool; + /// Modify the value of the `Watch` using a closure. Returns `false` if the + /// `Watch` does not already contain a value. + fn modify(&self, f: &mut dyn Fn(&mut Option)); + /// Used when a receiver is dropped to decrement the receiver count. /// /// ## This method should not be called by the user. @@ -143,6 +170,29 @@ impl WatchBehavior for Watch self.mutex.lock(|state| state.borrow().data.clone()) } + fn poll_peek_and(&self, f: &mut dyn Fn(&T) -> bool, cx: &mut Context<'_>) -> Poll { + self.mutex.lock(|state| { + let mut s = state.borrow_mut(); + match s.data { + Some(ref data) if f(data) => Poll::Ready(data.clone()), + _ => { + s.wakers.register(cx.waker()); + Poll::Pending + } + } + }) + } + + fn try_peek_and(&self, f: &mut dyn Fn(&T) -> bool) -> Option { + self.mutex.lock(|state| { + let s = state.borrow(); + match s.data { + Some(ref data) if f(data) => Some(data.clone()), + _ => None, + } + }) + } + fn poll_get(&self, id: &mut u64, cx: &mut Context<'_>) -> Poll { self.mutex.lock(|state| { let mut s = state.borrow_mut(); @@ -167,6 +217,35 @@ impl WatchBehavior for Watch }) } + fn poll_get_and(&self, id: &mut u64, f: &mut dyn Fn(&T) -> bool, cx: &mut Context<'_>) -> Poll { + self.mutex.lock(|state| { + let mut s = state.borrow_mut(); + match s.data { + Some(ref data) if f(data) => { + *id = s.current_id; + Poll::Ready(data.clone()) + } + _ => { + s.wakers.register(cx.waker()); + Poll::Pending + } + } + }) + } + + fn try_get_and(&self, id: &mut u64, f: &mut dyn Fn(&T) -> bool) -> Option { + self.mutex.lock(|state| { + let s = state.borrow(); + match s.data { + Some(ref data) if f(data) => { + *id = s.current_id; + Some(data.clone()) + } + _ => None, + } + }) + } + fn poll_changed(&self, id: &mut u64, cx: &mut Context<'_>) -> Poll { self.mutex.lock(|state| { let mut s = state.borrow_mut(); @@ -189,13 +268,42 @@ impl WatchBehavior for Watch match s.current_id > *id { true => { *id = s.current_id; - state.borrow().data.clone() + s.data.clone() } false => None, } }) } + fn poll_changed_and(&self, id: &mut u64, f: &mut dyn Fn(&T) -> bool, cx: &mut Context<'_>) -> Poll { + self.mutex.lock(|state| { + let mut s = state.borrow_mut(); + match (&s.data, s.current_id > *id) { + (Some(data), true) if f(data) => { + *id = s.current_id; + Poll::Ready(data.clone()) + } + _ => { + s.wakers.register(cx.waker()); + Poll::Pending + } + } + }) + } + + fn try_changed_and(&self, id: &mut u64, f: &mut dyn Fn(&T) -> bool) -> Option { + self.mutex.lock(|state| { + let s = state.borrow(); + match (&s.data, s.current_id > *id) { + (Some(data), true) if f(data) => { + *id = s.current_id; + s.data.clone() + } + _ => None, + } + }) + } + fn contains_value(&self) -> bool { self.mutex.lock(|state| state.borrow().data.is_some()) } @@ -206,6 +314,15 @@ impl WatchBehavior for Watch s.receiver_count -= 1; }) } + + fn modify(&self, f: &mut dyn Fn(&mut Option)) { + self.mutex.lock(|state| { + let mut s = state.borrow_mut(); + f(&mut s.data); + s.current_id += 1; + s.wakers.wake(); + }) + } } impl Watch { @@ -300,10 +417,27 @@ impl<'a, T: Clone, W: WatchBehavior + ?Sized> Snd<'a, T, W> { self.watch.try_peek() } + /// Tries to peek the current value of the `Watch` if it matches the predicate + /// function `f`. + pub fn try_peek_and(&self, mut f: F) -> Option + where + F: Fn(&T) -> bool, + { + self.watch.try_peek_and(&mut f) + } + /// Returns true if the `Watch` contains a value. pub fn contains_value(&self) -> bool { self.watch.contains_value() } + + /// Modify the value of the `Watch` using a closure. + pub fn modify(&self, mut f: F) + where + F: Fn(&mut Option), + { + self.watch.modify(&mut f) + } } /// A sender of a `Watch` channel. @@ -399,6 +533,26 @@ impl<'a, T: Clone, W: WatchBehavior + ?Sized> Rcv<'a, T, W> { self.watch.try_peek() } + /// Returns the current value of the `Watch` if it matches the predicate function `f`, + /// or waits for it to match, **without** marking it as seen. + /// + /// **Note**: Futures do nothing unless you `.await` or poll them. + pub async fn peek_and(&self, mut f: F) -> T + where + F: Fn(&T) -> bool, + { + poll_fn(|cx| self.watch.poll_peek_and(&mut f, cx)).await + } + + /// Tries to peek the current value of the `Watch` if it matches the predicate + /// function `f` without waiting, and **without** marking it as seen. + pub fn try_peek_and(&self, mut f: F) -> Option + where + F: Fn(&T) -> bool, + { + self.watch.try_peek_and(&mut f) + } + /// Returns the current value of the `Watch` once it is initialized, marking it as seen. /// /// **Note**: Futures do nothing unless you `.await` or poll them. @@ -411,6 +565,26 @@ impl<'a, T: Clone, W: WatchBehavior + ?Sized> Rcv<'a, T, W> { self.watch.try_get(&mut self.at_id) } + /// Returns the value of the `Watch` if it matches the predicate function `f`, + /// or waits for it to match, marking it as seen. + /// + /// **Note**: Futures do nothing unless you `.await` or poll them. + pub async fn get_and(&mut self, mut f: F) -> T + where + F: Fn(&T) -> bool, + { + poll_fn(|cx| self.watch.poll_get_and(&mut self.at_id, &mut f, cx)).await + } + + /// Tries to get the current value of the `Watch` if it matches the predicate + /// function `f` without waiting, marking it as seen. + pub fn try_get_and(&mut self, mut f: F) -> Option + where + F: Fn(&T) -> bool, + { + self.watch.try_get_and(&mut self.at_id, &mut f) + } + /// Waits for the `Watch` to change and returns the new value, marking it as seen. /// /// **Note**: Futures do nothing unless you `.await` or poll them. @@ -423,6 +597,26 @@ impl<'a, T: Clone, W: WatchBehavior + ?Sized> Rcv<'a, T, W> { self.watch.try_changed(&mut self.at_id) } + /// Waits for the `Watch` to change to a value which satisfies the predicate + /// function `f` and returns the new value, marking it as seen. + /// + /// **Note**: Futures do nothing unless you `.await` or poll them. + pub async fn changed_and(&mut self, mut f: F) -> T + where + F: Fn(&T) -> bool, + { + poll_fn(|cx| self.watch.poll_changed_and(&mut self.at_id, &mut f, cx)).await + } + + /// Tries to get the new value of the watch which satisfies the predicate + /// function `f` and returns the new value without waiting, marking it as seen. + pub fn try_changed_and(&mut self, mut f: F) -> Option + where + F: Fn(&T) -> bool, + { + self.watch.try_changed_and(&mut self.at_id, &mut f) + } + /// Checks if the `Watch` contains a value. If this returns true, /// then awaiting [`Rcv::get`] and [`Rcv::peek`] will return immediately. pub fn contains_value(&self) -> bool { @@ -442,12 +636,9 @@ pub struct Receiver<'a, M: RawMutex, T: Clone, const N: usize>(Rcv<'a, T, Watch< impl<'a, M: RawMutex, T: Clone, const N: usize> Receiver<'a, M, T, N> { /// Converts the `Receiver` into a [`DynReceiver`]. pub fn as_dyn(self) -> DynReceiver<'a, T> { - // We need to increment the receiver count since the original - // receiver is being dropped, which decrements the count. - self.watch.mutex.lock(|state| { - state.borrow_mut().receiver_count += 1; - }); - DynReceiver(Rcv::new(self.0.watch, self.at_id)) + let rcv = DynReceiver(Rcv::new(self.0.watch, self.at_id)); + core::mem::forget(self); // Ensures the destructor is not called + rcv } } @@ -524,6 +715,68 @@ mod tests { block_on(f); } + #[test] + fn sender_modify() { + let f = async { + static WATCH: Watch = Watch::new(); + + // Obtain receiver and sender + let mut rcv = WATCH.receiver().unwrap(); + let snd = WATCH.sender(); + + // Receive the new value + snd.send(10); + assert_eq!(rcv.try_changed(), Some(10)); + + // Modify the value inplace + snd.modify(|opt|{ + if let Some(inner) = opt { + *inner += 5; + } + }); + + // Get the modified value + assert_eq!(rcv.try_changed(), Some(15)); + assert_eq!(rcv.try_changed(), None); + }; + block_on(f); + } + + #[test] + fn predicate_fn() { + let f = async { + static WATCH: Watch = Watch::new(); + + // Obtain receiver and sender + let mut rcv = WATCH.receiver().unwrap(); + let snd = WATCH.sender(); + + snd.send(10); + assert_eq!(rcv.try_peek_and(|x| x > &5), Some(10)); + assert_eq!(rcv.try_peek_and(|x| x < &5), None); + assert!(rcv.try_changed().is_some()); + + snd.send(15); + assert_eq!(rcv.try_get_and(|x| x > &5), Some(15)); + assert_eq!(rcv.try_get_and(|x| x < &5), None); + assert!(rcv.try_changed().is_none()); + + snd.send(20); + assert_eq!(rcv.try_changed_and(|x| x > &5), Some(20)); + assert_eq!(rcv.try_changed_and(|x| x > &5), None); + + snd.send(25); + assert_eq!(rcv.try_changed_and(|x| x < &5), None); + assert_eq!(rcv.try_changed(), Some(25)); + + snd.send(30); + assert_eq!(rcv.changed_and(|x| x > &5).await, 30); + assert_eq!(rcv.peek_and(|x| x > &5).await, 30); + assert_eq!(rcv.get_and(|x| x > &5).await, 30); + }; + block_on(f); + } + #[test] fn receive_after_create() { let f = async { From e02a987bafd4f0fcf9d80e7c4f6e1504b8b02cec Mon Sep 17 00:00:00 2001 From: Peter Krull Date: Sat, 2 Mar 2024 00:16:17 +0100 Subject: [PATCH 0012/1217] This one is for cargo fmt --- embassy-sync/src/watch.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-sync/src/watch.rs b/embassy-sync/src/watch.rs index 520696f7d..298c09d43 100644 --- a/embassy-sync/src/watch.rs +++ b/embassy-sync/src/watch.rs @@ -729,7 +729,7 @@ mod tests { assert_eq!(rcv.try_changed(), Some(10)); // Modify the value inplace - snd.modify(|opt|{ + snd.modify(|opt| { if let Some(inner) = opt { *inner += 5; } From f01ffbcc12c40c68a57bc2daffdfad697bc28921 Mon Sep 17 00:00:00 2001 From: Chen Yuheng <1016867898@qq.com> Date: Thu, 11 Jul 2024 10:33:43 +0800 Subject: [PATCH 0013/1217] Add oversampling and differential for g4 --- embassy-stm32/src/adc/g4.rs | 60 ++++++++++++++++++++ embassy-stm32/src/adc/mod.rs | 1 + examples/stm32g4/src/bin/adc_differential.rs | 47 +++++++++++++++ examples/stm32g4/src/bin/adc_oversampling.rs | 57 +++++++++++++++++++ 4 files changed, 165 insertions(+) create mode 100644 examples/stm32g4/src/bin/adc_differential.rs create mode 100644 examples/stm32g4/src/bin/adc_oversampling.rs diff --git a/embassy-stm32/src/adc/g4.rs b/embassy-stm32/src/adc/g4.rs index c1e584f59..896a70578 100644 --- a/embassy-stm32/src/adc/g4.rs +++ b/embassy-stm32/src/adc/g4.rs @@ -1,4 +1,8 @@ #[allow(unused)] + +#[cfg(stm32g4)] +use pac::adc::vals::{Adcaldif, Difsel, Exten, Rovsm, Trovs}; +#[cfg(stm32h7)] use pac::adc::vals::{Adcaldif, Difsel, Exten}; use pac::adccommon::vals::Presc; @@ -228,6 +232,62 @@ impl<'d, T: Instance> Adc<'d, T> { Vbat {} } + /// Enable differential channel. + /// Caution: + /// : When configuring the channel “i†in differential input mode, its negative input voltage VINN[i] + /// is connected to another channel. As a consequence, this channel is no longer usable in + /// single-ended mode or in differential mode and must never be configured to be converted. + /// Some channels are shared between ADC1/ADC2/ADC3/ADC4/ADC5: this can make the + /// channel on the other ADC unusable. The only exception is when ADC master and the slave + /// operate in interleaved mode. + #[cfg(stm32g4)] + pub fn set_differential_channel(&mut self, ch: usize ,enable: bool) { + T::regs().cr().modify(|w| w.set_aden(false)); // disable adc + T::regs().difsel().modify(|w| { + w.set_difsel(ch, if enable { Difsel::DIFFERENTIAL } else { Difsel::SINGLEENDED }); + }); + T::regs().cr().modify(|w| w.set_aden(true)); + } + + #[cfg(stm32g4)] + pub fn set_differential(&mut self, channel: &mut impl AdcChannel, enable: bool) { + self.set_differential_channel(channel.channel() as usize, enable); + } + + /// Set oversampling shift. + #[cfg(stm32g4)] + pub fn set_oversampling_shift(&mut self, shift: u8) { + T::regs().cfgr2().modify(|reg| reg.set_ovss(shift)); + } + + /// Set oversampling ratio. + #[cfg(stm32g4)] + pub fn set_oversampling_ratio(&mut self, ratio: u8) { + T::regs().cfgr2().modify(|reg| reg.set_ovsr(ratio)); + } + + /// Enable oversampling in regular mode. + #[cfg(stm32g4)] + pub fn enable_regular_oversampling_mode(&mut self,mode:Rovsm,trig_mode:Trovs, enable: bool) { + T::regs().cfgr2().modify(|reg| reg.set_trovs(trig_mode)); + T::regs().cfgr2().modify(|reg| reg.set_rovsm(mode)); + T::regs().cfgr2().modify(|reg| reg.set_rovse(enable)); + } + + // Reads that are not implemented as INJECTED in "blocking_read" + // #[cfg(stm32g4)] + // pub fn enalble_injected_oversampling_mode(&mut self, enable: bool) { + // T::regs().cfgr2().modify(|reg| reg.set_jovse(enable)); + // } + + // #[cfg(stm32g4)] + // pub fn enable_oversampling_regular_injected_mode(&mut self, enable: bool) { + // // the regularoversampling mode is forced to resumed mode (ROVSM bit ignored), + // T::regs().cfgr2().modify(|reg| reg.set_rovse(enable)); + // T::regs().cfgr2().modify(|reg| reg.set_jovse(enable)); + // } + + /// Set the ADC sample time. pub fn set_sample_time(&mut self, sample_time: SampleTime) { self.sample_time = sample_time; diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index 7a7d7cd8e..b530bb4c8 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs @@ -26,6 +26,7 @@ use embassy_sync::waitqueue::AtomicWaker; #[cfg(not(any(adc_f1, adc_f3_v2)))] pub use crate::pac::adc::vals::Res as Resolution; pub use crate::pac::adc::vals::SampleTime; +pub use crate::pac::adc::vals ; use crate::peripherals; dma_trait!(RxDma, Instance); diff --git a/examples/stm32g4/src/bin/adc_differential.rs b/examples/stm32g4/src/bin/adc_differential.rs new file mode 100644 index 000000000..78d071d45 --- /dev/null +++ b/examples/stm32g4/src/bin/adc_differential.rs @@ -0,0 +1,47 @@ +//! adc differential mode example +//! +//! This example uses adc1 in differential mode +//! p:pa0 n:pa1 + +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::adc::{Adc, SampleTime}; +use embassy_stm32::Config; +use embassy_time::Timer; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let mut config = Config::default(); + { + use embassy_stm32::rcc::*; + config.rcc.pll = Some(Pll { + source: PllSource::HSI, + prediv: PllPreDiv::DIV4, + mul: PllMul::MUL85, + divp: None, + divq: None, + // Main system clock at 170 MHz + divr: Some(PllRDiv::DIV2), + }); + config.rcc.mux.adc12sel = mux::Adcsel::SYS; + config.rcc.sys = Sysclk::PLL1_R; + } + let mut p = embassy_stm32::init(config); + + let mut adc = Adc::new(p.ADC1); + adc.set_sample_time(SampleTime::CYCLES247_5); + adc.set_differential(&mut p.PA0, true); //p:pa0,n:pa1 + + // can also use + // adc.set_differential_channel(1, true); + info!("adc initialized"); + loop { + let measured = adc.blocking_read(&mut p.PA0); + info!("data: {}", measured); + Timer::after_millis(500).await; + } +} diff --git a/examples/stm32g4/src/bin/adc_oversampling.rs b/examples/stm32g4/src/bin/adc_oversampling.rs new file mode 100644 index 000000000..d31eb20f8 --- /dev/null +++ b/examples/stm32g4/src/bin/adc_oversampling.rs @@ -0,0 +1,57 @@ +//! adc oversampling example +//! +//! This example uses adc oversampling to achieve 16bit data + +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::adc::vals::{Rovsm, Trovs}; +use embassy_stm32::adc::{Adc, SampleTime}; +use embassy_stm32::Config; +use embassy_time::Timer; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let mut config = Config::default(); + { + use embassy_stm32::rcc::*; + config.rcc.pll = Some(Pll { + source: PllSource::HSI, + prediv: PllPreDiv::DIV4, + mul: PllMul::MUL85, + divp: None, + divq: None, + // Main system clock at 170 MHz + divr: Some(PllRDiv::DIV2), + }); + config.rcc.mux.adc12sel = mux::Adcsel::SYS; + config.rcc.sys = Sysclk::PLL1_R; + } + let mut p = embassy_stm32::init(config); + + let mut adc = Adc::new(p.ADC1); + adc.set_sample_time(SampleTime::CYCLES6_5); + // From https://www.st.com/resource/en/reference_manual/rm0440-stm32g4-series-advanced-armbased-32bit-mcus-stmicroelectronics.pdf + // page652 Oversampler + // Table 172. Maximum output results vs N and M. Grayed values indicates truncation + // 0x00 oversampling ratio X2 + // 0x01 oversampling ratio X4 + // 0x02 oversampling ratio X8 + // 0x03 oversampling ratio X16 + // 0x04 oversampling ratio X32 + // 0x05 oversampling ratio X64 + // 0x06 oversampling ratio X128 + // 0x07 oversampling ratio X256 + adc.set_oversampling_ratio(0x03); // ratio X3 + adc.set_oversampling_shift(0b0000); // no shift + adc.enable_regular_oversampling_mode(Rovsm::RESUMED, Trovs::AUTOMATIC, true); + + loop { + let measured = adc.blocking_read(&mut p.PA0); + info!("data: 0x{:X}", measured); //max 0xFFF0 -> 65520 + Timer::after_millis(500).await; + } +} From fd5501d455f2e2e6aab9f09767599fcb16d33937 Mon Sep 17 00:00:00 2001 From: Chen Yuheng <1016867898@qq.com> Date: Thu, 11 Jul 2024 15:34:34 +0800 Subject: [PATCH 0014/1217] delete unused "info!" and fmt --- embassy-stm32/src/adc/g4.rs | 22 ++++++++++++++-------- embassy-stm32/src/adc/mod.rs | 2 +- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/embassy-stm32/src/adc/g4.rs b/embassy-stm32/src/adc/g4.rs index 896a70578..3e9ba8ae2 100644 --- a/embassy-stm32/src/adc/g4.rs +++ b/embassy-stm32/src/adc/g4.rs @@ -1,9 +1,9 @@ #[allow(unused)] - -#[cfg(stm32g4)] -use pac::adc::vals::{Adcaldif, Difsel, Exten, Rovsm, Trovs}; #[cfg(stm32h7)] use pac::adc::vals::{Adcaldif, Difsel, Exten}; +#[allow(unused)] +#[cfg(stm32g4)] +use pac::adc::vals::{Adcaldif, Difsel, Exten, Rovsm, Trovs}; use pac::adccommon::vals::Presc; use super::{blocking_delay_us, Adc, AdcChannel, Instance, Resolution, SampleTime}; @@ -241,10 +241,17 @@ impl<'d, T: Instance> Adc<'d, T> { /// channel on the other ADC unusable. The only exception is when ADC master and the slave /// operate in interleaved mode. #[cfg(stm32g4)] - pub fn set_differential_channel(&mut self, ch: usize ,enable: bool) { + pub fn set_differential_channel(&mut self, ch: usize, enable: bool) { T::regs().cr().modify(|w| w.set_aden(false)); // disable adc T::regs().difsel().modify(|w| { - w.set_difsel(ch, if enable { Difsel::DIFFERENTIAL } else { Difsel::SINGLEENDED }); + w.set_difsel( + ch, + if enable { + Difsel::DIFFERENTIAL + } else { + Difsel::SINGLEENDED + }, + ); }); T::regs().cr().modify(|w| w.set_aden(true)); } @@ -268,8 +275,8 @@ impl<'d, T: Instance> Adc<'d, T> { /// Enable oversampling in regular mode. #[cfg(stm32g4)] - pub fn enable_regular_oversampling_mode(&mut self,mode:Rovsm,trig_mode:Trovs, enable: bool) { - T::regs().cfgr2().modify(|reg| reg.set_trovs(trig_mode)); + pub fn enable_regular_oversampling_mode(&mut self, mode: Rovsm, trig_mode: Trovs, enable: bool) { + T::regs().cfgr2().modify(|reg| reg.set_trovs(trig_mode)); T::regs().cfgr2().modify(|reg| reg.set_rovsm(mode)); T::regs().cfgr2().modify(|reg| reg.set_rovse(enable)); } @@ -287,7 +294,6 @@ impl<'d, T: Instance> Adc<'d, T> { // T::regs().cfgr2().modify(|reg| reg.set_jovse(enable)); // } - /// Set the ADC sample time. pub fn set_sample_time(&mut self, sample_time: SampleTime) { self.sample_time = sample_time; diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index b530bb4c8..30f7de09b 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs @@ -23,10 +23,10 @@ pub use _version::*; #[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))] use embassy_sync::waitqueue::AtomicWaker; +pub use crate::pac::adc::vals; #[cfg(not(any(adc_f1, adc_f3_v2)))] pub use crate::pac::adc::vals::Res as Resolution; pub use crate::pac::adc::vals::SampleTime; -pub use crate::pac::adc::vals ; use crate::peripherals; dma_trait!(RxDma, Instance); From e6f4db507d62178ddb05a4569a9f9352a25222e0 Mon Sep 17 00:00:00 2001 From: Samuel Hicks Date: Fri, 19 Jul 2024 17:45:29 +0100 Subject: [PATCH 0015/1217] net/tcp: fix flush() waiting forever if socket is reset with pending write data --- embassy-net/src/tcp.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-net/src/tcp.rs b/embassy-net/src/tcp.rs index be0e1a129..18200287e 100644 --- a/embassy-net/src/tcp.rs +++ b/embassy-net/src/tcp.rs @@ -515,7 +515,7 @@ impl<'d> TcpIo<'d> { async fn flush(&mut self) -> Result<(), Error> { poll_fn(move |cx| { self.with_mut(|s, _| { - let data_pending = s.send_queue() > 0; + let data_pending = (s.send_queue() > 0) && s.state() != tcp::State::Closed; let fin_pending = matches!( s.state(), tcp::State::FinWait1 | tcp::State::Closing | tcp::State::LastAck From 60aa9c15a8a246d1d099beec8a1e3cbf08f52a8f Mon Sep 17 00:00:00 2001 From: Tobias Naumann Date: Fri, 26 Jul 2024 14:25:10 +0200 Subject: [PATCH 0016/1217] Implement low-power feature for stm32l4 MCUs --- embassy-stm32/src/low_power.rs | 6 +++--- embassy-stm32/src/rtc/low_power.rs | 4 ++-- embassy-stm32/src/rtc/v2.rs | 5 ++++- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/embassy-stm32/src/low_power.rs b/embassy-stm32/src/low_power.rs index 604bdf416..f3e4c6994 100644 --- a/embassy-stm32/src/low_power.rs +++ b/embassy-stm32/src/low_power.rs @@ -109,10 +109,10 @@ pub enum StopMode { Stop2, } -#[cfg(stm32l5)] +#[cfg(any(stm32l4, stm32l5))] use stm32_metapac::pwr::vals::Lpms; -#[cfg(stm32l5)] +#[cfg(any(stm32l4, stm32l5))] impl Into for StopMode { fn into(self) -> Lpms { match self { @@ -181,7 +181,7 @@ impl Executor { #[allow(unused_variables)] fn configure_stop(&mut self, stop_mode: StopMode) { - #[cfg(stm32l5)] + #[cfg(any(stm32l4, stm32l5))] crate::pac::PWR.cr1().modify(|m| m.set_lpms(stop_mode.into())); #[cfg(stm32h5)] crate::pac::PWR.pmcr().modify(|v| { diff --git a/embassy-stm32/src/rtc/low_power.rs b/embassy-stm32/src/rtc/low_power.rs index a4ff1acbc..6042389ac 100644 --- a/embassy-stm32/src/rtc/low_power.rs +++ b/embassy-stm32/src/rtc/low_power.rs @@ -65,7 +65,7 @@ pub(crate) enum WakeupPrescaler { Div16 = 16, } -#[cfg(any(stm32f4, stm32l0, stm32g4, stm32l5, stm32wb, stm32h5, stm32g0))] +#[cfg(any(stm32f4, stm32l0, stm32g4, stm32l4, stm32l5, stm32wb, stm32h5, stm32g0))] impl From for crate::pac::rtc::vals::Wucksel { fn from(val: WakeupPrescaler) -> Self { use crate::pac::rtc::vals::Wucksel; @@ -79,7 +79,7 @@ impl From for crate::pac::rtc::vals::Wucksel { } } -#[cfg(any(stm32f4, stm32l0, stm32g4, stm32l5, stm32wb, stm32h5, stm32g0))] +#[cfg(any(stm32f4, stm32l0, stm32g4, stm32l4, stm32l5, stm32wb, stm32h5, stm32g0))] impl From for WakeupPrescaler { fn from(val: crate::pac::rtc::vals::Wucksel) -> Self { use crate::pac::rtc::vals::Wucksel; diff --git a/embassy-stm32/src/rtc/v2.rs b/embassy-stm32/src/rtc/v2.rs index cdc1cb299..5d9025bbe 100644 --- a/embassy-stm32/src/rtc/v2.rs +++ b/embassy-stm32/src/rtc/v2.rs @@ -131,10 +131,13 @@ impl SealedInstance for crate::peripherals::RTC { #[cfg(all(feature = "low-power", stm32f4))] const EXTI_WAKEUP_LINE: usize = 22; + #[cfg(all(feature = "low-power", stm32l4))] + const EXTI_WAKEUP_LINE: usize = 20; + #[cfg(all(feature = "low-power", stm32l0))] const EXTI_WAKEUP_LINE: usize = 20; - #[cfg(all(feature = "low-power", stm32f4))] + #[cfg(all(feature = "low-power", any(stm32f4, stm32l4)))] type WakeupInterrupt = crate::interrupt::typelevel::RTC_WKUP; #[cfg(all(feature = "low-power", stm32l0))] From b2d8d7f009877ad288a563643f3e983eaecafc58 Mon Sep 17 00:00:00 2001 From: rafael Date: Sat, 27 Jul 2024 14:48:42 +0200 Subject: [PATCH 0017/1217] add example to rp: orchestrate multiple tasks --- examples/rp/src/bin/orchestrate_tasks.rs | 267 +++++++++++++++++++++++ 1 file changed, 267 insertions(+) create mode 100644 examples/rp/src/bin/orchestrate_tasks.rs diff --git a/examples/rp/src/bin/orchestrate_tasks.rs b/examples/rp/src/bin/orchestrate_tasks.rs new file mode 100644 index 000000000..b9282e273 --- /dev/null +++ b/examples/rp/src/bin/orchestrate_tasks.rs @@ -0,0 +1,267 @@ +//! This example demonstrates some approaches to communicate between tasks in order to orchestrate the state of the system. +//! +//! We demonstrate how to: +//! - use a channel to send messages between tasks, in this case here in order to have one task control the state of the system. +//! - use a signal to terminate a task. +//! - use command channels to send commands to another task. +//! - use different ways to receive messages, from a straightforwar awaiting on one channel to a more complex awaiting on multiple channels. +//! +//! There are more patterns to orchestrate tasks, this is just one example. +//! +//! We will use these tasks to generate example "state information": +//! - a task that generates random numbers in intervals of 60s +//! - a task that generates random numbers in intervals of 30s +//! - a task that generates random numbers in intervals of 90s +//! - a task that notifies about being attached/disattached from usb power +//! - a task that measures vsys voltage in intervals of 30s + +#![no_std] +#![no_main] + +use assign_resources::assign_resources; +use defmt::*; +use embassy_executor::Spawner; +use embassy_futures::select::{select, Either}; +use embassy_rp::adc::{Adc, Channel, Config, InterruptHandler}; +use embassy_rp::bind_interrupts; +use embassy_rp::clocks::RoscRng; +use embassy_rp::gpio::{Input, Pull}; +use embassy_rp::peripherals; +use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; +use embassy_sync::{channel, signal}; +use embassy_time::{Duration, Timer}; +use rand::RngCore; +use {defmt_rtt as _, panic_probe as _}; + +// This is just some preparation, see example `assign_resources.rs` for more information on this. We prep the rresources that we will be using in different tasks. +// **Note**: This will not work with a board that has a wifi chip, because the wifi chip uses pins 24 and 29 for its own purposes. A way around this in software +// is not trivial, at least if you intend to use wifi, too. Workaround is to wire from vsys and vbus pins to appropriate pins on the board through a voltage divider. Then use those pins. +// For this example it will not matter much, the concept of what we are showing remains valid. +assign_resources! { + vsys: Vsys { + adc: ADC, + pin_29: PIN_29, + }, + vbus: Vbus { + pin_24: PIN_24, + }, +} + +bind_interrupts!(struct Irqs { + ADC_IRQ_FIFO => InterruptHandler; +}); + +/// This is the type of Events that we will send from the worker tasks to the orchestrating task. +enum Events { + UsbPowered(bool), + VsysVoltage(f32), + FirstRandomSeed(u32), + SecondRandomSeed(u32), + ThirdRandomSeed(u32), +} + +/// This is the type of Commands that we will send from the orchestrating task to the worker tasks. +/// Note that we are lazy here and only have one command, you might want to have more. +enum Commands { + /// This command will stop the appropriate worker task + Stop, +} + +/// This is the state of the system, we will use this to orchestrate the system. This is a simple example, in a real world application this would be more complex. +#[derive(Default, Debug, Clone, Format)] +struct State { + usb_powered: bool, + vsys_voltage: f32, + first_random_seed: u32, + second_random_seed: u32, + third_random_seed: u32, + times_we_got_first_random_seed: u8, + maximum_times_we_want_first_random_seed: u8, +} + +impl State { + fn new() -> Self { + Self { + usb_powered: false, + vsys_voltage: 0.0, + first_random_seed: 0, + second_random_seed: 0, + third_random_seed: 0, + times_we_got_first_random_seed: 0, + maximum_times_we_want_first_random_seed: 3, + } + } +} + +/// Channel for the events that we want the orchestrator to react to, all state events are of the type Enum Events. +/// We use a channel with an arbitrary size of 10, the precise size of the queue depends on your use case. This depends on how many events we +/// expect to be generated in a given time frame and how fast the orchestrator can react to them. And then if we rather want the senders to wait for +/// new slots in the queue or if we want the orchestrator to have a backlog of events to process. In this case here we expect to always be enough slots +/// in the queue, so the worker tasks can in all nominal cases send their events and continue with their work without waiting. +/// For the events we - in this case here - do not want to loose any events, so a channel is a good choice. See embassy_sync docs for other options. +static EVENT_CHANNEL: channel::Channel = channel::Channel::new(); + +/// Signal for stopping the first random signal task. We use a signal here, because we need no queue. It is suffiient to have one signal active. +static STOP_FIRST_RANDOM_SIGNAL: signal::Signal = signal::Signal::new(); + +// And now we can put all this into use + +/// This is the main task, that will not do very much besides spawning the other tasks. This is a design choice, you could do the +/// orchestrating here. This is to show that we do not need a main loop here, the system will run indefinitely as long as at least one task is running. +#[embassy_executor::main] +async fn main(spawner: Spawner) { + // initialize the peripherals + let p = embassy_rp::init(Default::default()); + // split the resources, for convenience - see above + let r = split_resources! {p}; + + // spawn the tasks + spawner.spawn(orchestrate(spawner)).unwrap(); + spawner.spawn(random_30s(spawner)).unwrap(); + spawner.spawn(random_60s(spawner)).unwrap(); + spawner.spawn(random_90s(spawner)).unwrap(); + spawner.spawn(usb_power(spawner, r.vbus)).unwrap(); + spawner.spawn(vsys_voltage(spawner, r.vsys)).unwrap(); +} + +/// This is the task handling the system state and orchestrating the other tasks. WEe can regard this as the "main loop" of the system. +#[embassy_executor::task] +async fn orchestrate(_spawner: Spawner) { + let mut state = State::new(); + + // we need to have a receiver for the events + let receiver = EVENT_CHANNEL.receiver(); + + loop { + // we await on the receiver, this will block until a new event is available + // as an alternative to this, we could also await on multiple channels, this would block until at least one of the channels has an event + // see the embassy_futures docs: https://docs.embassy.dev/embassy-futures/git/default/select/index.html + // The task random_30s does a select, if you want to have a look at that. + // Another reason to use select may also be that we want to have a timeout, so we can react to the absence of events within a time frame. + // We keep it simple here. + let event = receiver.receive().await; + + // react to the events + match event { + Events::UsbPowered(usb_powered) => { + // update the state and/or react to the event here + state.usb_powered = usb_powered; + info!("Usb powered: {}", usb_powered); + } + Events::VsysVoltage(voltage) => { + // update the state and/or react to the event here + state.vsys_voltage = voltage; + info!("Vsys voltage: {}", voltage); + } + Events::FirstRandomSeed(seed) => { + // update the state and/or react to the event here + state.first_random_seed = seed; + // here we change some meta state, we count how many times we got the first random seed + state.times_we_got_first_random_seed += 1; + info!( + "First random seed: {}, and that was iteration {} of receiving this.", + seed, &state.times_we_got_first_random_seed + ); + } + Events::SecondRandomSeed(seed) => { + // update the state and/or react to the event here + state.second_random_seed = seed; + info!("Second random seed: {}", seed); + } + Events::ThirdRandomSeed(seed) => { + // update the state and/or react to the event here + state.third_random_seed = seed; + info!("Third random seed: {}", seed); + } + } + // we now have an altered state + // there is a crate for detecting field changes on crates.io (https://crates.io/crates/fieldset) that might be useful here + // for now we just keep it simple + info!("State: {:?}", &state); + + // here we react to the state, in this case here we want to stop the first random seed task after we got it a defined number of times + if state.times_we_got_first_random_seed == state.maximum_times_we_want_first_random_seed { + info!("Stopping the first random signal task"); + // we send a command to the task + STOP_FIRST_RANDOM_SIGNAL.signal(Commands::Stop); + } + } +} + +/// This task will generate random numbers in intervals of 30s +/// The task will terminate after it has received a command signal to stop, see the orchestrate task for that. +#[embassy_executor::task] +async fn random_30s(_spawner: Spawner) { + let mut rng = RoscRng; + let sender = EVENT_CHANNEL.sender(); + loop { + // we either await on the timer or the signal, whichever comes first. + let futures = select(Timer::after(Duration::from_secs(30)), STOP_FIRST_RANDOM_SIGNAL.wait()).await; + match futures { + Either::First(_) => { + // we received are operating on the timer + info!("30s are up, generating random number"); + let random_number = rng.next_u32(); + sender.send(Events::FirstRandomSeed(random_number)).await; + } + Either::Second(_) => { + // we received the signal to stop + info!("Received signal to stop, goodbye!"); + break; + } + } + } +} + +/// This task will generate random numbers in intervals of 60s +#[embassy_executor::task] +async fn random_60s(_spawner: Spawner) { + let mut rng = RoscRng; + let sender = EVENT_CHANNEL.sender(); + loop { + Timer::after(Duration::from_secs(60)).await; + let random_number = rng.next_u32(); + sender.send(Events::SecondRandomSeed(random_number)).await; + } +} + +/// This task will generate random numbers in intervals of 90s +#[embassy_executor::task] +async fn random_90s(_spawner: Spawner) { + let mut rng = RoscRng; + let sender = EVENT_CHANNEL.sender(); + loop { + Timer::after(Duration::from_secs(90)).await; + let random_number = rng.next_u32(); + sender.send(Events::ThirdRandomSeed(random_number)).await; + } +} + +/// This task will notify if we are connected to usb power +#[embassy_executor::task] +pub async fn usb_power(_spawner: Spawner, r: Vbus) { + let mut vbus_in = Input::new(r.pin_24, Pull::None); + let sender = EVENT_CHANNEL.sender(); + loop { + sender.send(Events::UsbPowered(vbus_in.is_high())).await; + vbus_in.wait_for_any_edge().await; + } +} + +/// This task will measure the vsys voltage in intervals of 30s +#[embassy_executor::task] +pub async fn vsys_voltage(_spawner: Spawner, r: Vsys) { + let mut adc = Adc::new(r.adc, Irqs, Config::default()); + let vsys_in = r.pin_29; + let mut channel = Channel::new_pin(vsys_in, Pull::None); + let sender = EVENT_CHANNEL.sender(); + loop { + // read the adc value + let adc_value = adc.read(&mut channel).await.unwrap(); + // convert the adc value to voltage. + // 3.3 is the reference voltage, 3.0 is the factor for the inbuilt voltage divider and 4096 is the resolution of the adc + let voltage = (adc_value as f32) * 3.3 * 3.0 / 4096.0; + sender.send(Events::VsysVoltage(voltage)).await; + Timer::after(Duration::from_secs(30)).await; + } +} From 97125e53cdf425a146c6552a25164cdfd6075fe7 Mon Sep 17 00:00:00 2001 From: rafael Date: Sat, 27 Jul 2024 14:54:02 +0200 Subject: [PATCH 0018/1217] add example to rp: orchestrate multiple tasks --- examples/rp/src/bin/orchestrate_tasks.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/examples/rp/src/bin/orchestrate_tasks.rs b/examples/rp/src/bin/orchestrate_tasks.rs index b9282e273..1ef6b5fb6 100644 --- a/examples/rp/src/bin/orchestrate_tasks.rs +++ b/examples/rp/src/bin/orchestrate_tasks.rs @@ -23,10 +23,9 @@ use defmt::*; use embassy_executor::Spawner; use embassy_futures::select::{select, Either}; use embassy_rp::adc::{Adc, Channel, Config, InterruptHandler}; -use embassy_rp::bind_interrupts; use embassy_rp::clocks::RoscRng; use embassy_rp::gpio::{Input, Pull}; -use embassy_rp::peripherals; +use embassy_rp::{bind_interrupts, peripherals}; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::{channel, signal}; use embassy_time::{Duration, Timer}; From 5d46b694ca60ee69d83eb2bd53f592b2c5b03d28 Mon Sep 17 00:00:00 2001 From: rafael Date: Sat, 27 Jul 2024 14:57:46 +0200 Subject: [PATCH 0019/1217] add example to rp: orchestrate multiple tasks --- examples/rp/src/bin/orchestrate_tasks.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/rp/src/bin/orchestrate_tasks.rs b/examples/rp/src/bin/orchestrate_tasks.rs index 1ef6b5fb6..b3c37de4c 100644 --- a/examples/rp/src/bin/orchestrate_tasks.rs +++ b/examples/rp/src/bin/orchestrate_tasks.rs @@ -4,7 +4,7 @@ //! - use a channel to send messages between tasks, in this case here in order to have one task control the state of the system. //! - use a signal to terminate a task. //! - use command channels to send commands to another task. -//! - use different ways to receive messages, from a straightforwar awaiting on one channel to a more complex awaiting on multiple channels. +//! - use different ways to receive messages, from a straightforwar awaiting on one channel to a more complex awaiting on multiple futures. //! //! There are more patterns to orchestrate tasks, this is just one example. //! From e05e5d33f0ab832b2ea1c48674c99b41581118be Mon Sep 17 00:00:00 2001 From: rafael Date: Sun, 28 Jul 2024 00:19:54 +0200 Subject: [PATCH 0020/1217] review comments --- examples/rp/src/bin/orchestrate_tasks.rs | 66 +++++++++++++++++++++--- 1 file changed, 59 insertions(+), 7 deletions(-) diff --git a/examples/rp/src/bin/orchestrate_tasks.rs b/examples/rp/src/bin/orchestrate_tasks.rs index b3c37de4c..0e21d5833 100644 --- a/examples/rp/src/bin/orchestrate_tasks.rs +++ b/examples/rp/src/bin/orchestrate_tasks.rs @@ -14,6 +14,7 @@ //! - a task that generates random numbers in intervals of 90s //! - a task that notifies about being attached/disattached from usb power //! - a task that measures vsys voltage in intervals of 30s +//! - a task that consumes the state information and reacts to it #![no_std] #![no_main] @@ -57,6 +58,7 @@ enum Events { FirstRandomSeed(u32), SecondRandomSeed(u32), ThirdRandomSeed(u32), + ResetFirstRandomSeed, } /// This is the type of Commands that we will send from the orchestrating task to the worker tasks. @@ -103,6 +105,11 @@ static EVENT_CHANNEL: channel::Channel = ch /// Signal for stopping the first random signal task. We use a signal here, because we need no queue. It is suffiient to have one signal active. static STOP_FIRST_RANDOM_SIGNAL: signal::Signal = signal::Signal::new(); +/// Channel for the state that we want the consumer task to react to. We use a channel here, because we want to have a queue of state changes, although +/// we want the queue to be of size 1, because we want to finish rwacting to the state change before the next one comes in. This is just a design choice +/// and depends on your use case. +static CONSUMER_CHANNEL: channel::Channel = channel::Channel::new(); + // And now we can put all this into use /// This is the main task, that will not do very much besides spawning the other tasks. This is a design choice, you could do the @@ -116,11 +123,11 @@ async fn main(spawner: Spawner) { // spawn the tasks spawner.spawn(orchestrate(spawner)).unwrap(); - spawner.spawn(random_30s(spawner)).unwrap(); spawner.spawn(random_60s(spawner)).unwrap(); spawner.spawn(random_90s(spawner)).unwrap(); spawner.spawn(usb_power(spawner, r.vbus)).unwrap(); spawner.spawn(vsys_voltage(spawner, r.vsys)).unwrap(); + spawner.spawn(consumer(spawner)).unwrap(); } /// This is the task handling the system state and orchestrating the other tasks. WEe can regard this as the "main loop" of the system. @@ -131,6 +138,9 @@ async fn orchestrate(_spawner: Spawner) { // we need to have a receiver for the events let receiver = EVENT_CHANNEL.receiver(); + // and we need a sender for the consumer task + let state_sender = CONSUMER_CHANNEL.sender(); + loop { // we await on the receiver, this will block until a new event is available // as an alternative to this, we could also await on multiple channels, this would block until at least one of the channels has an event @@ -172,23 +182,65 @@ async fn orchestrate(_spawner: Spawner) { state.third_random_seed = seed; info!("Third random seed: {}", seed); } + Events::ResetFirstRandomSeed => { + // update the state and/or react to the event here + state.times_we_got_first_random_seed = 0; + state.first_random_seed = 0; + info!("Resetting the first random seed counter"); + } } // we now have an altered state // there is a crate for detecting field changes on crates.io (https://crates.io/crates/fieldset) that might be useful here // for now we just keep it simple - info!("State: {:?}", &state); - // here we react to the state, in this case here we want to stop the first random seed task after we got it a defined number of times - if state.times_we_got_first_random_seed == state.maximum_times_we_want_first_random_seed { - info!("Stopping the first random signal task"); - // we send a command to the task - STOP_FIRST_RANDOM_SIGNAL.signal(Commands::Stop); + // we send the state to the consumer task + // since the channel has a size of 1, this will block until the consumer task has received the state, which is what we want here in this example + // **Note:** It is bad design to send too much data between tasks, with no clear definition of what "too much" is. In this example we send the + // whole state, in a real world application you might want to send only the data, that is relevant to the consumer task AND only when it has changed. + // We keep it simple here. + state_sender.send(state.clone()).await; + } +} + +/// This task will consume the state information and react to it. This is a simple example, in a real world application this would be more complex +/// and we could have multiple consumer tasks, each reacting to different parts of the state. +#[embassy_executor::task] +async fn consumer(spawner: Spawner) { + // we need to have a receiver for the state + let receiver = CONSUMER_CHANNEL.receiver(); + let sender = EVENT_CHANNEL.sender(); + loop { + // we await on the receiver, this will block until a new state is available + let state = receiver.receive().await; + // react to the state, in this case here we just log it + info!("The consumer has reveived this state: {:?}", &state); + + // here we react to the state, in this case here we want to start or stop the first random signal task depending on the state of the system + match state.times_we_got_first_random_seed { + max if max == state.maximum_times_we_want_first_random_seed => { + info!("Stopping the first random signal task"); + // we send a command to the task + STOP_FIRST_RANDOM_SIGNAL.signal(Commands::Stop); + // we notify the orchestrator that we have sent the command + sender.send(Events::ResetFirstRandomSeed).await; + } + 0 => { + // we start the task, which presents us with an interesting problem, because we may return here before the task has started + // here we just try and log if the task has started, in a real world application you might want to handle this more gracefully + info!("Starting the first random signal task"); + match spawner.spawn(random_30s(spawner)) { + Ok(_) => info!("Successfully spawned random_30s task"), + Err(e) => info!("Failed to spawn random_30s task: {:?}", e), + } + } + _ => {} } } } /// This task will generate random numbers in intervals of 30s /// The task will terminate after it has received a command signal to stop, see the orchestrate task for that. +/// Note that we are not spawning this task from main, as we will show how such a task can be spawned and closed dynamically. #[embassy_executor::task] async fn random_30s(_spawner: Spawner) { let mut rng = RoscRng; From a7258927209827e27f4190af57020c2a8017dbaa Mon Sep 17 00:00:00 2001 From: Karun Date: Mon, 5 Aug 2024 15:37:03 -0400 Subject: [PATCH 0021/1217] Convert uart half_duplex to use open-drain pull-up --- embassy-stm32/src/usart/mod.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index 7ed3793a1..3283fb6b7 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -1029,8 +1029,9 @@ impl<'d> Uart<'d, Async> { /// (when it is available for your chip). There is no functional difference between these methods, as both /// allow bidirectional communication. /// - /// The pin is always released when no data is transmitted. Thus, it acts as a standard - /// I/O in idle or in reception. + /// The TX pin is always released when no data is transmitted. Thus, it acts as a standard + /// I/O in idle or in reception. It means that the I/O must be configured so that TX is + /// configured as alternate function open-drain with an external pull-up /// Apart from this, the communication protocol is similar to normal USART mode. Any conflict /// on the line must be managed by software (for instance by using a centralized arbiter). #[doc(alias("HDSEL"))] @@ -1051,7 +1052,7 @@ impl<'d> Uart<'d, Async> { Self::new_inner( peri, None, - new_pin!(tx, AfType::output(OutputType::PushPull, Speed::Medium)), + new_pin!(tx, AfType::output_pull(OutputType::OpenDrain, Speed::Medium, Pull::Up)), None, None, None, From 446169b2c1c85ced844e1a888d7fec75047e11c1 Mon Sep 17 00:00:00 2001 From: Karun Date: Tue, 6 Aug 2024 11:52:16 -0400 Subject: [PATCH 0022/1217] Add gpio version dependency Add configurable output type for half-duplex --- embassy-stm32/src/usart/mod.rs | 81 ++++++++++++++++++++++++++++++++-- 1 file changed, 77 insertions(+), 4 deletions(-) diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index 3283fb6b7..0c5bbf491 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -211,6 +211,19 @@ impl Default for Config { } } +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +/// Half duplex IO mode +pub enum HalfDuplexConfig { + /// Push pull allows for faster baudrates, may require series resistor + PushPull, + /// Open drain output using external pull up resistor + OpenDrainExternal, + #[cfg(not(gpio_v1))] + /// Open drain output using internal pull up resistor + OpenDrainInternal, +} + /// Serial error #[derive(Debug, Eq, PartialEq, Copy, Clone)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -1042,6 +1055,7 @@ impl<'d> Uart<'d, Async> { tx_dma: impl Peripheral

> + 'd, rx_dma: impl Peripheral

> + 'd, mut config: Config, + half_duplex: HalfDuplexConfig, ) -> Result { #[cfg(not(any(usart_v1, usart_v2)))] { @@ -1052,7 +1066,21 @@ impl<'d> Uart<'d, Async> { Self::new_inner( peri, None, - new_pin!(tx, AfType::output_pull(OutputType::OpenDrain, Speed::Medium, Pull::Up)), + new_pin!( + tx, + match half_duplex { + HalfDuplexConfig::PushPull => { + AfType::output(OutputType::PushPull, Speed::Medium) + } + HalfDuplexConfig::OpenDrainExternal => { + AfType::output(OutputType::OpenDrain, Speed::Medium) + } + #[cfg(not(gpio_v1))] + HalfDuplexConfig::OpenDrainInternal => { + AfType::output_pull(OutputType::OpenDrain, Speed::Medium, Pull::Up) + } + } + ), None, None, None, @@ -1080,6 +1108,7 @@ impl<'d> Uart<'d, Async> { tx_dma: impl Peripheral

> + 'd, rx_dma: impl Peripheral

> + 'd, mut config: Config, + half_duplex: HalfDuplexConfig, ) -> Result { config.swap_rx_tx = true; config.half_duplex = true; @@ -1088,7 +1117,21 @@ impl<'d> Uart<'d, Async> { peri, None, None, - new_pin!(rx, AfType::output(OutputType::PushPull, Speed::Medium)), + new_pin!( + rx, + match half_duplex { + HalfDuplexConfig::PushPull => { + AfType::output(OutputType::PushPull, Speed::Medium) + } + HalfDuplexConfig::OpenDrainExternal => { + AfType::output(OutputType::OpenDrain, Speed::Medium) + } + #[cfg(not(gpio_v1))] + HalfDuplexConfig::OpenDrainInternal => { + AfType::output_pull(OutputType::OpenDrain, Speed::Medium, Pull::Up) + } + } + ), None, None, new_dma!(tx_dma), @@ -1193,6 +1236,7 @@ impl<'d> Uart<'d, Blocking> { peri: impl Peripheral

+ 'd, tx: impl Peripheral

> + 'd, mut config: Config, + half_duplex: HalfDuplexConfig, ) -> Result { #[cfg(not(any(usart_v1, usart_v2)))] { @@ -1203,7 +1247,21 @@ impl<'d> Uart<'d, Blocking> { Self::new_inner( peri, None, - new_pin!(tx, AfType::output(OutputType::PushPull, Speed::Medium)), + new_pin!( + tx, + match half_duplex { + HalfDuplexConfig::PushPull => { + AfType::output(OutputType::PushPull, Speed::Medium) + } + HalfDuplexConfig::OpenDrainExternal => { + AfType::output(OutputType::OpenDrain, Speed::Medium) + } + #[cfg(not(gpio_v1))] + HalfDuplexConfig::OpenDrainInternal => { + AfType::output_pull(OutputType::OpenDrain, Speed::Medium, Pull::Up) + } + } + ), None, None, None, @@ -1228,6 +1286,7 @@ impl<'d> Uart<'d, Blocking> { peri: impl Peripheral

+ 'd, rx: impl Peripheral

> + 'd, mut config: Config, + half_duplex: HalfDuplexConfig, ) -> Result { config.swap_rx_tx = true; config.half_duplex = true; @@ -1236,7 +1295,21 @@ impl<'d> Uart<'d, Blocking> { peri, None, None, - new_pin!(rx, AfType::output(OutputType::PushPull, Speed::Medium)), + new_pin!( + rx, + match half_duplex { + HalfDuplexConfig::PushPull => { + AfType::output(OutputType::PushPull, Speed::Medium) + } + HalfDuplexConfig::OpenDrainExternal => { + AfType::output(OutputType::OpenDrain, Speed::Medium) + } + #[cfg(not(gpio_v1))] + HalfDuplexConfig::OpenDrainInternal => { + AfType::output_pull(OutputType::OpenDrain, Speed::Medium, Pull::Up) + } + } + ), None, None, None, From 0b8779593772f336531c0ebb5a583190b4f31c6b Mon Sep 17 00:00:00 2001 From: ferris Date: Tue, 13 Aug 2024 17:25:00 +0200 Subject: [PATCH 0023/1217] Add OTG core DMA address registers --- embassy-usb-synopsys-otg/src/otg_v1.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/embassy-usb-synopsys-otg/src/otg_v1.rs b/embassy-usb-synopsys-otg/src/otg_v1.rs index 111bc4a63..a8530980c 100644 --- a/embassy-usb-synopsys-otg/src/otg_v1.rs +++ b/embassy-usb-synopsys-otg/src/otg_v1.rs @@ -272,6 +272,12 @@ impl Otg { assert!(n < 12usize); unsafe { Reg::from_ptr(self.ptr.add(0x0510usize + n * 32usize) as _) } } + #[doc = "Host channel DMA address register"] + #[inline(always)] + pub const fn hcdma(self, n: usize) -> Reg { + assert!(n < 12usize); + unsafe { Reg::from_ptr(self.ptr.add(0x0514usize + n * 32usize) as _) } + } #[doc = "Device configuration register"] #[inline(always)] pub const fn dcfg(self) -> Reg { @@ -364,6 +370,12 @@ impl Otg { assert!(n < 16usize); unsafe { Reg::from_ptr(self.ptr.add(0x0b10usize + n * 32usize) as _) } } + #[doc = "Device OUT/IN endpoint DMA address register"] + #[inline(always)] + pub const fn doepdma(self, n: usize) -> Reg { + assert!(n < 16usize); + unsafe { Reg::from_ptr(self.ptr.add(0x0b14usize + n * 32usize) as _) } + } #[doc = "Power and clock gating control register"] #[inline(always)] pub const fn pcgcctl(self) -> Reg { From a63d46507de7fbb44233ba5557630791f62a985a Mon Sep 17 00:00:00 2001 From: Haobo Gu Date: Thu, 15 Aug 2024 10:58:10 +0800 Subject: [PATCH 0024/1217] feat(usb): add device qualifier descriptor Signed-off-by: Haobo Gu --- embassy-usb/src/descriptor.rs | 21 +++++++++++++++++++++ embassy-usb/src/lib.rs | 4 ++++ 2 files changed, 25 insertions(+) diff --git a/embassy-usb/src/descriptor.rs b/embassy-usb/src/descriptor.rs index eb3d1f53a..f1773fa8a 100644 --- a/embassy-usb/src/descriptor.rs +++ b/embassy-usb/src/descriptor.rs @@ -13,6 +13,8 @@ pub mod descriptor_type { pub const STRING: u8 = 3; pub const INTERFACE: u8 = 4; pub const ENDPOINT: u8 = 5; + pub const DEVICE_QUALIFIER: u8 = 6; + pub const OTHER_SPEED_CONFIGURATION: u8 = 7; pub const IAD: u8 = 11; pub const BOS: u8 = 15; pub const CAPABILITY: u8 = 16; @@ -272,6 +274,25 @@ pub(crate) fn device_descriptor(config: &Config) -> [u8; 18] { ] } +/// Create a new Device Qualifier Descriptor array. +/// +/// All device qualifier descriptors are always 10 bytes, so there's no need for +/// a variable-length buffer or DescriptorWriter. +pub(crate) fn device_qualifier_descriptor(config: &Config) -> [u8; 10] { + [ + 10, // bLength + 0x06, // bDescriptorType + 0x10, + 0x02, // bcdUSB 2.1 + config.device_class, // bDeviceClass + config.device_sub_class, // bDeviceSubClass + config.device_protocol, // bDeviceProtocol + config.max_packet_size_0, // bMaxPacketSize0 + 1, // bNumConfigurations + 0, // Reserved + ] +} + /// A writer for Binary Object Store descriptor. pub struct BosWriter<'a> { pub(crate) writer: DescriptorWriter<'a>, diff --git a/embassy-usb/src/lib.rs b/embassy-usb/src/lib.rs index d58950838..a5478ca0e 100644 --- a/embassy-usb/src/lib.rs +++ b/embassy-usb/src/lib.rs @@ -190,6 +190,7 @@ struct Inner<'d, D: Driver<'d>> { config: Config<'d>, device_descriptor: [u8; 18], + device_qualifier_descriptor: [u8; 10], config_descriptor: &'d [u8], bos_descriptor: &'d [u8], msos_descriptor: crate::msos::MsOsDescriptorSet<'d>, @@ -225,6 +226,7 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> { // This prevent further allocation by consuming the driver. let (bus, control) = driver.start(config.max_packet_size_0 as u16); let device_descriptor = descriptor::device_descriptor(&config); + let device_qualifier_descriptor = descriptor::device_qualifier_descriptor(&config); Self { control_buf, @@ -233,6 +235,7 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> { bus, config, device_descriptor, + device_qualifier_descriptor, config_descriptor, bos_descriptor, msos_descriptor, @@ -764,6 +767,7 @@ impl<'d, D: Driver<'d>> Inner<'d, D> { } } } + descriptor_type::DEVICE_QUALIFIER => InResponse::Accepted(&self.device_qualifier_descriptor), _ => InResponse::Rejected, } } From ccf8ce7c7e01555755c43996b65d4d9043eebbf5 Mon Sep 17 00:00:00 2001 From: Jonathan 'theJPster' Pallant Date: Fri, 16 Aug 2024 15:23:56 +0100 Subject: [PATCH 0025/1217] Note where some embassy-rs files come from. In a similar fashion to other source files taken from rp-rs. --- embassy-rp/src/binary_info/consts.rs | 3 +++ embassy-rp/src/binary_info/macros.rs | 3 +++ embassy-rp/src/binary_info/mod.rs | 3 +++ embassy-rp/src/binary_info/types.rs | 3 +++ embassy-rp/src/block.rs | 3 +++ 5 files changed, 15 insertions(+) diff --git a/embassy-rp/src/binary_info/consts.rs b/embassy-rp/src/binary_info/consts.rs index c8270c081..d5fcd0d75 100644 --- a/embassy-rp/src/binary_info/consts.rs +++ b/embassy-rp/src/binary_info/consts.rs @@ -1,5 +1,8 @@ //! Constants for binary info +// Credit: Taken from https://github.com/thejpster/rp-hal-rp2350-public (also licensed Apache 2.0 + MIT). +// Copyright (c) rp-rs organization + /// All Raspberry Pi specified IDs have this tag. /// /// You can create your own for custom fields. diff --git a/embassy-rp/src/binary_info/macros.rs b/embassy-rp/src/binary_info/macros.rs index 0d6ba5eb5..faf6148c8 100644 --- a/embassy-rp/src/binary_info/macros.rs +++ b/embassy-rp/src/binary_info/macros.rs @@ -1,5 +1,8 @@ //! Handy macros for making Binary Info entries +// Credit: Taken from https://github.com/thejpster/rp-hal-rp2350-public (also licensed Apache 2.0 + MIT). +// Copyright (c) rp-rs organization + /// Generate a static item containing the given environment variable, /// and return its [`EntryAddr`](super::EntryAddr). #[macro_export] diff --git a/embassy-rp/src/binary_info/mod.rs b/embassy-rp/src/binary_info/mod.rs index 213565cdf..ea475086b 100644 --- a/embassy-rp/src/binary_info/mod.rs +++ b/embassy-rp/src/binary_info/mod.rs @@ -13,6 +13,9 @@ //! ]; //! ``` +// Credit: Taken from https://github.com/thejpster/rp-hal-rp2350-public (also licensed Apache 2.0 + MIT). +// Copyright (c) rp-rs organization + pub mod consts; mod types; diff --git a/embassy-rp/src/binary_info/types.rs b/embassy-rp/src/binary_info/types.rs index d2b192e32..6aec1902e 100644 --- a/embassy-rp/src/binary_info/types.rs +++ b/embassy-rp/src/binary_info/types.rs @@ -1,5 +1,8 @@ //! Types for the Binary Info system +// Credit: Taken from https://github.com/thejpster/rp-hal-rp2350-public (also licensed Apache 2.0 + MIT). +// Copyright (c) rp-rs organization + /// This is the 'Binary Info' header block that `picotool` looks for in your UF2 /// file/ELF file/Pico in Bootloader Mode to give you useful metadata about your /// program. diff --git a/embassy-rp/src/block.rs b/embassy-rp/src/block.rs index d270bbf1c..a3e1ad925 100644 --- a/embassy-rp/src/block.rs +++ b/embassy-rp/src/block.rs @@ -6,6 +6,9 @@ //! firmware image. The `PARTITION_TABLE` Block (here the `PartitionTable` type) //! tells the ROM how to divide the flash space up into partitions. +// Credit: Taken from https://github.com/thejpster/rp-hal-rp2350-public (also licensed Apache 2.0 + MIT). +// Copyright (c) rp-rs organization + // These all have a 1 byte size /// An item ID for encoding a Vector Table address From 16c3e5880fcbd21b0b67ac313e28c3b340fe3ece Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Fri, 16 Aug 2024 17:51:52 +0200 Subject: [PATCH 0026/1217] Add license files to embassy-rp crediting rp-rs. --- embassy-rp/LICENSE-APACHE | 202 ++++++++++++++++++++++++++++++++++++++ embassy-rp/LICENSE-MIT | 26 +++++ 2 files changed, 228 insertions(+) create mode 100644 embassy-rp/LICENSE-APACHE create mode 100644 embassy-rp/LICENSE-MIT diff --git a/embassy-rp/LICENSE-APACHE b/embassy-rp/LICENSE-APACHE new file mode 100644 index 000000000..48be1263d --- /dev/null +++ b/embassy-rp/LICENSE-APACHE @@ -0,0 +1,202 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright (c) Embassy project contributors +Portions copyright (c) rp-rs organization + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/embassy-rp/LICENSE-MIT b/embassy-rp/LICENSE-MIT new file mode 100644 index 000000000..f1cfbd5f7 --- /dev/null +++ b/embassy-rp/LICENSE-MIT @@ -0,0 +1,26 @@ +Copyright (c) Embassy project contributors +Portions copyright (c) rp-rs organization + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. From d6bf4c45d28072348f1527809c21311989e52012 Mon Sep 17 00:00:00 2001 From: Anthony Grondin <104731965+AnthonyGrondin@users.noreply.github.com> Date: Fri, 16 Aug 2024 22:51:28 -0400 Subject: [PATCH 0027/1217] feat(mdns): Enable mdns support through smoltcp --- embassy-net/Cargo.toml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/embassy-net/Cargo.toml b/embassy-net/Cargo.toml index d86a30755..28bac485b 100644 --- a/embassy-net/Cargo.toml +++ b/embassy-net/Cargo.toml @@ -44,6 +44,8 @@ raw = ["smoltcp/socket-raw"] tcp = ["smoltcp/socket-tcp"] ## Enable DNS support dns = ["smoltcp/socket-dns", "smoltcp/proto-dns"] +## Enable mDNS support +mdns = ["dns", "smoltcp/socket-mdns"] ## Enable DHCPv4 support dhcpv4 = ["proto-ipv4", "medium-ethernet", "smoltcp/socket-dhcpv4"] ## Enable DHCPv4 support with hostname From 20b1b15bda969309566ad495d54635da8b7f29b2 Mon Sep 17 00:00:00 2001 From: rafael Date: Sat, 17 Aug 2024 12:37:42 +0200 Subject: [PATCH 0028/1217] add one more embassy in the wild example (#3262) --- docs/pages/embassy_in_the_wild.adoc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/pages/embassy_in_the_wild.adoc b/docs/pages/embassy_in_the_wild.adoc index 76b1169bd..bb457a869 100644 --- a/docs/pages/embassy_in_the_wild.adoc +++ b/docs/pages/embassy_in_the_wild.adoc @@ -2,6 +2,8 @@ Here are known examples of real-world projects which make use of Embassy. Feel free to link:https://github.com/embassy-rs/embassy/blob/main/docs/pages/embassy_in_the_wild.adoc[add more]! +* link:https://github.com/1-rafael-1/pi-pico-alarmclock-rust[A Raspberry Pi Pico W Alarmclock] +** A hobbyist project building an alarm clock around a Pi Pico W complete with code, components list and enclosure design files. * link:https://github.com/haobogu/rmk/[RMK: A feature-rich Rust keyboard firmware] ** RMK has built-in layer support, wireless(BLE) support, real-time key editing support using vial, and more! ** Targets STM32, RP2040, nRF52 and ESP32 MCUs From 2b7e76efe9916170cba69da964d53c19a246ae45 Mon Sep 17 00:00:00 2001 From: Alexandros Liarokapis Date: Sat, 17 Aug 2024 00:26:33 +0300 Subject: [PATCH 0029/1217] Fix dma nvic issues on dual core lines This commit addresses #3256 by disabling dma NVIC interrupt enablement at startup. Instead, per-channel NVIC interrupt enablement is now done with the rest of the dma channel configuration. This ensures that each core will only handle the interrupts of the DMA channels that it uses. --- embassy-stm32/build.rs | 70 +++++++++++++++------- embassy-stm32/src/dma/dma_bdma.rs | 9 +++ embassy-stm32/src/dma/gpdma.rs | 9 +++ embassy-stm32/src/lib.rs | 20 ++++++- embassy-stm32/src/rcc/bd.rs | 2 + embassy-stm32/src/rcc/c0.rs | 1 + embassy-stm32/src/rcc/f013.rs | 1 + embassy-stm32/src/rcc/f247.rs | 2 + embassy-stm32/src/rcc/g0.rs | 2 + embassy-stm32/src/rcc/g4.rs | 2 + embassy-stm32/src/rcc/h.rs | 3 +- embassy-stm32/src/rcc/l.rs | 1 + embassy-stm32/src/rcc/u5.rs | 1 + embassy-stm32/src/rcc/wba.rs | 1 + examples/boot/application/stm32wl/memory.x | 6 +- examples/stm32wl/memory.x | 6 +- 16 files changed, 108 insertions(+), 28 deletions(-) diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index d8a7ea0e6..1984a1420 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -1494,6 +1494,36 @@ fn main() { .flat_map(|p| &p.registers) .any(|p| p.kind == "dmamux"); + let mut dma_irqs: BTreeMap<&str, Vec> = BTreeMap::new(); + + for p in METADATA.peripherals { + if let Some(r) = &p.registers { + if r.kind == "dma" || r.kind == "bdma" || r.kind == "gpdma" || r.kind == "lpdma" { + for irq in p.interrupts { + let ch_name = format!("{}_{}", p.name, irq.signal); + let ch = METADATA.dma_channels.iter().find(|c| c.name == ch_name).unwrap(); + + // Some H7 chips have BDMA1 hardcoded for DFSDM, ie no DMAMUX. It's unsupported, skip it. + if has_dmamux && ch.dmamux.is_none() { + continue; + } + + dma_irqs.entry(irq.interrupt).or_default().push(ch_name); + } + } + } + } + + #[cfg(feature = "_dual-core")] + let mut dma_ch_to_irq: BTreeMap<&str, Vec> = BTreeMap::new(); + + #[cfg(feature = "_dual-core")] + for (irq, channels) in &dma_irqs { + for channel in channels { + dma_ch_to_irq.entry(channel).or_default().push(irq.to_string()); + } + } + for (ch_idx, ch) in METADATA.dma_channels.iter().enumerate() { // Some H7 chips have BDMA1 hardcoded for DFSDM, ie no DMAMUX. It's unsupported, skip it. if has_dmamux && ch.dmamux.is_none() { @@ -1502,6 +1532,16 @@ fn main() { let name = format_ident!("{}", ch.name); let idx = ch_idx as u8; + #[cfg(feature = "_dual-core")] + let irq = { + let irq_name = if let Some(x) = &dma_ch_to_irq.get(ch.name) { + format_ident!("{}", x.get(0).unwrap()) + } else { + panic!("failed to find dma interrupt") + }; + quote!(crate::pac::Interrupt::#irq_name) + }; + g.extend(quote!(dma_channel_impl!(#name, #idx);)); let dma = format_ident!("{}", ch.dma); @@ -1532,6 +1572,7 @@ fn main() { None => quote!(), }; + #[cfg(not(feature = "_dual-core"))] dmas.extend(quote! { crate::dma::ChannelInfo { dma: #dma_info, @@ -1539,31 +1580,20 @@ fn main() { #dmamux }, }); + #[cfg(feature = "_dual-core")] + dmas.extend(quote! { + crate::dma::ChannelInfo { + dma: #dma_info, + num: #ch_num, + irq: #irq, + #dmamux + }, + }); } // ======== // Generate DMA IRQs. - let mut dma_irqs: BTreeMap<&str, Vec> = BTreeMap::new(); - - for p in METADATA.peripherals { - if let Some(r) = &p.registers { - if r.kind == "dma" || r.kind == "bdma" || r.kind == "gpdma" { - for irq in p.interrupts { - let ch_name = format!("{}_{}", p.name, irq.signal); - let ch = METADATA.dma_channels.iter().find(|c| c.name == ch_name).unwrap(); - - // Some H7 chips have BDMA1 hardcoded for DFSDM, ie no DMAMUX. It's unsupported, skip it. - if has_dmamux && ch.dmamux.is_none() { - continue; - } - - dma_irqs.entry(irq.interrupt).or_default().push(ch_name); - } - } - } - } - let dma_irqs: TokenStream = dma_irqs .iter() .map(|(irq, channels)| { diff --git a/embassy-stm32/src/dma/dma_bdma.rs b/embassy-stm32/src/dma/dma_bdma.rs index 8a6aa53a0..8e2964f94 100644 --- a/embassy-stm32/src/dma/dma_bdma.rs +++ b/embassy-stm32/src/dma/dma_bdma.rs @@ -15,6 +15,8 @@ use crate::{interrupt, pac}; pub(crate) struct ChannelInfo { pub(crate) dma: DmaInfo, pub(crate) num: usize, + #[cfg(feature = "_dual-core")] + pub(crate) irq: pac::Interrupt, #[cfg(dmamux)] pub(crate) dmamux: super::DmamuxInfo, } @@ -259,10 +261,12 @@ pub(crate) unsafe fn init( foreach_interrupt! { ($peri:ident, dma, $block:ident, $signal_name:ident, $irq:ident) => { crate::interrupt::typelevel::$irq::set_priority_with_cs(cs, dma_priority); + #[cfg(not(feature = "_dual-core"))] crate::interrupt::typelevel::$irq::enable(); }; ($peri:ident, bdma, $block:ident, $signal_name:ident, $irq:ident) => { crate::interrupt::typelevel::$irq::set_priority_with_cs(cs, bdma_priority); + #[cfg(not(feature = "_dual-core"))] crate::interrupt::typelevel::$irq::enable(); }; } @@ -341,6 +345,11 @@ impl AnyChannel { options: TransferOptions, ) { let info = self.info(); + #[cfg(feature = "_dual-core")] + { + use embassy_hal_internal::interrupt::InterruptExt as _; + info.irq.enable(); + } #[cfg(dmamux)] super::dmamux::configure_dmamux(&info.dmamux, _request); diff --git a/embassy-stm32/src/dma/gpdma.rs b/embassy-stm32/src/dma/gpdma.rs index 13d5d15be..f9d66ca86 100644 --- a/embassy-stm32/src/dma/gpdma.rs +++ b/embassy-stm32/src/dma/gpdma.rs @@ -18,6 +18,8 @@ use crate::pac::gpdma::vals; pub(crate) struct ChannelInfo { pub(crate) dma: pac::gpdma::Gpdma, pub(crate) num: usize, + #[cfg(feature = "_dual-core")] + pub(crate) irq: pac::Interrupt, } /// GPDMA transfer options. @@ -57,6 +59,7 @@ pub(crate) unsafe fn init(cs: critical_section::CriticalSection, irq_priority: P foreach_interrupt! { ($peri:ident, gpdma, $block:ident, $signal_name:ident, $irq:ident) => { crate::interrupt::typelevel::$irq::set_priority_with_cs(cs, irq_priority); + #[cfg(not(feature = "_dual-core"))] crate::interrupt::typelevel::$irq::enable(); }; } @@ -67,6 +70,12 @@ impl AnyChannel { /// Safety: Must be called with a matching set of parameters for a valid dma channel pub(crate) unsafe fn on_irq(&self) { let info = self.info(); + #[cfg(feature = "_dual-core")] + { + use embassy_hal_internal::interrupt::InterruptExt as _; + info.irq.enable(); + } + let state = &STATE[self.id as usize]; let ch = info.dma.ch(info.num); diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 12ebbae2d..98695e738 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -197,6 +197,7 @@ pub use crate::pac::NVIC_PRIO_BITS; /// `embassy-stm32` global configuration. #[non_exhaustive] +#[derive(Clone, Copy)] pub struct Config { /// RCC config. pub rcc: rcc::Config, @@ -303,6 +304,7 @@ mod dual_core { pub struct SharedData { init_flag: AtomicUsize, clocks: UnsafeCell>, + config: UnsafeCell>, } unsafe impl Sync for SharedData {} @@ -325,6 +327,8 @@ mod dual_core { rcc::set_freqs_ptr(shared_data.clocks.get()); let p = init_hw(config); + unsafe { *shared_data.config.get() }.write(config); + shared_data.init_flag.store(INIT_DONE_FLAG, Ordering::SeqCst); p @@ -372,9 +376,23 @@ mod dual_core { fn init_secondary_hw(shared_data: &'static SharedData) -> Peripherals { rcc::set_freqs_ptr(shared_data.clocks.get()); + let config = unsafe { (*shared_data.config.get()).assume_init() }; + // We use different timers on the different cores, so we have to still initialize one here - #[cfg(feature = "_time-driver")] critical_section::with(|cs| { + unsafe { + dma::init( + cs, + #[cfg(bdma)] + config.bdma_interrupt_priority, + #[cfg(dma)] + config.dma_interrupt_priority, + #[cfg(gpdma)] + config.gpdma_interrupt_priority, + ) + } + + #[cfg(feature = "_time-driver")] // must be after rcc init time_driver::init(cs); }); diff --git a/embassy-stm32/src/rcc/bd.rs b/embassy-stm32/src/rcc/bd.rs index 4e9c18594..9ccca8a2a 100644 --- a/embassy-stm32/src/rcc/bd.rs +++ b/embassy-stm32/src/rcc/bd.rs @@ -16,6 +16,7 @@ pub enum LseMode { Bypass, } +#[derive(Clone, Copy)] pub struct LseConfig { pub frequency: Hertz, pub mode: LseMode, @@ -80,6 +81,7 @@ fn bdcr() -> Reg { return crate::pac::RCC.csr1(); } +#[derive(Clone, Copy)] pub struct LsConfig { pub rtc: RtcClockSource, pub lsi: bool, diff --git a/embassy-stm32/src/rcc/c0.rs b/embassy-stm32/src/rcc/c0.rs index 5adf37941..6712aedc4 100644 --- a/embassy-stm32/src/rcc/c0.rs +++ b/embassy-stm32/src/rcc/c0.rs @@ -37,6 +37,7 @@ pub struct Hsi { /// Clocks configutation #[non_exhaustive] +#[derive(Clone, Copy)] pub struct Config { /// HSI Configuration pub hsi: Option, diff --git a/embassy-stm32/src/rcc/f013.rs b/embassy-stm32/src/rcc/f013.rs index 63dc27bdd..60577b213 100644 --- a/embassy-stm32/src/rcc/f013.rs +++ b/embassy-stm32/src/rcc/f013.rs @@ -76,6 +76,7 @@ pub enum HrtimClockSource { /// Clocks configutation #[non_exhaustive] +#[derive(Clone, Copy)] pub struct Config { pub hsi: bool, pub hse: Option, diff --git a/embassy-stm32/src/rcc/f247.rs b/embassy-stm32/src/rcc/f247.rs index 61f687d30..58056301a 100644 --- a/embassy-stm32/src/rcc/f247.rs +++ b/embassy-stm32/src/rcc/f247.rs @@ -63,6 +63,7 @@ pub struct Pll { /// Used to calculate flash waitstates. See /// RM0033 - Table 3. Number of wait states according to Cortex®-M3 clock frequency #[cfg(stm32f2)] +#[derive(Clone, Copy)] pub enum VoltageScale { /// 2.7 to 3.6 V Range0, @@ -76,6 +77,7 @@ pub enum VoltageScale { /// Configuration of the core clocks #[non_exhaustive] +#[derive(Clone, Copy)] pub struct Config { pub hsi: bool, pub hse: Option, diff --git a/embassy-stm32/src/rcc/g0.rs b/embassy-stm32/src/rcc/g0.rs index c2fa0ca39..c53c83b0e 100644 --- a/embassy-stm32/src/rcc/g0.rs +++ b/embassy-stm32/src/rcc/g0.rs @@ -33,6 +33,7 @@ pub struct Hse { /// Use this struct to configure the PLL source, input frequency, multiplication factor, and output /// dividers. Be sure to keep check the datasheet for your specific part for the appropriate /// frequency ranges for each of these settings. +#[derive(Clone, Copy)] pub struct Pll { /// PLL Source clock selection. pub source: PllSource, @@ -55,6 +56,7 @@ pub struct Pll { /// Clocks configutation #[non_exhaustive] +#[derive(Clone, Copy)] pub struct Config { /// HSI Enable pub hsi: bool, diff --git a/embassy-stm32/src/rcc/g4.rs b/embassy-stm32/src/rcc/g4.rs index c261c0fed..16561f908 100644 --- a/embassy-stm32/src/rcc/g4.rs +++ b/embassy-stm32/src/rcc/g4.rs @@ -32,6 +32,7 @@ pub struct Hse { /// Use this struct to configure the PLL source, input frequency, multiplication factor, and output /// dividers. Be sure to keep check the datasheet for your specific part for the appropriate /// frequency ranges for each of these settings. +#[derive(Clone, Copy)] pub struct Pll { /// PLL Source clock selection. pub source: PllSource, @@ -54,6 +55,7 @@ pub struct Pll { /// Clocks configutation #[non_exhaustive] +#[derive(Clone, Copy)] pub struct Config { /// HSI Enable pub hsi: bool, diff --git a/embassy-stm32/src/rcc/h.rs b/embassy-stm32/src/rcc/h.rs index e3c7dd158..376a0b454 100644 --- a/embassy-stm32/src/rcc/h.rs +++ b/embassy-stm32/src/rcc/h.rs @@ -120,7 +120,7 @@ impl From for Timpre { /// Power supply configuration /// See RM0433 Rev 4 7.4 #[cfg(any(pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468, pwr_h7rs))] -#[derive(PartialEq)] +#[derive(Clone, Copy, PartialEq)] pub enum SupplyConfig { /// Default power supply configuration. /// V CORE Power Domains are supplied from the LDO according to VOS. @@ -180,6 +180,7 @@ pub enum SMPSSupplyVoltage { /// Configuration of the core clocks #[non_exhaustive] +#[derive(Clone, Copy)] pub struct Config { pub hsi: Option, pub hse: Option, diff --git a/embassy-stm32/src/rcc/l.rs b/embassy-stm32/src/rcc/l.rs index e9266c65b..6120d33be 100644 --- a/embassy-stm32/src/rcc/l.rs +++ b/embassy-stm32/src/rcc/l.rs @@ -30,6 +30,7 @@ pub struct Hse { } /// Clocks configuration +#[derive(Clone, Copy)] pub struct Config { // base clock sources pub msi: Option, diff --git a/embassy-stm32/src/rcc/u5.rs b/embassy-stm32/src/rcc/u5.rs index d6331f512..28545ca51 100644 --- a/embassy-stm32/src/rcc/u5.rs +++ b/embassy-stm32/src/rcc/u5.rs @@ -59,6 +59,7 @@ pub struct Pll { pub divr: Option, } +#[derive(Clone, Copy)] pub struct Config { // base clock sources pub msi: Option, diff --git a/embassy-stm32/src/rcc/wba.rs b/embassy-stm32/src/rcc/wba.rs index 8e1779d7c..1fee648d4 100644 --- a/embassy-stm32/src/rcc/wba.rs +++ b/embassy-stm32/src/rcc/wba.rs @@ -15,6 +15,7 @@ pub struct Hse { } /// Clocks configuration +#[derive(Clone, Copy)] pub struct Config { // base clock sources pub hsi: bool, diff --git a/examples/boot/application/stm32wl/memory.x b/examples/boot/application/stm32wl/memory.x index 5af1723f5..20109e37e 100644 --- a/examples/boot/application/stm32wl/memory.x +++ b/examples/boot/application/stm32wl/memory.x @@ -5,8 +5,8 @@ MEMORY BOOTLOADER_STATE : ORIGIN = 0x08006000, LENGTH = 4K FLASH : ORIGIN = 0x08008000, LENGTH = 64K DFU : ORIGIN = 0x08018000, LENGTH = 68K - SHARED_RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 64 - RAM (rwx) : ORIGIN = 0x20000040, LENGTH = 32K - 64 + SHARED_RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 128 + RAM (rwx) : ORIGIN = 0x20000080, LENGTH = 32K - 128 } __bootloader_state_start = ORIGIN(BOOTLOADER_STATE) - ORIGIN(BOOTLOADER); @@ -21,4 +21,4 @@ SECTIONS { *(.shared_data) } > SHARED_RAM -} \ No newline at end of file +} diff --git a/examples/stm32wl/memory.x b/examples/stm32wl/memory.x index 0298caa4b..4590867a8 100644 --- a/examples/stm32wl/memory.x +++ b/examples/stm32wl/memory.x @@ -2,8 +2,8 @@ MEMORY { /* NOTE 1 K = 1 KiBi = 1024 bytes */ FLASH : ORIGIN = 0x08000000, LENGTH = 256K - SHARED_RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 64 - RAM (rwx) : ORIGIN = 0x20000040, LENGTH = 64K - 64 + SHARED_RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 128 + RAM (rwx) : ORIGIN = 0x20000080, LENGTH = 64K - 128 } SECTIONS @@ -12,4 +12,4 @@ SECTIONS { *(.shared_data) } > SHARED_RAM -} \ No newline at end of file +} From 550f2cfca020222868670b927f9de130559b09a7 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sat, 17 Aug 2024 17:45:29 +0200 Subject: [PATCH 0030/1217] Temporarily disable stm32f1 tests. --- ci.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ci.sh b/ci.sh index 3e3d9ad00..8ccdb09c8 100755 --- a/ci.sh +++ b/ci.sh @@ -289,6 +289,9 @@ cargo batch \ $BUILD_EXTRA +# temporarily disabled, bluepill board got bricked +rm -rf out/tests/stm32f103c8 + rm out/tests/stm32wb55rg/wpan_mac rm out/tests/stm32wb55rg/wpan_ble From 4bef0fc95342adbda42a4cc6751a406a4f602c67 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sat, 17 Aug 2024 18:14:56 +0200 Subject: [PATCH 0031/1217] disable uart ringbuffered test on f2. --- ci.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ci.sh b/ci.sh index 8ccdb09c8..da842577d 100755 --- a/ci.sh +++ b/ci.sh @@ -301,8 +301,9 @@ rm out/tests/stm32f207zg/eth # doesn't work, gives "noise error", no idea why. usart_dma does pass. rm out/tests/stm32u5a5zj/usart -# flaky, perhaps bad wire +# flaky, probably due to bad ringbuffered dma code. rm out/tests/stm32l152re/usart_rx_ringbuffered +rm out/tests/stm32f207zg/usart_rx_ringbuffered if [[ -z "${TELEPROBE_TOKEN-}" ]]; then echo No teleprobe token found, skipping running HIL tests From 8884766450e49e4557a2b5babed1ccf93058680a Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sat, 17 Aug 2024 21:49:06 +0200 Subject: [PATCH 0032/1217] stm32: update metapac --- embassy-stm32/Cargo.toml | 4 ++-- embassy-stm32/src/adc/f3.rs | 2 +- embassy-stm32/src/adc/f3_v1_1.rs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index ac9e9644c..54abd0799 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -72,7 +72,7 @@ rand_core = "0.6.3" sdio-host = "0.5.0" critical-section = "1.1" #stm32-metapac = { version = "15" } -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-e0cfd165fd8fffaa0df66a35eeca83b228496645" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-5ef354f3e49f790e47f5c818f243459742c9b83b" } vcell = "0.1.3" nb = "1.0.0" @@ -97,7 +97,7 @@ proc-macro2 = "1.0.36" quote = "1.0.15" #stm32-metapac = { version = "15", default-features = false, features = ["metadata"]} -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-e0cfd165fd8fffaa0df66a35eeca83b228496645", default-features = false, features = ["metadata"] } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-5ef354f3e49f790e47f5c818f243459742c9b83b", default-features = false, features = ["metadata"] } [features] default = ["rt"] diff --git a/embassy-stm32/src/adc/f3.rs b/embassy-stm32/src/adc/f3.rs index ac88c9742..0ebeb8a9e 100644 --- a/embassy-stm32/src/adc/f3.rs +++ b/embassy-stm32/src/adc/f3.rs @@ -42,7 +42,7 @@ impl super::SealedAdcChannel for Vref { impl Vref { /// The value that vref would be if vdda was at 3300mv pub fn value(&self) -> u16 { - crate::pac::VREFINTCAL.data().read().value() + crate::pac::VREFINTCAL.data().read() } } diff --git a/embassy-stm32/src/adc/f3_v1_1.rs b/embassy-stm32/src/adc/f3_v1_1.rs index 689c2871d..291a3861e 100644 --- a/embassy-stm32/src/adc/f3_v1_1.rs +++ b/embassy-stm32/src/adc/f3_v1_1.rs @@ -74,7 +74,7 @@ impl super::SealedAdcChannel for Vref { impl Vref { /// The value that vref would be if vdda was at 3000mv pub fn calibrated_value(&self) -> u16 { - crate::pac::VREFINTCAL.data().read().value() + crate::pac::VREFINTCAL.data().read() } pub async fn calibrate(&mut self, adc: &mut Adc<'_, T>) -> Calibration { From eab3a57263d52eed517ee0fb9ccb307196664ee6 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sat, 17 Aug 2024 21:56:14 +0200 Subject: [PATCH 0033/1217] rp: use the rp-binary-info crate for binary info. --- ci.sh | 1 + embassy-rp/Cargo.toml | 3 +- embassy-rp/src/binary_info/consts.rs | 34 ---- embassy-rp/src/binary_info/macros.rs | 171 ---------------- embassy-rp/src/binary_info/mod.rs | 175 ----------------- embassy-rp/src/binary_info/types.rs | 195 ------------------- embassy-rp/src/lib.rs | 5 +- examples/rp23/src/bin/adc.rs | 8 +- examples/rp23/src/bin/adc_dma.rs | 8 +- examples/rp23/src/bin/assign_resources.rs | 8 +- examples/rp23/src/bin/blinky.rs | 8 +- examples/rp23/src/bin/blinky_two_channels.rs | 8 +- examples/rp23/src/bin/blinky_two_tasks.rs | 8 +- examples/rp23/src/bin/button.rs | 8 +- examples/rp23/src/bin/debounce.rs | 8 +- examples/rp23/src/bin/flash.rs | 8 +- examples/rp23/src/bin/gpio_async.rs | 8 +- examples/rp23/src/bin/gpout.rs | 8 +- examples/rp23/src/bin/i2c_async.rs | 8 +- examples/rp23/src/bin/i2c_async_embassy.rs | 8 +- examples/rp23/src/bin/i2c_blocking.rs | 8 +- examples/rp23/src/bin/i2c_slave.rs | 8 +- examples/rp23/src/bin/interrupt.rs | 8 +- examples/rp23/src/bin/multicore.rs | 8 +- examples/rp23/src/bin/multiprio.rs | 8 +- examples/rp23/src/bin/pio_async.rs | 8 +- examples/rp23/src/bin/pio_dma.rs | 8 +- examples/rp23/src/bin/pio_hd44780.rs | 8 +- examples/rp23/src/bin/pio_i2s.rs | 8 +- examples/rp23/src/bin/pio_pwm.rs | 8 +- examples/rp23/src/bin/pio_rotary_encoder.rs | 8 +- examples/rp23/src/bin/pio_servo.rs | 8 +- examples/rp23/src/bin/pio_stepper.rs | 8 +- examples/rp23/src/bin/pio_ws2812.rs | 8 +- examples/rp23/src/bin/pwm.rs | 8 +- examples/rp23/src/bin/pwm_input.rs | 8 +- examples/rp23/src/bin/rosc.rs | 8 +- examples/rp23/src/bin/shared_bus.rs | 8 +- examples/rp23/src/bin/sharing.rs | 8 +- examples/rp23/src/bin/spi.rs | 8 +- examples/rp23/src/bin/spi_async.rs | 8 +- examples/rp23/src/bin/spi_display.rs | 8 +- examples/rp23/src/bin/spi_sdmmc.rs | 8 +- examples/rp23/src/bin/uart.rs | 8 +- examples/rp23/src/bin/uart_buffered_split.rs | 8 +- examples/rp23/src/bin/uart_r503.rs | 8 +- examples/rp23/src/bin/uart_unidir.rs | 8 +- examples/rp23/src/bin/usb_webusb.rs | 8 +- examples/rp23/src/bin/watchdog.rs | 8 +- examples/rp23/src/bin/zerocopy.rs | 8 +- 50 files changed, 178 insertions(+), 750 deletions(-) delete mode 100644 embassy-rp/src/binary_info/consts.rs delete mode 100644 embassy-rp/src/binary_info/macros.rs delete mode 100644 embassy-rp/src/binary_info/mod.rs delete mode 100644 embassy-rp/src/binary_info/types.rs diff --git a/ci.sh b/ci.sh index da842577d..70fe4f5d8 100755 --- a/ci.sh +++ b/ci.sh @@ -88,6 +88,7 @@ cargo batch \ --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features time-driver,qspi-as-gpio,rp2040 \ --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv8m.main-none-eabihf --features time-driver,defmt,rp235xa \ --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv8m.main-none-eabihf --features time-driver,log,rp235xa \ + --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv8m.main-none-eabihf --features time-driver,rp235xa,binary-info \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,exti,time \ diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index d0612957f..29a8a3c53 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml @@ -105,7 +105,7 @@ _test = [] ## ## Takes up a little flash space, but picotool can then report the name of your ## program and other details. -binary-info = [ "rt" ] +binary-info = ["rt", "dep:rp-binary-info", "rp-binary-info?/binary-info"] [dependencies] embassy-sync = { version = "0.6.0", path = "../embassy-sync" } @@ -143,6 +143,7 @@ pio = {version= "0.2.1" } rp2040-boot2 = "0.3" document-features = "0.2.7" sha2-const-stable = "0.1" +rp-binary-info = { version = "0.1.0", optional = true } [dev-dependencies] embassy-executor = { version = "0.6.0", path = "../embassy-executor", features = ["arch-std", "executor-thread"] } diff --git a/embassy-rp/src/binary_info/consts.rs b/embassy-rp/src/binary_info/consts.rs deleted file mode 100644 index d5fcd0d75..000000000 --- a/embassy-rp/src/binary_info/consts.rs +++ /dev/null @@ -1,34 +0,0 @@ -//! Constants for binary info - -// Credit: Taken from https://github.com/thejpster/rp-hal-rp2350-public (also licensed Apache 2.0 + MIT). -// Copyright (c) rp-rs organization - -/// All Raspberry Pi specified IDs have this tag. -/// -/// You can create your own for custom fields. -pub const TAG_RASPBERRY_PI: u16 = super::make_tag(b"RP"); - -/// Used to note the program name - use with StringEntry -pub const ID_RP_PROGRAM_NAME: u32 = 0x02031c86; -/// Used to note the program version - use with StringEntry -pub const ID_RP_PROGRAM_VERSION_STRING: u32 = 0x11a9bc3a; -/// Used to note the program build date - use with StringEntry -pub const ID_RP_PROGRAM_BUILD_DATE_STRING: u32 = 0x9da22254; -/// Used to note the size of the binary - use with IntegerEntry -pub const ID_RP_BINARY_END: u32 = 0x68f465de; -/// Used to note a URL for the program - use with StringEntry -pub const ID_RP_PROGRAM_URL: u32 = 0x1856239a; -/// Used to note a description of the program - use with StringEntry -pub const ID_RP_PROGRAM_DESCRIPTION: u32 = 0xb6a07c19; -/// Used to note some feature of the program - use with StringEntry -pub const ID_RP_PROGRAM_FEATURE: u32 = 0xa1f4b453; -/// Used to note some whether this was a Debug or Release build - use with StringEntry -pub const ID_RP_PROGRAM_BUILD_ATTRIBUTE: u32 = 0x4275f0d3; -/// Used to note the Pico SDK version used - use with StringEntry -pub const ID_RP_SDK_VERSION: u32 = 0x5360b3ab; -/// Used to note which board this program targets - use with StringEntry -pub const ID_RP_PICO_BOARD: u32 = 0xb63cffbb; -/// Used to note which `boot2` image this program uses - use with StringEntry -pub const ID_RP_BOOT2_NAME: u32 = 0x7f8882e1; - -// End of file diff --git a/embassy-rp/src/binary_info/macros.rs b/embassy-rp/src/binary_info/macros.rs deleted file mode 100644 index faf6148c8..000000000 --- a/embassy-rp/src/binary_info/macros.rs +++ /dev/null @@ -1,171 +0,0 @@ -//! Handy macros for making Binary Info entries - -// Credit: Taken from https://github.com/thejpster/rp-hal-rp2350-public (also licensed Apache 2.0 + MIT). -// Copyright (c) rp-rs organization - -/// Generate a static item containing the given environment variable, -/// and return its [`EntryAddr`](super::EntryAddr). -#[macro_export] -macro_rules! binary_info_env { - ($tag:expr, $id:expr, $env_var_name:expr) => { - $crate::binary_info_str!($tag, $id, { - let value = concat!(env!($env_var_name), "\0"); - // # Safety - // - // We used `concat!` to null-terminate on the line above. - let value_cstr = unsafe { core::ffi::CStr::from_bytes_with_nul_unchecked(value.as_bytes()) }; - value_cstr - }) - }; -} - -/// Generate a static item containing the given string, and return its -/// [`EntryAddr`](super::EntryAddr). -/// -/// You must pass a numeric tag, a numeric ID, and `&CStr` (which is always -/// null-terminated). -#[macro_export] -macro_rules! binary_info_str { - ($tag:expr, $id:expr, $str:expr) => {{ - static ENTRY: $crate::binary_info::StringEntry = $crate::binary_info::StringEntry::new($tag, $id, $str); - ENTRY.addr() - }}; -} - -/// Generate a static item containing the given string, and return its -/// [`EntryAddr`](super::EntryAddr). -/// -/// You must pass a numeric tag, a numeric ID, and `&CStr` (which is always -/// null-terminated). -#[macro_export] -macro_rules! binary_info_int { - ($tag:expr, $id:expr, $int:expr) => {{ - static ENTRY: $crate::binary_info::IntegerEntry = $crate::binary_info::IntegerEntry::new($tag, $id, $int); - ENTRY.addr() - }}; -} - -/// Generate a static item containing the program name, and return its -/// [`EntryAddr`](super::EntryAddr). -#[macro_export] -macro_rules! binary_info_rp_program_name { - ($name:expr) => { - $crate::binary_info_str!( - $crate::binary_info::consts::TAG_RASPBERRY_PI, - $crate::binary_info::consts::ID_RP_PROGRAM_NAME, - $name - ) - }; -} - -/// Generate a static item containing the `CARGO_BIN_NAME` as the program name, -/// and return its [`EntryAddr`](super::EntryAddr). -#[macro_export] -macro_rules! binary_info_rp_cargo_bin_name { - () => { - $crate::binary_info_env!( - $crate::binary_info::consts::TAG_RASPBERRY_PI, - $crate::binary_info::consts::ID_RP_PROGRAM_NAME, - "CARGO_BIN_NAME" - ) - }; -} - -/// Generate a static item containing the program version, and return its -/// [`EntryAddr`](super::EntryAddr). -#[macro_export] -macro_rules! binary_info_rp_program_version { - ($version:expr) => {{ - $crate::binary_info_str!( - $crate::binary_info::consts::TAG_RASPBERRY_PI, - $crate::binary_info::consts::ID_RP_PROGRAM_VERSION, - $version - ) - }}; -} - -/// Generate a static item containing the `CARGO_PKG_VERSION` as the program -/// version, and return its [`EntryAddr`](super::EntryAddr). -#[macro_export] -macro_rules! binary_info_rp_cargo_version { - () => { - $crate::binary_info_env!( - $crate::binary_info::consts::TAG_RASPBERRY_PI, - $crate::binary_info::consts::ID_RP_PROGRAM_VERSION_STRING, - "CARGO_PKG_VERSION" - ) - }; -} - -/// Generate a static item containing the program URL, and return its -/// [`EntryAddr`](super::EntryAddr). -#[macro_export] -macro_rules! binary_info_rp_program_url { - ($url:expr) => { - $crate::binary_info_str!( - $crate::binary_info::consts::TAG_RASPBERRY_PI, - $crate::binary_info::consts::ID_RP_PROGRAM_URL, - $url - ) - }; -} - -/// Generate a static item containing the `CARGO_PKG_HOMEPAGE` as the program URL, -/// and return its [`EntryAddr`](super::EntryAddr). -#[macro_export] -macro_rules! binary_info_rp_cargo_homepage_url { - () => { - $crate::binary_info_env!( - $crate::binary_info::consts::TAG_RASPBERRY_PI, - $crate::binary_info::consts::ID_RP_PROGRAM_URL, - "CARGO_PKG_HOMEPAGE" - ) - }; -} - -/// Generate a static item containing the program description, and return its -/// [`EntryAddr`](super::EntryAddr). -#[macro_export] -macro_rules! binary_info_rp_program_description { - ($description:expr) => { - $crate::binary_info_str!( - $crate::binary_info::consts::TAG_RASPBERRY_PI, - $crate::binary_info::consts::ID_RP_PROGRAM_DESCRIPTION, - $description - ) - }; -} - -/// Generate a static item containing whether this is a debug or a release -/// build, and return its [`EntryAddr`](super::EntryAddr). -#[macro_export] -macro_rules! binary_info_rp_program_build_attribute { - () => { - $crate::binary_info_str!( - $crate::binary_info::consts::TAG_RASPBERRY_PI, - $crate::binary_info::consts::ID_RP_PROGRAM_BUILD_ATTRIBUTE, - { - if cfg!(debug_assertions) { - c"debug" - } else { - c"release" - } - } - ) - }; -} - -/// Generate a static item containing the specific board this program runs on, -/// and return its [`EntryAddr`](super::EntryAddr). -#[macro_export] -macro_rules! binary_info_rp_pico_board { - ($board:expr) => { - $crate::binary_info_str!( - $crate::binary_info::consts::TAG_RASPBERRY_PI, - $crate::binary_info::consts::ID_RP_PICO_BOARD, - $board - ) - }; -} - -// End of file diff --git a/embassy-rp/src/binary_info/mod.rs b/embassy-rp/src/binary_info/mod.rs deleted file mode 100644 index ea475086b..000000000 --- a/embassy-rp/src/binary_info/mod.rs +++ /dev/null @@ -1,175 +0,0 @@ -//! Code and types for creating Picotool compatible "Binary Info" metadata -//! -//! Add something like this to your program, and compile with the "binary-info" -//! and "rt" features: -//! -//! ``` -//! #[link_section = ".bi_entries"] -//! #[used] -//! pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 3] = [ -//! embassy_rp::binary_info_rp_program_name!(c"Program Name Here"), -//! embassy_rp::binary_info_rp_cargo_version!(), -//! embassy_rp::binary_info_int!(embassy_rp::binary_info::make_tag(b"JP"), 0x0000_0001, 0x12345678), -//! ]; -//! ``` - -// Credit: Taken from https://github.com/thejpster/rp-hal-rp2350-public (also licensed Apache 2.0 + MIT). -// Copyright (c) rp-rs organization - -pub mod consts; - -mod types; -pub use types::*; - -#[macro_use] -mod macros; - -extern "C" { - /// The linker script sets this symbol to have the address of the first - /// entry in the `.bi_entries` section. - static __bi_entries_start: EntryAddr; - /// The linker script sets this symbol to have the address just past the - /// last entry in the `.bi_entries` section. - static __bi_entries_end: EntryAddr; - /// The linker script sets this symbol to have the address of the first - /// entry in the `.data` section. - static __sdata: u32; - /// The linker script sets this symbol to have the address just past the - /// first entry in the `.data` section. - static __edata: u32; - /// The linker script sets this symbol to have the address of the - /// initialisation data for the first entry in the `.data` section (i.e. a - /// flash address, not a RAM address). - static __sidata: u32; -} - -/// Picotool can find this block in our ELF file and report interesting -/// metadata. -/// -/// The data here tells picotool the start and end flash addresses of our -/// metadata. -#[cfg(feature = "binary-info")] -#[link_section = ".start_block"] -#[used] -pub static PICOTOOL_HEADER: Header = unsafe { - Header::new( - core::ptr::addr_of!(__bi_entries_start), - core::ptr::addr_of!(__bi_entries_end), - &MAPPING_TABLE, - ) -}; - -/// This tells picotool how to convert RAM addresses back into Flash addresses -#[cfg(feature = "binary-info")] -pub static MAPPING_TABLE: [MappingTableEntry; 2] = [ - // This is the entry for .data - MappingTableEntry { - source_addr_start: unsafe { core::ptr::addr_of!(__sidata) }, - dest_addr_start: unsafe { core::ptr::addr_of!(__sdata) }, - dest_addr_end: unsafe { core::ptr::addr_of!(__edata) }, - }, - // This is the terminating marker - MappingTableEntry::null(), -]; - -/// Create a 'Binary Info' entry containing the program name -/// -/// This is well-known to picotool, and will be displayed if you run `picotool info`. -/// -/// * Tag: [`consts::TAG_RASPBERRY_PI`] -/// * ID: [`consts::ID_RP_PROGRAM_NAME`] -pub const fn rp_program_name(name: &'static core::ffi::CStr) -> StringEntry { - StringEntry::new(consts::TAG_RASPBERRY_PI, consts::ID_RP_PROGRAM_NAME, name) -} - -/// Create a 'Binary Info' entry containing the program version. -/// -/// * Tag: [`consts::TAG_RASPBERRY_PI`] -/// * Id: [`consts::ID_RP_PROGRAM_VERSION_STRING`] -pub const fn rp_program_version(name: &'static core::ffi::CStr) -> StringEntry { - StringEntry::new(consts::TAG_RASPBERRY_PI, consts::ID_RP_PROGRAM_VERSION_STRING, name) -} - -/// Create a 'Binary Info' entry with a URL -/// -/// * Tag: [`consts::TAG_RASPBERRY_PI`] -/// * Id: [`consts::ID_RP_PROGRAM_URL`] -pub const fn rp_program_url(url: &'static core::ffi::CStr) -> StringEntry { - StringEntry::new(consts::TAG_RASPBERRY_PI, consts::ID_RP_PROGRAM_URL, url) -} - -/// Create a 'Binary Info' with the program build date -/// -/// * Tag: [`consts::TAG_RASPBERRY_PI`] -/// * Id: [`consts::ID_RP_PROGRAM_BUILD_DATE_STRING`] -pub const fn rp_program_build_date_string(value: &'static core::ffi::CStr) -> StringEntry { - StringEntry::new(consts::TAG_RASPBERRY_PI, consts::ID_RP_PROGRAM_BUILD_DATE_STRING, value) -} - -/// Create a 'Binary Info' with the size of the binary -/// -/// * Tag: [`consts::TAG_RASPBERRY_PI`] -/// * Id: [`consts::ID_RP_BINARY_END`] -pub const fn rp_binary_end(value: u32) -> IntegerEntry { - IntegerEntry::new(consts::TAG_RASPBERRY_PI, consts::ID_RP_BINARY_END, value) -} - -/// Create a 'Binary Info' with a description of the program -/// -/// * Tag: [`consts::TAG_RASPBERRY_PI`] -/// * Id: [`consts::ID_RP_PROGRAM_DESCRIPTION`] -pub const fn rp_program_description(value: &'static core::ffi::CStr) -> StringEntry { - StringEntry::new(consts::TAG_RASPBERRY_PI, consts::ID_RP_PROGRAM_DESCRIPTION, value) -} - -/// Create a 'Binary Info' with some feature of the program -/// -/// * Tag: [`consts::TAG_RASPBERRY_PI`] -/// * Id: [`consts::ID_RP_PROGRAM_FEATURE`] -pub const fn rp_program_feature(value: &'static core::ffi::CStr) -> StringEntry { - StringEntry::new(consts::TAG_RASPBERRY_PI, consts::ID_RP_PROGRAM_FEATURE, value) -} - -/// Create a 'Binary Info' with some whether this was a Debug or Release build -/// -/// * Tag: [`consts::TAG_RASPBERRY_PI`] -/// * Id: [`consts::ID_RP_PROGRAM_BUILD_ATTRIBUTE`] -pub const fn rp_program_build_attribute(value: &'static core::ffi::CStr) -> StringEntry { - StringEntry::new(consts::TAG_RASPBERRY_PI, consts::ID_RP_PROGRAM_BUILD_ATTRIBUTE, value) -} - -/// Create a 'Binary Info' with the Pico SDK version used -/// -/// * Tag: [`consts::TAG_RASPBERRY_PI`] -/// * Id: [`consts::ID_RP_SDK_VERSION`] -pub const fn rp_sdk_version(value: &'static core::ffi::CStr) -> StringEntry { - StringEntry::new(consts::TAG_RASPBERRY_PI, consts::ID_RP_SDK_VERSION, value) -} - -/// Create a 'Binary Info' with which board this program targets -/// -/// * Tag: [`consts::TAG_RASPBERRY_PI`] -/// * Id: [`consts::ID_RP_PICO_BOARD`] -pub const fn rp_pico_board(value: &'static core::ffi::CStr) -> StringEntry { - StringEntry::new(consts::TAG_RASPBERRY_PI, consts::ID_RP_PICO_BOARD, value) -} - -/// Create a 'Binary Info' with which `boot2` image this program uses -/// -/// * Tag: [`consts::TAG_RASPBERRY_PI`] -/// * Id: [`consts::ID_RP_BOOT2_NAME`] -pub const fn rp_boot2_name(value: &'static core::ffi::CStr) -> StringEntry { - StringEntry::new(consts::TAG_RASPBERRY_PI, consts::ID_RP_BOOT2_NAME, value) -} - -/// Create a tag from two ASCII letters. -/// -/// ``` -/// let tag = embassy_rp::binary_info::make_tag(b"RP"); -/// assert_eq!(tag, 0x5052); -/// ``` -pub const fn make_tag(c: &[u8; 2]) -> u16 { - u16::from_le_bytes(*c) -} - -// End of file diff --git a/embassy-rp/src/binary_info/types.rs b/embassy-rp/src/binary_info/types.rs deleted file mode 100644 index 6aec1902e..000000000 --- a/embassy-rp/src/binary_info/types.rs +++ /dev/null @@ -1,195 +0,0 @@ -//! Types for the Binary Info system - -// Credit: Taken from https://github.com/thejpster/rp-hal-rp2350-public (also licensed Apache 2.0 + MIT). -// Copyright (c) rp-rs organization - -/// This is the 'Binary Info' header block that `picotool` looks for in your UF2 -/// file/ELF file/Pico in Bootloader Mode to give you useful metadata about your -/// program. -/// -/// It should be placed in the first 4096 bytes of flash, so use your `memory.x` -/// to insert a section between `.text` and `.vector_table` and put a static -/// value of this type in that section. -#[repr(C)] -pub struct Header { - /// Must be equal to Picotool::MARKER_START - marker_start: u32, - /// The first in our table of pointers to Entries - entries_start: *const EntryAddr, - /// The last in our table of pointers to Entries - entries_end: *const EntryAddr, - /// The first entry in a null-terminated RAM/Flash mapping table - mapping_table: *const MappingTableEntry, - /// Must be equal to Picotool::MARKER_END - marker_end: u32, -} - -impl Header { - /// This is the `BINARY_INFO_MARKER_START` magic value from `picotool` - const MARKER_START: u32 = 0x7188ebf2; - /// This is the `BINARY_INFO_MARKER_END` magic value from `picotool` - const MARKER_END: u32 = 0xe71aa390; - - /// Create a new `picotool` compatible header. - /// - /// * `entries_start` - the first [`EntryAddr`] in the table - /// * `entries_end` - the last [`EntryAddr`] in the table - /// * `mapping_table` - the RAM/Flash address mapping table - pub const fn new( - entries_start: *const EntryAddr, - entries_end: *const EntryAddr, - mapping_table: &'static [MappingTableEntry], - ) -> Self { - let mapping_table = mapping_table.as_ptr(); - Self { - marker_start: Self::MARKER_START, - entries_start, - entries_end, - mapping_table, - marker_end: Self::MARKER_END, - } - } -} - -// We need this as rustc complains that is is unsafe to share `*const u32` -// pointers between threads. We only allow these to be created with static -// data, so this is OK. -unsafe impl Sync for Header {} - -/// This is a reference to an entry. It's like a `&dyn` ref to some type `T: -/// Entry`, except that the run-time type information is encoded into the -/// Entry itself in very specific way. -#[repr(transparent)] -pub struct EntryAddr(*const u32); - -// We need this as rustc complains that is is unsafe to share `*const u32` -// pointers between threads. We only allow these to be created with static -// data, so this is OK. -unsafe impl Sync for EntryAddr {} - -/// Allows us to tell picotool where values are in the UF2 given their run-time -/// address. -/// -/// The most obvious example is RAM variables, which must be found in the -/// `.data` section of the UF2. -#[repr(C)] -pub struct MappingTableEntry { - /// The start address in RAM (or wherever the address picotool finds will - /// point) - pub source_addr_start: *const u32, - /// The start address in flash (or whever the data actually lives in the - /// ELF) - pub dest_addr_start: *const u32, - /// The end address in flash - pub dest_addr_end: *const u32, -} - -impl MappingTableEntry { - /// Generate a null entry to mark the end of the list - pub const fn null() -> MappingTableEntry { - MappingTableEntry { - source_addr_start: core::ptr::null(), - dest_addr_start: core::ptr::null(), - dest_addr_end: core::ptr::null(), - } - } -} - -// We need this as rustc complains that is is unsafe to share `*const u32` -// pointers between threads. We only allow these to be created with static -// data, so this is OK. -unsafe impl Sync for MappingTableEntry {} - -/// This is the set of data types that `picotool` supports. -#[repr(u16)] -pub enum DataType { - /// Raw data - Raw = 1, - /// Data with a size - SizedData = 2, - /// A list of binary data - BinaryInfoListZeroTerminated = 3, - /// A BSON encoded blob - Bson = 4, - /// An Integer with an ID - IdAndInt = 5, - /// A string with an Id - IdAndString = 6, - /// A block device - BlockDevice = 7, - /// GPIO pins, with their function - PinsWithFunction = 8, - /// GPIO pins, with their name - PinsWithName = 9, - /// GPIO pins, with multiple names? - PinsWithNames = 10, -} - -/// All Entries start with this common header -#[repr(C)] -struct EntryCommon { - data_type: DataType, - tag: u16, -} - -/// An entry which contains both an ID (e.g. `ID_RP_PROGRAM_NAME`) and a pointer -/// to a null-terminated string. -#[repr(C)] -pub struct StringEntry { - header: EntryCommon, - id: u32, - value: *const core::ffi::c_char, -} - -impl StringEntry { - /// Create a new `StringEntry` - pub const fn new(tag: u16, id: u32, value: &'static core::ffi::CStr) -> StringEntry { - StringEntry { - header: EntryCommon { - data_type: DataType::IdAndString, - tag, - }, - id, - value: value.as_ptr(), - } - } - - /// Get this entry's address - pub const fn addr(&self) -> EntryAddr { - EntryAddr(self as *const Self as *const u32) - } -} - -// We need this as rustc complains that is is unsafe to share `*const -// core::ffi::c_char` pointers between threads. We only allow these to be -// created with static string slices, so it's OK. -unsafe impl Sync for StringEntry {} - -/// An entry which contains both an ID (e.g. `ID_RP_BINARY_END`) and an integer. -#[repr(C)] -pub struct IntegerEntry { - header: EntryCommon, - id: u32, - value: u32, -} - -impl IntegerEntry { - /// Create a new `StringEntry` - pub const fn new(tag: u16, id: u32, value: u32) -> IntegerEntry { - IntegerEntry { - header: EntryCommon { - data_type: DataType::IdAndInt, - tag, - }, - id, - value, - } - } - - /// Get this entry's address - pub const fn addr(&self) -> EntryAddr { - EntryAddr(self as *const Self as *const u32) - } -} - -// End of file diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs index 1fc397107..21f0771de 100644 --- a/embassy-rp/src/lib.rs +++ b/embassy-rp/src/lib.rs @@ -9,6 +9,9 @@ // This mod MUST go first, so that the others see its macros. pub(crate) mod fmt; +#[cfg(feature = "binary-info")] +pub use rp_binary_info as binary_info; + #[cfg(feature = "critical-section-impl")] mod critical_section_impl; @@ -16,8 +19,6 @@ mod intrinsics; pub mod adc; #[cfg(feature = "_rp235x")] -pub mod binary_info; -#[cfg(feature = "_rp235x")] pub mod block; #[cfg(feature = "rp2040")] pub mod bootsel; diff --git a/examples/rp23/src/bin/adc.rs b/examples/rp23/src/bin/adc.rs index 19872607e..d1f053d39 100644 --- a/examples/rp23/src/bin/adc.rs +++ b/examples/rp23/src/bin/adc.rs @@ -21,10 +21,10 @@ pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); #[link_section = ".bi_entries"] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info_rp_cargo_bin_name!(), - embassy_rp::binary_info_rp_cargo_version!(), - embassy_rp::binary_info_rp_program_description!(c"Blinky"), - embassy_rp::binary_info_rp_program_build_attribute!(), + embassy_rp::binary_info::rp_program_name!(c"example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_build_attribute!(), ]; bind_interrupts!(struct Irqs { diff --git a/examples/rp23/src/bin/adc_dma.rs b/examples/rp23/src/bin/adc_dma.rs index d538ddaa2..5046e5530 100644 --- a/examples/rp23/src/bin/adc_dma.rs +++ b/examples/rp23/src/bin/adc_dma.rs @@ -21,10 +21,10 @@ pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); #[link_section = ".bi_entries"] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info_rp_cargo_bin_name!(), - embassy_rp::binary_info_rp_cargo_version!(), - embassy_rp::binary_info_rp_program_description!(c"Blinky"), - embassy_rp::binary_info_rp_program_build_attribute!(), + embassy_rp::binary_info::rp_program_name!(c"example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_build_attribute!(), ]; bind_interrupts!(struct Irqs { diff --git a/examples/rp23/src/bin/assign_resources.rs b/examples/rp23/src/bin/assign_resources.rs index 923c13514..2f9783917 100644 --- a/examples/rp23/src/bin/assign_resources.rs +++ b/examples/rp23/src/bin/assign_resources.rs @@ -28,10 +28,10 @@ pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); #[link_section = ".bi_entries"] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info_rp_cargo_bin_name!(), - embassy_rp::binary_info_rp_cargo_version!(), - embassy_rp::binary_info_rp_program_description!(c"Blinky"), - embassy_rp::binary_info_rp_program_build_attribute!(), + embassy_rp::binary_info::rp_program_name!(c"example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_build_attribute!(), ]; #[embassy_executor::main] diff --git a/examples/rp23/src/bin/blinky.rs b/examples/rp23/src/bin/blinky.rs index 02bdf9b3d..9e45679c8 100644 --- a/examples/rp23/src/bin/blinky.rs +++ b/examples/rp23/src/bin/blinky.rs @@ -21,10 +21,10 @@ pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); #[link_section = ".bi_entries"] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info_rp_cargo_bin_name!(), - embassy_rp::binary_info_rp_cargo_version!(), - embassy_rp::binary_info_rp_program_description!(c"Blinky"), - embassy_rp::binary_info_rp_program_build_attribute!(), + embassy_rp::binary_info::rp_program_name!(c"example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_build_attribute!(), ]; #[embassy_executor::main] diff --git a/examples/rp23/src/bin/blinky_two_channels.rs b/examples/rp23/src/bin/blinky_two_channels.rs index 4d7dc89fa..87fc58bbc 100644 --- a/examples/rp23/src/bin/blinky_two_channels.rs +++ b/examples/rp23/src/bin/blinky_two_channels.rs @@ -23,10 +23,10 @@ pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); #[link_section = ".bi_entries"] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info_rp_cargo_bin_name!(), - embassy_rp::binary_info_rp_cargo_version!(), - embassy_rp::binary_info_rp_program_description!(c"Blinky"), - embassy_rp::binary_info_rp_program_build_attribute!(), + embassy_rp::binary_info::rp_program_name!(c"example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_build_attribute!(), ]; enum LedState { diff --git a/examples/rp23/src/bin/blinky_two_tasks.rs b/examples/rp23/src/bin/blinky_two_tasks.rs index 24b960242..40236c53b 100644 --- a/examples/rp23/src/bin/blinky_two_tasks.rs +++ b/examples/rp23/src/bin/blinky_two_tasks.rs @@ -23,10 +23,10 @@ pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); #[link_section = ".bi_entries"] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info_rp_cargo_bin_name!(), - embassy_rp::binary_info_rp_cargo_version!(), - embassy_rp::binary_info_rp_program_description!(c"Blinky"), - embassy_rp::binary_info_rp_program_build_attribute!(), + embassy_rp::binary_info::rp_program_name!(c"example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_build_attribute!(), ]; type LedType = Mutex>>; diff --git a/examples/rp23/src/bin/button.rs b/examples/rp23/src/bin/button.rs index 0a0559397..fb067a370 100644 --- a/examples/rp23/src/bin/button.rs +++ b/examples/rp23/src/bin/button.rs @@ -18,10 +18,10 @@ pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); #[link_section = ".bi_entries"] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info_rp_cargo_bin_name!(), - embassy_rp::binary_info_rp_cargo_version!(), - embassy_rp::binary_info_rp_program_description!(c"Blinky"), - embassy_rp::binary_info_rp_program_build_attribute!(), + embassy_rp::binary_info::rp_program_name!(c"example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_build_attribute!(), ]; #[embassy_executor::main] diff --git a/examples/rp23/src/bin/debounce.rs b/examples/rp23/src/bin/debounce.rs index e82e71f61..e672521ec 100644 --- a/examples/rp23/src/bin/debounce.rs +++ b/examples/rp23/src/bin/debounce.rs @@ -19,10 +19,10 @@ pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); #[link_section = ".bi_entries"] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info_rp_cargo_bin_name!(), - embassy_rp::binary_info_rp_cargo_version!(), - embassy_rp::binary_info_rp_program_description!(c"Blinky"), - embassy_rp::binary_info_rp_program_build_attribute!(), + embassy_rp::binary_info::rp_program_name!(c"example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_build_attribute!(), ]; pub struct Debouncer<'a> { diff --git a/examples/rp23/src/bin/flash.rs b/examples/rp23/src/bin/flash.rs index 2917dda0b..811561f26 100644 --- a/examples/rp23/src/bin/flash.rs +++ b/examples/rp23/src/bin/flash.rs @@ -19,10 +19,10 @@ pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); #[link_section = ".bi_entries"] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info_rp_cargo_bin_name!(), - embassy_rp::binary_info_rp_cargo_version!(), - embassy_rp::binary_info_rp_program_description!(c"Blinky"), - embassy_rp::binary_info_rp_program_build_attribute!(), + embassy_rp::binary_info::rp_program_name!(c"example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_build_attribute!(), ]; const ADDR_OFFSET: u32 = 0x100000; diff --git a/examples/rp23/src/bin/gpio_async.rs b/examples/rp23/src/bin/gpio_async.rs index 1618f7c8b..ff12367bf 100644 --- a/examples/rp23/src/bin/gpio_async.rs +++ b/examples/rp23/src/bin/gpio_async.rs @@ -21,10 +21,10 @@ pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); #[link_section = ".bi_entries"] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info_rp_cargo_bin_name!(), - embassy_rp::binary_info_rp_cargo_version!(), - embassy_rp::binary_info_rp_program_description!(c"Blinky"), - embassy_rp::binary_info_rp_program_build_attribute!(), + embassy_rp::binary_info::rp_program_name!(c"example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_build_attribute!(), ]; /// It requires an external signal to be manually triggered on PIN 16. For diff --git a/examples/rp23/src/bin/gpout.rs b/examples/rp23/src/bin/gpout.rs index b15963f02..d2ee55197 100644 --- a/examples/rp23/src/bin/gpout.rs +++ b/examples/rp23/src/bin/gpout.rs @@ -20,10 +20,10 @@ pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); #[link_section = ".bi_entries"] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info_rp_cargo_bin_name!(), - embassy_rp::binary_info_rp_cargo_version!(), - embassy_rp::binary_info_rp_program_description!(c"Blinky"), - embassy_rp::binary_info_rp_program_build_attribute!(), + embassy_rp::binary_info::rp_program_name!(c"example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_build_attribute!(), ]; #[embassy_executor::main] diff --git a/examples/rp23/src/bin/i2c_async.rs b/examples/rp23/src/bin/i2c_async.rs index 2528fe1d2..c8d918b56 100644 --- a/examples/rp23/src/bin/i2c_async.rs +++ b/examples/rp23/src/bin/i2c_async.rs @@ -24,10 +24,10 @@ pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); #[link_section = ".bi_entries"] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info_rp_cargo_bin_name!(), - embassy_rp::binary_info_rp_cargo_version!(), - embassy_rp::binary_info_rp_program_description!(c"Blinky"), - embassy_rp::binary_info_rp_program_build_attribute!(), + embassy_rp::binary_info::rp_program_name!(c"example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_build_attribute!(), ]; bind_interrupts!(struct Irqs { diff --git a/examples/rp23/src/bin/i2c_async_embassy.rs b/examples/rp23/src/bin/i2c_async_embassy.rs index 461b1d171..cce0abcde 100644 --- a/examples/rp23/src/bin/i2c_async_embassy.rs +++ b/examples/rp23/src/bin/i2c_async_embassy.rs @@ -19,10 +19,10 @@ pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); #[link_section = ".bi_entries"] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info_rp_cargo_bin_name!(), - embassy_rp::binary_info_rp_cargo_version!(), - embassy_rp::binary_info_rp_program_description!(c"Blinky"), - embassy_rp::binary_info_rp_program_build_attribute!(), + embassy_rp::binary_info::rp_program_name!(c"example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_build_attribute!(), ]; // Our anonymous hypotetical temperature sensor could be: diff --git a/examples/rp23/src/bin/i2c_blocking.rs b/examples/rp23/src/bin/i2c_blocking.rs index 6d36d1890..85c33bf0d 100644 --- a/examples/rp23/src/bin/i2c_blocking.rs +++ b/examples/rp23/src/bin/i2c_blocking.rs @@ -22,10 +22,10 @@ pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); #[link_section = ".bi_entries"] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info_rp_cargo_bin_name!(), - embassy_rp::binary_info_rp_cargo_version!(), - embassy_rp::binary_info_rp_program_description!(c"Blinky"), - embassy_rp::binary_info_rp_program_build_attribute!(), + embassy_rp::binary_info::rp_program_name!(c"example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_build_attribute!(), ]; #[allow(dead_code)] diff --git a/examples/rp23/src/bin/i2c_slave.rs b/examples/rp23/src/bin/i2c_slave.rs index 1f3408cf3..fb5f3cda1 100644 --- a/examples/rp23/src/bin/i2c_slave.rs +++ b/examples/rp23/src/bin/i2c_slave.rs @@ -19,10 +19,10 @@ pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); #[link_section = ".bi_entries"] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info_rp_cargo_bin_name!(), - embassy_rp::binary_info_rp_cargo_version!(), - embassy_rp::binary_info_rp_program_description!(c"Blinky"), - embassy_rp::binary_info_rp_program_build_attribute!(), + embassy_rp::binary_info::rp_program_name!(c"example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_build_attribute!(), ]; bind_interrupts!(struct Irqs { diff --git a/examples/rp23/src/bin/interrupt.rs b/examples/rp23/src/bin/interrupt.rs index 6184b1bd7..ee3d9bfe7 100644 --- a/examples/rp23/src/bin/interrupt.rs +++ b/examples/rp23/src/bin/interrupt.rs @@ -33,10 +33,10 @@ pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); #[link_section = ".bi_entries"] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info_rp_cargo_bin_name!(), - embassy_rp::binary_info_rp_cargo_version!(), - embassy_rp::binary_info_rp_program_description!(c"Blinky"), - embassy_rp::binary_info_rp_program_build_attribute!(), + embassy_rp::binary_info::rp_program_name!(c"example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_build_attribute!(), ]; static COUNTER: AtomicU32 = AtomicU32::new(0); diff --git a/examples/rp23/src/bin/multicore.rs b/examples/rp23/src/bin/multicore.rs index 8649143e1..9ab43d7a5 100644 --- a/examples/rp23/src/bin/multicore.rs +++ b/examples/rp23/src/bin/multicore.rs @@ -24,10 +24,10 @@ pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); #[link_section = ".bi_entries"] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info_rp_cargo_bin_name!(), - embassy_rp::binary_info_rp_cargo_version!(), - embassy_rp::binary_info_rp_program_description!(c"Blinky"), - embassy_rp::binary_info_rp_program_build_attribute!(), + embassy_rp::binary_info::rp_program_name!(c"example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_build_attribute!(), ]; static mut CORE1_STACK: Stack<4096> = Stack::new(); diff --git a/examples/rp23/src/bin/multiprio.rs b/examples/rp23/src/bin/multiprio.rs index 7590fb431..27cd3656e 100644 --- a/examples/rp23/src/bin/multiprio.rs +++ b/examples/rp23/src/bin/multiprio.rs @@ -74,10 +74,10 @@ pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); #[link_section = ".bi_entries"] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info_rp_cargo_bin_name!(), - embassy_rp::binary_info_rp_cargo_version!(), - embassy_rp::binary_info_rp_program_description!(c"Blinky"), - embassy_rp::binary_info_rp_program_build_attribute!(), + embassy_rp::binary_info::rp_program_name!(c"example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_build_attribute!(), ]; #[embassy_executor::task] diff --git a/examples/rp23/src/bin/pio_async.rs b/examples/rp23/src/bin/pio_async.rs index 005708bc2..231afc80e 100644 --- a/examples/rp23/src/bin/pio_async.rs +++ b/examples/rp23/src/bin/pio_async.rs @@ -20,10 +20,10 @@ pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); #[link_section = ".bi_entries"] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info_rp_cargo_bin_name!(), - embassy_rp::binary_info_rp_cargo_version!(), - embassy_rp::binary_info_rp_program_description!(c"Blinky"), - embassy_rp::binary_info_rp_program_build_attribute!(), + embassy_rp::binary_info::rp_program_name!(c"example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_build_attribute!(), ]; bind_interrupts!(struct Irqs { diff --git a/examples/rp23/src/bin/pio_dma.rs b/examples/rp23/src/bin/pio_dma.rs index 48fd9123f..60fbcb83a 100644 --- a/examples/rp23/src/bin/pio_dma.rs +++ b/examples/rp23/src/bin/pio_dma.rs @@ -21,10 +21,10 @@ pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); #[link_section = ".bi_entries"] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info_rp_cargo_bin_name!(), - embassy_rp::binary_info_rp_cargo_version!(), - embassy_rp::binary_info_rp_program_description!(c"Blinky"), - embassy_rp::binary_info_rp_program_build_attribute!(), + embassy_rp::binary_info::rp_program_name!(c"example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_build_attribute!(), ]; bind_interrupts!(struct Irqs { diff --git a/examples/rp23/src/bin/pio_hd44780.rs b/examples/rp23/src/bin/pio_hd44780.rs index fc658267d..92aa858f9 100644 --- a/examples/rp23/src/bin/pio_hd44780.rs +++ b/examples/rp23/src/bin/pio_hd44780.rs @@ -26,10 +26,10 @@ pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); #[link_section = ".bi_entries"] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info_rp_cargo_bin_name!(), - embassy_rp::binary_info_rp_cargo_version!(), - embassy_rp::binary_info_rp_program_description!(c"Blinky"), - embassy_rp::binary_info_rp_program_build_attribute!(), + embassy_rp::binary_info::rp_program_name!(c"example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_build_attribute!(), ]; bind_interrupts!(pub struct Irqs { diff --git a/examples/rp23/src/bin/pio_i2s.rs b/examples/rp23/src/bin/pio_i2s.rs index 5a3bde759..d6d2d0ade 100644 --- a/examples/rp23/src/bin/pio_i2s.rs +++ b/examples/rp23/src/bin/pio_i2s.rs @@ -29,10 +29,10 @@ pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); #[link_section = ".bi_entries"] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info_rp_cargo_bin_name!(), - embassy_rp::binary_info_rp_cargo_version!(), - embassy_rp::binary_info_rp_program_description!(c"Blinky"), - embassy_rp::binary_info_rp_program_build_attribute!(), + embassy_rp::binary_info::rp_program_name!(c"example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_build_attribute!(), ]; bind_interrupts!(struct Irqs { diff --git a/examples/rp23/src/bin/pio_pwm.rs b/examples/rp23/src/bin/pio_pwm.rs index 7c5eefc45..587f91ac3 100644 --- a/examples/rp23/src/bin/pio_pwm.rs +++ b/examples/rp23/src/bin/pio_pwm.rs @@ -22,10 +22,10 @@ pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); #[link_section = ".bi_entries"] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info_rp_cargo_bin_name!(), - embassy_rp::binary_info_rp_cargo_version!(), - embassy_rp::binary_info_rp_program_description!(c"Blinky"), - embassy_rp::binary_info_rp_program_build_attribute!(), + embassy_rp::binary_info::rp_program_name!(c"example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_build_attribute!(), ]; const REFRESH_INTERVAL: u64 = 20000; diff --git a/examples/rp23/src/bin/pio_rotary_encoder.rs b/examples/rp23/src/bin/pio_rotary_encoder.rs index 287992a83..c147351e8 100644 --- a/examples/rp23/src/bin/pio_rotary_encoder.rs +++ b/examples/rp23/src/bin/pio_rotary_encoder.rs @@ -21,10 +21,10 @@ pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); #[link_section = ".bi_entries"] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info_rp_cargo_bin_name!(), - embassy_rp::binary_info_rp_cargo_version!(), - embassy_rp::binary_info_rp_program_description!(c"Blinky"), - embassy_rp::binary_info_rp_program_build_attribute!(), + embassy_rp::binary_info::rp_program_name!(c"example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_build_attribute!(), ]; bind_interrupts!(struct Irqs { diff --git a/examples/rp23/src/bin/pio_servo.rs b/examples/rp23/src/bin/pio_servo.rs index 1dec86927..5e8714178 100644 --- a/examples/rp23/src/bin/pio_servo.rs +++ b/examples/rp23/src/bin/pio_servo.rs @@ -22,10 +22,10 @@ pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); #[link_section = ".bi_entries"] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info_rp_cargo_bin_name!(), - embassy_rp::binary_info_rp_cargo_version!(), - embassy_rp::binary_info_rp_program_description!(c"Blinky"), - embassy_rp::binary_info_rp_program_build_attribute!(), + embassy_rp::binary_info::rp_program_name!(c"example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_build_attribute!(), ]; const DEFAULT_MIN_PULSE_WIDTH: u64 = 1000; // uncalibrated default, the shortest duty cycle sent to a servo diff --git a/examples/rp23/src/bin/pio_stepper.rs b/examples/rp23/src/bin/pio_stepper.rs index 8b52dc37a..24785443b 100644 --- a/examples/rp23/src/bin/pio_stepper.rs +++ b/examples/rp23/src/bin/pio_stepper.rs @@ -25,10 +25,10 @@ pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); #[link_section = ".bi_entries"] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info_rp_cargo_bin_name!(), - embassy_rp::binary_info_rp_cargo_version!(), - embassy_rp::binary_info_rp_program_description!(c"Blinky"), - embassy_rp::binary_info_rp_program_build_attribute!(), + embassy_rp::binary_info::rp_program_name!(c"example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_build_attribute!(), ]; bind_interrupts!(struct Irqs { diff --git a/examples/rp23/src/bin/pio_ws2812.rs b/examples/rp23/src/bin/pio_ws2812.rs index 99d9cf7e6..00fe5e396 100644 --- a/examples/rp23/src/bin/pio_ws2812.rs +++ b/examples/rp23/src/bin/pio_ws2812.rs @@ -27,10 +27,10 @@ pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); #[link_section = ".bi_entries"] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info_rp_cargo_bin_name!(), - embassy_rp::binary_info_rp_cargo_version!(), - embassy_rp::binary_info_rp_program_description!(c"Blinky"), - embassy_rp::binary_info_rp_program_build_attribute!(), + embassy_rp::binary_info::rp_program_name!(c"example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_build_attribute!(), ]; bind_interrupts!(struct Irqs { diff --git a/examples/rp23/src/bin/pwm.rs b/examples/rp23/src/bin/pwm.rs index 4cd3b3eb4..bfc2c6f67 100644 --- a/examples/rp23/src/bin/pwm.rs +++ b/examples/rp23/src/bin/pwm.rs @@ -20,10 +20,10 @@ pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); #[link_section = ".bi_entries"] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info_rp_cargo_bin_name!(), - embassy_rp::binary_info_rp_cargo_version!(), - embassy_rp::binary_info_rp_program_description!(c"Blinky"), - embassy_rp::binary_info_rp_program_build_attribute!(), + embassy_rp::binary_info::rp_program_name!(c"example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_build_attribute!(), ]; #[embassy_executor::main] diff --git a/examples/rp23/src/bin/pwm_input.rs b/examples/rp23/src/bin/pwm_input.rs index b75d04963..b65f2778b 100644 --- a/examples/rp23/src/bin/pwm_input.rs +++ b/examples/rp23/src/bin/pwm_input.rs @@ -19,10 +19,10 @@ pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); #[link_section = ".bi_entries"] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info_rp_cargo_bin_name!(), - embassy_rp::binary_info_rp_cargo_version!(), - embassy_rp::binary_info_rp_program_description!(c"Blinky"), - embassy_rp::binary_info_rp_program_build_attribute!(), + embassy_rp::binary_info::rp_program_name!(c"example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_build_attribute!(), ]; #[embassy_executor::main] diff --git a/examples/rp23/src/bin/rosc.rs b/examples/rp23/src/bin/rosc.rs index 28c778f51..f65b236b1 100644 --- a/examples/rp23/src/bin/rosc.rs +++ b/examples/rp23/src/bin/rosc.rs @@ -21,10 +21,10 @@ pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); #[link_section = ".bi_entries"] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info_rp_cargo_bin_name!(), - embassy_rp::binary_info_rp_cargo_version!(), - embassy_rp::binary_info_rp_program_description!(c"Blinky"), - embassy_rp::binary_info_rp_program_build_attribute!(), + embassy_rp::binary_info::rp_program_name!(c"example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_build_attribute!(), ]; #[embassy_executor::main] diff --git a/examples/rp23/src/bin/shared_bus.rs b/examples/rp23/src/bin/shared_bus.rs index 00e65f80d..b3fde13e3 100644 --- a/examples/rp23/src/bin/shared_bus.rs +++ b/examples/rp23/src/bin/shared_bus.rs @@ -27,10 +27,10 @@ pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); #[link_section = ".bi_entries"] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info_rp_cargo_bin_name!(), - embassy_rp::binary_info_rp_cargo_version!(), - embassy_rp::binary_info_rp_program_description!(c"Blinky"), - embassy_rp::binary_info_rp_program_build_attribute!(), + embassy_rp::binary_info::rp_program_name!(c"example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_build_attribute!(), ]; type Spi1Bus = Mutex>; diff --git a/examples/rp23/src/bin/sharing.rs b/examples/rp23/src/bin/sharing.rs index b5ef08147..4a3301cfd 100644 --- a/examples/rp23/src/bin/sharing.rs +++ b/examples/rp23/src/bin/sharing.rs @@ -40,10 +40,10 @@ pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); #[link_section = ".bi_entries"] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info_rp_cargo_bin_name!(), - embassy_rp::binary_info_rp_cargo_version!(), - embassy_rp::binary_info_rp_program_description!(c"Blinky"), - embassy_rp::binary_info_rp_program_build_attribute!(), + embassy_rp::binary_info::rp_program_name!(c"example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_build_attribute!(), ]; type UartAsyncMutex = mutex::Mutex>; diff --git a/examples/rp23/src/bin/spi.rs b/examples/rp23/src/bin/spi.rs index 98aa7622c..924873e60 100644 --- a/examples/rp23/src/bin/spi.rs +++ b/examples/rp23/src/bin/spi.rs @@ -21,10 +21,10 @@ pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); #[link_section = ".bi_entries"] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info_rp_cargo_bin_name!(), - embassy_rp::binary_info_rp_cargo_version!(), - embassy_rp::binary_info_rp_program_description!(c"Blinky"), - embassy_rp::binary_info_rp_program_build_attribute!(), + embassy_rp::binary_info::rp_program_name!(c"example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_build_attribute!(), ]; #[embassy_executor::main] diff --git a/examples/rp23/src/bin/spi_async.rs b/examples/rp23/src/bin/spi_async.rs index 71eaa5c05..4a74f991c 100644 --- a/examples/rp23/src/bin/spi_async.rs +++ b/examples/rp23/src/bin/spi_async.rs @@ -19,10 +19,10 @@ pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); #[link_section = ".bi_entries"] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info_rp_cargo_bin_name!(), - embassy_rp::binary_info_rp_cargo_version!(), - embassy_rp::binary_info_rp_program_description!(c"Blinky"), - embassy_rp::binary_info_rp_program_build_attribute!(), + embassy_rp::binary_info::rp_program_name!(c"example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_build_attribute!(), ]; #[embassy_executor::main] diff --git a/examples/rp23/src/bin/spi_display.rs b/examples/rp23/src/bin/spi_display.rs index 2441b1186..71dd84658 100644 --- a/examples/rp23/src/bin/spi_display.rs +++ b/examples/rp23/src/bin/spi_display.rs @@ -36,10 +36,10 @@ pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); #[link_section = ".bi_entries"] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info_rp_cargo_bin_name!(), - embassy_rp::binary_info_rp_cargo_version!(), - embassy_rp::binary_info_rp_program_description!(c"Blinky"), - embassy_rp::binary_info_rp_program_build_attribute!(), + embassy_rp::binary_info::rp_program_name!(c"example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_build_attribute!(), ]; use crate::my_display_interface::SPIDeviceInterface; diff --git a/examples/rp23/src/bin/spi_sdmmc.rs b/examples/rp23/src/bin/spi_sdmmc.rs index d7af77a30..dabf41ab8 100644 --- a/examples/rp23/src/bin/spi_sdmmc.rs +++ b/examples/rp23/src/bin/spi_sdmmc.rs @@ -25,10 +25,10 @@ pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); #[link_section = ".bi_entries"] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info_rp_cargo_bin_name!(), - embassy_rp::binary_info_rp_cargo_version!(), - embassy_rp::binary_info_rp_program_description!(c"Blinky"), - embassy_rp::binary_info_rp_program_build_attribute!(), + embassy_rp::binary_info::rp_program_name!(c"example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_build_attribute!(), ]; struct DummyTimesource(); diff --git a/examples/rp23/src/bin/uart.rs b/examples/rp23/src/bin/uart.rs index ae00f36dc..0ffe0b293 100644 --- a/examples/rp23/src/bin/uart.rs +++ b/examples/rp23/src/bin/uart.rs @@ -20,10 +20,10 @@ pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); #[link_section = ".bi_entries"] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info_rp_cargo_bin_name!(), - embassy_rp::binary_info_rp_cargo_version!(), - embassy_rp::binary_info_rp_program_description!(c"Blinky"), - embassy_rp::binary_info_rp_program_build_attribute!(), + embassy_rp::binary_info::rp_program_name!(c"example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_build_attribute!(), ]; #[embassy_executor::main] diff --git a/examples/rp23/src/bin/uart_buffered_split.rs b/examples/rp23/src/bin/uart_buffered_split.rs index 2b14520d5..4e69a20c4 100644 --- a/examples/rp23/src/bin/uart_buffered_split.rs +++ b/examples/rp23/src/bin/uart_buffered_split.rs @@ -26,10 +26,10 @@ pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); #[link_section = ".bi_entries"] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info_rp_cargo_bin_name!(), - embassy_rp::binary_info_rp_cargo_version!(), - embassy_rp::binary_info_rp_program_description!(c"Blinky"), - embassy_rp::binary_info_rp_program_build_attribute!(), + embassy_rp::binary_info::rp_program_name!(c"example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_build_attribute!(), ]; bind_interrupts!(struct Irqs { diff --git a/examples/rp23/src/bin/uart_r503.rs b/examples/rp23/src/bin/uart_r503.rs index 39a17d305..5ac8839e3 100644 --- a/examples/rp23/src/bin/uart_r503.rs +++ b/examples/rp23/src/bin/uart_r503.rs @@ -19,10 +19,10 @@ pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); #[link_section = ".bi_entries"] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info_rp_cargo_bin_name!(), - embassy_rp::binary_info_rp_cargo_version!(), - embassy_rp::binary_info_rp_program_description!(c"Blinky"), - embassy_rp::binary_info_rp_program_build_attribute!(), + embassy_rp::binary_info::rp_program_name!(c"example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_build_attribute!(), ]; bind_interrupts!(pub struct Irqs { diff --git a/examples/rp23/src/bin/uart_unidir.rs b/examples/rp23/src/bin/uart_unidir.rs index 38210a8d0..988e44a79 100644 --- a/examples/rp23/src/bin/uart_unidir.rs +++ b/examples/rp23/src/bin/uart_unidir.rs @@ -25,10 +25,10 @@ pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); #[link_section = ".bi_entries"] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info_rp_cargo_bin_name!(), - embassy_rp::binary_info_rp_cargo_version!(), - embassy_rp::binary_info_rp_program_description!(c"Blinky"), - embassy_rp::binary_info_rp_program_build_attribute!(), + embassy_rp::binary_info::rp_program_name!(c"example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_build_attribute!(), ]; bind_interrupts!(struct Irqs { diff --git a/examples/rp23/src/bin/usb_webusb.rs b/examples/rp23/src/bin/usb_webusb.rs index f4ecde30e..3ade2226b 100644 --- a/examples/rp23/src/bin/usb_webusb.rs +++ b/examples/rp23/src/bin/usb_webusb.rs @@ -38,10 +38,10 @@ pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); #[link_section = ".bi_entries"] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info_rp_cargo_bin_name!(), - embassy_rp::binary_info_rp_cargo_version!(), - embassy_rp::binary_info_rp_program_description!(c"Blinky"), - embassy_rp::binary_info_rp_program_build_attribute!(), + embassy_rp::binary_info::rp_program_name!(c"example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_build_attribute!(), ]; bind_interrupts!(struct Irqs { diff --git a/examples/rp23/src/bin/watchdog.rs b/examples/rp23/src/bin/watchdog.rs index 3ac457219..a901c1164 100644 --- a/examples/rp23/src/bin/watchdog.rs +++ b/examples/rp23/src/bin/watchdog.rs @@ -22,10 +22,10 @@ pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); #[link_section = ".bi_entries"] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info_rp_cargo_bin_name!(), - embassy_rp::binary_info_rp_cargo_version!(), - embassy_rp::binary_info_rp_program_description!(c"Blinky"), - embassy_rp::binary_info_rp_program_build_attribute!(), + embassy_rp::binary_info::rp_program_name!(c"example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_build_attribute!(), ]; #[embassy_executor::main] diff --git a/examples/rp23/src/bin/zerocopy.rs b/examples/rp23/src/bin/zerocopy.rs index d04e1bf2a..86fca6f12 100644 --- a/examples/rp23/src/bin/zerocopy.rs +++ b/examples/rp23/src/bin/zerocopy.rs @@ -27,10 +27,10 @@ pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); #[link_section = ".bi_entries"] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info_rp_cargo_bin_name!(), - embassy_rp::binary_info_rp_cargo_version!(), - embassy_rp::binary_info_rp_program_description!(c"Blinky"), - embassy_rp::binary_info_rp_program_build_attribute!(), + embassy_rp::binary_info::rp_program_name!(c"example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_build_attribute!(), ]; type SampleBuffer = [u16; 512]; From a91de8d6b02e9ea69e9f2c62f11f590c64e771a2 Mon Sep 17 00:00:00 2001 From: Rafael Bachmann Date: Sun, 18 Aug 2024 10:36:04 +0200 Subject: [PATCH 0034/1217] Fix link to PriorityChannel Fix: #2899 --- embassy-sync/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-sync/README.md b/embassy-sync/README.md index dec1fbc32..97a663d6d 100644 --- a/embassy-sync/README.md +++ b/embassy-sync/README.md @@ -5,7 +5,7 @@ An [Embassy](https://embassy.dev) project. Synchronization primitives and data structures with async support: - [`Channel`](channel::Channel) - A Multiple Producer Multiple Consumer (MPMC) channel. Each message is only received by a single consumer. -- [`PriorityChannel`](channel::priority::PriorityChannel) - A Multiple Producer Multiple Consumer (MPMC) channel. Each message is only received by a single consumer. Higher priority items are shifted to the front of the channel. +- [`PriorityChannel`](channel::priority_channel::PriorityChannel) - A Multiple Producer Multiple Consumer (MPMC) channel. Each message is only received by a single consumer. Higher priority items are shifted to the front of the channel. - [`PubSubChannel`](pubsub::PubSubChannel) - A broadcast channel (publish-subscribe) channel. Each message is received by all consumers. - [`Signal`](signal::Signal) - Signalling latest value to a single consumer. - [`Mutex`](mutex::Mutex) - Mutex for synchronizing state between asynchronous tasks. From d8459685fd1e53a0fb57f44d950e0bc4f450c5f7 Mon Sep 17 00:00:00 2001 From: James Munns Date: Sun, 18 Aug 2024 10:58:07 +0200 Subject: [PATCH 0035/1217] Update faq.adoc - "code doesn't work in release mode" (#3267) Add debugging tips from chat --- docs/pages/faq.adoc | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/docs/pages/faq.adoc b/docs/pages/faq.adoc index 4ab04e2a1..8eb947b5e 100644 --- a/docs/pages/faq.adoc +++ b/docs/pages/faq.adoc @@ -361,4 +361,14 @@ Practically, there's not a LOT of difference either way - so go with what makes == splitting peripherals resources between tasks -There are two ways to split resources between tasks, either manually assigned or by a convenient macro. See link:https://github.com/embassy-rs/embassy/blob/main/examples/rp/src/bin/assign_resources.rs[this example] \ No newline at end of file +There are two ways to split resources between tasks, either manually assigned or by a convenient macro. See link:https://github.com/embassy-rs/embassy/blob/main/examples/rp/src/bin/assign_resources.rs[this example] + +== My code/driver works in debug mode, but not release mode (or with LTO) + +Issues like these while implementing drivers often fall into one of the following general causes, which are a good list of common errors to check for: + +1. Some kind of race condition - the faster code means you miss an interrupt or something +2. Some kind of UB, if you have unsafe code, or something like DMA with fences missing +3. Some kind of hardware errata, or some hardware misconfiguration like wrong clock speeds +4. Some issue with an interrupt handler, either enabling, disabling, or re-enabling of interrupts when necessary +5. Some kind of async issue, like not registering wakers fully before checking flags, or not registering or pending wakers at the right time From 1b0661ebb17fca93d11891a1c488005d3d644784 Mon Sep 17 00:00:00 2001 From: Sjoerd Simons Date: Sun, 18 Aug 2024 21:06:13 +0200 Subject: [PATCH 0036/1217] [UCPD] Add support for non-SOP packets Allow capturing (and distinguishing) non-SOP packets as well. The default configuration will just configure SOP packets. For ease of use the default receive function signature is unchanged as for PD sinks (which is likely the common usage) just SOP is enough so no need to differentiate. --- embassy-stm32/src/ucpd.rs | 77 ++++++++++++++++++++++++++-- examples/stm32g4/src/bin/usb_c_pd.rs | 2 +- tests/stm32/src/bin/ucpd.rs | 4 +- 3 files changed, 76 insertions(+), 7 deletions(-) diff --git a/embassy-stm32/src/ucpd.rs b/embassy-stm32/src/ucpd.rs index 40aea75cb..ee0a2c7c1 100644 --- a/embassy-stm32/src/ucpd.rs +++ b/embassy-stm32/src/ucpd.rs @@ -27,7 +27,7 @@ use crate::dma::{ChannelAndRequest, TransferOptions}; use crate::interrupt; use crate::interrupt::typelevel::Interrupt; use crate::pac::ucpd::vals::{Anamode, Ccenable, PscUsbpdclk, Txmode}; -pub use crate::pac::ucpd::vals::{Phyccsel as CcSel, TypecVstateCc as CcVState}; +pub use crate::pac::ucpd::vals::{Phyccsel as CcSel, Rxordset, TypecVstateCc as CcVState}; use crate::rcc::{self, RccPeripheral}; pub(crate) fn init( @@ -86,6 +86,34 @@ pub enum CcPull { Source3_0A, } +/// UCPD configuration +#[non_exhaustive] +#[derive(Copy, Clone, Debug)] +pub struct Config { + /// Receive SOP packets + pub sop: bool, + /// Receive SOP' packets + pub sop_prime: bool, + /// Receive SOP'' packets + pub sop_double_prime: bool, + /// Receive SOP'_Debug packets + pub sop_prime_debug: bool, + /// Receive SOP''_Debug packets + pub sop_double_prime_debug: bool, +} + +impl Default for Config { + fn default() -> Self { + Self { + sop: true, + sop_prime: false, + sop_double_prime: false, + sop_prime_debug: false, + sop_double_prime_debug: false, + } + } +} + /// UCPD driver. pub struct Ucpd<'d, T: Instance> { cc_phy: CcPhy<'d, T>, @@ -98,6 +126,7 @@ impl<'d, T: Instance> Ucpd<'d, T> { _irq: impl interrupt::typelevel::Binding> + 'd, cc1: impl Peripheral

> + 'd, cc2: impl Peripheral

> + 'd, + config: Config, ) -> Self { into_ref!(cc1, cc2); cc1.set_as_analog(); @@ -129,9 +158,15 @@ impl<'d, T: Instance> Ucpd<'d, T> { // 1.75us * 17 = ~30us w.set_ifrgap(17 - 1); - // TODO: Currently only hard reset and SOP messages can be received. // UNDOCUMENTED: This register can only be written while UCPDEN=0 (found by testing). - w.set_rxordseten(0b1001); + let rxordset = (config.sop as u16) << 0 + | (config.sop_prime as u16) << 1 + | (config.sop_double_prime as u16) << 2 + // Hard reset + | 0x1 << 3 + | (config.sop_prime_debug as u16) << 4 + | (config.sop_double_prime_debug as u16) << 5; + w.set_rxordseten(rxordset); // Enable DMA w.set_txdmaen(true); @@ -288,6 +323,22 @@ impl<'d, T: Instance> CcPhy<'d, T> { } } +/// Receive SOP. +#[derive(Debug, Clone, Copy)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum Sop { + /// SOP + Sop, + /// SOP' + SopPrime, + /// SOP'' + SopDoublePrime, + /// SOP'_Debug + SopPrimeDebug, + /// SOP''_Debug + SopDoublePrimeDebug, +} + /// Receive Error. #[derive(Debug, Clone, Copy)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -340,6 +391,13 @@ impl<'d, T: Instance> PdPhy<'d, T> { /// /// Returns the number of received bytes or an error. pub async fn receive(&mut self, buf: &mut [u8]) -> Result { + self.receive_with_sop(buf).await.map(|(_sop, size)| size) + } + + /// Receives SOP and a PD message into the provided buffer. + /// + /// Returns the start of packet type and number of received bytes or an error. + pub async fn receive_with_sop(&mut self, buf: &mut [u8]) -> Result<(Sop, usize), RxError> { let r = T::REGS; let dma = unsafe { @@ -388,7 +446,18 @@ impl<'d, T: Instance> PdPhy<'d, T> { } } - Ok(r.rx_payszr().read().rxpaysz().into()) + let sop = match r.rx_ordsetr().read().rxordset() { + Rxordset::SOP => Sop::Sop, + Rxordset::SOPPRIME => Sop::SopPrime, + Rxordset::SOPDOUBLEPRIME => Sop::SopDoublePrime, + Rxordset::SOPPRIMEDEBUG => Sop::SopPrimeDebug, + Rxordset::SOPDOUBLEPRIMEDEBUG => Sop::SopDoublePrimeDebug, + Rxordset::CABLERESET => return Err(RxError::HardReset), + // Extension headers are not supported + _ => unreachable!(), + }; + + Ok((sop, r.rx_payszr().read().rxpaysz().into())) } fn enable_rx_interrupt(enable: bool) { diff --git a/examples/stm32g4/src/bin/usb_c_pd.rs b/examples/stm32g4/src/bin/usb_c_pd.rs index 7caea634f..2e87d3931 100644 --- a/examples/stm32g4/src/bin/usb_c_pd.rs +++ b/examples/stm32g4/src/bin/usb_c_pd.rs @@ -55,7 +55,7 @@ async fn main(_spawner: Spawner) { info!("Hello World!"); - let mut ucpd = Ucpd::new(p.UCPD1, Irqs {}, p.PB6, p.PB4); + let mut ucpd = Ucpd::new(p.UCPD1, Irqs {}, p.PB6, p.PB4, Default::default()); ucpd.cc_phy().set_pull(CcPull::Sink); info!("Waiting for USB connection..."); diff --git a/tests/stm32/src/bin/ucpd.rs b/tests/stm32/src/bin/ucpd.rs index a6d13b34a..bd7b35d6b 100644 --- a/tests/stm32/src/bin/ucpd.rs +++ b/tests/stm32/src/bin/ucpd.rs @@ -106,8 +106,8 @@ async fn main(_spawner: Spawner) { info!("Hello World!"); // Wire between PD0 and PA8 - let ucpd1 = Ucpd::new(p.UCPD1, Irqs {}, p.PA8, p.PB15); - let ucpd2 = Ucpd::new(p.UCPD2, Irqs {}, p.PD0, p.PD2); + let ucpd1 = Ucpd::new(p.UCPD1, Irqs {}, p.PA8, p.PB15, Default::default()); + let ucpd2 = Ucpd::new(p.UCPD2, Irqs {}, p.PD0, p.PD2, Default::default()); join( source(ucpd1, p.DMA1_CH1, p.DMA1_CH2), From fcf9b3239e9c845d8f2b4eb5aea853f7ce377bf1 Mon Sep 17 00:00:00 2001 From: Karun Date: Mon, 19 Aug 2024 11:27:18 -0400 Subject: [PATCH 0037/1217] remove duplication --- embassy-stm32/src/usart/mod.rs | 77 +++++++--------------------------- 1 file changed, 16 insertions(+), 61 deletions(-) diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index 0c5bbf491..4f2ff8b2a 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -14,7 +14,7 @@ use embassy_sync::waitqueue::AtomicWaker; use futures_util::future::{select, Either}; use crate::dma::ChannelAndRequest; -use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed}; +use crate::gpio::{self, AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed}; use crate::interrupt::typelevel::Interrupt as _; use crate::interrupt::{self, Interrupt, InterruptExt}; use crate::mode::{Async, Blocking, Mode}; @@ -224,6 +224,17 @@ pub enum HalfDuplexConfig { OpenDrainInternal, } +impl HalfDuplexConfig { + pub fn af_type(self) -> gpio::AfType { + match self { + HalfDuplexConfig::PushPull => AfType::output(OutputType::PushPull, Speed::Medium), + HalfDuplexConfig::OpenDrainExternal => AfType::output(OutputType::OpenDrain, Speed::Medium), + #[cfg(not(gpio_v1))] + HalfDuplexConfig::OpenDrainInternal => AfType::output_pull(OutputType::OpenDrain, Speed::Medium, Pull::Up), + } + } +} + /// Serial error #[derive(Debug, Eq, PartialEq, Copy, Clone)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -1066,21 +1077,7 @@ impl<'d> Uart<'d, Async> { Self::new_inner( peri, None, - new_pin!( - tx, - match half_duplex { - HalfDuplexConfig::PushPull => { - AfType::output(OutputType::PushPull, Speed::Medium) - } - HalfDuplexConfig::OpenDrainExternal => { - AfType::output(OutputType::OpenDrain, Speed::Medium) - } - #[cfg(not(gpio_v1))] - HalfDuplexConfig::OpenDrainInternal => { - AfType::output_pull(OutputType::OpenDrain, Speed::Medium, Pull::Up) - } - } - ), + new_pin!(tx, half_duplex.af_type()), None, None, None, @@ -1117,21 +1114,7 @@ impl<'d> Uart<'d, Async> { peri, None, None, - new_pin!( - rx, - match half_duplex { - HalfDuplexConfig::PushPull => { - AfType::output(OutputType::PushPull, Speed::Medium) - } - HalfDuplexConfig::OpenDrainExternal => { - AfType::output(OutputType::OpenDrain, Speed::Medium) - } - #[cfg(not(gpio_v1))] - HalfDuplexConfig::OpenDrainInternal => { - AfType::output_pull(OutputType::OpenDrain, Speed::Medium, Pull::Up) - } - } - ), + new_pin!(rx, half_duplex.af_type()), None, None, new_dma!(tx_dma), @@ -1247,21 +1230,7 @@ impl<'d> Uart<'d, Blocking> { Self::new_inner( peri, None, - new_pin!( - tx, - match half_duplex { - HalfDuplexConfig::PushPull => { - AfType::output(OutputType::PushPull, Speed::Medium) - } - HalfDuplexConfig::OpenDrainExternal => { - AfType::output(OutputType::OpenDrain, Speed::Medium) - } - #[cfg(not(gpio_v1))] - HalfDuplexConfig::OpenDrainInternal => { - AfType::output_pull(OutputType::OpenDrain, Speed::Medium, Pull::Up) - } - } - ), + new_pin!(tx, half_duplex.af_type()), None, None, None, @@ -1295,21 +1264,7 @@ impl<'d> Uart<'d, Blocking> { peri, None, None, - new_pin!( - rx, - match half_duplex { - HalfDuplexConfig::PushPull => { - AfType::output(OutputType::PushPull, Speed::Medium) - } - HalfDuplexConfig::OpenDrainExternal => { - AfType::output(OutputType::OpenDrain, Speed::Medium) - } - #[cfg(not(gpio_v1))] - HalfDuplexConfig::OpenDrainInternal => { - AfType::output_pull(OutputType::OpenDrain, Speed::Medium, Pull::Up) - } - } - ), + new_pin!(rx, half_duplex.af_type()), None, None, None, From bbc06035c136887aad91a1944efcc4c98401866f Mon Sep 17 00:00:00 2001 From: Karun Date: Mon, 19 Aug 2024 12:15:39 -0400 Subject: [PATCH 0038/1217] make half duplex fn private --- embassy-stm32/src/usart/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index 4f2ff8b2a..89d92dda2 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -225,7 +225,7 @@ pub enum HalfDuplexConfig { } impl HalfDuplexConfig { - pub fn af_type(self) -> gpio::AfType { + fn af_type(self) -> gpio::AfType { match self { HalfDuplexConfig::PushPull => AfType::output(OutputType::PushPull, Speed::Medium), HalfDuplexConfig::OpenDrainExternal => AfType::output(OutputType::OpenDrain, Speed::Medium), From aff66b9695a70222b20c19585f04df2ecbabccb1 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Fri, 21 Jun 2024 20:17:39 +0200 Subject: [PATCH 0039/1217] nrf: add try_write to BufferedUarte. --- embassy-nrf/src/buffered_uarte.rs | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/embassy-nrf/src/buffered_uarte.rs b/embassy-nrf/src/buffered_uarte.rs index 159b4db8f..6d39597c6 100644 --- a/embassy-nrf/src/buffered_uarte.rs +++ b/embassy-nrf/src/buffered_uarte.rs @@ -358,6 +358,11 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> { self.tx.write(buf).await } + /// Try writing a buffer without waiting, returning how many bytes were written. + pub fn try_write(&mut self, buf: &[u8]) -> Result { + self.tx.try_write(buf) + } + /// Flush this output stream, ensuring that all intermediately buffered contents reach their destination. pub async fn flush(&mut self) -> Result<(), Error> { self.tx.flush().await @@ -482,6 +487,29 @@ impl<'d, U: UarteInstance> BufferedUarteTx<'d, U> { .await } + /// Try writing a buffer without waiting, returning how many bytes were written. + pub fn try_write(&mut self, buf: &[u8]) -> Result { + //trace!("poll_write: {:?}", buf.len()); + let s = U::buffered_state(); + let mut tx = unsafe { s.tx_buf.writer() }; + + let tx_buf = tx.push_slice(); + if tx_buf.is_empty() { + return Ok(0); + } + + let n = min(tx_buf.len(), buf.len()); + tx_buf[..n].copy_from_slice(&buf[..n]); + tx.push_done(n); + + //trace!("poll_write: queued {:?}", n); + + compiler_fence(Ordering::SeqCst); + U::Interrupt::pend(); + + Ok(n) + } + /// Flush this output stream, ensuring that all intermediately buffered contents reach their destination. pub async fn flush(&mut self) -> Result<(), Error> { poll_fn(move |cx| { From 160e1c38ceab0ae8876c2bf5f12438edd4d9b018 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Fri, 21 Jun 2024 20:19:54 +0200 Subject: [PATCH 0040/1217] Add embassy-net-nrf91. --- embassy-net-nrf91/Cargo.toml | 37 + embassy-net-nrf91/README.md | 9 + embassy-net-nrf91/src/fmt.rs | 274 ++++++ embassy-net-nrf91/src/lib.rs | 970 +++++++++++++++++++ examples/nrf9160/.cargo/config.toml | 3 +- examples/nrf9160/Cargo.toml | 5 + examples/nrf9160/memory.x | 8 +- examples/nrf9160/src/bin/modem_tcp_client.rs | 250 +++++ 8 files changed, 1553 insertions(+), 3 deletions(-) create mode 100644 embassy-net-nrf91/Cargo.toml create mode 100644 embassy-net-nrf91/README.md create mode 100644 embassy-net-nrf91/src/fmt.rs create mode 100644 embassy-net-nrf91/src/lib.rs create mode 100644 examples/nrf9160/src/bin/modem_tcp_client.rs diff --git a/embassy-net-nrf91/Cargo.toml b/embassy-net-nrf91/Cargo.toml new file mode 100644 index 000000000..2156346a4 --- /dev/null +++ b/embassy-net-nrf91/Cargo.toml @@ -0,0 +1,37 @@ +[package] +name = "embassy-net-nrf91" +version = "0.1.0" +edition = "2021" +description = "embassy-net driver for Nordic nRF91-series cellular modems" +keywords = ["embedded", "nrf91", "embassy-net", "cellular"] +categories = ["embedded", "hardware-support", "no-std", "network-programming", "asynchronous"] +license = "MIT OR Apache-2.0" +repository = "https://github.com/embassy-rs/embassy" +documentation = "https://docs.embassy.dev/embassy-net-nrf91" + +[features] +defmt = [ "dep:defmt", "heapless/defmt-03" ] +log = [ "dep:log" ] + +[dependencies] +defmt = { version = "0.3", optional = true } +log = { version = "0.4.14", optional = true } + +nrf9160-pac = { version = "0.12.0" } + +embassy-time = { version = "0.3.1", path = "../embassy-time" } +embassy-sync = { version = "0.6.0", path = "../embassy-sync"} +embassy-futures = { version = "0.1.0", path = "../embassy-futures"} +embassy-net-driver-channel = { version = "0.2.0", path = "../embassy-net-driver-channel"} + +heapless = "0.8" +embedded-io = "0.6.1" + +[package.metadata.embassy_docs] +src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-nrf91-v$VERSION/embassy-net-nrf91/src/" +src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-net-nrf91/src/" +target = "thumbv7em-none-eabi" +features = ["defmt"] + +[package.metadata.docs.rs] +features = ["defmt"] diff --git a/embassy-net-nrf91/README.md b/embassy-net-nrf91/README.md new file mode 100644 index 000000000..30da71787 --- /dev/null +++ b/embassy-net-nrf91/README.md @@ -0,0 +1,9 @@ +# nRF91 `embassy-net` integration + +[`embassy-net`](https://crates.io/crates/embassy-net) driver for Nordic nRF91-series cellular modems. + +See the [`examples`](https://github.com/embassy-rs/embassy/tree/main/examples/nrf9160) directory for usage examples with the nRF9160. + +## Interoperability + +This crate can run on any executor. diff --git a/embassy-net-nrf91/src/fmt.rs b/embassy-net-nrf91/src/fmt.rs new file mode 100644 index 000000000..35b929fde --- /dev/null +++ b/embassy-net-nrf91/src/fmt.rs @@ -0,0 +1,274 @@ +#![macro_use] +#![allow(unused)] + +use core::fmt::{Debug, Display, LowerHex}; + +#[cfg(all(feature = "defmt", feature = "log"))] +compile_error!("You may not enable both `defmt` and `log` features."); + +#[collapse_debuginfo(yes)] +macro_rules! assert { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::assert!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::assert!($($x)*); + } + }; +} + +#[collapse_debuginfo(yes)] +macro_rules! assert_eq { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::assert_eq!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::assert_eq!($($x)*); + } + }; +} + +#[collapse_debuginfo(yes)] +macro_rules! assert_ne { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::assert_ne!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::assert_ne!($($x)*); + } + }; +} + +#[collapse_debuginfo(yes)] +macro_rules! debug_assert { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::debug_assert!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::debug_assert!($($x)*); + } + }; +} + +#[collapse_debuginfo(yes)] +macro_rules! debug_assert_eq { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::debug_assert_eq!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::debug_assert_eq!($($x)*); + } + }; +} + +#[collapse_debuginfo(yes)] +macro_rules! debug_assert_ne { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::debug_assert_ne!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::debug_assert_ne!($($x)*); + } + }; +} + +#[collapse_debuginfo(yes)] +macro_rules! todo { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::todo!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::todo!($($x)*); + } + }; +} + +#[cfg(not(feature = "defmt"))] +#[collapse_debuginfo(yes)] +macro_rules! unreachable { + ($($x:tt)*) => { + ::core::unreachable!($($x)*) + }; +} + +#[cfg(feature = "defmt")] +#[collapse_debuginfo(yes)] +macro_rules! unreachable { + ($($x:tt)*) => { + ::defmt::unreachable!($($x)*) + }; +} + +#[collapse_debuginfo(yes)] +macro_rules! panic { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::panic!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::panic!($($x)*); + } + }; +} + +#[collapse_debuginfo(yes)] +macro_rules! trace { + ($s:literal $(, $x:expr)* $(,)?) => { + { + #[cfg(feature = "log")] + ::log::trace!($s $(, $x)*); + #[cfg(feature = "defmt")] + ::defmt::trace!($s $(, $x)*); + #[cfg(not(any(feature = "log", feature="defmt")))] + let _ = ($( & $x ),*); + } + }; +} + +#[collapse_debuginfo(yes)] +macro_rules! debug { + ($s:literal $(, $x:expr)* $(,)?) => { + { + #[cfg(feature = "log")] + ::log::debug!($s $(, $x)*); + #[cfg(feature = "defmt")] + ::defmt::debug!($s $(, $x)*); + #[cfg(not(any(feature = "log", feature="defmt")))] + let _ = ($( & $x ),*); + } + }; +} + +#[collapse_debuginfo(yes)] +macro_rules! info { + ($s:literal $(, $x:expr)* $(,)?) => { + { + #[cfg(feature = "log")] + ::log::info!($s $(, $x)*); + #[cfg(feature = "defmt")] + ::defmt::info!($s $(, $x)*); + #[cfg(not(any(feature = "log", feature="defmt")))] + let _ = ($( & $x ),*); + } + }; +} + +#[collapse_debuginfo(yes)] +macro_rules! warn { + ($s:literal $(, $x:expr)* $(,)?) => { + { + #[cfg(feature = "log")] + ::log::warn!($s $(, $x)*); + #[cfg(feature = "defmt")] + ::defmt::warn!($s $(, $x)*); + #[cfg(not(any(feature = "log", feature="defmt")))] + let _ = ($( & $x ),*); + } + }; +} + +#[collapse_debuginfo(yes)] +macro_rules! error { + ($s:literal $(, $x:expr)* $(,)?) => { + { + #[cfg(feature = "log")] + ::log::error!($s $(, $x)*); + #[cfg(feature = "defmt")] + ::defmt::error!($s $(, $x)*); + #[cfg(not(any(feature = "log", feature="defmt")))] + let _ = ($( & $x ),*); + } + }; +} + +#[cfg(feature = "defmt")] +#[collapse_debuginfo(yes)] +macro_rules! unwrap { + ($($x:tt)*) => { + ::defmt::unwrap!($($x)*) + }; +} + +#[cfg(not(feature = "defmt"))] +#[collapse_debuginfo(yes)] +macro_rules! unwrap { + ($arg:expr) => { + match $crate::fmt::Try::into_result($arg) { + ::core::result::Result::Ok(t) => t, + ::core::result::Result::Err(e) => { + ::core::panic!("unwrap of `{}` failed: {:?}", ::core::stringify!($arg), e); + } + } + }; + ($arg:expr, $($msg:expr),+ $(,)? ) => { + match $crate::fmt::Try::into_result($arg) { + ::core::result::Result::Ok(t) => t, + ::core::result::Result::Err(e) => { + ::core::panic!("unwrap of `{}` failed: {}: {:?}", ::core::stringify!($arg), ::core::format_args!($($msg,)*), e); + } + } + } +} + +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub struct NoneError; + +pub trait Try { + type Ok; + type Error; + fn into_result(self) -> Result; +} + +impl Try for Option { + type Ok = T; + type Error = NoneError; + + #[inline] + fn into_result(self) -> Result { + self.ok_or(NoneError) + } +} + +impl Try for Result { + type Ok = T; + type Error = E; + + #[inline] + fn into_result(self) -> Self { + self + } +} + +pub(crate) struct Bytes<'a>(pub &'a [u8]); + +impl<'a> Debug for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +impl<'a> Display for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +impl<'a> LowerHex for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +#[cfg(feature = "defmt")] +impl<'a> defmt::Format for Bytes<'a> { + fn format(&self, fmt: defmt::Formatter) { + defmt::write!(fmt, "{:02x}", self.0) + } +} diff --git a/embassy-net-nrf91/src/lib.rs b/embassy-net-nrf91/src/lib.rs new file mode 100644 index 000000000..62ade6dd3 --- /dev/null +++ b/embassy-net-nrf91/src/lib.rs @@ -0,0 +1,970 @@ +#![no_std] +#![doc = include_str!("../README.md")] +#![warn(missing_docs)] + +// must be first +mod fmt; + +use core::cell::RefCell; +use core::future::poll_fn; +use core::marker::PhantomData; +use core::mem::{self, MaybeUninit}; +use core::ptr::{self, addr_of, addr_of_mut, copy_nonoverlapping}; +use core::slice; +use core::sync::atomic::{compiler_fence, fence, Ordering}; +use core::task::{Poll, Waker}; + +use embassy_net_driver_channel as ch; +use embassy_sync::waitqueue::{AtomicWaker, WakerRegistration}; +use heapless::Vec; +use nrf9160_pac as pac; +use pac::NVIC; + +const RX_SIZE: usize = 8 * 1024; +const TRACE_SIZE: usize = 16 * 1024; +const MTU: usize = 1500; + +/// Network driver. +/// +/// This is the type you have to pass to `embassy-net` when creating the network stack. +pub type NetDriver<'a> = ch::Device<'a, MTU>; + +static WAKER: AtomicWaker = AtomicWaker::new(); + +/// Call this function on IPC IRQ +pub fn on_ipc_irq() { + let ipc = unsafe { &*pac::IPC_NS::ptr() }; + + trace!("irq"); + + ipc.inten.write(|w| w); + WAKER.wake(); +} + +struct Allocator<'a> { + start: *mut u8, + end: *mut u8, + _phantom: PhantomData<&'a mut u8>, +} + +impl<'a> Allocator<'a> { + fn alloc_bytes(&mut self, size: usize) -> &'a mut [MaybeUninit] { + // safety: both pointers come from the same allocation. + let available_size = unsafe { self.end.offset_from(self.start) } as usize; + if size > available_size { + panic!("out of memory") + } + + // safety: we've checked above this doesn't go out of bounds. + let p = self.start; + self.start = unsafe { p.add(size) }; + + // safety: we've checked the pointer is in-bounds. + unsafe { slice::from_raw_parts_mut(p as *mut _, size) } + } + + fn alloc(&mut self) -> &'a mut MaybeUninit { + let align = mem::align_of::(); + let size = mem::size_of::(); + + let align_size = match (self.start as usize) % align { + 0 => 0, + n => align - n, + }; + + // safety: both pointers come from the same allocation. + let available_size = unsafe { self.end.offset_from(self.start) } as usize; + if align_size + size > available_size { + panic!("out of memory") + } + + // safety: we've checked above this doesn't go out of bounds. + let p = unsafe { self.start.add(align_size) }; + self.start = unsafe { p.add(size) }; + + // safety: we've checked the pointer is aligned and in-bounds. + unsafe { &mut *(p as *mut _) } + } +} + +/// Create a new nRF91 embassy-net driver. +pub async fn new<'a, TW: embedded_io::Write>( + state: &'a mut State, + shmem: &'a mut [MaybeUninit], + trace_writer: TW, +) -> (NetDriver<'a>, Control<'a>, Runner<'a, TW>) { + let shmem_len = shmem.len(); + let shmem_ptr = shmem.as_mut_ptr() as *mut u8; + + const SPU_REGION_SIZE: usize = 8192; // 8kb + assert!(shmem_len != 0); + assert!( + shmem_len % SPU_REGION_SIZE == 0, + "shmem length must be a multiple of 8kb" + ); + assert!( + (shmem_ptr as usize) % SPU_REGION_SIZE == 0, + "shmem length must be a multiple of 8kb" + ); + assert!( + (shmem_ptr as usize + shmem_len) < 0x2002_0000, + "shmem must be in the lower 128kb of RAM" + ); + + let spu = unsafe { &*pac::SPU_S::ptr() }; + debug!("Setting IPC RAM as nonsecure..."); + let region_start = (shmem_ptr as usize - 0x2000_0000) / SPU_REGION_SIZE; + let region_end = region_start + shmem_len / SPU_REGION_SIZE; + for i in region_start..region_end { + spu.ramregion[i].perm.write(|w| { + w.execute().set_bit(); + w.write().set_bit(); + w.read().set_bit(); + w.secattr().clear_bit(); + w.lock().clear_bit(); + w + }) + } + + spu.periphid[42].perm.write(|w| w.secattr().non_secure()); + + let mut alloc = Allocator { + start: shmem_ptr, + end: unsafe { shmem_ptr.add(shmem_len) }, + _phantom: PhantomData, + }; + + let ipc = unsafe { &*pac::IPC_NS::ptr() }; + let power = unsafe { &*pac::POWER_S::ptr() }; + + let cb: &mut ControlBlock = alloc.alloc().write(unsafe { mem::zeroed() }); + let rx = alloc.alloc_bytes(RX_SIZE); + let trace = alloc.alloc_bytes(TRACE_SIZE); + + cb.version = 0x00010000; + cb.rx_base = rx.as_mut_ptr() as _; + cb.rx_size = RX_SIZE; + cb.control_list_ptr = &mut cb.lists[0]; + cb.data_list_ptr = &mut cb.lists[1]; + cb.modem_info_ptr = &mut cb.modem_info; + cb.trace_ptr = &mut cb.trace; + cb.lists[0].len = LIST_LEN; + cb.lists[1].len = LIST_LEN; + cb.trace.base = trace.as_mut_ptr() as _; + cb.trace.size = TRACE_SIZE; + + ipc.gpmem[0].write(|w| unsafe { w.bits(cb as *mut _ as u32) }); + ipc.gpmem[1].write(|w| unsafe { w.bits(0) }); + + // connect task/event i to channel i + for i in 0..8 { + ipc.send_cnf[i].write(|w| unsafe { w.bits(1 << i) }); + ipc.receive_cnf[i].write(|w| unsafe { w.bits(1 << i) }); + } + + compiler_fence(Ordering::SeqCst); + + // POWER.LTEMODEM.STARTN = 0 + // The reg is missing in the PAC?? + let startn = unsafe { (power as *const _ as *mut u32).add(0x610 / 4) }; + unsafe { startn.write_volatile(0) } + + unsafe { NVIC::unmask(pac::Interrupt::IPC) }; + + let state_inner = &*state.inner.write(RefCell::new(StateInner { + init: false, + init_waker: WakerRegistration::new(), + cb, + requests: [const { None }; REQ_COUNT], + next_req_serial: 0x12345678, + + rx_control_list: ptr::null_mut(), + rx_data_list: ptr::null_mut(), + rx_seq_no: 0, + rx_check: PointerChecker { + start: rx.as_mut_ptr() as *mut u8, + end: (rx.as_mut_ptr() as *mut u8).wrapping_add(RX_SIZE), + }, + + tx_seq_no: 0, + tx_buf_used: [false; TX_BUF_COUNT], + + trace_chans: Vec::new(), + trace_check: PointerChecker { + start: trace.as_mut_ptr() as *mut u8, + end: (trace.as_mut_ptr() as *mut u8).wrapping_add(TRACE_SIZE), + }, + })); + + let control = Control { state: state_inner }; + + let (ch_runner, device) = ch::new(&mut state.ch, ch::driver::HardwareAddress::Ip); + let state_ch = ch_runner.state_runner(); + state_ch.set_link_state(ch::driver::LinkState::Up); + + let runner = Runner { + ch: ch_runner, + state: state_inner, + trace_writer, + }; + + (device, control, runner) +} + +/// Shared state for the drivver. +pub struct State { + ch: ch::State, + inner: MaybeUninit>, +} + +impl State { + /// Create a new State. + pub const fn new() -> Self { + Self { + ch: ch::State::new(), + inner: MaybeUninit::uninit(), + } + } +} + +const TX_BUF_COUNT: usize = 4; +const TX_BUF_SIZE: usize = 1024; + +struct TraceChannelInfo { + ptr: *mut TraceChannel, + start: *mut u8, + end: *mut u8, +} + +const REQ_COUNT: usize = 4; + +struct PendingRequest { + req_serial: u32, + resp_msg: *mut Message, + waker: Waker, +} + +struct StateInner { + init: bool, + init_waker: WakerRegistration, + + cb: *mut ControlBlock, + requests: [Option; REQ_COUNT], + next_req_serial: u32, + + rx_control_list: *mut List, + rx_data_list: *mut List, + rx_seq_no: u16, + rx_check: PointerChecker, + + tx_seq_no: u16, + tx_buf_used: [bool; TX_BUF_COUNT], + + trace_chans: Vec, + trace_check: PointerChecker, +} + +impl StateInner { + fn poll(&mut self, trace_writer: &mut impl embedded_io::Write, ch: &mut ch::Runner) { + trace!("poll!"); + let ipc = unsafe { &*pac::IPC_NS::ptr() }; + + if ipc.events_receive[0].read().bits() != 0 { + ipc.events_receive[0].reset(); + trace!("ipc 0"); + } + + if ipc.events_receive[2].read().bits() != 0 { + ipc.events_receive[2].reset(); + trace!("ipc 2"); + + if !self.init { + let desc = unsafe { addr_of!((*self.cb).modem_info).read_volatile() }; + assert_eq!(desc.version, 1); + + self.rx_check.check_mut(desc.control_list_ptr); + self.rx_check.check_mut(desc.data_list_ptr); + + self.rx_control_list = desc.control_list_ptr; + self.rx_data_list = desc.data_list_ptr; + let rx_control_len = unsafe { addr_of!((*self.rx_control_list).len).read_volatile() }; + let rx_data_len = unsafe { addr_of!((*self.rx_data_list).len).read_volatile() }; + assert_eq!(rx_control_len, LIST_LEN); + assert_eq!(rx_data_len, LIST_LEN); + self.init = true; + + debug!("IPC initialized OK!"); + self.init_waker.wake(); + } + } + + if ipc.events_receive[4].read().bits() != 0 { + ipc.events_receive[4].reset(); + trace!("ipc 4"); + + loop { + let list = unsafe { &mut *self.rx_control_list }; + let control_work = self.process(list, true, ch); + let list = unsafe { &mut *self.rx_data_list }; + let data_work = self.process(list, false, ch); + if !control_work && !data_work { + break; + } + } + } + + if ipc.events_receive[6].read().bits() != 0 { + ipc.events_receive[6].reset(); + trace!("ipc 6"); + } + + if ipc.events_receive[7].read().bits() != 0 { + ipc.events_receive[7].reset(); + trace!("ipc 7: trace"); + + let msg = unsafe { addr_of!((*self.cb).trace.rx_state).read_volatile() }; + if msg != 0 { + trace!("trace msg {}", msg); + match msg { + 0 => unreachable!(), + 1 => { + let ctx = unsafe { addr_of!((*self.cb).trace.rx_ptr).read_volatile() } as *mut TraceContext; + debug!("trace init: {:?}", ctx); + self.trace_check.check(ctx); + let chans = unsafe { addr_of!((*ctx).chans).read_volatile() }; + for chan_ptr in chans { + let chan = self.trace_check.check_read(chan_ptr); + self.trace_check.check(chan.start); + self.trace_check.check(chan.end); + assert!(chan.start < chan.end); + self.trace_chans + .push(TraceChannelInfo { + ptr: chan_ptr, + start: chan.start, + end: chan.end, + }) + .map_err(|_| ()) + .unwrap() + } + } + 2 => { + for chan_info in &self.trace_chans { + let read_ptr = unsafe { addr_of!((*chan_info.ptr).read_ptr).read_volatile() }; + let write_ptr = unsafe { addr_of!((*chan_info.ptr).write_ptr).read_volatile() }; + assert!(read_ptr >= chan_info.start && read_ptr <= chan_info.end); + assert!(write_ptr >= chan_info.start && write_ptr <= chan_info.end); + if read_ptr != write_ptr { + let id = unsafe { addr_of!((*chan_info.ptr).id).read_volatile() }; + fence(Ordering::SeqCst); // synchronize volatile accesses with the slice access. + if read_ptr < write_ptr { + Self::handle_trace(trace_writer, id, unsafe { + slice::from_raw_parts(read_ptr, write_ptr.offset_from(read_ptr) as _) + }); + } else { + Self::handle_trace(trace_writer, id, unsafe { + slice::from_raw_parts(read_ptr, chan_info.end.offset_from(read_ptr) as _) + }); + Self::handle_trace(trace_writer, id, unsafe { + slice::from_raw_parts( + chan_info.start, + write_ptr.offset_from(chan_info.start) as _, + ) + }); + } + fence(Ordering::SeqCst); // synchronize volatile accesses with the slice access. + unsafe { addr_of_mut!((*chan_info.ptr).read_ptr).write_volatile(write_ptr) }; + } + } + } + _ => warn!("unknown trace msg {}", msg), + } + unsafe { addr_of_mut!((*self.cb).trace.rx_state).write_volatile(0) }; + } + } + + ipc.intenset.write(|w| { + w.receive0().set_bit(); + w.receive2().set_bit(); + w.receive4().set_bit(); + w.receive6().set_bit(); + w.receive7().set_bit(); + w + }); + } + + fn handle_trace(writer: &mut impl embedded_io::Write, id: u8, data: &[u8]) { + trace!("trace: {} {}", id, data.len()); + let mut header = [0u8; 5]; + header[0] = 0xEF; + header[1] = 0xBE; + header[2..4].copy_from_slice(&(data.len() as u16).to_le_bytes()); + header[4] = id; + writer.write_all(&header).unwrap(); + writer.write_all(data).unwrap(); + } + + fn process(&mut self, list: *mut List, is_control: bool, ch: &mut ch::Runner) -> bool { + let mut did_work = false; + for i in 0..LIST_LEN { + let item_ptr = unsafe { addr_of_mut!((*list).items[i]) }; + let preamble = unsafe { addr_of!((*item_ptr).state).read_volatile() }; + if preamble & 0xFF == 0x01 && preamble >> 16 == self.rx_seq_no as u32 { + let msg_ptr = unsafe { addr_of!((*item_ptr).message).read_volatile() }; + let msg = self.rx_check.check_read(msg_ptr); + + debug!("rx seq {} msg: {:?}", preamble >> 16, msg); + + if is_control { + self.handle_control(&msg); + } else { + self.handle_data(&msg, ch); + } + + unsafe { addr_of_mut!((*item_ptr).state).write_volatile(0x03) }; + self.rx_seq_no = self.rx_seq_no.wrapping_add(1); + + did_work = true; + } + } + did_work + } + + fn find_free_message(&mut self, ch: usize) -> Option { + for i in 0..LIST_LEN { + let preamble = unsafe { addr_of!((*self.cb).lists[ch].items[i].state).read_volatile() }; + if matches!(preamble & 0xFF, 0 | 3) { + trace!("using tx msg idx {}", i); + return Some(i); + } + } + return None; + } + + fn find_free_tx_buf(&mut self) -> Option { + for i in 0..TX_BUF_COUNT { + if !self.tx_buf_used[i] { + trace!("using tx buf idx {}", i); + return Some(i); + } + } + return None; + } + + fn send_message(&mut self, msg: &mut Message, data: &[u8]) { + if data.is_empty() { + msg.data = ptr::null_mut(); + msg.data_len = 0; + } else { + assert!(data.len() <= TX_BUF_SIZE); + let buf_idx = self.find_free_tx_buf().unwrap(); // TODO handle out of bufs + let buf = unsafe { addr_of_mut!((*self.cb).tx_bufs[buf_idx]) } as *mut u8; + unsafe { copy_nonoverlapping(data.as_ptr(), buf, data.len()) } + msg.data = buf; + msg.data_len = data.len(); + self.tx_buf_used[buf_idx] = true; + + fence(Ordering::SeqCst); // synchronize copy_nonoverlapping (non-volatile) with volatile writes below. + } + + // TODO free data buf if send_message_raw fails. + self.send_message_raw(msg); + } + + fn send_message_raw(&mut self, msg: &Message) { + let (ch, ipc_ch) = match msg.channel { + 1 => (0, 1), // control + 2 => (1, 3), // data + _ => unreachable!(), + }; + + // allocate a msg. + let idx = self.find_free_message(ch).unwrap(); // TODO handle list full + + debug!("tx seq {} msg: {:?}", self.tx_seq_no, msg); + + let msg_slot = unsafe { addr_of_mut!((*self.cb).msgs[ch][idx]) }; + unsafe { msg_slot.write_volatile(*msg) } + let list_item = unsafe { addr_of_mut!((*self.cb).lists[ch].items[idx]) }; + unsafe { addr_of_mut!((*list_item).message).write_volatile(msg_slot) } + unsafe { addr_of_mut!((*list_item).state).write_volatile((self.tx_seq_no as u32) << 16 | 0x01) } + self.tx_seq_no = self.tx_seq_no.wrapping_add(1); + + let ipc = unsafe { &*pac::IPC_NS::ptr() }; + ipc.tasks_send[ipc_ch].write(|w| unsafe { w.bits(1) }); + } + + fn handle_control(&mut self, msg: &Message) { + match msg.id >> 16 { + 1 => debug!("control msg: modem ready"), + 2 => self.handle_control_free(msg.data), + _ => warn!("unknown control message id {:08x}", msg.id), + } + } + + fn handle_control_free(&mut self, ptr: *mut u8) { + let base = unsafe { addr_of!((*self.cb).tx_bufs) } as usize; + let ptr = ptr as usize; + + if ptr < base { + warn!("control free bad pointer {:08x}", ptr); + return; + } + + let diff = ptr - base; + let idx = diff / TX_BUF_SIZE; + + if idx >= TX_BUF_COUNT || idx * TX_BUF_SIZE != diff { + warn!("control free bad pointer {:08x}", ptr); + return; + } + + trace!("control free pointer {:08x} idx {}", ptr, idx); + if !self.tx_buf_used[idx] { + warn!( + "control free pointer {:08x} idx {}: buffer was already free??", + ptr, idx + ); + } + self.tx_buf_used[idx] = false; + } + + fn handle_data(&mut self, msg: &Message, ch: &mut ch::Runner) { + if !msg.data.is_null() { + self.rx_check.check_length(msg.data, msg.data_len); + } + + let freed = match msg.id & 0xFFFF { + // AT + 3 => { + match msg.id >> 16 { + // AT request ack + 2 => false, + // AT response + 3 => self.handle_resp(msg), + // AT notification + 4 => false, + x => { + warn!("received unknown AT kind {}", x); + false + } + } + } + // IP + 4 => { + match msg.id >> 28 { + // IP response + 8 => self.handle_resp(msg), + // IP notification + 9 => match (msg.id >> 16) & 0xFFF { + // IP receive notification + 1 => { + if let Some(buf) = ch.try_rx_buf() { + let mut len = msg.data_len; + if len > buf.len() { + warn!("truncating rx'd packet from {} to {} bytes", len, buf.len()); + len = buf.len(); + } + fence(Ordering::SeqCst); // synchronize volatile accesses with the nonvolatile copy_nonoverlapping. + unsafe { ptr::copy_nonoverlapping(msg.data, buf.as_mut_ptr(), len) } + fence(Ordering::SeqCst); // synchronize volatile accesses with the nonvolatile copy_nonoverlapping. + ch.rx_done(len); + } + false + } + _ => false, + }, + x => { + warn!("received unknown IP kind {}", x); + false + } + } + } + x => { + warn!("received unknown kind {}", x); + false + } + }; + + if !freed { + self.send_free(msg); + } + } + + fn handle_resp(&mut self, msg: &Message) -> bool { + let req_serial = u32::from_le_bytes(msg.param[0..4].try_into().unwrap()); + if req_serial == 0 { + return false; + } + + for optr in &mut self.requests { + if let Some(r) = optr { + if r.req_serial == req_serial { + let r = optr.take().unwrap(); + unsafe { r.resp_msg.write(*msg) } + r.waker.wake(); + *optr = None; + return true; + } + } + } + + warn!( + "resp with id {} serial {} doesn't match any pending req", + msg.id, req_serial + ); + false + } + + fn send_free(&mut self, msg: &Message) { + if msg.data.is_null() { + return; + } + + let mut free_msg: Message = unsafe { mem::zeroed() }; + free_msg.channel = 1; // control + free_msg.id = 0x20001; // free + free_msg.data = msg.data; + free_msg.data_len = msg.data_len; + + self.send_message_raw(&free_msg); + } +} + +struct PointerChecker { + start: *mut u8, + end: *mut u8, +} + +impl PointerChecker { + // check the pointer is in bounds in the arena, panic otherwise. + fn check_length(&self, ptr: *const u8, len: usize) { + assert!(ptr as usize >= self.start as usize); + let end_ptr = (ptr as usize).checked_add(len).unwrap(); + assert!(end_ptr <= self.end as usize); + } + + // check the pointer is in bounds in the arena, panic otherwise. + fn check(&self, ptr: *const T) { + assert!(ptr.is_aligned()); + self.check_length(ptr as *const u8, mem::size_of::()); + } + + // check the pointer is in bounds in the arena, panic otherwise. + fn check_read(&self, ptr: *const T) -> T { + self.check(ptr); + unsafe { ptr.read_volatile() } + } + + // check the pointer is in bounds in the arena, panic otherwise. + fn check_mut(&self, ptr: *mut T) { + self.check(ptr as *const T) + } +} + +/// Control handle for the driver. +/// +/// You can use this object to control the modem at runtime, such as running AT commands. +pub struct Control<'a> { + state: &'a RefCell, +} + +impl<'a> Control<'a> { + /// Wait for modem IPC to be initialized. + pub async fn wait_init(&self) { + poll_fn(|cx| { + let mut state = self.state.borrow_mut(); + if state.init { + return Poll::Ready(()); + } + state.init_waker.register(cx.waker()); + Poll::Pending + }) + .await + } + + async fn request(&self, msg: &mut Message, req_data: &[u8], resp_data: &mut [u8]) -> usize { + // get waker + let waker = poll_fn(|cx| Poll::Ready(cx.waker().clone())).await; + + // Send request + let mut state = self.state.borrow_mut(); + let mut req_serial = state.next_req_serial; + if msg.id & 0xFFFF == 3 { + // AT response seems to keep only the lower 8 bits. Others do keep the full 32 bits..?? + req_serial &= 0xFF; + } + + // increment next_req_serial, skip zero because we use it as an "ignore" value. + // We have to skip when the *lowest byte* is zero because AT responses. + state.next_req_serial = state.next_req_serial.wrapping_add(1); + if state.next_req_serial & 0xFF == 0 { + state.next_req_serial = state.next_req_serial.wrapping_add(1); + } + + msg.param[0..4].copy_from_slice(&req_serial.to_le_bytes()); + state.send_message(msg, req_data); + + // Setup the pending request state. + let (req_slot_idx, req_slot) = state + .requests + .iter_mut() + .enumerate() + .find(|(_, x)| x.is_none()) + .unwrap(); + msg.id = 0; // zero out id, so when it becomes nonzero we know the req is done. + let msg_ptr: *mut Message = msg; + *req_slot = Some(PendingRequest { + req_serial, + resp_msg: msg_ptr, + waker, + }); + + drop(state); // don't borrow state across awaits. + + // On cancel, unregister the request slot. + let _drop = OnDrop::new(|| { + // Remove request slot. + let mut state = self.state.borrow_mut(); + let slot = &mut state.requests[req_slot_idx]; + if let Some(s) = slot { + if s.req_serial == req_serial { + *slot = None; + } + } + + // If cancelation raced with actually receiving the response, + // we own the data, so we have to free it. + let msg = unsafe { &mut *msg_ptr }; + if msg.id != 0 { + state.send_free(msg); + } + }); + // Wait for response. + poll_fn(|_| { + // we have to use the raw pointer and not the original reference `msg` + // because that'd invalidate the raw ptr that's still stored in `req_slot`. + if unsafe { (*msg_ptr).id } != 0 { + Poll::Ready(()) + } else { + Poll::Pending + } + }) + .await; + _drop.defuse(); + + if msg.data.is_null() { + // no response data. + return 0; + } + + // Copy response data out, if any. + // Pointer was validated in StateInner::handle_data(). + let mut len = msg.data_len; + if len > resp_data.len() { + warn!("truncating response data from {} to {}", len, resp_data.len()); + len = resp_data.len(); + } + fence(Ordering::SeqCst); // synchronize volatile accesses with the nonvolatile copy_nonoverlapping. + unsafe { ptr::copy_nonoverlapping(msg.data, resp_data.as_mut_ptr(), len) } + fence(Ordering::SeqCst); // synchronize volatile accesses with the nonvolatile copy_nonoverlapping. + self.state.borrow_mut().send_free(msg); + len + } + + /// Run an AT command. + /// + /// The response is written in `resp` and its length returned. + pub async fn at_command(&self, req: &[u8], resp: &mut [u8]) -> usize { + let mut msg: Message = unsafe { mem::zeroed() }; + msg.channel = 2; // data + msg.id = 0x0001_0003; // AT command + msg.param_len = 4; + + self.request(&mut msg, req, resp).await + } + + /// Open the raw socket used for sending/receiving IP packets. + /// + /// This must be done after `AT+CFUN=1` (?) + pub async fn open_raw_socket(&self) { + let mut msg: Message = unsafe { mem::zeroed() }; + msg.channel = 2; // data + msg.id = 0x7001_0004; // open socket + msg.param_len = 20; + + let param = [ + 0xFF, 0xFF, 0xFF, 0xFF, // req_serial + 0xFF, 0xFF, 0xFF, 0xFF, // ??? + 0x05, 0x00, 0x00, 0x00, // family + 0x03, 0x00, 0x00, 0x00, // type + 0x00, 0x00, 0x00, 0x00, // protocol + ]; + msg.param[..param.len()].copy_from_slice(¶m); + + self.request(&mut msg, &[], &mut []).await; + + assert_eq!(msg.id, 0x80010004); + assert!(msg.param_len >= 12); + let status = u32::from_le_bytes(msg.param[8..12].try_into().unwrap()); + assert_eq!(status, 0); + assert_eq!(msg.param_len, 16); + let fd = u32::from_le_bytes(msg.param[12..16].try_into().unwrap()); + debug!("got FD: {}", fd); + } +} + +/// Background runner for the driver. +pub struct Runner<'a, TW: embedded_io::Write> { + ch: ch::Runner<'a, MTU>, + state: &'a RefCell, + trace_writer: TW, +} + +impl<'a, TW: embedded_io::Write> Runner<'a, TW> { + /// Run the driver operation in the background. + /// + /// You must run this in a background task, concurrently with all network operations. + pub async fn run(mut self) -> ! { + poll_fn(|cx| { + WAKER.register(cx.waker()); + + let mut state = self.state.borrow_mut(); + state.poll(&mut self.trace_writer, &mut self.ch); + + if let Poll::Ready(buf) = self.ch.poll_tx_buf(cx) { + let fd = 128u32; // TODO unhardcode + let mut msg: Message = unsafe { mem::zeroed() }; + msg.channel = 2; // data + msg.id = 0x7006_0004; // IP send + msg.param_len = 12; + msg.param[4..8].copy_from_slice(&fd.to_le_bytes()); + state.send_message(&mut msg, buf); + self.ch.tx_done(); + } + + Poll::Pending + }) + .await + } +} + +const LIST_LEN: usize = 16; + +#[repr(C)] +struct ControlBlock { + version: u32, + rx_base: *mut u8, + rx_size: usize, + control_list_ptr: *mut List, + data_list_ptr: *mut List, + modem_info_ptr: *mut ModemInfo, + trace_ptr: *mut Trace, + unk: u32, + + modem_info: ModemInfo, + trace: Trace, + + // 0 = control, 1 = data + lists: [List; 2], + msgs: [[Message; LIST_LEN]; 2], + + tx_bufs: [[u8; TX_BUF_SIZE]; TX_BUF_COUNT], +} + +#[repr(C)] +struct ModemInfo { + version: u32, + control_list_ptr: *mut List, + data_list_ptr: *mut List, + padding: [u32; 5], +} + +#[repr(C)] +struct Trace { + size: usize, + base: *mut u8, + tx_state: u32, + tx_ptr: *mut u8, + rx_state: u32, + rx_ptr: *mut u8, + unk1: u32, + unk2: u32, +} + +const TRACE_CHANNEL_COUNT: usize = 3; + +#[repr(C)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +struct TraceContext { + unk1: u32, + unk2: u32, + len: u32, + chans: [*mut TraceChannel; TRACE_CHANNEL_COUNT], +} + +#[repr(C)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +struct TraceChannel { + id: u8, + unk1: u8, + unk2: u8, + unk3: u8, + write_ptr: *mut u8, + read_ptr: *mut u8, + start: *mut u8, + end: *mut u8, +} + +#[repr(C)] +struct List { + len: usize, + items: [ListItem; LIST_LEN], +} + +#[repr(C)] +struct ListItem { + /// top 16 bits: seqno + /// bottom 8 bits: + /// 0x01: sent + /// 0x02: held + /// 0x03: freed + state: u32, + message: *mut Message, +} + +#[repr(C)] +#[derive(defmt::Format, Clone, Copy)] +struct Message { + id: u32, + + /// 1 = control, 2 = data + channel: u8, + unk1: u8, + unk2: u8, + unk3: u8, + + data: *mut u8, + data_len: usize, + param_len: usize, + param: [u8; 44], +} + +struct OnDrop { + f: MaybeUninit, +} + +impl OnDrop { + pub fn new(f: F) -> Self { + Self { f: MaybeUninit::new(f) } + } + + pub fn defuse(self) { + mem::forget(self) + } +} + +impl Drop for OnDrop { + fn drop(&mut self) { + unsafe { self.f.as_ptr().read()() } + } +} diff --git a/examples/nrf9160/.cargo/config.toml b/examples/nrf9160/.cargo/config.toml index f64c63966..6072b8595 100644 --- a/examples/nrf9160/.cargo/config.toml +++ b/examples/nrf9160/.cargo/config.toml @@ -1,5 +1,6 @@ [target.'cfg(all(target_arch = "arm", target_os = "none"))'] -runner = "probe-rs run --chip nRF9160_xxAA" +# runner = "probe-rs run --chip nRF9160_xxAA" +runner = [ "probe-rs", "run", "--chip=nRF9160_xxAA", "--always-print-stacktrace", "--log-format={t} {[{L}]%bold} {s} {{c} {ff}:{l:1}%dimmed}" ] [build] target = "thumbv8m.main-none-eabihf" diff --git a/examples/nrf9160/Cargo.toml b/examples/nrf9160/Cargo.toml index c30b54ebd..fc24e99d2 100644 --- a/examples/nrf9160/Cargo.toml +++ b/examples/nrf9160/Cargo.toml @@ -8,6 +8,8 @@ license = "MIT OR Apache-2.0" embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf9160-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } +embassy-net-nrf91 = { version = "0.1.0", path = "../../embassy-net-nrf91", features = ["defmt"] } +embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "proto-ipv4", "medium-ip"] } defmt = "0.3" defmt-rtt = "0.4" @@ -15,6 +17,9 @@ defmt-rtt = "0.4" cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } cortex-m-rt = "0.7.0" panic-probe = { version = "0.3", features = ["print-defmt"] } +static_cell = { version = "2" } +embedded-io = "0.6.1" +embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } [profile.release] debug = 2 diff --git a/examples/nrf9160/memory.x b/examples/nrf9160/memory.x index 4c7d4ebf0..e33498773 100644 --- a/examples/nrf9160/memory.x +++ b/examples/nrf9160/memory.x @@ -1,5 +1,9 @@ MEMORY { - FLASH : ORIGIN = 0x00000000, LENGTH = 1024K - RAM : ORIGIN = 0x20018000, LENGTH = 160K + FLASH : ORIGIN = 0x00000000, LENGTH = 1024K + RAM : ORIGIN = 0x20010000, LENGTH = 192K + IPC : ORIGIN = 0x20000000, LENGTH = 64K } + +PROVIDE(__start_ipc = ORIGIN(IPC)); +PROVIDE(__end_ipc = ORIGIN(IPC) + LENGTH(IPC)); diff --git a/examples/nrf9160/src/bin/modem_tcp_client.rs b/examples/nrf9160/src/bin/modem_tcp_client.rs new file mode 100644 index 000000000..b1dac18a1 --- /dev/null +++ b/examples/nrf9160/src/bin/modem_tcp_client.rs @@ -0,0 +1,250 @@ +#![no_std] +#![no_main] + +use core::mem::MaybeUninit; +use core::ptr::addr_of_mut; +use core::str::FromStr; +use core::{slice, str}; + +use defmt::{assert, *}; +use embassy_executor::Spawner; +use embassy_net::{Ipv4Address, Ipv4Cidr, Stack, StackResources}; +use embassy_net_nrf91::{Runner, State}; +use embassy_nrf::buffered_uarte::{self, BufferedUarteTx}; +use embassy_nrf::gpio::{AnyPin, Level, Output, OutputDrive, Pin}; +use embassy_nrf::uarte::Baudrate; +use embassy_nrf::{bind_interrupts, interrupt, peripherals, uarte}; +use embassy_time::{Duration, Timer}; +use embedded_io_async::Write; +use static_cell::StaticCell; +use {defmt_rtt as _, panic_probe as _}; + +#[interrupt] +fn IPC() { + embassy_net_nrf91::on_ipc_irq(); +} + +bind_interrupts!(struct Irqs { + UARTE0_SPIM0_SPIS0_TWIM0_TWIS0 => buffered_uarte::InterruptHandler; +}); + +// embassy-net-nrf91 only supports blocking trace write for now. +// We don't want to block packet processing with slow uart writes, so +// we make an adapter that writes whatever fits in the buffer and drops +// data if it's full. +struct TraceWriter(BufferedUarteTx<'static, peripherals::SERIAL0>); + +impl embedded_io::ErrorType for TraceWriter { + type Error = core::convert::Infallible; +} + +impl embedded_io::Write for TraceWriter { + fn write(&mut self, buf: &[u8]) -> Result { + let _ = self.0.try_write(buf); + Ok(buf.len()) + } + fn flush(&mut self) -> Result<(), Self::Error> { + Ok(()) + } +} + +#[embassy_executor::task] +async fn modem_task(runner: Runner<'static, TraceWriter>) -> ! { + runner.run().await +} + +#[embassy_executor::task] +async fn net_task(stack: &'static Stack>) -> ! { + stack.run().await +} + +#[embassy_executor::task] +async fn blink_task(pin: AnyPin) { + let mut led = Output::new(pin, Level::Low, OutputDrive::Standard); + loop { + led.set_high(); + Timer::after_millis(100).await; + led.set_low(); + Timer::after_millis(100).await; + } +} + +extern "C" { + static __start_ipc: u8; + static __end_ipc: u8; +} + +#[embassy_executor::main] +async fn main(spawner: Spawner) { + let p = embassy_nrf::init(Default::default()); + + info!("Hello World!"); + + unwrap!(spawner.spawn(blink_task(p.P0_02.degrade()))); + + let ipc_mem = unsafe { + let ipc_start = &__start_ipc as *const u8 as *mut MaybeUninit; + let ipc_end = &__end_ipc as *const u8 as *mut MaybeUninit; + let ipc_len = ipc_end.offset_from(ipc_start) as usize; + slice::from_raw_parts_mut(ipc_start, ipc_len) + }; + + static mut TRACE_BUF: [u8; 4096] = [0u8; 4096]; + let mut config = uarte::Config::default(); + config.baudrate = Baudrate::BAUD1M; + let trace_writer = TraceWriter(BufferedUarteTx::new( + //let trace_uart = BufferedUarteTx::new( + unsafe { peripherals::SERIAL0::steal() }, + Irqs, + unsafe { peripherals::P0_01::steal() }, + //unsafe { peripherals::P0_14::steal() }, + config, + unsafe { &mut *addr_of_mut!(TRACE_BUF) }, + )); + + static STATE: StaticCell = StaticCell::new(); + let (device, control, runner) = embassy_net_nrf91::new(STATE.init(State::new()), ipc_mem, trace_writer).await; + unwrap!(spawner.spawn(modem_task(runner))); + + let config = embassy_net::Config::default(); + + // Generate "random" seed. nRF91 has no RNG, TODO figure out something... + let seed = 123456; + + // Init network stack + static RESOURCES: StaticCell> = StaticCell::new(); + static STACK: StaticCell>> = StaticCell::new(); + let stack = &*STACK.init(Stack::new( + device, + config, + RESOURCES.init(StackResources::<2>::new()), + seed, + )); + + unwrap!(spawner.spawn(net_task(stack))); + + control.wait_init().await; + info!("INIT OK"); + + let mut buf = [0u8; 256]; + + let n = control.at_command(b"AT+CFUN?", &mut buf).await; + info!("AT resp: '{}'", unsafe { str::from_utf8_unchecked(&buf[..n]) }); + + let n = control + .at_command(b"AT+CGDCONT=0,\"IP\",\"iot.nat.es\"", &mut buf) + .await; + info!("AT resp: '{}'", unsafe { str::from_utf8_unchecked(&buf[..n]) }); + let n = control + .at_command(b"AT+CGAUTH=0,1,\"orange\",\"orange\"", &mut buf) + .await; + info!("AT resp: '{}'", unsafe { str::from_utf8_unchecked(&buf[..n]) }); + + let n = control.at_command(b"AT+CFUN=1", &mut buf).await; + info!("AT resp: '{}'", unsafe { str::from_utf8_unchecked(&buf[..n]) }); + + info!("waiting for attach..."); + loop { + Timer::after_millis(500).await; + let n = control.at_command(b"AT+CGATT?", &mut buf).await; + let mut res = &buf[..n]; + pop_prefix(&mut res, b"+CGATT: "); + let res = split_field(&mut res); + info!("AT resp field: '{}'", unsafe { str::from_utf8_unchecked(res) }); + if res == b"1" { + break; + } + } + + let n = control.at_command(b"AT+CGPADDR=0", &mut buf).await; + let mut res = &buf[..n]; + pop_prefix(&mut res, b"+CGPADDR: 0,"); + let ip = split_field(&mut res); + let ip = Ipv4Address::from_str(unsafe { str::from_utf8_unchecked(ip) }).unwrap(); + info!("IP: '{}'", ip); + + info!("============== OPENING SOCKET"); + control.open_raw_socket().await; + + stack.set_config_v4(embassy_net::ConfigV4::Static(embassy_net::StaticConfigV4 { + address: Ipv4Cidr::new(ip, 32), + gateway: None, + dns_servers: Default::default(), + })); + + let mut rx_buffer = [0; 4096]; + let mut tx_buffer = [0; 4096]; + loop { + let mut socket = embassy_net::tcp::TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer); + socket.set_timeout(Some(Duration::from_secs(10))); + + info!("Connecting..."); + let host_addr = embassy_net::Ipv4Address::from_str("83.51.182.206").unwrap(); + if let Err(e) = socket.connect((host_addr, 8000)).await { + warn!("connect error: {:?}", e); + continue; + } + info!("Connected to {:?}", socket.remote_endpoint()); + + let msg = b"Hello world!\n"; + loop { + if let Err(e) = socket.write_all(msg).await { + warn!("write error: {:?}", e); + break; + } + info!("txd: {}", core::str::from_utf8(msg).unwrap()); + Timer::after_secs(1).await; + } + } +} + +fn is_whitespace(char: u8) -> bool { + match char { + b'\r' | b'\n' | b' ' => true, + _ => false, + } +} + +fn is_separator(char: u8) -> bool { + match char { + b',' | b'\r' | b'\n' | b' ' => true, + _ => false, + } +} + +fn split_field<'a>(data: &mut &'a [u8]) -> &'a [u8] { + while !data.is_empty() && is_whitespace(data[0]) { + *data = &data[1..]; + } + + if data.is_empty() { + return &[]; + } + + if data[0] == b'"' { + let data2 = &data[1..]; + let end = data2.iter().position(|&x| x == b'"').unwrap_or(data2.len()); + let field = &data2[..end]; + let mut rest = &data2[data2.len().min(end + 1)..]; + if rest.first() == Some(&b'\"') { + rest = &rest[1..]; + } + while !rest.is_empty() && is_separator(rest[0]) { + rest = &rest[1..]; + } + *data = rest; + field + } else { + let end = data.iter().position(|&x| is_separator(x)).unwrap_or(data.len()); + let field = &data[0..end]; + let rest = &data[data.len().min(end + 1)..]; + *data = rest; + field + } +} + +fn pop_prefix(data: &mut &[u8], prefix: &[u8]) { + assert!(data.len() >= prefix.len()); + assert!(&data[..prefix.len()] == prefix); + *data = &data[prefix.len()..]; +} From 11652ff5c7b139fd14ae270659181c65e59515dc Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 25 Jun 2024 21:15:23 +0200 Subject: [PATCH 0041/1217] don't crash if tx buffers fill up. --- embassy-net-nrf91/src/lib.rs | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/embassy-net-nrf91/src/lib.rs b/embassy-net-nrf91/src/lib.rs index 62ade6dd3..70ad176da 100644 --- a/embassy-net-nrf91/src/lib.rs +++ b/embassy-net-nrf91/src/lib.rs @@ -1,6 +1,7 @@ #![no_std] #![doc = include_str!("../README.md")] #![warn(missing_docs)] +#![deny(unused_must_use)] // must be first mod fmt; @@ -244,6 +245,10 @@ struct PendingRequest { waker: Waker, } +#[derive(Copy, Clone, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +struct NoFreeBufs; + struct StateInner { init: bool, init_waker: WakerRegistration, @@ -450,13 +455,13 @@ impl StateInner { return None; } - fn send_message(&mut self, msg: &mut Message, data: &[u8]) { + fn send_message(&mut self, msg: &mut Message, data: &[u8]) -> Result<(), NoFreeBufs> { if data.is_empty() { msg.data = ptr::null_mut(); msg.data_len = 0; } else { assert!(data.len() <= TX_BUF_SIZE); - let buf_idx = self.find_free_tx_buf().unwrap(); // TODO handle out of bufs + let buf_idx = self.find_free_tx_buf().ok_or(NoFreeBufs)?; let buf = unsafe { addr_of_mut!((*self.cb).tx_bufs[buf_idx]) } as *mut u8; unsafe { copy_nonoverlapping(data.as_ptr(), buf, data.len()) } msg.data = buf; @@ -467,10 +472,10 @@ impl StateInner { } // TODO free data buf if send_message_raw fails. - self.send_message_raw(msg); + self.send_message_raw(msg) } - fn send_message_raw(&mut self, msg: &Message) { + fn send_message_raw(&mut self, msg: &Message) -> Result<(), NoFreeBufs> { let (ch, ipc_ch) = match msg.channel { 1 => (0, 1), // control 2 => (1, 3), // data @@ -478,7 +483,7 @@ impl StateInner { }; // allocate a msg. - let idx = self.find_free_message(ch).unwrap(); // TODO handle list full + let idx = self.find_free_message(ch).ok_or(NoFreeBufs)?; debug!("tx seq {} msg: {:?}", self.tx_seq_no, msg); @@ -491,6 +496,7 @@ impl StateInner { let ipc = unsafe { &*pac::IPC_NS::ptr() }; ipc.tasks_send[ipc_ch].write(|w| unsafe { w.bits(1) }); + Ok(()) } fn handle_control(&mut self, msg: &Message) { @@ -626,7 +632,7 @@ impl StateInner { free_msg.data = msg.data; free_msg.data_len = msg.data_len; - self.send_message_raw(&free_msg); + unwrap!(self.send_message_raw(&free_msg)); } } @@ -702,7 +708,7 @@ impl<'a> Control<'a> { } msg.param[0..4].copy_from_slice(&req_serial.to_le_bytes()); - state.send_message(msg, req_data); + unwrap!(state.send_message(msg, req_data)); // Setup the pending request state. let (req_slot_idx, req_slot) = state @@ -838,7 +844,9 @@ impl<'a, TW: embedded_io::Write> Runner<'a, TW> { msg.id = 0x7006_0004; // IP send msg.param_len = 12; msg.param[4..8].copy_from_slice(&fd.to_le_bytes()); - state.send_message(&mut msg, buf); + if let Err(e) = state.send_message(&mut msg, buf) { + warn!("tx failed: {:?}", e); + } self.ch.tx_done(); } From bc67cc22aa1461e6bce19b663b00bdccc818a998 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Mon, 5 Aug 2024 12:09:29 +0200 Subject: [PATCH 0042/1217] update driver channel dependency --- embassy-net-nrf91/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-net-nrf91/Cargo.toml b/embassy-net-nrf91/Cargo.toml index 2156346a4..e2d596d59 100644 --- a/embassy-net-nrf91/Cargo.toml +++ b/embassy-net-nrf91/Cargo.toml @@ -22,7 +22,7 @@ nrf9160-pac = { version = "0.12.0" } embassy-time = { version = "0.3.1", path = "../embassy-time" } embassy-sync = { version = "0.6.0", path = "../embassy-sync"} embassy-futures = { version = "0.1.0", path = "../embassy-futures"} -embassy-net-driver-channel = { version = "0.2.0", path = "../embassy-net-driver-channel"} +embassy-net-driver-channel = { version = "0.3.0", path = "../embassy-net-driver-channel"} heapless = "0.8" embedded-io = "0.6.1" From 86a45b47e529864ac5a203b4ad26b9ee62127a1e Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Mon, 5 Aug 2024 12:09:58 +0200 Subject: [PATCH 0043/1217] add at command file --- embassy-net-nrf91/src/at.rs | 45 +++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 embassy-net-nrf91/src/at.rs diff --git a/embassy-net-nrf91/src/at.rs b/embassy-net-nrf91/src/at.rs new file mode 100644 index 000000000..04cbf3876 --- /dev/null +++ b/embassy-net-nrf91/src/at.rs @@ -0,0 +1,45 @@ +use crate::{Error, Control}; + +// Drives the control loop of the modem based on declarative configuration. +pub struct AtDriver<'a> { + control: Control<'a>, + config: Config, +} + +pub struct Config { + pub network: NetworkConfig, +} + +pub struct NetworkConfig { + pub apn: &'static str, + pub prot: AuthProtection, + pub userid: &'static str, + pub password: &'static str, +} + +#[repr(u8)] +pub enum AuthProtection { + None = 0, + Pap = 1, + Chap = 2, +} + +impl<'a> AtDriver<'a> { + pub async fn new(control: Control<'a>, config: Config) -> Result { + control.wait_init().await; + Ok(Self { + control, + config, + }) + } + + async fn setup(&self) -> Result<(), Error> { + + } + + pub fn run(&self, stack: Stack>) -> ! { + loop { + + } + } +} From c9ad897d4a6f1c66d77372fd27ec135e0c798f65 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Wed, 21 Aug 2024 18:12:59 +0200 Subject: [PATCH 0044/1217] Use released bt-hci crate --- cyw43/Cargo.toml | 2 +- examples/rp/Cargo.toml | 1 - examples/rp23/Cargo.toml | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/cyw43/Cargo.toml b/cyw43/Cargo.toml index 9b469c338..751e59a69 100644 --- a/cyw43/Cargo.toml +++ b/cyw43/Cargo.toml @@ -36,7 +36,7 @@ heapless = "0.8.0" # Bluetooth deps embedded-io-async = { version = "0.6.0", optional = true } -bt-hci = { git = "https://github.com/alexmoon/bt-hci.git", rev = "b9cd5954f6bd89b535cad9c418e9fdf12812d7c3", optional = true, default-features = false } +bt-hci = { version = "0.1.0", optional = true } [package.metadata.embassy_docs] src_base = "https://github.com/embassy-rs/embassy/blob/cyw43-v$VERSION/cyw43/src/" diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index 83d5792b6..04b4c6317 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml @@ -74,7 +74,6 @@ opt-level = "z" [patch.crates-io] trouble-host = { git = "https://github.com/embassy-rs/trouble.git", rev = "4b8c0f499b34e46ca23a56e2d1640ede371722cf" } -bt-hci = { git = "https://github.com/alexmoon/bt-hci.git", rev = "b9cd5954f6bd89b535cad9c418e9fdf12812d7c3" } embassy-executor = { path = "../../embassy-executor" } embassy-sync = { path = "../../embassy-sync" } embassy-futures = { path = "../../embassy-futures" } diff --git a/examples/rp23/Cargo.toml b/examples/rp23/Cargo.toml index 8f8d6ff10..087f6fd69 100644 --- a/examples/rp23/Cargo.toml +++ b/examples/rp23/Cargo.toml @@ -71,7 +71,6 @@ opt-level = "z" [patch.crates-io] trouble-host = { git = "https://github.com/embassy-rs/trouble.git", rev = "4b8c0f499b34e46ca23a56e2d1640ede371722cf" } -bt-hci = { git = "https://github.com/alexmoon/bt-hci.git", rev = "b9cd5954f6bd89b535cad9c418e9fdf12812d7c3" } embassy-executor = { path = "../../embassy-executor" } embassy-sync = { path = "../../embassy-sync" } embassy-futures = { path = "../../embassy-futures" } From acc26a076a44c4c64b960e259bb516a9bd636dfd Mon Sep 17 00:00:00 2001 From: dvdsk Date: Fri, 23 Aug 2024 15:04:00 +0200 Subject: [PATCH 0045/1217] embassy-net/read document return value Ok(0) --- embassy-net/src/tcp.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/embassy-net/src/tcp.rs b/embassy-net/src/tcp.rs index 18200287e..62ee5cb66 100644 --- a/embassy-net/src/tcp.rs +++ b/embassy-net/src/tcp.rs @@ -79,6 +79,9 @@ impl<'a> TcpReader<'a> { /// /// Returns how many bytes were read, or an error. If no data is available, it waits /// until there is at least one byte available. + /// + /// A return value of Ok(0) means that the socket was closed and is longer able to + /// accept bytes or that the buffer provided is empty. pub async fn read(&mut self, buf: &mut [u8]) -> Result { self.io.read(buf).await } @@ -273,6 +276,9 @@ impl<'a> TcpSocket<'a> { /// /// Returns how many bytes were read, or an error. If no data is available, it waits /// until there is at least one byte available. + /// + /// A return value of Ok(0) means that the socket was closed and is longer able to + /// accept bytes or that the buffer provided is empty. pub async fn read(&mut self, buf: &mut [u8]) -> Result { self.io.read(buf).await } From 5479647962477a794dfcde19d8e865eb47150caf Mon Sep 17 00:00:00 2001 From: dvdsk Date: Fri, 23 Aug 2024 19:16:33 +0200 Subject: [PATCH 0046/1217] embassy-net: fix/clearify TcpReader docs. Expand docs on timeouts --- embassy-net/src/tcp.rs | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/embassy-net/src/tcp.rs b/embassy-net/src/tcp.rs index 62ee5cb66..b2e3279cc 100644 --- a/embassy-net/src/tcp.rs +++ b/embassy-net/src/tcp.rs @@ -80,8 +80,14 @@ impl<'a> TcpReader<'a> { /// Returns how many bytes were read, or an error. If no data is available, it waits /// until there is at least one byte available. /// - /// A return value of Ok(0) means that the socket was closed and is longer able to - /// accept bytes or that the buffer provided is empty. + /// # Note + /// A return value of Ok(0) means that we have read all data and the remote + /// side has closed our receive half of the socket. The remote can no longer + /// send bytes. + /// + /// The send half of the socket is still open. If you want to reconnect using + /// the socket you split this reader off the send half needs to be closed using + /// [`abort()`](TcpSocket::abort). pub async fn read(&mut self, buf: &mut [u8]) -> Result { self.io.read(buf).await } @@ -277,8 +283,8 @@ impl<'a> TcpSocket<'a> { /// Returns how many bytes were read, or an error. If no data is available, it waits /// until there is at least one byte available. /// - /// A return value of Ok(0) means that the socket was closed and is longer able to - /// accept bytes or that the buffer provided is empty. + /// A return value of Ok(0) means that the socket was closed and is longer + /// able to receive any data. pub async fn read(&mut self, buf: &mut [u8]) -> Result { self.io.read(buf).await } @@ -303,6 +309,10 @@ impl<'a> TcpSocket<'a> { /// /// If the timeout is set, the socket will be closed if no data is received for the /// specified duration. + /// + /// # Note: + /// Set a keep alive interval ([`set_keep_alive`] to prevent timeouts when + /// the remote could still respond. pub fn set_timeout(&mut self, duration: Option) { self.io .with_mut(|s, _| s.set_timeout(duration.map(duration_to_smoltcp))) @@ -314,6 +324,9 @@ impl<'a> TcpSocket<'a> { /// the specified duration of inactivity. /// /// If not set, the socket will not send keep-alive packets. + /// + /// By setting a [`timeout`](Self::timeout) larger then the keep alive you + /// can detect a remote endpoint that no longer answers. pub fn set_keep_alive(&mut self, interval: Option) { self.io .with_mut(|s, _| s.set_keep_alive(interval.map(duration_to_smoltcp))) From 8c1024b2a59c82ffccaba0327c02bc99da047943 Mon Sep 17 00:00:00 2001 From: Ugljesa Jovanovic Date: Sat, 24 Aug 2024 12:11:54 +0200 Subject: [PATCH 0047/1217] Set up timer0 tick when initializing clocks --- embassy-rp/src/clocks.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs index 5f7ba10e2..ed146844c 100644 --- a/embassy-rp/src/clocks.rs +++ b/embassy-rp/src/clocks.rs @@ -512,12 +512,18 @@ pub(crate) unsafe fn init(config: ClockConfig) { w.set_int(config.ref_clk.div); }); - // Configure tick generation on the 2040. On the 2350 the timers are driven from the sysclk. + // Configure tick generation on the 2040. #[cfg(feature = "rp2040")] pac::WATCHDOG.tick().write(|w| { w.set_cycles((clk_ref_freq / 1_000_000) as u16); w.set_enable(true); }); + // Configure tick generator on the 2350 + #[cfg(feature = "_rp235x")] + { + pac::TICKS.timer0_cycles().write(|w| w.0 = clk_ref_freq / 1_000_000); + pac::TICKS.timer0_ctrl().write(|w| w.set_enable(true)); + } let (sys_src, sys_aux, clk_sys_freq) = { use {ClkSysCtrlAuxsrc as Aux, ClkSysCtrlSrc as Src}; From 87e97fb69d31606456ddbf9e3308364773648929 Mon Sep 17 00:00:00 2001 From: elagil Date: Sat, 24 Aug 2024 20:16:00 +0200 Subject: [PATCH 0048/1217] feat: add function to check if SAI is muted --- embassy-stm32/src/sai/mod.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/embassy-stm32/src/sai/mod.rs b/embassy-stm32/src/sai/mod.rs index c48d81b5f..6bf184dd8 100644 --- a/embassy-stm32/src/sai/mod.rs +++ b/embassy-stm32/src/sai/mod.rs @@ -987,6 +987,21 @@ impl<'d, T: Instance, W: word::Word> Sai<'d, T, W> { ch.cr2().modify(|w| w.set_mute(value)); } + /// Determine the mute state of the receiver. + /// + /// Clears the mute state flag in the status register. + pub fn is_muted(&self) -> Result { + match &self.ring_buffer { + RingBuffer::Readable(_) => { + let ch = T::REGS.ch(self.sub_block as usize); + let mute_state = ch.sr().read().mutedet(); + ch.clrfr().write(|w| w.set_cmutedet(true)); + Ok(mute_state) + } + _ => Err(Error::NotAReceiver), + } + } + /// Write data to the SAI ringbuffer. /// /// This appends the data to the buffer and returns immediately. The From 557cff708505eb02c2b4c7f264a726bb9c17812a Mon Sep 17 00:00:00 2001 From: elagil Date: Sat, 24 Aug 2024 20:23:10 +0200 Subject: [PATCH 0049/1217] feat: Add support for a full-speed ULPI mode --- embassy-stm32/src/usb/otg.rs | 49 +++++++++++++++++++++++++++++ embassy-usb-synopsys-otg/src/lib.rs | 7 +++-- 2 files changed, 54 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/usb/otg.rs b/embassy-stm32/src/usb/otg.rs index 8ee8dcc36..e27b164e4 100644 --- a/embassy-stm32/src/usb/otg.rs +++ b/embassy-stm32/src/usb/otg.rs @@ -97,6 +97,55 @@ impl<'d, T: Instance> Driver<'d, T> { } } + /// Initializes USB OTG peripheral with external Full-speed PHY (usually, a High-speed PHY in Full-speed mode). + /// + /// # Arguments + /// + /// * `ep_out_buffer` - An internal buffer used to temporarily store received packets. + /// Must be large enough to fit all OUT endpoint max packet sizes. + /// Endpoint allocation will fail if it is too small. + pub fn new_fs_ulpi( + _peri: impl Peripheral

+ 'd, + _irq: impl interrupt::typelevel::Binding> + 'd, + ulpi_clk: impl Peripheral

> + 'd, + ulpi_dir: impl Peripheral

> + 'd, + ulpi_nxt: impl Peripheral

> + 'd, + ulpi_stp: impl Peripheral

> + 'd, + ulpi_d0: impl Peripheral

> + 'd, + ulpi_d1: impl Peripheral

> + 'd, + ulpi_d2: impl Peripheral

> + 'd, + ulpi_d3: impl Peripheral

> + 'd, + ulpi_d4: impl Peripheral

> + 'd, + ulpi_d5: impl Peripheral

> + 'd, + ulpi_d6: impl Peripheral

> + 'd, + ulpi_d7: impl Peripheral

> + 'd, + ep_out_buffer: &'d mut [u8], + config: Config, + ) -> Self { + config_ulpi_pins!( + ulpi_clk, ulpi_dir, ulpi_nxt, ulpi_stp, ulpi_d0, ulpi_d1, ulpi_d2, ulpi_d3, ulpi_d4, ulpi_d5, ulpi_d6, + ulpi_d7 + ); + + let regs = T::regs(); + + let instance = OtgInstance { + regs: T::regs(), + state: T::state(), + fifo_depth_words: T::FIFO_DEPTH_WORDS, + extra_rx_fifo_words: RX_FIFO_EXTRA_SIZE_WORDS, + endpoint_count: T::ENDPOINT_COUNT, + phy_type: PhyType::ExternalFullSpeed, + quirk_setup_late_cnak: quirk_setup_late_cnak(regs), + calculate_trdt_fn: calculate_trdt::, + }; + + Self { + inner: OtgDriver::new(ep_out_buffer, instance, config), + phantom: PhantomData, + } + } + /// Initializes USB OTG peripheral with external High-Speed PHY. /// /// # Arguments diff --git a/embassy-usb-synopsys-otg/src/lib.rs b/embassy-usb-synopsys-otg/src/lib.rs index b90e059f6..82752010a 100644 --- a/embassy-usb-synopsys-otg/src/lib.rs +++ b/embassy-usb-synopsys-otg/src/lib.rs @@ -179,6 +179,8 @@ pub enum PhyType { /// /// Available on a few STM32 chips. InternalHighSpeed, + /// External ULPI Full-Speed PHY (or High-Speed PHY in Full-Speed mode) + ExternalFullSpeed, /// External ULPI High-Speed PHY ExternalHighSpeed, } @@ -188,14 +190,14 @@ impl PhyType { pub fn internal(&self) -> bool { match self { PhyType::InternalFullSpeed | PhyType::InternalHighSpeed => true, - PhyType::ExternalHighSpeed => false, + PhyType::ExternalHighSpeed | PhyType::ExternalFullSpeed => false, } } /// Get whether this PHY is any of the high-speed types. pub fn high_speed(&self) -> bool { match self { - PhyType::InternalFullSpeed => false, + PhyType::InternalFullSpeed | PhyType::ExternalFullSpeed => false, PhyType::ExternalHighSpeed | PhyType::InternalHighSpeed => true, } } @@ -204,6 +206,7 @@ impl PhyType { match self { PhyType::InternalFullSpeed => vals::Dspd::FULL_SPEED_INTERNAL, PhyType::InternalHighSpeed => vals::Dspd::HIGH_SPEED, + PhyType::ExternalFullSpeed => vals::Dspd::FULL_SPEED_EXTERNAL, PhyType::ExternalHighSpeed => vals::Dspd::HIGH_SPEED, } } From 41e162541aa56553162932278ba8b6763fb63ecd Mon Sep 17 00:00:00 2001 From: Emil Fresk Date: Sun, 25 Aug 2024 07:14:19 +0200 Subject: [PATCH 0050/1217] stm32: Fix log storm when no CAN is connected Running the bxcan driver without having it connected to a CAN bus causes the `info` logs to bombard. This removes the logging statements as they looked like remnants from the development of the driver. --- embassy-stm32/src/can/bxcan/mod.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/embassy-stm32/src/can/bxcan/mod.rs b/embassy-stm32/src/can/bxcan/mod.rs index 278c93ff4..baa4bee79 100644 --- a/embassy-stm32/src/can/bxcan/mod.rs +++ b/embassy-stm32/src/can/bxcan/mod.rs @@ -68,7 +68,6 @@ pub struct SceInterruptHandler { impl interrupt::typelevel::Handler for SceInterruptHandler { unsafe fn on_interrupt() { - info!("sce irq"); let msr = T::regs().msr(); let msr_val = msr.read(); @@ -76,9 +75,8 @@ impl interrupt::typelevel::Handler for SceInterrup msr.modify(|m| m.set_slaki(true)); T::state().err_waker.wake(); } else if msr_val.erri() { - info!("Error interrupt"); // Disable the interrupt, but don't acknowledge the error, so that it can be - // forwarded off the the bus message consumer. If we don't provide some way for + // forwarded off the bus message consumer. If we don't provide some way for // downstream code to determine that it has already provided this bus error instance // to the bus message consumer, we are doomed to re-provide a single error instance for // an indefinite amount of time. From bea1f34440eff7842c0c04e8b7381cdb429f5005 Mon Sep 17 00:00:00 2001 From: Daniel Trnka Date: Wed, 21 Aug 2024 13:15:48 +0200 Subject: [PATCH 0051/1217] stm32/usart: sending break character --- embassy-stm32/src/usart/mod.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index 89d92dda2..cbd4ac3bc 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -520,6 +520,21 @@ impl<'d, M: Mode> UartTx<'d, M> { pub fn blocking_flush(&mut self) -> Result<(), Error> { blocking_flush(self.info) } + + /// Send break character + pub fn send_break(&self) { + // Busy wait until previous break has been sent + #[cfg(any(usart_v1, usart_v2))] + while self.info.regs.cr1().read().sbk() {} + #[cfg(any(usart_v3, usart_v4))] + while self.info.regs.isr().read().sbkf() {} + + // Send break right after completing the current character transmission + #[cfg(any(usart_v1, usart_v2))] + self.info.regs.cr1().modify(|w| w.set_sbk(true)); + #[cfg(any(usart_v3, usart_v4))] + self.info.regs.rqr().write(|w| w.set_sbkrq(true)); + } } fn blocking_flush(info: &Info) -> Result<(), Error> { @@ -1365,6 +1380,11 @@ impl<'d, M: Mode> Uart<'d, M> { pub fn split(self) -> (UartTx<'d, M>, UartRx<'d, M>) { (self.tx, self.rx) } + + /// Send break character + pub fn send_break(&self) { + self.tx.send_break(); + } } fn reconfigure(info: &Info, kernel_clock: Hertz, config: &Config) -> Result<(), ConfigError> { From 9b142bd80fad43beeb1114ec289f570310aae2de Mon Sep 17 00:00:00 2001 From: Cirrus Date: Sun, 25 Aug 2024 13:14:36 -0700 Subject: [PATCH 0052/1217] feat(embassy-net): add zero-copy UDP send/recv functions Added recv_from_with and send_to_with. These are conceptually similar to TCP's read_with and write_with functions. An application can parse received datagrams directly out of the receive buffer or assemble a datagram of known-length directly into the send buffer. --- embassy-net/src/udp.rs | 63 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/embassy-net/src/udp.rs b/embassy-net/src/udp.rs index 6e50c4e01..1d5360187 100644 --- a/embassy-net/src/udp.rs +++ b/embassy-net/src/udp.rs @@ -138,6 +138,35 @@ impl<'a> UdpSocket<'a> { }) } + /// Receive a datagram with a zero-copy function. + /// + /// When no datagram is available, this method will return `Poll::Pending` and + /// register the current task to be notified when a datagram is received. + /// + /// When a datagram is received, this method will call the provided function + /// with the number of bytes received and the remote endpoint and return + /// `Poll::Ready` with the function's returned value. + pub async fn recv_from_with(&mut self, f: F) -> R + where + F: FnOnce(&[u8], UdpMetadata) -> R, + { + let mut f = Some(f); + poll_fn(move |cx| { + self.with_mut(|s, _| { + match s.recv() { + Ok((buffer, endpoint)) => Poll::Ready(unwrap!(f.take())(buffer, endpoint)), + Err(udp::RecvError::Truncated) => unreachable!(), + Err(udp::RecvError::Exhausted) => { + // socket buffer is empty wait until at least one byte has arrived + s.register_recv_waker(cx.waker()); + Poll::Pending + } + } + }) + }) + .await + } + /// Send a datagram to the specified remote endpoint. /// /// This method will wait until the datagram has been sent. @@ -181,6 +210,40 @@ impl<'a> UdpSocket<'a> { }) } + /// Send a datagram to the specified remote endpoint with a zero-copy function. + /// + /// This method will wait until the buffer can fit the requested size before + /// calling the function to fill its contents. + /// + /// When the remote endpoint is not reachable, this method will return `Err(SendError::NoRoute)` + pub async fn send_to_with(&mut self, size: usize, remote_endpoint: T, f: F) -> Result + where + T: Into + Copy, + F: FnOnce(&mut [u8]) -> R, + { + let mut f = Some(f); + poll_fn(move |cx| { + self.with_mut(|s, _| { + match s.send(size, remote_endpoint) { + Ok(buffer) => Poll::Ready(Ok(unwrap!(f.take())(buffer))), + Err(udp::SendError::BufferFull) => { + s.register_send_waker(cx.waker()); + Poll::Pending + } + Err(udp::SendError::Unaddressable) => { + // If no sender/outgoing port is specified, there is not really "no route" + if s.endpoint().port == 0 { + Poll::Ready(Err(SendError::SocketNotBound)) + } else { + Poll::Ready(Err(SendError::NoRoute)) + } + } + } + }) + }) + .await + } + /// Returns the local endpoint of the socket. pub fn endpoint(&self) -> IpListenEndpoint { self.with(|s, _| s.endpoint()) From 0a33edc9976caddcdebe0943cce78376f9c49789 Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Mon, 26 Aug 2024 09:41:52 -0400 Subject: [PATCH 0053/1217] Import rom_data for the rp235x, don't use intrinsics on rp235x Many thanks to @thejpster for his work on the rom_data! Working around boot2 is currently a bit hacky for the rp235x, that will improve in upcoming rp235x flash pr. --- embassy-rp/src/flash.rs | 82 +- embassy-rp/src/lib.rs | 1 + embassy-rp/src/rom_data/mod.rs | 33 + .../src/{rom_data.rs => rom_data/rp2040.rs} | 4 +- embassy-rp/src/rom_data/rp235x.rs | 752 ++++++++++++++++++ 5 files changed, 850 insertions(+), 22 deletions(-) create mode 100644 embassy-rp/src/rom_data/mod.rs rename embassy-rp/src/{rom_data.rs => rom_data/rp2040.rs} (99%) create mode 100644 embassy-rp/src/rom_data/rp235x.rs diff --git a/embassy-rp/src/flash.rs b/embassy-rp/src/flash.rs index a68493932..5f7922f8e 100644 --- a/embassy-rp/src/flash.rs +++ b/embassy-rp/src/flash.rs @@ -510,11 +510,19 @@ mod ram_helpers { /// /// `addr` and `len` parameters must be valid and are not checked. pub unsafe fn flash_range_erase(addr: u32, len: u32) { + #[cfg(feature = "rp2040")] let mut boot2 = [0u32; 256 / 4]; - let ptrs = if USE_BOOT2 { - rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256); - flash_function_pointers_with_boot2(true, false, &boot2) - } else { + let ptrs = { + #[cfg(feature = "rp2040")] + { + if USE_BOOT2 { + rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256); + flash_function_pointers_with_boot2(true, false, &boot2) + } else { + flash_function_pointers(true, false) + } + } + #[cfg(feature = "_rp235x")] flash_function_pointers(true, false) }; @@ -540,11 +548,19 @@ mod ram_helpers { /// /// `addr` and `len` parameters must be valid and are not checked. pub unsafe fn flash_range_erase_and_program(addr: u32, data: &[u8]) { + #[cfg(feature = "rp2040")] let mut boot2 = [0u32; 256 / 4]; - let ptrs = if USE_BOOT2 { - rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256); - flash_function_pointers_with_boot2(true, true, &boot2) - } else { + let ptrs = { + #[cfg(feature = "rp2040")] + { + if USE_BOOT2 { + rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256); + flash_function_pointers_with_boot2(true, true, &boot2) + } else { + flash_function_pointers(true, true) + } + } + #[cfg(feature = "_rp235x")] flash_function_pointers(true, true) }; @@ -575,11 +591,19 @@ mod ram_helpers { /// /// `addr` and `len` parameters must be valid and are not checked. pub unsafe fn flash_range_program(addr: u32, data: &[u8]) { + #[cfg(feature = "rp2040")] let mut boot2 = [0u32; 256 / 4]; - let ptrs = if USE_BOOT2 { - rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256); - flash_function_pointers_with_boot2(false, true, &boot2) - } else { + let ptrs = { + #[cfg(feature = "rp2040")] + { + if USE_BOOT2 { + rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256); + flash_function_pointers_with_boot2(false, true, &boot2) + } else { + flash_function_pointers(false, true) + } + } + #[cfg(feature = "_rp235x")] flash_function_pointers(false, true) }; @@ -708,13 +732,22 @@ mod ram_helpers { /// /// Credit: taken from `rp2040-flash` (also licensed Apache+MIT) pub unsafe fn flash_unique_id(out: &mut [u8]) { + #[cfg(feature = "rp2040")] let mut boot2 = [0u32; 256 / 4]; - let ptrs = if USE_BOOT2 { - rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256); - flash_function_pointers_with_boot2(false, false, &boot2) - } else { + let ptrs = { + #[cfg(feature = "rp2040")] + { + if USE_BOOT2 { + rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256); + flash_function_pointers_with_boot2(false, false, &boot2) + } else { + flash_function_pointers(false, false) + } + } + #[cfg(feature = "_rp235x")] flash_function_pointers(false, false) }; + // 4B - read unique ID let cmd = [0x4B]; read_flash(&cmd[..], 4, out, &ptrs as *const FlashFunctionPointers); @@ -736,13 +769,22 @@ mod ram_helpers { /// /// Credit: taken from `rp2040-flash` (also licensed Apache+MIT) pub unsafe fn flash_jedec_id() -> u32 { + #[cfg(feature = "rp2040")] let mut boot2 = [0u32; 256 / 4]; - let ptrs = if USE_BOOT2 { - rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256); - flash_function_pointers_with_boot2(false, false, &boot2) - } else { + let ptrs = { + #[cfg(feature = "rp2040")] + { + if USE_BOOT2 { + rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256); + flash_function_pointers_with_boot2(false, false, &boot2) + } else { + flash_function_pointers(false, false) + } + } + #[cfg(feature = "_rp235x")] flash_function_pointers(false, false) }; + let mut id = [0u8; 4]; // 9F - read JEDEC ID let cmd = [0x9F]; diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs index 21f0771de..c2c57eaa0 100644 --- a/embassy-rp/src/lib.rs +++ b/embassy-rp/src/lib.rs @@ -15,6 +15,7 @@ pub use rp_binary_info as binary_info; #[cfg(feature = "critical-section-impl")] mod critical_section_impl; +#[cfg(feature = "rp2040")] mod intrinsics; pub mod adc; diff --git a/embassy-rp/src/rom_data/mod.rs b/embassy-rp/src/rom_data/mod.rs new file mode 100644 index 000000000..e5fcf8e3c --- /dev/null +++ b/embassy-rp/src/rom_data/mod.rs @@ -0,0 +1,33 @@ +#![cfg_attr( + feature = "rp2040", + doc = r" +//! Functions and data from the RPI Bootrom. +//! +//! From the [RP2040 datasheet](https://datasheets.raspberrypi.org/rp2040/rp2040-datasheet.pdf), Section 2.8.2.1: +//! +//! > The Bootrom contains a number of public functions that provide useful +//! > RP2040 functionality that might be needed in the absence of any other code +//! > on the device, as well as highly optimized versions of certain key +//! > functionality that would otherwise have to take up space in most user +//! > binaries. +" +)] +#![cfg_attr( + feature = "_rp235x", + doc = r" +//! Functions and data from the RPI Bootrom. +//! +//! From [Section 5.4](https://rptl.io/rp2350-datasheet#section_bootrom) of the +//! RP2350 datasheet: +//! +//! > Whilst some ROM space is dedicated to the implementation of the boot +//! > sequence and USB/UART boot interfaces, the bootrom also contains public +//! > functions that provide useful RP2350 functionality that may be useful for +//! > any code or runtime running on the device +" +)] + +#[cfg_attr(feature = "rp2040", path = "rp2040.rs")] +#[cfg_attr(feature = "_rp235x", path = "rp235x.rs")] +mod inner; +pub use inner::*; diff --git a/embassy-rp/src/rom_data.rs b/embassy-rp/src/rom_data/rp2040.rs similarity index 99% rename from embassy-rp/src/rom_data.rs rename to embassy-rp/src/rom_data/rp2040.rs index baebe5b6c..5a74eddd6 100644 --- a/embassy-rp/src/rom_data.rs +++ b/embassy-rp/src/rom_data/rp2040.rs @@ -189,7 +189,7 @@ macro_rules! rom_functions { declare_rom_function! { $(#[$outer])* fn $name( $($argname: $ty),* ) -> $ret { - $crate::rom_data::rom_table_lookup($crate::rom_data::FUNC_TABLE, *$c) + $crate::rom_data::inner::rom_table_lookup($crate::rom_data::inner::FUNC_TABLE, *$c) } } @@ -205,7 +205,7 @@ macro_rules! rom_functions { declare_rom_function! { $(#[$outer])* unsafe fn $name( $($argname: $ty),* ) -> $ret { - $crate::rom_data::rom_table_lookup($crate::rom_data::FUNC_TABLE, *$c) + $crate::rom_data::inner::rom_table_lookup($crate::rom_data::inner::FUNC_TABLE, *$c) } } diff --git a/embassy-rp/src/rom_data/rp235x.rs b/embassy-rp/src/rom_data/rp235x.rs new file mode 100644 index 000000000..b16fee8f7 --- /dev/null +++ b/embassy-rp/src/rom_data/rp235x.rs @@ -0,0 +1,752 @@ +//! Functions and data from the RPI Bootrom. +//! +//! From [Section 5.4](https://rptl.io/rp2350-datasheet#section_bootrom) of the +//! RP2350 datasheet: +//! +//! > Whilst some ROM space is dedicated to the implementation of the boot +//! > sequence and USB/UART boot interfaces, the bootrom also contains public +//! > functions that provide useful RP2350 functionality that may be useful for +//! > any code or runtime running on the device + +// Credit: taken from `rp-hal` (also licensed Apache+MIT) +// https://github.com/rp-rs/rp-hal/blob/main/rp235x-hal/src/rom_data.rs + +/// A bootrom function table code. +pub type RomFnTableCode = [u8; 2]; + +/// This function searches for the tag which matches the mask. +type RomTableLookupFn = unsafe extern "C" fn(code: u32, mask: u32) -> usize; + +/// Pointer to the value lookup function supplied by the ROM. +/// +/// This address is described at `5.5.1. Locating the API Functions` +#[cfg(all(target_arch = "arm", target_os = "none"))] +const ROM_TABLE_LOOKUP_A2: *const u16 = 0x0000_0016 as _; + +/// Pointer to the value lookup function supplied by the ROM. +/// +/// This address is described at `5.5.1. Locating the API Functions` +#[cfg(all(target_arch = "arm", target_os = "none"))] +const ROM_TABLE_LOOKUP_A1: *const u32 = 0x0000_0018 as _; + +/// Pointer to the data lookup function supplied by the ROM. +/// +/// On Arm, the same function is used to look up code and data. +#[cfg(all(target_arch = "arm", target_os = "none"))] +const ROM_DATA_LOOKUP_A2: *const u16 = ROM_TABLE_LOOKUP_A2; + +/// Pointer to the data lookup function supplied by the ROM. +/// +/// On Arm, the same function is used to look up code and data. +#[cfg(all(target_arch = "arm", target_os = "none"))] +const ROM_DATA_LOOKUP_A1: *const u32 = ROM_TABLE_LOOKUP_A1; + +/// Pointer to the value lookup function supplied by the ROM. +/// +/// This address is described at `5.5.1. Locating the API Functions` +#[cfg(not(all(target_arch = "arm", target_os = "none")))] +const ROM_TABLE_LOOKUP_A2: *const u16 = 0x0000_7DFA as _; + +/// Pointer to the value lookup function supplied by the ROM. +/// +/// This address is described at `5.5.1. Locating the API Functions` +#[cfg(not(all(target_arch = "arm", target_os = "none")))] +const ROM_TABLE_LOOKUP_A1: *const u32 = 0x0000_7DF8 as _; + +/// Pointer to the data lookup function supplied by the ROM. +/// +/// On RISC-V, a different function is used to look up data. +#[cfg(not(all(target_arch = "arm", target_os = "none")))] +const ROM_DATA_LOOKUP_A2: *const u16 = 0x0000_7DF8 as _; + +/// Pointer to the data lookup function supplied by the ROM. +/// +/// On RISC-V, a different function is used to look up data. +#[cfg(not(all(target_arch = "arm", target_os = "none")))] +const ROM_DATA_LOOKUP_A1: *const u32 = 0x0000_7DF4 as _; + +/// Address of the version number of the ROM. +const VERSION_NUMBER: *const u8 = 0x0000_0013 as _; + +#[allow(unused)] +mod rt_flags { + pub const FUNC_RISCV: u32 = 0x0001; + pub const FUNC_RISCV_FAR: u32 = 0x0003; + pub const FUNC_ARM_SEC: u32 = 0x0004; + // reserved for 32-bit pointer: 0x0008 + pub const FUNC_ARM_NONSEC: u32 = 0x0010; + // reserved for 32-bit pointer: 0x0020 + pub const DATA: u32 = 0x0040; + // reserved for 32-bit pointer: 0x0080 + #[cfg(all(target_arch = "arm", target_os = "none"))] + pub const FUNC_ARM_SEC_RISCV: u32 = FUNC_ARM_SEC; + #[cfg(not(all(target_arch = "arm", target_os = "none")))] + pub const FUNC_ARM_SEC_RISCV: u32 = FUNC_RISCV; +} + +/// Retrieve rom content from a table using a code. +pub fn rom_table_lookup(tag: RomFnTableCode, mask: u32) -> usize { + let tag = u16::from_le_bytes(tag) as u32; + unsafe { + let lookup_func = if rom_version_number() == 1 { + ROM_TABLE_LOOKUP_A1.read() as usize + } else { + ROM_TABLE_LOOKUP_A2.read() as usize + }; + let lookup_func: RomTableLookupFn = core::mem::transmute(lookup_func); + lookup_func(tag, mask) + } +} + +/// Retrieve rom data content from a table using a code. +pub fn rom_data_lookup(tag: RomFnTableCode, mask: u32) -> usize { + let tag = u16::from_le_bytes(tag) as u32; + unsafe { + let lookup_func = if rom_version_number() == 1 { + ROM_DATA_LOOKUP_A1.read() as usize + } else { + ROM_DATA_LOOKUP_A2.read() as usize + }; + let lookup_func: RomTableLookupFn = core::mem::transmute(lookup_func); + lookup_func(tag, mask) + } +} + +macro_rules! declare_rom_function { + ( + $(#[$outer:meta])* + fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty + $lookup:block + ) => { + #[doc = r"Additional access for the `"] + #[doc = stringify!($name)] + #[doc = r"` ROM function."] + pub mod $name { + /// Retrieve a function pointer. + #[cfg(not(feature = "rom-func-cache"))] + pub fn ptr() -> extern "C" fn( $($argname: $ty),* ) -> $ret { + let p: usize = $lookup; + unsafe { + let func : extern "C" fn( $($argname: $ty),* ) -> $ret = core::mem::transmute(p); + func + } + } + + /// Retrieve a function pointer. + #[cfg(feature = "rom-func-cache")] + pub fn ptr() -> extern "C" fn( $($argname: $ty),* ) -> $ret { + use core::sync::atomic::{AtomicU16, Ordering}; + + // All pointers in the ROM fit in 16 bits, so we don't need a + // full width word to store the cached value. + static CACHED_PTR: AtomicU16 = AtomicU16::new(0); + // This is safe because the lookup will always resolve + // to the same value. So even if an interrupt or another + // core starts at the same time, it just repeats some + // work and eventually writes back the correct value. + let p: usize = match CACHED_PTR.load(Ordering::Relaxed) { + 0 => { + let raw: usize = $lookup; + CACHED_PTR.store(raw as u16, Ordering::Relaxed); + raw + }, + val => val as usize, + }; + unsafe { + let func : extern "C" fn( $($argname: $ty),* ) -> $ret = core::mem::transmute(p); + func + } + } + } + + $(#[$outer])* + pub extern "C" fn $name( $($argname: $ty),* ) -> $ret { + $name::ptr()($($argname),*) + } + }; + + ( + $(#[$outer:meta])* + unsafe fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty + $lookup:block + ) => { + #[doc = r"Additional access for the `"] + #[doc = stringify!($name)] + #[doc = r"` ROM function."] + pub mod $name { + /// Retrieve a function pointer. + #[cfg(not(feature = "rom-func-cache"))] + pub fn ptr() -> unsafe extern "C" fn( $($argname: $ty),* ) -> $ret { + let p: usize = $lookup; + unsafe { + let func : unsafe extern "C" fn( $($argname: $ty),* ) -> $ret = core::mem::transmute(p); + func + } + } + + /// Retrieve a function pointer. + #[cfg(feature = "rom-func-cache")] + pub fn ptr() -> unsafe extern "C" fn( $($argname: $ty),* ) -> $ret { + use core::sync::atomic::{AtomicU16, Ordering}; + + // All pointers in the ROM fit in 16 bits, so we don't need a + // full width word to store the cached value. + static CACHED_PTR: AtomicU16 = AtomicU16::new(0); + // This is safe because the lookup will always resolve + // to the same value. So even if an interrupt or another + // core starts at the same time, it just repeats some + // work and eventually writes back the correct value. + let p: usize = match CACHED_PTR.load(Ordering::Relaxed) { + 0 => { + let raw: usize = $lookup; + CACHED_PTR.store(raw as u16, Ordering::Relaxed); + raw + }, + val => val as usize, + }; + unsafe { + let func : unsafe extern "C" fn( $($argname: $ty),* ) -> $ret = core::mem::transmute(p); + func + } + } + } + + $(#[$outer])* + /// # Safety + /// + /// This is a low-level C function. It may be difficult to call safely from + /// Rust. If in doubt, check the rp235x datasheet for details and do your own + /// safety evaluation. + pub unsafe extern "C" fn $name( $($argname: $ty),* ) -> $ret { + $name::ptr()($($argname),*) + } + }; +} + +// **************** 5.5.7 Low-level Flash Commands **************** + +declare_rom_function! { + /// Restore all QSPI pad controls to their default state, and connect the + /// QMI peripheral to the QSPI pads. + /// + /// Supported architectures: ARM-S, RISC-V + unsafe fn connect_internal_flash() -> () { + crate::rom_data::rom_table_lookup(*b"IF", crate::rom_data::inner::rt_flags::FUNC_ARM_SEC_RISCV) + } +} + +declare_rom_function! { + /// Initialise the QMI for serial operations (direct mode) + /// + /// Also initialise a basic XIP mode, where the QMI will perform 03h serial + /// read commands at low speed (CLKDIV=12) in response to XIP reads. + /// + /// Then, issue a sequence to the QSPI device on chip select 0, designed to + /// return it from continuous read mode ("XIP mode") and/or QPI mode to a + /// state where it will accept serial commands. This is necessary after + /// system reset to restore the QSPI device to a known state, because + /// resetting RP2350 does not reset attached QSPI devices. It is also + /// necessary when user code, having already performed some + /// continuous-read-mode or QPI-mode accesses, wishes to return the QSPI + /// device to a state where it will accept the serial erase and programming + /// commands issued by the bootrom’s flash access functions. + /// + /// If a GPIO for the secondary chip select is configured via FLASH_DEVINFO, + /// then the XIP exit sequence is also issued to chip select 1. + /// + /// The QSPI device should be accessible for XIP reads after calling this + /// function; the name flash_exit_xip refers to returning the QSPI device + /// from its XIP state to a serial command state. + /// + /// Supported architectures: ARM-S, RISC-V + unsafe fn flash_exit_xip() -> () { + crate::rom_data::rom_table_lookup(*b"EX", crate::rom_data::inner::rt_flags::FUNC_ARM_SEC_RISCV) + } +} + +declare_rom_function! { + /// Erase count bytes, starting at addr (offset from start of flash). + /// + /// Optionally, pass a block erase command e.g. D8h block erase, and the + /// size of the block erased by this command — this function will use the + /// larger block erase where possible, for much higher erase speed. addr + /// must be aligned to a 4096-byte sector, and count must be a multiple of + /// 4096 bytes. + /// + /// This is a low-level flash API, and no validation of the arguments is + /// performed. See flash_op() for a higher-level API which checks alignment, + /// flash bounds and partition permissions, and can transparently apply a + /// runtime-to-storage address translation. + /// + /// The QSPI device must be in a serial command state before calling this + /// API, which can be achieved by calling connect_internal_flash() followed + /// by flash_exit_xip(). After the erase, the flash cache should be flushed + /// via flash_flush_cache() to ensure the modified flash data is visible to + /// cached XIP accesses. + /// + /// Finally, the original XIP mode should be restored by copying the saved + /// XIP setup function from bootram into SRAM, and executing it: the bootrom + /// provides a default function which restores the flash mode/clkdiv + /// discovered during flash scanning, and user programs can override this + /// with their own XIP setup function. + /// + /// For the duration of the erase operation, QMI is in direct mode (Section + /// 12.14.5) and attempting to access XIP from DMA, the debugger or the + /// other core will return a bus fault. XIP becomes accessible again once + /// the function returns. + /// + /// Supported architectures: ARM-S, RISC-V + unsafe fn flash_range_erase(addr: u32, count: usize, block_size: u32, block_cmd: u8) -> () { + crate::rom_data::rom_table_lookup(*b"RE", crate::rom_data::inner::rt_flags::FUNC_ARM_SEC_RISCV) + } +} + +declare_rom_function! { + /// Program data to a range of flash storage addresses starting at addr + /// (offset from the start of flash) and count bytes in size. + /// + /// `addr` must be aligned to a 256-byte boundary, and count must be a + /// multiple of 256. + /// + /// This is a low-level flash API, and no validation of the arguments is + /// performed. See flash_op() for a higher-level API which checks alignment, + /// flash bounds and partition permissions, and can transparently apply a + /// runtime-to-storage address translation. + /// + /// The QSPI device must be in a serial command state before calling this + /// API — see notes on flash_range_erase(). + /// + /// Supported architectures: ARM-S, RISC-V + unsafe fn flash_range_program(addr: u32, data: *const u8, count: usize) -> () { + crate::rom_data::rom_table_lookup(*b"RP", crate::rom_data::inner::rt_flags::FUNC_ARM_SEC_RISCV) + } +} + +declare_rom_function! { + /// Flush the entire XIP cache, by issuing an invalidate by set/way + /// maintenance operation to every cache line (Section 4.4.1). + /// + /// This ensures that flash program/erase operations are visible to + /// subsequent cached XIP reads. + /// + /// Note that this unpins pinned cache lines, which may interfere with + /// cache-as-SRAM use of the XIP cache. + /// + /// No other operations are performed. + /// + /// Supported architectures: ARM-S, RISC-V + unsafe fn flash_flush_cache() -> () { + crate::rom_data::rom_table_lookup(*b"FC", crate::rom_data::inner::rt_flags::FUNC_ARM_SEC_RISCV) + } +} + +declare_rom_function! { + /// Configure the QMI to generate a standard 03h serial read command, with + /// 24 address bits, upon each XIP access. + /// + /// This is a slow XIP configuration, but is widely supported. CLKDIV is set + /// to 12. The debugger may call this function to ensure that flash is + /// readable following a program/erase operation. + /// + /// Note that the same setup is performed by flash_exit_xip(), and the + /// RP2350 flash program/erase functions do not leave XIP in an inaccessible + /// state, so calls to this function are largely redundant. It is provided + /// for compatibility with RP2040. + /// + /// Supported architectures: ARM-S, RISC-V + unsafe fn flash_enter_cmd_xip() -> () { + crate::rom_data::rom_table_lookup(*b"CX", crate::rom_data::inner::rt_flags::FUNC_ARM_SEC_RISCV) + } +} + +declare_rom_function! { + /// Configure QMI for one of a small menu of XIP read modes supported by the + /// bootrom. This mode is configured for both memory windows (both chip + /// selects), and the clock divisor is also applied to direct mode. + /// + /// The available modes are: + /// + /// * 0: `03h` serial read: serial address, serial data, no wait cycles + /// * 1: `0Bh` serial read: serial address, serial data, 8 wait cycles + /// * 2: `BBh` dual-IO read: dual address, dual data, 4 wait cycles + /// (including MODE bits, which are driven to 0) + /// * 3: `EBh` quad-IO read: quad address, quad data, 6 wait cycles + /// (including MODE bits, which are driven to 0) + /// + /// The XIP write command/format are not configured by this function. When + /// booting from flash, the bootrom tries each of these modes in turn, from + /// 3 down to 0. The first mode that is found to work is remembered, and a + /// default XIP setup function is written into bootram that calls this + /// function (flash_select_xip_read_mode) with the parameters discovered + /// during flash scanning. This can be called at any time to restore the + /// flash parameters discovered during flash boot. + /// + /// All XIP modes configured by the bootrom have an 8-bit serial command + /// prefix, so that the flash can remain in a serial command state, meaning + /// XIP accesses can be mixed more freely with program/erase serial + /// operations. This has a performance penalty, so users can perform their + /// own flash setup after flash boot using continuous read mode or QPI mode + /// to avoid or alleviate the command prefix cost. + /// + /// Supported architectures: ARM-S, RISC-V + unsafe fn flash_select_xip_read_mode(bootrom_xip_mode: u8, clkdiv: u8) -> () { + crate::rom_data::rom_table_lookup(*b"XM", crate::rom_data::inner::rt_flags::FUNC_ARM_SEC_RISCV) + } +} + +declare_rom_function! { + /// Restore the QMI address translation registers, ATRANS0 through ATRANS7, + /// to their reset state. This makes the runtime- to-storage address map an + /// identity map, i.e. the mapped and unmapped address are equal, and the + /// entire space is fully mapped. + /// + /// See [Section 12.14.4](https://rptl.io/rp2350-datasheet#section_bootrom) of the RP2350 + /// datasheet. + /// + /// Supported architectures: ARM-S, RISC-V + unsafe fn flash_reset_address_trans() -> () { + crate::rom_data::rom_table_lookup(*b"RA", crate::rom_data::inner::rt_flags::FUNC_ARM_SEC_RISCV) + } +} + +// **************** High-level Flash Commands **************** + +declare_rom_function! { + /// Applies the address translation currently configured by QMI address + /// translation registers, ATRANS0 through ATRANS7. + /// + /// See [Section 12.14.4](https://rptl.io/rp2350-datasheet#section_bootrom) of the RP2350 + /// datasheet. + /// + /// Translating an address outside of the XIP runtime address window, or + /// beyond the bounds of an ATRANSx_SIZE field, returns + /// BOOTROM_ERROR_INVALID_ADDRESS, which is not a valid flash storage + /// address. Otherwise, return the storage address which QMI would access + /// when presented with the runtime address addr. This is effectively a + /// virtual-to-physical address translation for QMI. + /// + /// Supported architectures: ARM-S, RISC-V + unsafe fn flash_runtime_to_storage_addr(addr: u32) -> i32 { + crate::rom_data::rom_table_lookup(*b"FA", crate::rom_data::inner::rt_flags::FUNC_ARM_SEC_RISCV) + } +} + +declare_rom_function! { + /// Non-secure version of [flash_runtime_to_storage_addr()] + /// + /// Supported architectures: ARM-NS + #[cfg(all(target_arch = "arm", target_os = "none"))] + unsafe fn flash_runtime_to_storage_addr_ns(addr: u32) -> i32 { + crate::rom_data::rom_table_lookup(*b"FA", crate::rom_data::inner::rt_flags::FUNC_ARM_NONSEC) + } +} + +declare_rom_function! { + /// Perform a flash read, erase, or program operation. + /// + /// Erase operations must be sector-aligned (4096 bytes) and sector- + /// multiple-sized, and program operations must be page-aligned (256 bytes) + /// and page-multiple-sized; misaligned erase and program operations will + /// return BOOTROM_ERROR_BAD_ALIGNMENT. The operation — erase, read, program + /// — is selected by the CFLASH_OP_BITS bitfield of the flags argument. + /// + /// See datasheet section 5.5.8.2 for more details. + /// + /// Supported architectures: ARM-S, RISC-V + unsafe fn flash_op(flags: u32, addr: u32, size_bytes: u32, buffer: *mut u8) -> i32 { + crate::rom_data::rom_table_lookup(*b"FO", crate::rom_data::inner::rt_flags::FUNC_ARM_SEC_RISCV) + } +} + +declare_rom_function! { + /// Non-secure version of [flash_op()] + /// + /// Supported architectures: ARM-NS + #[cfg(all(target_arch = "arm", target_os = "none"))] + unsafe fn flash_op_ns(flags: u32, addr: u32, size_bytes: u32, buffer: *mut u8) -> i32 { + crate::rom_data::rom_table_lookup(*b"FO", crate::rom_data::inner::rt_flags::FUNC_ARM_NONSEC) + } +} + +// **************** Security Related Functions **************** + +declare_rom_function! { + /// Allow or disallow the specific NS API (note all NS APIs default to + /// disabled). + /// + /// See datasheet section 5.5.9.1 for more details. + /// + /// Supported architectures: ARM-S + #[cfg(all(target_arch = "arm", target_os = "none"))] + unsafe fn set_ns_api_permission(ns_api_num: u32, allowed: u8) -> i32 { + crate::rom_data::rom_table_lookup(*b"SP", crate::rom_data::inner::rt_flags::FUNC_ARM_SEC) + } +} + +declare_rom_function! { + /// Utility method that can be used by secure ARM code to validate a buffer + /// passed to it from Non-secure code. + /// + /// See datasheet section 5.5.9.2 for more details. + /// + /// Supported architectures: ARM-S, RISC-V + unsafe fn validate_ns_buffer() -> () { + crate::rom_data::rom_table_lookup(*b"VB", crate::rom_data::inner::rt_flags::FUNC_ARM_SEC_RISCV) + } +} + +// **************** Miscellaneous Functions **************** + +declare_rom_function! { + /// Resets the RP2350 and uses the watchdog facility to restart. + /// + /// See datasheet section 5.5.10.1 for more details. + /// + /// Supported architectures: ARM-S, RISC-V + fn reboot(flags: u32, delay_ms: u32, p0: u32, p1: u32) -> i32 { + crate::rom_data::rom_table_lookup(*b"RB", crate::rom_data::inner::rt_flags::FUNC_ARM_SEC_RISCV) + } +} + +declare_rom_function! { + /// Non-secure version of [reboot()] + /// + /// Supported architectures: ARM-NS + #[cfg(all(target_arch = "arm", target_os = "none"))] + fn reboot_ns(flags: u32, delay_ms: u32, p0: u32, p1: u32) -> i32 { + crate::rom_data::rom_table_lookup(*b"RB", crate::rom_data::inner::rt_flags::FUNC_ARM_NONSEC) + } +} + +declare_rom_function! { + /// Resets internal bootrom state. + /// + /// See datasheet section 5.5.10.2 for more details. + /// + /// Supported architectures: ARM-S, RISC-V + unsafe fn bootrom_state_reset(flags: u32) -> () { + crate::rom_data::rom_table_lookup(*b"SR", crate::rom_data::inner::rt_flags::FUNC_ARM_SEC_RISCV) + } +} + +declare_rom_function! { + /// Set a boot ROM callback. + /// + /// The only supported callback_number is 0 which sets the callback used for + /// the secure_call API. + /// + /// See datasheet section 5.5.10.3 for more details. + /// + /// Supported architectures: ARM-S, RISC-V + unsafe fn set_rom_callback(callback_number: i32, callback_fn: *const ()) -> i32 { + crate::rom_data::rom_table_lookup(*b"RC", crate::rom_data::inner::rt_flags::FUNC_ARM_SEC_RISCV) + } +} + +// **************** System Information Functions **************** + +declare_rom_function! { + /// Fills a buffer with various system information. + /// + /// Note that this API is also used to return information over the PICOBOOT + /// interface. + /// + /// See datasheet section 5.5.11.1 for more details. + /// + /// Supported architectures: ARM-S, RISC-V + unsafe fn get_sys_info(out_buffer: *mut u32, out_buffer_word_size: usize, flags: u32) -> i32 { + crate::rom_data::rom_table_lookup(*b"GS", crate::rom_data::inner::rt_flags::FUNC_ARM_SEC_RISCV) + } +} + +declare_rom_function! { + /// Non-secure version of [get_sys_info()] + /// + /// Supported architectures: ARM-NS + #[cfg(all(target_arch = "arm", target_os = "none"))] + unsafe fn get_sys_info_ns(out_buffer: *mut u32, out_buffer_word_size: usize, flags: u32) -> i32 { + crate::rom_data::rom_table_lookup(*b"GS", crate::rom_data::inner::rt_flags::FUNC_ARM_NONSEC) + } +} + +declare_rom_function! { + /// Fills a buffer with information from the partition table. + /// + /// Note that this API is also used to return information over the PICOBOOT + /// interface. + /// + /// See datasheet section 5.5.11.2 for more details. + /// + /// Supported architectures: ARM-S, RISC-V + unsafe fn get_partition_table_info(out_buffer: *mut u32, out_buffer_word_size: usize, flags_and_partition: u32) -> i32 { + crate::rom_data::rom_table_lookup(*b"GP", crate::rom_data::inner::rt_flags::FUNC_ARM_SEC_RISCV) + } +} + +declare_rom_function! { + /// Non-secure version of [get_partition_table_info()] + /// + /// Supported architectures: ARM-NS + #[cfg(all(target_arch = "arm", target_os = "none"))] + unsafe fn get_partition_table_info_ns(out_buffer: *mut u32, out_buffer_word_size: usize, flags_and_partition: u32) -> i32 { + crate::rom_data::rom_table_lookup(*b"GP", crate::rom_data::inner::rt_flags::FUNC_ARM_NONSEC) + } +} + +declare_rom_function! { + /// Loads the current partition table from flash, if present. + /// + /// See datasheet section 5.5.11.3 for more details. + /// + /// Supported architectures: ARM-S, RISC-V + unsafe fn load_partition_table(workarea_base: *mut u8, workarea_size: usize, force_reload: bool) -> i32 { + crate::rom_data::rom_table_lookup(*b"LP", crate::rom_data::inner::rt_flags::FUNC_ARM_SEC_RISCV) + } +} + +declare_rom_function! { + /// Writes data from a buffer into OTP, or reads data from OTP into a buffer. + /// + /// See datasheet section 5.5.11.4 for more details. + /// + /// Supported architectures: ARM-S, RISC-V + unsafe fn otp_access(buf: *mut u8, buf_len: usize, row_and_flags: u32) -> i32 { + crate::rom_data::rom_table_lookup(*b"OA", crate::rom_data::inner::rt_flags::FUNC_ARM_SEC_RISCV) + } +} + +declare_rom_function! { + /// Non-secure version of [otp_access()] + /// + /// Supported architectures: ARM-NS + #[cfg(all(target_arch = "arm", target_os = "none"))] + unsafe fn otp_access_ns(buf: *mut u8, buf_len: usize, row_and_flags: u32) -> i32 { + crate::rom_data::rom_table_lookup(*b"OA", crate::rom_data::inner::rt_flags::FUNC_ARM_NONSEC) + } +} + +// **************** Boot Related Functions **************** + +declare_rom_function! { + /// Determines which of the partitions has the "better" IMAGE_DEF. In the + /// case of executable images, this is the one that would be booted. + /// + /// See datasheet section 5.5.12.1 for more details. + /// + /// Supported architectures: ARM-S, RISC-V + unsafe fn pick_ab_parition(workarea_base: *mut u8, workarea_size: usize, partition_a_num: u32) -> i32 { + crate::rom_data::rom_table_lookup(*b"AB", crate::rom_data::inner::rt_flags::FUNC_ARM_SEC_RISCV) + } +} + +declare_rom_function! { + /// Searches a memory region for a launchable image, and executes it if + /// possible. + /// + /// See datasheet section 5.5.12.2 for more details. + /// + /// Supported architectures: ARM-S, RISC-V + unsafe fn chain_image(workarea_base: *mut u8, workarea_size: usize, region_base: i32, region_size: u32) -> i32 { + crate::rom_data::rom_table_lookup(*b"CI", crate::rom_data::inner::rt_flags::FUNC_ARM_SEC_RISCV) + } +} + +declare_rom_function! { + /// Perform an "explicit" buy of an executable launched via an IMAGE_DEF + /// which was "explicit buy" flagged. + /// + /// See datasheet section 5.5.12.3 for more details. + /// + /// Supported architectures: ARM-S, RISC-V + unsafe fn explicit_buy(buffer: *mut u8, buffer_size: u32) -> i32 { + crate::rom_data::rom_table_lookup(*b"EB", crate::rom_data::inner::rt_flags::FUNC_ARM_SEC_RISCV) + } +} + +declare_rom_function! { + /// Not yet documented. + /// + /// See datasheet section 5.5.12.4 for more details. + /// + /// Supported architectures: ARM-S, RISC-V + unsafe fn get_uf2_target_partition(workarea_base: *mut u8, workarea_size: usize, family_id: u32, partition_out: *mut u32) -> i32 { + crate::rom_data::rom_table_lookup(*b"GU", crate::rom_data::inner::rt_flags::FUNC_ARM_SEC_RISCV) + } +} + +declare_rom_function! { + /// Returns: The index of the B partition of partition A if a partition + /// table is present and loaded, and there is a partition A with a B + /// partition; otherwise returns BOOTROM_ERROR_NOT_FOUND. + /// + /// See datasheet section 5.5.12.5 for more details. + /// + /// Supported architectures: ARM-S, RISC-V + unsafe fn get_b_partition(partition_a: u32) -> i32 { + crate::rom_data::rom_table_lookup(*b"GB", crate::rom_data::inner::rt_flags::FUNC_ARM_SEC_RISCV) + } +} + +// **************** Non-secure-specific Functions **************** + +// NB: The "secure_call" function should be here, but it doesn't have a fixed +// function signature as it is designed to let you bounce into any secure +// function from non-secure mode. + +// **************** RISC-V Functions **************** + +declare_rom_function! { + /// Set stack for RISC-V bootrom functions to use. + /// + /// See datasheet section 5.5.14.1 for more details. + /// + /// Supported architectures: RISC-V + #[cfg(not(all(target_arch = "arm", target_os = "none")))] + unsafe fn set_bootrom_stack(base_size: *mut u32) -> i32 { + crate::rom_data::rom_table_lookup(*b"SS", crate::rom_data::inner::rt_flags::FUNC_RISCV) + } +} + +/// The version number of the rom. +pub fn rom_version_number() -> u8 { + unsafe { *VERSION_NUMBER } +} + +/// The 8 most significant hex digits of the Bootrom git revision. +pub fn git_revision() -> u32 { + let ptr = rom_data_lookup(*b"GR", rt_flags::DATA) as *const u32; + unsafe { ptr.read() } +} + +/// A pointer to the resident partition table info. +/// +/// The resident partition table is the subset of the full partition table that +/// is kept in memory, and used for flash permissions. +pub fn partition_table_pointer() -> *const u32 { + let ptr = rom_data_lookup(*b"PT", rt_flags::DATA) as *const *const u32; + unsafe { ptr.read() } +} + +/// Determine if we are in secure mode +/// +/// Returns `true` if we are in secure mode and `false` if we are in non-secure +/// mode. +#[cfg(all(target_arch = "arm", target_os = "none"))] +pub fn is_secure_mode() -> bool { + // Look at the start of ROM, which is always readable + #[allow(clippy::zero_ptr)] + let rom_base: *mut u32 = 0x0000_0000 as *mut u32; + // Use the 'tt' instruction to check the permissions for that address + let tt = cortex_m::asm::tt(rom_base); + // Is the secure bit set? => secure mode + (tt & (1 << 22)) != 0 +} + +/// Determine if we are in secure mode +/// +/// Always returns `false` on RISC-V as it is impossible to determine if +/// you are in Machine Mode or User Mode by design. +#[cfg(not(all(target_arch = "arm", target_os = "none")))] +pub fn is_secure_mode() -> bool { + false +} From d4ab9fc247731e5f8ede4bb60a8c3c63136e1e6d Mon Sep 17 00:00:00 2001 From: James Bowes Date: Mon, 26 Aug 2024 10:33:13 -0300 Subject: [PATCH 0054/1217] chore: Remove unused keyboard code from rp mouse example The usb mouse example included code copied from the keyboard example to set up a button, which is not used in the mouse example. Remove it, to make the example clearer. --- examples/rp/src/bin/usb_hid_mouse.rs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/examples/rp/src/bin/usb_hid_mouse.rs b/examples/rp/src/bin/usb_hid_mouse.rs index cce344fb0..5ee650910 100644 --- a/examples/rp/src/bin/usb_hid_mouse.rs +++ b/examples/rp/src/bin/usb_hid_mouse.rs @@ -8,7 +8,6 @@ use embassy_executor::Spawner; use embassy_futures::join::join; use embassy_rp::bind_interrupts; use embassy_rp::clocks::RoscRng; -use embassy_rp::gpio::{Input, Pull}; use embassy_rp::peripherals::USB; use embassy_rp::usb::{Driver, InterruptHandler}; use embassy_time::Timer; @@ -75,12 +74,6 @@ async fn main(_spawner: Spawner) { // Run the USB device. let usb_fut = usb.run(); - // Set up the signal pin that will be used to trigger the keyboard. - let mut signal_pin = Input::new(p.PIN_16, Pull::None); - - // Enable the schmitt trigger to slightly debounce. - signal_pin.set_schmitt(true); - let (reader, mut writer) = hid.split(); // Do stuff with the class! From 9347571fea243719826ff21b250bc0dff7f51fa5 Mon Sep 17 00:00:00 2001 From: Pedro Ferreira Date: Mon, 26 Aug 2024 20:28:30 +0200 Subject: [PATCH 0055/1217] rp: add example code to flash bluetooth fw (#3290) --- examples/rp/src/bin/bluetooth.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples/rp/src/bin/bluetooth.rs b/examples/rp/src/bin/bluetooth.rs index 901521b60..7524e7929 100644 --- a/examples/rp/src/bin/bluetooth.rs +++ b/examples/rp/src/bin/bluetooth.rs @@ -43,8 +43,10 @@ async fn main(spawner: Spawner) { // at hardcoded addresses, instead of baking them into the program with `include_bytes!`: // probe-rs download 43439A0.bin --format bin --chip RP2040 --base-address 0x10100000 // probe-rs download 43439A0_clm.bin --format bin --chip RP2040 --base-address 0x10140000 + // probe-rs download 43439A0_btfw.bin --format bin --chip RP2040 --base-address 0x10141400 //let fw = unsafe { core::slice::from_raw_parts(0x10100000 as *const u8, 224190) }; //let clm = unsafe { core::slice::from_raw_parts(0x10140000 as *const u8, 4752) }; + //let btfw = unsafe { core::slice::from_raw_parts(0x10141400 as *const u8, 6164) }; let pwr = Output::new(p.PIN_23, Level::Low); let cs = Output::new(p.PIN_25, Level::High); From f0a86070512ad739641cee7d9fa39d63f5c8a9f6 Mon Sep 17 00:00:00 2001 From: Scott Mabin Date: Mon, 26 Aug 2024 19:45:57 +0100 Subject: [PATCH 0056/1217] Add block-device-driver impl for use with embedded-fatfs (#2607) --- embassy-stm32/Cargo.toml | 2 ++ embassy-stm32/src/sdmmc/mod.rs | 41 ++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 54abd0799..9a6a5908e 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -88,6 +88,8 @@ static_assertions = { version = "1.1" } volatile-register = { version = "0.2.1" } bitflags = "2.4.2" +block-device-driver = { version = "0.2" } +aligned = "0.4.1" [dev-dependencies] critical-section = { version = "1.1", features = ["std"] } diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs index 44ff9fcd5..ed344c412 100644 --- a/embassy-stm32/src/sdmmc/mod.rs +++ b/embassy-stm32/src/sdmmc/mod.rs @@ -1511,3 +1511,44 @@ foreach_peripheral!( } }; ); + +impl<'d, T: Instance, Dma: SdmmcDma + 'd> block_device_driver::BlockDevice<512> for Sdmmc<'d, T, Dma> { + type Error = Error; + type Align = aligned::A4; + + async fn read( + &mut self, + mut block_address: u32, + buf: &mut [aligned::Aligned], + ) -> Result<(), Self::Error> { + // FIXME/TODO because of missing read_blocks multiple we have to do this one block at a time + for block in buf.iter_mut() { + // safety aligned by block device + let block = unsafe { &mut *(block as *mut _ as *mut crate::sdmmc::DataBlock) }; + self.read_block(block_address, block).await?; + block_address += 1; + } + + Ok(()) + } + + async fn write( + &mut self, + mut block_address: u32, + buf: &[aligned::Aligned], + ) -> Result<(), Self::Error> { + // FIXME/TODO because of missing read_blocks multiple we have to do this one block at a time + for block in buf.iter() { + // safety aligned by block device + let block = unsafe { &*(block as *const _ as *const crate::sdmmc::DataBlock) }; + self.write_block(block_address, block).await?; + block_address += 1; + } + + Ok(()) + } + + async fn size(&mut self) -> Result { + Ok(self.card()?.size()) + } +} From b56e95bf7c2c5ab0ead23ee66de05cf9a288bc5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Wed, 28 Aug 2024 10:26:48 +0200 Subject: [PATCH 0057/1217] Fix a typo --- embassy-time-driver/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-time-driver/src/lib.rs b/embassy-time-driver/src/lib.rs index 565597935..aab2f626e 100644 --- a/embassy-time-driver/src/lib.rs +++ b/embassy-time-driver/src/lib.rs @@ -98,7 +98,7 @@ pub trait Driver: Send + Sync + 'static { /// /// Implementations MUST ensure that: /// - This is guaranteed to be monotonic, i.e. a call to now() will always return - /// a greater or equal value than earler calls. Time can't "roll backwards". + /// a greater or equal value than earlier calls. Time can't "roll backwards". /// - It "never" overflows. It must not overflow in a sufficiently long time frame, say /// in 10_000 years (Human civilization is likely to already have self-destructed /// 10_000 years from now.). This means if your hardware only has 16bit/32bit timers From 22f4459ae28fe7e299f775f95952132d3c3dffa2 Mon Sep 17 00:00:00 2001 From: Daniel Trnka Date: Wed, 28 Aug 2024 21:35:31 +0200 Subject: [PATCH 0058/1217] stm32/usart: sending break character in buffered usart --- embassy-stm32/src/usart/buffered.rs | 14 ++++++++++++-- embassy-stm32/src/usart/mod.rs | 27 ++++++++++++++++----------- 2 files changed, 28 insertions(+), 13 deletions(-) diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs index 06cc0e41d..86f56eb7c 100644 --- a/embassy-stm32/src/usart/buffered.rs +++ b/embassy-stm32/src/usart/buffered.rs @@ -12,8 +12,8 @@ use embassy_sync::waitqueue::AtomicWaker; #[cfg(not(any(usart_v1, usart_v2)))] use super::DePin; use super::{ - clear_interrupt_flags, configure, rdr, reconfigure, sr, tdr, Config, ConfigError, CtsPin, Error, Info, Instance, - Regs, RtsPin, RxPin, TxPin, + clear_interrupt_flags, configure, rdr, reconfigure, send_break, sr, tdr, Config, ConfigError, CtsPin, Error, Info, + Instance, Regs, RtsPin, RxPin, TxPin, }; use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed}; use crate::interrupt::{self, InterruptExt}; @@ -359,6 +359,11 @@ impl<'d> BufferedUart<'d> { Ok(()) } + + /// Send break character + pub fn send_break(&self) { + self.tx.send_break() + } } impl<'d> BufferedUartRx<'d> { @@ -538,6 +543,11 @@ impl<'d> BufferedUartTx<'d> { Ok(()) } + + /// Send break character + pub fn send_break(&self) { + send_break(&self.info.regs); + } } impl<'d> Drop for BufferedUartRx<'d> { diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index cbd4ac3bc..e7f2f890a 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -523,17 +523,7 @@ impl<'d, M: Mode> UartTx<'d, M> { /// Send break character pub fn send_break(&self) { - // Busy wait until previous break has been sent - #[cfg(any(usart_v1, usart_v2))] - while self.info.regs.cr1().read().sbk() {} - #[cfg(any(usart_v3, usart_v4))] - while self.info.regs.isr().read().sbkf() {} - - // Send break right after completing the current character transmission - #[cfg(any(usart_v1, usart_v2))] - self.info.regs.cr1().modify(|w| w.set_sbk(true)); - #[cfg(any(usart_v3, usart_v4))] - self.info.regs.rqr().write(|w| w.set_sbkrq(true)); + send_break(&self.info.regs); } } @@ -549,6 +539,21 @@ fn blocking_flush(info: &Info) -> Result<(), Error> { Ok(()) } +/// Send break character +pub fn send_break(regs: &Regs) { + // Busy wait until previous break has been sent + #[cfg(any(usart_v1, usart_v2))] + while regs.cr1().read().sbk() {} + #[cfg(any(usart_v3, usart_v4))] + while regs.isr().read().sbkf() {} + + // Send break right after completing the current character transmission + #[cfg(any(usart_v1, usart_v2))] + regs.cr1().modify(|w| w.set_sbk(true)); + #[cfg(any(usart_v3, usart_v4))] + regs.rqr().write(|w| w.set_sbkrq(true)); +} + impl<'d> UartRx<'d, Async> { /// Create a new rx-only UART with no hardware flow control. /// From 372270a9b962196ede9c60a705cc3138ba592fec Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Tue, 27 Aug 2024 13:19:07 -0400 Subject: [PATCH 0059/1217] rp235x flash support. The 2350 doesn't have a boot2 like the 2040, but it does have the concept of a xip setup function that could be customized. By default the bootrom searches for the attached flash chip and provides an xip setup func at the base of the bootram. That bootram is not executable, so it still needs to be copied to ram like boot2 would be. Currently does not use inline assembly. Also switch to picotool, as elf2uf2 has not been patched to support the 2350. --- embassy-rp/src/flash.rs | 135 ++++++++++++++----------------- embassy-rp/src/lib.rs | 4 +- examples/rp23/.cargo/config.toml | 3 +- examples/rp23/src/bin/flash.rs | 15 +--- 4 files changed, 68 insertions(+), 89 deletions(-) diff --git a/embassy-rp/src/flash.rs b/embassy-rp/src/flash.rs index 5f7922f8e..dab99b4e2 100644 --- a/embassy-rp/src/flash.rs +++ b/embassy-rp/src/flash.rs @@ -17,9 +17,13 @@ use crate::peripherals::FLASH; /// Flash base address. pub const FLASH_BASE: *const u32 = 0x10000000 as _; +/// Address for xip setup function set up by the 235x bootrom. +#[cfg(feature = "_rp235x")] +pub const BOOTROM_BASE: *const u32 = 0x400e0000 as _; + /// If running from RAM, we might have no boot2. Use bootrom `flash_enter_cmd_xip` instead. // TODO: when run-from-ram is set, completely skip the "pause cores and jumpp to RAM" dance. -pub const USE_BOOT2: bool = !cfg!(feature = "run-from-ram"); +pub const USE_BOOT2: bool = !cfg!(feature = "run-from-ram") | cfg!(feature = "_rp235x"); // **NOTE**: // @@ -97,7 +101,10 @@ impl<'a, 'd, T: Instance, const FLASH_SIZE: usize> Drop for BackgroundRead<'a, ' // Errata RP2040-E8: Perform an uncached read to make sure there's not a transfer in // flight that might effect an address written to start a new transfer. This stalls // until after any transfer is complete, so the address will not change anymore. + #[cfg(feature = "rp2040")] const XIP_NOCACHE_NOALLOC_BASE: *const u32 = 0x13000000 as *const _; + #[cfg(feature = "_rp235x")] + const XIP_NOCACHE_NOALLOC_BASE: *const u32 = 0x14000000 as *const _; unsafe { core::ptr::read_volatile(XIP_NOCACHE_NOALLOC_BASE); } @@ -225,12 +232,14 @@ impl<'d, T: Instance, M: Mode, const FLASH_SIZE: usize> Flash<'d, T, M, FLASH_SI } /// Read SPI flash unique ID + #[cfg(feature = "rp2040")] pub fn blocking_unique_id(&mut self, uid: &mut [u8]) -> Result<(), Error> { unsafe { in_ram(|| ram_helpers::flash_unique_id(uid))? }; Ok(()) } /// Read SPI flash JEDEC ID + #[cfg(feature = "rp2040")] pub fn blocking_jedec_id(&mut self) -> Result { let mut jedec = None; unsafe { @@ -301,7 +310,10 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, Async, FLASH_SIZE> { // Use the XIP AUX bus port, rather than the FIFO register access (e.x. // pac::XIP_CTRL.stream_fifo().as_ptr()) to avoid DMA stalling on // general XIP access. + #[cfg(feature = "rp2040")] const XIP_AUX_BASE: *const u32 = 0x50400000 as *const _; + #[cfg(feature = "_rp235x")] + const XIP_AUX_BASE: *const u32 = 0x50500000 as *const _; let transfer = unsafe { crate::dma::read( self.dma.as_mut().unwrap(), @@ -510,19 +522,14 @@ mod ram_helpers { /// /// `addr` and `len` parameters must be valid and are not checked. pub unsafe fn flash_range_erase(addr: u32, len: u32) { - #[cfg(feature = "rp2040")] let mut boot2 = [0u32; 256 / 4]; - let ptrs = { + let ptrs = if USE_BOOT2 { #[cfg(feature = "rp2040")] - { - if USE_BOOT2 { - rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256); - flash_function_pointers_with_boot2(true, false, &boot2) - } else { - flash_function_pointers(true, false) - } - } + rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256); #[cfg(feature = "_rp235x")] + core::ptr::copy_nonoverlapping(BOOTROM_BASE as *const u8, boot2.as_mut_ptr() as *mut u8, 256); + flash_function_pointers_with_boot2(true, false, &boot2) + } else { flash_function_pointers(true, false) }; @@ -548,19 +555,14 @@ mod ram_helpers { /// /// `addr` and `len` parameters must be valid and are not checked. pub unsafe fn flash_range_erase_and_program(addr: u32, data: &[u8]) { - #[cfg(feature = "rp2040")] let mut boot2 = [0u32; 256 / 4]; - let ptrs = { + let ptrs = if USE_BOOT2 { #[cfg(feature = "rp2040")] - { - if USE_BOOT2 { - rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256); - flash_function_pointers_with_boot2(true, true, &boot2) - } else { - flash_function_pointers(true, true) - } - } + rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256); #[cfg(feature = "_rp235x")] + core::ptr::copy_nonoverlapping(BOOTROM_BASE as *const u8, (boot2).as_mut_ptr() as *mut u8, 256); + flash_function_pointers_with_boot2(true, true, &boot2) + } else { flash_function_pointers(true, true) }; @@ -591,19 +593,14 @@ mod ram_helpers { /// /// `addr` and `len` parameters must be valid and are not checked. pub unsafe fn flash_range_program(addr: u32, data: &[u8]) { - #[cfg(feature = "rp2040")] let mut boot2 = [0u32; 256 / 4]; - let ptrs = { + let ptrs = if USE_BOOT2 { #[cfg(feature = "rp2040")] - { - if USE_BOOT2 { - rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256); - flash_function_pointers_with_boot2(false, true, &boot2) - } else { - flash_function_pointers(false, true) - } - } + rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256); #[cfg(feature = "_rp235x")] + core::ptr::copy_nonoverlapping(BOOTROM_BASE as *const u8, boot2.as_mut_ptr() as *mut u8, 256); + flash_function_pointers_with_boot2(false, true, &boot2) + } else { flash_function_pointers(false, true) }; @@ -630,16 +627,7 @@ mod ram_helpers { #[link_section = ".data.ram_func"] #[cfg(feature = "rp2040")] unsafe fn write_flash_inner(addr: u32, len: u32, data: Option<&[u8]>, ptrs: *const FlashFunctionPointers) { - /* - Should be equivalent to: - rom_data::connect_internal_flash(); - rom_data::flash_exit_xip(); - rom_data::flash_range_erase(addr, len, 1 << 31, 0); // if selected - rom_data::flash_range_program(addr, data as *const _, len); // if selected - rom_data::flash_flush_cache(); - rom_data::flash_enter_cmd_xip(); - */ - #[cfg(target_arch = "arm")] + //#[cfg(target_arch = "arm")] core::arch::asm!( "mov r8, r0", "mov r9, r2", @@ -691,11 +679,30 @@ mod ram_helpers { ); } + /// # Safety + /// + /// Nothing must access flash while this is running. + /// Usually this means: + /// - interrupts must be disabled + /// - 2nd core must be running code from RAM or ROM with interrupts disabled + /// - DMA must not access flash memory + /// Length of data must be a multiple of 4096 + /// addr must be aligned to 4096 #[inline(never)] #[link_section = ".data.ram_func"] #[cfg(feature = "_rp235x")] - unsafe fn write_flash_inner(_addr: u32, _len: u32, _data: Option<&[u8]>, _ptrs: *const FlashFunctionPointers) { - todo!(); + unsafe fn write_flash_inner(addr: u32, len: u32, data: Option<&[u8]>, ptrs: *const FlashFunctionPointers) { + let data = data.map(|d| d.as_ptr()).unwrap_or(core::ptr::null()); + ((*ptrs).connect_internal_flash)(); + ((*ptrs).flash_exit_xip)(); + if (*ptrs).flash_range_erase.is_some() { + ((*ptrs).flash_range_erase.unwrap())(addr, len as usize, 1 << 31, 0); + } + if (*ptrs).flash_range_program.is_some() { + ((*ptrs).flash_range_program.unwrap())(addr, data as *const _, len as usize); + } + ((*ptrs).flash_flush_cache)(); + ((*ptrs).flash_enter_cmd_xip)(); } #[repr(C)] @@ -731,20 +738,13 @@ mod ram_helpers { /// - DMA must not access flash memory /// /// Credit: taken from `rp2040-flash` (also licensed Apache+MIT) + #[cfg(feature = "rp2040")] pub unsafe fn flash_unique_id(out: &mut [u8]) { - #[cfg(feature = "rp2040")] let mut boot2 = [0u32; 256 / 4]; - let ptrs = { - #[cfg(feature = "rp2040")] - { - if USE_BOOT2 { - rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256); - flash_function_pointers_with_boot2(false, false, &boot2) - } else { - flash_function_pointers(false, false) - } - } - #[cfg(feature = "_rp235x")] + let ptrs = if USE_BOOT2 { + rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256); + flash_function_pointers_with_boot2(false, false, &boot2) + } else { flash_function_pointers(false, false) }; @@ -768,20 +768,13 @@ mod ram_helpers { /// - DMA must not access flash memory /// /// Credit: taken from `rp2040-flash` (also licensed Apache+MIT) + #[cfg(feature = "rp2040")] pub unsafe fn flash_jedec_id() -> u32 { - #[cfg(feature = "rp2040")] let mut boot2 = [0u32; 256 / 4]; - let ptrs = { - #[cfg(feature = "rp2040")] - { - if USE_BOOT2 { - rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256); - flash_function_pointers_with_boot2(false, false, &boot2) - } else { - flash_function_pointers(false, false) - } - } - #[cfg(feature = "_rp235x")] + let ptrs = if USE_BOOT2 { + rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256); + flash_function_pointers_with_boot2(false, false, &boot2) + } else { flash_function_pointers(false, false) }; @@ -792,6 +785,7 @@ mod ram_helpers { u32::from_be_bytes(id) } + #[cfg(feature = "rp2040")] unsafe fn read_flash(cmd_addr: &[u8], dummy_len: u32, out: &mut [u8], ptrs: *const FlashFunctionPointers) { read_flash_inner( FlashCommand { @@ -932,13 +926,6 @@ mod ram_helpers { clobber_abi("C"), ); } - - #[inline(never)] - #[link_section = ".data.ram_func"] - #[cfg(feature = "_rp235x")] - unsafe fn read_flash_inner(_cmd: FlashCommand, _ptrs: *const FlashFunctionPointers) { - todo!(); - } } /// Make sure to uphold the contract points with rp2040-flash. diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs index c2c57eaa0..f8fcfe52b 100644 --- a/embassy-rp/src/lib.rs +++ b/embassy-rp/src/lib.rs @@ -402,7 +402,7 @@ embassy_hal_internal::peripherals! { BOOTSEL, } -#[cfg(not(feature = "boot2-none"))] +#[cfg(all(not(feature = "boot2-none"), feature = "rp2040"))] macro_rules! select_bootloader { ( $( $feature:literal => $loader:ident, )+ default => $default:ident ) => { $( @@ -419,7 +419,7 @@ macro_rules! select_bootloader { } } -#[cfg(not(feature = "boot2-none"))] +#[cfg(all(not(feature = "boot2-none"), feature = "rp2040"))] select_bootloader! { "boot2-at25sf128a" => BOOT_LOADER_AT25SF128A, "boot2-gd25q64cs" => BOOT_LOADER_GD25Q64CS, diff --git a/examples/rp23/.cargo/config.toml b/examples/rp23/.cargo/config.toml index f77e004dc..9a92b1ce2 100644 --- a/examples/rp23/.cargo/config.toml +++ b/examples/rp23/.cargo/config.toml @@ -1,6 +1,7 @@ [target.'cfg(all(target_arch = "arm", target_os = "none"))'] #runner = "probe-rs run --chip RP2040" -runner = "elf2uf2-rs -d" +#runner = "elf2uf2-rs -d" +runner = "picotool load -u -v -x -t elf" [build] target = "thumbv8m.main-none-eabihf" diff --git a/examples/rp23/src/bin/flash.rs b/examples/rp23/src/bin/flash.rs index 811561f26..84011e394 100644 --- a/examples/rp23/src/bin/flash.rs +++ b/examples/rp23/src/bin/flash.rs @@ -21,7 +21,7 @@ pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ embassy_rp::binary_info::rp_program_name!(c"example"), embassy_rp::binary_info::rp_cargo_version!(), - embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_description!(c"Flash"), embassy_rp::binary_info::rp_program_build_attribute!(), ]; @@ -41,22 +41,13 @@ async fn main(_spawner: Spawner) { let mut flash = embassy_rp::flash::Flash::<_, Async, FLASH_SIZE>::new(p.FLASH, p.DMA_CH0); - // Get JEDEC id - let jedec = flash.blocking_jedec_id().unwrap(); - info!("jedec id: 0x{:x}", jedec); - - // Get unique id - let mut uid = [0; 8]; - flash.blocking_unique_id(&mut uid).unwrap(); - info!("unique id: {:?}", uid); - erase_write_sector(&mut flash, 0x00); multiwrite_bytes(&mut flash, ERASE_SIZE as u32); background_read(&mut flash, (ERASE_SIZE * 2) as u32).await; - loop {} + info!("Flash Works!"); } fn multiwrite_bytes(flash: &mut embassy_rp::flash::Flash<'_, FLASH, Async, FLASH_SIZE>, offset: u32) { @@ -82,7 +73,7 @@ fn multiwrite_bytes(flash: &mut embassy_rp::flash::Flash<'_, FLASH, Async, FLASH defmt::unwrap!(flash.blocking_read(ADDR_OFFSET + offset, &mut read_buf)); info!("Contents after write starts with {=[u8]}", read_buf[0..4]); - if &read_buf[0..4] != &[0x01, 0x02, 0x03, 0x04] { + if read_buf[0..4] != [0x01, 0x02, 0x03, 0x04] { defmt::panic!("unexpected"); } } From abcb39a58b63c32e91b748d4380f4f6492fd28cb Mon Sep 17 00:00:00 2001 From: Maxime Vincent Date: Thu, 29 Aug 2024 17:32:43 +0200 Subject: [PATCH 0060/1217] Allow bos_descriptor_buf to be a zero-length slice --- embassy-usb/src/descriptor.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/embassy-usb/src/descriptor.rs b/embassy-usb/src/descriptor.rs index f1773fa8a..c4d79e39f 100644 --- a/embassy-usb/src/descriptor.rs +++ b/embassy-usb/src/descriptor.rs @@ -308,6 +308,9 @@ impl<'a> BosWriter<'a> { } pub(crate) fn bos(&mut self) { + if (self.writer.buf.len() - self.writer.position) < 5 { + return; + } self.num_caps_mark = Some(self.writer.position + 4); self.writer.write( descriptor_type::BOS, @@ -350,6 +353,9 @@ impl<'a> BosWriter<'a> { } pub(crate) fn end_bos(&mut self) { + if self.writer.position == 0 { + return; + } self.num_caps_mark = None; let position = self.writer.position as u16; self.writer.buf[2..4].copy_from_slice(&position.to_le_bytes()); From 0434798439b9037a4fa5f30165879292e388f042 Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Thu, 29 Aug 2024 12:28:23 -0400 Subject: [PATCH 0061/1217] Import otp from rp-hal, helper fns for chipid and randid Again, credit to @thejpster for doing the hard part and figuring out the otp. --- embassy-rp/src/lib.rs | 2 + embassy-rp/src/otp.rs | 108 +++++++++++++++++++++++++++++++++++ examples/rp23/src/bin/otp.rs | 46 +++++++++++++++ 3 files changed, 156 insertions(+) create mode 100644 embassy-rp/src/otp.rs create mode 100644 examples/rp23/src/bin/otp.rs diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs index f8fcfe52b..c357c14c2 100644 --- a/embassy-rp/src/lib.rs +++ b/embassy-rp/src/lib.rs @@ -32,6 +32,8 @@ pub mod gpio; pub mod i2c; pub mod i2c_slave; pub mod multicore; +#[cfg(feature = "_rp235x")] +pub mod otp; pub mod pwm; mod reset; pub mod rom_data; diff --git a/embassy-rp/src/otp.rs b/embassy-rp/src/otp.rs new file mode 100644 index 000000000..cdaf5bded --- /dev/null +++ b/embassy-rp/src/otp.rs @@ -0,0 +1,108 @@ +//! Interface to the RP2350's One Time Programmable Memory + +// Credit: taken from `rp-hal` (also licensed Apache+MIT) +// https://github.com/rp-rs/rp-hal/blob/main/rp235x-hal/src/rom_data.rs + +/// The ways in which we can fail to read OTP +#[derive(Debug, Clone)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum Error { + /// The user passed an invalid index to a function. + InvalidIndex, + /// The hardware refused to let us read this word, probably due to + /// read lock set earlier in the boot process. + InvalidPermissions, +} + +/// OTP read address, using automatic Error Correction. +/// +/// A 32-bit read returns the ECC-corrected data for two neighbouring rows, or +/// all-ones on permission failure. Only the first 8 KiB is populated. +pub const OTP_DATA_BASE: *const u32 = 0x4013_0000 as *const u32; + +/// OTP read address, without using any automatic Error Correction. +/// +/// A 32-bit read returns 24-bits of raw data from the OTP word. +pub const OTP_DATA_RAW_BASE: *const u32 = 0x4013_4000 as *const u32; + +/// How many pages in OTP (post error-correction) +pub const NUM_PAGES: usize = 64; + +/// How many rows in one page in OTP (post error-correction) +pub const NUM_ROWS_PER_PAGE: usize = 64; + +/// How many rows in OTP (post error-correction) +pub const NUM_ROWS: usize = NUM_PAGES * NUM_ROWS_PER_PAGE; + +/// Read one ECC protected word from the OTP +pub fn read_ecc_word(row: usize) -> Result { + if row >= NUM_ROWS { + return Err(Error::InvalidIndex); + } + // First do a raw read to check permissions + let _ = read_raw_word(row)?; + // One 32-bit read gets us two rows + let offset = row >> 1; + // # Safety + // + // We checked this offset was in range already. + let value = unsafe { OTP_DATA_BASE.add(offset).read() }; + if (row & 1) == 0 { + Ok(value as u16) + } else { + Ok((value >> 16) as u16) + } +} + +/// Read one raw word from the OTP +/// +/// You get the 24-bit raw value in the lower part of the 32-bit result. +pub fn read_raw_word(row: usize) -> Result { + if row >= NUM_ROWS { + return Err(Error::InvalidIndex); + } + // One 32-bit read gets us one row + // # Safety + // + // We checked this offset was in range already. + let value = unsafe { OTP_DATA_RAW_BASE.add(row).read() }; + if value == 0xFFFF_FFFF { + Err(Error::InvalidPermissions) + } else { + Ok(value) + } +} + +/// Get the random 64bit chipid from rows 0x0-0x3. +pub fn get_chipid() -> Result { + let w0 = read_ecc_word(0x000)?.to_be_bytes(); + let w1 = read_ecc_word(0x001)?.to_be_bytes(); + let w2 = read_ecc_word(0x002)?.to_be_bytes(); + let w3 = read_ecc_word(0x003)?.to_be_bytes(); + + Ok(u64::from_be_bytes([ + w3[0], w3[1], w2[0], w2[1], w1[0], w1[1], w0[0], w0[1], + ])) +} + +/// Get the 128bit private random number from rows 0x4-0xb. +/// +/// This ID is not exposed through the USB PICOBOOT GET_INFO command +/// or the ROM get_sys_info() API. However note that the USB PICOBOOT OTP +/// access point can read the entirety of page 0, so this value is not +/// meaningfully private unless the USB PICOBOOT interface is disabled via the +//// DISABLE_BOOTSEL_USB_PICOBOOT_IFC flag in BOOT_FLAGS0 +pub fn get_private_random_number() -> Result { + let w0 = read_ecc_word(0x004)?.to_be_bytes(); + let w1 = read_ecc_word(0x005)?.to_be_bytes(); + let w2 = read_ecc_word(0x006)?.to_be_bytes(); + let w3 = read_ecc_word(0x007)?.to_be_bytes(); + let w4 = read_ecc_word(0x008)?.to_be_bytes(); + let w5 = read_ecc_word(0x009)?.to_be_bytes(); + let w6 = read_ecc_word(0x00a)?.to_be_bytes(); + let w7 = read_ecc_word(0x00b)?.to_be_bytes(); + + Ok(u128::from_be_bytes([ + w7[0], w7[1], w6[0], w6[1], w5[0], w5[1], w4[0], w4[1], w3[0], w3[1], w2[0], w2[1], w1[0], w1[1], w0[0], w0[1], + ])) +} diff --git a/examples/rp23/src/bin/otp.rs b/examples/rp23/src/bin/otp.rs new file mode 100644 index 000000000..c4d79c6ea --- /dev/null +++ b/examples/rp23/src/bin/otp.rs @@ -0,0 +1,46 @@ +//! This example shows reading the OTP constants on the RP235x. + +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_rp::block::ImageDef; +use embassy_rp::otp; +use embassy_time::Timer; +use {defmt_rtt as _, panic_probe as _}; + +#[link_section = ".start_block"] +#[used] +pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); + +// Program metadata for `picotool info` +#[link_section = ".bi_entries"] +#[used] +pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ + embassy_rp::binary_info::rp_program_name!(c"OTP Read Example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"OTP Read Example"), + embassy_rp::binary_info::rp_program_build_attribute!(), +]; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let _ = embassy_rp::init(Default::default()); + // + // add some delay to give an attached debug probe time to parse the + // defmt RTT header. Reading that header might touch flash memory, which + // interferes with flash write operations. + // https://github.com/knurling-rs/defmt/pull/683 + Timer::after_millis(10).await; + + let unique_id = unwrap!(otp::get_unique_id()); + info!("Unique id:{:X}", unique_id); + + let private_rand = unwrap!(otp::get_private_random_number()); + info!("Private Rand:{:X}", private_rand); + + loop { + Timer::after_secs(1).await; + } +} From 4c07c356e44020d39bc27d44d24272ad369426c3 Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Thu, 29 Aug 2024 21:35:57 -0400 Subject: [PATCH 0062/1217] Fixup: forgot to rename fn in example --- examples/rp23/src/bin/otp.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/rp23/src/bin/otp.rs b/examples/rp23/src/bin/otp.rs index c4d79c6ea..106e514ca 100644 --- a/examples/rp23/src/bin/otp.rs +++ b/examples/rp23/src/bin/otp.rs @@ -34,8 +34,8 @@ async fn main(_spawner: Spawner) { // https://github.com/knurling-rs/defmt/pull/683 Timer::after_millis(10).await; - let unique_id = unwrap!(otp::get_unique_id()); - info!("Unique id:{:X}", unique_id); + let chip_id = unwrap!(otp::get_chipid()); + info!("Unique id:{:X}", chip_id); let private_rand = unwrap!(otp::get_private_random_number()); info!("Private Rand:{:X}", private_rand); From f6d92b76111d8619c92b13aa28e765abe356465c Mon Sep 17 00:00:00 2001 From: Badr Bouslikhin Date: Fri, 30 Aug 2024 18:52:23 +0200 Subject: [PATCH 0063/1217] fix(stm32): disable transmitter during half-duplex read --- embassy-stm32/src/usart/mod.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index 89d92dda2..af34b548e 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -526,9 +526,12 @@ fn blocking_flush(info: &Info) -> Result<(), Error> { let r = info.regs; while !sr(r).read().tc() {} - // Enable Receiver after transmission complete for Half-Duplex mode + // Disable Transmitter and enable receiver after transmission complete for Half-Duplex mode if r.cr3().read().hdsel() { - r.cr1().modify(|reg| reg.set_re(true)); + r.cr1().modify(|reg| { + reg.set_te(false); + reg.set_re(true); + }); } Ok(()) From 82f274ea097c4aef35cb452d94654f94ab549895 Mon Sep 17 00:00:00 2001 From: Maxime Vincent Date: Mon, 2 Sep 2024 12:05:33 +0200 Subject: [PATCH 0064/1217] stm32: add f2 flash support (blocking) --- embassy-stm32/src/flash/f2.rs | 142 +++++++++++++++++++++++++++++++++ embassy-stm32/src/flash/mod.rs | 5 +- 2 files changed, 145 insertions(+), 2 deletions(-) create mode 100644 embassy-stm32/src/flash/f2.rs diff --git a/embassy-stm32/src/flash/f2.rs b/embassy-stm32/src/flash/f2.rs new file mode 100644 index 000000000..cdab1fd2d --- /dev/null +++ b/embassy-stm32/src/flash/f2.rs @@ -0,0 +1,142 @@ +use core::ptr::write_volatile; +use core::sync::atomic::{fence, AtomicBool, Ordering}; + +use pac::flash::regs::Sr; + +use super::{FlashBank, FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; +use crate::flash::Error; +use crate::pac; + +static DATA_CACHE_WAS_ENABLED: AtomicBool = AtomicBool::new(false); + +impl FlashSector { + const fn snb(&self) -> u8 { + ((self.bank as u8) << 4) + self.index_in_bank + } +} + +pub(crate) const fn is_default_layout() -> bool { + true +} + +pub(crate) const fn get_flash_regions() -> &'static [&'static FlashRegion] { + &FLASH_REGIONS +} + +pub(crate) unsafe fn lock() { + pac::FLASH.cr().modify(|w| w.set_lock(true)); +} + +pub(crate) unsafe fn unlock() { + if pac::FLASH.cr().read().lock() { + pac::FLASH.keyr().write_value(0x4567_0123); + pac::FLASH.keyr().write_value(0xCDEF_89AB); + } +} + +pub(crate) unsafe fn enable_blocking_write() { + assert_eq!(0, WRITE_SIZE % 4); + save_data_cache_state(); + + pac::FLASH.cr().write(|w| { + w.set_pg(true); + w.set_psize(pac::flash::vals::Psize::PSIZE32); + }); +} + +pub(crate) unsafe fn disable_blocking_write() { + pac::FLASH.cr().write(|w| w.set_pg(false)); + restore_data_cache_state(); +} + +pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> { + write_start(start_address, buf); + blocking_wait_ready() +} + +unsafe fn write_start(start_address: u32, buf: &[u8; WRITE_SIZE]) { + let mut address = start_address; + for val in buf.chunks(4) { + write_volatile(address as *mut u32, u32::from_le_bytes(unwrap!(val.try_into()))); + address += val.len() as u32; + + // prevents parallelism errors + fence(Ordering::SeqCst); + } +} + +pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> { + save_data_cache_state(); + + trace!("Blocking erasing sector number {}", sector.snb()); + + pac::FLASH.cr().modify(|w| { + w.set_ser(true); + w.set_snb(sector.snb()) + }); + + pac::FLASH.cr().modify(|w| { + w.set_strt(true); + }); + + let ret: Result<(), Error> = blocking_wait_ready(); + clear_all_err(); + restore_data_cache_state(); + ret +} + +pub(crate) unsafe fn clear_all_err() { + // read and write back the same value. + // This clears all "write 1 to clear" bits. + pac::FLASH.sr().modify(|_| {}); +} + +unsafe fn blocking_wait_ready() -> Result<(), Error> { + loop { + let sr = pac::FLASH.sr().read(); + + if !sr.bsy() { + return get_result(sr); + } + } +} + +fn get_result(sr: Sr) -> Result<(), Error> { + if sr.pgserr() { + Err(Error::Seq) + } else if sr.pgperr() { + Err(Error::Parallelism) + } else if sr.pgaerr() { + Err(Error::Unaligned) + } else if sr.wrperr() { + Err(Error::Protected) + } else { + Ok(()) + } +} + +fn save_data_cache_state() { + let dual_bank = unwrap!(get_flash_regions().last()).bank == FlashBank::Bank2; + if dual_bank { + // Disable data cache during write/erase if there are two banks, see errata 2.2.12 + let dcen = pac::FLASH.acr().read().dcen(); + DATA_CACHE_WAS_ENABLED.store(dcen, Ordering::Relaxed); + if dcen { + pac::FLASH.acr().modify(|w| w.set_dcen(false)); + } + } +} + +fn restore_data_cache_state() { + let dual_bank = unwrap!(get_flash_regions().last()).bank == FlashBank::Bank2; + if dual_bank { + // Restore data cache if it was enabled + let dcen = DATA_CACHE_WAS_ENABLED.load(Ordering::Relaxed); + if dcen { + // Reset data cache before we enable it again + pac::FLASH.acr().modify(|w| w.set_dcrst(true)); + pac::FLASH.acr().modify(|w| w.set_dcrst(false)); + pac::FLASH.acr().modify(|w| w.set_dcen(true)) + } + } +} diff --git a/embassy-stm32/src/flash/mod.rs b/embassy-stm32/src/flash/mod.rs index ce2d1a04c..bce638db0 100644 --- a/embassy-stm32/src/flash/mod.rs +++ b/embassy-stm32/src/flash/mod.rs @@ -94,6 +94,7 @@ pub enum FlashBank { #[cfg_attr(any(flash_l0, flash_l1, flash_l4, flash_wl, flash_wb), path = "l.rs")] #[cfg_attr(flash_f0, path = "f0.rs")] #[cfg_attr(any(flash_f1, flash_f3), path = "f1f3.rs")] +#[cfg_attr(flash_f2, path = "f2.rs")] #[cfg_attr(flash_f4, path = "f4.rs")] #[cfg_attr(flash_f7, path = "f7.rs")] #[cfg_attr(any(flash_g0, flash_g4c2, flash_g4c3, flash_g4c4), path = "g.rs")] @@ -104,8 +105,8 @@ pub enum FlashBank { #[cfg_attr(flash_u0, path = "u0.rs")] #[cfg_attr( not(any( - flash_l0, flash_l1, flash_l4, flash_wl, flash_wb, flash_f0, flash_f1, flash_f3, flash_f4, flash_f7, flash_g0, - flash_g4c2, flash_g4c3, flash_g4c4, flash_h7, flash_h7ab, flash_u5, flash_h50, flash_u0 + flash_l0, flash_l1, flash_l4, flash_wl, flash_wb, flash_f0, flash_f1, flash_f2, flash_f3, flash_f4, flash_f7, + flash_g0, flash_g4c2, flash_g4c3, flash_g4c4, flash_h7, flash_h7ab, flash_u5, flash_h50, flash_u0 )), path = "other.rs" )] From b277f42c9d681ce3c929858adffcefbdb7adabef Mon Sep 17 00:00:00 2001 From: Adrian Friedli Date: Mon, 2 Sep 2024 22:07:49 +0200 Subject: [PATCH 0065/1217] nrf52840: fix naming of LED states in examples (#3304) The LEDs on the nrf52840 DK are active low. --- examples/nrf52840/src/bin/channel.rs | 4 ++-- examples/nrf52840/src/bin/channel_sender_receiver.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/nrf52840/src/bin/channel.rs b/examples/nrf52840/src/bin/channel.rs index 7fcea9dbd..e06ba1c73 100644 --- a/examples/nrf52840/src/bin/channel.rs +++ b/examples/nrf52840/src/bin/channel.rs @@ -35,8 +35,8 @@ async fn main(spawner: Spawner) { loop { match CHANNEL.receive().await { - LedState::On => led.set_high(), - LedState::Off => led.set_low(), + LedState::On => led.set_low(), + LedState::Off => led.set_high(), } } } diff --git a/examples/nrf52840/src/bin/channel_sender_receiver.rs b/examples/nrf52840/src/bin/channel_sender_receiver.rs index 3095a04ec..29f70f91c 100644 --- a/examples/nrf52840/src/bin/channel_sender_receiver.rs +++ b/examples/nrf52840/src/bin/channel_sender_receiver.rs @@ -33,8 +33,8 @@ async fn recv_task(led: AnyPin, receiver: Receiver<'static, NoopRawMutex, LedSta loop { match receiver.receive().await { - LedState::On => led.set_high(), - LedState::Off => led.set_low(), + LedState::On => led.set_low(), + LedState::Off => led.set_high(), } } } From 32cff6530fdb81066451cc1d3f1fbbb420e985da Mon Sep 17 00:00:00 2001 From: Lucas Martins Mendes Date: Tue, 3 Sep 2024 16:02:39 -0300 Subject: [PATCH 0066/1217] chore: fix using default_features instead of default-features in embassy boot dependency (#3306) --- embassy-boot/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-boot/Cargo.toml b/embassy-boot/Cargo.toml index 85b3695a1..d27fe763e 100644 --- a/embassy-boot/Cargo.toml +++ b/embassy-boot/Cargo.toml @@ -27,7 +27,7 @@ features = ["defmt"] defmt = { version = "0.3", optional = true } digest = "0.10" log = { version = "0.4", optional = true } -ed25519-dalek = { version = "2", default_features = false, features = ["digest"], optional = true } +ed25519-dalek = { version = "2", default-features = false, features = ["digest"], optional = true } embassy-embedded-hal = { version = "0.2.0", path = "../embassy-embedded-hal" } embassy-sync = { version = "0.6.0", path = "../embassy-sync" } embedded-storage = "0.3.1" @@ -42,7 +42,7 @@ rand = "0.8" futures = { version = "0.3", features = ["executor"] } sha1 = "0.10.5" critical-section = { version = "1.1.1", features = ["std"] } -ed25519-dalek = { version = "2", default_features = false, features = ["std", "rand_core", "digest"] } +ed25519-dalek = { version = "2", default-features = false, features = ["std", "rand_core", "digest"] } [features] ed25519-dalek = ["dep:ed25519-dalek", "_verify"] From a6db8678eb5a7c9ebcf6449799b4ff525fe52d5f Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Wed, 4 Sep 2024 11:04:36 +0200 Subject: [PATCH 0067/1217] Add utility for setting configuration for a context --- embassy-net-nrf91/src/at.rs | 45 ----- embassy-net-nrf91/src/context.rs | 196 +++++++++++++++++++ embassy-net-nrf91/src/lib.rs | 2 + examples/nrf9160/src/bin/modem_tcp_client.rs | 64 +++--- 4 files changed, 220 insertions(+), 87 deletions(-) delete mode 100644 embassy-net-nrf91/src/at.rs create mode 100644 embassy-net-nrf91/src/context.rs diff --git a/embassy-net-nrf91/src/at.rs b/embassy-net-nrf91/src/at.rs deleted file mode 100644 index 04cbf3876..000000000 --- a/embassy-net-nrf91/src/at.rs +++ /dev/null @@ -1,45 +0,0 @@ -use crate::{Error, Control}; - -// Drives the control loop of the modem based on declarative configuration. -pub struct AtDriver<'a> { - control: Control<'a>, - config: Config, -} - -pub struct Config { - pub network: NetworkConfig, -} - -pub struct NetworkConfig { - pub apn: &'static str, - pub prot: AuthProtection, - pub userid: &'static str, - pub password: &'static str, -} - -#[repr(u8)] -pub enum AuthProtection { - None = 0, - Pap = 1, - Chap = 2, -} - -impl<'a> AtDriver<'a> { - pub async fn new(control: Control<'a>, config: Config) -> Result { - control.wait_init().await; - Ok(Self { - control, - config, - }) - } - - async fn setup(&self) -> Result<(), Error> { - - } - - pub fn run(&self, stack: Stack>) -> ! { - loop { - - } - } -} diff --git a/embassy-net-nrf91/src/context.rs b/embassy-net-nrf91/src/context.rs new file mode 100644 index 000000000..6dda51793 --- /dev/null +++ b/embassy-net-nrf91/src/context.rs @@ -0,0 +1,196 @@ +use core::net::IpAddr; +use heapless::String; +use core::str::FromStr; +use core::fmt::Write; + +/// Provides a higher level API for configuring and reading information for a given +/// context id. +pub struct Control<'a> { + control: crate::Control<'a>, + cid: u8, +} + +pub struct Config<'a> { + pub gateway: &'a str, + pub auth_prot: AuthProt, + pub auth: Option<(&'a str, &'a str)>, +} + +#[repr(u8)] +pub enum AuthProt { + None = 0, + Pap = 1, + Chap = 2, +} + +#[derive(Clone, Copy, PartialEq, Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum Error { + BufferTooSmall, + AtCommand, + AddrParseError, + Format, +} + +impl From for Error { + fn from(_: core::fmt::Error) -> Self { + Self::Format + } +} + +#[derive(PartialEq, Debug)] +pub struct Status { + pub attached: bool, + pub ip: Option, +} + +#[cfg(feature = "defmt")] +impl defmt::Format for Status { + fn format(&self, f: defmt::Formatter<'_>) { + defmt::write!(f, "attached: {}", self.attached); + if let Some(ip) = &self.ip { + defmt::write!(f, ", ip: {}", defmt::Debug2Format(&ip)); + } + } +} + +impl<'a> Control<'a> { + pub async fn new(control: crate::Control<'a>, cid: u8) -> Self { + control.wait_init().await; + Self { control, cid } + } + + /// Bypass modem configurator + pub async fn at_command(&self, req: &[u8], resp: &mut [u8]) -> usize { + self.control.at_command(req, resp).await + } + + /// Configures the modem with the provided config. + pub async fn configure(&self, config: Config<'_>) -> Result<(), Error> { + let mut cmd: String<128> = String::new(); + let mut buf: [u8; 256] = [0; 256]; + + write!(cmd, "AT+CGDCONT={},\"IP\",\"{}\"", self.cid, config.gateway).map_err(|_| Error::BufferTooSmall)?; + let n = self.control.at_command(cmd.as_bytes(), &mut buf).await; + let mut res = &buf[..n]; + let res = split_field(&mut res); + if res != b"OK" { + return Err(Error::AtCommand) + } + cmd.clear(); + + write!(cmd, "AT+CGAUTH={},{}", self.cid, config.auth_prot as u8)?; + if let Some((username, password)) = config.auth { + write!(cmd, ",\"{}\",\"{}\"", username, password).map_err(|_| Error::BufferTooSmall)?; + } + let n = self.control.at_command(cmd.as_bytes(), &mut buf).await; + let mut res = &buf[..n]; + let res = split_field(&mut res); + if res != b"OK" { + return Err(Error::AtCommand) + } + cmd.clear(); + + let n = self.control.at_command(b"AT+CFUN=1", &mut buf).await; + let mut res = &buf[..n]; + let res = split_field(&mut res); + if res != b"OK" { + return Err(Error::AtCommand); + } + + Ok(()) + } + + pub async fn status(&self) -> Result { + let mut buf: [u8; 256] = [0; 256]; + let n = self.control.at_command(b"AT+CGATT?", &mut buf).await; + let mut res = &buf[..n]; + pop_prefix(&mut res, b"+CGATT: "); + let res = split_field(&mut res); + let attached = res == b"1"; + + if !attached { + return Ok(Status { attached, ip: None }) + } + + let mut s: String<128> = String::new(); + write!(s, "AT+CGPADDR={}", self.cid)?; + let n = self.control.at_command(s.as_bytes(), &mut buf).await; + let mut res = &buf[..n]; + s.clear(); + + write!(s, "+CGPADDR: {},", self.cid)?; + + info!("RES: {:?}", unsafe {core::str::from_utf8_unchecked(res)}); + if s.len() > res.len() { + let res = split_field(&mut res); + if res == b"OK" { + Ok(Status { attached, ip: None }) + } else { + Err(Error::AtCommand) + } + } else { + pop_prefix(&mut res, s.as_bytes()); + + let ip = split_field(&mut res); + if !ip.is_empty() { + let ip = IpAddr::from_str(unsafe { core::str::from_utf8_unchecked(ip) }).map_err(|_| Error::AddrParseError)?; + self.control.open_raw_socket().await; + Ok(Status { attached, ip: Some(ip) }) + } else { + Ok(Status { attached, ip: None }) + } + } + } +} + +pub(crate) fn is_whitespace(char: u8) -> bool { + match char { + b'\r' | b'\n' | b' ' => true, + _ => false, + } +} + +pub(crate) fn is_separator(char: u8) -> bool { + match char { + b',' | b'\r' | b'\n' | b' ' => true, + _ => false, + } +} + +pub(crate) fn split_field<'a>(data: &mut &'a [u8]) -> &'a [u8] { + while !data.is_empty() && is_whitespace(data[0]) { + *data = &data[1..]; + } + + if data.is_empty() { + return &[]; + } + + if data[0] == b'"' { + let data2 = &data[1..]; + let end = data2.iter().position(|&x| x == b'"').unwrap_or(data2.len()); + let field = &data2[..end]; + let mut rest = &data2[data2.len().min(end + 1)..]; + if rest.first() == Some(&b'\"') { + rest = &rest[1..]; + } + while !rest.is_empty() && is_separator(rest[0]) { + rest = &rest[1..]; + } + *data = rest; + field + } else { + let end = data.iter().position(|&x| is_separator(x)).unwrap_or(data.len()); + let field = &data[0..end]; + let rest = &data[data.len().min(end + 1)..]; + *data = rest; + field + } +} + +pub(crate) fn pop_prefix(data: &mut &[u8], prefix: &[u8]) { + assert!(data.len() >= prefix.len()); + assert!(&data[..prefix.len()] == prefix); + *data = &data[prefix.len()..]; +} diff --git a/embassy-net-nrf91/src/lib.rs b/embassy-net-nrf91/src/lib.rs index 70ad176da..beed7c65a 100644 --- a/embassy-net-nrf91/src/lib.rs +++ b/embassy-net-nrf91/src/lib.rs @@ -6,6 +6,8 @@ // must be first mod fmt; +pub mod context; + use core::cell::RefCell; use core::future::poll_fn; use core::marker::PhantomData; diff --git a/examples/nrf9160/src/bin/modem_tcp_client.rs b/examples/nrf9160/src/bin/modem_tcp_client.rs index b1dac18a1..817ad17c7 100644 --- a/examples/nrf9160/src/bin/modem_tcp_client.rs +++ b/examples/nrf9160/src/bin/modem_tcp_client.rs @@ -2,14 +2,15 @@ #![no_main] use core::mem::MaybeUninit; +use core::net::IpAddr; use core::ptr::addr_of_mut; use core::str::FromStr; use core::{slice, str}; -use defmt::{assert, *}; +use defmt::{assert, info, warn, unwrap}; use embassy_executor::Spawner; use embassy_net::{Ipv4Address, Ipv4Cidr, Stack, StackResources}; -use embassy_net_nrf91::{Runner, State}; +use embassy_net_nrf91::{Runner, State, context}; use embassy_nrf::buffered_uarte::{self, BufferedUarteTx}; use embassy_nrf::gpio::{AnyPin, Level, Output, OutputDrive, Pin}; use embassy_nrf::uarte::Baudrate; @@ -63,9 +64,9 @@ async fn blink_task(pin: AnyPin) { let mut led = Output::new(pin, Level::Low, OutputDrive::Standard); loop { led.set_high(); - Timer::after_millis(100).await; + Timer::after_millis(1000).await; led.set_low(); - Timer::after_millis(100).await; + Timer::after_millis(1000).await; } } @@ -123,51 +124,30 @@ async fn main(spawner: Spawner) { unwrap!(spawner.spawn(net_task(stack))); - control.wait_init().await; - info!("INIT OK"); + let control = context::Control::new(control, 0).await; - let mut buf = [0u8; 256]; - - let n = control.at_command(b"AT+CFUN?", &mut buf).await; - info!("AT resp: '{}'", unsafe { str::from_utf8_unchecked(&buf[..n]) }); - - let n = control - .at_command(b"AT+CGDCONT=0,\"IP\",\"iot.nat.es\"", &mut buf) - .await; - info!("AT resp: '{}'", unsafe { str::from_utf8_unchecked(&buf[..n]) }); - let n = control - .at_command(b"AT+CGAUTH=0,1,\"orange\",\"orange\"", &mut buf) - .await; - info!("AT resp: '{}'", unsafe { str::from_utf8_unchecked(&buf[..n]) }); - - let n = control.at_command(b"AT+CFUN=1", &mut buf).await; - info!("AT resp: '{}'", unsafe { str::from_utf8_unchecked(&buf[..n]) }); + unwrap!(control.configure(context::Config { + gateway: "iot.nat.es", + auth_prot: context::AuthProt::Pap, + auth: Some(("orange", "orange")), + }).await); info!("waiting for attach..."); - loop { - Timer::after_millis(500).await; - let n = control.at_command(b"AT+CGATT?", &mut buf).await; - let mut res = &buf[..n]; - pop_prefix(&mut res, b"+CGATT: "); - let res = split_field(&mut res); - info!("AT resp field: '{}'", unsafe { str::from_utf8_unchecked(res) }); - if res == b"1" { - break; - } + + let mut status = unwrap!(control.status().await); + while !status.attached && status.ip.is_none() { + Timer::after_millis(1000).await; + status = unwrap!(control.status().await); + info!("STATUS: {:?}", status); } - let n = control.at_command(b"AT+CGPADDR=0", &mut buf).await; - let mut res = &buf[..n]; - pop_prefix(&mut res, b"+CGPADDR: 0,"); - let ip = split_field(&mut res); - let ip = Ipv4Address::from_str(unsafe { str::from_utf8_unchecked(ip) }).unwrap(); - info!("IP: '{}'", ip); - - info!("============== OPENING SOCKET"); - control.open_raw_socket().await; + let Some(IpAddr::V4(addr)) = status.ip else { + panic!("Unexpected IP address"); + }; + let addr = Ipv4Address(addr.octets()); stack.set_config_v4(embassy_net::ConfigV4::Static(embassy_net::StaticConfigV4 { - address: Ipv4Cidr::new(ip, 32), + address: Ipv4Cidr::new(addr, 32), gateway: None, dns_servers: Default::default(), })); From aabdd45424ae71550be542a3a62872b33a4e0717 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Wed, 4 Sep 2024 11:09:27 +0200 Subject: [PATCH 0068/1217] remove debug logging --- embassy-net-nrf91/src/context.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/embassy-net-nrf91/src/context.rs b/embassy-net-nrf91/src/context.rs index 6dda51793..c47b1ade6 100644 --- a/embassy-net-nrf91/src/context.rs +++ b/embassy-net-nrf91/src/context.rs @@ -121,7 +121,6 @@ impl<'a> Control<'a> { write!(s, "+CGPADDR: {},", self.cid)?; - info!("RES: {:?}", unsafe {core::str::from_utf8_unchecked(res)}); if s.len() > res.len() { let res = split_field(&mut res); if res == b"OK" { From b76b7ca9f5d64e83f7f69a6f7d97ba605ab2af7f Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Wed, 4 Sep 2024 12:58:33 +0200 Subject: [PATCH 0069/1217] Use at-commands crate and support DNS * Use at-commands for building and parsing AT commands which has better error handling. * Retrieve DNS servers * Retrieve gateway * Update example to configure embassy-net with retrieved parameters. --- embassy-net-nrf91/Cargo.toml | 1 + embassy-net-nrf91/src/context.rs | 202 ++++++++++--------- examples/nrf9160/Cargo.toml | 1 + examples/nrf9160/src/bin/modem_tcp_client.rs | 78 ++----- 4 files changed, 126 insertions(+), 156 deletions(-) diff --git a/embassy-net-nrf91/Cargo.toml b/embassy-net-nrf91/Cargo.toml index e2d596d59..07a0c8886 100644 --- a/embassy-net-nrf91/Cargo.toml +++ b/embassy-net-nrf91/Cargo.toml @@ -26,6 +26,7 @@ embassy-net-driver-channel = { version = "0.3.0", path = "../embassy-net-driver- heapless = "0.8" embedded-io = "0.6.1" +at-commands = "0.5.4" [package.metadata.embassy_docs] src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-nrf91-v$VERSION/embassy-net-nrf91/src/" diff --git a/embassy-net-nrf91/src/context.rs b/embassy-net-nrf91/src/context.rs index c47b1ade6..b532dca14 100644 --- a/embassy-net-nrf91/src/context.rs +++ b/embassy-net-nrf91/src/context.rs @@ -2,6 +2,8 @@ use core::net::IpAddr; use heapless::String; use core::str::FromStr; use core::fmt::Write; +use heapless::Vec; +use at_commands::{builder::CommandBuilder, parser::CommandParser}; /// Provides a higher level API for configuring and reading information for a given /// context id. @@ -28,10 +30,17 @@ pub enum AuthProt { pub enum Error { BufferTooSmall, AtCommand, + AtParseError, AddrParseError, Format, } +impl From for Error { + fn from(_: at_commands::parser::ParseError) -> Self { + Self::AtParseError + } +} + impl From for Error { fn from(_: core::fmt::Error) -> Self { Self::Format @@ -42,6 +51,8 @@ impl From for Error { pub struct Status { pub attached: bool, pub ip: Option, + pub gateway: Option, + pub dns: Vec, } #[cfg(feature = "defmt")] @@ -67,129 +78,122 @@ impl<'a> Control<'a> { /// Configures the modem with the provided config. pub async fn configure(&self, config: Config<'_>) -> Result<(), Error> { - let mut cmd: String<128> = String::new(); + let mut cmd: [u8; 256] = [0; 256]; let mut buf: [u8; 256] = [0; 256]; - write!(cmd, "AT+CGDCONT={},\"IP\",\"{}\"", self.cid, config.gateway).map_err(|_| Error::BufferTooSmall)?; - let n = self.control.at_command(cmd.as_bytes(), &mut buf).await; - let mut res = &buf[..n]; - let res = split_field(&mut res); - if res != b"OK" { - return Err(Error::AtCommand) - } - cmd.clear(); + let op = CommandBuilder::create_set(&mut cmd, true) + .named("+CGDCONT") + .with_int_parameter(self.cid) + .with_string_parameter("IP") + .with_string_parameter(config.gateway) + .finish().map_err(|_| Error::BufferTooSmall)?; + let n = self.control.at_command(op, &mut buf).await; + CommandParser::parse(&buf[..n]).expect_identifier(b"OK").finish()?; - write!(cmd, "AT+CGAUTH={},{}", self.cid, config.auth_prot as u8)?; + let mut op = CommandBuilder::create_set(&mut cmd, true) + .named("+CGAUTH") + .with_int_parameter(self.cid) + .with_int_parameter(config.auth_prot as u8); if let Some((username, password)) = config.auth { - write!(cmd, ",\"{}\",\"{}\"", username, password).map_err(|_| Error::BufferTooSmall)?; + op = op.with_string_parameter(username).with_string_parameter(password); } - let n = self.control.at_command(cmd.as_bytes(), &mut buf).await; - let mut res = &buf[..n]; - let res = split_field(&mut res); - if res != b"OK" { - return Err(Error::AtCommand) - } - cmd.clear(); + let op = op.finish().map_err(|_| Error::BufferTooSmall)?; - let n = self.control.at_command(b"AT+CFUN=1", &mut buf).await; - let mut res = &buf[..n]; - let res = split_field(&mut res); - if res != b"OK" { - return Err(Error::AtCommand); - } + let n = self.control.at_command(op, &mut buf).await; + CommandParser::parse(&buf[..n]).expect_identifier(b"OK").finish()?; + + let op = CommandBuilder::create_set(&mut cmd, true) + .named("+CFUN") + .with_int_parameter(1) + .finish().map_err(|_| Error::BufferTooSmall)?; + let n = self.control.at_command(op, &mut buf).await; + CommandParser::parse(&buf[..n]).expect_identifier(b"OK").finish()?; Ok(()) } pub async fn status(&self) -> Result { + let mut cmd: [u8; 256] = [0; 256]; let mut buf: [u8; 256] = [0; 256]; - let n = self.control.at_command(b"AT+CGATT?", &mut buf).await; - let mut res = &buf[..n]; - pop_prefix(&mut res, b"+CGATT: "); - let res = split_field(&mut res); - let attached = res == b"1"; + let op = CommandBuilder::create_query(&mut cmd, true) + .named("+CGATT") + .finish().map_err(|_| Error::BufferTooSmall)?; + let n = self.control.at_command(op, &mut buf).await; + let (res, ) = CommandParser::parse(&buf[..n]) + .expect_identifier(b"+CGATT: ") + .expect_int_parameter() + .expect_identifier(b"\r\nOK").finish()?; + let attached = res == 1; if !attached { - return Ok(Status { attached, ip: None }) + return Ok(Status { attached, ip: None, gateway: None, dns: Vec::new() }) } - let mut s: String<128> = String::new(); - write!(s, "AT+CGPADDR={}", self.cid)?; - let n = self.control.at_command(s.as_bytes(), &mut buf).await; - let mut res = &buf[..n]; - s.clear(); + let op = CommandBuilder::create_set(&mut cmd, true) + .named("+CGPADDR") + .with_int_parameter(self.cid) + .finish().map_err(|_| Error::BufferTooSmall)?; + let n = self.control.at_command(op, &mut buf).await; + let (_, ip1, ip2, ) = CommandParser::parse(&buf[..n]) + .expect_identifier(b"+CGPADDR: ") + .expect_int_parameter() + .expect_optional_string_parameter() + .expect_optional_string_parameter() + .expect_identifier(b"\r\nOK").finish()?; - write!(s, "+CGPADDR: {},", self.cid)?; + let ip = if let Some(ip) = ip1 { + let ip = IpAddr::from_str(ip).map_err(|_| Error::AddrParseError)?; + self.control.open_raw_socket().await; + Some(ip) + } else { + None + }; - if s.len() > res.len() { - let res = split_field(&mut res); - if res == b"OK" { - Ok(Status { attached, ip: None }) + let op = CommandBuilder::create_set(&mut cmd, true) + .named("+CGCONTRDP") + .with_int_parameter(self.cid) + .finish().map_err(|_| Error::BufferTooSmall)?; + let n = self.control.at_command(op, &mut buf).await; + let (_cid, _bid, _apn, _mask, gateway, dns1, dns2, _, _, _, _, mtu) = CommandParser::parse(&buf[..n]) + .expect_identifier(b"+CGCONTRDP: ") + .expect_int_parameter() + .expect_optional_int_parameter() + .expect_optional_string_parameter() + .expect_optional_string_parameter() + .expect_optional_string_parameter() + .expect_optional_string_parameter() + .expect_optional_string_parameter() + .expect_optional_int_parameter() + .expect_optional_int_parameter() + .expect_optional_int_parameter() + .expect_optional_int_parameter() + .expect_optional_int_parameter() + .expect_identifier(b"\r\nOK").finish()?; + + let gateway = if let Some(ip) = gateway { + if ip.is_empty() { + None } else { - Err(Error::AtCommand) + Some(IpAddr::from_str(ip).map_err(|_| Error::AddrParseError)?) } } else { - pop_prefix(&mut res, s.as_bytes()); + None + }; - let ip = split_field(&mut res); - if !ip.is_empty() { - let ip = IpAddr::from_str(unsafe { core::str::from_utf8_unchecked(ip) }).map_err(|_| Error::AddrParseError)?; - self.control.open_raw_socket().await; - Ok(Status { attached, ip: Some(ip) }) - } else { - Ok(Status { attached, ip: None }) - } + let mut dns = Vec::new(); + if let Some(ip) = dns1 { + dns.push(IpAddr::from_str(ip).map_err(|_| Error::AddrParseError)?).unwrap(); } - } -} -pub(crate) fn is_whitespace(char: u8) -> bool { - match char { - b'\r' | b'\n' | b' ' => true, - _ => false, - } -} - -pub(crate) fn is_separator(char: u8) -> bool { - match char { - b',' | b'\r' | b'\n' | b' ' => true, - _ => false, - } -} - -pub(crate) fn split_field<'a>(data: &mut &'a [u8]) -> &'a [u8] { - while !data.is_empty() && is_whitespace(data[0]) { - *data = &data[1..]; - } - - if data.is_empty() { - return &[]; - } - - if data[0] == b'"' { - let data2 = &data[1..]; - let end = data2.iter().position(|&x| x == b'"').unwrap_or(data2.len()); - let field = &data2[..end]; - let mut rest = &data2[data2.len().min(end + 1)..]; - if rest.first() == Some(&b'\"') { - rest = &rest[1..]; + if let Some(ip) = dns2 { + dns.push(IpAddr::from_str(ip).map_err(|_| Error::AddrParseError)?).unwrap(); } - while !rest.is_empty() && is_separator(rest[0]) { - rest = &rest[1..]; - } - *data = rest; - field - } else { - let end = data.iter().position(|&x| is_separator(x)).unwrap_or(data.len()); - let field = &data[0..end]; - let rest = &data[data.len().min(end + 1)..]; - *data = rest; - field + + Ok(Status { + attached, + ip, + gateway, + dns, + }) } } - -pub(crate) fn pop_prefix(data: &mut &[u8], prefix: &[u8]) { - assert!(data.len() >= prefix.len()); - assert!(&data[..prefix.len()] == prefix); - *data = &data[prefix.len()..]; -} diff --git a/examples/nrf9160/Cargo.toml b/examples/nrf9160/Cargo.toml index fc24e99d2..9aeb99317 100644 --- a/examples/nrf9160/Cargo.toml +++ b/examples/nrf9160/Cargo.toml @@ -14,6 +14,7 @@ embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defm defmt = "0.3" defmt-rtt = "0.4" +heapless = "0.8" cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } cortex-m-rt = "0.7.0" panic-probe = { version = "0.3", features = ["print-defmt"] } diff --git a/examples/nrf9160/src/bin/modem_tcp_client.rs b/examples/nrf9160/src/bin/modem_tcp_client.rs index 817ad17c7..f80861693 100644 --- a/examples/nrf9160/src/bin/modem_tcp_client.rs +++ b/examples/nrf9160/src/bin/modem_tcp_client.rs @@ -5,9 +5,10 @@ use core::mem::MaybeUninit; use core::net::IpAddr; use core::ptr::addr_of_mut; use core::str::FromStr; -use core::{slice, str}; +use core::slice; use defmt::{assert, info, warn, unwrap}; +use heapless::Vec; use embassy_executor::Spawner; use embassy_net::{Ipv4Address, Ipv4Cidr, Stack, StackResources}; use embassy_net_nrf91::{Runner, State, context}; @@ -146,10 +147,23 @@ async fn main(spawner: Spawner) { }; let addr = Ipv4Address(addr.octets()); + let gateway = if let Some(IpAddr::V4(addr)) = status.gateway { + Some(Ipv4Address(addr.octets())) + } else { + None + }; + + let mut dns_servers = Vec::new(); + for dns in status.dns { + if let IpAddr::V4(ip) = dns { + unwrap!(dns_servers.push(Ipv4Address(ip.octets()))); + } + } + stack.set_config_v4(embassy_net::ConfigV4::Static(embassy_net::StaticConfigV4 { address: Ipv4Cidr::new(addr, 32), - gateway: None, - dns_servers: Default::default(), + gateway, + dns_servers, })); let mut rx_buffer = [0; 4096]; @@ -159,15 +173,16 @@ async fn main(spawner: Spawner) { socket.set_timeout(Some(Duration::from_secs(10))); info!("Connecting..."); - let host_addr = embassy_net::Ipv4Address::from_str("83.51.182.206").unwrap(); - if let Err(e) = socket.connect((host_addr, 8000)).await { + let host_addr = embassy_net::Ipv4Address::from_str("45.79.112.203").unwrap(); + if let Err(e) = socket.connect((host_addr, 4242)).await { warn!("connect error: {:?}", e); + Timer::after_secs(1).await; continue; } info!("Connected to {:?}", socket.remote_endpoint()); let msg = b"Hello world!\n"; - loop { + for _ in 0..10 { if let Err(e) = socket.write_all(msg).await { warn!("write error: {:?}", e); break; @@ -177,54 +192,3 @@ async fn main(spawner: Spawner) { } } } - -fn is_whitespace(char: u8) -> bool { - match char { - b'\r' | b'\n' | b' ' => true, - _ => false, - } -} - -fn is_separator(char: u8) -> bool { - match char { - b',' | b'\r' | b'\n' | b' ' => true, - _ => false, - } -} - -fn split_field<'a>(data: &mut &'a [u8]) -> &'a [u8] { - while !data.is_empty() && is_whitespace(data[0]) { - *data = &data[1..]; - } - - if data.is_empty() { - return &[]; - } - - if data[0] == b'"' { - let data2 = &data[1..]; - let end = data2.iter().position(|&x| x == b'"').unwrap_or(data2.len()); - let field = &data2[..end]; - let mut rest = &data2[data2.len().min(end + 1)..]; - if rest.first() == Some(&b'\"') { - rest = &rest[1..]; - } - while !rest.is_empty() && is_separator(rest[0]) { - rest = &rest[1..]; - } - *data = rest; - field - } else { - let end = data.iter().position(|&x| is_separator(x)).unwrap_or(data.len()); - let field = &data[0..end]; - let rest = &data[data.len().min(end + 1)..]; - *data = rest; - field - } -} - -fn pop_prefix(data: &mut &[u8], prefix: &[u8]) { - assert!(data.len() >= prefix.len()); - assert!(&data[..prefix.len()] == prefix); - *data = &data[prefix.len()..]; -} From 5e27a3e64f46340e50bc6f61e6ef5a89e9f077ab Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Wed, 4 Sep 2024 13:09:27 +0200 Subject: [PATCH 0070/1217] Document public API and fix warnings --- embassy-net-nrf91/src/context.rs | 48 +++++++++++--------- examples/nrf9160/src/bin/modem_tcp_client.rs | 6 +-- 2 files changed, 30 insertions(+), 24 deletions(-) diff --git a/embassy-net-nrf91/src/context.rs b/embassy-net-nrf91/src/context.rs index b532dca14..9c67cbc9f 100644 --- a/embassy-net-nrf91/src/context.rs +++ b/embassy-net-nrf91/src/context.rs @@ -1,38 +1,46 @@ +//! Helper utility to configure a specific modem context. use core::net::IpAddr; -use heapless::String; use core::str::FromStr; -use core::fmt::Write; use heapless::Vec; use at_commands::{builder::CommandBuilder, parser::CommandParser}; -/// Provides a higher level API for configuring and reading information for a given -/// context id. +/// Provides a higher level API for controlling a given context. pub struct Control<'a> { control: crate::Control<'a>, cid: u8, } +/// Configuration for a given context pub struct Config<'a> { - pub gateway: &'a str, + /// Desired APN address. + pub apn: &'a str, + /// Desired authentication protocol. pub auth_prot: AuthProt, + /// Credentials. pub auth: Option<(&'a str, &'a str)>, } +/// Authentication protocol. #[repr(u8)] pub enum AuthProt { + /// No authentication. None = 0, + /// PAP authentication. Pap = 1, + /// CHAP authentication. Chap = 2, } +/// Error returned by control. #[derive(Clone, Copy, PartialEq, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum Error { + /// Not enough space for command. BufferTooSmall, - AtCommand, + /// Error parsing response from modem. AtParseError, + /// Error parsing IP addresses. AddrParseError, - Format, } impl From for Error { @@ -41,17 +49,16 @@ impl From for Error { } } -impl From for Error { - fn from(_: core::fmt::Error) -> Self { - Self::Format - } -} - +/// Status of a given context. #[derive(PartialEq, Debug)] pub struct Status { + /// Attached to APN or not. pub attached: bool, + /// IP if assigned. pub ip: Option, + /// Gateway if assigned. pub gateway: Option, + /// DNS servers if assigned. pub dns: Vec, } @@ -66,16 +73,14 @@ impl defmt::Format for Status { } impl<'a> Control<'a> { + /// Create a new instance of a control handle for a given context. + /// + /// Will wait for the modem to be initialized if not. pub async fn new(control: crate::Control<'a>, cid: u8) -> Self { control.wait_init().await; Self { control, cid } } - /// Bypass modem configurator - pub async fn at_command(&self, req: &[u8], resp: &mut [u8]) -> usize { - self.control.at_command(req, resp).await - } - /// Configures the modem with the provided config. pub async fn configure(&self, config: Config<'_>) -> Result<(), Error> { let mut cmd: [u8; 256] = [0; 256]; @@ -85,7 +90,7 @@ impl<'a> Control<'a> { .named("+CGDCONT") .with_int_parameter(self.cid) .with_string_parameter("IP") - .with_string_parameter(config.gateway) + .with_string_parameter(config.apn) .finish().map_err(|_| Error::BufferTooSmall)?; let n = self.control.at_command(op, &mut buf).await; CommandParser::parse(&buf[..n]).expect_identifier(b"OK").finish()?; @@ -112,6 +117,7 @@ impl<'a> Control<'a> { Ok(()) } + /// Read current connectivity status for modem. pub async fn status(&self) -> Result { let mut cmd: [u8; 256] = [0; 256]; let mut buf: [u8; 256] = [0; 256]; @@ -134,7 +140,7 @@ impl<'a> Control<'a> { .with_int_parameter(self.cid) .finish().map_err(|_| Error::BufferTooSmall)?; let n = self.control.at_command(op, &mut buf).await; - let (_, ip1, ip2, ) = CommandParser::parse(&buf[..n]) + let (_, ip1, _ip2, ) = CommandParser::parse(&buf[..n]) .expect_identifier(b"+CGPADDR: ") .expect_int_parameter() .expect_optional_string_parameter() @@ -154,7 +160,7 @@ impl<'a> Control<'a> { .with_int_parameter(self.cid) .finish().map_err(|_| Error::BufferTooSmall)?; let n = self.control.at_command(op, &mut buf).await; - let (_cid, _bid, _apn, _mask, gateway, dns1, dns2, _, _, _, _, mtu) = CommandParser::parse(&buf[..n]) + let (_cid, _bid, _apn, _mask, gateway, dns1, dns2, _, _, _, _, _mtu) = CommandParser::parse(&buf[..n]) .expect_identifier(b"+CGCONTRDP: ") .expect_int_parameter() .expect_optional_int_parameter() diff --git a/examples/nrf9160/src/bin/modem_tcp_client.rs b/examples/nrf9160/src/bin/modem_tcp_client.rs index f80861693..55ab2a707 100644 --- a/examples/nrf9160/src/bin/modem_tcp_client.rs +++ b/examples/nrf9160/src/bin/modem_tcp_client.rs @@ -7,7 +7,7 @@ use core::ptr::addr_of_mut; use core::str::FromStr; use core::slice; -use defmt::{assert, info, warn, unwrap}; +use defmt::{info, warn, unwrap}; use heapless::Vec; use embassy_executor::Spawner; use embassy_net::{Ipv4Address, Ipv4Cidr, Stack, StackResources}; @@ -93,7 +93,7 @@ async fn main(spawner: Spawner) { static mut TRACE_BUF: [u8; 4096] = [0u8; 4096]; let mut config = uarte::Config::default(); - config.baudrate = Baudrate::BAUD1M; + config.baudrate = Baudrate::BAUD115200; let trace_writer = TraceWriter(BufferedUarteTx::new( //let trace_uart = BufferedUarteTx::new( unsafe { peripherals::SERIAL0::steal() }, @@ -128,7 +128,7 @@ async fn main(spawner: Spawner) { let control = context::Control::new(control, 0).await; unwrap!(control.configure(context::Config { - gateway: "iot.nat.es", + apn: "iot.nat.es", auth_prot: context::AuthProt::Pap, auth: Some(("orange", "orange")), }).await); From b4221d75b87664485977d37df28f7319143411fc Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Wed, 4 Sep 2024 14:09:17 +0200 Subject: [PATCH 0071/1217] Make tracing optional and use dedicated task --- embassy-net-nrf91/src/lib.rs | 90 +++++++++++++++----- examples/nrf9160/src/bin/modem_tcp_client.rs | 58 ++++++------- 2 files changed, 98 insertions(+), 50 deletions(-) diff --git a/embassy-net-nrf91/src/lib.rs b/embassy-net-nrf91/src/lib.rs index beed7c65a..673784cb2 100644 --- a/embassy-net-nrf91/src/lib.rs +++ b/embassy-net-nrf91/src/lib.rs @@ -19,12 +19,15 @@ use core::task::{Poll, Waker}; use embassy_net_driver_channel as ch; use embassy_sync::waitqueue::{AtomicWaker, WakerRegistration}; +use embassy_sync::blocking_mutex::raw::NoopRawMutex; use heapless::Vec; use nrf9160_pac as pac; use pac::NVIC; +use embassy_sync::pipe; const RX_SIZE: usize = 8 * 1024; const TRACE_SIZE: usize = 16 * 1024; +const TRACE_BUF: usize = 1024; const MTU: usize = 1500; /// Network driver. @@ -91,11 +94,30 @@ impl<'a> Allocator<'a> { } /// Create a new nRF91 embassy-net driver. -pub async fn new<'a, TW: embedded_io::Write>( +pub async fn new<'a>( state: &'a mut State, shmem: &'a mut [MaybeUninit], - trace_writer: TW, -) -> (NetDriver<'a>, Control<'a>, Runner<'a, TW>) { +) -> (NetDriver<'a>, Control<'a>, Runner<'a>) { + let (n, c, r, _) = new_internal(state, shmem, None).await; + (n, c, r) +} + +/// Create a new nRF91 embassy-net driver with trace. +pub async fn new_with_trace<'a>( + state: &'a mut State, + shmem: &'a mut [MaybeUninit], + trace_buffer: &'a mut TraceBuffer, +) -> (NetDriver<'a>, Control<'a>, Runner<'a>, TraceReader<'a>) { + let (n, c, r, t) = new_internal(state, shmem, Some(trace_buffer)).await; + (n, c, r, t.unwrap()) +} + +/// Create a new nRF91 embassy-net driver. +async fn new_internal<'a>( + state: &'a mut State, + shmem: &'a mut [MaybeUninit], + trace_buffer: Option<&'a mut TraceBuffer>, +) -> (NetDriver<'a>, Control<'a>, Runner<'a>, Option>) { let shmem_len = shmem.len(); let shmem_ptr = shmem.as_mut_ptr() as *mut u8; @@ -205,21 +227,49 @@ pub async fn new<'a, TW: embedded_io::Write>( let state_ch = ch_runner.state_runner(); state_ch.set_link_state(ch::driver::LinkState::Up); + let (trace_reader, trace_writer) = if let Some(trace) = trace_buffer { + let (r, w) = trace.trace.split(); + (Some(r), Some(w)) + } else { + (None, None) + }; + let runner = Runner { ch: ch_runner, state: state_inner, trace_writer, }; - (device, control, runner) + (device, control, runner, trace_reader) } -/// Shared state for the drivver. +/// State holding modem traces. +pub struct TraceBuffer { + trace: pipe::Pipe, +} + +/// Represents writer half of the trace buffer. +pub type TraceWriter<'a> = pipe::Writer<'a, NoopRawMutex, TRACE_BUF>; + +/// Represents the reader half of the trace buffer. +pub type TraceReader<'a> = pipe::Reader<'a, NoopRawMutex, TRACE_BUF>; + +impl TraceBuffer { + /// Create a new TraceBuffer. + pub const fn new() -> Self { + Self { + trace: pipe::Pipe::new(), + } + } +} + +/// Shared state for the driver. pub struct State { ch: ch::State, inner: MaybeUninit>, } + impl State { /// Create a new State. pub const fn new() -> Self { @@ -272,7 +322,7 @@ struct StateInner { } impl StateInner { - fn poll(&mut self, trace_writer: &mut impl embedded_io::Write, ch: &mut ch::Runner) { + fn poll(&mut self, trace_writer: &mut Option>, ch: &mut ch::Runner) { trace!("poll!"); let ipc = unsafe { &*pac::IPC_NS::ptr() }; @@ -399,15 +449,17 @@ impl StateInner { }); } - fn handle_trace(writer: &mut impl embedded_io::Write, id: u8, data: &[u8]) { - trace!("trace: {} {}", id, data.len()); - let mut header = [0u8; 5]; - header[0] = 0xEF; - header[1] = 0xBE; - header[2..4].copy_from_slice(&(data.len() as u16).to_le_bytes()); - header[4] = id; - writer.write_all(&header).unwrap(); - writer.write_all(data).unwrap(); + fn handle_trace(writer: &mut Option>, id: u8, data: &[u8]) { + if let Some(writer) = writer { + trace!("trace: {} {}", id, data.len()); + let mut header = [0u8; 5]; + header[0] = 0xEF; + header[1] = 0xBE; + header[2..4].copy_from_slice(&(data.len() as u16).to_le_bytes()); + header[4] = id; + writer.try_write(&header).ok(); + writer.try_write(data).ok(); + } } fn process(&mut self, list: *mut List, is_control: bool, ch: &mut ch::Runner) -> bool { @@ -794,7 +846,7 @@ impl<'a> Control<'a> { /// Open the raw socket used for sending/receiving IP packets. /// /// This must be done after `AT+CFUN=1` (?) - pub async fn open_raw_socket(&self) { + async fn open_raw_socket(&self) { let mut msg: Message = unsafe { mem::zeroed() }; msg.channel = 2; // data msg.id = 0x7001_0004; // open socket @@ -822,13 +874,13 @@ impl<'a> Control<'a> { } /// Background runner for the driver. -pub struct Runner<'a, TW: embedded_io::Write> { +pub struct Runner<'a> { ch: ch::Runner<'a, MTU>, state: &'a RefCell, - trace_writer: TW, + trace_writer: Option>, } -impl<'a, TW: embedded_io::Write> Runner<'a, TW> { +impl<'a> Runner<'a> { /// Run the driver operation in the background. /// /// You must run this in a background task, concurrently with all network operations. diff --git a/examples/nrf9160/src/bin/modem_tcp_client.rs b/examples/nrf9160/src/bin/modem_tcp_client.rs index 55ab2a707..c65e6e153 100644 --- a/examples/nrf9160/src/bin/modem_tcp_client.rs +++ b/examples/nrf9160/src/bin/modem_tcp_client.rs @@ -4,20 +4,20 @@ use core::mem::MaybeUninit; use core::net::IpAddr; use core::ptr::addr_of_mut; -use core::str::FromStr; use core::slice; +use core::str::FromStr; -use defmt::{info, warn, unwrap}; -use heapless::Vec; +use defmt::{info, unwrap, warn}; use embassy_executor::Spawner; use embassy_net::{Ipv4Address, Ipv4Cidr, Stack, StackResources}; -use embassy_net_nrf91::{Runner, State, context}; +use embassy_net_nrf91::{context, Runner, State, TraceBuffer, TraceReader}; use embassy_nrf::buffered_uarte::{self, BufferedUarteTx}; use embassy_nrf::gpio::{AnyPin, Level, Output, OutputDrive, Pin}; use embassy_nrf::uarte::Baudrate; use embassy_nrf::{bind_interrupts, interrupt, peripherals, uarte}; use embassy_time::{Duration, Timer}; use embedded_io_async::Write; +use heapless::Vec; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; @@ -30,28 +30,17 @@ bind_interrupts!(struct Irqs { UARTE0_SPIM0_SPIS0_TWIM0_TWIS0 => buffered_uarte::InterruptHandler; }); -// embassy-net-nrf91 only supports blocking trace write for now. -// We don't want to block packet processing with slow uart writes, so -// we make an adapter that writes whatever fits in the buffer and drops -// data if it's full. -struct TraceWriter(BufferedUarteTx<'static, peripherals::SERIAL0>); - -impl embedded_io::ErrorType for TraceWriter { - type Error = core::convert::Infallible; -} - -impl embedded_io::Write for TraceWriter { - fn write(&mut self, buf: &[u8]) -> Result { - let _ = self.0.try_write(buf); - Ok(buf.len()) - } - fn flush(&mut self) -> Result<(), Self::Error> { - Ok(()) +#[embassy_executor::task] +async fn trace_task(mut uart: BufferedUarteTx<'static, peripherals::SERIAL0>, reader: TraceReader<'static>) -> ! { + let mut rx = [0u8; 1024]; + loop { + let n = reader.read(&mut rx[..]).await; + unwrap!(uart.write_all(&rx[..n]).await); } } #[embassy_executor::task] -async fn modem_task(runner: Runner<'static, TraceWriter>) -> ! { +async fn modem_task(runner: Runner<'static>) -> ! { runner.run().await } @@ -93,8 +82,8 @@ async fn main(spawner: Spawner) { static mut TRACE_BUF: [u8; 4096] = [0u8; 4096]; let mut config = uarte::Config::default(); - config.baudrate = Baudrate::BAUD115200; - let trace_writer = TraceWriter(BufferedUarteTx::new( + config.baudrate = Baudrate::BAUD1M; + let uart = BufferedUarteTx::new( //let trace_uart = BufferedUarteTx::new( unsafe { peripherals::SERIAL0::steal() }, Irqs, @@ -102,11 +91,14 @@ async fn main(spawner: Spawner) { //unsafe { peripherals::P0_14::steal() }, config, unsafe { &mut *addr_of_mut!(TRACE_BUF) }, - )); + ); static STATE: StaticCell = StaticCell::new(); - let (device, control, runner) = embassy_net_nrf91::new(STATE.init(State::new()), ipc_mem, trace_writer).await; + static TRACE: StaticCell = StaticCell::new(); + let (device, control, runner, tracer) = + embassy_net_nrf91::new_with_trace(STATE.init(State::new()), ipc_mem, TRACE.init(TraceBuffer::new())).await; unwrap!(spawner.spawn(modem_task(runner))); + unwrap!(spawner.spawn(trace_task(uart, tracer))); let config = embassy_net::Config::default(); @@ -127,11 +119,15 @@ async fn main(spawner: Spawner) { let control = context::Control::new(control, 0).await; - unwrap!(control.configure(context::Config { - apn: "iot.nat.es", - auth_prot: context::AuthProt::Pap, - auth: Some(("orange", "orange")), - }).await); + unwrap!( + control + .configure(context::Config { + apn: "iot.nat.es", + auth_prot: context::AuthProt::Pap, + auth: Some(("orange", "orange")), + }) + .await + ); info!("waiting for attach..."); From 49881f6fd1e3d77d63dea2313afb5201eca8ebd9 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Wed, 4 Sep 2024 14:21:13 +0200 Subject: [PATCH 0072/1217] rustfmt --- embassy-net-nrf91/src/context.rs | 45 ++++++++++++++++++++++---------- embassy-net-nrf91/src/lib.rs | 10 +++---- 2 files changed, 35 insertions(+), 20 deletions(-) diff --git a/embassy-net-nrf91/src/context.rs b/embassy-net-nrf91/src/context.rs index 9c67cbc9f..954830417 100644 --- a/embassy-net-nrf91/src/context.rs +++ b/embassy-net-nrf91/src/context.rs @@ -1,8 +1,10 @@ //! Helper utility to configure a specific modem context. use core::net::IpAddr; use core::str::FromStr; + +use at_commands::builder::CommandBuilder; +use at_commands::parser::CommandParser; use heapless::Vec; -use at_commands::{builder::CommandBuilder, parser::CommandParser}; /// Provides a higher level API for controlling a given context. pub struct Control<'a> { @@ -91,7 +93,8 @@ impl<'a> Control<'a> { .with_int_parameter(self.cid) .with_string_parameter("IP") .with_string_parameter(config.apn) - .finish().map_err(|_| Error::BufferTooSmall)?; + .finish() + .map_err(|_| Error::BufferTooSmall)?; let n = self.control.at_command(op, &mut buf).await; CommandParser::parse(&buf[..n]).expect_identifier(b"OK").finish()?; @@ -110,7 +113,8 @@ impl<'a> Control<'a> { let op = CommandBuilder::create_set(&mut cmd, true) .named("+CFUN") .with_int_parameter(1) - .finish().map_err(|_| Error::BufferTooSmall)?; + .finish() + .map_err(|_| Error::BufferTooSmall)?; let n = self.control.at_command(op, &mut buf).await; CommandParser::parse(&buf[..n]).expect_identifier(b"OK").finish()?; @@ -124,28 +128,37 @@ impl<'a> Control<'a> { let op = CommandBuilder::create_query(&mut cmd, true) .named("+CGATT") - .finish().map_err(|_| Error::BufferTooSmall)?; + .finish() + .map_err(|_| Error::BufferTooSmall)?; let n = self.control.at_command(op, &mut buf).await; - let (res, ) = CommandParser::parse(&buf[..n]) + let (res,) = CommandParser::parse(&buf[..n]) .expect_identifier(b"+CGATT: ") .expect_int_parameter() - .expect_identifier(b"\r\nOK").finish()?; + .expect_identifier(b"\r\nOK") + .finish()?; let attached = res == 1; if !attached { - return Ok(Status { attached, ip: None, gateway: None, dns: Vec::new() }) + return Ok(Status { + attached, + ip: None, + gateway: None, + dns: Vec::new(), + }); } let op = CommandBuilder::create_set(&mut cmd, true) .named("+CGPADDR") .with_int_parameter(self.cid) - .finish().map_err(|_| Error::BufferTooSmall)?; + .finish() + .map_err(|_| Error::BufferTooSmall)?; let n = self.control.at_command(op, &mut buf).await; - let (_, ip1, _ip2, ) = CommandParser::parse(&buf[..n]) + let (_, ip1, _ip2) = CommandParser::parse(&buf[..n]) .expect_identifier(b"+CGPADDR: ") .expect_int_parameter() .expect_optional_string_parameter() .expect_optional_string_parameter() - .expect_identifier(b"\r\nOK").finish()?; + .expect_identifier(b"\r\nOK") + .finish()?; let ip = if let Some(ip) = ip1 { let ip = IpAddr::from_str(ip).map_err(|_| Error::AddrParseError)?; @@ -158,7 +171,8 @@ impl<'a> Control<'a> { let op = CommandBuilder::create_set(&mut cmd, true) .named("+CGCONTRDP") .with_int_parameter(self.cid) - .finish().map_err(|_| Error::BufferTooSmall)?; + .finish() + .map_err(|_| Error::BufferTooSmall)?; let n = self.control.at_command(op, &mut buf).await; let (_cid, _bid, _apn, _mask, gateway, dns1, dns2, _, _, _, _, _mtu) = CommandParser::parse(&buf[..n]) .expect_identifier(b"+CGCONTRDP: ") @@ -174,7 +188,8 @@ impl<'a> Control<'a> { .expect_optional_int_parameter() .expect_optional_int_parameter() .expect_optional_int_parameter() - .expect_identifier(b"\r\nOK").finish()?; + .expect_identifier(b"\r\nOK") + .finish()?; let gateway = if let Some(ip) = gateway { if ip.is_empty() { @@ -188,11 +203,13 @@ impl<'a> Control<'a> { let mut dns = Vec::new(); if let Some(ip) = dns1 { - dns.push(IpAddr::from_str(ip).map_err(|_| Error::AddrParseError)?).unwrap(); + dns.push(IpAddr::from_str(ip).map_err(|_| Error::AddrParseError)?) + .unwrap(); } if let Some(ip) = dns2 { - dns.push(IpAddr::from_str(ip).map_err(|_| Error::AddrParseError)?).unwrap(); + dns.push(IpAddr::from_str(ip).map_err(|_| Error::AddrParseError)?) + .unwrap(); } Ok(Status { diff --git a/embassy-net-nrf91/src/lib.rs b/embassy-net-nrf91/src/lib.rs index 673784cb2..a60e27d97 100644 --- a/embassy-net-nrf91/src/lib.rs +++ b/embassy-net-nrf91/src/lib.rs @@ -17,13 +17,12 @@ use core::slice; use core::sync::atomic::{compiler_fence, fence, Ordering}; use core::task::{Poll, Waker}; -use embassy_net_driver_channel as ch; -use embassy_sync::waitqueue::{AtomicWaker, WakerRegistration}; use embassy_sync::blocking_mutex::raw::NoopRawMutex; -use heapless::Vec; -use nrf9160_pac as pac; -use pac::NVIC; use embassy_sync::pipe; +use embassy_sync::waitqueue::{AtomicWaker, WakerRegistration}; +use heapless::Vec; +use pac::NVIC; +use {embassy_net_driver_channel as ch, nrf9160_pac as pac}; const RX_SIZE: usize = 8 * 1024; const TRACE_SIZE: usize = 16 * 1024; @@ -269,7 +268,6 @@ pub struct State { inner: MaybeUninit>, } - impl State { /// Create a new State. pub const fn new() -> Self { From 372e45dabc0cfd3eb495e902665bb752a67aa804 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Wed, 4 Sep 2024 18:47:26 +0200 Subject: [PATCH 0073/1217] Add context run task --- embassy-net-nrf91/src/context.rs | 86 +++++++++++++++++- embassy-net-nrf91/src/lib.rs | 5 +- examples/nrf9160/src/bin/modem_tcp_client.rs | 93 +++++++++++--------- 3 files changed, 137 insertions(+), 47 deletions(-) diff --git a/embassy-net-nrf91/src/context.rs b/embassy-net-nrf91/src/context.rs index 954830417..f73719224 100644 --- a/embassy-net-nrf91/src/context.rs +++ b/embassy-net-nrf91/src/context.rs @@ -5,6 +5,7 @@ use core::str::FromStr; use at_commands::builder::CommandBuilder; use at_commands::parser::CommandParser; use heapless::Vec; +use embassy_time::{Timer, Duration}; /// Provides a higher level API for controlling a given context. pub struct Control<'a> { @@ -23,6 +24,8 @@ pub struct Config<'a> { } /// Authentication protocol. +#[derive(Clone, Copy, PartialEq, Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[repr(u8)] pub enum AuthProt { /// No authentication. @@ -84,7 +87,7 @@ impl<'a> Control<'a> { } /// Configures the modem with the provided config. - pub async fn configure(&self, config: Config<'_>) -> Result<(), Error> { + pub async fn configure(&self, config: &Config<'_>) -> Result<(), Error> { let mut cmd: [u8; 256] = [0; 256]; let mut buf: [u8; 256] = [0; 256]; @@ -118,9 +121,64 @@ impl<'a> Control<'a> { let n = self.control.at_command(op, &mut buf).await; CommandParser::parse(&buf[..n]).expect_identifier(b"OK").finish()?; + let op = CommandBuilder::create_set(&mut cmd, true) + .named("%XPDNCFG") + .with_int_parameter(1) + .finish() + .map_err(|_| Error::BufferTooSmall)?; + let n = self.control.at_command(op, &mut buf).await; + CommandParser::parse(&buf[..n]).expect_identifier(b"OK").finish()?; + + + Ok(()) } + /// Attach to the PDN + pub async fn attach(&self) -> Result<(), Error> { + let mut cmd: [u8; 256] = [0; 256]; + let mut buf: [u8; 256] = [0; 256]; + let op = CommandBuilder::create_set(&mut cmd, true) + .named("+CGATT") + .with_int_parameter(1) + .finish() + .map_err(|_| Error::BufferTooSmall)?; + let n = self.control.at_command(op, &mut buf).await; + CommandParser::parse(&buf[..n]).expect_identifier(b"OK").finish()?; + Ok(()) + } + + /// Read current connectivity status for modem. + pub async fn detach(&self) -> Result<(), Error> { + let mut cmd: [u8; 256] = [0; 256]; + let mut buf: [u8; 256] = [0; 256]; + let op = CommandBuilder::create_set(&mut cmd, true) + .named("+CGATT") + .with_int_parameter(0) + .finish() + .map_err(|_| Error::BufferTooSmall)?; + let n = self.control.at_command(op, &mut buf).await; + CommandParser::parse(&buf[..n]).expect_identifier(b"OK").finish()?; + Ok(()) + } + + async fn attached(&self) -> Result { + let mut cmd: [u8; 256] = [0; 256]; + let mut buf: [u8; 256] = [0; 256]; + + let op = CommandBuilder::create_query(&mut cmd, true) + .named("+CGATT") + .finish() + .map_err(|_| Error::BufferTooSmall)?; + let n = self.control.at_command(op, &mut buf).await; + let (res,) = CommandParser::parse(&buf[..n]) + .expect_identifier(b"+CGATT: ") + .expect_int_parameter() + .expect_identifier(b"\r\nOK") + .finish()?; + Ok(res == 1) + } + /// Read current connectivity status for modem. pub async fn status(&self) -> Result { let mut cmd: [u8; 256] = [0; 256]; @@ -162,7 +220,6 @@ impl<'a> Control<'a> { let ip = if let Some(ip) = ip1 { let ip = IpAddr::from_str(ip).map_err(|_| Error::AddrParseError)?; - self.control.open_raw_socket().await; Some(ip) } else { None @@ -219,4 +276,29 @@ impl<'a> Control<'a> { dns, }) } + + /// Run a control loop for this context, ensuring that reaattach is handled. + pub async fn run(&self, config: &Config<'_>, reattach: F) -> Result<(), Error> { + self.configure(config).await?; + while !self.attached().await? { + Timer::after(Duration::from_secs(1)).await; + } + let status = self.status().await?; + let mut fd = self.control.open_raw_socket().await; + reattach(&status); + + loop { + if !self.attached().await? { + // TODO: self.control.close_raw_socket(fd).await; + self.attach().await?; + while !self.attached().await? { + Timer::after(Duration::from_secs(1)).await; + } + let status = self.status().await?; + // TODO: let mut fd = self.control.open_raw_socket().await; + reattach(&status); + } + Timer::after(Duration::from_secs(10)).await; + } + } } diff --git a/embassy-net-nrf91/src/lib.rs b/embassy-net-nrf91/src/lib.rs index a60e27d97..ab3c6f327 100644 --- a/embassy-net-nrf91/src/lib.rs +++ b/embassy-net-nrf91/src/lib.rs @@ -844,7 +844,7 @@ impl<'a> Control<'a> { /// Open the raw socket used for sending/receiving IP packets. /// /// This must be done after `AT+CFUN=1` (?) - async fn open_raw_socket(&self) { + async fn open_raw_socket(&self) -> u32 { let mut msg: Message = unsafe { mem::zeroed() }; msg.channel = 2; // data msg.id = 0x7001_0004; // open socket @@ -867,7 +867,8 @@ impl<'a> Control<'a> { assert_eq!(status, 0); assert_eq!(msg.param_len, 16); let fd = u32::from_le_bytes(msg.param[12..16].try_into().unwrap()); - debug!("got FD: {}", fd); + trace!("got FD: {}", fd); + fd } } diff --git a/examples/nrf9160/src/bin/modem_tcp_client.rs b/examples/nrf9160/src/bin/modem_tcp_client.rs index c65e6e153..a6f42eb3b 100644 --- a/examples/nrf9160/src/bin/modem_tcp_client.rs +++ b/examples/nrf9160/src/bin/modem_tcp_client.rs @@ -49,6 +49,43 @@ async fn net_task(stack: &'static Stack>) stack.run().await } +#[embassy_executor::task] +async fn control_task( + control: &'static context::Control<'static>, + config: context::Config<'static>, + stack: &'static Stack>, +) { + unwrap!( + control + .run(&config, |status| { + let Some(IpAddr::V4(addr)) = status.ip else { + panic!("Unexpected IP address"); + }; + let addr = Ipv4Address(addr.octets()); + + let gateway = if let Some(IpAddr::V4(addr)) = status.gateway { + Some(Ipv4Address(addr.octets())) + } else { + None + }; + + let mut dns_servers = Vec::new(); + for dns in status.dns.iter() { + if let IpAddr::V4(ip) = dns { + unwrap!(dns_servers.push(Ipv4Address(ip.octets()))); + } + } + + stack.set_config_v4(embassy_net::ConfigV4::Static(embassy_net::StaticConfigV4 { + address: Ipv4Cidr::new(addr, 32), + gateway, + dns_servers, + })); + }) + .await + ); +} + #[embassy_executor::task] async fn blink_task(pin: AnyPin) { let mut led = Output::new(pin, Level::Low, OutputDrive::Standard); @@ -117,50 +154,20 @@ async fn main(spawner: Spawner) { unwrap!(spawner.spawn(net_task(stack))); - let control = context::Control::new(control, 0).await; + static CONTROL: StaticCell> = StaticCell::new(); + let control = CONTROL.init(context::Control::new(control, 0).await); - unwrap!( - control - .configure(context::Config { - apn: "iot.nat.es", - auth_prot: context::AuthProt::Pap, - auth: Some(("orange", "orange")), - }) - .await - ); + unwrap!(spawner.spawn(control_task( + control, + context::Config { + apn: "iot.nat.es", + auth_prot: context::AuthProt::Pap, + auth: Some(("orange", "orange")), + }, + stack + ))); - info!("waiting for attach..."); - - let mut status = unwrap!(control.status().await); - while !status.attached && status.ip.is_none() { - Timer::after_millis(1000).await; - status = unwrap!(control.status().await); - info!("STATUS: {:?}", status); - } - - let Some(IpAddr::V4(addr)) = status.ip else { - panic!("Unexpected IP address"); - }; - let addr = Ipv4Address(addr.octets()); - - let gateway = if let Some(IpAddr::V4(addr)) = status.gateway { - Some(Ipv4Address(addr.octets())) - } else { - None - }; - - let mut dns_servers = Vec::new(); - for dns in status.dns { - if let IpAddr::V4(ip) = dns { - unwrap!(dns_servers.push(Ipv4Address(ip.octets()))); - } - } - - stack.set_config_v4(embassy_net::ConfigV4::Static(embassy_net::StaticConfigV4 { - address: Ipv4Cidr::new(addr, 32), - gateway, - dns_servers, - })); + stack.wait_config_up().await; let mut rx_buffer = [0; 4096]; let mut tx_buffer = [0; 4096]; @@ -172,7 +179,7 @@ async fn main(spawner: Spawner) { let host_addr = embassy_net::Ipv4Address::from_str("45.79.112.203").unwrap(); if let Err(e) = socket.connect((host_addr, 4242)).await { warn!("connect error: {:?}", e); - Timer::after_secs(1).await; + Timer::after_secs(10).await; continue; } info!("Connected to {:?}", socket.remote_endpoint()); From aa3c7b900e5dfba440f86743cdf37c4e14ad60f0 Mon Sep 17 00:00:00 2001 From: Kezi Date: Wed, 4 Sep 2024 18:36:40 +0200 Subject: [PATCH 0074/1217] support custom style for usb logger --- embassy-usb-logger/src/lib.rs | 53 +++++++++++++++++++++++++++++++++-- 1 file changed, 50 insertions(+), 3 deletions(-) diff --git a/embassy-usb-logger/src/lib.rs b/embassy-usb-logger/src/lib.rs index 34d1ca663..11188b4ef 100644 --- a/embassy-usb-logger/src/lib.rs +++ b/embassy-usb-logger/src/lib.rs @@ -41,12 +41,24 @@ pub const MAX_PACKET_SIZE: u8 = 64; /// The logger handle, which contains a pipe with configurable size for buffering log messages. pub struct UsbLogger { buffer: Pipe, + custom_style: Option) -> ()>, } impl UsbLogger { /// Create a new logger instance. pub const fn new() -> Self { - Self { buffer: Pipe::new() } + Self { + buffer: Pipe::new(), + custom_style: None, + } + } + + /// Create a new logger instance with a custom formatter. + pub const fn with_custom_style(custom_style: fn(&Record, &mut Writer<'_, N>) -> ()) -> Self { + Self { + buffer: Pipe::new(), + custom_style: Some(custom_style), + } } /// Run the USB logger using the state and USB driver. Never returns. @@ -137,14 +149,19 @@ impl log::Log for UsbLogger { fn log(&self, record: &Record) { if self.enabled(record.metadata()) { - let _ = write!(Writer(&self.buffer), "{}\r\n", record.args()); + if let Some(custom_style) = self.custom_style { + custom_style(record, &mut Writer(&self.buffer)); + } else { + let _ = write!(Writer(&self.buffer), "{}\r\n", record.args()); + } } } fn flush(&self) {} } -struct Writer<'d, const N: usize>(&'d Pipe); +/// A writer that writes to the USB logger buffer. +pub struct Writer<'d, const N: usize>(&'d Pipe); impl<'d, const N: usize> core::fmt::Write for Writer<'d, N> { fn write_str(&mut self, s: &str) -> Result<(), core::fmt::Error> { @@ -210,3 +227,33 @@ macro_rules! with_class { LOGGER.create_future_from_class($p) }}; } + +/// Initialize the USB serial logger from a serial class and return the future to run it. +/// This version of the macro allows for a custom style function to be passed in. +/// The custom style function will be called for each log record and is responsible for writing the log message to the buffer. +/// +/// Arguments specify the buffer size, log level, the serial class and the custom style function, respectively. +/// +/// # Usage +/// +/// ``` +/// let log_fut = embassy_usb_logger::with_custom_style!(1024, log::LevelFilter::Info, logger_class, |record, writer| { +/// use core::fmt::Write; +/// let level = record.level().as_str(); +/// write!(writer, "[{level}] {}\r\n", record.args()).unwrap(); +/// }); +/// ``` +/// +/// # Safety +/// +/// This macro should only be invoked only once since it is setting the global logging state of the application. +#[macro_export] +macro_rules! with_custom_style { + ( $x:expr, $l:expr, $p:ident, $s:expr ) => {{ + static LOGGER: ::embassy_usb_logger::UsbLogger<$x> = ::embassy_usb_logger::UsbLogger::with_custom_style($s); + unsafe { + let _ = ::log::set_logger_racy(&LOGGER).map(|()| log::set_max_level_racy($l)); + } + LOGGER.create_future_from_class($p) + }}; +} From ccfa6264b0ad258625f2dd667ba8e6eaca1cfdc3 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Wed, 4 Sep 2024 19:31:55 +0200 Subject: [PATCH 0075/1217] Add closing if raw socket to handle re-attach --- embassy-net-nrf91/src/context.rs | 8 +++----- embassy-net-nrf91/src/lib.rs | 15 +++++++++++++++ examples/nrf9160/src/bin/modem_tcp_client.rs | 2 ++ 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/embassy-net-nrf91/src/context.rs b/embassy-net-nrf91/src/context.rs index f73719224..511468316 100644 --- a/embassy-net-nrf91/src/context.rs +++ b/embassy-net-nrf91/src/context.rs @@ -4,8 +4,8 @@ use core::str::FromStr; use at_commands::builder::CommandBuilder; use at_commands::parser::CommandParser; +use embassy_time::{Duration, Timer}; use heapless::Vec; -use embassy_time::{Timer, Duration}; /// Provides a higher level API for controlling a given context. pub struct Control<'a> { @@ -129,8 +129,6 @@ impl<'a> Control<'a> { let n = self.control.at_command(op, &mut buf).await; CommandParser::parse(&buf[..n]).expect_identifier(b"OK").finish()?; - - Ok(()) } @@ -289,13 +287,13 @@ impl<'a> Control<'a> { loop { if !self.attached().await? { - // TODO: self.control.close_raw_socket(fd).await; + self.control.close_raw_socket(fd).await; self.attach().await?; while !self.attached().await? { Timer::after(Duration::from_secs(1)).await; } let status = self.status().await?; - // TODO: let mut fd = self.control.open_raw_socket().await; + fd = self.control.open_raw_socket().await; reattach(&status); } Timer::after(Duration::from_secs(10)).await; diff --git a/embassy-net-nrf91/src/lib.rs b/embassy-net-nrf91/src/lib.rs index ab3c6f327..d8cbe47fc 100644 --- a/embassy-net-nrf91/src/lib.rs +++ b/embassy-net-nrf91/src/lib.rs @@ -870,6 +870,21 @@ impl<'a> Control<'a> { trace!("got FD: {}", fd); fd } + + async fn close_raw_socket(&self, fd: u32) { + let mut msg: Message = unsafe { mem::zeroed() }; + msg.channel = 2; // data + msg.id = 0x7009_0004; // close socket + msg.param_len = 8; + msg.param[4..8].copy_from_slice(&fd.to_le_bytes()); + + self.request(&mut msg, &[], &mut []).await; + + assert_eq!(msg.id, 0x80090004); + assert!(msg.param_len >= 12); + let status = u32::from_le_bytes(msg.param[8..12].try_into().unwrap()); + assert_eq!(status, 0); + } } /// Background runner for the driver. diff --git a/examples/nrf9160/src/bin/modem_tcp_client.rs b/examples/nrf9160/src/bin/modem_tcp_client.rs index a6f42eb3b..fb14b746f 100644 --- a/examples/nrf9160/src/bin/modem_tcp_client.rs +++ b/examples/nrf9160/src/bin/modem_tcp_client.rs @@ -193,5 +193,7 @@ async fn main(spawner: Spawner) { info!("txd: {}", core::str::from_utf8(msg).unwrap()); Timer::after_secs(1).await; } + // Test auto-attach + unwrap!(control.detach().await); } } From e75903138a92e6c749454cee516c812df618bbfa Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Wed, 4 Sep 2024 13:42:03 -0400 Subject: [PATCH 0076/1217] Fix commented out code --- embassy-rp/src/flash.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-rp/src/flash.rs b/embassy-rp/src/flash.rs index dab99b4e2..fbc8b35ec 100644 --- a/embassy-rp/src/flash.rs +++ b/embassy-rp/src/flash.rs @@ -627,7 +627,7 @@ mod ram_helpers { #[link_section = ".data.ram_func"] #[cfg(feature = "rp2040")] unsafe fn write_flash_inner(addr: u32, len: u32, data: Option<&[u8]>, ptrs: *const FlashFunctionPointers) { - //#[cfg(target_arch = "arm")] + #[cfg(target_arch = "arm")] core::arch::asm!( "mov r8, r0", "mov r9, r2", From df4ed5c91ded2e7292e72d7e38dc6c6e0958fece Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Wed, 4 Sep 2024 21:09:37 +0200 Subject: [PATCH 0077/1217] stm32/tests: disable flaky stm32wl55jc/usart_rx_ringbuffered --- ci.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/ci.sh b/ci.sh index 70fe4f5d8..8fef731a4 100755 --- a/ci.sh +++ b/ci.sh @@ -305,6 +305,7 @@ rm out/tests/stm32u5a5zj/usart # flaky, probably due to bad ringbuffered dma code. rm out/tests/stm32l152re/usart_rx_ringbuffered rm out/tests/stm32f207zg/usart_rx_ringbuffered +rm out/tests/stm32wl55jc/usart_rx_ringbuffered if [[ -z "${TELEPROBE_TOKEN-}" ]]; then echo No teleprobe token found, skipping running HIL tests From 836e8add1bcb09c476a3aa3d7a416a15b8c21e6a Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Thu, 5 Sep 2024 10:02:45 +0200 Subject: [PATCH 0078/1217] Mintor fixes after testing re-attach --- embassy-net-nrf91/src/context.rs | 20 +++++--- examples/nrf9160/src/bin/modem_tcp_client.rs | 54 +++++++++++--------- 2 files changed, 41 insertions(+), 33 deletions(-) diff --git a/embassy-net-nrf91/src/context.rs b/embassy-net-nrf91/src/context.rs index 511468316..6b841aa16 100644 --- a/embassy-net-nrf91/src/context.rs +++ b/embassy-net-nrf91/src/context.rs @@ -275,24 +275,28 @@ impl<'a> Control<'a> { }) } - /// Run a control loop for this context, ensuring that reaattach is handled. - pub async fn run(&self, config: &Config<'_>, reattach: F) -> Result<(), Error> { - self.configure(config).await?; + async fn wait_attached(&self) -> Result { while !self.attached().await? { Timer::after(Duration::from_secs(1)).await; } let status = self.status().await?; + Ok(status) + } + + /// Run a control loop for this context, ensuring that reaattach is handled. + pub async fn run(&self, config: &Config<'_>, reattach: F) -> Result<(), Error> { + self.configure(config).await?; + let status = self.wait_attached().await?; let mut fd = self.control.open_raw_socket().await; reattach(&status); loop { if !self.attached().await? { + trace!("detached"); + self.control.close_raw_socket(fd).await; - self.attach().await?; - while !self.attached().await? { - Timer::after(Duration::from_secs(1)).await; - } - let status = self.status().await?; + let status = self.wait_attached().await?; + trace!("attached"); fd = self.control.open_raw_socket().await; reattach(&status); } diff --git a/examples/nrf9160/src/bin/modem_tcp_client.rs b/examples/nrf9160/src/bin/modem_tcp_client.rs index fb14b746f..b7d56802d 100644 --- a/examples/nrf9160/src/bin/modem_tcp_client.rs +++ b/examples/nrf9160/src/bin/modem_tcp_client.rs @@ -10,6 +10,7 @@ use core::str::FromStr; use defmt::{info, unwrap, warn}; use embassy_executor::Spawner; use embassy_net::{Ipv4Address, Ipv4Cidr, Stack, StackResources}; +use embassy_net_nrf91::context::Status; use embassy_net_nrf91::{context, Runner, State, TraceBuffer, TraceReader}; use embassy_nrf::buffered_uarte::{self, BufferedUarteTx}; use embassy_nrf::gpio::{AnyPin, Level, Output, OutputDrive, Pin}; @@ -58,34 +59,38 @@ async fn control_task( unwrap!( control .run(&config, |status| { - let Some(IpAddr::V4(addr)) = status.ip else { - panic!("Unexpected IP address"); - }; - let addr = Ipv4Address(addr.octets()); - - let gateway = if let Some(IpAddr::V4(addr)) = status.gateway { - Some(Ipv4Address(addr.octets())) - } else { - None - }; - - let mut dns_servers = Vec::new(); - for dns in status.dns.iter() { - if let IpAddr::V4(ip) = dns { - unwrap!(dns_servers.push(Ipv4Address(ip.octets()))); - } - } - - stack.set_config_v4(embassy_net::ConfigV4::Static(embassy_net::StaticConfigV4 { - address: Ipv4Cidr::new(addr, 32), - gateway, - dns_servers, - })); + stack.set_config_v4(status_to_config(status)); }) .await ); } +fn status_to_config(status: &Status) -> embassy_net::ConfigV4 { + let Some(IpAddr::V4(addr)) = status.ip else { + panic!("Unexpected IP address"); + }; + let addr = Ipv4Address(addr.octets()); + + let gateway = if let Some(IpAddr::V4(addr)) = status.gateway { + Some(Ipv4Address(addr.octets())) + } else { + None + }; + + let mut dns_servers = Vec::new(); + for dns in status.dns.iter() { + if let IpAddr::V4(ip) = dns { + unwrap!(dns_servers.push(Ipv4Address(ip.octets()))); + } + } + + embassy_net::ConfigV4::Static(embassy_net::StaticConfigV4 { + address: Ipv4Cidr::new(addr, 32), + gateway, + dns_servers, + }) +} + #[embassy_executor::task] async fn blink_task(pin: AnyPin) { let mut led = Output::new(pin, Level::Low, OutputDrive::Standard); @@ -193,7 +198,6 @@ async fn main(spawner: Spawner) { info!("txd: {}", core::str::from_utf8(msg).unwrap()); Timer::after_secs(1).await; } - // Test auto-attach - unwrap!(control.detach().await); + Timer::after_secs(4).await; } } From 5d0ed246400b1e7973c1fe870dba977ab7186a21 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Thu, 5 Sep 2024 10:31:51 +0200 Subject: [PATCH 0079/1217] Move configure out of run --- embassy-net-nrf91/src/context.rs | 3 +-- examples/nrf9160/src/bin/modem_tcp_client.rs | 3 ++- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/embassy-net-nrf91/src/context.rs b/embassy-net-nrf91/src/context.rs index 6b841aa16..3671fdd68 100644 --- a/embassy-net-nrf91/src/context.rs +++ b/embassy-net-nrf91/src/context.rs @@ -284,8 +284,7 @@ impl<'a> Control<'a> { } /// Run a control loop for this context, ensuring that reaattach is handled. - pub async fn run(&self, config: &Config<'_>, reattach: F) -> Result<(), Error> { - self.configure(config).await?; + pub async fn run(&self, reattach: F) -> Result<(), Error> { let status = self.wait_attached().await?; let mut fd = self.control.open_raw_socket().await; reattach(&status); diff --git a/examples/nrf9160/src/bin/modem_tcp_client.rs b/examples/nrf9160/src/bin/modem_tcp_client.rs index b7d56802d..7d78eba0a 100644 --- a/examples/nrf9160/src/bin/modem_tcp_client.rs +++ b/examples/nrf9160/src/bin/modem_tcp_client.rs @@ -56,9 +56,10 @@ async fn control_task( config: context::Config<'static>, stack: &'static Stack>, ) { + unwrap!(control.configure(&config).await); unwrap!( control - .run(&config, |status| { + .run(|status| { stack.set_config_v4(status_to_config(status)); }) .await From d71fd447cc4778be8abfdaf510be3a75dac23bf8 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Thu, 5 Sep 2024 11:25:19 +0200 Subject: [PATCH 0080/1217] Add method for buypassing and running at command directly --- embassy-net-nrf91/src/context.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/embassy-net-nrf91/src/context.rs b/embassy-net-nrf91/src/context.rs index 3671fdd68..b936e5f87 100644 --- a/embassy-net-nrf91/src/context.rs +++ b/embassy-net-nrf91/src/context.rs @@ -86,6 +86,11 @@ impl<'a> Control<'a> { Self { control, cid } } + /// Perform a raw AT command + pub async fn at_command(&self, req: &[u8], resp: &mut [u8]) -> usize { + self.control.at_command(req, resp).await + } + /// Configures the modem with the provided config. pub async fn configure(&self, config: &Config<'_>) -> Result<(), Error> { let mut cmd: [u8; 256] = [0; 256]; From db00f3f5ecbf7f9a8acb340556b8fc6b156736fa Mon Sep 17 00:00:00 2001 From: Samuel Maier Date: Thu, 5 Sep 2024 11:45:49 +0200 Subject: [PATCH 0081/1217] Enable critical-section/std on wasm Without that feature one will find import errors on opening the webpage, that are hard to debug. The feature was indirectly enabled in the wasm example, however the reason wasn't documented and thus it was easy to miss. --- embassy-executor/Cargo.toml | 2 +- examples/wasm/Cargo.toml | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/embassy-executor/Cargo.toml b/embassy-executor/Cargo.toml index 5984cc49c..01fa28b88 100644 --- a/embassy-executor/Cargo.toml +++ b/embassy-executor/Cargo.toml @@ -79,7 +79,7 @@ arch-cortex-m = ["_arch", "dep:cortex-m"] ## RISC-V 32 arch-riscv32 = ["_arch"] ## WASM -arch-wasm = ["_arch", "dep:wasm-bindgen", "dep:js-sys"] +arch-wasm = ["_arch", "dep:wasm-bindgen", "dep:js-sys", "critical-section/std"] ## AVR arch-avr = ["_arch", "dep:portable-atomic", "dep:avr-device"] diff --git a/examples/wasm/Cargo.toml b/examples/wasm/Cargo.toml index 9bd37550c..75de079b7 100644 --- a/examples/wasm/Cargo.toml +++ b/examples/wasm/Cargo.toml @@ -16,7 +16,6 @@ wasm-logger = "0.2.0" wasm-bindgen = "0.2" web-sys = { version = "0.3", features = ["Document", "Element", "HtmlElement", "Node", "Window" ] } log = "0.4.11" -critical-section = { version = "1.1", features = ["std"] } [profile.release] debug = 2 From ccf68d73910a68dc9e33beb666b20aba7430e015 Mon Sep 17 00:00:00 2001 From: elagil Date: Thu, 5 Sep 2024 21:29:04 +0200 Subject: [PATCH 0082/1217] feat(usb): add support for ISO endpoints --- embassy-stm32/src/usb/usb.rs | 211 ++++++++++++++++++++++++++++++----- 1 file changed, 186 insertions(+), 25 deletions(-) diff --git a/embassy-stm32/src/usb/usb.rs b/embassy-stm32/src/usb/usb.rs index 9384c8688..0ab2306c8 100644 --- a/embassy-stm32/src/usb/usb.rs +++ b/embassy-stm32/src/usb/usb.rs @@ -80,6 +80,8 @@ impl interrupt::typelevel::Handler for InterruptHandl if istr.ctr() { let index = istr.ep_id() as usize; + CTR_TRIGGERED[index].store(true, Ordering::Relaxed); + let mut epr = regs.epr(index).read(); if epr.ctr_rx() { if index == 0 && epr.setup() { @@ -120,6 +122,10 @@ const USBRAM_ALIGN: usize = 4; const NEW_AW: AtomicWaker = AtomicWaker::new(); static BUS_WAKER: AtomicWaker = NEW_AW; static EP0_SETUP: AtomicBool = AtomicBool::new(false); + +const NEW_CTR_TRIGGERED: AtomicBool = AtomicBool::new(false); +static CTR_TRIGGERED: [AtomicBool; EP_COUNT] = [NEW_CTR_TRIGGERED; EP_COUNT]; + static EP_IN_WAKERS: [AtomicWaker; EP_COUNT] = [NEW_AW; EP_COUNT]; static EP_OUT_WAKERS: [AtomicWaker; EP_COUNT] = [NEW_AW; EP_COUNT]; static IRQ_RESET: AtomicBool = AtomicBool::new(false); @@ -163,20 +169,37 @@ fn calc_out_len(len: u16) -> (u16, u16) { mod btable { use super::*; - pub(super) fn write_in(index: usize, addr: u16) { + pub(super) fn write_in_tx(index: usize, addr: u16) { USBRAM.mem(index * 4 + 0).write_value(addr); } - pub(super) fn write_in_len(index: usize, _addr: u16, len: u16) { + pub(super) fn write_in_rx(index: usize, addr: u16) { + USBRAM.mem(index * 4 + 2).write_value(addr); + } + + pub(super) fn write_in_len_rx(index: usize, _addr: u16, len: u16) { + USBRAM.mem(index * 4 + 3).write_value(len); + } + + pub(super) fn write_in_len_tx(index: usize, _addr: u16, len: u16) { USBRAM.mem(index * 4 + 1).write_value(len); } - pub(super) fn write_out(index: usize, addr: u16, max_len_bits: u16) { + pub(super) fn write_out_rx(index: usize, addr: u16, max_len_bits: u16) { USBRAM.mem(index * 4 + 2).write_value(addr); USBRAM.mem(index * 4 + 3).write_value(max_len_bits); } - pub(super) fn read_out_len(index: usize) -> u16 { + pub(super) fn write_out_tx(index: usize, addr: u16, max_len_bits: u16) { + USBRAM.mem(index * 4 + 0).write_value(addr); + USBRAM.mem(index * 4 + 1).write_value(max_len_bits); + } + + pub(super) fn read_out_len_tx(index: usize) -> u16 { + USBRAM.mem(index * 4 + 1).read() + } + + pub(super) fn read_out_len_rx(index: usize) -> u16 { USBRAM.mem(index * 4 + 3).read() } } @@ -184,19 +207,37 @@ mod btable { mod btable { use super::*; - pub(super) fn write_in(_index: usize, _addr: u16) {} + pub(super) fn write_in_tx(_index: usize, _addr: u16) {} - pub(super) fn write_in_len(index: usize, addr: u16, len: u16) { + pub(super) fn write_in_rx(_index: usize, _addr: u16) {} + + pub(super) fn write_in_len_tx(index: usize, addr: u16, len: u16) { USBRAM.mem(index * 2).write_value((addr as u32) | ((len as u32) << 16)); } - pub(super) fn write_out(index: usize, addr: u16, max_len_bits: u16) { + pub(super) fn write_in_len_rx(index: usize, addr: u16, len: u16) { + USBRAM + .mem(index * 2 + 1) + .write_value((addr as u32) | ((len as u32) << 16)); + } + + pub(super) fn write_out_tx(index: usize, addr: u16, max_len_bits: u16) { + USBRAM + .mem(index * 2) + .write_value((addr as u32) | ((max_len_bits as u32) << 16)); + } + + pub(super) fn write_out_rx(index: usize, addr: u16, max_len_bits: u16) { USBRAM .mem(index * 2 + 1) .write_value((addr as u32) | ((max_len_bits as u32) << 16)); } - pub(super) fn read_out_len(index: usize) -> u16 { + pub(super) fn read_out_len_tx(index: usize) -> u16 { + (USBRAM.mem(index * 2).read() >> 16) as u16 + } + + pub(super) fn read_out_len_rx(index: usize) -> u16 { (USBRAM.mem(index * 2 + 1).read() >> 16) as u16 } } @@ -327,6 +368,13 @@ impl<'d, T: Instance> Driver<'d, T> { return false; // reserved for control pipe } let used = ep.used_out || ep.used_in; + if used && (ep.ep_type == EndpointType::Isochronous || ep.ep_type == EndpointType::Bulk) { + // Isochronous and bulk endpoints are double-buffered. + // Their corresponding endpoint/channel registers are forced to be unidirectional. + // Do not reuse this index. + return false; + } + let used_dir = match D::dir() { Direction::Out => ep.used_out, Direction::In => ep.used_in, @@ -350,7 +398,11 @@ impl<'d, T: Instance> Driver<'d, T> { let addr = self.alloc_ep_mem(len); trace!(" len_bits = {:04x}", len_bits); - btable::write_out::(index, addr, len_bits); + btable::write_out_rx::(index, addr, len_bits); + + if ep_type == EndpointType::Isochronous { + btable::write_out_tx::(index, addr, len_bits); + } EndpointBuffer { addr, @@ -366,7 +418,11 @@ impl<'d, T: Instance> Driver<'d, T> { let addr = self.alloc_ep_mem(len); // ep_in_len is written when actually TXing packets. - btable::write_in::(index, addr); + btable::write_in_tx::(index, addr); + + if ep_type == EndpointType::Isochronous { + btable::write_in_rx::(index, addr); + } EndpointBuffer { addr, @@ -656,6 +712,18 @@ impl Dir for Out { } } +/// Selects the packet buffer. +/// +/// For double-buffered endpoints, both the `Rx` and `Tx` buffer from a channel are used for the same +/// direction of transfer. This is opposed to single-buffered endpoints, where one channel can serve +/// two directions at the same time. +enum PacketBuffer { + /// The RX buffer - must be used for single-buffered OUT endpoints + Rx, + /// The TX buffer - must be used for single-buffered IN endpoints + Tx, +} + /// USB endpoint. pub struct Endpoint<'d, T: Instance, D> { _phantom: PhantomData<(&'d mut T, D)>, @@ -664,15 +732,46 @@ pub struct Endpoint<'d, T: Instance, D> { } impl<'d, T: Instance, D> Endpoint<'d, T, D> { - fn write_data(&mut self, buf: &[u8]) { + /// Write to a double-buffered endpoint. + /// + /// For double-buffered endpoints, the data buffers overlap, but we still need to write to the right counter field. + /// The DTOG_TX bit indicates the buffer that is currently in use by the USB peripheral, that is, the buffer in + /// which the next transmit packet will be stored, so we need to write the counter of the OTHER buffer, which is + /// where the last transmitted packet was stored. + fn write_data_double_buffered(&mut self, buf: &[u8], packet_buffer: PacketBuffer) { let index = self.info.addr.index(); self.buf.write(buf); - btable::write_in_len::(index, self.buf.addr, buf.len() as _); + + match packet_buffer { + PacketBuffer::Rx => btable::write_in_len_rx::(index, self.buf.addr, buf.len() as _), + PacketBuffer::Tx => btable::write_in_len_tx::(index, self.buf.addr, buf.len() as _), + } } - fn read_data(&mut self, buf: &mut [u8]) -> Result { + /// Write to a single-buffered endpoint. + fn write_data(&mut self, buf: &[u8]) { + self.write_data_double_buffered(buf, PacketBuffer::Tx); + } + + /// Read from a double-buffered endpoint. + /// + /// For double-buffered endpoints, the data buffers overlap, but we still need to read from the right counter field. + /// The DTOG_RX bit indicates the buffer that is currently in use by the USB peripheral, that is, the buffer in + /// which the next received packet will be stored, so we need to read the counter of the OTHER buffer, which is + /// where the last received packet was stored. + fn read_data_double_buffered( + &mut self, + buf: &mut [u8], + packet_buffer: PacketBuffer, + ) -> Result { let index = self.info.addr.index(); - let rx_len = btable::read_out_len::(index) as usize & 0x3FF; + + let rx_len = match packet_buffer { + PacketBuffer::Rx => btable::read_out_len_rx::(index), + PacketBuffer::Tx => btable::read_out_len_tx::(index), + } as usize + & 0x3FF; + trace!("READ DONE, rx_len = {}", rx_len); if rx_len > buf.len() { return Err(EndpointError::BufferOverflow); @@ -680,6 +779,11 @@ impl<'d, T: Instance, D> Endpoint<'d, T, D> { self.buf.read(&mut buf[..rx_len]); Ok(rx_len) } + + /// Read from a single-buffered endpoint. + fn read_data(&mut self, buf: &mut [u8]) -> Result { + self.read_data_double_buffered(buf, PacketBuffer::Rx) + } } impl<'d, T: Instance> driver::Endpoint for Endpoint<'d, T, In> { @@ -734,25 +838,53 @@ impl<'d, T: Instance> driver::EndpointOut for Endpoint<'d, T, Out> { EP_OUT_WAKERS[index].register(cx.waker()); let regs = T::regs(); let stat = regs.epr(index).read().stat_rx(); - if matches!(stat, Stat::NAK | Stat::DISABLED) { - Poll::Ready(stat) + if self.info.ep_type == EndpointType::Isochronous { + // The isochronous endpoint does not change its `STAT_RX` field to `NAK` when receiving a packet. + // Therefore, this instead waits until the `CTR` interrupt was triggered. + if matches!(stat, Stat::DISABLED) || CTR_TRIGGERED[index].load(Ordering::Relaxed) { + Poll::Ready(stat) + } else { + Poll::Pending + } } else { - Poll::Pending + if matches!(stat, Stat::NAK | Stat::DISABLED) { + Poll::Ready(stat) + } else { + Poll::Pending + } } }) .await; + CTR_TRIGGERED[index].store(false, Ordering::Relaxed); + if stat == Stat::DISABLED { return Err(EndpointError::Disabled); } - let rx_len = self.read_data(buf)?; - let regs = T::regs(); + + let packet_buffer = if self.info.ep_type == EndpointType::Isochronous { + // Find the buffer, which is currently in use. Read from the OTHER buffer. + if regs.epr(index).read().dtog_rx() { + PacketBuffer::Rx + } else { + PacketBuffer::Tx + } + } else { + PacketBuffer::Rx + }; + + let rx_len = self.read_data_double_buffered(buf, packet_buffer)?; + regs.epr(index).write(|w| { w.set_ep_type(convert_type(self.info.ep_type)); w.set_ea(self.info.addr.index() as _); - w.set_stat_rx(Stat::from_bits(Stat::NAK.to_bits() ^ Stat::VALID.to_bits())); + if self.info.ep_type == EndpointType::Isochronous { + w.set_stat_rx(Stat::from_bits(0)); // STAT_RX remains `VALID`. + } else { + w.set_stat_rx(Stat::from_bits(Stat::NAK.to_bits() ^ Stat::VALID.to_bits())); + } w.set_stat_tx(Stat::from_bits(0)); w.set_ctr_rx(true); // don't clear w.set_ctr_tx(true); // don't clear @@ -776,25 +908,54 @@ impl<'d, T: Instance> driver::EndpointIn for Endpoint<'d, T, In> { EP_IN_WAKERS[index].register(cx.waker()); let regs = T::regs(); let stat = regs.epr(index).read().stat_tx(); - if matches!(stat, Stat::NAK | Stat::DISABLED) { - Poll::Ready(stat) + if self.info.ep_type == EndpointType::Isochronous { + // The isochronous endpoint does not change its `STAT_RX` field to `NAK` when receiving a packet. + // Therefore, this instead waits until the `CTR` interrupt was triggered. + if matches!(stat, Stat::DISABLED) || CTR_TRIGGERED[index].load(Ordering::Relaxed) { + Poll::Ready(stat) + } else { + Poll::Pending + } } else { - Poll::Pending + if matches!(stat, Stat::NAK | Stat::DISABLED) { + Poll::Ready(stat) + } else { + Poll::Pending + } } }) .await; + CTR_TRIGGERED[index].store(false, Ordering::Relaxed); + if stat == Stat::DISABLED { return Err(EndpointError::Disabled); } - self.write_data(buf); + let regs = T::regs(); + + let packet_buffer = if self.info.ep_type == EndpointType::Isochronous { + // Find the buffer, which is currently in use. Write to the OTHER buffer. + if regs.epr(index).read().dtog_tx() { + PacketBuffer::Tx + } else { + PacketBuffer::Rx + } + } else { + PacketBuffer::Tx + }; + + self.write_data_double_buffered(buf, packet_buffer); let regs = T::regs(); regs.epr(index).write(|w| { w.set_ep_type(convert_type(self.info.ep_type)); w.set_ea(self.info.addr.index() as _); - w.set_stat_tx(Stat::from_bits(Stat::NAK.to_bits() ^ Stat::VALID.to_bits())); + if self.info.ep_type == EndpointType::Isochronous { + w.set_stat_tx(Stat::from_bits(0)); // STAT_TX remains `VALID`. + } else { + w.set_stat_tx(Stat::from_bits(Stat::NAK.to_bits() ^ Stat::VALID.to_bits())); + } w.set_stat_rx(Stat::from_bits(0)); w.set_ctr_rx(true); // don't clear w.set_ctr_tx(true); // don't clear From d37c482e2179c95740bb4284f4df30637551199b Mon Sep 17 00:00:00 2001 From: elagil Date: Thu, 5 Sep 2024 21:29:11 +0200 Subject: [PATCH 0083/1217] feat(usb-otg): add support for ISO endpoints --- embassy-usb-synopsys-otg/src/lib.rs | 30 ++++++++++++++++++++++++++ embassy-usb-synopsys-otg/src/otg_v1.rs | 16 +++++++------- 2 files changed, 38 insertions(+), 8 deletions(-) diff --git a/embassy-usb-synopsys-otg/src/lib.rs b/embassy-usb-synopsys-otg/src/lib.rs index 5fb82db42..b145f4aa8 100644 --- a/embassy-usb-synopsys-otg/src/lib.rs +++ b/embassy-usb-synopsys-otg/src/lib.rs @@ -1071,6 +1071,21 @@ impl<'d> embassy_usb_driver::EndpointOut for Endpoint<'d, Out> { w.set_pktcnt(1); }); + if self.info.ep_type == EndpointType::Isochronous { + // Isochronous endpoints must set the correct even/odd frame bit to + // correspond with the next frame's number. + let frame_number = self.regs.dsts().read().fnsof(); + let frame_is_odd = frame_number & 0x01 == 1; + + self.regs.doepctl(index).modify(|r| { + if frame_is_odd { + r.set_sd0pid_sevnfrm(true); + } else { + r.set_sd1pid_soddfrm(true); + } + }); + } + // Clear NAK to indicate we are ready to receive more data self.regs.doepctl(index).modify(|w| { w.set_cnak(true); @@ -1158,6 +1173,21 @@ impl<'d> embassy_usb_driver::EndpointIn for Endpoint<'d, In> { w.set_xfrsiz(buf.len() as _); }); + if self.info.ep_type == EndpointType::Isochronous { + // Isochronous endpoints must set the correct even/odd frame bit to + // correspond with the next frame's number. + let frame_number = self.regs.dsts().read().fnsof(); + let frame_is_odd = frame_number & 0x01 == 1; + + self.regs.diepctl(index).modify(|r| { + if frame_is_odd { + r.set_sd0pid_sevnfrm(true); + } else { + r.set_sd1pid_soddfrm(true); + } + }); + } + // Enable endpoint self.regs.diepctl(index).modify(|w| { w.set_cnak(true); diff --git a/embassy-usb-synopsys-otg/src/otg_v1.rs b/embassy-usb-synopsys-otg/src/otg_v1.rs index a8530980c..d3abc328d 100644 --- a/embassy-usb-synopsys-otg/src/otg_v1.rs +++ b/embassy-usb-synopsys-otg/src/otg_v1.rs @@ -795,15 +795,15 @@ pub mod regs { pub fn set_sd0pid_sevnfrm(&mut self, val: bool) { self.0 = (self.0 & !(0x01 << 28usize)) | (((val as u32) & 0x01) << 28usize); } - #[doc = "SODDFRM/SD1PID"] + #[doc = "SD1PID/SODDFRM"] #[inline(always)] - pub const fn soddfrm_sd1pid(&self) -> bool { + pub const fn sd1pid_soddfrm(&self) -> bool { let val = (self.0 >> 29usize) & 0x01; val != 0 } - #[doc = "SODDFRM/SD1PID"] + #[doc = "SD1PID/SODDFRM"] #[inline(always)] - pub fn set_soddfrm_sd1pid(&mut self, val: bool) { + pub fn set_sd1pid_soddfrm(&mut self, val: bool) { self.0 = (self.0 & !(0x01 << 29usize)) | (((val as u32) & 0x01) << 29usize); } #[doc = "EPDIS"] @@ -1174,15 +1174,15 @@ pub mod regs { pub fn set_sd0pid_sevnfrm(&mut self, val: bool) { self.0 = (self.0 & !(0x01 << 28usize)) | (((val as u32) & 0x01) << 28usize); } - #[doc = "SODDFRM"] + #[doc = "SD1PID/SODDFRM"] #[inline(always)] - pub const fn soddfrm(&self) -> bool { + pub const fn sd1pid_soddfrm(&self) -> bool { let val = (self.0 >> 29usize) & 0x01; val != 0 } - #[doc = "SODDFRM"] + #[doc = "SD1PID/SODDFRM"] #[inline(always)] - pub fn set_soddfrm(&mut self, val: bool) { + pub fn set_sd1pid_soddfrm(&mut self, val: bool) { self.0 = (self.0 & !(0x01 << 29usize)) | (((val as u32) & 0x01) << 29usize); } #[doc = "EPDIS"] From a8ca6713e6e9b7ad5dd53f9b46bcf5e893adda1e Mon Sep 17 00:00:00 2001 From: elagil Date: Thu, 5 Sep 2024 21:29:24 +0200 Subject: [PATCH 0084/1217] feat(usb): make use of ISO endpoint support --- embassy-usb/src/builder.rs | 140 ++++++++++++++++++++++++++++++---- embassy-usb/src/descriptor.rs | 91 +++++++++++++++++++--- 2 files changed, 206 insertions(+), 25 deletions(-) diff --git a/embassy-usb/src/builder.rs b/embassy-usb/src/builder.rs index 7168e077c..e1bf8041f 100644 --- a/embassy-usb/src/builder.rs +++ b/embassy-usb/src/builder.rs @@ -1,8 +1,8 @@ use heapless::Vec; use crate::config::MAX_HANDLER_COUNT; -use crate::descriptor::{BosWriter, DescriptorWriter}; -use crate::driver::{Driver, Endpoint, EndpointType}; +use crate::descriptor::{BosWriter, DescriptorWriter, SynchronizationType, UsageType}; +use crate::driver::{Driver, Endpoint, EndpointInfo, EndpointType}; use crate::msos::{DeviceLevelDescriptor, FunctionLevelDescriptor, MsOsDescriptorWriter}; use crate::types::{InterfaceNumber, StringIndex}; use crate::{Handler, Interface, UsbDevice, MAX_INTERFACE_COUNT, STRING_INDEX_CUSTOM_START}; @@ -414,7 +414,7 @@ impl<'a, 'd, D: Driver<'d>> InterfaceAltBuilder<'a, 'd, D> { /// Descriptors are written in the order builder functions are called. Note that some /// classes care about the order. pub fn descriptor(&mut self, descriptor_type: u8, descriptor: &[u8]) { - self.builder.config_descriptor.write(descriptor_type, descriptor); + self.builder.config_descriptor.write(descriptor_type, descriptor, &[]); } /// Add a custom Binary Object Store (BOS) descriptor to this alternate setting. @@ -422,26 +422,80 @@ impl<'a, 'd, D: Driver<'d>> InterfaceAltBuilder<'a, 'd, D> { self.builder.bos_descriptor.capability(capability_type, capability); } - fn endpoint_in(&mut self, ep_type: EndpointType, max_packet_size: u16, interval_ms: u8) -> D::EndpointIn { + /// Write a custom endpoint descriptor for a certain endpoint. + /// + /// This can be necessary, if the endpoint descriptors can only be written + /// after the endpoint was created. As an example, an endpoint descriptor + /// may contain the address of an endpoint that was allocated earlier. + pub fn endpoint_descriptor( + &mut self, + endpoint: &EndpointInfo, + synchronization_type: SynchronizationType, + usage_type: UsageType, + extra_fields: &[u8], + ) { + self.builder + .config_descriptor + .endpoint(endpoint, synchronization_type, usage_type, extra_fields); + } + + /// Allocate an IN endpoint, without writing its descriptor. + /// + /// Used for granular control over the order of endpoint and descriptor creation. + pub fn alloc_endpoint_in(&mut self, ep_type: EndpointType, max_packet_size: u16, interval_ms: u8) -> D::EndpointIn { let ep = self .builder .driver .alloc_endpoint_in(ep_type, max_packet_size, interval_ms) .expect("alloc_endpoint_in failed"); - self.builder.config_descriptor.endpoint(ep.info()); + ep + } + + fn endpoint_in( + &mut self, + ep_type: EndpointType, + max_packet_size: u16, + interval_ms: u8, + synchronization_type: SynchronizationType, + usage_type: UsageType, + extra_fields: &[u8], + ) -> D::EndpointIn { + let ep = self.alloc_endpoint_in(ep_type, max_packet_size, interval_ms); + self.endpoint_descriptor(ep.info(), synchronization_type, usage_type, extra_fields); ep } - fn endpoint_out(&mut self, ep_type: EndpointType, max_packet_size: u16, interval_ms: u8) -> D::EndpointOut { + /// Allocate an OUT endpoint, without writing its descriptor. + /// + /// Use for granular control over the order of endpoint and descriptor creation. + pub fn alloc_endpoint_out( + &mut self, + ep_type: EndpointType, + max_packet_size: u16, + interval_ms: u8, + ) -> D::EndpointOut { let ep = self .builder .driver .alloc_endpoint_out(ep_type, max_packet_size, interval_ms) .expect("alloc_endpoint_out failed"); - self.builder.config_descriptor.endpoint(ep.info()); + ep + } + + fn endpoint_out( + &mut self, + ep_type: EndpointType, + max_packet_size: u16, + interval_ms: u8, + synchronization_type: SynchronizationType, + usage_type: UsageType, + extra_fields: &[u8], + ) -> D::EndpointOut { + let ep = self.alloc_endpoint_out(ep_type, max_packet_size, interval_ms); + self.endpoint_descriptor(ep.info(), synchronization_type, usage_type, extra_fields); ep } @@ -451,7 +505,14 @@ impl<'a, 'd, D: Driver<'d>> InterfaceAltBuilder<'a, 'd, D> { /// Descriptors are written in the order builder functions are called. Note that some /// classes care about the order. pub fn endpoint_bulk_in(&mut self, max_packet_size: u16) -> D::EndpointIn { - self.endpoint_in(EndpointType::Bulk, max_packet_size, 0) + self.endpoint_in( + EndpointType::Bulk, + max_packet_size, + 0, + SynchronizationType::NoSynchronization, + UsageType::DataEndpoint, + &[], + ) } /// Allocate a BULK OUT endpoint and write its descriptor. @@ -459,7 +520,14 @@ impl<'a, 'd, D: Driver<'d>> InterfaceAltBuilder<'a, 'd, D> { /// Descriptors are written in the order builder functions are called. Note that some /// classes care about the order. pub fn endpoint_bulk_out(&mut self, max_packet_size: u16) -> D::EndpointOut { - self.endpoint_out(EndpointType::Bulk, max_packet_size, 0) + self.endpoint_out( + EndpointType::Bulk, + max_packet_size, + 0, + SynchronizationType::NoSynchronization, + UsageType::DataEndpoint, + &[], + ) } /// Allocate a INTERRUPT IN endpoint and write its descriptor. @@ -467,24 +535,66 @@ impl<'a, 'd, D: Driver<'d>> InterfaceAltBuilder<'a, 'd, D> { /// Descriptors are written in the order builder functions are called. Note that some /// classes care about the order. pub fn endpoint_interrupt_in(&mut self, max_packet_size: u16, interval_ms: u8) -> D::EndpointIn { - self.endpoint_in(EndpointType::Interrupt, max_packet_size, interval_ms) + self.endpoint_in( + EndpointType::Interrupt, + max_packet_size, + interval_ms, + SynchronizationType::NoSynchronization, + UsageType::DataEndpoint, + &[], + ) } /// Allocate a INTERRUPT OUT endpoint and write its descriptor. pub fn endpoint_interrupt_out(&mut self, max_packet_size: u16, interval_ms: u8) -> D::EndpointOut { - self.endpoint_out(EndpointType::Interrupt, max_packet_size, interval_ms) + self.endpoint_out( + EndpointType::Interrupt, + max_packet_size, + interval_ms, + SynchronizationType::NoSynchronization, + UsageType::DataEndpoint, + &[], + ) } /// Allocate a ISOCHRONOUS IN endpoint and write its descriptor. /// /// Descriptors are written in the order builder functions are called. Note that some /// classes care about the order. - pub fn endpoint_isochronous_in(&mut self, max_packet_size: u16, interval_ms: u8) -> D::EndpointIn { - self.endpoint_in(EndpointType::Isochronous, max_packet_size, interval_ms) + pub fn endpoint_isochronous_in( + &mut self, + max_packet_size: u16, + interval_ms: u8, + synchronization_type: SynchronizationType, + usage_type: UsageType, + extra_fields: &[u8], + ) -> D::EndpointIn { + self.endpoint_in( + EndpointType::Isochronous, + max_packet_size, + interval_ms, + synchronization_type, + usage_type, + extra_fields, + ) } /// Allocate a ISOCHRONOUS OUT endpoint and write its descriptor. - pub fn endpoint_isochronous_out(&mut self, max_packet_size: u16, interval_ms: u8) -> D::EndpointOut { - self.endpoint_out(EndpointType::Isochronous, max_packet_size, interval_ms) + pub fn endpoint_isochronous_out( + &mut self, + max_packet_size: u16, + interval_ms: u8, + synchronization_type: SynchronizationType, + usage_type: UsageType, + extra_fields: &[u8], + ) -> D::EndpointOut { + self.endpoint_out( + EndpointType::Isochronous, + max_packet_size, + interval_ms, + synchronization_type, + usage_type, + extra_fields, + ) } } diff --git a/embassy-usb/src/descriptor.rs b/embassy-usb/src/descriptor.rs index f1773fa8a..0f2931c38 100644 --- a/embassy-usb/src/descriptor.rs +++ b/embassy-usb/src/descriptor.rs @@ -1,4 +1,5 @@ //! Utilities for writing USB descriptors. +use embassy_usb_driver::EndpointType; use crate::builder::Config; use crate::driver::EndpointInfo; @@ -38,6 +39,40 @@ pub mod capability_type { pub const PLATFORM: u8 = 5; } +/// USB endpoint synchronization type. The values of this enum can be directly +/// cast into `u8` to get the bmAttributes synchronization type bits. +/// Values other than `NoSynchronization` are only allowed on isochronous endpoints. +#[repr(u8)] +#[derive(Copy, Clone, Eq, PartialEq, Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum SynchronizationType { + /// No synchronization is used. + NoSynchronization = 0b00, + /// Unsynchronized, although sinks provide data rate feedback. + Asynchronous = 0b01, + /// Synchronized using feedback or feedforward data rate information. + Adaptive = 0b10, + /// Synchronized to the USB’s SOF. + Synchronous = 0b11, +} + +/// USB endpoint usage type. The values of this enum can be directly cast into +/// `u8` to get the bmAttributes usage type bits. +/// Values other than `DataEndpoint` are only allowed on isochronous endpoints. +#[repr(u8)] +#[derive(Copy, Clone, Eq, PartialEq, Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum UsageType { + /// Use the endpoint for regular data transfer. + DataEndpoint = 0b00, + /// Endpoint conveys explicit feedback information for one or more data endpoints. + FeedbackEndpoint = 0b01, + /// A data endpoint that also serves as an implicit feedback endpoint for one or more data endpoints. + ImplicitFeedbackDataEndpoint = 0b10, + /// Reserved usage type. + Reserved = 0b11, +} + /// A writer for USB descriptors. pub(crate) struct DescriptorWriter<'a> { pub buf: &'a mut [u8], @@ -65,23 +100,26 @@ impl<'a> DescriptorWriter<'a> { self.position } - /// Writes an arbitrary (usually class-specific) descriptor. - pub fn write(&mut self, descriptor_type: u8, descriptor: &[u8]) { - let length = descriptor.len(); + /// Writes an arbitrary (usually class-specific) descriptor with optional extra fields. + pub fn write(&mut self, descriptor_type: u8, descriptor: &[u8], extra_fields: &[u8]) { + let descriptor_length = descriptor.len(); + let extra_fields_length = extra_fields.len(); + let total_length = descriptor_length + extra_fields_length; assert!( - (self.position + 2 + length) <= self.buf.len() && (length + 2) <= 255, + (self.position + 2 + total_length) <= self.buf.len() && (total_length + 2) <= 255, "Descriptor buffer full" ); - self.buf[self.position] = (length + 2) as u8; + self.buf[self.position] = (total_length + 2) as u8; self.buf[self.position + 1] = descriptor_type; let start = self.position + 2; - self.buf[start..start + length].copy_from_slice(descriptor); + self.buf[start..start + descriptor_length].copy_from_slice(descriptor); + self.buf[start + descriptor_length..start + total_length].copy_from_slice(extra_fields); - self.position = start + length; + self.position = start + total_length; } pub(crate) fn configuration(&mut self, config: &Config) { @@ -99,6 +137,7 @@ impl<'a> DescriptorWriter<'a> { | if config.supports_remote_wakeup { 0x20 } else { 0x00 }, // bmAttributes (config.max_power / 2) as u8, // bMaxPower ], + &[], ); } @@ -145,6 +184,7 @@ impl<'a> DescriptorWriter<'a> { function_protocol, 0, ], + &[], ); } @@ -195,6 +235,7 @@ impl<'a> DescriptorWriter<'a> { interface_protocol, // bInterfaceProtocol str_index, // iInterface ], + &[], ); } @@ -204,21 +245,50 @@ impl<'a> DescriptorWriter<'a> { /// /// * `endpoint` - Endpoint previously allocated with /// [`UsbDeviceBuilder`](crate::bus::UsbDeviceBuilder). - pub fn endpoint(&mut self, endpoint: &EndpointInfo) { + /// * `synchronization_type` - The synchronization type of the endpoint. + /// * `usage_type` - The usage type of the endpoint. + /// * `extra_fields` - Additional, class-specific entries at the end of the endpoint descriptor. + pub fn endpoint( + &mut self, + endpoint: &EndpointInfo, + synchronization_type: SynchronizationType, + usage_type: UsageType, + extra_fields: &[u8], + ) { match self.num_endpoints_mark { Some(mark) => self.buf[mark] += 1, None => panic!("you can only call `endpoint` after `interface/interface_alt`."), }; + let mut bm_attributes = endpoint.ep_type as u8; + + // Synchronization types other than `NoSynchronization`, + // and usage types other than `DataEndpoint` + // are only allowed for isochronous endpoints. + if endpoint.ep_type != EndpointType::Isochronous { + assert_eq!(synchronization_type, SynchronizationType::NoSynchronization); + assert_eq!(usage_type, UsageType::DataEndpoint); + } else { + if usage_type == UsageType::FeedbackEndpoint { + assert_eq!(synchronization_type, SynchronizationType::NoSynchronization) + } + + let synchronization_bm_attibutes: u8 = (synchronization_type as u8) << 2; + let usage_bm_attibutes: u8 = (usage_type as u8) << 4; + + bm_attributes |= usage_bm_attibutes | synchronization_bm_attibutes; + } + self.write( descriptor_type::ENDPOINT, &[ - endpoint.addr.into(), // bEndpointAddress - endpoint.ep_type as u8, // bmAttributes + endpoint.addr.into(), // bEndpointAddress + bm_attributes, // bmAttributes endpoint.max_packet_size as u8, (endpoint.max_packet_size >> 8) as u8, // wMaxPacketSize endpoint.interval_ms, // bInterval ], + extra_fields, ); } @@ -315,6 +385,7 @@ impl<'a> BosWriter<'a> { 0x00, 0x00, // wTotalLength 0x00, // bNumDeviceCaps ], + &[], ); self.capability(capability_type::USB_2_0_EXTENSION, &[0; 4]); From ccce870642f295cda901493df422b25d211da503 Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Thu, 5 Sep 2024 18:01:05 -0400 Subject: [PATCH 0085/1217] ci: Fix the "test" task when using stm32-metapac from a CI artifact --- .github/ci/test.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/ci/test.sh b/.github/ci/test.sh index da0021684..0de265049 100755 --- a/.github/ci/test.sh +++ b/.github/ci/test.sh @@ -8,6 +8,10 @@ export RUSTUP_HOME=/ci/cache/rustup export CARGO_HOME=/ci/cache/cargo export CARGO_TARGET_DIR=/ci/cache/target +# needed for "dumb HTTP" transport support +# used when pointing stm32-metapac to a CI-built one. +export CARGO_NET_GIT_FETCH_WITH_CLI=true + cargo test --manifest-path ./embassy-futures/Cargo.toml cargo test --manifest-path ./embassy-sync/Cargo.toml cargo test --manifest-path ./embassy-embedded-hal/Cargo.toml From ac7ebea762519505a0ea54ce753ec2a9fc67dfe9 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Fri, 6 Sep 2024 09:34:39 +0200 Subject: [PATCH 0086/1217] Make sure to CFUN=0 before changing configuration --- embassy-net-nrf91/src/context.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/embassy-net-nrf91/src/context.rs b/embassy-net-nrf91/src/context.rs index b936e5f87..d5d088ec0 100644 --- a/embassy-net-nrf91/src/context.rs +++ b/embassy-net-nrf91/src/context.rs @@ -92,10 +92,21 @@ impl<'a> Control<'a> { } /// Configures the modem with the provided config. + /// + /// NOTE: This will disconnect the modem from any current APN and should not + /// be called if the configuration has not been changed. pub async fn configure(&self, config: &Config<'_>) -> Result<(), Error> { let mut cmd: [u8; 256] = [0; 256]; let mut buf: [u8; 256] = [0; 256]; + let op = CommandBuilder::create_set(&mut cmd, true) + .named("+CFUN") + .with_int_parameter(0) + .finish() + .map_err(|_| Error::BufferTooSmall)?; + let n = self.control.at_command(op, &mut buf).await; + CommandParser::parse(&buf[..n]).expect_identifier(b"OK").finish()?; + let op = CommandBuilder::create_set(&mut cmd, true) .named("+CGDCONT") .with_int_parameter(self.cid) @@ -104,6 +115,7 @@ impl<'a> Control<'a> { .finish() .map_err(|_| Error::BufferTooSmall)?; let n = self.control.at_command(op, &mut buf).await; + // info!("RES1: {}", unsafe { core::str::from_utf8_unchecked(&buf[..n]) }); CommandParser::parse(&buf[..n]).expect_identifier(b"OK").finish()?; let mut op = CommandBuilder::create_set(&mut cmd, true) @@ -116,6 +128,7 @@ impl<'a> Control<'a> { let op = op.finish().map_err(|_| Error::BufferTooSmall)?; let n = self.control.at_command(op, &mut buf).await; + // info!("RES2: {}", unsafe { core::str::from_utf8_unchecked(&buf[..n]) }); CommandParser::parse(&buf[..n]).expect_identifier(b"OK").finish()?; let op = CommandBuilder::create_set(&mut cmd, true) From 5e74434cb8b89b62f7bc0d2a9ab90d94aa11fe4b Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Fri, 6 Sep 2024 09:52:26 +0200 Subject: [PATCH 0087/1217] Ensure modem is enabled in run() --- embassy-net-nrf91/src/context.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/embassy-net-nrf91/src/context.rs b/embassy-net-nrf91/src/context.rs index d5d088ec0..2f2452bd0 100644 --- a/embassy-net-nrf91/src/context.rs +++ b/embassy-net-nrf91/src/context.rs @@ -303,6 +303,18 @@ impl<'a> Control<'a> { /// Run a control loop for this context, ensuring that reaattach is handled. pub async fn run(&self, reattach: F) -> Result<(), Error> { + let mut cmd: [u8; 256] = [0; 256]; + let mut buf: [u8; 256] = [0; 256]; + + // Make sure modem is enabled + let op = CommandBuilder::create_set(&mut cmd, true) + .named("+CFUN") + .with_int_parameter(1) + .finish() + .map_err(|_| Error::BufferTooSmall)?; + + let n = self.control.at_command(op, &mut buf).await; + CommandParser::parse(&buf[..n]).expect_identifier(b"OK").finish()?; let status = self.wait_attached().await?; let mut fd = self.control.open_raw_socket().await; reattach(&status); From e2e3143c2ea9a606eff2fa1d4e51a74824b5c2ac Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Fri, 6 Sep 2024 09:58:54 +0200 Subject: [PATCH 0088/1217] Add explicit disable/enable function and skip enable in configure --- embassy-net-nrf91/src/context.rs | 55 ++++++++++++++++++++------------ 1 file changed, 35 insertions(+), 20 deletions(-) diff --git a/embassy-net-nrf91/src/context.rs b/embassy-net-nrf91/src/context.rs index 2f2452bd0..22629fe5b 100644 --- a/embassy-net-nrf91/src/context.rs +++ b/embassy-net-nrf91/src/context.rs @@ -95,6 +95,8 @@ impl<'a> Control<'a> { /// /// NOTE: This will disconnect the modem from any current APN and should not /// be called if the configuration has not been changed. + /// + /// After configuring, invoke [`enable()`] to activate the configuration. pub async fn configure(&self, config: &Config<'_>) -> Result<(), Error> { let mut cmd: [u8; 256] = [0; 256]; let mut buf: [u8; 256] = [0; 256]; @@ -131,22 +133,6 @@ impl<'a> Control<'a> { // info!("RES2: {}", unsafe { core::str::from_utf8_unchecked(&buf[..n]) }); CommandParser::parse(&buf[..n]).expect_identifier(b"OK").finish()?; - let op = CommandBuilder::create_set(&mut cmd, true) - .named("+CFUN") - .with_int_parameter(1) - .finish() - .map_err(|_| Error::BufferTooSmall)?; - let n = self.control.at_command(op, &mut buf).await; - CommandParser::parse(&buf[..n]).expect_identifier(b"OK").finish()?; - - let op = CommandBuilder::create_set(&mut cmd, true) - .named("%XPDNCFG") - .with_int_parameter(1) - .finish() - .map_err(|_| Error::BufferTooSmall)?; - let n = self.control.at_command(op, &mut buf).await; - CommandParser::parse(&buf[..n]).expect_identifier(b"OK").finish()?; - Ok(()) } @@ -301,20 +287,49 @@ impl<'a> Control<'a> { Ok(status) } - /// Run a control loop for this context, ensuring that reaattach is handled. - pub async fn run(&self, reattach: F) -> Result<(), Error> { + /// Disable modem + pub async fn disable(&self) -> Result<(), Error> { + let mut cmd: [u8; 256] = [0; 256]; + let mut buf: [u8; 256] = [0; 256]; + + let op = CommandBuilder::create_set(&mut cmd, true) + .named("+CFUN") + .with_int_parameter(0) + .finish() + .map_err(|_| Error::BufferTooSmall)?; + let n = self.control.at_command(op, &mut buf).await; + CommandParser::parse(&buf[..n]).expect_identifier(b"OK").finish()?; + + Ok(()) + } + + /// Enable modem + pub async fn enable(&self) -> Result<(), Error> { let mut cmd: [u8; 256] = [0; 256]; let mut buf: [u8; 256] = [0; 256]; - // Make sure modem is enabled let op = CommandBuilder::create_set(&mut cmd, true) .named("+CFUN") .with_int_parameter(1) .finish() .map_err(|_| Error::BufferTooSmall)?; - let n = self.control.at_command(op, &mut buf).await; CommandParser::parse(&buf[..n]).expect_identifier(b"OK").finish()?; + + // Make modem survive PDN detaches + let op = CommandBuilder::create_set(&mut cmd, true) + .named("%XPDNCFG") + .with_int_parameter(1) + .finish() + .map_err(|_| Error::BufferTooSmall)?; + let n = self.control.at_command(op, &mut buf).await; + CommandParser::parse(&buf[..n]).expect_identifier(b"OK").finish()?; + Ok(()) + } + + /// Run a control loop for this context, ensuring that reaattach is handled. + pub async fn run(&self, reattach: F) -> Result<(), Error> { + self.enable().await?; let status = self.wait_attached().await?; let mut fd = self.control.open_raw_socket().await; reattach(&status); From 01d8508b6c9bf89e27a83b9587bcc13c358c1e51 Mon Sep 17 00:00:00 2001 From: Oleksandr Babak Date: Fri, 6 Sep 2024 11:16:44 +0200 Subject: [PATCH 0089/1217] fix: nightly api changed during the night --- embassy-executor/src/raw/waker.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/embassy-executor/src/raw/waker.rs b/embassy-executor/src/raw/waker.rs index 8d3910a25..8bb2cfd05 100644 --- a/embassy-executor/src/raw/waker.rs +++ b/embassy-executor/src/raw/waker.rs @@ -50,8 +50,7 @@ pub fn task_from_waker(waker: &Waker) -> TaskRef { #[cfg(feature = "nightly")] { - let raw_waker = waker.as_raw(); - (raw_waker.vtable(), raw_waker.data()) + (waker.vtable(), waker.data()) } }; From 1b1db2401bfdfe6f813fb7738529749e4ec80882 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Fri, 6 Sep 2024 11:22:07 +0200 Subject: [PATCH 0090/1217] Use byte slice for config --- embassy-net-nrf91/src/context.rs | 4 ++-- examples/nrf9160/src/bin/modem_tcp_client.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/embassy-net-nrf91/src/context.rs b/embassy-net-nrf91/src/context.rs index 22629fe5b..8b45919ef 100644 --- a/embassy-net-nrf91/src/context.rs +++ b/embassy-net-nrf91/src/context.rs @@ -16,11 +16,11 @@ pub struct Control<'a> { /// Configuration for a given context pub struct Config<'a> { /// Desired APN address. - pub apn: &'a str, + pub apn: &'a [u8], /// Desired authentication protocol. pub auth_prot: AuthProt, /// Credentials. - pub auth: Option<(&'a str, &'a str)>, + pub auth: Option<(&'a [u8], &'a [u8])>, } /// Authentication protocol. diff --git a/examples/nrf9160/src/bin/modem_tcp_client.rs b/examples/nrf9160/src/bin/modem_tcp_client.rs index 7d78eba0a..5335b6b51 100644 --- a/examples/nrf9160/src/bin/modem_tcp_client.rs +++ b/examples/nrf9160/src/bin/modem_tcp_client.rs @@ -166,9 +166,9 @@ async fn main(spawner: Spawner) { unwrap!(spawner.spawn(control_task( control, context::Config { - apn: "iot.nat.es", + apn: b"iot.nat.es", auth_prot: context::AuthProt::Pap, - auth: Some(("orange", "orange")), + auth: Some((b"orange", b"orange")), }, stack ))); From 5b4941a51040d1bbcc00590a504e078e2f72f3bd Mon Sep 17 00:00:00 2001 From: Oleksandr Babak Date: Fri, 6 Sep 2024 11:29:12 +0200 Subject: [PATCH 0091/1217] ci: update rust-toolchain --- rust-toolchain-nightly.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain-nightly.toml b/rust-toolchain-nightly.toml index dfa231344..0b10d7194 100644 --- a/rust-toolchain-nightly.toml +++ b/rust-toolchain-nightly.toml @@ -1,5 +1,5 @@ [toolchain] -channel = "nightly-2024-07-16" +channel = "nightly-2024-09-06" components = [ "rust-src", "rustfmt", "llvm-tools", "miri" ] targets = [ "thumbv7em-none-eabi", From 1443f3386b3b216dc50306d14f5dacce29b2bf97 Mon Sep 17 00:00:00 2001 From: Oleksandr Babak Date: Fri, 6 Sep 2024 11:34:30 +0200 Subject: [PATCH 0092/1217] fix: remove stable nightly feature --- embassy-executor/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/embassy-executor/src/lib.rs b/embassy-executor/src/lib.rs index 553ed76d3..6a2e493a2 100644 --- a/embassy-executor/src/lib.rs +++ b/embassy-executor/src/lib.rs @@ -1,5 +1,4 @@ #![cfg_attr(not(any(feature = "arch-std", feature = "arch-wasm")), no_std)] -#![cfg_attr(feature = "nightly", feature(waker_getters))] #![allow(clippy::new_without_default)] #![doc = include_str!("../README.md")] #![warn(missing_docs)] From 8ac758bdee793496f842f4c267bda2b6f935a0bb Mon Sep 17 00:00:00 2001 From: Grant Miller Date: Fri, 6 Sep 2024 09:07:29 -0500 Subject: [PATCH 0093/1217] embassy-stm32: Add SimplePwmChannel --- embassy-stm32/src/timer/simple_pwm.rs | 112 ++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs index b7771bd64..f94ed1be5 100644 --- a/embassy-stm32/src/timer/simple_pwm.rs +++ b/embassy-stm32/src/timer/simple_pwm.rs @@ -51,6 +51,96 @@ channel_impl!(new_ch2, Ch2, Channel2Pin); channel_impl!(new_ch3, Ch3, Channel3Pin); channel_impl!(new_ch4, Ch4, Channel4Pin); +/// A single channel of a pwm, obtained from [`SimplePwm::split`]. +/// +/// It is not possible to change the pwm frequency because +/// the frequency configuration is shared with all four channels. +pub struct SimplePwmChannel<'d, T: GeneralInstance4Channel> { + timer: &'d Timer<'d, T>, + channel: Channel, +} + +// TODO: check for RMW races +impl<'d, T: GeneralInstance4Channel> SimplePwmChannel<'d, T> { + /// Enable the given channel. + pub fn enable(&mut self) { + self.timer.enable_channel(self.channel, true); + } + + /// Disable the given channel. + pub fn disable(&mut self) { + self.timer.enable_channel(self.channel, false); + } + + /// Check whether given channel is enabled + pub fn is_enabled(&self) -> bool { + self.timer.get_channel_enable_state(self.channel) + } + + /// Get max duty value. + /// + /// This value depends on the configured frequency and the timer's clock rate from RCC. + pub fn get_max_duty(&self) -> u32 { + self.timer.get_max_compare_value() + 1 + } + + /// Set the duty for a given channel. + /// + /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included. + pub fn set_duty(&mut self, duty: u32) { + assert!(duty <= self.get_max_duty()); + self.timer.set_compare_value(self.channel, duty) + } + + /// Get the duty for a given channel. + /// + /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included. + pub fn get_duty(&self) -> u32 { + self.timer.get_compare_value(self.channel) + } + + /// Set the output polarity for a given channel. + pub fn set_polarity(&mut self, polarity: OutputPolarity) { + self.timer.set_output_polarity(self.channel, polarity); + } + + /// Set the output compare mode for a given channel. + pub fn set_output_compare_mode(&mut self, mode: OutputCompareMode) { + self.timer.set_output_compare_mode(self.channel, mode); + } +} + +/// A group of four [`SimplePwmChannel`]s, obtained from [`SimplePwm::split`]. +pub struct SimplePwmChannels<'d, T: GeneralInstance4Channel> { + /// Channel 1 + pub ch1: SimplePwmChannel<'d, T>, + /// Channel 2 + pub ch2: SimplePwmChannel<'d, T>, + /// Channel 3 + pub ch3: SimplePwmChannel<'d, T>, + /// Channel 4 + pub ch4: SimplePwmChannel<'d, T>, +} + +impl<'d, T: GeneralInstance4Channel> embedded_hal_1::pwm::ErrorType for SimplePwmChannel<'d, T> { + type Error = core::convert::Infallible; +} + +impl<'d, T: GeneralInstance4Channel> embedded_hal_1::pwm::SetDutyCycle for SimplePwmChannel<'d, T> { + fn max_duty_cycle(&self) -> u16 { + // TODO: panics if CCR is 0xFFFF + // TODO: rename get_max_duty to max_duty_cycle + unwrap!(self.get_max_duty().try_into()) + } + + fn set_duty_cycle(&mut self, duty: u16) -> Result<(), Self::Error> { + self.set_duty(duty.into()); + Ok(()) + } + + // TODO: default methods? +} + /// Simple PWM driver. pub struct SimplePwm<'d, T: GeneralInstance4Channel> { inner: Timer<'d, T>, @@ -89,6 +179,28 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> { this } + fn channel(&self, channel: Channel) -> SimplePwmChannel<'_, T> { + SimplePwmChannel { + timer: &self.inner, + channel, + } + } + + /// Splits a [`SimplePwm`] into four pwm channels. + /// + /// This returns all four channels, including channels that + /// aren't configured with a [`PwmPin`]. + // TODO: I hate the name "split" + pub fn split(&mut self) -> SimplePwmChannels<'_, T> { + // TODO: pre-enable channels? + SimplePwmChannels { + ch1: self.channel(Channel::Ch1), + ch2: self.channel(Channel::Ch2), + ch3: self.channel(Channel::Ch3), + ch4: self.channel(Channel::Ch4), + } + } + /// Enable the given channel. pub fn enable(&mut self, channel: Channel) { self.inner.enable_channel(channel, true); From f7f062e0a3f303dfc4f976907b2555f2cfb48621 Mon Sep 17 00:00:00 2001 From: Grant Miller Date: Fri, 6 Sep 2024 10:25:29 -0500 Subject: [PATCH 0094/1217] Deduplicate SimplePwm's channel methods --- embassy-stm32/src/timer/simple_pwm.rs | 119 ++++++++++++++------------ 1 file changed, 63 insertions(+), 56 deletions(-) diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs index f94ed1be5..7179a7a59 100644 --- a/embassy-stm32/src/timer/simple_pwm.rs +++ b/embassy-stm32/src/timer/simple_pwm.rs @@ -51,7 +51,8 @@ channel_impl!(new_ch2, Ch2, Channel2Pin); channel_impl!(new_ch3, Ch3, Channel3Pin); channel_impl!(new_ch4, Ch4, Channel4Pin); -/// A single channel of a pwm, obtained from [`SimplePwm::split`]. +/// A single channel of a pwm, obtained from [`SimplePwm::split`], +/// [`SimplePwm::channel`], [`SimplePwm::ch1`], etc. /// /// It is not possible to change the pwm frequency because /// the frequency configuration is shared with all four channels. @@ -179,13 +180,52 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> { this } - fn channel(&self, channel: Channel) -> SimplePwmChannel<'_, T> { + /// Get a single channel + /// + /// If you need to use multiple channels, use [`Self::split`]. + pub fn channel(&mut self, channel: Channel) -> SimplePwmChannel<'_, T> { SimplePwmChannel { timer: &self.inner, channel, } } + /// Channel 1 + /// + /// This is just a convenience wrapper around [`Self::channel`]. + /// + /// If you need to use multiple channels, use [`Self::split`]. + pub fn ch1(&mut self) -> SimplePwmChannel<'_, T> { + self.channel(Channel::Ch1) + } + + /// Channel 2 + /// + /// This is just a convenience wrapper around [`Self::channel`]. + /// + /// If you need to use multiple channels, use [`Self::split`]. + pub fn ch2(&mut self) -> SimplePwmChannel<'_, T> { + self.channel(Channel::Ch2) + } + + /// Channel 3 + /// + /// This is just a convenience wrapper around [`Self::channel`]. + /// + /// If you need to use multiple channels, use [`Self::split`]. + pub fn ch3(&mut self) -> SimplePwmChannel<'_, T> { + self.channel(Channel::Ch3) + } + + /// Channel 4 + /// + /// This is just a convenience wrapper around [`Self::channel`]. + /// + /// If you need to use multiple channels, use [`Self::split`]. + pub fn ch4(&mut self) -> SimplePwmChannel<'_, T> { + self.channel(Channel::Ch4) + } + /// Splits a [`SimplePwm`] into four pwm channels. /// /// This returns all four channels, including channels that @@ -193,29 +233,21 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> { // TODO: I hate the name "split" pub fn split(&mut self) -> SimplePwmChannels<'_, T> { // TODO: pre-enable channels? + + // we can't use self.channel() because that takes &mut self + let ch = |channel| SimplePwmChannel { + timer: &self.inner, + channel, + }; + SimplePwmChannels { - ch1: self.channel(Channel::Ch1), - ch2: self.channel(Channel::Ch2), - ch3: self.channel(Channel::Ch3), - ch4: self.channel(Channel::Ch4), + ch1: ch(Channel::Ch1), + ch2: ch(Channel::Ch2), + ch3: ch(Channel::Ch3), + ch4: ch(Channel::Ch4), } } - /// Enable the given channel. - pub fn enable(&mut self, channel: Channel) { - self.inner.enable_channel(channel, true); - } - - /// Disable the given channel. - pub fn disable(&mut self, channel: Channel) { - self.inner.enable_channel(channel, false); - } - - /// Check whether given channel is enabled - pub fn is_enabled(&self, channel: Channel) -> bool { - self.inner.get_channel_enable_state(channel) - } - /// Set PWM frequency. /// /// Note: when you call this, the max duty value changes, so you will have to @@ -236,31 +268,6 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> { self.inner.get_max_compare_value() + 1 } - /// Set the duty for a given channel. - /// - /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included. - pub fn set_duty(&mut self, channel: Channel, duty: u32) { - assert!(duty <= self.get_max_duty()); - self.inner.set_compare_value(channel, duty) - } - - /// Get the duty for a given channel. - /// - /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included. - pub fn get_duty(&self, channel: Channel) -> u32 { - self.inner.get_compare_value(channel) - } - - /// Set the output polarity for a given channel. - pub fn set_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { - self.inner.set_output_polarity(channel, polarity); - } - - /// Set the output compare mode for a given channel. - pub fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode) { - self.inner.set_output_compare_mode(channel, mode); - } - /// Generate a sequence of PWM waveform /// /// Note: @@ -276,8 +283,8 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> { #[allow(clippy::let_unit_value)] // eg. stm32f334 let req = dma.request(); - let original_duty_state = self.get_duty(channel); - let original_enable_state = self.is_enabled(channel); + let original_duty_state = self.channel(channel).get_duty(); + let original_enable_state = self.channel(channel).is_enabled(); let original_update_dma_state = self.inner.get_update_dma_state(); if !original_update_dma_state { @@ -285,7 +292,7 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> { } if !original_enable_state { - self.enable(channel); + self.channel(channel).enable(); } unsafe { @@ -313,10 +320,10 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> { // restore output compare state if !original_enable_state { - self.disable(channel); + self.channel(channel).disable(); } - self.set_duty(channel, original_duty_state); + self.channel(channel).set_duty(original_duty_state); // Since DMA is closed before timer update event trigger DMA is turn off, // this can almost always trigger a DMA FIFO error. @@ -346,8 +353,8 @@ macro_rules! impl_waveform_chx { let cc_channel = Channel::$cc_ch; - let original_duty_state = self.get_duty(cc_channel); - let original_enable_state = self.is_enabled(cc_channel); + let original_duty_state = self.channel(cc_channel).get_duty(); + let original_enable_state = self.channel(cc_channel).is_enabled(); let original_cc_dma_on_update = self.inner.get_cc_dma_selection() == Ccds::ONUPDATE; let original_cc_dma_enabled = self.inner.get_cc_dma_enable_state(cc_channel); @@ -361,7 +368,7 @@ macro_rules! impl_waveform_chx { } if !original_enable_state { - self.enable(cc_channel); + self.channel(cc_channel).enable(); } unsafe { @@ -389,10 +396,10 @@ macro_rules! impl_waveform_chx { // restore output compare state if !original_enable_state { - self.disable(cc_channel); + self.channel(cc_channel).disable(); } - self.set_duty(cc_channel, original_duty_state); + self.channel(cc_channel).set_duty(original_duty_state); // Since DMA is closed before timer Capture Compare Event trigger DMA is turn off, // this can almost always trigger a DMA FIFO error. From ee25f14b20fc2aabf428fbc7b2bd684ece66a2a1 Mon Sep 17 00:00:00 2001 From: Badr Bouslikhin Date: Fri, 6 Sep 2024 18:35:23 +0200 Subject: [PATCH 0095/1217] fix(stm32): reorder dma and idle futures --- embassy-stm32/src/usart/ringbuffered.rs | 34 ++++++++++++------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/embassy-stm32/src/usart/ringbuffered.rs b/embassy-stm32/src/usart/ringbuffered.rs index 8cf75933a..b0652046c 100644 --- a/embassy-stm32/src/usart/ringbuffered.rs +++ b/embassy-stm32/src/usart/ringbuffered.rs @@ -184,20 +184,6 @@ impl<'d> RingBufferedUartRx<'d> { async fn wait_for_data_or_idle(&mut self) -> Result<(), Error> { compiler_fence(Ordering::SeqCst); - let mut dma_init = false; - // Future which completes when there is dma is half full or full - let dma = poll_fn(|cx| { - self.ring_buf.set_waker(cx.waker()); - - let status = match dma_init { - false => Poll::Pending, - true => Poll::Ready(()), - }; - - dma_init = true; - status - }); - // Future which completes when idle line is detected let s = self.state; let uart = poll_fn(|cx| { @@ -219,9 +205,23 @@ impl<'d> RingBufferedUartRx<'d> { } }); - match select(dma, uart).await { - Either::Left(((), _)) => Ok(()), - Either::Right((result, _)) => result, + let mut dma_init = false; + // Future which completes when there is dma is half full or full + let dma = poll_fn(|cx| { + self.ring_buf.set_waker(cx.waker()); + + let status = match dma_init { + false => Poll::Pending, + true => Poll::Ready(()), + }; + + dma_init = true; + status + }); + + match select(uart, dma).await { + Either::Left((result, _)) => result, + Either::Right(((), _)) => Ok(()), } } } From 0e477a4df506981e770e41edec31e2bc0cd6b6c6 Mon Sep 17 00:00:00 2001 From: Badr Bouslikhin Date: Fri, 6 Sep 2024 18:36:11 +0200 Subject: [PATCH 0096/1217] fix(stm32): enable dma half transfer interrupt for buffereduart --- embassy-stm32/src/dma/dma_bdma.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/embassy-stm32/src/dma/dma_bdma.rs b/embassy-stm32/src/dma/dma_bdma.rs index 8e2964f94..df041c4e9 100644 --- a/embassy-stm32/src/dma/dma_bdma.rs +++ b/embassy-stm32/src/dma/dma_bdma.rs @@ -777,6 +777,7 @@ impl<'a, W: Word> ReadableRingBuffer<'a, W> { let dir = Dir::PeripheralToMemory; let data_size = W::size(); + options.half_transfer_ir = true; options.complete_transfer_ir = true; options.circular = true; From cfc76cec711447300e2d957439a32d6ad418a58c Mon Sep 17 00:00:00 2001 From: Grant Miller Date: Fri, 6 Sep 2024 13:29:54 -0500 Subject: [PATCH 0097/1217] Match embedded-hal api --- embassy-stm32/src/timer/simple_pwm.rs | 105 ++++++++++++++++++-------- 1 file changed, 72 insertions(+), 33 deletions(-) diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs index 7179a7a59..23c727731 100644 --- a/embassy-stm32/src/timer/simple_pwm.rs +++ b/embassy-stm32/src/timer/simple_pwm.rs @@ -81,23 +81,45 @@ impl<'d, T: GeneralInstance4Channel> SimplePwmChannel<'d, T> { /// Get max duty value. /// /// This value depends on the configured frequency and the timer's clock rate from RCC. - pub fn get_max_duty(&self) -> u32 { - self.timer.get_max_compare_value() + 1 + pub fn max_duty_cycle(&self) -> u16 { + unwrap!(self.timer.get_max_compare_value().checked_add(1)) } /// Set the duty for a given channel. /// - /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included. - pub fn set_duty(&mut self, duty: u32) { - assert!(duty <= self.get_max_duty()); - self.timer.set_compare_value(self.channel, duty) + /// The value ranges from 0 for 0% duty, to [`max_duty_cycle`](Self::max_duty_cycle) for 100% duty, both included. + pub fn set_duty_cycle(&mut self, duty: u16) { + assert!(duty <= (*self).max_duty_cycle()); + self.timer.set_compare_value(self.channel, duty.into()) + } + + fn set_duty_cycle_fully_off(&mut self) { + self.set_duty_cycle(0); + } + + fn set_duty_cycle_fully_on(&mut self) { + self.set_duty_cycle((*self).max_duty_cycle()); + } + + fn set_duty_cycle_fraction(&mut self, num: u16, denom: u16) { + assert!(denom != 0); + assert!(num <= denom); + let duty = u32::from(num) * u32::from(self.max_duty_cycle()) / u32::from(denom); + + // This is safe because we know that `num <= denom`, so `duty <= self.max_duty_cycle()` (u16) + #[allow(clippy::cast_possible_truncation)] + self.set_duty_cycle(duty as u16); + } + + fn set_duty_cycle_percent(&mut self, percent: u8) { + self.set_duty_cycle_fraction(u16::from(percent), 100) } /// Get the duty for a given channel. /// - /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included. - pub fn get_duty(&self) -> u32 { - self.timer.get_compare_value(self.channel) + /// The value ranges from 0 for 0% duty, to [`max_duty_cycle`](Self::max_duty_cycle) for 100% duty, both included. + pub fn get_duty(&self) -> u16 { + unwrap!(self.timer.get_compare_value(self.channel).try_into()) } /// Set the output polarity for a given channel. @@ -123,25 +145,6 @@ pub struct SimplePwmChannels<'d, T: GeneralInstance4Channel> { pub ch4: SimplePwmChannel<'d, T>, } -impl<'d, T: GeneralInstance4Channel> embedded_hal_1::pwm::ErrorType for SimplePwmChannel<'d, T> { - type Error = core::convert::Infallible; -} - -impl<'d, T: GeneralInstance4Channel> embedded_hal_1::pwm::SetDutyCycle for SimplePwmChannel<'d, T> { - fn max_duty_cycle(&self) -> u16 { - // TODO: panics if CCR is 0xFFFF - // TODO: rename get_max_duty to max_duty_cycle - unwrap!(self.get_max_duty().try_into()) - } - - fn set_duty_cycle(&mut self, duty: u16) -> Result<(), Self::Error> { - self.set_duty(duty.into()); - Ok(()) - } - - // TODO: default methods? -} - /// Simple PWM driver. pub struct SimplePwm<'d, T: GeneralInstance4Channel> { inner: Timer<'d, T>, @@ -253,6 +256,7 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> { /// Note: when you call this, the max duty value changes, so you will have to /// call `set_duty` on all channels with the duty calculated based on the new max duty. pub fn set_frequency(&mut self, freq: Hertz) { + // TODO: prevent ARR = u16::MAX? let multiplier = if self.inner.get_counting_mode().is_center_aligned() { 2u8 } else { @@ -264,8 +268,8 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> { /// Get max duty value. /// /// This value depends on the configured frequency and the timer's clock rate from RCC. - pub fn get_max_duty(&self) -> u32 { - self.inner.get_max_compare_value() + 1 + pub fn max_duty_cycle(&self) -> u16 { + unwrap!(self.inner.get_max_compare_value().checked_add(1)) } /// Generate a sequence of PWM waveform @@ -323,7 +327,7 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> { self.channel(channel).disable(); } - self.channel(channel).set_duty(original_duty_state); + self.channel(channel).set_duty_cycle(original_duty_state); // Since DMA is closed before timer update event trigger DMA is turn off, // this can almost always trigger a DMA FIFO error. @@ -399,7 +403,7 @@ macro_rules! impl_waveform_chx { self.channel(cc_channel).disable(); } - self.channel(cc_channel).set_duty(original_duty_state); + self.channel(cc_channel).set_duty_cycle(original_duty_state); // Since DMA is closed before timer Capture Compare Event trigger DMA is turn off, // this can almost always trigger a DMA FIFO error. @@ -423,6 +427,41 @@ impl_waveform_chx!(waveform_ch2, Ch2Dma, Ch2); impl_waveform_chx!(waveform_ch3, Ch3Dma, Ch3); impl_waveform_chx!(waveform_ch4, Ch4Dma, Ch4); +impl<'d, T: GeneralInstance4Channel> embedded_hal_1::pwm::ErrorType for SimplePwmChannel<'d, T> { + type Error = core::convert::Infallible; +} + +impl<'d, T: GeneralInstance4Channel> embedded_hal_1::pwm::SetDutyCycle for SimplePwmChannel<'d, T> { + fn max_duty_cycle(&self) -> u16 { + self.max_duty_cycle() + } + + fn set_duty_cycle(&mut self, duty: u16) -> Result<(), Self::Error> { + self.set_duty_cycle(duty); + Ok(()) + } + + fn set_duty_cycle_fully_off(&mut self) -> Result<(), Self::Error> { + self.set_duty_cycle_fully_off(); + Ok(()) + } + + fn set_duty_cycle_fully_on(&mut self) -> Result<(), Self::Error> { + self.set_duty_cycle_fully_on(); + Ok(()) + } + + fn set_duty_cycle_fraction(&mut self, num: u16, denom: u16) -> Result<(), Self::Error> { + self.set_duty_cycle_fraction(num, denom); + Ok(()) + } + + fn set_duty_cycle_percent(&mut self, percent: u8) -> Result<(), Self::Error> { + self.set_duty_cycle_percent(percent); + Ok(()) + } +} + impl<'d, T: GeneralInstance4Channel> embedded_hal_02::Pwm for SimplePwm<'d, T> { type Channel = Channel; type Time = Hertz; @@ -449,7 +488,7 @@ impl<'d, T: GeneralInstance4Channel> embedded_hal_02::Pwm for SimplePwm<'d, T> { } fn set_duty(&mut self, channel: Self::Channel, duty: Self::Duty) { - assert!(duty <= self.get_max_duty()); + assert!(duty <= self.max_duty_cycle() as u32); self.inner.set_compare_value(channel, duty) } From 1a8977db7837a5635d3c5e0ae8213d1b3181ffb7 Mon Sep 17 00:00:00 2001 From: Grant Miller Date: Fri, 6 Sep 2024 13:53:49 -0500 Subject: [PATCH 0098/1217] Update examples --- examples/stm32f4/src/bin/pwm.rs | 18 +++++++++--------- examples/stm32f4/src/bin/ws2812_pwm.rs | 4 ++-- examples/stm32g0/src/bin/input_capture.rs | 8 ++++---- examples/stm32g0/src/bin/pwm_input.rs | 9 ++++----- examples/stm32g4/src/bin/pwm.rs | 18 +++++++++--------- examples/stm32h7/src/bin/pwm.rs | 18 +++++++++--------- 6 files changed, 37 insertions(+), 38 deletions(-) diff --git a/examples/stm32f4/src/bin/pwm.rs b/examples/stm32f4/src/bin/pwm.rs index 8844a9f0e..0cd65a258 100644 --- a/examples/stm32f4/src/bin/pwm.rs +++ b/examples/stm32f4/src/bin/pwm.rs @@ -15,22 +15,22 @@ async fn main(_spawner: Spawner) { let p = embassy_stm32::init(Default::default()); info!("Hello World!"); - let ch1 = PwmPin::new_ch1(p.PE9, OutputType::PushPull); - let mut pwm = SimplePwm::new(p.TIM1, Some(ch1), None, None, None, khz(10), Default::default()); - let max = pwm.get_max_duty(); - pwm.enable(Channel::Ch1); + let ch1_pin = PwmPin::new_ch1(p.PE9, OutputType::PushPull); + let mut pwm = SimplePwm::new(p.TIM1, Some(ch1_pin), None, None, None, khz(10), Default::default()); + let mut ch1 = pwm.ch1(); + ch1.enable(); info!("PWM initialized"); - info!("PWM max duty {}", max); + info!("PWM max duty {}", ch1.max_duty_cycle()); loop { - pwm.set_duty(Channel::Ch1, 0); + ch1.set_duty_cycle_fully_off(); Timer::after_millis(300).await; - pwm.set_duty(Channel::Ch1, max / 4); + ch1.set_duty_cycle_fraction(1, 4); Timer::after_millis(300).await; - pwm.set_duty(Channel::Ch1, max / 2); + ch1.set_dutycycle_fraction(1, 2); Timer::after_millis(300).await; - pwm.set_duty(Channel::Ch1, max - 1); + ch1.set_duty_cycle(ch1.max_duty_cycle() - 1); Timer::after_millis(300).await; } } diff --git a/examples/stm32f4/src/bin/ws2812_pwm.rs b/examples/stm32f4/src/bin/ws2812_pwm.rs index cbaff75fc..7a9fa302b 100644 --- a/examples/stm32f4/src/bin/ws2812_pwm.rs +++ b/examples/stm32f4/src/bin/ws2812_pwm.rs @@ -61,7 +61,7 @@ async fn main(_spawner: Spawner) { // construct ws2812 non-return-to-zero (NRZ) code bit by bit // ws2812 only need 24 bits for each LED, but we add one bit more to keep PWM output low - let max_duty = ws2812_pwm.get_max_duty() as u16; + let max_duty = ws2812_pwm.max_duty_cycle(); let n0 = 8 * max_duty / 25; // ws2812 Bit 0 high level timing let n1 = 2 * n0; // ws2812 Bit 1 high level timing @@ -84,7 +84,7 @@ async fn main(_spawner: Spawner) { let pwm_channel = Channel::Ch1; // make sure PWM output keep low on first start - ws2812_pwm.set_duty(pwm_channel, 0); + ws2812_pwm.channel(pwm_channel).set_duty(0); // flip color at 2 Hz let mut ticker = Ticker::every(Duration::from_millis(500)); diff --git a/examples/stm32g0/src/bin/input_capture.rs b/examples/stm32g0/src/bin/input_capture.rs index 69fdae96d..bc814cb13 100644 --- a/examples/stm32g0/src/bin/input_capture.rs +++ b/examples/stm32g0/src/bin/input_capture.rs @@ -47,10 +47,10 @@ async fn main(spawner: Spawner) { unwrap!(spawner.spawn(blinky(p.PB1))); // Connect PB1 and PA8 with a 1k Ohm resistor - let ch1 = PwmPin::new_ch1(p.PA8, OutputType::PushPull); - let mut pwm = SimplePwm::new(p.TIM1, Some(ch1), None, None, None, khz(1), Default::default()); - pwm.enable(Channel::Ch1); - pwm.set_duty(Channel::Ch1, 50); + let ch1_pin = PwmPin::new_ch1(p.PA8, OutputType::PushPull); + let mut pwm = SimplePwm::new(p.TIM1, Some(ch1_pin), None, None, None, khz(1), Default::default()); + pwm.ch1().enable(); + pwm.ch1().set_duty_cycle(50); let ch1 = CapturePin::new_ch1(p.PA0, Pull::None); let mut ic = InputCapture::new(p.TIM2, Some(ch1), None, None, None, Irqs, khz(1000), Default::default()); diff --git a/examples/stm32g0/src/bin/pwm_input.rs b/examples/stm32g0/src/bin/pwm_input.rs index 152ecda86..983705e2f 100644 --- a/examples/stm32g0/src/bin/pwm_input.rs +++ b/examples/stm32g0/src/bin/pwm_input.rs @@ -43,11 +43,10 @@ async fn main(spawner: Spawner) { unwrap!(spawner.spawn(blinky(p.PB1))); // Connect PA8 and PA6 with a 1k Ohm resistor - let ch1 = PwmPin::new_ch1(p.PA8, OutputType::PushPull); - let mut pwm = SimplePwm::new(p.TIM1, Some(ch1), None, None, None, khz(1), Default::default()); - let max = pwm.get_max_duty(); - pwm.set_duty(Channel::Ch1, max / 4); - pwm.enable(Channel::Ch1); + let ch1_pin = PwmPin::new_ch1(p.PA8, OutputType::PushPull); + let mut pwm = SimplePwm::new(p.TIM1, Some(ch1_pin), None, None, None, khz(1), Default::default()); + pwm.ch1().set_duty_cycle_fraction(1, 4); + pwm.ch1().enable(); let mut pwm_input = PwmInput::new(p.TIM2, p.PA0, Pull::None, khz(1000)); pwm_input.enable(); diff --git a/examples/stm32g4/src/bin/pwm.rs b/examples/stm32g4/src/bin/pwm.rs index d4809a481..3833be58f 100644 --- a/examples/stm32g4/src/bin/pwm.rs +++ b/examples/stm32g4/src/bin/pwm.rs @@ -15,22 +15,22 @@ async fn main(_spawner: Spawner) { let p = embassy_stm32::init(Default::default()); info!("Hello World!"); - let ch1 = PwmPin::new_ch1(p.PC0, OutputType::PushPull); - let mut pwm = SimplePwm::new(p.TIM1, Some(ch1), None, None, None, khz(10), Default::default()); - let max = pwm.get_max_duty(); - pwm.enable(Channel::Ch1); + let ch1_pin = PwmPin::new_ch1(p.PC0, OutputType::PushPull); + let mut pwm = SimplePwm::new(p.TIM1, Some(ch1_pin), None, None, None, khz(10), Default::default()); + let mut ch1 = pwm.ch1(); + ch1.enable(); info!("PWM initialized"); - info!("PWM max duty {}", max); + info!("PWM max duty {}", ch1.max_duty_cycle()); loop { - pwm.set_duty(Channel::Ch1, 0); + ch1.set_duty_cycle_fully_off(); Timer::after_millis(300).await; - pwm.set_duty(Channel::Ch1, max / 4); + ch1.set_duty_cycle_fraction(1, 4); Timer::after_millis(300).await; - pwm.set_duty(Channel::Ch1, max / 2); + ch1.set_dutycycle_fraction(1, 2); Timer::after_millis(300).await; - pwm.set_duty(Channel::Ch1, max - 1); + ch1.set_duty_cycle(ch1.max_duty_cycle() - 1); Timer::after_millis(300).await; } } diff --git a/examples/stm32h7/src/bin/pwm.rs b/examples/stm32h7/src/bin/pwm.rs index 1e48ba67b..1d0b89e97 100644 --- a/examples/stm32h7/src/bin/pwm.rs +++ b/examples/stm32h7/src/bin/pwm.rs @@ -37,22 +37,22 @@ async fn main(_spawner: Spawner) { let p = embassy_stm32::init(config); info!("Hello World!"); - let ch1 = PwmPin::new_ch1(p.PA6, OutputType::PushPull); - let mut pwm = SimplePwm::new(p.TIM3, Some(ch1), None, None, None, khz(10), Default::default()); - let max = pwm.get_max_duty(); - pwm.enable(Channel::Ch1); + let ch1_pin = PwmPin::new_ch1(p.PA6, OutputType::PushPull); + let mut pwm = SimplePwm::new(p.TIM3, Some(ch1_pin), None, None, None, khz(10), Default::default()); + let mut ch1 = pwm.ch1; + ch1.enable(); info!("PWM initialized"); - info!("PWM max duty {}", max); + info!("PWM max duty {}", ch1.max_duty_cycle()); loop { - pwm.set_duty(Channel::Ch1, 0); + ch1.set_duty_cycle_fully_off(); Timer::after_millis(300).await; - pwm.set_duty(Channel::Ch1, max / 4); + ch1.set_duty_cycle_fraction(1, 4); Timer::after_millis(300).await; - pwm.set_duty(Channel::Ch1, max / 2); + ch1.set_dutycycle_fraction(1, 2); Timer::after_millis(300).await; - pwm.set_duty(Channel::Ch1, max - 1); + ch1.set_duty_cycle(ch1.max_duty_cycle() - 1); Timer::after_millis(300).await; } } From 71e49839fc350c19c2fd7eebda0fe76afbfdb157 Mon Sep 17 00:00:00 2001 From: Grant Miller Date: Fri, 6 Sep 2024 14:01:10 -0500 Subject: [PATCH 0099/1217] oops --- embassy-stm32/src/timer/simple_pwm.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs index 23c727731..885abd23f 100644 --- a/embassy-stm32/src/timer/simple_pwm.rs +++ b/embassy-stm32/src/timer/simple_pwm.rs @@ -82,7 +82,9 @@ impl<'d, T: GeneralInstance4Channel> SimplePwmChannel<'d, T> { /// /// This value depends on the configured frequency and the timer's clock rate from RCC. pub fn max_duty_cycle(&self) -> u16 { - unwrap!(self.timer.get_max_compare_value().checked_add(1)) + let max = self.timer.get_max_compare_value(); + assert!(max < u16::MAX as u32); + max as u16 + 1 } /// Set the duty for a given channel. @@ -269,7 +271,9 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> { /// /// This value depends on the configured frequency and the timer's clock rate from RCC. pub fn max_duty_cycle(&self) -> u16 { - unwrap!(self.inner.get_max_compare_value().checked_add(1)) + let max = self.inner.get_max_compare_value(); + assert!(max < u16::MAX as u32); + max as u16 + 1 } /// Generate a sequence of PWM waveform From f571ab9d600cdb6e3f146a6b2bf464fb817065af Mon Sep 17 00:00:00 2001 From: Grant Miller Date: Fri, 6 Sep 2024 14:04:58 -0500 Subject: [PATCH 0100/1217] oops again --- embassy-stm32/src/timer/simple_pwm.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs index 885abd23f..8673bce54 100644 --- a/embassy-stm32/src/timer/simple_pwm.rs +++ b/embassy-stm32/src/timer/simple_pwm.rs @@ -95,15 +95,15 @@ impl<'d, T: GeneralInstance4Channel> SimplePwmChannel<'d, T> { self.timer.set_compare_value(self.channel, duty.into()) } - fn set_duty_cycle_fully_off(&mut self) { + pub fn set_duty_cycle_fully_off(&mut self) { self.set_duty_cycle(0); } - fn set_duty_cycle_fully_on(&mut self) { + pub fn set_duty_cycle_fully_on(&mut self) { self.set_duty_cycle((*self).max_duty_cycle()); } - fn set_duty_cycle_fraction(&mut self, num: u16, denom: u16) { + pub fn set_duty_cycle_fraction(&mut self, num: u16, denom: u16) { assert!(denom != 0); assert!(num <= denom); let duty = u32::from(num) * u32::from(self.max_duty_cycle()) / u32::from(denom); @@ -113,7 +113,7 @@ impl<'d, T: GeneralInstance4Channel> SimplePwmChannel<'d, T> { self.set_duty_cycle(duty as u16); } - fn set_duty_cycle_percent(&mut self, percent: u8) { + pub fn set_duty_cycle_percent(&mut self, percent: u8) { self.set_duty_cycle_fraction(u16::from(percent), 100) } From d24c47a3ff4a82786b67f06d876bafb1bdabc163 Mon Sep 17 00:00:00 2001 From: Grant Miller Date: Fri, 6 Sep 2024 14:08:22 -0500 Subject: [PATCH 0101/1217] Missing docs --- embassy-stm32/src/timer/simple_pwm.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs index 8673bce54..47188053c 100644 --- a/embassy-stm32/src/timer/simple_pwm.rs +++ b/embassy-stm32/src/timer/simple_pwm.rs @@ -95,14 +95,20 @@ impl<'d, T: GeneralInstance4Channel> SimplePwmChannel<'d, T> { self.timer.set_compare_value(self.channel, duty.into()) } + /// Set the duty cycle to 0%, or always inactive. pub fn set_duty_cycle_fully_off(&mut self) { self.set_duty_cycle(0); } + /// Set the duty cycle to 100%, or always active. pub fn set_duty_cycle_fully_on(&mut self) { self.set_duty_cycle((*self).max_duty_cycle()); } + /// Set the duty cycle to `num / denom`. + /// + /// The caller is responsible for ensuring that `num` is less than or equal to `denom`, + /// and that `denom` is not zero. pub fn set_duty_cycle_fraction(&mut self, num: u16, denom: u16) { assert!(denom != 0); assert!(num <= denom); @@ -113,6 +119,9 @@ impl<'d, T: GeneralInstance4Channel> SimplePwmChannel<'d, T> { self.set_duty_cycle(duty as u16); } + /// Set the duty cycle to `percent / 100` + /// + /// The caller is responsible for ensuring that `percent` is less than or equal to 100. pub fn set_duty_cycle_percent(&mut self, percent: u8) { self.set_duty_cycle_fraction(u16::from(percent), 100) } From b8beaba6df08c4455f55780a6e13191d95ad9eec Mon Sep 17 00:00:00 2001 From: Grant Miller Date: Fri, 6 Sep 2024 15:08:58 -0500 Subject: [PATCH 0102/1217] last oops I promise --- embassy-stm32/src/timer/simple_pwm.rs | 6 +++--- examples/stm32f4/src/bin/pwm.rs | 3 +-- examples/stm32f4/src/bin/ws2812_pwm.rs | 2 +- examples/stm32g0/src/bin/pwm_input.rs | 1 - examples/stm32g4/src/bin/pwm.rs | 3 +-- examples/stm32h7/src/bin/pwm.rs | 5 ++--- 6 files changed, 8 insertions(+), 12 deletions(-) diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs index 47188053c..7e2e9c202 100644 --- a/embassy-stm32/src/timer/simple_pwm.rs +++ b/embassy-stm32/src/timer/simple_pwm.rs @@ -129,7 +129,7 @@ impl<'d, T: GeneralInstance4Channel> SimplePwmChannel<'d, T> { /// Get the duty for a given channel. /// /// The value ranges from 0 for 0% duty, to [`max_duty_cycle`](Self::max_duty_cycle) for 100% duty, both included. - pub fn get_duty(&self) -> u16 { + pub fn current_duty_cycle(&self) -> u16 { unwrap!(self.timer.get_compare_value(self.channel).try_into()) } @@ -300,7 +300,7 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> { #[allow(clippy::let_unit_value)] // eg. stm32f334 let req = dma.request(); - let original_duty_state = self.channel(channel).get_duty(); + let original_duty_state = self.channel(channel).current_duty_cycle(); let original_enable_state = self.channel(channel).is_enabled(); let original_update_dma_state = self.inner.get_update_dma_state(); @@ -370,7 +370,7 @@ macro_rules! impl_waveform_chx { let cc_channel = Channel::$cc_ch; - let original_duty_state = self.channel(cc_channel).get_duty(); + let original_duty_state = self.channel(cc_channel).current_duty_cycle(); let original_enable_state = self.channel(cc_channel).is_enabled(); let original_cc_dma_on_update = self.inner.get_cc_dma_selection() == Ccds::ONUPDATE; let original_cc_dma_enabled = self.inner.get_cc_dma_enable_state(cc_channel); diff --git a/examples/stm32f4/src/bin/pwm.rs b/examples/stm32f4/src/bin/pwm.rs index 0cd65a258..04811162b 100644 --- a/examples/stm32f4/src/bin/pwm.rs +++ b/examples/stm32f4/src/bin/pwm.rs @@ -6,7 +6,6 @@ use embassy_executor::Spawner; use embassy_stm32::gpio::OutputType; use embassy_stm32::time::khz; use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm}; -use embassy_stm32::timer::Channel; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; @@ -28,7 +27,7 @@ async fn main(_spawner: Spawner) { Timer::after_millis(300).await; ch1.set_duty_cycle_fraction(1, 4); Timer::after_millis(300).await; - ch1.set_dutycycle_fraction(1, 2); + ch1.set_duty_cycle_fraction(1, 2); Timer::after_millis(300).await; ch1.set_duty_cycle(ch1.max_duty_cycle() - 1); Timer::after_millis(300).await; diff --git a/examples/stm32f4/src/bin/ws2812_pwm.rs b/examples/stm32f4/src/bin/ws2812_pwm.rs index 7a9fa302b..3ab93d6e0 100644 --- a/examples/stm32f4/src/bin/ws2812_pwm.rs +++ b/examples/stm32f4/src/bin/ws2812_pwm.rs @@ -84,7 +84,7 @@ async fn main(_spawner: Spawner) { let pwm_channel = Channel::Ch1; // make sure PWM output keep low on first start - ws2812_pwm.channel(pwm_channel).set_duty(0); + ws2812_pwm.channel(pwm_channel).set_duty_cycle(0); // flip color at 2 Hz let mut ticker = Ticker::every(Duration::from_millis(500)); diff --git a/examples/stm32g0/src/bin/pwm_input.rs b/examples/stm32g0/src/bin/pwm_input.rs index 983705e2f..db9cf4f8a 100644 --- a/examples/stm32g0/src/bin/pwm_input.rs +++ b/examples/stm32g0/src/bin/pwm_input.rs @@ -14,7 +14,6 @@ use embassy_stm32::gpio::{Level, Output, OutputType, Pull, Speed}; use embassy_stm32::time::khz; use embassy_stm32::timer::pwm_input::PwmInput; use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm}; -use embassy_stm32::timer::Channel; use embassy_stm32::{bind_interrupts, peripherals, timer}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32g4/src/bin/pwm.rs b/examples/stm32g4/src/bin/pwm.rs index 3833be58f..6c965012c 100644 --- a/examples/stm32g4/src/bin/pwm.rs +++ b/examples/stm32g4/src/bin/pwm.rs @@ -6,7 +6,6 @@ use embassy_executor::Spawner; use embassy_stm32::gpio::OutputType; use embassy_stm32::time::khz; use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm}; -use embassy_stm32::timer::Channel; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; @@ -28,7 +27,7 @@ async fn main(_spawner: Spawner) { Timer::after_millis(300).await; ch1.set_duty_cycle_fraction(1, 4); Timer::after_millis(300).await; - ch1.set_dutycycle_fraction(1, 2); + ch1.set_duty_cycle_fraction(1, 2); Timer::after_millis(300).await; ch1.set_duty_cycle(ch1.max_duty_cycle() - 1); Timer::after_millis(300).await; diff --git a/examples/stm32h7/src/bin/pwm.rs b/examples/stm32h7/src/bin/pwm.rs index 1d0b89e97..a1c53fc3f 100644 --- a/examples/stm32h7/src/bin/pwm.rs +++ b/examples/stm32h7/src/bin/pwm.rs @@ -6,7 +6,6 @@ use embassy_executor::Spawner; use embassy_stm32::gpio::OutputType; use embassy_stm32::time::khz; use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm}; -use embassy_stm32::timer::Channel; use embassy_stm32::Config; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; @@ -39,7 +38,7 @@ async fn main(_spawner: Spawner) { let ch1_pin = PwmPin::new_ch1(p.PA6, OutputType::PushPull); let mut pwm = SimplePwm::new(p.TIM3, Some(ch1_pin), None, None, None, khz(10), Default::default()); - let mut ch1 = pwm.ch1; + let mut ch1 = pwm.ch1(); ch1.enable(); info!("PWM initialized"); @@ -50,7 +49,7 @@ async fn main(_spawner: Spawner) { Timer::after_millis(300).await; ch1.set_duty_cycle_fraction(1, 4); Timer::after_millis(300).await; - ch1.set_dutycycle_fraction(1, 2); + ch1.set_duty_cycle_fraction(1, 2); Timer::after_millis(300).await; ch1.set_duty_cycle(ch1.max_duty_cycle() - 1); Timer::after_millis(300).await; From df06c2bbfe51e22e0d3eda3d760839f617ffbd96 Mon Sep 17 00:00:00 2001 From: Grant Miller Date: Sat, 7 Sep 2024 11:13:18 -0500 Subject: [PATCH 0103/1217] wip: split by value --- embassy-stm32/src/timer/low_level.rs | 9 +++++++++ embassy-stm32/src/timer/mod.rs | 1 + embassy-stm32/src/timer/simple_pwm.rs | 17 +++++++++++------ 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/embassy-stm32/src/timer/low_level.rs b/embassy-stm32/src/timer/low_level.rs index e643722aa..6377054c5 100644 --- a/embassy-stm32/src/timer/low_level.rs +++ b/embassy-stm32/src/timer/low_level.rs @@ -6,6 +6,8 @@ //! //! The available functionality depends on the timer type. +use core::mem::ManuallyDrop; + use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; // Re-export useful enums pub use stm32_metapac::timer::vals::{FilterValue, Sms as SlaveMode, Ts as TriggerSource}; @@ -198,6 +200,13 @@ impl<'d, T: CoreInstance> Timer<'d, T> { Self { tim } } + pub(crate) unsafe fn clone_unchecked(&self) -> ManuallyDrop { + // this doesn't work for some reason + // let tim = unsafe { self.tim.clone_unchecked() }; + let tim = todo!(); + ManuallyDrop::new(Self { tim }) + } + /// Get access to the virutal core 16bit timer registers. /// /// Note: This works even if the timer is more capable, because registers diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs index 25782ee13..6cf22689b 100644 --- a/embassy-stm32/src/timer/mod.rs +++ b/embassy-stm32/src/timer/mod.rs @@ -2,6 +2,7 @@ use core::marker::PhantomData; +use embassy_hal_internal::Peripheral; use embassy_sync::waitqueue::AtomicWaker; #[cfg(not(stm32l0))] diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs index 7e2e9c202..9e4a09095 100644 --- a/embassy-stm32/src/timer/simple_pwm.rs +++ b/embassy-stm32/src/timer/simple_pwm.rs @@ -1,6 +1,7 @@ //! Simple PWM driver. use core::marker::PhantomData; +use core::mem::ManuallyDrop; use embassy_hal_internal::{into_ref, PeripheralRef}; @@ -57,7 +58,7 @@ channel_impl!(new_ch4, Ch4, Channel4Pin); /// It is not possible to change the pwm frequency because /// the frequency configuration is shared with all four channels. pub struct SimplePwmChannel<'d, T: GeneralInstance4Channel> { - timer: &'d Timer<'d, T>, + timer: ManuallyDrop>, channel: Channel, } @@ -199,7 +200,7 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> { /// If you need to use multiple channels, use [`Self::split`]. pub fn channel(&mut self, channel: Channel) -> SimplePwmChannel<'_, T> { SimplePwmChannel { - timer: &self.inner, + timer: unsafe { self.inner.clone_unchecked() }, channel, } } @@ -245,12 +246,16 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> { /// This returns all four channels, including channels that /// aren't configured with a [`PwmPin`]. // TODO: I hate the name "split" - pub fn split(&mut self) -> SimplePwmChannels<'_, T> { - // TODO: pre-enable channels? + pub fn split(self) -> SimplePwmChannels<'static, T> + where + // must be static because the timer will never be dropped/disabled + 'd: 'static, + { + // without this, the timer would be disabled at the end of this function + let timer = ManuallyDrop::new(self.inner); - // we can't use self.channel() because that takes &mut self let ch = |channel| SimplePwmChannel { - timer: &self.inner, + timer: unsafe { timer.clone_unchecked() }, channel, }; From 74e724f96869680da4893ad7024676bef1c57334 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 9 Sep 2024 02:13:17 +0200 Subject: [PATCH 0104/1217] Update to Rust 1.81 (#3322) --- rust-toolchain.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain.toml b/rust-toolchain.toml index ce9040a70..80acb3b5e 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,5 +1,5 @@ [toolchain] -channel = "1.80" +channel = "1.81" components = [ "rust-src", "rustfmt", "llvm-tools" ] targets = [ "thumbv7em-none-eabi", From 3ac38e917cc56530fa9b3515fd28a1f576b285e8 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sun, 8 Sep 2024 23:48:45 +0200 Subject: [PATCH 0105/1217] cyw43: use enum for ioctl instead of consts. --- cyw43/src/consts.rs | 299 +++++++++++++++++++++++++++++++++++++++++-- cyw43/src/control.rs | 59 ++++----- cyw43/src/ioctl.rs | 5 +- cyw43/src/runner.rs | 4 +- 4 files changed, 319 insertions(+), 48 deletions(-) diff --git a/cyw43/src/consts.rs b/cyw43/src/consts.rs index b6e22e61d..d47e5097a 100644 --- a/cyw43/src/consts.rs +++ b/cyw43/src/consts.rs @@ -113,17 +113,6 @@ pub(crate) const IRQ_F1_INTR: u16 = 0x2000; pub(crate) const IRQ_F2_INTR: u16 = 0x4000; pub(crate) const IRQ_F3_INTR: u16 = 0x8000; -pub(crate) const IOCTL_CMD_UP: u32 = 2; -pub(crate) const IOCTL_CMD_DOWN: u32 = 3; -pub(crate) const IOCTL_CMD_SET_SSID: u32 = 26; -pub(crate) const IOCTL_CMD_SET_CHANNEL: u32 = 30; -pub(crate) const IOCTL_CMD_DISASSOC: u32 = 52; -pub(crate) const IOCTL_CMD_ANTDIV: u32 = 64; -pub(crate) const IOCTL_CMD_SET_AP: u32 = 118; -pub(crate) const IOCTL_CMD_SET_VAR: u32 = 263; -pub(crate) const IOCTL_CMD_GET_VAR: u32 = 262; -pub(crate) const IOCTL_CMD_SET_PASSPHRASE: u32 = 268; - pub(crate) const CHANNEL_TYPE_CONTROL: u8 = 0; pub(crate) const CHANNEL_TYPE_EVENT: u8 = 1; pub(crate) const CHANNEL_TYPE_DATA: u8 = 2; @@ -376,3 +365,291 @@ impl core::fmt::Display for FormatInterrupt { core::fmt::Debug::fmt(self, f) } } + +#[derive(Copy, Clone, Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[repr(u32)] +pub(crate) enum Ioctl { + GetMagic = 0, + GetVersion = 1, + Up = 2, + Down = 3, + GetLoop = 4, + SetLoop = 5, + Dump = 6, + GetMsglevel = 7, + SetMsglevel = 8, + GetPromisc = 9, + SetPromisc = 10, + GetRate = 12, + GetInstance = 14, + GetInfra = 19, + SetInfra = 20, + GetAuth = 21, + SetAuth = 22, + GetBssid = 23, + SetBssid = 24, + GetSsid = 25, + SetSsid = 26, + Restart = 27, + GetChannel = 29, + SetChannel = 30, + GetSrl = 31, + SetSrl = 32, + GetLrl = 33, + SetLrl = 34, + GetPlcphdr = 35, + SetPlcphdr = 36, + GetRadio = 37, + SetRadio = 38, + GetPhytype = 39, + DumpRate = 40, + SetRateParams = 41, + GetKey = 44, + SetKey = 45, + GetRegulatory = 46, + SetRegulatory = 47, + GetPassiveScan = 48, + SetPassiveScan = 49, + Scan = 50, + ScanResults = 51, + Disassoc = 52, + Reassoc = 53, + GetRoamTrigger = 54, + SetRoamTrigger = 55, + GetRoamDelta = 56, + SetRoamDelta = 57, + GetRoamScanPeriod = 58, + SetRoamScanPeriod = 59, + Evm = 60, + GetTxant = 61, + SetTxant = 62, + GetAntdiv = 63, + SetAntdiv = 64, + GetClosed = 67, + SetClosed = 68, + GetMaclist = 69, + SetMaclist = 70, + GetRateset = 71, + SetRateset = 72, + Longtrain = 74, + GetBcnprd = 75, + SetBcnprd = 76, + GetDtimprd = 77, + SetDtimprd = 78, + GetSrom = 79, + SetSrom = 80, + GetWepRestrict = 81, + SetWepRestrict = 82, + GetCountry = 83, + SetCountry = 84, + GetPm = 85, + SetPm = 86, + GetWake = 87, + SetWake = 88, + GetForcelink = 90, + SetForcelink = 91, + FreqAccuracy = 92, + CarrierSuppress = 93, + GetPhyreg = 94, + SetPhyreg = 95, + GetRadioreg = 96, + SetRadioreg = 97, + GetRevinfo = 98, + GetUcantdiv = 99, + SetUcantdiv = 100, + RReg = 101, + WReg = 102, + GetMacmode = 105, + SetMacmode = 106, + GetMonitor = 107, + SetMonitor = 108, + GetGmode = 109, + SetGmode = 110, + GetLegacyErp = 111, + SetLegacyErp = 112, + GetRxAnt = 113, + GetCurrRateset = 114, + GetScansuppress = 115, + SetScansuppress = 116, + GetAp = 117, + SetAp = 118, + GetEapRestrict = 119, + SetEapRestrict = 120, + ScbAuthorize = 121, + ScbDeauthorize = 122, + GetWdslist = 123, + SetWdslist = 124, + GetAtim = 125, + SetAtim = 126, + GetRssi = 127, + GetPhyantdiv = 128, + SetPhyantdiv = 129, + ApRxOnly = 130, + GetTxPathPwr = 131, + SetTxPathPwr = 132, + GetWsec = 133, + SetWsec = 134, + GetPhyNoise = 135, + GetBssInfo = 136, + GetPktcnts = 137, + GetLazywds = 138, + SetLazywds = 139, + GetBandlist = 140, + GetBand = 141, + SetBand = 142, + ScbDeauthenticate = 143, + GetShortslot = 144, + GetShortslotOverride = 145, + SetShortslotOverride = 146, + GetShortslotRestrict = 147, + SetShortslotRestrict = 148, + GetGmodeProtection = 149, + GetGmodeProtectionOverride = 150, + SetGmodeProtectionOverride = 151, + Upgrade = 152, + GetIgnoreBcns = 155, + SetIgnoreBcns = 156, + GetScbTimeout = 157, + SetScbTimeout = 158, + GetAssoclist = 159, + GetClk = 160, + SetClk = 161, + GetUp = 162, + Out = 163, + GetWpaAuth = 164, + SetWpaAuth = 165, + GetUcflags = 166, + SetUcflags = 167, + GetPwridx = 168, + SetPwridx = 169, + GetTssi = 170, + GetSupRatesetOverride = 171, + SetSupRatesetOverride = 172, + GetProtectionControl = 178, + SetProtectionControl = 179, + GetPhylist = 180, + EncryptStrength = 181, + DecryptStatus = 182, + GetKeySeq = 183, + GetScanChannelTime = 184, + SetScanChannelTime = 185, + GetScanUnassocTime = 186, + SetScanUnassocTime = 187, + GetScanHomeTime = 188, + SetScanHomeTime = 189, + GetScanNprobes = 190, + SetScanNprobes = 191, + GetPrbRespTimeout = 192, + SetPrbRespTimeout = 193, + GetAtten = 194, + SetAtten = 195, + GetShmem = 196, + SetShmem = 197, + SetWsecTest = 200, + ScbDeauthenticateForReason = 201, + TkipCountermeasures = 202, + GetPiomode = 203, + SetPiomode = 204, + SetAssocPrefer = 205, + GetAssocPrefer = 206, + SetRoamPrefer = 207, + GetRoamPrefer = 208, + SetLed = 209, + GetLed = 210, + GetInterferenceMode = 211, + SetInterferenceMode = 212, + GetChannelQa = 213, + StartChannelQa = 214, + GetChannelSel = 215, + StartChannelSel = 216, + GetValidChannels = 217, + GetFakefrag = 218, + SetFakefrag = 219, + GetPwroutPercentage = 220, + SetPwroutPercentage = 221, + SetBadFramePreempt = 222, + GetBadFramePreempt = 223, + SetLeapList = 224, + GetLeapList = 225, + GetCwmin = 226, + SetCwmin = 227, + GetCwmax = 228, + SetCwmax = 229, + GetWet = 230, + SetWet = 231, + GetPub = 232, + GetKeyPrimary = 235, + SetKeyPrimary = 236, + GetAciArgs = 238, + SetAciArgs = 239, + UnsetCallback = 240, + SetCallback = 241, + GetRadar = 242, + SetRadar = 243, + SetSpectManagment = 244, + GetSpectManagment = 245, + WdsGetRemoteHwaddr = 246, + WdsGetWpaSup = 247, + SetCsScanTimer = 248, + GetCsScanTimer = 249, + MeasureRequest = 250, + Init = 251, + SendQuiet = 252, + Keepalive = 253, + SendPwrConstraint = 254, + UpgradeStatus = 255, + CurrentPwr = 256, + GetScanPassiveTime = 257, + SetScanPassiveTime = 258, + LegacyLinkBehavior = 259, + GetChannelsInCountry = 260, + GetCountryList = 261, + GetVar = 262, + SetVar = 263, + NvramGet = 264, + NvramSet = 265, + NvramDump = 266, + Reboot = 267, + SetWsecPmk = 268, + GetAuthMode = 269, + SetAuthMode = 270, + GetWakeentry = 271, + SetWakeentry = 272, + NdconfigItem = 273, + Nvotpw = 274, + Otpw = 275, + IovBlockGet = 276, + IovModulesGet = 277, + SoftReset = 278, + GetAllowMode = 279, + SetAllowMode = 280, + GetDesiredBssid = 281, + SetDesiredBssid = 282, + DisassocMyap = 283, + GetNbands = 284, + GetBandstates = 285, + GetWlcBssInfo = 286, + GetAssocInfo = 287, + GetOidPhy = 288, + SetOidPhy = 289, + SetAssocTime = 290, + GetDesiredSsid = 291, + GetChanspec = 292, + GetAssocState = 293, + SetPhyState = 294, + GetScanPending = 295, + GetScanreqPending = 296, + GetPrevRoamReason = 297, + SetPrevRoamReason = 298, + GetBandstatesPi = 299, + GetPhyState = 300, + GetBssWpaRsn = 301, + GetBssWpa2Rsn = 302, + GetBssBcnTs = 303, + GetIntDisassoc = 304, + SetNumPeers = 305, + GetNumBss = 306, + GetWsecPmk = 318, + GetRandomBytes = 319, +} diff --git a/cyw43/src/control.rs b/cyw43/src/control.rs index 22c52bd96..48be772c0 100644 --- a/cyw43/src/control.rs +++ b/cyw43/src/control.rs @@ -109,7 +109,7 @@ impl<'a> Control<'a> { buf[0..8].copy_from_slice(b"clmload\x00"); buf[8..20].copy_from_slice(&header.to_bytes()); buf[20..][..chunk.len()].copy_from_slice(&chunk); - self.ioctl(IoctlType::Set, IOCTL_CMD_SET_VAR, 0, &mut buf[..8 + 12 + chunk.len()]) + self.ioctl(IoctlType::Set, Ioctl::SetVar, 0, &mut buf[..8 + 12 + chunk.len()]) .await; } @@ -145,7 +145,7 @@ impl<'a> Control<'a> { Timer::after_millis(100).await; // Set antenna to chip antenna - self.ioctl_set_u32(IOCTL_CMD_ANTDIV, 0, 0).await; + self.ioctl_set_u32(Ioctl::SetAntdiv, 0, 0).await; self.set_iovar_u32("bus:txglom", 0).await; Timer::after_millis(100).await; @@ -183,8 +183,8 @@ impl<'a> Control<'a> { Timer::after_millis(100).await; - self.ioctl_set_u32(110, 0, 1).await; // SET_GMODE = auto - self.ioctl_set_u32(142, 0, 0).await; // SET_BAND = any + self.ioctl_set_u32(Ioctl::SetGmode, 0, 1).await; // SET_GMODE = auto + self.ioctl_set_u32(Ioctl::SetBand, 0, 0).await; // SET_BAND = any Timer::after_millis(100).await; @@ -195,12 +195,12 @@ impl<'a> Control<'a> { /// Set the WiFi interface up. async fn up(&mut self) { - self.ioctl(IoctlType::Set, IOCTL_CMD_UP, 0, &mut []).await; + self.ioctl(IoctlType::Set, Ioctl::Up, 0, &mut []).await; } /// Set the interface down. async fn down(&mut self) { - self.ioctl(IoctlType::Set, IOCTL_CMD_DOWN, 0, &mut []).await; + self.ioctl(IoctlType::Set, Ioctl::Down, 0, &mut []).await; } /// Set power management mode. @@ -213,17 +213,17 @@ impl<'a> Control<'a> { self.set_iovar_u32("bcn_li_dtim", mode.dtim_period() as u32).await; self.set_iovar_u32("assoc_listen", mode.assoc() as u32).await; } - self.ioctl_set_u32(86, 0, mode_num).await; + self.ioctl_set_u32(Ioctl::SetPm, 0, mode_num).await; } /// Join an unprotected network with the provided ssid. pub async fn join_open(&mut self, ssid: &str) -> Result<(), Error> { self.set_iovar_u32("ampdu_ba_wsize", 8).await; - self.ioctl_set_u32(134, 0, 0).await; // wsec = open + self.ioctl_set_u32(Ioctl::SetWsec, 0, 0).await; // wsec = open self.set_iovar_u32x2("bsscfg:sup_wpa", 0, 0).await; - self.ioctl_set_u32(20, 0, 1).await; // set_infra = 1 - self.ioctl_set_u32(22, 0, 0).await; // set_auth = open (0) + self.ioctl_set_u32(Ioctl::SetInfra, 0, 1).await; // set_infra = 1 + self.ioctl_set_u32(Ioctl::SetAuth, 0, 0).await; // set_auth = open (0) let mut i = SsidInfo { len: ssid.len() as _, @@ -238,24 +238,19 @@ impl<'a> Control<'a> { async fn join_wpa2_passphrase_info(&mut self, ssid: &str, passphrase_info: &PassphraseInfo) -> Result<(), Error> { self.set_iovar_u32("ampdu_ba_wsize", 8).await; - self.ioctl_set_u32(134, 0, 4).await; // wsec = wpa2 + self.ioctl_set_u32(Ioctl::SetWsec, 0, 4).await; // wsec = open self.set_iovar_u32x2("bsscfg:sup_wpa", 0, 1).await; self.set_iovar_u32x2("bsscfg:sup_wpa2_eapver", 0, 0xFFFF_FFFF).await; self.set_iovar_u32x2("bsscfg:sup_wpa_tmo", 0, 2500).await; Timer::after_millis(100).await; - self.ioctl( - IoctlType::Set, - IOCTL_CMD_SET_PASSPHRASE, - 0, - &mut passphrase_info.to_bytes(), - ) - .await; // WLC_SET_WSEC_PMK + self.ioctl(IoctlType::Set, Ioctl::SetWsecPmk, 0, &mut passphrase_info.to_bytes()) + .await; // WLC_SET_WSEC_PMK - self.ioctl_set_u32(20, 0, 1).await; // set_infra = 1 - self.ioctl_set_u32(22, 0, 0).await; // set_auth = 0 (open) - self.ioctl_set_u32(165, 0, 0x80).await; // set_wpa_auth + self.ioctl_set_u32(Ioctl::SetInfra, 0, 1).await; // set_infra = 1 + self.ioctl_set_u32(Ioctl::SetAuth, 0, 0).await; // set_auth = 0 (open) + self.ioctl_set_u32(Ioctl::SetWpaAuth, 0, 0x80).await; let mut i = SsidInfo { len: ssid.len() as _, @@ -294,9 +289,7 @@ impl<'a> Control<'a> { // the actual join operation starts here // we make sure to enable events before so we don't miss any - // set_ssid - self.ioctl(IoctlType::Set, IOCTL_CMD_SET_SSID, 0, &mut i.to_bytes()) - .await; + self.ioctl(IoctlType::Set, Ioctl::SetSsid, 0, &mut i.to_bytes()).await; // to complete the join, we wait for a SET_SSID event // we also save the AUTH status for the user, it may be interesting @@ -357,7 +350,7 @@ impl<'a> Control<'a> { self.up().await; // Turn on AP mode - self.ioctl_set_u32(IOCTL_CMD_SET_AP, 0, 1).await; + self.ioctl_set_u32(Ioctl::SetAp, 0, 1).await; // Set SSID let mut i = SsidInfoWithIndex { @@ -371,7 +364,7 @@ impl<'a> Control<'a> { self.set_iovar("bsscfg:ssid", &i.to_bytes()).await; // Set channel number - self.ioctl_set_u32(IOCTL_CMD_SET_CHANNEL, 0, channel as u32).await; + self.ioctl_set_u32(Ioctl::SetChannel, 0, channel as u32).await; // Set security self.set_iovar_u32x2("bsscfg:wsec", 0, (security as u32) & 0xFF).await; @@ -388,7 +381,7 @@ impl<'a> Control<'a> { passphrase: [0; 64], }; pfi.passphrase[..passphrase.as_bytes().len()].copy_from_slice(passphrase.as_bytes()); - self.ioctl(IoctlType::Set, IOCTL_CMD_SET_PASSPHRASE, 0, &mut pfi.to_bytes()) + self.ioctl(IoctlType::Set, Ioctl::SetWsecPmk, 0, &mut pfi.to_bytes()) .await; } @@ -405,7 +398,7 @@ impl<'a> Control<'a> { self.set_iovar_u32x2("bss", 0, 0).await; // bss = BSS_DOWN // Turn off AP mode - self.ioctl_set_u32(IOCTL_CMD_SET_AP, 0, 0).await; + self.ioctl_set_u32(Ioctl::SetAp, 0, 0).await; // Temporarily set wifi down self.down().await; @@ -496,7 +489,7 @@ impl<'a> Control<'a> { buf[name.len() + 1..][..val.len()].copy_from_slice(val); let total_len = name.len() + 1 + val.len(); - self.ioctl(IoctlType::Set, IOCTL_CMD_SET_VAR, 0, &mut buf[..total_len]) + self.ioctl(IoctlType::Set, Ioctl::SetVar, 0, &mut buf[..total_len]) .await; } @@ -510,7 +503,7 @@ impl<'a> Control<'a> { let total_len = max(name.len() + 1, res.len()); let res_len = self - .ioctl(IoctlType::Get, IOCTL_CMD_GET_VAR, 0, &mut buf[..total_len]) + .ioctl(IoctlType::Get, Ioctl::GetVar, 0, &mut buf[..total_len]) .await; let out_len = min(res.len(), res_len); @@ -518,12 +511,12 @@ impl<'a> Control<'a> { out_len } - async fn ioctl_set_u32(&mut self, cmd: u32, iface: u32, val: u32) { + async fn ioctl_set_u32(&mut self, cmd: Ioctl, iface: u32, val: u32) { let mut buf = val.to_le_bytes(); self.ioctl(IoctlType::Set, cmd, iface, &mut buf).await; } - async fn ioctl(&mut self, kind: IoctlType, cmd: u32, iface: u32, buf: &mut [u8]) -> usize { + async fn ioctl(&mut self, kind: IoctlType, cmd: Ioctl, iface: u32, buf: &mut [u8]) -> usize { struct CancelOnDrop<'a>(&'a IoctlState); impl CancelOnDrop<'_> { @@ -615,7 +608,7 @@ impl<'a> Control<'a> { } /// Leave the wifi, with which we are currently associated. pub async fn leave(&mut self) { - self.ioctl(IoctlType::Set, IOCTL_CMD_DISASSOC, 0, &mut []).await; + self.ioctl(IoctlType::Set, Ioctl::Disassoc, 0, &mut []).await; info!("Disassociated") } diff --git a/cyw43/src/ioctl.rs b/cyw43/src/ioctl.rs index 61524c274..3186370cc 100644 --- a/cyw43/src/ioctl.rs +++ b/cyw43/src/ioctl.rs @@ -4,6 +4,7 @@ use core::task::{Poll, Waker}; use embassy_sync::waitqueue::WakerRegistration; +use crate::consts::Ioctl; use crate::fmt::Bytes; #[derive(Clone, Copy)] @@ -16,7 +17,7 @@ pub enum IoctlType { pub struct PendingIoctl { pub buf: *mut [u8], pub kind: IoctlType, - pub cmd: u32, + pub cmd: Ioctl, pub iface: u32, } @@ -101,7 +102,7 @@ impl IoctlState { self.state.set(IoctlStateInner::Done { resp_len: 0 }); } - pub async fn do_ioctl(&self, kind: IoctlType, cmd: u32, iface: u32, buf: &mut [u8]) -> usize { + pub async fn do_ioctl(&self, kind: IoctlType, cmd: Ioctl, iface: u32, buf: &mut [u8]) -> usize { self.state .set(IoctlStateInner::Pending(PendingIoctl { buf, kind, cmd, iface })); self.wake_runner(); diff --git a/cyw43/src/runner.rs b/cyw43/src/runner.rs index 959718341..77910b281 100644 --- a/cyw43/src/runner.rs +++ b/cyw43/src/runner.rs @@ -560,7 +560,7 @@ where self.sdpcm_seq != self.sdpcm_seq_max && self.sdpcm_seq_max.wrapping_sub(self.sdpcm_seq) & 0x80 == 0 } - async fn send_ioctl(&mut self, kind: IoctlType, cmd: u32, iface: u32, data: &[u8], buf: &mut [u32; 512]) { + async fn send_ioctl(&mut self, kind: IoctlType, cmd: Ioctl, iface: u32, data: &[u8], buf: &mut [u32; 512]) { let buf8 = slice8_mut(buf); let total_len = SdpcmHeader::SIZE + CdcHeader::SIZE + data.len(); @@ -582,7 +582,7 @@ where }; let cdc_header = CdcHeader { - cmd: cmd, + cmd: cmd as u32, len: data.len() as _, flags: kind as u16 | (iface as u16) << 12, id: self.ioctl_id, From 6b21f6d3d1f48bfa722d648918e06b627350bbff Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 9 Sep 2024 01:03:41 +0200 Subject: [PATCH 0106/1217] cyw43: log ioctls. --- cyw43/src/control.rs | 16 ++++++++++++---- cyw43/src/ioctl.rs | 2 +- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/cyw43/src/control.rs b/cyw43/src/control.rs index 48be772c0..97dcb4d09 100644 --- a/cyw43/src/control.rs +++ b/cyw43/src/control.rs @@ -481,7 +481,7 @@ impl<'a> Control<'a> { } async fn set_iovar_v(&mut self, name: &str, val: &[u8]) { - debug!("set {} = {:02x}", name, Bytes(val)); + debug!("iovar set {} = {:02x}", name, Bytes(val)); let mut buf = [0; BUFSIZE]; buf[..name.len()].copy_from_slice(name.as_bytes()); @@ -489,13 +489,13 @@ impl<'a> Control<'a> { buf[name.len() + 1..][..val.len()].copy_from_slice(val); let total_len = name.len() + 1 + val.len(); - self.ioctl(IoctlType::Set, Ioctl::SetVar, 0, &mut buf[..total_len]) + self.ioctl_inner(IoctlType::Set, Ioctl::SetVar, 0, &mut buf[..total_len]) .await; } // TODO this is not really working, it always returns all zeros. async fn get_iovar(&mut self, name: &str, res: &mut [u8]) -> usize { - debug!("get {}", name); + debug!("iovar get {}", name); let mut buf = [0; 64]; buf[..name.len()].copy_from_slice(name.as_bytes()); @@ -503,7 +503,7 @@ impl<'a> Control<'a> { let total_len = max(name.len() + 1, res.len()); let res_len = self - .ioctl(IoctlType::Get, Ioctl::GetVar, 0, &mut buf[..total_len]) + .ioctl_inner(IoctlType::Get, Ioctl::GetVar, 0, &mut buf[..total_len]) .await; let out_len = min(res.len(), res_len); @@ -517,6 +517,14 @@ impl<'a> Control<'a> { } async fn ioctl(&mut self, kind: IoctlType, cmd: Ioctl, iface: u32, buf: &mut [u8]) -> usize { + if kind == IoctlType::Set { + debug!("ioctl set {:?} iface {} = {:02x}", cmd, iface, Bytes(buf)); + } + let n = self.ioctl_inner(kind, cmd, iface, buf).await; + n + } + + async fn ioctl_inner(&mut self, kind: IoctlType, cmd: Ioctl, iface: u32, buf: &mut [u8]) -> usize { struct CancelOnDrop<'a>(&'a IoctlState); impl CancelOnDrop<'_> { diff --git a/cyw43/src/ioctl.rs b/cyw43/src/ioctl.rs index 3186370cc..f8b2d9aba 100644 --- a/cyw43/src/ioctl.rs +++ b/cyw43/src/ioctl.rs @@ -7,7 +7,7 @@ use embassy_sync::waitqueue::WakerRegistration; use crate::consts::Ioctl; use crate::fmt::Bytes; -#[derive(Clone, Copy)] +#[derive(Clone, Copy, PartialEq, Eq)] pub enum IoctlType { Get = 0, Set = 2, From b9a1aaea5b89bd5689796bdfa4227353ee8a452b Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 9 Sep 2024 01:09:15 +0200 Subject: [PATCH 0107/1217] cyw43: add support for WPA3 and more extensive security options. --- cyw43/src/consts.rs | 15 ++ cyw43/src/control.rs | 196 ++++++++++++++++++------- cyw43/src/lib.rs | 4 +- cyw43/src/structs.rs | 9 ++ examples/rp/src/bin/wifi_tcp_server.rs | 7 +- examples/rp/src/bin/wifi_webrequest.rs | 7 +- tests/rp/src/bin/cyw43-perf.rs | 6 +- 7 files changed, 181 insertions(+), 63 deletions(-) diff --git a/cyw43/src/consts.rs b/cyw43/src/consts.rs index d47e5097a..c3f0dbfd8 100644 --- a/cyw43/src/consts.rs +++ b/cyw43/src/consts.rs @@ -653,3 +653,18 @@ pub(crate) enum Ioctl { GetWsecPmk = 318, GetRandomBytes = 319, } + +pub(crate) const WSEC_TKIP: u32 = 0x02; +pub(crate) const WSEC_AES: u32 = 0x04; + +pub(crate) const AUTH_OPEN: u32 = 0x00; +pub(crate) const AUTH_SAE: u32 = 0x03; + +pub(crate) const MFP_NONE: u32 = 0; +pub(crate) const MFP_CAPABLE: u32 = 1; +pub(crate) const MFP_REQUIRED: u32 = 2; + +pub(crate) const WPA_AUTH_DISABLED: u32 = 0x0000; +pub(crate) const WPA_AUTH_WPA_PSK: u32 = 0x0004; +pub(crate) const WPA_AUTH_WPA2_PSK: u32 = 0x0080; +pub(crate) const WPA_AUTH_WPA3_SAE_PSK: u32 = 0x40000; diff --git a/cyw43/src/control.rs b/cyw43/src/control.rs index 97dcb4d09..071ba88e4 100644 --- a/cyw43/src/control.rs +++ b/cyw43/src/control.rs @@ -35,7 +35,7 @@ pub struct Control<'a> { ioctl_state: &'a IoctlState, } -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum ScanType { Active, @@ -43,8 +43,9 @@ pub enum ScanType { } /// Scan options. -#[derive(Clone)] +#[derive(Clone, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[non_exhaustive] pub struct ScanOptions { /// SSID to scan for. pub ssid: Option>, @@ -74,6 +75,79 @@ impl Default for ScanOptions { } } +/// Authentication type, used in [`JoinOptions::auth`]. +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum JoinAuth { + /// Open network + Open, + /// WPA only + Wpa, + /// WPA2 only + Wpa2, + /// WPA3 only + Wpa3, + /// WPA2 + WPA3 + Wpa2Wpa3, +} + +/// Options for [`Control::join`]. +#[derive(Clone, Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[non_exhaustive] +pub struct JoinOptions<'a> { + /// Authentication type. Default `Wpa2Wpa3`. + pub auth: JoinAuth, + /// Enable TKIP encryption. Default false. + pub cipher_tkip: bool, + /// Enable AES encryption. Default true. + pub cipher_aes: bool, + /// Passphrase. Default empty. + pub passphrase: &'a [u8], + /// If false, `passphrase` is the human-readable passphrase string. + /// If true, `passphrase` is the result of applying the PBKDF2 hash to the + /// passphrase string. This makes it possible to avoid storing unhashed passwords. + /// + /// This is not compatible with WPA3. + /// Default false. + pub passphrase_is_prehashed: bool, +} + +impl<'a> JoinOptions<'a> { + /// Create a new `JoinOptions` for joining open networks. + pub fn new_open() -> Self { + Self { + auth: JoinAuth::Open, + cipher_tkip: false, + cipher_aes: false, + passphrase: &[], + passphrase_is_prehashed: false, + } + } + + /// Create a new `JoinOptions` for joining encrypted networks. + /// + /// Defaults to supporting WPA2+WPA3 with AES only, you may edit + /// the returned options to change this. + pub fn new(passphrase: &'a [u8]) -> Self { + let mut this = Self::default(); + this.passphrase = passphrase; + this + } +} + +impl<'a> Default for JoinOptions<'a> { + fn default() -> Self { + Self { + auth: JoinAuth::Wpa2Wpa3, + cipher_tkip: false, + cipher_aes: true, + passphrase: &[], + passphrase_is_prehashed: false, + } + } +} + impl<'a> Control<'a> { pub(crate) fn new(state_ch: ch::StateRunner<'a>, event_sub: &'a Events, ioctl_state: &'a IoctlState) -> Self { Self { @@ -217,13 +291,70 @@ impl<'a> Control<'a> { } /// Join an unprotected network with the provided ssid. - pub async fn join_open(&mut self, ssid: &str) -> Result<(), Error> { + pub async fn join(&mut self, ssid: &str, options: JoinOptions<'_>) -> Result<(), Error> { self.set_iovar_u32("ampdu_ba_wsize", 8).await; - self.ioctl_set_u32(Ioctl::SetWsec, 0, 0).await; // wsec = open - self.set_iovar_u32x2("bsscfg:sup_wpa", 0, 0).await; - self.ioctl_set_u32(Ioctl::SetInfra, 0, 1).await; // set_infra = 1 - self.ioctl_set_u32(Ioctl::SetAuth, 0, 0).await; // set_auth = open (0) + if options.auth == JoinAuth::Open { + self.ioctl_set_u32(Ioctl::SetWsec, 0, 0).await; + self.set_iovar_u32x2("bsscfg:sup_wpa", 0, 0).await; + self.ioctl_set_u32(Ioctl::SetInfra, 0, 1).await; + self.ioctl_set_u32(Ioctl::SetAuth, 0, 0).await; + self.ioctl_set_u32(Ioctl::SetWpaAuth, 0, WPA_AUTH_DISABLED).await; + } else { + let mut wsec = 0; + if options.cipher_aes { + wsec |= WSEC_AES; + } + if options.cipher_tkip { + wsec |= WSEC_TKIP; + } + self.ioctl_set_u32(Ioctl::SetWsec, 0, wsec).await; + + self.set_iovar_u32x2("bsscfg:sup_wpa", 0, 1).await; + self.set_iovar_u32x2("bsscfg:sup_wpa2_eapver", 0, 0xFFFF_FFFF).await; + self.set_iovar_u32x2("bsscfg:sup_wpa_tmo", 0, 2500).await; + + Timer::after_millis(100).await; + + let (wpa12, wpa3, auth, mfp, wpa_auth) = match options.auth { + JoinAuth::Open => unreachable!(), + JoinAuth::Wpa => (true, false, AUTH_OPEN, MFP_NONE, WPA_AUTH_WPA_PSK), + JoinAuth::Wpa2 => (true, false, AUTH_OPEN, MFP_CAPABLE, WPA_AUTH_WPA2_PSK), + JoinAuth::Wpa3 => (false, true, AUTH_SAE, MFP_REQUIRED, WPA_AUTH_WPA3_SAE_PSK), + JoinAuth::Wpa2Wpa3 => (true, true, AUTH_SAE, MFP_CAPABLE, WPA_AUTH_WPA3_SAE_PSK), + }; + + if wpa12 { + let mut flags = 0; + if !options.passphrase_is_prehashed { + flags |= 1; + } + let mut pfi = PassphraseInfo { + len: options.passphrase.len() as _, + flags, + passphrase: [0; 64], + }; + pfi.passphrase[..options.passphrase.len()].copy_from_slice(options.passphrase); + Timer::after_millis(3).await; + self.ioctl(IoctlType::Set, Ioctl::SetWsecPmk, 0, &mut pfi.to_bytes()) + .await; + } + + if wpa3 { + let mut pfi = SaePassphraseInfo { + len: options.passphrase.len() as _, + passphrase: [0; 128], + }; + pfi.passphrase[..options.passphrase.len()].copy_from_slice(options.passphrase); + Timer::after_millis(3).await; + self.set_iovar("sae_password", &pfi.to_bytes()).await; + } + + self.ioctl_set_u32(Ioctl::SetInfra, 0, 1).await; + self.ioctl_set_u32(Ioctl::SetAuth, 0, auth).await; + self.set_iovar_u32("mfp", mfp).await; + self.ioctl_set_u32(Ioctl::SetWpaAuth, 0, wpa_auth).await; + } let mut i = SsidInfo { len: ssid.len() as _, @@ -234,55 +365,6 @@ impl<'a> Control<'a> { self.wait_for_join(i).await } - /// Join a protected network with the provided ssid and [`PassphraseInfo`]. - async fn join_wpa2_passphrase_info(&mut self, ssid: &str, passphrase_info: &PassphraseInfo) -> Result<(), Error> { - self.set_iovar_u32("ampdu_ba_wsize", 8).await; - - self.ioctl_set_u32(Ioctl::SetWsec, 0, 4).await; // wsec = open - self.set_iovar_u32x2("bsscfg:sup_wpa", 0, 1).await; - self.set_iovar_u32x2("bsscfg:sup_wpa2_eapver", 0, 0xFFFF_FFFF).await; - self.set_iovar_u32x2("bsscfg:sup_wpa_tmo", 0, 2500).await; - - Timer::after_millis(100).await; - - self.ioctl(IoctlType::Set, Ioctl::SetWsecPmk, 0, &mut passphrase_info.to_bytes()) - .await; // WLC_SET_WSEC_PMK - - self.ioctl_set_u32(Ioctl::SetInfra, 0, 1).await; // set_infra = 1 - self.ioctl_set_u32(Ioctl::SetAuth, 0, 0).await; // set_auth = 0 (open) - self.ioctl_set_u32(Ioctl::SetWpaAuth, 0, 0x80).await; - - let mut i = SsidInfo { - len: ssid.len() as _, - ssid: [0; 32], - }; - i.ssid[..ssid.len()].copy_from_slice(ssid.as_bytes()); - - self.wait_for_join(i).await - } - - /// Join a protected network with the provided ssid and passphrase. - pub async fn join_wpa2(&mut self, ssid: &str, passphrase: &str) -> Result<(), Error> { - let mut pfi = PassphraseInfo { - len: passphrase.len() as _, - flags: 1, - passphrase: [0; 64], - }; - pfi.passphrase[..passphrase.len()].copy_from_slice(passphrase.as_bytes()); - self.join_wpa2_passphrase_info(ssid, &pfi).await - } - - /// Join a protected network with the provided ssid and precomputed PSK. - pub async fn join_wpa2_psk(&mut self, ssid: &str, psk: &[u8; 32]) -> Result<(), Error> { - let mut pfi = PassphraseInfo { - len: psk.len() as _, - flags: 0, - passphrase: [0; 64], - }; - pfi.passphrase[..psk.len()].copy_from_slice(psk); - self.join_wpa2_passphrase_info(ssid, &pfi).await - } - async fn wait_for_join(&mut self, i: SsidInfo) -> Result<(), Error> { self.events.mask.enable(&[Event::SET_SSID, Event::AUTH]); let mut subscriber = self.events.queue.subscriber().unwrap(); @@ -477,7 +559,7 @@ impl<'a> Control<'a> { } async fn set_iovar(&mut self, name: &str, val: &[u8]) { - self.set_iovar_v::<64>(name, val).await + self.set_iovar_v::<196>(name, val).await } async fn set_iovar_v(&mut self, name: &str, val: &[u8]) { diff --git a/cyw43/src/lib.rs b/cyw43/src/lib.rs index efeb3f313..6b71c18e6 100644 --- a/cyw43/src/lib.rs +++ b/cyw43/src/lib.rs @@ -28,7 +28,9 @@ use ioctl::IoctlState; use crate::bus::Bus; pub use crate::bus::SpiBusCyw43; -pub use crate::control::{AddMulticastAddressError, Control, Error as ControlError, ScanOptions, Scanner}; +pub use crate::control::{ + AddMulticastAddressError, Control, Error as ControlError, JoinAuth, JoinOptions, ScanOptions, Scanner, +}; pub use crate::runner::Runner; pub use crate::structs::BssInfo; diff --git a/cyw43/src/structs.rs b/cyw43/src/structs.rs index ae7ef6038..81ae6a98d 100644 --- a/cyw43/src/structs.rs +++ b/cyw43/src/structs.rs @@ -394,6 +394,15 @@ pub struct PassphraseInfo { } impl_bytes!(PassphraseInfo); +#[derive(Clone, Copy)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[repr(C)] +pub struct SaePassphraseInfo { + pub len: u16, + pub passphrase: [u8; 128], +} +impl_bytes!(SaePassphraseInfo); + #[derive(Clone, Copy)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[repr(C)] diff --git a/examples/rp/src/bin/wifi_tcp_server.rs b/examples/rp/src/bin/wifi_tcp_server.rs index 61eeb82f7..b2950d98a 100644 --- a/examples/rp/src/bin/wifi_tcp_server.rs +++ b/examples/rp/src/bin/wifi_tcp_server.rs @@ -7,6 +7,7 @@ use core::str::from_utf8; +use cyw43::JoinOptions; use cyw43_pio::PioSpi; use defmt::*; use embassy_executor::Spawner; @@ -95,8 +96,10 @@ async fn main(spawner: Spawner) { unwrap!(spawner.spawn(net_task(stack))); loop { - //control.join_open(WIFI_NETWORK).await; - match control.join_wpa2(WIFI_NETWORK, WIFI_PASSWORD).await { + match control + .join(WIFI_NETWORK, JoinOptions::new(WIFI_PASSWORD.as_bytes())) + .await + { Ok(_) => break, Err(err) => { info!("join failed with status={}", err.status); diff --git a/examples/rp/src/bin/wifi_webrequest.rs b/examples/rp/src/bin/wifi_webrequest.rs index 889371241..b43be8905 100644 --- a/examples/rp/src/bin/wifi_webrequest.rs +++ b/examples/rp/src/bin/wifi_webrequest.rs @@ -7,6 +7,7 @@ use core::str::from_utf8; +use cyw43::JoinOptions; use cyw43_pio::PioSpi; use defmt::*; use embassy_executor::Spawner; @@ -98,8 +99,10 @@ async fn main(spawner: Spawner) { unwrap!(spawner.spawn(net_task(stack))); loop { - //match control.join_open(WIFI_NETWORK).await { // for open networks - match control.join_wpa2(WIFI_NETWORK, WIFI_PASSWORD).await { + match control + .join(WIFI_NETWORK, JoinOptions::new(WIFI_PASSWORD.as_bytes())) + .await + { Ok(_) => break, Err(err) => { info!("join failed with status={}", err.status); diff --git a/tests/rp/src/bin/cyw43-perf.rs b/tests/rp/src/bin/cyw43-perf.rs index 38fbde7c1..11c8aa58c 100644 --- a/tests/rp/src/bin/cyw43-perf.rs +++ b/tests/rp/src/bin/cyw43-perf.rs @@ -2,6 +2,7 @@ #![no_main] teleprobe_meta::target!(b"rpi-pico"); +use cyw43::JoinOptions; use cyw43_pio::PioSpi; use defmt::{panic, *}; use embassy_executor::Spawner; @@ -81,7 +82,10 @@ async fn main(spawner: Spawner) { unwrap!(spawner.spawn(net_task(stack))); loop { - match control.join_wpa2(WIFI_NETWORK, WIFI_PASSWORD).await { + match control + .join(WIFI_NETWORK, JoinOptions::new(WIFI_PASSWORD.as_bytes())) + .await + { Ok(_) => break, Err(err) => { panic!("join failed with status={}", err.status); From 6af1cb7a20fe15750b353e2e6af6832786f8c065 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Mon, 9 Sep 2024 15:45:15 +0200 Subject: [PATCH 0108/1217] Use TX_BUF_SIZE matching MTU --- embassy-net-nrf91/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-net-nrf91/src/lib.rs b/embassy-net-nrf91/src/lib.rs index d8cbe47fc..60cdc38c6 100644 --- a/embassy-net-nrf91/src/lib.rs +++ b/embassy-net-nrf91/src/lib.rs @@ -279,7 +279,7 @@ impl State { } const TX_BUF_COUNT: usize = 4; -const TX_BUF_SIZE: usize = 1024; +const TX_BUF_SIZE: usize = 1500; struct TraceChannelInfo { ptr: *mut TraceChannel, From e698fbe598def25a1aa3e2a2625144817f2fa12d Mon Sep 17 00:00:00 2001 From: elagil Date: Tue, 10 Sep 2024 21:33:31 +0200 Subject: [PATCH 0109/1217] fix: pull-down clock/data lines for receive --- embassy-stm32/src/sai/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/sai/mod.rs b/embassy-stm32/src/sai/mod.rs index 6bf184dd8..63f48ace0 100644 --- a/embassy-stm32/src/sai/mod.rs +++ b/embassy-stm32/src/sai/mod.rs @@ -661,12 +661,12 @@ fn get_af_types(mode: Mode, tx_rx: TxRx) -> (AfType, AfType) { //sd is defined by tx/rx mode match tx_rx { TxRx::Transmitter => AfType::output(OutputType::PushPull, Speed::VeryHigh), - TxRx::Receiver => AfType::input(Pull::None), + TxRx::Receiver => AfType::input(Pull::Down), // Ensure mute level when no input is connected. }, //clocks (mclk, sck and fs) are defined by master/slave match mode { Mode::Master => AfType::output(OutputType::PushPull, Speed::VeryHigh), - Mode::Slave => AfType::input(Pull::None), + Mode::Slave => AfType::input(Pull::Down), // Ensure no clocks when no input is connected. }, ) } From a1c9a2e8bd83852d774255c82e71d2054c7c02e4 Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Thu, 29 Aug 2024 16:18:43 -0400 Subject: [PATCH 0110/1217] First working draft of a lptim driver This driver is able to PWM a pin --- embassy-stm32/build.rs | 2 + embassy-stm32/src/lib.rs | 2 + embassy-stm32/src/lptim/mod.rs | 145 ++++++++++++++++++++++++++++++ embassy-stm32/src/lptim/traits.rs | 95 ++++++++++++++++++++ 4 files changed, 244 insertions(+) create mode 100644 embassy-stm32/src/lptim/mod.rs create mode 100644 embassy-stm32/src/lptim/traits.rs diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 1984a1420..33985a3f4 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -1015,6 +1015,8 @@ fn main() { (("hrtim", "CHE2"), quote!(crate::hrtim::ChannelEComplementaryPin)), (("hrtim", "CHF1"), quote!(crate::hrtim::ChannelFPin)), (("hrtim", "CHF2"), quote!(crate::hrtim::ChannelFComplementaryPin)), + (("lptim", "CH1"), quote!(crate::lptim::Channel1Pin)), + (("lptim", "CH2"), quote!(crate::lptim::Channel1Pin)), (("sdmmc", "CK"), quote!(crate::sdmmc::CkPin)), (("sdmmc", "CMD"), quote!(crate::sdmmc::CmdPin)), (("sdmmc", "D0"), quote!(crate::sdmmc::D0Pin)), diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 98695e738..451f595e0 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -89,6 +89,8 @@ pub mod i2s; pub mod ipcc; #[cfg(feature = "low-power")] pub mod low_power; +#[cfg(lptim)] +pub mod lptim; #[cfg(ltdc)] pub mod ltdc; #[cfg(opamp)] diff --git a/embassy-stm32/src/lptim/mod.rs b/embassy-stm32/src/lptim/mod.rs new file mode 100644 index 000000000..3cf95149e --- /dev/null +++ b/embassy-stm32/src/lptim/mod.rs @@ -0,0 +1,145 @@ +//! Low-power timer (LPTIM) + +mod traits; + +use core::marker::PhantomData; + +use embassy_hal_internal::{into_ref, PeripheralRef}; +pub use traits::Instance; + +use crate::gpio::{AfType, AnyPin, OutputType, Speed}; +// use crate::time::Hertz; +use crate::{rcc, Peripheral}; + +/// LPTIM master instance. +pub struct Master { + phantom: PhantomData, +} + +/// LPTIM channel 1 instance. +pub struct Ch1 { + phantom: PhantomData, +} + +/// LPTIM channel 2 instance. +pub struct Ch2 { + phantom: PhantomData, +} + +trait SealedChannel { + fn raw() -> usize; +} + +/// channel instance trait. +#[allow(private_bounds)] +pub trait Channel: SealedChannel {} + +/// LPTIM PWM pin. +pub struct PwmPin<'d, T, C> { + _pin: PeripheralRef<'d, AnyPin>, + phantom: PhantomData<(T, C)>, +} + +macro_rules! channel_impl { + ($new_chx:ident, $channel:tt, $ch_num:expr, $pin_trait:ident) => { + impl<'d, T: Instance> PwmPin<'d, T, $channel> { + #[doc = concat!("Create a new ", stringify!($channel), " PWM pin instance.")] + pub fn $new_chx(pin: impl Peripheral

> + 'd) -> Self { + into_ref!(pin); + critical_section::with(|_| { + pin.set_low(); + pin.set_as_af( + pin.af_num(), + AfType::output(OutputType::PushPull, Speed::VeryHigh), + ); + }); + PwmPin { + _pin: pin.map_into(), + phantom: PhantomData, + } + } + } + + impl SealedChannel for $channel { + fn raw() -> usize { + $ch_num + } + } + impl Channel for $channel {} + }; +} + +channel_impl!(new_ch1, Ch1, 0, Channel1Pin); +channel_impl!(new_ch2, Ch2, 1, Channel2Pin); + +/// Struct used to divide a high resolution timer into multiple channels +pub struct Pwm<'d, T: Instance> { + _inner: PeripheralRef<'d, T>, + /// Master instance. + pub master: Master, + /// Channel 1. + pub ch_1: Ch1, + /// Channel 2. + pub ch_2: Ch2, +} + +impl<'d, T: Instance> Pwm<'d, T> { + /// Create a new LPTIM driver. + /// + /// This splits the LPTIM into its constituent parts, which you can then use individually. + pub fn new( + tim: impl Peripheral

+ 'd, + _ch1: Option>>, + _ch2: Option>>, + ) -> Self { + Self::new_inner(tim) + } + + fn new_inner(tim: impl Peripheral

+ 'd) -> Self { + into_ref!(tim); + + rcc::enable_and_reset::(); + + T::regs().cr().modify(|w| w.set_enable(true)); + + // Set frequency. Should be configurable. + // By default, 16MHz. We want 440Hz. + // That's 36363 cycles + T::regs().arr().write_value(stm32_metapac::lptim::regs::Arr(36363)); + + // Set duty cycle. Should be configurable. Should take care of channel too (only Ch1 now) + T::regs().ccr(0).write_value(stm32_metapac::lptim::regs::Ccr(18181)); + + // Enable channel as PWM. Default state anyway. Implement later. + // T::regs().ccmr().modify(|w| { + // w.set_ccsel(0, 0); + // w.set_ccsel(1, 0); + // }) + + // Enable output on pins. Should care about the channels! + T::regs().ccmr().modify(|w| { + w.set_cce(0, true); + w.set_cce(1, true); + }); + + Self { + _inner: tim, + master: Master { phantom: PhantomData }, + ch_1: Ch1 { phantom: PhantomData }, + ch_2: Ch2 { phantom: PhantomData }, + } + } + + /// Start + pub fn start(&mut self) { + T::regs().cr().modify(|w| w.set_cntstrt(true)); + } + + /// Stop + pub fn stop(&mut self) { + T::regs().cr().modify(|w| w.set_cntstrt(false)); + } +} + +pin_trait!(Channel1Pin, Instance); +pin_trait!(Channel2Pin, Instance); diff --git a/embassy-stm32/src/lptim/traits.rs b/embassy-stm32/src/lptim/traits.rs new file mode 100644 index 000000000..a8f890a78 --- /dev/null +++ b/embassy-stm32/src/lptim/traits.rs @@ -0,0 +1,95 @@ +use crate::rcc::RccPeripheral; +use crate::time::Hertz; + +#[repr(u8)] +#[derive(Clone, Copy)] +pub(crate) enum Prescaler { + Div1 = 1, + Div2 = 2, + Div4 = 4, + Div8 = 8, + Div16 = 16, + Div32 = 32, + Div64 = 64, + Div128 = 128, +} + +impl From for u8 { + fn from(val: Prescaler) -> Self { + match val { + Prescaler::Div1 => 0b000, + Prescaler::Div2 => 0b001, + Prescaler::Div4 => 0b010, + Prescaler::Div8 => 0b011, + Prescaler::Div16 => 0b100, + Prescaler::Div32 => 0b101, + Prescaler::Div64 => 0b110, + Prescaler::Div128 => 0b111, + } + } +} + +impl From for Prescaler { + fn from(val: u8) -> Self { + match val { + 0b000 => Prescaler::Div1, + 0b001 => Prescaler::Div2, + 0b010 => Prescaler::Div4, + 0b011 => Prescaler::Div8, + 0b100 => Prescaler::Div16, + 0b101 => Prescaler::Div32, + 0b110 => Prescaler::Div64, + 0b111 => Prescaler::Div128, + _ => unreachable!(), + } + } +} + +impl Prescaler { + pub fn compute_min_high_res(val: u32) -> Self { + *[ + Prescaler::Div1, + Prescaler::Div2, + Prescaler::Div4, + Prescaler::Div8, + Prescaler::Div16, + Prescaler::Div32, + Prescaler::Div64, + Prescaler::Div128, + ] + .iter() + .skip_while(|psc| **psc as u32 <= val) + .next() + .unwrap() + } + + pub fn compute_min_low_res(val: u32) -> Self { + *[Prescaler::Div32, Prescaler::Div64, Prescaler::Div128] + .iter() + .skip_while(|psc| **psc as u32 <= val) + .next() + .unwrap() + } +} + +pub(crate) trait SealedInstance: RccPeripheral { + fn regs() -> crate::pac::lptim::LptimAdv; +} + +/// LPTIM instance trait. +#[allow(private_bounds)] +pub trait Instance: SealedInstance + 'static {} + +foreach_interrupt! { + ($inst:ident, lptim, LPTIM_ADV, UP, $irq:ident) => { + impl SealedInstance for crate::peripherals::$inst { + fn regs() -> crate::pac::lptim::LptimAdv { + crate::pac::$inst + } + } + + impl Instance for crate::peripherals::$inst { + + } + }; +} From 3b8859653e4028c194ceed9432a4f76c3c856816 Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Wed, 4 Sep 2024 14:46:35 -0400 Subject: [PATCH 0111/1217] stm32: Clean up the lptim driver --- embassy-stm32/src/lptim/mod.rs | 166 +++++------------------ embassy-stm32/src/lptim/pwm.rs | 122 +++++++++++++++++ embassy-stm32/src/lptim/timer.rs | 212 ++++++++++++++++++++++++++++++ embassy-stm32/src/lptim/traits.rs | 95 ------------- 4 files changed, 369 insertions(+), 226 deletions(-) create mode 100644 embassy-stm32/src/lptim/pwm.rs create mode 100644 embassy-stm32/src/lptim/timer.rs delete mode 100644 embassy-stm32/src/lptim/traits.rs diff --git a/embassy-stm32/src/lptim/mod.rs b/embassy-stm32/src/lptim/mod.rs index 3cf95149e..baedf9fe2 100644 --- a/embassy-stm32/src/lptim/mod.rs +++ b/embassy-stm32/src/lptim/mod.rs @@ -1,145 +1,49 @@ //! Low-power timer (LPTIM) -mod traits; +pub mod pwm; +pub mod timer; -use core::marker::PhantomData; +use crate::rcc::RccPeripheral; -use embassy_hal_internal::{into_ref, PeripheralRef}; -pub use traits::Instance; - -use crate::gpio::{AfType, AnyPin, OutputType, Speed}; -// use crate::time::Hertz; -use crate::{rcc, Peripheral}; - -/// LPTIM master instance. -pub struct Master { - phantom: PhantomData, -} - -/// LPTIM channel 1 instance. -pub struct Ch1 { - phantom: PhantomData, -} - -/// LPTIM channel 2 instance. -pub struct Ch2 { - phantom: PhantomData, -} - -trait SealedChannel { - fn raw() -> usize; -} - -/// channel instance trait. -#[allow(private_bounds)] -pub trait Channel: SealedChannel {} - -/// LPTIM PWM pin. -pub struct PwmPin<'d, T, C> { - _pin: PeripheralRef<'d, AnyPin>, - phantom: PhantomData<(T, C)>, -} - -macro_rules! channel_impl { - ($new_chx:ident, $channel:tt, $ch_num:expr, $pin_trait:ident) => { - impl<'d, T: Instance> PwmPin<'d, T, $channel> { - #[doc = concat!("Create a new ", stringify!($channel), " PWM pin instance.")] - pub fn $new_chx(pin: impl Peripheral

> + 'd) -> Self { - into_ref!(pin); - critical_section::with(|_| { - pin.set_low(); - pin.set_as_af( - pin.af_num(), - AfType::output(OutputType::PushPull, Speed::VeryHigh), - ); - }); - PwmPin { - _pin: pin.map_into(), - phantom: PhantomData, - } - } - } - - impl SealedChannel for $channel { - fn raw() -> usize { - $ch_num - } - } - impl Channel for $channel {} - }; -} - -channel_impl!(new_ch1, Ch1, 0, Channel1Pin); -channel_impl!(new_ch2, Ch2, 1, Channel2Pin); - -/// Struct used to divide a high resolution timer into multiple channels -pub struct Pwm<'d, T: Instance> { - _inner: PeripheralRef<'d, T>, - /// Master instance. - pub master: Master, +/// Timer channel. +#[derive(Clone, Copy)] +pub enum Channel { /// Channel 1. - pub ch_1: Ch1, + Ch1, /// Channel 2. - pub ch_2: Ch2, + Ch2, } -impl<'d, T: Instance> Pwm<'d, T> { - /// Create a new LPTIM driver. - /// - /// This splits the LPTIM into its constituent parts, which you can then use individually. - pub fn new( - tim: impl Peripheral

+ 'd, - _ch1: Option>>, - _ch2: Option>>, - ) -> Self { - Self::new_inner(tim) - } - - fn new_inner(tim: impl Peripheral

+ 'd) -> Self { - into_ref!(tim); - - rcc::enable_and_reset::(); - - T::regs().cr().modify(|w| w.set_enable(true)); - - // Set frequency. Should be configurable. - // By default, 16MHz. We want 440Hz. - // That's 36363 cycles - T::regs().arr().write_value(stm32_metapac::lptim::regs::Arr(36363)); - - // Set duty cycle. Should be configurable. Should take care of channel too (only Ch1 now) - T::regs().ccr(0).write_value(stm32_metapac::lptim::regs::Ccr(18181)); - - // Enable channel as PWM. Default state anyway. Implement later. - // T::regs().ccmr().modify(|w| { - // w.set_ccsel(0, 0); - // w.set_ccsel(1, 0); - // }) - - // Enable output on pins. Should care about the channels! - T::regs().ccmr().modify(|w| { - w.set_cce(0, true); - w.set_cce(1, true); - }); - - Self { - _inner: tim, - master: Master { phantom: PhantomData }, - ch_1: Ch1 { phantom: PhantomData }, - ch_2: Ch2 { phantom: PhantomData }, +impl Channel { + /// Get the channel index (0..1) + pub fn index(&self) -> usize { + match self { + Channel::Ch1 => 0, + Channel::Ch2 => 1, } } - - /// Start - pub fn start(&mut self) { - T::regs().cr().modify(|w| w.set_cntstrt(true)); - } - - /// Stop - pub fn stop(&mut self) { - T::regs().cr().modify(|w| w.set_cntstrt(false)); - } } pin_trait!(Channel1Pin, Instance); pin_trait!(Channel2Pin, Instance); + +pub(crate) trait SealedInstance: RccPeripheral { + fn regs() -> crate::pac::lptim::LptimAdv; +} + +/// LPTIM instance trait. +#[allow(private_bounds)] +pub trait Instance: SealedInstance + 'static {} +foreach_interrupt! { + ($inst:ident, lptim, LPTIM_ADV, UP, $irq:ident) => { + impl SealedInstance for crate::peripherals::$inst { + fn regs() -> crate::pac::lptim::LptimAdv { + crate::pac::$inst + } + } + + impl Instance for crate::peripherals::$inst { + + } + }; +} diff --git a/embassy-stm32/src/lptim/pwm.rs b/embassy-stm32/src/lptim/pwm.rs new file mode 100644 index 000000000..725aa676e --- /dev/null +++ b/embassy-stm32/src/lptim/pwm.rs @@ -0,0 +1,122 @@ +//! PWM driver. + +use core::marker::PhantomData; + +use embassy_hal_internal::{into_ref, PeripheralRef}; + +use super::timer::{ChannelDirection, Timer}; +use super::{Channel, Channel1Pin, Channel2Pin, Instance}; +use crate::gpio::{AfType, AnyPin, OutputType, Speed}; +use crate::time::Hertz; +use crate::Peripheral; + +/// Channel 1 marker type. +pub enum Ch1 {} +/// Channel 2 marker type. +pub enum Ch2 {} + +/// PWM pin wrapper. +/// +/// This wraps a pin to make it usable with PWM. +pub struct PwmPin<'d, T, C> { + _pin: PeripheralRef<'d, AnyPin>, + phantom: PhantomData<(T, C)>, +} + +macro_rules! channel_impl { + ($new_chx:ident, $channel:ident, $pin_trait:ident) => { + impl<'d, T: Instance> PwmPin<'d, T, $channel> { + #[doc = concat!("Create a new ", stringify!($channel), " PWM pin instance.")] + pub fn $new_chx(pin: impl Peripheral

> + 'd) -> Self { + into_ref!(pin); + critical_section::with(|_| { + pin.set_low(); + pin.set_as_af( + pin.af_num(), + AfType::output(OutputType::PushPull, Speed::VeryHigh), + ); + }); + PwmPin { + _pin: pin.map_into(), + phantom: PhantomData, + } + } + } + }; +} + +channel_impl!(new_ch1, Ch1, Channel1Pin); +channel_impl!(new_ch2, Ch2, Channel2Pin); + +/// PWM driver. +pub struct Pwm<'d, T: Instance> { + inner: Timer<'d, T>, // _inner: PeripheralRef<'d, T>, +} + +impl<'d, T: Instance> Pwm<'d, T> { + /// Create a new PWM driver. + pub fn new( + tim: impl Peripheral

+ 'd, + _ch1_pin: Option>, + _ch2_pin: Option>, + freq: Hertz, + ) -> Self { + let mut this = Self { inner: Timer::new(tim) }; + + this.inner.enable(); + this.set_frequency(freq); + + [Channel::Ch1, Channel::Ch2].iter().for_each(|&channel| { + this.inner.set_channel_direction(channel, ChannelDirection::OutputPwm); + }); + + this.inner.continuous_mode_start(); + + this + } + + /// Enable the given channel. + pub fn enable(&mut self, channel: Channel) { + self.inner.enable_channel(channel, true); + } + + /// Disable the given channel. + pub fn disable(&mut self, channel: Channel) { + self.inner.enable_channel(channel, false); + } + + /// Check whether given channel is enabled + pub fn is_enabled(&self, channel: Channel) -> bool { + self.inner.get_channel_enable_state(channel) + } + + /// Set PWM frequency. + /// + /// Note: when you call this, the max duty value changes, so you will have to + /// call `set_duty` on all channels with the duty calculated based on the new max duty. + pub fn set_frequency(&mut self, frequency: Hertz) { + self.inner.set_frequency(frequency); + } + + /// Get max duty value. + /// + /// This value depends on the configured frequency and the timer's clock rate from RCC. + pub fn get_max_duty(&self) -> u16 { + self.inner.get_max_compare_value() + 1 + } + + /// Set the duty for a given channel. + /// + /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included. + pub fn set_duty(&mut self, channel: Channel, duty: u16) { + assert!(duty <= self.get_max_duty()); + self.inner.set_compare_value(channel, duty) + } + + /// Get the duty for a given channel. + /// + /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included. + pub fn get_duty(&self, channel: Channel) -> u16 { + self.inner.get_compare_value(channel) + } +} diff --git a/embassy-stm32/src/lptim/timer.rs b/embassy-stm32/src/lptim/timer.rs new file mode 100644 index 000000000..06392b2e7 --- /dev/null +++ b/embassy-stm32/src/lptim/timer.rs @@ -0,0 +1,212 @@ +//! Low-level timer driver. + +use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; + +use super::{Channel, Instance}; +use crate::pac::lptim::vals; +use crate::rcc; +use crate::time::Hertz; + +/// Direction of a low-power timer channel +pub enum ChannelDirection { + /// Use channel as a PWM output + OutputPwm, + /// Use channel as an input capture + InputCapture, +} + +impl From for vals::Ccsel { + fn from(direction: ChannelDirection) -> Self { + match direction { + ChannelDirection::OutputPwm => vals::Ccsel::OUTPUTCOMPARE, + ChannelDirection::InputCapture => vals::Ccsel::INPUTCAPTURE, + } + } +} + +enum Prescaler { + Div1, + Div2, + Div4, + Div8, + Div16, + Div32, + Div64, + Div128, +} + +impl From<&Prescaler> for vals::Presc { + fn from(prescaler: &Prescaler) -> Self { + match prescaler { + Prescaler::Div1 => vals::Presc::DIV1, + Prescaler::Div2 => vals::Presc::DIV2, + Prescaler::Div4 => vals::Presc::DIV4, + Prescaler::Div8 => vals::Presc::DIV8, + Prescaler::Div16 => vals::Presc::DIV16, + Prescaler::Div32 => vals::Presc::DIV32, + Prescaler::Div64 => vals::Presc::DIV64, + Prescaler::Div128 => vals::Presc::DIV128, + } + } +} + +impl From for Prescaler { + fn from(prescaler: vals::Presc) -> Self { + match prescaler { + vals::Presc::DIV1 => Prescaler::Div1, + vals::Presc::DIV2 => Prescaler::Div2, + vals::Presc::DIV4 => Prescaler::Div4, + vals::Presc::DIV8 => Prescaler::Div8, + vals::Presc::DIV16 => Prescaler::Div16, + vals::Presc::DIV32 => Prescaler::Div32, + vals::Presc::DIV64 => Prescaler::Div64, + vals::Presc::DIV128 => Prescaler::Div128, + } + } +} + +impl From<&Prescaler> for u32 { + fn from(prescaler: &Prescaler) -> Self { + match prescaler { + Prescaler::Div1 => 1, + Prescaler::Div2 => 2, + Prescaler::Div4 => 4, + Prescaler::Div8 => 8, + Prescaler::Div16 => 16, + Prescaler::Div32 => 32, + Prescaler::Div64 => 64, + Prescaler::Div128 => 128, + } + } +} + +impl From for Prescaler { + fn from(prescaler: u32) -> Self { + match prescaler { + 1 => Prescaler::Div1, + 2 => Prescaler::Div2, + 4 => Prescaler::Div4, + 8 => Prescaler::Div8, + 16 => Prescaler::Div16, + 32 => Prescaler::Div32, + 64 => Prescaler::Div64, + 128 => Prescaler::Div128, + _ => unreachable!(), + } + } +} + +impl Prescaler { + pub fn from_ticks(ticks: u32) -> Self { + // We need to scale down to a 16-bit range + (ticks >> 16).next_power_of_two().into() + } + + pub fn scale_down(&self, ticks: u32) -> u16 { + (ticks / u32::from(self)).try_into().unwrap() + } + + pub fn scale_up(&self, ticks: u16) -> u32 { + u32::from(self) * ticks as u32 + } +} + +/// Low-level timer driver. +pub struct Timer<'d, T: Instance> { + _tim: PeripheralRef<'d, T>, +} + +impl<'d, T: Instance> Timer<'d, T> { + /// Create a new timer driver. + pub fn new(tim: impl Peripheral

+ 'd) -> Self { + into_ref!(tim); + + rcc::enable_and_reset::(); + + Self { _tim: tim } + } + + /// Enable the timer. + pub fn enable(&self) { + T::regs().cr().modify(|w| w.set_enable(true)); + } + + /// Disable the timer. + pub fn disable(&self) { + T::regs().cr().modify(|w| w.set_enable(false)); + } + + /// Start the timer in single pulse mode. + pub fn single_mode_start(&self) { + T::regs().cr().modify(|w| w.set_sngstrt(true)); + } + + /// Start the timer in continuous mode. + pub fn continuous_mode_start(&self) { + T::regs().cr().modify(|w| w.set_cntstrt(true)); + } + + /// Set channel direction. + pub fn set_channel_direction(&self, channel: Channel, direction: ChannelDirection) { + T::regs() + .ccmr() + .modify(|w| w.set_ccsel(channel.index(), direction.into())); + } + + /// Set the frequency of how many times per second the timer counts up to the max value or down to 0. + pub fn set_frequency(&self, frequency: Hertz) { + let f = frequency.0; + assert!(f > 0); + + let pclk_f = T::frequency().0; + + let pclk_ticks_per_timer_period = pclk_f / f; + + let psc = Prescaler::from_ticks(pclk_ticks_per_timer_period); + let arr = psc.scale_down(pclk_ticks_per_timer_period); + + T::regs().cfgr().modify(|r| r.set_presc((&psc).into())); + T::regs().arr().modify(|r| r.set_arr(arr.into())); + } + + /// Get the timer frequency. + pub fn get_frequency(&self) -> Hertz { + let pclk_f = T::frequency(); + let arr = T::regs().arr().read().arr(); + let psc = Prescaler::from(T::regs().cfgr().read().presc()); + + pclk_f / psc.scale_up(arr) + } + + /// Get the clock frequency of the timer (before prescaler is applied). + pub fn get_clock_frequency(&self) -> Hertz { + T::frequency() + } + + /// Enable/disable a channel. + pub fn enable_channel(&self, channel: Channel, enable: bool) { + T::regs().ccmr().modify(|w| { + w.set_cce(channel.index(), enable); + }); + } + + /// Get enable/disable state of a channel + pub fn get_channel_enable_state(&self, channel: Channel) -> bool { + T::regs().ccmr().read().cce(channel.index()) + } + + /// Set compare value for a channel. + pub fn set_compare_value(&self, channel: Channel, value: u16) { + T::regs().ccr(channel.index()).modify(|w| w.set_ccr(value)); + } + + /// Get compare value for a channel. + pub fn get_compare_value(&self, channel: Channel) -> u16 { + T::regs().ccr(channel.index()).read().ccr() + } + + /// Get max compare value. This depends on the timer frequency and the clock frequency from RCC. + pub fn get_max_compare_value(&self) -> u16 { + T::regs().arr().read().arr() + } +} diff --git a/embassy-stm32/src/lptim/traits.rs b/embassy-stm32/src/lptim/traits.rs deleted file mode 100644 index a8f890a78..000000000 --- a/embassy-stm32/src/lptim/traits.rs +++ /dev/null @@ -1,95 +0,0 @@ -use crate::rcc::RccPeripheral; -use crate::time::Hertz; - -#[repr(u8)] -#[derive(Clone, Copy)] -pub(crate) enum Prescaler { - Div1 = 1, - Div2 = 2, - Div4 = 4, - Div8 = 8, - Div16 = 16, - Div32 = 32, - Div64 = 64, - Div128 = 128, -} - -impl From for u8 { - fn from(val: Prescaler) -> Self { - match val { - Prescaler::Div1 => 0b000, - Prescaler::Div2 => 0b001, - Prescaler::Div4 => 0b010, - Prescaler::Div8 => 0b011, - Prescaler::Div16 => 0b100, - Prescaler::Div32 => 0b101, - Prescaler::Div64 => 0b110, - Prescaler::Div128 => 0b111, - } - } -} - -impl From for Prescaler { - fn from(val: u8) -> Self { - match val { - 0b000 => Prescaler::Div1, - 0b001 => Prescaler::Div2, - 0b010 => Prescaler::Div4, - 0b011 => Prescaler::Div8, - 0b100 => Prescaler::Div16, - 0b101 => Prescaler::Div32, - 0b110 => Prescaler::Div64, - 0b111 => Prescaler::Div128, - _ => unreachable!(), - } - } -} - -impl Prescaler { - pub fn compute_min_high_res(val: u32) -> Self { - *[ - Prescaler::Div1, - Prescaler::Div2, - Prescaler::Div4, - Prescaler::Div8, - Prescaler::Div16, - Prescaler::Div32, - Prescaler::Div64, - Prescaler::Div128, - ] - .iter() - .skip_while(|psc| **psc as u32 <= val) - .next() - .unwrap() - } - - pub fn compute_min_low_res(val: u32) -> Self { - *[Prescaler::Div32, Prescaler::Div64, Prescaler::Div128] - .iter() - .skip_while(|psc| **psc as u32 <= val) - .next() - .unwrap() - } -} - -pub(crate) trait SealedInstance: RccPeripheral { - fn regs() -> crate::pac::lptim::LptimAdv; -} - -/// LPTIM instance trait. -#[allow(private_bounds)] -pub trait Instance: SealedInstance + 'static {} - -foreach_interrupt! { - ($inst:ident, lptim, LPTIM_ADV, UP, $irq:ident) => { - impl SealedInstance for crate::peripherals::$inst { - fn regs() -> crate::pac::lptim::LptimAdv { - crate::pac::$inst - } - } - - impl Instance for crate::peripherals::$inst { - - } - }; -} From b449e04a88d76b41aae91d98bd66bf2754637d03 Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Wed, 4 Sep 2024 18:06:46 -0400 Subject: [PATCH 0112/1217] stm32: Temporary fix around incomplete stm32-metapac --- embassy-stm32/src/lptim/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/src/lptim/mod.rs b/embassy-stm32/src/lptim/mod.rs index baedf9fe2..327a1d44b 100644 --- a/embassy-stm32/src/lptim/mod.rs +++ b/embassy-stm32/src/lptim/mod.rs @@ -35,7 +35,7 @@ pub(crate) trait SealedInstance: RccPeripheral { #[allow(private_bounds)] pub trait Instance: SealedInstance + 'static {} foreach_interrupt! { - ($inst:ident, lptim, LPTIM_ADV, UP, $irq:ident) => { + ($inst:ident, lptim, LPTIM_ADV, GLOBAL, $irq:ident) => { impl SealedInstance for crate::peripherals::$inst { fn regs() -> crate::pac::lptim::LptimAdv { crate::pac::$inst From 37130f45e4f74f7b4faeb7cac017c4588e5b422a Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Thu, 5 Sep 2024 11:39:09 -0400 Subject: [PATCH 0113/1217] stm32: Use the updated LPTIM pac --- embassy-stm32/src/lptim/mod.rs | 6 +++--- embassy-stm32/src/lptim/pwm.rs | 1 + embassy-stm32/src/lptim/timer.rs | 9 ++++++--- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/embassy-stm32/src/lptim/mod.rs b/embassy-stm32/src/lptim/mod.rs index 327a1d44b..dc5f1d5bb 100644 --- a/embassy-stm32/src/lptim/mod.rs +++ b/embassy-stm32/src/lptim/mod.rs @@ -28,16 +28,16 @@ pin_trait!(Channel1Pin, Instance); pin_trait!(Channel2Pin, Instance); pub(crate) trait SealedInstance: RccPeripheral { - fn regs() -> crate::pac::lptim::LptimAdv; + fn regs() -> crate::pac::lptim::Lptim; } /// LPTIM instance trait. #[allow(private_bounds)] pub trait Instance: SealedInstance + 'static {} foreach_interrupt! { - ($inst:ident, lptim, LPTIM_ADV, GLOBAL, $irq:ident) => { + ($inst:ident, lptim, LPTIM, UP, $irq:ident) => { impl SealedInstance for crate::peripherals::$inst { - fn regs() -> crate::pac::lptim::LptimAdv { + fn regs() -> crate::pac::lptim::Lptim { crate::pac::$inst } } diff --git a/embassy-stm32/src/lptim/pwm.rs b/embassy-stm32/src/lptim/pwm.rs index 725aa676e..24725f625 100644 --- a/embassy-stm32/src/lptim/pwm.rs +++ b/embassy-stm32/src/lptim/pwm.rs @@ -66,6 +66,7 @@ impl<'d, T: Instance> Pwm<'d, T> { this.inner.enable(); this.set_frequency(freq); + #[cfg(any(lptim_v2a, lptim_v2b))] [Channel::Ch1, Channel::Ch2].iter().for_each(|&channel| { this.inner.set_channel_direction(channel, ChannelDirection::OutputPwm); }); diff --git a/embassy-stm32/src/lptim/timer.rs b/embassy-stm32/src/lptim/timer.rs index 06392b2e7..b354c1f61 100644 --- a/embassy-stm32/src/lptim/timer.rs +++ b/embassy-stm32/src/lptim/timer.rs @@ -8,6 +8,7 @@ use crate::rcc; use crate::time::Hertz; /// Direction of a low-power timer channel +#[cfg(any(lptim_v2a, lptim_v2b))] pub enum ChannelDirection { /// Use channel as a PWM output OutputPwm, @@ -15,6 +16,7 @@ pub enum ChannelDirection { InputCapture, } +#[cfg(any(lptim_v2a, lptim_v2b))] impl From for vals::Ccsel { fn from(direction: ChannelDirection) -> Self { match direction { @@ -147,9 +149,10 @@ impl<'d, T: Instance> Timer<'d, T> { } /// Set channel direction. + #[cfg(any(lptim_v2a, lptim_v2b))] pub fn set_channel_direction(&self, channel: Channel, direction: ChannelDirection) { T::regs() - .ccmr() + .ccmr(0) .modify(|w| w.set_ccsel(channel.index(), direction.into())); } @@ -185,14 +188,14 @@ impl<'d, T: Instance> Timer<'d, T> { /// Enable/disable a channel. pub fn enable_channel(&self, channel: Channel, enable: bool) { - T::regs().ccmr().modify(|w| { + T::regs().ccmr(0).modify(|w| { w.set_cce(channel.index(), enable); }); } /// Get enable/disable state of a channel pub fn get_channel_enable_state(&self, channel: Channel) -> bool { - T::regs().ccmr().read().cce(channel.index()) + T::regs().ccmr(0).read().cce(channel.index()) } /// Set compare value for a channel. From 652133bce48f39ea5f379d056ca46a7f2ca3a99a Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Thu, 5 Sep 2024 15:10:39 -0400 Subject: [PATCH 0114/1217] stm32: Support LPTIM v1 and v2 --- embassy-stm32/build.rs | 1 + embassy-stm32/src/lptim/channel.rs | 18 ++ embassy-stm32/src/lptim/mod.rs | 22 +-- embassy-stm32/src/lptim/pwm.rs | 107 ++++++++---- .../src/lptim/timer/channel_direction.rs | 18 ++ .../src/lptim/{timer.rs => timer/mod.rs} | 156 +++++------------- embassy-stm32/src/lptim/timer/prescaler.rs | 90 ++++++++++ 7 files changed, 245 insertions(+), 167 deletions(-) create mode 100644 embassy-stm32/src/lptim/channel.rs create mode 100644 embassy-stm32/src/lptim/timer/channel_direction.rs rename embassy-stm32/src/lptim/{timer.rs => timer/mod.rs} (53%) create mode 100644 embassy-stm32/src/lptim/timer/prescaler.rs diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 33985a3f4..511eb6d37 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -1017,6 +1017,7 @@ fn main() { (("hrtim", "CHF2"), quote!(crate::hrtim::ChannelFComplementaryPin)), (("lptim", "CH1"), quote!(crate::lptim::Channel1Pin)), (("lptim", "CH2"), quote!(crate::lptim::Channel1Pin)), + (("lptim", "OUT"), quote!(crate::lptim::OutputPin)), (("sdmmc", "CK"), quote!(crate::sdmmc::CkPin)), (("sdmmc", "CMD"), quote!(crate::sdmmc::CmdPin)), (("sdmmc", "D0"), quote!(crate::sdmmc::D0Pin)), diff --git a/embassy-stm32/src/lptim/channel.rs b/embassy-stm32/src/lptim/channel.rs new file mode 100644 index 000000000..17fc2fb86 --- /dev/null +++ b/embassy-stm32/src/lptim/channel.rs @@ -0,0 +1,18 @@ +/// Timer channel. +#[derive(Clone, Copy)] +pub enum Channel { + /// Channel 1. + Ch1, + /// Channel 2. + Ch2, +} + +impl Channel { + /// Get the channel index (0..1) + pub fn index(&self) -> usize { + match self { + Channel::Ch1 => 0, + Channel::Ch2 => 1, + } + } +} diff --git a/embassy-stm32/src/lptim/mod.rs b/embassy-stm32/src/lptim/mod.rs index dc5f1d5bb..9c10efa43 100644 --- a/embassy-stm32/src/lptim/mod.rs +++ b/embassy-stm32/src/lptim/mod.rs @@ -6,24 +6,12 @@ pub mod timer; use crate::rcc::RccPeripheral; /// Timer channel. -#[derive(Clone, Copy)] -pub enum Channel { - /// Channel 1. - Ch1, - /// Channel 2. - Ch2, -} - -impl Channel { - /// Get the channel index (0..1) - pub fn index(&self) -> usize { - match self { - Channel::Ch1 => 0, - Channel::Ch2 => 1, - } - } -} +#[cfg(any(lptim_v2a, lptim_v2b))] +mod channel; +#[cfg(any(lptim_v2a, lptim_v2b))] +pub use channel::Channel; +pin_trait!(OutputPin, Instance); pin_trait!(Channel1Pin, Instance); pin_trait!(Channel2Pin, Instance); diff --git a/embassy-stm32/src/lptim/pwm.rs b/embassy-stm32/src/lptim/pwm.rs index 24725f625..586148848 100644 --- a/embassy-stm32/src/lptim/pwm.rs +++ b/embassy-stm32/src/lptim/pwm.rs @@ -4,12 +4,18 @@ use core::marker::PhantomData; use embassy_hal_internal::{into_ref, PeripheralRef}; -use super::timer::{ChannelDirection, Timer}; -use super::{Channel, Channel1Pin, Channel2Pin, Instance}; +use super::timer::Timer; +use super::Instance; +#[cfg(not(any(lptim_v2a, lptim_v2b)))] +use super::OutputPin; +#[cfg(any(lptim_v2a, lptim_v2b))] +use super::{channel::Channel, timer::ChannelDirection, Channel1Pin, Channel2Pin}; use crate::gpio::{AfType, AnyPin, OutputType, Speed}; use crate::time::Hertz; use crate::Peripheral; +/// Output marker type. +pub enum Output {} /// Channel 1 marker type. pub enum Ch1 {} /// Channel 2 marker type. @@ -45,14 +51,44 @@ macro_rules! channel_impl { }; } +#[cfg(not(any(lptim_v2a, lptim_v2b)))] +channel_impl!(new, Output, OutputPin); +#[cfg(any(lptim_v2a, lptim_v2b))] channel_impl!(new_ch1, Ch1, Channel1Pin); +#[cfg(any(lptim_v2a, lptim_v2b))] channel_impl!(new_ch2, Ch2, Channel2Pin); /// PWM driver. pub struct Pwm<'d, T: Instance> { - inner: Timer<'d, T>, // _inner: PeripheralRef<'d, T>, + inner: Timer<'d, T>, } +#[cfg(not(any(lptim_v2a, lptim_v2b)))] +impl<'d, T: Instance> Pwm<'d, T> { + /// Create a new PWM driver. + pub fn new(tim: impl Peripheral

+ 'd, _output_pin: PwmPin<'d, T, Output>, freq: Hertz) -> Self { + Self::new_inner(tim, freq) + } + + /// Set the duty. + /// + /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included. + pub fn set_duty(&mut self, duty: u16) { + assert!(duty <= self.get_max_duty()); + self.inner.set_compare_value(duty) + } + + /// Get the duty. + /// + /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included. + pub fn get_duty(&self) -> u16 { + self.inner.get_compare_value() + } + + fn post_init(&mut self) {} +} + +#[cfg(any(lptim_v2a, lptim_v2b))] impl<'d, T: Instance> Pwm<'d, T> { /// Create a new PWM driver. pub fn new( @@ -61,19 +97,7 @@ impl<'d, T: Instance> Pwm<'d, T> { _ch2_pin: Option>, freq: Hertz, ) -> Self { - let mut this = Self { inner: Timer::new(tim) }; - - this.inner.enable(); - this.set_frequency(freq); - - #[cfg(any(lptim_v2a, lptim_v2b))] - [Channel::Ch1, Channel::Ch2].iter().for_each(|&channel| { - this.inner.set_channel_direction(channel, ChannelDirection::OutputPwm); - }); - - this.inner.continuous_mode_start(); - - this + Self::new_inner(tim, freq) } /// Enable the given channel. @@ -91,21 +115,6 @@ impl<'d, T: Instance> Pwm<'d, T> { self.inner.get_channel_enable_state(channel) } - /// Set PWM frequency. - /// - /// Note: when you call this, the max duty value changes, so you will have to - /// call `set_duty` on all channels with the duty calculated based on the new max duty. - pub fn set_frequency(&mut self, frequency: Hertz) { - self.inner.set_frequency(frequency); - } - - /// Get max duty value. - /// - /// This value depends on the configured frequency and the timer's clock rate from RCC. - pub fn get_max_duty(&self) -> u16 { - self.inner.get_max_compare_value() + 1 - } - /// Set the duty for a given channel. /// /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included. @@ -120,4 +129,40 @@ impl<'d, T: Instance> Pwm<'d, T> { pub fn get_duty(&self, channel: Channel) -> u16 { self.inner.get_compare_value(channel) } + + fn post_init(&mut self) { + [Channel::Ch1, Channel::Ch2].iter().for_each(|&channel| { + self.inner.set_channel_direction(channel, ChannelDirection::OutputPwm); + }); + } +} + +impl<'d, T: Instance> Pwm<'d, T> { + fn new_inner(tim: impl Peripheral

+ 'd, freq: Hertz) -> Self { + let mut this = Self { inner: Timer::new(tim) }; + + this.inner.enable(); + this.set_frequency(freq); + + this.post_init(); + + this.inner.continuous_mode_start(); + + this + } + + /// Set PWM frequency. + /// + /// Note: when you call this, the max duty value changes, so you will have to + /// call `set_duty` on all channels with the duty calculated based on the new max duty. + pub fn set_frequency(&mut self, frequency: Hertz) { + self.inner.set_frequency(frequency); + } + + /// Get max duty value. + /// + /// This value depends on the configured frequency and the timer's clock rate from RCC. + pub fn get_max_duty(&self) -> u16 { + self.inner.get_max_compare_value() + 1 + } } diff --git a/embassy-stm32/src/lptim/timer/channel_direction.rs b/embassy-stm32/src/lptim/timer/channel_direction.rs new file mode 100644 index 000000000..a38df63cd --- /dev/null +++ b/embassy-stm32/src/lptim/timer/channel_direction.rs @@ -0,0 +1,18 @@ +use crate::pac::lptim::vals; + +/// Direction of a low-power timer channel +pub enum ChannelDirection { + /// Use channel as a PWM output + OutputPwm, + /// Use channel as an input capture + InputCapture, +} + +impl From for vals::Ccsel { + fn from(direction: ChannelDirection) -> Self { + match direction { + ChannelDirection::OutputPwm => vals::Ccsel::OUTPUTCOMPARE, + ChannelDirection::InputCapture => vals::Ccsel::INPUTCAPTURE, + } + } +} diff --git a/embassy-stm32/src/lptim/timer.rs b/embassy-stm32/src/lptim/timer/mod.rs similarity index 53% rename from embassy-stm32/src/lptim/timer.rs rename to embassy-stm32/src/lptim/timer/mod.rs index b354c1f61..e62fcab49 100644 --- a/embassy-stm32/src/lptim/timer.rs +++ b/embassy-stm32/src/lptim/timer/mod.rs @@ -1,118 +1,20 @@ //! Low-level timer driver. +mod prescaler; use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; -use super::{Channel, Instance}; -use crate::pac::lptim::vals; +#[cfg(any(lptim_v2a, lptim_v2b))] +use super::channel::Channel; +#[cfg(any(lptim_v2a, lptim_v2b))] +mod channel_direction; +#[cfg(any(lptim_v2a, lptim_v2b))] +pub use channel_direction::ChannelDirection; +use prescaler::Prescaler; + +use super::Instance; use crate::rcc; use crate::time::Hertz; -/// Direction of a low-power timer channel -#[cfg(any(lptim_v2a, lptim_v2b))] -pub enum ChannelDirection { - /// Use channel as a PWM output - OutputPwm, - /// Use channel as an input capture - InputCapture, -} - -#[cfg(any(lptim_v2a, lptim_v2b))] -impl From for vals::Ccsel { - fn from(direction: ChannelDirection) -> Self { - match direction { - ChannelDirection::OutputPwm => vals::Ccsel::OUTPUTCOMPARE, - ChannelDirection::InputCapture => vals::Ccsel::INPUTCAPTURE, - } - } -} - -enum Prescaler { - Div1, - Div2, - Div4, - Div8, - Div16, - Div32, - Div64, - Div128, -} - -impl From<&Prescaler> for vals::Presc { - fn from(prescaler: &Prescaler) -> Self { - match prescaler { - Prescaler::Div1 => vals::Presc::DIV1, - Prescaler::Div2 => vals::Presc::DIV2, - Prescaler::Div4 => vals::Presc::DIV4, - Prescaler::Div8 => vals::Presc::DIV8, - Prescaler::Div16 => vals::Presc::DIV16, - Prescaler::Div32 => vals::Presc::DIV32, - Prescaler::Div64 => vals::Presc::DIV64, - Prescaler::Div128 => vals::Presc::DIV128, - } - } -} - -impl From for Prescaler { - fn from(prescaler: vals::Presc) -> Self { - match prescaler { - vals::Presc::DIV1 => Prescaler::Div1, - vals::Presc::DIV2 => Prescaler::Div2, - vals::Presc::DIV4 => Prescaler::Div4, - vals::Presc::DIV8 => Prescaler::Div8, - vals::Presc::DIV16 => Prescaler::Div16, - vals::Presc::DIV32 => Prescaler::Div32, - vals::Presc::DIV64 => Prescaler::Div64, - vals::Presc::DIV128 => Prescaler::Div128, - } - } -} - -impl From<&Prescaler> for u32 { - fn from(prescaler: &Prescaler) -> Self { - match prescaler { - Prescaler::Div1 => 1, - Prescaler::Div2 => 2, - Prescaler::Div4 => 4, - Prescaler::Div8 => 8, - Prescaler::Div16 => 16, - Prescaler::Div32 => 32, - Prescaler::Div64 => 64, - Prescaler::Div128 => 128, - } - } -} - -impl From for Prescaler { - fn from(prescaler: u32) -> Self { - match prescaler { - 1 => Prescaler::Div1, - 2 => Prescaler::Div2, - 4 => Prescaler::Div4, - 8 => Prescaler::Div8, - 16 => Prescaler::Div16, - 32 => Prescaler::Div32, - 64 => Prescaler::Div64, - 128 => Prescaler::Div128, - _ => unreachable!(), - } - } -} - -impl Prescaler { - pub fn from_ticks(ticks: u32) -> Self { - // We need to scale down to a 16-bit range - (ticks >> 16).next_power_of_two().into() - } - - pub fn scale_down(&self, ticks: u32) -> u16 { - (ticks / u32::from(self)).try_into().unwrap() - } - - pub fn scale_up(&self, ticks: u16) -> u32 { - u32::from(self) * ticks as u32 - } -} - /// Low-level timer driver. pub struct Timer<'d, T: Instance> { _tim: PeripheralRef<'d, T>, @@ -148,14 +50,6 @@ impl<'d, T: Instance> Timer<'d, T> { T::regs().cr().modify(|w| w.set_cntstrt(true)); } - /// Set channel direction. - #[cfg(any(lptim_v2a, lptim_v2b))] - pub fn set_channel_direction(&self, channel: Channel, direction: ChannelDirection) { - T::regs() - .ccmr(0) - .modify(|w| w.set_ccsel(channel.index(), direction.into())); - } - /// Set the frequency of how many times per second the timer counts up to the max value or down to 0. pub fn set_frequency(&self, frequency: Hertz) { let f = frequency.0; @@ -186,6 +80,14 @@ impl<'d, T: Instance> Timer<'d, T> { T::frequency() } + /// Get max compare value. This depends on the timer frequency and the clock frequency from RCC. + pub fn get_max_compare_value(&self) -> u16 { + T::regs().arr().read().arr() + } +} + +#[cfg(any(lptim_v2a, lptim_v2b))] +impl<'d, T: Instance> Timer<'d, T> { /// Enable/disable a channel. pub fn enable_channel(&self, channel: Channel, enable: bool) { T::regs().ccmr(0).modify(|w| { @@ -208,8 +110,24 @@ impl<'d, T: Instance> Timer<'d, T> { T::regs().ccr(channel.index()).read().ccr() } - /// Get max compare value. This depends on the timer frequency and the clock frequency from RCC. - pub fn get_max_compare_value(&self) -> u16 { - T::regs().arr().read().arr() + /// Set channel direction. + #[cfg(any(lptim_v2a, lptim_v2b))] + pub fn set_channel_direction(&self, channel: Channel, direction: ChannelDirection) { + T::regs() + .ccmr(0) + .modify(|w| w.set_ccsel(channel.index(), direction.into())); + } +} + +#[cfg(not(any(lptim_v2a, lptim_v2b)))] +impl<'d, T: Instance> Timer<'d, T> { + /// Set compare value for a channel. + pub fn set_compare_value(&self, value: u16) { + T::regs().cmp().modify(|w| w.set_cmp(value)); + } + + /// Get compare value for a channel. + pub fn get_compare_value(&self) -> u16 { + T::regs().cmp().read().cmp() } } diff --git a/embassy-stm32/src/lptim/timer/prescaler.rs b/embassy-stm32/src/lptim/timer/prescaler.rs new file mode 100644 index 000000000..5d2326faf --- /dev/null +++ b/embassy-stm32/src/lptim/timer/prescaler.rs @@ -0,0 +1,90 @@ +//! Low-level timer driver. + +use crate::pac::lptim::vals; + +pub enum Prescaler { + Div1, + Div2, + Div4, + Div8, + Div16, + Div32, + Div64, + Div128, +} + +impl From<&Prescaler> for vals::Presc { + fn from(prescaler: &Prescaler) -> Self { + match prescaler { + Prescaler::Div1 => vals::Presc::DIV1, + Prescaler::Div2 => vals::Presc::DIV2, + Prescaler::Div4 => vals::Presc::DIV4, + Prescaler::Div8 => vals::Presc::DIV8, + Prescaler::Div16 => vals::Presc::DIV16, + Prescaler::Div32 => vals::Presc::DIV32, + Prescaler::Div64 => vals::Presc::DIV64, + Prescaler::Div128 => vals::Presc::DIV128, + } + } +} + +impl From for Prescaler { + fn from(prescaler: vals::Presc) -> Self { + match prescaler { + vals::Presc::DIV1 => Prescaler::Div1, + vals::Presc::DIV2 => Prescaler::Div2, + vals::Presc::DIV4 => Prescaler::Div4, + vals::Presc::DIV8 => Prescaler::Div8, + vals::Presc::DIV16 => Prescaler::Div16, + vals::Presc::DIV32 => Prescaler::Div32, + vals::Presc::DIV64 => Prescaler::Div64, + vals::Presc::DIV128 => Prescaler::Div128, + } + } +} + +impl From<&Prescaler> for u32 { + fn from(prescaler: &Prescaler) -> Self { + match prescaler { + Prescaler::Div1 => 1, + Prescaler::Div2 => 2, + Prescaler::Div4 => 4, + Prescaler::Div8 => 8, + Prescaler::Div16 => 16, + Prescaler::Div32 => 32, + Prescaler::Div64 => 64, + Prescaler::Div128 => 128, + } + } +} + +impl From for Prescaler { + fn from(prescaler: u32) -> Self { + match prescaler { + 1 => Prescaler::Div1, + 2 => Prescaler::Div2, + 4 => Prescaler::Div4, + 8 => Prescaler::Div8, + 16 => Prescaler::Div16, + 32 => Prescaler::Div32, + 64 => Prescaler::Div64, + 128 => Prescaler::Div128, + _ => unreachable!(), + } + } +} + +impl Prescaler { + pub fn from_ticks(ticks: u32) -> Self { + // We need to scale down to a 16-bit range + (ticks >> 16).next_power_of_two().into() + } + + pub fn scale_down(&self, ticks: u32) -> u16 { + (ticks / u32::from(self)).try_into().unwrap() + } + + pub fn scale_up(&self, ticks: u16) -> u32 { + u32::from(self) * ticks as u32 + } +} From ac319970b82e3e613c35d45a11f31423204115e0 Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Thu, 5 Sep 2024 16:30:45 -0400 Subject: [PATCH 0115/1217] stm32: Work around LPTIM4 --- embassy-stm32/src/lptim/mod.rs | 25 ++++++++++++++++++------- embassy-stm32/src/lptim/pwm.rs | 4 ++-- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/embassy-stm32/src/lptim/mod.rs b/embassy-stm32/src/lptim/mod.rs index 9c10efa43..05ed4de44 100644 --- a/embassy-stm32/src/lptim/mod.rs +++ b/embassy-stm32/src/lptim/mod.rs @@ -11,17 +11,23 @@ mod channel; #[cfg(any(lptim_v2a, lptim_v2b))] pub use channel::Channel; -pin_trait!(OutputPin, Instance); -pin_trait!(Channel1Pin, Instance); -pin_trait!(Channel2Pin, Instance); +pin_trait!(OutputPin, BasicInstance); +pin_trait!(Channel1Pin, BasicInstance); +pin_trait!(Channel2Pin, BasicInstance); pub(crate) trait SealedInstance: RccPeripheral { fn regs() -> crate::pac::lptim::Lptim; } +pub(crate) trait SealedBasicInstance: RccPeripheral {} + +/// LPTIM basic instance trait. +#[allow(private_bounds)] +pub trait BasicInstance: SealedBasicInstance + 'static {} /// LPTIM instance trait. #[allow(private_bounds)] -pub trait Instance: SealedInstance + 'static {} +pub trait Instance: BasicInstance + SealedInstance + 'static {} + foreach_interrupt! { ($inst:ident, lptim, LPTIM, UP, $irq:ident) => { impl SealedInstance for crate::peripherals::$inst { @@ -29,9 +35,14 @@ foreach_interrupt! { crate::pac::$inst } } - - impl Instance for crate::peripherals::$inst { - + impl SealedBasicInstance for crate::peripherals::$inst { } + impl BasicInstance for crate::peripherals::$inst {} + impl Instance for crate::peripherals::$inst {} + }; + ($inst:ident, lptim, LPTIM_BASIC, UP, $irq:ident) => { + impl SealedBasicInstance for crate::peripherals::$inst { + } + impl BasicInstance for crate::peripherals::$inst {} }; } diff --git a/embassy-stm32/src/lptim/pwm.rs b/embassy-stm32/src/lptim/pwm.rs index 586148848..1f43eb6ee 100644 --- a/embassy-stm32/src/lptim/pwm.rs +++ b/embassy-stm32/src/lptim/pwm.rs @@ -5,11 +5,11 @@ use core::marker::PhantomData; use embassy_hal_internal::{into_ref, PeripheralRef}; use super::timer::Timer; -use super::Instance; #[cfg(not(any(lptim_v2a, lptim_v2b)))] use super::OutputPin; #[cfg(any(lptim_v2a, lptim_v2b))] use super::{channel::Channel, timer::ChannelDirection, Channel1Pin, Channel2Pin}; +use super::{BasicInstance, Instance}; use crate::gpio::{AfType, AnyPin, OutputType, Speed}; use crate::time::Hertz; use crate::Peripheral; @@ -31,7 +31,7 @@ pub struct PwmPin<'d, T, C> { macro_rules! channel_impl { ($new_chx:ident, $channel:ident, $pin_trait:ident) => { - impl<'d, T: Instance> PwmPin<'d, T, $channel> { + impl<'d, T: BasicInstance> PwmPin<'d, T, $channel> { #[doc = concat!("Create a new ", stringify!($channel), " PWM pin instance.")] pub fn $new_chx(pin: impl Peripheral

> + 'd) -> Self { into_ref!(pin); From 69208daf6dba8ef5285e309219991dd63c38506e Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Thu, 5 Sep 2024 17:42:09 -0400 Subject: [PATCH 0116/1217] stm32: Fixing stupid typo (thanks @dirbaio) --- embassy-stm32/build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 511eb6d37..19cf193d9 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -1016,7 +1016,7 @@ fn main() { (("hrtim", "CHF1"), quote!(crate::hrtim::ChannelFPin)), (("hrtim", "CHF2"), quote!(crate::hrtim::ChannelFComplementaryPin)), (("lptim", "CH1"), quote!(crate::lptim::Channel1Pin)), - (("lptim", "CH2"), quote!(crate::lptim::Channel1Pin)), + (("lptim", "CH2"), quote!(crate::lptim::Channel2Pin)), (("lptim", "OUT"), quote!(crate::lptim::OutputPin)), (("sdmmc", "CK"), quote!(crate::sdmmc::CkPin)), (("sdmmc", "CMD"), quote!(crate::sdmmc::CmdPin)), From d69f68b8c006dc785652a74fbe730583900d1923 Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Fri, 6 Sep 2024 20:15:45 -0400 Subject: [PATCH 0117/1217] stm32: Use a GLOBAL interrupt for lptim --- embassy-stm32/src/lptim/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/lptim/mod.rs b/embassy-stm32/src/lptim/mod.rs index 05ed4de44..1649cc5b4 100644 --- a/embassy-stm32/src/lptim/mod.rs +++ b/embassy-stm32/src/lptim/mod.rs @@ -29,7 +29,7 @@ pub trait BasicInstance: SealedBasicInstance + 'static {} pub trait Instance: BasicInstance + SealedInstance + 'static {} foreach_interrupt! { - ($inst:ident, lptim, LPTIM, UP, $irq:ident) => { + ($inst:ident, lptim, LPTIM, GLOBAL, $irq:ident) => { impl SealedInstance for crate::peripherals::$inst { fn regs() -> crate::pac::lptim::Lptim { crate::pac::$inst @@ -40,7 +40,7 @@ foreach_interrupt! { impl BasicInstance for crate::peripherals::$inst {} impl Instance for crate::peripherals::$inst {} }; - ($inst:ident, lptim, LPTIM_BASIC, UP, $irq:ident) => { + ($inst:ident, lptim, LPTIM_BASIC, GLOBAL, $irq:ident) => { impl SealedBasicInstance for crate::peripherals::$inst { } impl BasicInstance for crate::peripherals::$inst {} From c739091085eafeb01703626284428905d75aa98f Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Wed, 11 Sep 2024 01:00:23 +0200 Subject: [PATCH 0118/1217] Update stm32-metapac. --- embassy-stm32/Cargo.toml | 4 ++-- embassy-stm32/src/adc/mod.rs | 16 +++++++++------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 9a6a5908e..3c6484c96 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -72,7 +72,7 @@ rand_core = "0.6.3" sdio-host = "0.5.0" critical-section = "1.1" #stm32-metapac = { version = "15" } -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-5ef354f3e49f790e47f5c818f243459742c9b83b" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-ad00827345b4b758b2453082809d6e3b634b5364" } vcell = "0.1.3" nb = "1.0.0" @@ -99,7 +99,7 @@ proc-macro2 = "1.0.36" quote = "1.0.15" #stm32-metapac = { version = "15", default-features = false, features = ["metadata"]} -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-5ef354f3e49f790e47f5c818f243459742c9b83b", default-features = false, features = ["metadata"] } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-ad00827345b4b758b2453082809d6e3b634b5364", default-features = false, features = ["metadata"] } [features] default = ["rt"] diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index 2ac0c0083..4ab82c1d9 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs @@ -4,7 +4,7 @@ #![allow(missing_docs)] // TODO #![cfg_attr(adc_f3_v2, allow(unused))] -#[cfg(not(adc_f3_v2))] +#[cfg(not(any(adc_f3_v2, adc_u5)))] #[cfg_attr(adc_f1, path = "f1.rs")] #[cfg_attr(adc_f3, path = "f3.rs")] #[cfg_attr(adc_f3_v1_1, path = "f3_v1_1.rs")] @@ -19,14 +19,16 @@ mod _version; use core::marker::PhantomData; #[allow(unused)] -#[cfg(not(adc_f3_v2))] +#[cfg(not(any(adc_f3_v2, adc_u5)))] pub use _version::*; #[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))] use embassy_sync::waitqueue::AtomicWaker; +#[cfg(not(any(adc_u5)))] pub use crate::pac::adc::vals; -#[cfg(not(any(adc_f1, adc_f3_v2)))] +#[cfg(not(any(adc_f1, adc_f3_v2, adc_u5)))] pub use crate::pac::adc::vals::Res as Resolution; +#[cfg(not(any(adc_u5)))] pub use crate::pac::adc::vals::SampleTime; use crate::peripherals; @@ -36,7 +38,7 @@ dma_trait!(RxDma, Instance); pub struct Adc<'d, T: Instance> { #[allow(unused)] adc: crate::PeripheralRef<'d, T>, - #[cfg(not(any(adc_f3_v2, adc_f3_v1_1)))] + #[cfg(not(any(adc_f3_v2, adc_f3_v1_1, adc_u5)))] sample_time: SampleTime, } @@ -57,7 +59,7 @@ impl State { trait SealedInstance { #[allow(unused)] fn regs() -> crate::pac::adc::Adc; - #[cfg(not(any(adc_f1, adc_v1, adc_l0, adc_f3_v2, adc_f3_v1_1, adc_g0)))] + #[cfg(not(any(adc_f1, adc_v1, adc_l0, adc_f3_v2, adc_f3_v1_1, adc_g0, adc_u5)))] #[allow(unused)] fn common_regs() -> crate::pac::adccommon::AdcCommon; #[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))] @@ -163,7 +165,7 @@ foreach_adc!( crate::pac::$inst } - #[cfg(not(any(adc_f1, adc_v1, adc_l0, adc_f3_v2, adc_f3_v1_1, adc_g0)))] + #[cfg(not(any(adc_f1, adc_v1, adc_l0, adc_f3_v2, adc_f3_v1_1, adc_g0, adc_u5)))] fn common_regs() -> crate::pac::adccommon::AdcCommon { return crate::pac::$common_inst } @@ -200,7 +202,7 @@ macro_rules! impl_adc_pin { /// Get the maximum reading value for this resolution. /// /// This is `2**n - 1`. -#[cfg(not(any(adc_f1, adc_f3_v2)))] +#[cfg(not(any(adc_f1, adc_f3_v2, adc_u5)))] pub const fn resolution_to_max_count(res: Resolution) -> u32 { match res { #[cfg(adc_v4)] From d193c9ef44a61c9de381044fd2968a95ce2ffc75 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 13 Aug 2024 17:45:48 +0200 Subject: [PATCH 0119/1217] time-driver: clarify docs for set_alarm. --- embassy-time-driver/src/lib.rs | 52 ++++++++++++++++++++++++++-------- 1 file changed, 40 insertions(+), 12 deletions(-) diff --git a/embassy-time-driver/src/lib.rs b/embassy-time-driver/src/lib.rs index aab2f626e..8000a9dcb 100644 --- a/embassy-time-driver/src/lib.rs +++ b/embassy-time-driver/src/lib.rs @@ -113,24 +113,52 @@ pub trait Driver: Send + Sync + 'static { /// It is UB to make the alarm fire before setting a callback. unsafe fn allocate_alarm(&self) -> Option; - /// Sets the callback function to be called when the alarm triggers. + /// Set the callback function to be called when the alarm triggers. /// The callback may be called from any context (interrupt or thread mode). fn set_alarm_callback(&self, alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()); - /// Sets an alarm at the given timestamp. When the current timestamp reaches the alarm - /// timestamp, the provided callback function will be called. + /// Set an alarm at the given timestamp. /// - /// The `Driver` implementation should guarantee that the alarm callback is never called synchronously from `set_alarm`. - /// Rather - if `timestamp` is already in the past - `false` should be returned and alarm should not be set, - /// or alternatively, the driver should return `true` and arrange to call the alarm callback as soon as possible, but not synchronously. - /// There is a rare third possibility that the alarm was barely in the future, and by the time it was enabled, it had slipped into the - /// past. This is can be detected by double-checking that the alarm is still in the future after enabling it; if it isn't, `false` - /// should also be returned to indicate that the callback may have been called already by the alarm, but it is not guaranteed, so the - /// caller should also call the callback, just like in the more common `false` case. (Note: This requires idempotency of the callback.) + /// ## Behavior /// - /// When callback is called, it is guaranteed that now() will return a value greater or equal than timestamp. + /// If `timestamp` is in the future, `set_alarm` schedules calling the callback function + /// at that time, and returns `true`. /// - /// Only one alarm can be active at a time for each AlarmHandle. This overwrites any previously-set alarm if any. + /// If `timestamp` is in the past, `set_alarm` has two allowed behaviors. Implementations can pick whether to: + /// + /// - Schedule calling the callback function "immediately", as if the requested timestamp was "now+epsilon" and return `true`, or + /// - Not schedule the callback, and return `false`. + /// + /// Callers must ensure to behave correctly with either behavior. + /// + /// When callback is called, it is guaranteed that `now()` will return a value greater than or equal to `timestamp`. + /// + /// ## Reentrancy + /// + /// Calling the callback from `set_alarm` synchronously is not allowed. If the implementation chooses the first option above, + /// it must still call the callback from another context (i.e. an interrupt handler or background thread), it's not allowed + /// to call it synchronously in the context `set_alarm` is running. + /// + /// The reason for the above is callers are explicitly permitted to do both of: + /// - Lock a mutex in the alarm callback. + /// - Call `set_alarm` while having that mutex locked. + /// + /// If `set_alarm` called the callback synchronously, it'd cause a deadlock or panic because it'd cause the + /// mutex to be locked twice reentrantly in the same context. + /// + /// ## Overwriting alarms + /// + /// Only one alarm can be active at a time for each `AlarmHandle`. This overwrites any previously-set alarm if any. + /// + /// ## Unsetting the alarm + /// + /// There is no `unset_alarm` API. Instead, callers can call `set_alarm` with `timestamp` set to `u64::MAX`. + /// + /// This allows for more efficient implementations, since they don't need to distinguish between the "alarm set" and + /// "alarm not set" cases, thanks to the fact "Alarm set for u64::MAX" is effectively equivalent for "alarm not set". + /// + /// This means implementations need to be careful to avoid timestamp overflows. The recommendation is to make `timestamp` + /// be in the same units as hardware ticks to avoid any conversions, which makes avoiding overflow easier. fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) -> bool; } From 833537231e763c31eeb29fe7aad005a08477189d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=BCha=20=C3=9Cn=C3=BCvar?= <87157627+phycrax@users.noreply.github.com> Date: Wed, 11 Sep 2024 12:50:46 +0800 Subject: [PATCH 0120/1217] add link to rustybits zero to async video in resources section --- docs/pages/overview.adoc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/pages/overview.adoc b/docs/pages/overview.adoc index 7d59d5521..2ebc85f6d 100644 --- a/docs/pages/overview.adoc +++ b/docs/pages/overview.adoc @@ -77,3 +77,7 @@ For more reading material on async Rust and Embassy: * link:https://tweedegolf.nl/en/blog/65/async-rust-vs-rtos-showdown[Comparsion of FreeRTOS and Embassy] * link:https://dev.to/apollolabsbin/series/20707[Tutorials] * link:https://blog.drogue.io/firmware-updates-part-1/[Firmware Updates with Embassy] + +Videos: + +* link:https://www.youtube.com/watch?v=wni5h5vIPhU[From Zero to Async in Embedded Rust] \ No newline at end of file From 29932c295c44cea1a2ab5ad94c5d0bd16c07243d Mon Sep 17 00:00:00 2001 From: Oleksandr Babak Date: Wed, 11 Sep 2024 10:42:46 +0200 Subject: [PATCH 0121/1217] fix: `select_slice` is unsound. fixes #3320 --- embassy-futures/src/select.rs | 35 +++++++++++++++-------------------- 1 file changed, 15 insertions(+), 20 deletions(-) diff --git a/embassy-futures/src/select.rs b/embassy-futures/src/select.rs index 97a81a86d..57f0cb41f 100644 --- a/embassy-futures/src/select.rs +++ b/embassy-futures/src/select.rs @@ -237,7 +237,7 @@ impl Future for SelectArray { #[derive(Debug)] #[must_use = "futures do nothing unless you `.await` or poll them"] pub struct SelectSlice<'a, Fut> { - inner: &'a mut [Fut], + inner: Pin<&'a mut [Fut]>, } /// Creates a new future which will select over a slice of futures. @@ -247,31 +247,26 @@ pub struct SelectSlice<'a, Fut> { /// future that was ready. /// /// If the slice is empty, the resulting future will be Pending forever. -pub fn select_slice<'a, Fut: Future>(slice: &'a mut [Fut]) -> SelectSlice<'a, Fut> { +pub fn select_slice<'a, Fut: Future>(slice: Pin<&'a mut [Fut]>) -> SelectSlice<'a, Fut> { SelectSlice { inner: slice } } impl<'a, Fut: Future> Future for SelectSlice<'a, Fut> { type Output = (Fut::Output, usize); - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - // Safety: Since `self` is pinned, `inner` cannot move. Since `inner` cannot move, - // its elements also cannot move. Therefore it is safe to access `inner` and pin - // references to the contained futures. - let item = unsafe { - self.get_unchecked_mut() - .inner - .iter_mut() - .enumerate() - .find_map(|(i, f)| match Pin::new_unchecked(f).poll(cx) { - Poll::Pending => None, - Poll::Ready(e) => Some((i, e)), - }) - }; - - match item { - Some((idx, res)) => Poll::Ready((res, idx)), - None => Poll::Pending, + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + // Safety: refer to + // https://users.rust-lang.org/t/working-with-pinned-slices-are-there-any-structurally-pinning-vec-like-collection-types/50634/2 + #[inline(always)] + fn pin_iter(slice: Pin<&mut [T]>) -> impl Iterator> { + unsafe { slice.get_unchecked_mut().iter_mut().map(|v| Pin::new_unchecked(v)) } } + for (i, fut) in pin_iter(self.inner.as_mut()).enumerate() { + if let Poll::Ready(res) = fut.poll(cx) { + return Poll::Ready((res, i)); + } + } + + Poll::Pending } } From 0ba91ca555efc75dca603adbb51355c92b2fdb80 Mon Sep 17 00:00:00 2001 From: klownfish Date: Wed, 11 Sep 2024 11:55:16 +0200 Subject: [PATCH 0122/1217] WIP: u5 adc --- embassy-stm32/src/adc/mod.rs | 13 +- embassy-stm32/src/adc/u5.rs | 375 +++++++++++++++++++++++++++++++++++ 2 files changed, 383 insertions(+), 5 deletions(-) create mode 100644 embassy-stm32/src/adc/u5.rs diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index 7a7d7cd8e..8ba586f5c 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs @@ -13,6 +13,7 @@ #[cfg_attr(any(adc_v3, adc_g0, adc_h5, adc_u0), path = "v3.rs")] #[cfg_attr(adc_v4, path = "v4.rs")] #[cfg_attr(adc_g4, path = "g4.rs")] +#[cfg_attr(adc_u5, path = "u5.rs")] mod _version; use core::marker::PhantomData; @@ -63,7 +64,7 @@ trait SealedInstance { } pub(crate) trait SealedAdcChannel { - #[cfg(any(adc_v1, adc_l0, adc_v2, adc_g4, adc_v4))] + #[cfg(any(adc_v1, adc_l0, adc_v2, adc_g4, adc_v4, adc_u5))] fn setup(&mut self) {} #[allow(unused)] @@ -97,7 +98,8 @@ pub(crate) fn blocking_delay_us(us: u32) { adc_f3_v1_1, adc_g0, adc_u0, - adc_h5 + adc_h5, + adc_u5 )))] #[allow(private_bounds)] pub trait Instance: SealedInstance + crate::Peripheral

{ @@ -116,7 +118,8 @@ pub trait Instance: SealedInstance + crate::Peripheral

{ adc_f3_v1_1, adc_g0, adc_u0, - adc_h5 + adc_h5, + adc_u5 ))] #[allow(private_bounds)] pub trait Instance: SealedInstance + crate::Peripheral

+ crate::rcc::RccPeripheral { @@ -128,7 +131,7 @@ pub trait Instance: SealedInstance + crate::Peripheral

+ crate::rcc::R pub trait AdcChannel: SealedAdcChannel + Sized { #[allow(unused_mut)] fn degrade_adc(mut self) -> AnyAdcChannel { - #[cfg(any(adc_v1, adc_l0, adc_v2, adc_g4, adc_v4))] + #[cfg(any(adc_v1, adc_l0, adc_v2, adc_g4, adc_v4, adc_u5))] self.setup(); AnyAdcChannel { @@ -183,7 +186,7 @@ macro_rules! impl_adc_pin { ($inst:ident, $pin:ident, $ch:expr) => { impl crate::adc::AdcChannel for crate::peripherals::$pin {} impl crate::adc::SealedAdcChannel for crate::peripherals::$pin { - #[cfg(any(adc_v1, adc_l0, adc_v2, adc_g4, adc_v4))] + #[cfg(any(adc_v1, adc_l0, adc_v2, adc_g4, adc_v4, adc_u5))] fn setup(&mut self) { ::set_as_analog(self); } diff --git a/embassy-stm32/src/adc/u5.rs b/embassy-stm32/src/adc/u5.rs new file mode 100644 index 000000000..9e6a94e5d --- /dev/null +++ b/embassy-stm32/src/adc/u5.rs @@ -0,0 +1,375 @@ +#[allow(unused)] +use pac::adc::vals::{Difsel, Exten, Pcsel}; +use pac::adccommon::vals::Presc; +use crate::peripherals::ADC4; + +use super::{ + blocking_delay_us, Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, SealedAdcChannel +}; +use crate::time::Hertz; +use crate::{pac, rcc, Peripheral}; + +// TODO: not correct +const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(55); +const VREF_CHANNEL: u8 = 19; +const TEMP_CHANNEL: u8 = 18; +const VBAT_CHANNEL: u8 = 17; + +/// Default VREF voltage used for sample conversion to millivolts. +pub const VREF_DEFAULT_MV: u32 = 3300; +/// VREF voltage used for factory calibration of VREFINTCAL register. +pub const VREF_CALIB_MV: u32 = 3300; + + +// NOTE: Vrefint/Temperature/Vbat are not available on all ADCs, this currently cannot be modeled with stm32-data, so these are available from the software on all ADCs +/// Internal voltage reference channel. +pub struct VrefInt; +impl AdcChannel for VrefInt {} +impl SealedAdcChannel for VrefInt { + fn channel(&self) -> u8 { + VREF_CHANNEL + } +} + +/// Internal temperature channel. +pub struct Temperature; +impl AdcChannel for Temperature {} +impl SealedAdcChannel for Temperature { + fn channel(&self) -> u8 { + TEMP_CHANNEL + } +} + +/// Internal battery voltage channel. +pub struct Vbat; +impl AdcChannel for Vbat {} +impl SealedAdcChannel for Vbat { + fn channel(&self) -> u8 { + VBAT_CHANNEL + } +} + +// NOTE (unused): The prescaler enum closely copies the hardware capabilities, +// but high prescaling doesn't make a lot of sense in the current implementation and is ommited. +#[allow(unused)] +enum Prescaler { + NotDivided, + DividedBy2, + DividedBy4, + DividedBy6, + DividedBy8, + DividedBy10, + DividedBy12, + DividedBy16, + DividedBy32, + DividedBy64, + DividedBy128, + DividedBy256, +} + +impl Prescaler { + fn from_ker_ck(frequency: Hertz) -> Self { + let raw_prescaler = frequency.0 / MAX_ADC_CLK_FREQ.0; + match raw_prescaler { + 0 => Self::NotDivided, + 1 => Self::DividedBy2, + 2..=3 => Self::DividedBy4, + 4..=5 => Self::DividedBy6, + 6..=7 => Self::DividedBy8, + 8..=9 => Self::DividedBy10, + 10..=11 => Self::DividedBy12, + _ => unimplemented!(), + } + } + + fn divisor(&self) -> u32 { + match self { + Prescaler::NotDivided => 1, + Prescaler::DividedBy2 => 2, + Prescaler::DividedBy4 => 4, + Prescaler::DividedBy6 => 6, + Prescaler::DividedBy8 => 8, + Prescaler::DividedBy10 => 10, + Prescaler::DividedBy12 => 12, + Prescaler::DividedBy16 => 16, + Prescaler::DividedBy32 => 32, + Prescaler::DividedBy64 => 64, + Prescaler::DividedBy128 => 128, + Prescaler::DividedBy256 => 256, + } + } + + fn presc(&self) -> Presc { + match self { + Prescaler::NotDivided => Presc::DIV1, + Prescaler::DividedBy2 => Presc::DIV2, + Prescaler::DividedBy4 => Presc::DIV4, + Prescaler::DividedBy6 => Presc::DIV6, + Prescaler::DividedBy8 => Presc::DIV8, + Prescaler::DividedBy10 => Presc::DIV10, + Prescaler::DividedBy12 => Presc::DIV12, + Prescaler::DividedBy16 => Presc::DIV16, + Prescaler::DividedBy32 => Presc::DIV32, + Prescaler::DividedBy64 => Presc::DIV64, + Prescaler::DividedBy128 => Presc::DIV128, + Prescaler::DividedBy256 => Presc::DIV256, + } + } +} + +/// Number of samples used for averaging. +pub enum Averaging { + Disabled, + Samples2, + Samples4, + Samples8, + Samples16, + Samples32, + Samples64, + Samples128, + Samples256, + Samples512, + Samples1024, +} + +// TODO +// impl Instance for ADC4 { + +// } + +impl<'d, T: Instance> Adc<'d, T> { + /// Create a new ADC driver. + pub fn new(adc: impl Peripheral

+ 'd) -> Self { + embassy_hal_internal::into_ref!(adc); + rcc::enable_and_reset::(); + + let prescaler = Prescaler::from_ker_ck(T::frequency()); + + T::common_regs().ccr().modify(|w| w.set_presc(prescaler.presc())); + + let frequency = Hertz(T::frequency().0 / prescaler.divisor()); + info!("ADC frequency set to {} Hz", frequency.0); + + if frequency > MAX_ADC_CLK_FREQ { + panic!("Maximal allowed frequency for the ADC is {} MHz and it varies with different packages, refer to ST docs for more information.", MAX_ADC_CLK_FREQ.0 / 1_000_000 ); + } + + let mut s = Self { + adc, + sample_time: SampleTime::from_bits(0), + }; + crate::pac::RCC.ahb2enr1().modify(|w| { + w.set_adc12en(true); + }); + blocking_delay_us(100); + + info!("chungus {}", line!()); + s.power_up(); + info!("chungus {}", line!()); + s.configure_differential_inputs(); + + info!("chungus {}", line!()); + s.calibrate(); + info!("chungus {}", line!()); + blocking_delay_us(1); + + info!("chungus {}", line!()); + s.enable(); + info!("chungus {}", line!()); + s.configure(); + info!("chungus {}", line!()); + + s + } + + fn power_up(&mut self) { + T::regs().isr().modify(|reg| { + reg.set_ldordy(true); + }); + info!("yummmum {}", T::regs().cr().as_ptr() as u32); + T::regs().cr().modify(|reg| { + info!("bajssis {}", reg.0); + reg.set_deeppwd(false); + info!("bajssis {}", reg.0); + reg.set_advregen(true); + info!("bajssis {}", reg.0); + }); + info!("kissis {}", T::regs().as_ptr() as u32); + info!("basdsadasadjsisssss{}", T::regs().isr().as_ptr() as u32); + while !T::regs().isr().read().ldordy() { + // info!("bajsisssss{}", T::regs().isr().read().0); + }; + + T::regs().isr().modify(|reg| { + reg.set_ldordy(true); + }); + } + + fn configure_differential_inputs(&mut self) { + T::regs().difsel().modify(|w| { + for n in 0..20 { + w.set_difsel(n, Difsel::SINGLEENDED); + } + }); + } + + fn calibrate(&mut self) { + T::regs().cr().modify(|w| { + w.set_adcallin(true); + w.set_aden(false) + }); + T::regs().calfact().modify(|w| { + w.set_capture_coef(false); + w.set_latch_coef(false) + }); + + T::regs().cr().modify(|w| w.set_adcal(true)); + while T::regs().cr().read().adcal() {} + } + + fn enable(&mut self) { + T::regs().isr().write(|w| w.set_adrdy(true)); + T::regs().cr().modify(|w| w.set_aden(true)); + while !T::regs().isr().read().adrdy() {} + T::regs().isr().write(|w| w.set_adrdy(true)); + } + + fn configure(&mut self) { + // single conversion mode, software trigger + T::regs().cfgr().modify(|w| { + w.set_cont(false); + w.set_exten(Exten::DISABLED); + }); + } + + /// Enable reading the voltage reference internal channel. + pub fn enable_vrefint(&self) -> VrefInt { + T::common_regs().ccr().modify(|reg| { + reg.set_vrefen(true); + }); + + VrefInt {} + } + + /// Enable reading the temperature internal channel. + pub fn enable_temperature(&self) -> Temperature { + T::common_regs().ccr().modify(|reg| { + reg.set_vsenseen(true); + }); + + Temperature {} + } + + /// Enable reading the vbat internal channel. + pub fn enable_vbat(&self) -> Vbat { + T::common_regs().ccr().modify(|reg| { + reg.set_vbaten(true); + }); + + Vbat {} + } + + /// Set the ADC sample time. + pub fn set_sample_time(&mut self, sample_time: SampleTime) { + self.sample_time = sample_time; + } + + /// Get the ADC sample time. + pub fn sample_time(&self) -> SampleTime { + self.sample_time + } + + /// Set the ADC resolution. + pub fn set_resolution(&mut self, resolution: Resolution) { + T::regs().cfgr().modify(|reg| reg.set_res(resolution.into())); + } + + /// Set hardware averaging. + pub fn set_averaging(&mut self, averaging: Averaging) { + let (enable, samples, right_shift) = match averaging { + Averaging::Disabled => (false, 0, 0), + Averaging::Samples2 => (true, 1, 1), + Averaging::Samples4 => (true, 3, 2), + Averaging::Samples8 => (true, 7, 3), + Averaging::Samples16 => (true, 15, 4), + Averaging::Samples32 => (true, 31, 5), + Averaging::Samples64 => (true, 63, 6), + Averaging::Samples128 => (true, 127, 7), + Averaging::Samples256 => (true, 255, 8), + Averaging::Samples512 => (true, 511, 9), + Averaging::Samples1024 => (true, 1023, 10), + }; + + T::regs().cfgr2().modify(|reg| { + reg.set_rovse(enable); + reg.set_osvr(samples); + reg.set_ovss(right_shift); + }) + } + + /// Perform a single conversion. + fn convert(&mut self) -> u16 { + T::regs().isr().modify(|reg| { + reg.set_eos(true); + reg.set_eoc(true); + }); + + // Start conversion + T::regs().cr().modify(|reg| { + reg.set_adstart(true); + }); + + while !T::regs().isr().read().eos() { + // spin + } + + T::regs().dr().read().0 as u16 + } + + /// Read an ADC channel. + pub fn blocking_read(&mut self, channel: &mut impl AdcChannel) -> u16 { + self.read_channel(channel) + } + + fn configure_channel(channel: &mut impl AdcChannel, sample_time: SampleTime) { + channel.setup(); + + let channel = channel.channel(); + + Self::set_channel_sample_time(channel, sample_time); + + T::regs().cfgr2().modify(|w| w.set_lshift(0)); + T::regs() + .pcsel() + .modify(|w| w.set_pcsel(channel as _, Pcsel::PRESELECTED)); + } + + fn read_channel(&mut self, channel: &mut impl AdcChannel) -> u16 { + Self::configure_channel(channel, self.sample_time); + + T::regs().sqr1().modify(|reg| { + reg.set_sq(0, channel.channel()); + reg.set_l(0); + }); + + self.convert() + } + + fn set_channel_sample_time(ch: u8, sample_time: SampleTime) { + let sample_time = sample_time.into(); + if ch <= 9 { + T::regs().smpr(0).modify(|reg| reg.set_smp(ch as _, sample_time)); + } else { + T::regs().smpr(1).modify(|reg| reg.set_smp((ch - 10) as _, sample_time)); + } + } + + fn cancel_conversions() { + if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() { + T::regs().cr().modify(|reg| { + reg.set_adstp(true); + }); + while T::regs().cr().read().adstart() {} + } + } +} From 3d6a270f30c45eaf394c8eb8bf182dd1a7ec2d7b Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Wed, 11 Sep 2024 19:44:11 -0400 Subject: [PATCH 0123/1217] rp: Fix indexing for pins >31 on rp235xb (#3330) * Fix indexing for pins >31 on rp235xb * fixup knowing that 1<<7 is 128 not 64 --- embassy-rp/src/gpio.rs | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/embassy-rp/src/gpio.rs b/embassy-rp/src/gpio.rs index d0bb7e574..31397172c 100644 --- a/embassy-rp/src/gpio.rs +++ b/embassy-rp/src/gpio.rs @@ -846,12 +846,12 @@ pub(crate) trait SealedPin: Sized { #[inline] fn _pin(&self) -> u8 { - self.pin_bank() & 0x1f + self.pin_bank() & 0x7f } #[inline] fn _bank(&self) -> Bank { - match self.pin_bank() >> 5 { + match self.pin_bank() >> 7 { #[cfg(feature = "qspi-as-gpio")] 1 => Bank::Qspi, _ => Bank::Bank0, @@ -880,15 +880,27 @@ pub(crate) trait SealedPin: Sized { } fn sio_out(&self) -> pac::sio::Gpio { - SIO.gpio_out(self._bank() as _) + if cfg!(feature = "rp2040") { + SIO.gpio_out(self._bank() as _) + } else { + SIO.gpio_out((self._pin() / 32) as _) + } } fn sio_oe(&self) -> pac::sio::Gpio { - SIO.gpio_oe(self._bank() as _) + if cfg!(feature = "rp2040") { + SIO.gpio_oe(self._bank() as _) + } else { + SIO.gpio_oe((self._pin() / 32) as _) + } } fn sio_in(&self) -> Reg { - SIO.gpio_in(self._bank() as _) + if cfg!(feature = "rp2040") { + SIO.gpio_in(self._bank() as _) + } else { + SIO.gpio_in((self._pin() / 32) as _) + } } fn int_proc(&self) -> pac::io::Int { @@ -953,7 +965,7 @@ macro_rules! impl_pin { impl SealedPin for peripherals::$name { #[inline] fn pin_bank(&self) -> u8 { - ($bank as u8) * 32 + $pin_num + ($bank as u8) * 128 + $pin_num } } From eeda57a4245019ec1acd13afd9d826679d5ebb5e Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Thu, 12 Sep 2024 11:37:17 -0400 Subject: [PATCH 0124/1217] rp2350 pio pin fixes Disable pad isolation on any used pin. Use GPIOBASE and offset pin bases if all pins are > 16, panic if some pins are < 16 and some are > 31 --- embassy-rp/src/pio/mod.rs | 120 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 120 insertions(+) diff --git a/embassy-rp/src/pio/mod.rs b/embassy-rp/src/pio/mod.rs index 68b1d6849..0d489763c 100644 --- a/embassy-rp/src/pio/mod.rs +++ b/embassy-rp/src/pio/mod.rs @@ -655,6 +655,10 @@ impl<'d, PIO: Instance> Config<'d, PIO> { /// Set pin used to signal jump. pub fn set_jmp_pin(&mut self, pin: &Pin<'d, PIO>) { + #[cfg(feature = "_rp235x")] + pin.pin.pad_ctrl().modify(|w| { + w.set_iso(false); + }); self.exec.jmp_pin = pin.pin(); } @@ -664,6 +668,12 @@ impl<'d, PIO: Instance> Config<'d, PIO> { pub fn set_set_pins(&mut self, pins: &[&Pin<'d, PIO>]) { assert!(pins.len() <= 5); assert_consecutive(pins); + #[cfg(feature = "_rp235x")] + for pin in pins { + pin.pin.pad_ctrl().modify(|w| { + w.set_iso(false); + }) + } self.pins.set_base = pins.first().map_or(0, |p| p.pin()); self.pins.set_count = pins.len() as u8; } @@ -673,6 +683,12 @@ impl<'d, PIO: Instance> Config<'d, PIO> { /// effective. pub fn set_out_pins(&mut self, pins: &[&Pin<'d, PIO>]) { assert_consecutive(pins); + #[cfg(feature = "_rp235x")] + for pin in pins { + pin.pin.pad_ctrl().modify(|w| { + w.set_iso(false); + }) + } self.pins.out_base = pins.first().map_or(0, |p| p.pin()); self.pins.out_count = pins.len() as u8; } @@ -682,6 +698,12 @@ impl<'d, PIO: Instance> Config<'d, PIO> { /// effective. pub fn set_in_pins(&mut self, pins: &[&Pin<'d, PIO>]) { assert_consecutive(pins); + #[cfg(feature = "_rp235x")] + for pin in pins { + pin.pin.pad_ctrl().modify(|w| { + w.set_iso(false); + }) + } self.pins.in_base = pins.first().map_or(0, |p| p.pin()); self.in_count = pins.len() as u8; } @@ -731,6 +753,8 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> { w.set_autopull(config.shift_out.auto_fill); w.set_autopush(config.shift_in.auto_fill); }); + + #[cfg(feature = "rp2040")] sm.pinctrl().write(|w| { w.set_sideset_count(config.pins.sideset_count); w.set_set_count(config.pins.set_count); @@ -740,6 +764,102 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> { w.set_set_base(config.pins.set_base); w.set_out_base(config.pins.out_base); }); + + #[cfg(feature = "_rp235x")] + { + let shift_gpio_base = { + match ( + if config.in_count > 0 { + Some(config.pins.in_base) + } else { + None + }, + if config.pins.sideset_count > 0 { + Some(config.pins.sideset_base) + } else { + None + }, + if config.pins.set_count > 0 { + Some(config.pins.set_base) + } else { + None + }, + if config.pins.out_count > 0 { + Some(config.pins.out_base) + } else { + None + }, + ) { + (None, None, None, None) => false, + + (Some(0..31), None, None, None) => false, + (None, Some(0..31), None, None) => false, + (None, None, Some(0..31), None) => false, + (None, None, None, Some(0..31)) => false, + + (Some(0..31), Some(0..31), None, None) => false, + (None, Some(0..31), Some(0..31), None) => false, + (None, None, Some(0..31), Some(0..31)) => false, + (Some(0..31), None, None, Some(0..31)) => false, + + (None, Some(0..31), Some(0..31), Some(0..31)) => false, + (Some(0..31), None, Some(0..31), Some(0..31)) => false, + (Some(0..31), Some(0..31), None, Some(0..31)) => false, + (Some(0..31), Some(0..31), Some(0..31), None) => false, + + (Some(0..31), Some(0..31), Some(0..31), Some(0..31)) => false, + + (Some(16..48), None, None, None) => true, + (None, Some(16..48), None, None) => true, + (None, None, Some(16..48), None) => true, + (None, None, None, Some(16..48)) => true, + + (Some(16..48), Some(16..48), None, None) => true, + (None, Some(16..48), Some(16..48), None) => true, + (None, None, Some(16..48), Some(16..48)) => true, + (Some(16..48), None, None, Some(16..48)) => true, + + (None, Some(16..48), Some(16..48), Some(16..48)) => true, + (Some(16..48), None, Some(16..48), Some(16..48)) => true, + (Some(16..48), Some(16..48), None, Some(16..48)) => true, + (Some(16..48), Some(16..48), Some(16..48), None) => true, + + (Some(16..48), Some(16..48), Some(16..48), Some(16..48)) => true, + + (i, side, set, out) => panic!( + "All pins must either be < 31 or >16, in:{}, side:{}, set:{}, out:{}", + i, side, set, out + ), + } + }; + + info!("shift: {}", shift_gpio_base); + + if shift_gpio_base { + sm.pinctrl().write(|w| { + w.set_sideset_count(config.pins.sideset_count); + w.set_set_count(config.pins.set_count); + w.set_out_count(config.pins.out_count); + w.set_in_base(config.pins.in_base - 16); + w.set_sideset_base(config.pins.sideset_base - 16); + w.set_set_base(config.pins.set_base - 16); + w.set_out_base(config.pins.out_base - 16); + }); + } else { + sm.pinctrl().write(|w| { + w.set_sideset_count(config.pins.sideset_count); + w.set_set_count(config.pins.set_count); + w.set_out_count(config.pins.out_count); + w.set_in_base(config.pins.in_base); + w.set_sideset_base(config.pins.sideset_base); + w.set_set_base(config.pins.set_base); + w.set_out_base(config.pins.out_base); + }); + } + + PIO::PIO.gpiobase().write(|w| w.set_gpiobase(shift_gpio_base)); + } + if let Some(origin) = config.origin { unsafe { instr::exec_jmp(self, origin) } } From 823a82adb7206435794c769be699e1b972d6f966 Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Thu, 12 Sep 2024 11:43:15 -0400 Subject: [PATCH 0125/1217] Fixup formatting to work with log --- embassy-rp/src/pio/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-rp/src/pio/mod.rs b/embassy-rp/src/pio/mod.rs index 0d489763c..ec29a690c 100644 --- a/embassy-rp/src/pio/mod.rs +++ b/embassy-rp/src/pio/mod.rs @@ -827,7 +827,7 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> { (Some(16..48), Some(16..48), Some(16..48), Some(16..48)) => true, (i, side, set, out) => panic!( - "All pins must either be < 31 or >16, in:{}, side:{}, set:{}, out:{}", + "All pins must either be < 31 or >16, in:{:?}, side:{:?}, set:{:?}, out:{:?}", i, side, set, out ), } From e359b24121d9747ea8260d8887829b6a97c312f1 Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Thu, 12 Sep 2024 11:50:36 -0400 Subject: [PATCH 0126/1217] remove debug print --- embassy-rp/src/pio/mod.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/embassy-rp/src/pio/mod.rs b/embassy-rp/src/pio/mod.rs index ec29a690c..2b1ed554e 100644 --- a/embassy-rp/src/pio/mod.rs +++ b/embassy-rp/src/pio/mod.rs @@ -833,8 +833,6 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> { } }; - info!("shift: {}", shift_gpio_base); - if shift_gpio_base { sm.pinctrl().write(|w| { w.set_sideset_count(config.pins.sideset_count); From ed6cbc7a3a1082b2063162cbf30fb6f9979d81ad Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Sun, 15 Sep 2024 20:09:18 -0400 Subject: [PATCH 0127/1217] Fix upper bound of case where pins should be <=31 --- embassy-rp/src/pio/mod.rs | 54 +++++++++++++++++++-------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/embassy-rp/src/pio/mod.rs b/embassy-rp/src/pio/mod.rs index 2b1ed554e..e8e411a25 100644 --- a/embassy-rp/src/pio/mod.rs +++ b/embassy-rp/src/pio/mod.rs @@ -792,42 +792,42 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> { ) { (None, None, None, None) => false, - (Some(0..31), None, None, None) => false, - (None, Some(0..31), None, None) => false, - (None, None, Some(0..31), None) => false, - (None, None, None, Some(0..31)) => false, + (Some(..32), None, None, None) => false, + (None, Some(..32), None, None) => false, + (None, None, Some(..32), None) => false, + (None, None, None, Some(..32)) => false, - (Some(0..31), Some(0..31), None, None) => false, - (None, Some(0..31), Some(0..31), None) => false, - (None, None, Some(0..31), Some(0..31)) => false, - (Some(0..31), None, None, Some(0..31)) => false, + (Some(..32), Some(..32), None, None) => false, + (None, Some(..32), Some(..32), None) => false, + (None, None, Some(..32), Some(..32)) => false, + (Some(..32), None, None, Some(..32)) => false, - (None, Some(0..31), Some(0..31), Some(0..31)) => false, - (Some(0..31), None, Some(0..31), Some(0..31)) => false, - (Some(0..31), Some(0..31), None, Some(0..31)) => false, - (Some(0..31), Some(0..31), Some(0..31), None) => false, + (None, Some(..32), Some(..32), Some(..32)) => false, + (Some(..32), None, Some(..32), Some(..32)) => false, + (Some(..32), Some(..32), None, Some(..32)) => false, + (Some(..32), Some(..32), Some(..32), None) => false, - (Some(0..31), Some(0..31), Some(0..31), Some(0..31)) => false, + (Some(..32), Some(..32), Some(..32), Some(..32)) => false, - (Some(16..48), None, None, None) => true, - (None, Some(16..48), None, None) => true, - (None, None, Some(16..48), None) => true, - (None, None, None, Some(16..48)) => true, + (Some(16..), None, None, None) => true, + (None, Some(16..), None, None) => true, + (None, None, Some(16..), None) => true, + (None, None, None, Some(16..)) => true, - (Some(16..48), Some(16..48), None, None) => true, - (None, Some(16..48), Some(16..48), None) => true, - (None, None, Some(16..48), Some(16..48)) => true, - (Some(16..48), None, None, Some(16..48)) => true, + (Some(16..), Some(16..), None, None) => true, + (None, Some(16..), Some(16..), None) => true, + (None, None, Some(16..), Some(16..)) => true, + (Some(16..), None, None, Some(16..)) => true, - (None, Some(16..48), Some(16..48), Some(16..48)) => true, - (Some(16..48), None, Some(16..48), Some(16..48)) => true, - (Some(16..48), Some(16..48), None, Some(16..48)) => true, - (Some(16..48), Some(16..48), Some(16..48), None) => true, + (None, Some(16..), Some(16..), Some(16..)) => true, + (Some(16..), None, Some(16..), Some(16..)) => true, + (Some(16..), Some(16..), None, Some(16..)) => true, + (Some(16..), Some(16..), Some(16..), None) => true, - (Some(16..48), Some(16..48), Some(16..48), Some(16..48)) => true, + (Some(16..), Some(16..), Some(16..), Some(16..)) => true, (i, side, set, out) => panic!( - "All pins must either be < 31 or >16, in:{:?}, side:{:?}, set:{:?}, out:{:?}", + "All pins must either be <=31 or >=16, in:{:?}, side:{:?}, set:{:?}, out:{:?}", i, side, set, out ), } From 55c3da5a4f48ea6c66371484c83d6298cde3befe Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Sun, 15 Sep 2024 20:48:54 -0400 Subject: [PATCH 0128/1217] Properly drop pins >30 --- embassy-rp/src/gpio.rs | 4 ++-- embassy-rp/src/pio/mod.rs | 9 ++++----- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/embassy-rp/src/gpio.rs b/embassy-rp/src/gpio.rs index 31397172c..520043b07 100644 --- a/embassy-rp/src/gpio.rs +++ b/embassy-rp/src/gpio.rs @@ -16,9 +16,9 @@ use crate::{interrupt, pac, peripherals, Peripheral, RegExt}; const NEW_AW: AtomicWaker = AtomicWaker::new(); #[cfg(any(feature = "rp2040", feature = "rp235xa"))] -const BANK0_PIN_COUNT: usize = 30; +pub(crate) const BANK0_PIN_COUNT: usize = 30; #[cfg(feature = "rp235xb")] -const BANK0_PIN_COUNT: usize = 48; +pub(crate) const BANK0_PIN_COUNT: usize = 48; static BANK0_WAKERS: [AtomicWaker; BANK0_PIN_COUNT] = [NEW_AW; BANK0_PIN_COUNT]; #[cfg(feature = "qspi-as-gpio")] diff --git a/embassy-rp/src/pio/mod.rs b/embassy-rp/src/pio/mod.rs index e8e411a25..fc940b045 100644 --- a/embassy-rp/src/pio/mod.rs +++ b/embassy-rp/src/pio/mod.rs @@ -5,7 +5,7 @@ use core::pin::Pin as FuturePin; use core::sync::atomic::{compiler_fence, Ordering}; use core::task::{Context, Poll}; -use atomic_polyfill::{AtomicU32, AtomicU8}; +use atomic_polyfill::{AtomicU64, AtomicU8}; use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; use embassy_sync::waitqueue::AtomicWaker; use fixed::types::extra::U8; @@ -1305,7 +1305,7 @@ impl<'d, PIO: Instance> Pio<'d, PIO> { // other way. pub struct State { users: AtomicU8, - used_pins: AtomicU32, + used_pins: AtomicU64, } fn on_pio_drop() { @@ -1313,8 +1313,7 @@ fn on_pio_drop() { if state.users.fetch_sub(1, Ordering::AcqRel) == 1 { let used_pins = state.used_pins.load(Ordering::Relaxed); let null = pac::io::vals::Gpio0ctrlFuncsel::NULL as _; - // we only have 30 pins. don't test the other two since gpio() asserts. - for i in 0..30 { + for i in 0..crate::gpio::BANK0_PIN_COUNT { if used_pins & (1 << i) != 0 { pac::IO_BANK0.gpio(i).ctrl().write(|w| w.set_funcsel(null)); } @@ -1339,7 +1338,7 @@ trait SealedInstance { fn state() -> &'static State { static STATE: State = State { users: AtomicU8::new(0), - used_pins: AtomicU32::new(0), + used_pins: AtomicU64::new(0), }; &STATE From 8519e54461b8d3c3c2a97c88823498c878187ba4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20H=C3=A9riveaux?= Date: Mon, 16 Sep 2024 11:48:54 +0200 Subject: [PATCH 0129/1217] fix(boot): return signature error when no features Always return signature error in verify_and_mark_updated when no signature features are enabled. --- embassy-boot/src/firmware_updater/asynch.rs | 12 ++++++++---- embassy-boot/src/firmware_updater/blocking.rs | 12 ++++++++---- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/embassy-boot/src/firmware_updater/asynch.rs b/embassy-boot/src/firmware_updater/asynch.rs index 26f65f295..86b441592 100644 --- a/embassy-boot/src/firmware_updater/asynch.rs +++ b/embassy-boot/src/firmware_updater/asynch.rs @@ -107,7 +107,8 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> FirmwareUpdater<'d, DFU, STATE> { let mut message = [0; 64]; self.hash::(_update_len, &mut chunk_buf, &mut message).await?; - public_key.verify(&message, &signature).map_err(into_signature_error)? + public_key.verify(&message, &signature).map_err(into_signature_error)?; + return self.state.mark_updated().await; } #[cfg(feature = "ed25519-salty")] { @@ -134,10 +135,13 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> FirmwareUpdater<'d, DFU, STATE> { message, r.is_ok() ); - r.map_err(into_signature_error)? + r.map_err(into_signature_error)?; + return self.state.mark_updated().await; + } + #[cfg(not(any(feature = "ed25519-dalek", feature = "ed25519-salty")))] + { + Err(FirmwareUpdaterError::Signature(signature::Error::new())) } - - self.state.mark_updated().await } /// Verify the update in DFU with any digest. diff --git a/embassy-boot/src/firmware_updater/blocking.rs b/embassy-boot/src/firmware_updater/blocking.rs index 35772a856..d3c723456 100644 --- a/embassy-boot/src/firmware_updater/blocking.rs +++ b/embassy-boot/src/firmware_updater/blocking.rs @@ -142,7 +142,8 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> BlockingFirmwareUpdater<'d, DFU, STATE> let mut chunk_buf = [0; 2]; self.hash::(_update_len, &mut chunk_buf, &mut message)?; - public_key.verify(&message, &signature).map_err(into_signature_error)? + public_key.verify(&message, &signature).map_err(into_signature_error)?; + return self.state.mark_updated(); } #[cfg(feature = "ed25519-salty")] { @@ -169,10 +170,13 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> BlockingFirmwareUpdater<'d, DFU, STATE> message, r.is_ok() ); - r.map_err(into_signature_error)? + r.map_err(into_signature_error)?; + return self.state.mark_updated(); + } + #[cfg(not(any(feature = "ed25519-dalek", feature = "ed25519-salty")))] + { + Err(FirmwareUpdaterError::Signature(signature::Error::new())) } - - self.state.mark_updated() } /// Verify the update in DFU with any digest. From 313e76af043c8b2bb2b31f8cc0eba7578ea41357 Mon Sep 17 00:00:00 2001 From: Sebastian Quilitz Date: Mon, 16 Sep 2024 12:26:00 +0200 Subject: [PATCH 0130/1217] rp: add constructor for tx-only blocking UART --- embassy-rp/src/uart/mod.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/embassy-rp/src/uart/mod.rs b/embassy-rp/src/uart/mod.rs index aba4b792a..c94e5e185 100644 --- a/embassy-rp/src/uart/mod.rs +++ b/embassy-rp/src/uart/mod.rs @@ -224,6 +224,17 @@ impl<'d, T: Instance, M: Mode> UartTx<'d, T, M> { } impl<'d, T: Instance> UartTx<'d, T, Blocking> { + /// Create a new UART TX instance for blocking mode operations. + pub fn new_blocking( + _uart: impl Peripheral

+ 'd, + tx: impl Peripheral

> + 'd, + config: Config, + ) -> Self { + into_ref!(tx); + Uart::::init(Some(tx.map_into()), None, None, None, config); + Self::new_inner(None) + } + /// Convert this uart TX instance into a buffered uart using the provided /// irq and transmit buffer. pub fn into_buffered( From 48fd0550d1569a44a6b58a41423b0f86270fb373 Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Mon, 16 Sep 2024 12:41:12 -0400 Subject: [PATCH 0131/1217] Review fixes Don't overflow on subtract Replace giant match with for loop dedupe register write --- embassy-rp/src/pio/mod.rs | 130 +++++++++++++------------------------- 1 file changed, 43 insertions(+), 87 deletions(-) diff --git a/embassy-rp/src/pio/mod.rs b/embassy-rp/src/pio/mod.rs index fc940b045..ace597f00 100644 --- a/embassy-rp/src/pio/mod.rs +++ b/embassy-rp/src/pio/mod.rs @@ -767,95 +767,51 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> { #[cfg(feature = "_rp235x")] { - let shift_gpio_base = { - match ( - if config.in_count > 0 { - Some(config.pins.in_base) - } else { - None - }, - if config.pins.sideset_count > 0 { - Some(config.pins.sideset_base) - } else { - None - }, - if config.pins.set_count > 0 { - Some(config.pins.set_base) - } else { - None - }, - if config.pins.out_count > 0 { - Some(config.pins.out_base) - } else { - None - }, - ) { - (None, None, None, None) => false, - - (Some(..32), None, None, None) => false, - (None, Some(..32), None, None) => false, - (None, None, Some(..32), None) => false, - (None, None, None, Some(..32)) => false, - - (Some(..32), Some(..32), None, None) => false, - (None, Some(..32), Some(..32), None) => false, - (None, None, Some(..32), Some(..32)) => false, - (Some(..32), None, None, Some(..32)) => false, - - (None, Some(..32), Some(..32), Some(..32)) => false, - (Some(..32), None, Some(..32), Some(..32)) => false, - (Some(..32), Some(..32), None, Some(..32)) => false, - (Some(..32), Some(..32), Some(..32), None) => false, - - (Some(..32), Some(..32), Some(..32), Some(..32)) => false, - - (Some(16..), None, None, None) => true, - (None, Some(16..), None, None) => true, - (None, None, Some(16..), None) => true, - (None, None, None, Some(16..)) => true, - - (Some(16..), Some(16..), None, None) => true, - (None, Some(16..), Some(16..), None) => true, - (None, None, Some(16..), Some(16..)) => true, - (Some(16..), None, None, Some(16..)) => true, - - (None, Some(16..), Some(16..), Some(16..)) => true, - (Some(16..), None, Some(16..), Some(16..)) => true, - (Some(16..), Some(16..), None, Some(16..)) => true, - (Some(16..), Some(16..), Some(16..), None) => true, - - (Some(16..), Some(16..), Some(16..), Some(16..)) => true, - - (i, side, set, out) => panic!( - "All pins must either be <=31 or >=16, in:{:?}, side:{:?}, set:{:?}, out:{:?}", - i, side, set, out - ), - } - }; - - if shift_gpio_base { - sm.pinctrl().write(|w| { - w.set_sideset_count(config.pins.sideset_count); - w.set_set_count(config.pins.set_count); - w.set_out_count(config.pins.out_count); - w.set_in_base(config.pins.in_base - 16); - w.set_sideset_base(config.pins.sideset_base - 16); - w.set_set_base(config.pins.set_base - 16); - w.set_out_base(config.pins.out_base - 16); - }); - } else { - sm.pinctrl().write(|w| { - w.set_sideset_count(config.pins.sideset_count); - w.set_set_count(config.pins.set_count); - w.set_out_count(config.pins.out_count); - w.set_in_base(config.pins.in_base); - w.set_sideset_base(config.pins.sideset_base); - w.set_set_base(config.pins.set_base); - w.set_out_base(config.pins.out_base); - }); + let mut low_ok = true; + let mut high_ok = true; + for pin in [ + config.pins.in_base, + config.pins.in_base + config.in_count, + config.pins.sideset_base, + config.pins.sideset_base + config.pins.sideset_count, + config.pins.set_base, + config.pins.set_base + config.pins.set_count, + config.pins.out_base, + config.pins.out_base + config.pins.out_count, + ] + .iter() + .flatten() + { + low_ok &= pin < 32; + high_ok &= pin >= 16; } - PIO::PIO.gpiobase().write(|w| w.set_gpiobase(shift_gpio_base)); + if !low_ok && !high_ok { + panic!( + "All pins must either be <32 or >=16, in:{:?}-{:?}, side:{:?}-{:?}, set:{:?}-{:?}, out:{:?}-{:?}", + config.pins.in_base, + config.pins.in_base + config.in_count, + config.pins.sideset_base, + config.pins.sideset_base + config.pins.sideset_count, + config.pins.set_base, + config.pins.set_base + config.pins.set_count, + config.pins.out_base, + config.pins.out_base + config.pins.out_count, + ) + } + let shift = if low_ok { 0 } else { 16 }; + + sm.pinctrl().write(|w| { + w.set_sideset_count(config.pins.sideset_count); + w.set_set_count(config.pins.set_count); + w.set_out_count(config.pins.out_count); + w.set_in_base(config.pins.in_base.checked_sub(shift).unwrap_or_default()); + w.set_sideset_base(config.pins.sideset_base.checked_sub(shift).unwrap_or_default()); + w.set_set_base(config.pins.set_base.checked_sub(shift).unwrap_or_default()); + w.set_out_base(config.pins.out_base.checked_sub(shift).unwrap_or_default()); + }); + + PIO::PIO.gpiobase().write(|w| w.set_gpiobase(shift == 16)); } if let Some(origin) = config.origin { From 9cfde66446ca5451a6cab80e0f2f783199fbeb62 Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Mon, 16 Sep 2024 12:47:07 -0400 Subject: [PATCH 0132/1217] Move pin isolation config to make_pio_pin --- embassy-rp/src/pio/mod.rs | 31 +++++-------------------------- 1 file changed, 5 insertions(+), 26 deletions(-) diff --git a/embassy-rp/src/pio/mod.rs b/embassy-rp/src/pio/mod.rs index ace597f00..b08f2df6b 100644 --- a/embassy-rp/src/pio/mod.rs +++ b/embassy-rp/src/pio/mod.rs @@ -655,10 +655,6 @@ impl<'d, PIO: Instance> Config<'d, PIO> { /// Set pin used to signal jump. pub fn set_jmp_pin(&mut self, pin: &Pin<'d, PIO>) { - #[cfg(feature = "_rp235x")] - pin.pin.pad_ctrl().modify(|w| { - w.set_iso(false); - }); self.exec.jmp_pin = pin.pin(); } @@ -668,12 +664,6 @@ impl<'d, PIO: Instance> Config<'d, PIO> { pub fn set_set_pins(&mut self, pins: &[&Pin<'d, PIO>]) { assert!(pins.len() <= 5); assert_consecutive(pins); - #[cfg(feature = "_rp235x")] - for pin in pins { - pin.pin.pad_ctrl().modify(|w| { - w.set_iso(false); - }) - } self.pins.set_base = pins.first().map_or(0, |p| p.pin()); self.pins.set_count = pins.len() as u8; } @@ -683,12 +673,6 @@ impl<'d, PIO: Instance> Config<'d, PIO> { /// effective. pub fn set_out_pins(&mut self, pins: &[&Pin<'d, PIO>]) { assert_consecutive(pins); - #[cfg(feature = "_rp235x")] - for pin in pins { - pin.pin.pad_ctrl().modify(|w| { - w.set_iso(false); - }) - } self.pins.out_base = pins.first().map_or(0, |p| p.pin()); self.pins.out_count = pins.len() as u8; } @@ -698,12 +682,6 @@ impl<'d, PIO: Instance> Config<'d, PIO> { /// effective. pub fn set_in_pins(&mut self, pins: &[&Pin<'d, PIO>]) { assert_consecutive(pins); - #[cfg(feature = "_rp235x")] - for pin in pins { - pin.pin.pad_ctrl().modify(|w| { - w.set_iso(false); - }) - } self.pins.in_base = pins.first().map_or(0, |p| p.pin()); self.in_count = pins.len() as u8; } @@ -778,10 +756,7 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> { config.pins.set_base + config.pins.set_count, config.pins.out_base, config.pins.out_base + config.pins.out_count, - ] - .iter() - .flatten() - { + ] { low_ok &= pin < 32; high_ok &= pin >= 16; } @@ -1080,6 +1055,10 @@ impl<'d, PIO: Instance> Common<'d, PIO> { pub fn make_pio_pin(&mut self, pin: impl Peripheral

+ 'd) -> Pin<'d, PIO> { into_ref!(pin); pin.gpio().ctrl().write(|w| w.set_funcsel(PIO::FUNCSEL as _)); + #[cfg(feature = "_rp235x")] + pin.pad_ctrl().modify(|w| { + w.set_iso(false); + }); // we can be relaxed about this because we're &mut here and nothing is cached PIO::state().used_pins.fetch_or(1 << pin.pin_bank(), Ordering::Relaxed); Pin { From 6e0c3e25fd8e07ce3ee46e0ba74064a4c4574e16 Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Mon, 16 Sep 2024 12:58:23 -0400 Subject: [PATCH 0133/1217] Only check ping groups that have count >0 --- embassy-rp/src/pio/mod.rs | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/embassy-rp/src/pio/mod.rs b/embassy-rp/src/pio/mod.rs index b08f2df6b..29a5bfab3 100644 --- a/embassy-rp/src/pio/mod.rs +++ b/embassy-rp/src/pio/mod.rs @@ -743,22 +743,21 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> { w.set_out_base(config.pins.out_base); }); - #[cfg(feature = "_rp235x")] + //#[cfg(feature = "_rp235x")] { let mut low_ok = true; let mut high_ok = true; - for pin in [ - config.pins.in_base, - config.pins.in_base + config.in_count, - config.pins.sideset_base, - config.pins.sideset_base + config.pins.sideset_count, - config.pins.set_base, - config.pins.set_base + config.pins.set_count, - config.pins.out_base, - config.pins.out_base + config.pins.out_count, - ] { - low_ok &= pin < 32; - high_ok &= pin >= 16; + + let in_pins = config.pins.in_base..config.pins.in_base + config.in_count; + let side_pins = config.pins.sideset_base..config.pins.sideset_base + config.pins.sideset_count; + let set_pins = config.pins.set_base..config.pins.set_base + config.pins.set_count; + let out_pins = config.pins.out_base..config.pins.out_base + config.pins.out_count; + + for pin_range in [in_pins, side_pins, set_pins, out_pins] { + for pin in pin_range { + low_ok &= pin < 32; + high_ok &= pin >= 16; + } } if !low_ok && !high_ok { From 8b34c94ef3640b2ec28b3de3c5d90db40b0b0ecd Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Mon, 16 Sep 2024 13:02:35 -0400 Subject: [PATCH 0134/1217] Improve error message when pin groups are not allowed --- embassy-rp/src/pio/mod.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/embassy-rp/src/pio/mod.rs b/embassy-rp/src/pio/mod.rs index 29a5bfab3..b2f9abaa0 100644 --- a/embassy-rp/src/pio/mod.rs +++ b/embassy-rp/src/pio/mod.rs @@ -764,13 +764,13 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> { panic!( "All pins must either be <32 or >=16, in:{:?}-{:?}, side:{:?}-{:?}, set:{:?}-{:?}, out:{:?}-{:?}", config.pins.in_base, - config.pins.in_base + config.in_count, + config.pins.in_base + config.in_count - 1, config.pins.sideset_base, - config.pins.sideset_base + config.pins.sideset_count, + config.pins.sideset_base + config.pins.sideset_count - 1, config.pins.set_base, - config.pins.set_base + config.pins.set_count, + config.pins.set_base + config.pins.set_count - 1, config.pins.out_base, - config.pins.out_base + config.pins.out_count, + config.pins.out_base + config.pins.out_count - 1, ) } let shift = if low_ok { 0 } else { 16 }; From d1508cc49c9ac029ececb1ae5e4c326ac678d1ec Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Mon, 16 Sep 2024 13:07:16 -0400 Subject: [PATCH 0135/1217] oops --- embassy-rp/src/pio/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-rp/src/pio/mod.rs b/embassy-rp/src/pio/mod.rs index b2f9abaa0..72aa8f104 100644 --- a/embassy-rp/src/pio/mod.rs +++ b/embassy-rp/src/pio/mod.rs @@ -743,7 +743,7 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> { w.set_out_base(config.pins.out_base); }); - //#[cfg(feature = "_rp235x")] + #[cfg(feature = "_rp235x")] { let mut low_ok = true; let mut high_ok = true; From 2855e65cc6ac5a3a102f3a309b4c450efffe1417 Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Mon, 16 Sep 2024 13:24:47 -0400 Subject: [PATCH 0136/1217] Disable pad isolation on clock in/out pins --- embassy-rp/src/clocks.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs index ed146844c..f229a5acd 100644 --- a/embassy-rp/src/clocks.rs +++ b/embassy-rp/src/clocks.rs @@ -847,6 +847,10 @@ impl<'d, T: GpinPin> Gpin<'d, T> { into_ref!(gpin); gpin.gpio().ctrl().write(|w| w.set_funcsel(0x08)); + #[cfg(feature = "_rp235x")] + gpin.pad_ctrl().write(|w| { + w.set_iso(false); + }); Gpin { gpin: gpin.map_into(), @@ -861,6 +865,7 @@ impl<'d, T: GpinPin> Gpin<'d, T> { impl<'d, T: GpinPin> Drop for Gpin<'d, T> { fn drop(&mut self) { + self.gpin.pad_ctrl().write(|_| {}); self.gpin .gpio() .ctrl() @@ -921,11 +926,15 @@ pub struct Gpout<'d, T: GpoutPin> { } impl<'d, T: GpoutPin> Gpout<'d, T> { - /// Create new general purpose cloud output. + /// Create new general purpose clock output. pub fn new(gpout: impl Peripheral

+ 'd) -> Self { into_ref!(gpout); gpout.gpio().ctrl().write(|w| w.set_funcsel(0x08)); + #[cfg(feature = "_rp235x")] + gpout.pad_ctrl().write(|w| { + w.set_iso(false); + }); Self { gpout } } @@ -1005,6 +1014,7 @@ impl<'d, T: GpoutPin> Gpout<'d, T> { impl<'d, T: GpoutPin> Drop for Gpout<'d, T> { fn drop(&mut self) { self.disable(); + self.gpout.pad_ctrl().write(|_| {}); self.gpout .gpio() .ctrl() From be0d9775e3bcc3c1bd1448e357d7c6cd67b68991 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Wed, 11 Sep 2024 22:06:26 +0200 Subject: [PATCH 0137/1217] net: refactor to simplify lifetimes/generics. --- ci.sh | 2 +- embassy-net/Cargo.toml | 10 +- embassy-net/README.md | 3 +- embassy-net/src/dns.rs | 25 +- embassy-net/src/{device.rs => driver_util.rs} | 2 +- embassy-net/src/lib.rs | 445 ++++++++---------- embassy-net/src/raw.rs | 53 ++- embassy-net/src/tcp.rs | 76 +-- embassy-net/src/udp.rs | 61 +-- .../nrf52840/src/bin/ethernet_enc28j60.rs | 14 +- examples/nrf52840/src/bin/usb_ethernet.rs | 11 +- examples/nrf52840/src/bin/wifi_esp_hosted.rs | 11 +- examples/nrf9160/src/bin/modem_tcp_client.rs | 16 +- .../rp/src/bin/ethernet_w5500_multisocket.rs | 19 +- .../rp/src/bin/ethernet_w5500_tcp_client.rs | 13 +- .../rp/src/bin/ethernet_w5500_tcp_server.rs | 13 +- examples/rp/src/bin/ethernet_w5500_udp.rs | 13 +- examples/rp/src/bin/usb_ethernet.rs | 11 +- examples/rp/src/bin/wifi_ap_tcp_server.rs | 16 +- examples/rp/src/bin/wifi_scan.rs | 5 +- examples/rp/src/bin/wifi_tcp_server.rs | 16 +- examples/rp/src/bin/wifi_webrequest.rs | 16 +- examples/std/src/bin/net.rs | 11 +- examples/std/src/bin/net_dns.rs | 11 +- examples/std/src/bin/net_ppp.rs | 17 +- examples/std/src/bin/net_udp.rs | 11 +- examples/std/src/bin/tcp_accept.rs | 11 +- examples/stm32f4/src/bin/eth.rs | 13 +- examples/stm32f4/src/bin/eth_w5500.rs | 11 +- examples/stm32f4/src/bin/usb_ethernet.rs | 11 +- examples/stm32f7/src/bin/eth.rs | 13 +- examples/stm32h5/src/bin/eth.rs | 13 +- examples/stm32h7/src/bin/eth.rs | 13 +- examples/stm32h7/src/bin/eth_client.rs | 13 +- examples/stm32h7/src/bin/eth_client_mii.rs | 13 +- .../src/bin/spe_adin1110_http_server.rs | 11 +- examples/stm32l5/src/bin/usb_ethernet.rs | 11 +- tests/nrf/src/bin/ethernet_enc28j60_perf.rs | 11 +- tests/nrf/src/bin/wifi_esp_hosted_perf.rs | 13 +- tests/perf-client/src/lib.rs | 9 +- tests/rp/src/bin/cyw43-perf.rs | 13 +- tests/rp/src/bin/ethernet_w5100s_perf.rs | 13 +- tests/stm32/src/bin/eth.rs | 11 +- 43 files changed, 500 insertions(+), 604 deletions(-) rename embassy-net/src/{device.rs => driver_util.rs} (98%) diff --git a/ci.sh b/ci.sh index 8fef731a4..5e8bddb8c 100755 --- a/ci.sh +++ b/ci.sh @@ -47,7 +47,7 @@ cargo batch \ --- build --release --manifest-path embassy-sync/Cargo.toml --target thumbv6m-none-eabi --features defmt \ --- build --release --manifest-path embassy-time/Cargo.toml --target thumbv6m-none-eabi --features defmt,defmt-timestamp-uptime,generic-queue-8,mock-driver \ --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,medium-ethernet,packet-trace \ - --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,igmp,medium-ethernet \ + --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,multicast,medium-ethernet \ --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet \ --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet,dhcpv4-hostname \ --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv6,medium-ethernet \ diff --git a/embassy-net/Cargo.toml b/embassy-net/Cargo.toml index 28bac485b..2e21b4231 100644 --- a/embassy-net/Cargo.toml +++ b/embassy-net/Cargo.toml @@ -16,11 +16,11 @@ categories = [ [package.metadata.embassy_docs] src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-v$VERSION/embassy-net/src/" src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-net/src/" -features = ["defmt", "tcp", "udp", "raw", "dns", "dhcpv4", "proto-ipv6", "medium-ethernet", "medium-ip", "medium-ieee802154", "igmp", "dhcpv4-hostname"] +features = ["defmt", "tcp", "udp", "raw", "dns", "dhcpv4", "proto-ipv6", "medium-ethernet", "medium-ip", "medium-ieee802154", "multicast", "dhcpv4-hostname"] target = "thumbv7em-none-eabi" [package.metadata.docs.rs] -features = ["defmt", "tcp", "udp", "raw", "dns", "dhcpv4", "proto-ipv6", "medium-ethernet", "medium-ip", "medium-ieee802154", "igmp", "dhcpv4-hostname"] +features = ["defmt", "tcp", "udp", "raw", "dns", "dhcpv4", "proto-ipv6", "medium-ethernet", "medium-ip", "medium-ieee802154", "multicast", "dhcpv4-hostname"] [features] default = [] @@ -60,15 +60,15 @@ medium-ethernet = ["smoltcp/medium-ethernet"] medium-ip = ["smoltcp/medium-ip"] ## Enable the IEEE 802.15.4 medium medium-ieee802154 = ["smoltcp/medium-ieee802154"] -## Enable IGMP support -igmp = ["smoltcp/proto-igmp"] +## Enable multicast support (for both ipv4 and/or ipv6 if enabled) +multicast = ["smoltcp/multicast"] [dependencies] defmt = { version = "0.3", optional = true } log = { version = "0.4.14", optional = true } -smoltcp = { version = "0.11.0", default-features = false, features = [ +smoltcp = { git="https://github.com/smoltcp-rs/smoltcp", rev="dd43c8f189178b0ab3bda798ed8578b5b0a6f094", default-features = false, features = [ "socket", "async", ] } diff --git a/embassy-net/README.md b/embassy-net/README.md index 6b7d46934..1722ffc7b 100644 --- a/embassy-net/README.md +++ b/embassy-net/README.md @@ -10,8 +10,9 @@ memory management designed to work well for embedded systems, aiming for a more - IPv4, IPv6 - Ethernet and bare-IP mediums. -- TCP, UDP, DNS, DHCPv4, IGMPv4 +- TCP, UDP, DNS, DHCPv4 - TCP sockets implement the `embedded-io` async traits. +- Multicast See the [`smoltcp`](https://github.com/smoltcp-rs/smoltcp) README for a detailed list of implemented and unimplemented features of the network protocols. diff --git a/embassy-net/src/dns.rs b/embassy-net/src/dns.rs index 8ccfa4e4f..1fbaea4f0 100644 --- a/embassy-net/src/dns.rs +++ b/embassy-net/src/dns.rs @@ -9,7 +9,7 @@ pub use smoltcp::socket::dns::{DnsQuery, Socket}; pub(crate) use smoltcp::socket::dns::{GetQueryResultError, StartQueryError}; pub use smoltcp::wire::{DnsQueryType, IpAddress}; -use crate::{Driver, Stack}; +use crate::Stack; /// Errors returned by DnsSocket. #[derive(Debug, PartialEq, Eq, Clone, Copy)] @@ -44,21 +44,15 @@ impl From for Error { /// This exists only for compatibility with crates that use `embedded-nal-async`. /// Prefer using [`Stack::dns_query`](crate::Stack::dns_query) directly if you're /// not using `embedded-nal-async`. -pub struct DnsSocket<'a, D> -where - D: Driver + 'static, -{ - stack: &'a Stack, +pub struct DnsSocket<'a> { + stack: Stack<'a>, } -impl<'a, D> DnsSocket<'a, D> -where - D: Driver + 'static, -{ +impl<'a> DnsSocket<'a> { /// Create a new DNS socket using the provided stack. /// /// NOTE: If using DHCP, make sure it has reconfigured the stack to ensure the DNS servers are updated. - pub fn new(stack: &'a Stack) -> Self { + pub fn new(stack: Stack<'a>) -> Self { Self { stack } } @@ -72,10 +66,7 @@ where } } -impl<'a, D> embedded_nal_async::Dns for DnsSocket<'a, D> -where - D: Driver + 'static, -{ +impl<'a> embedded_nal_async::Dns for DnsSocket<'a> { type Error = Error; async fn get_host_by_name( @@ -124,3 +115,7 @@ where todo!() } } + +fn _assert_covariant<'a, 'b: 'a>(x: DnsSocket<'b>) -> DnsSocket<'a> { + x +} diff --git a/embassy-net/src/device.rs b/embassy-net/src/driver_util.rs similarity index 98% rename from embassy-net/src/device.rs rename to embassy-net/src/driver_util.rs index 3b1d3c47c..b2af1d499 100644 --- a/embassy-net/src/device.rs +++ b/embassy-net/src/driver_util.rs @@ -74,7 +74,7 @@ where { fn consume(self, f: F) -> R where - F: FnOnce(&mut [u8]) -> R, + F: FnOnce(&[u8]) -> R, { self.0.consume(|buf| { #[cfg(feature = "packet-trace")] diff --git a/embassy-net/src/lib.rs b/embassy-net/src/lib.rs index 56321cec9..ef53fb905 100644 --- a/embassy-net/src/lib.rs +++ b/embassy-net/src/lib.rs @@ -12,9 +12,9 @@ compile_error!("You must enable at least one of the following features: proto-ip // This mod MUST go first, so that the others see its macros. pub(crate) mod fmt; -mod device; #[cfg(feature = "dns")] pub mod dns; +mod driver_util; #[cfg(feature = "raw")] pub mod raw; #[cfg(feature = "tcp")] @@ -25,6 +25,7 @@ pub mod udp; use core::cell::RefCell; use core::future::{poll_fn, Future}; +use core::mem::MaybeUninit; use core::pin::pin; use core::task::{Context, Poll}; @@ -36,7 +37,7 @@ use embassy_time::{Instant, Timer}; use heapless::Vec; #[cfg(feature = "dns")] pub use smoltcp::config::DNS_MAX_SERVER_COUNT; -#[cfg(feature = "igmp")] +#[cfg(feature = "multicast")] pub use smoltcp::iface::MulticastError; #[allow(unused_imports)] use smoltcp::iface::{Interface, SocketHandle, SocketSet, SocketStorage}; @@ -57,7 +58,7 @@ pub use smoltcp::wire::{Ipv4Address, Ipv4Cidr}; #[cfg(feature = "proto-ipv6")] pub use smoltcp::wire::{Ipv6Address, Ipv6Cidr}; -use crate::device::DriverAdapter; +use crate::driver_util::DriverAdapter; use crate::time::{instant_from_smoltcp, instant_to_smoltcp}; const LOCAL_PORT_MIN: u16 = 1025; @@ -69,33 +70,33 @@ const MAX_HOSTNAME_LEN: usize = 32; /// Memory resources needed for a network stack. pub struct StackResources { - sockets: [SocketStorage<'static>; SOCK], + sockets: MaybeUninit<[SocketStorage<'static>; SOCK]>, + inner: MaybeUninit>, #[cfg(feature = "dns")] - queries: [Option; MAX_QUERIES], + queries: MaybeUninit<[Option; MAX_QUERIES]>, #[cfg(feature = "dhcpv4-hostname")] - hostname: core::cell::UnsafeCell, + hostname: HostnameResources, } #[cfg(feature = "dhcpv4-hostname")] struct HostnameResources { - option: smoltcp::wire::DhcpOption<'static>, - data: [u8; MAX_HOSTNAME_LEN], + option: MaybeUninit>, + data: MaybeUninit<[u8; MAX_HOSTNAME_LEN]>, } impl StackResources { /// Create a new set of stack resources. pub const fn new() -> Self { - #[cfg(feature = "dns")] - const INIT: Option = None; Self { - sockets: [SocketStorage::EMPTY; SOCK], + sockets: MaybeUninit::uninit(), + inner: MaybeUninit::uninit(), #[cfg(feature = "dns")] - queries: [INIT; MAX_QUERIES], + queries: MaybeUninit::uninit(), #[cfg(feature = "dhcpv4-hostname")] - hostname: core::cell::UnsafeCell::new(HostnameResources { - option: smoltcp::wire::DhcpOption { kind: 0, data: &[] }, - data: [0; MAX_HOSTNAME_LEN], - }), + hostname: HostnameResources { + option: MaybeUninit::uninit(), + data: MaybeUninit::uninit(), + }, } } } @@ -239,16 +240,29 @@ pub enum ConfigV6 { Static(StaticConfigV6), } -/// A network stack. +/// Network stack runner. /// -/// This is the main entry point for the network stack. -pub struct Stack { - pub(crate) socket: RefCell, - inner: RefCell>, +/// You must call [`Runner::run()`] in a background task for the network stack to work. +pub struct Runner<'d, D: Driver> { + driver: D, + stack: Stack<'d>, } -struct Inner { - device: D, +/// Network stack handle +/// +/// Use this to create sockets. It's `Copy`, so you can pass +/// it by value instead of by reference. +#[derive(Copy, Clone)] +pub struct Stack<'d> { + inner: &'d RefCell, +} + +pub(crate) struct Inner { + pub(crate) sockets: SocketSet<'static>, // Lifetime type-erased. + pub(crate) iface: Interface, + pub(crate) waker: WakerRegistration, + hardware_address: HardwareAddress, + next_local_port: u16, link_up: bool, #[cfg(feature = "proto-ipv4")] static_v4: Option, @@ -262,14 +276,83 @@ struct Inner { #[cfg(feature = "dns")] dns_waker: WakerRegistration, #[cfg(feature = "dhcpv4-hostname")] - hostname: &'static mut core::cell::UnsafeCell, + hostname: *mut HostnameResources, } -pub(crate) struct SocketStack { - pub(crate) sockets: SocketSet<'static>, - pub(crate) iface: Interface, - pub(crate) waker: WakerRegistration, - next_local_port: u16, +fn _assert_covariant<'a, 'b: 'a>(x: Stack<'b>) -> Stack<'a> { + x +} + +/// Create a new network stack. +pub fn new<'d, D: Driver, const SOCK: usize>( + mut driver: D, + config: Config, + resources: &'d mut StackResources, + random_seed: u64, +) -> (Stack<'d>, Runner<'d, D>) { + let (hardware_address, medium) = to_smoltcp_hardware_address(driver.hardware_address()); + let mut iface_cfg = smoltcp::iface::Config::new(hardware_address); + iface_cfg.random_seed = random_seed; + + let iface = Interface::new( + iface_cfg, + &mut DriverAdapter { + inner: &mut driver, + cx: None, + medium, + }, + instant_to_smoltcp(Instant::now()), + ); + + unsafe fn transmute_slice(x: &mut [T]) -> &'static mut [T] { + core::mem::transmute(x) + } + + let sockets = resources.sockets.write([SocketStorage::EMPTY; SOCK]); + #[allow(unused_mut)] + let mut sockets: SocketSet<'static> = SocketSet::new(unsafe { transmute_slice(sockets) }); + + let next_local_port = (random_seed % (LOCAL_PORT_MAX - LOCAL_PORT_MIN) as u64) as u16 + LOCAL_PORT_MIN; + + #[cfg(feature = "dns")] + let dns_socket = sockets.add(dns::Socket::new( + &[], + managed::ManagedSlice::Borrowed(unsafe { + transmute_slice(resources.queries.write([const { None }; MAX_QUERIES])) + }), + )); + + let mut inner = Inner { + sockets, + iface, + waker: WakerRegistration::new(), + next_local_port, + hardware_address, + link_up: false, + #[cfg(feature = "proto-ipv4")] + static_v4: None, + #[cfg(feature = "proto-ipv6")] + static_v6: None, + #[cfg(feature = "dhcpv4")] + dhcp_socket: None, + config_waker: WakerRegistration::new(), + #[cfg(feature = "dns")] + dns_socket, + #[cfg(feature = "dns")] + dns_waker: WakerRegistration::new(), + #[cfg(feature = "dhcpv4-hostname")] + hostname: &mut resources.hostname, + }; + + #[cfg(feature = "proto-ipv4")] + inner.set_config_v4(config.ipv4); + #[cfg(feature = "proto-ipv6")] + inner.set_config_v6(config.ipv6); + inner.apply_static_config(); + + let inner = &*resources.inner.write(RefCell::new(inner)); + let stack = Stack { inner }; + (stack, Runner { driver, stack }) } fn to_smoltcp_hardware_address(addr: driver::HardwareAddress) -> (HardwareAddress, Medium) { @@ -292,89 +375,23 @@ fn to_smoltcp_hardware_address(addr: driver::HardwareAddress) -> (HardwareAddres } } -impl Stack { - /// Create a new network stack. - pub fn new( - mut device: D, - config: Config, - resources: &'static mut StackResources, - random_seed: u64, - ) -> Self { - let (hardware_addr, medium) = to_smoltcp_hardware_address(device.hardware_address()); - let mut iface_cfg = smoltcp::iface::Config::new(hardware_addr); - iface_cfg.random_seed = random_seed; - - let iface = Interface::new( - iface_cfg, - &mut DriverAdapter { - inner: &mut device, - cx: None, - medium, - }, - instant_to_smoltcp(Instant::now()), - ); - - let sockets = SocketSet::new(&mut resources.sockets[..]); - - let next_local_port = (random_seed % (LOCAL_PORT_MAX - LOCAL_PORT_MIN) as u64) as u16 + LOCAL_PORT_MIN; - - #[cfg_attr(feature = "medium-ieee802154", allow(unused_mut))] - let mut socket = SocketStack { - sockets, - iface, - waker: WakerRegistration::new(), - next_local_port, - }; - - let mut inner = Inner { - device, - link_up: false, - #[cfg(feature = "proto-ipv4")] - static_v4: None, - #[cfg(feature = "proto-ipv6")] - static_v6: None, - #[cfg(feature = "dhcpv4")] - dhcp_socket: None, - config_waker: WakerRegistration::new(), - #[cfg(feature = "dns")] - dns_socket: socket.sockets.add(dns::Socket::new( - &[], - managed::ManagedSlice::Borrowed(&mut resources.queries), - )), - #[cfg(feature = "dns")] - dns_waker: WakerRegistration::new(), - #[cfg(feature = "dhcpv4-hostname")] - hostname: &mut resources.hostname, - }; - - #[cfg(feature = "proto-ipv4")] - inner.set_config_v4(&mut socket, config.ipv4); - #[cfg(feature = "proto-ipv6")] - inner.set_config_v6(&mut socket, config.ipv6); - inner.apply_static_config(&mut socket); - - Self { - socket: RefCell::new(socket), - inner: RefCell::new(inner), - } +impl<'d> Stack<'d> { + fn with(&self, f: impl FnOnce(&Inner) -> R) -> R { + f(&*self.inner.borrow()) } - fn with(&self, f: impl FnOnce(&SocketStack, &Inner) -> R) -> R { - f(&*self.socket.borrow(), &*self.inner.borrow()) - } - - fn with_mut(&self, f: impl FnOnce(&mut SocketStack, &mut Inner) -> R) -> R { - f(&mut *self.socket.borrow_mut(), &mut *self.inner.borrow_mut()) + fn with_mut(&self, f: impl FnOnce(&mut Inner) -> R) -> R { + f(&mut *self.inner.borrow_mut()) } /// Get the hardware address of the network interface. pub fn hardware_address(&self) -> HardwareAddress { - self.with(|_s, i| to_smoltcp_hardware_address(i.device.hardware_address()).0) + self.with(|i| i.hardware_address) } /// Get whether the link is up. pub fn is_link_up(&self) -> bool { - self.with(|_s, i| i.link_up) + self.with(|i| i.link_up) } /// Get whether the network stack has a valid IP configuration. @@ -420,15 +437,14 @@ impl Stack { /// // provisioning space for 3 sockets here: one for DHCP, one for DNS, and one for your code (e.g. TCP). /// // If you use more sockets you must increase this. If you don't enable DHCP or DNS you can decrease it. /// static RESOURCES: StaticCell> = StaticCell::new(); - /// static STACK: StaticCell = StaticCell::new(); - /// let stack = &*STACK.init(embassy_net::Stack::new( - /// device, + /// let (stack, runner) = embassy_net::new( + /// driver, /// config, /// RESOURCES.init(embassy_net::StackResources::new()), /// seed - /// )); - /// // Launch network task that runs `stack.run().await` - /// spawner.spawn(net_task(stack)).unwrap(); + /// ); + /// // Launch network task that runs `runner.run().await` + /// spawner.spawn(net_task(runner)).unwrap(); /// // Wait for DHCP config /// stack.wait_config_up().await; /// // use the network stack @@ -448,7 +464,7 @@ impl Stack { // when a config is applied (static or DHCP). trace!("Waiting for config up"); - self.with_mut(|_, i| { + self.with_mut(|i| { i.config_waker.register(cx.waker()); }); @@ -464,45 +480,33 @@ impl Stack { /// acquire an IP address, or Some if it has. #[cfg(feature = "proto-ipv4")] pub fn config_v4(&self) -> Option { - self.with(|_, i| i.static_v4.clone()) + self.with(|i| i.static_v4.clone()) } /// Get the current IPv6 configuration. #[cfg(feature = "proto-ipv6")] pub fn config_v6(&self) -> Option { - self.with(|_, i| i.static_v6.clone()) + self.with(|i| i.static_v6.clone()) } /// Set the IPv4 configuration. #[cfg(feature = "proto-ipv4")] pub fn set_config_v4(&self, config: ConfigV4) { - self.with_mut(|s, i| { - i.set_config_v4(s, config); - i.apply_static_config(s); + self.with_mut(|i| { + i.set_config_v4(config); + i.apply_static_config(); }) } /// Set the IPv6 configuration. #[cfg(feature = "proto-ipv6")] pub fn set_config_v6(&self, config: ConfigV6) { - self.with_mut(|s, i| { - i.set_config_v6(s, config); - i.apply_static_config(s); + self.with_mut(|i| { + i.set_config_v6(config); + i.apply_static_config(); }) } - /// Run the network stack. - /// - /// You must call this in a background task, to process network events. - pub async fn run(&self) -> ! { - poll_fn(|cx| { - self.with_mut(|s, i| i.poll(cx, s)); - Poll::<()>::Pending - }) - .await; - unreachable!() - } - /// Make a query for a given name and return the corresponding IP addresses. #[cfg(feature = "dns")] pub async fn dns_query( @@ -528,11 +532,11 @@ impl Stack { } let query = poll_fn(|cx| { - self.with_mut(|s, i| { - let socket = s.sockets.get_mut::(i.dns_socket); - match socket.start_query(s.iface.context(), name, qtype) { + self.with_mut(|i| { + let socket = i.sockets.get_mut::(i.dns_socket); + match socket.start_query(i.iface.context(), name, qtype) { Ok(handle) => { - s.waker.wake(); + i.waker.wake(); Poll::Ready(Ok(handle)) } Err(dns::StartQueryError::NoFreeSlot) => { @@ -569,17 +573,17 @@ impl Stack { } let drop = OnDrop::new(|| { - self.with_mut(|s, i| { - let socket = s.sockets.get_mut::(i.dns_socket); + self.with_mut(|i| { + let socket = i.sockets.get_mut::(i.dns_socket); socket.cancel_query(query); - s.waker.wake(); + i.waker.wake(); i.dns_waker.wake(); }) }); let res = poll_fn(|cx| { - self.with_mut(|s, i| { - let socket = s.sockets.get_mut::(i.dns_socket); + self.with_mut(|i| { + let socket = i.sockets.get_mut::(i.dns_socket); match socket.get_query_result(query) { Ok(addrs) => { i.dns_waker.wake(); @@ -604,104 +608,34 @@ impl Stack { } } -#[cfg(feature = "igmp")] -impl Stack { +#[cfg(feature = "multicast")] +impl<'d> Stack<'d> { /// Join a multicast group. - pub async fn join_multicast_group(&self, addr: T) -> Result - where - T: Into, - { - let addr = addr.into(); - - poll_fn(move |cx| self.poll_join_multicast_group(addr, cx)).await - } - - /// Join a multicast group. - /// - /// When the send queue is full, this method will return `Poll::Pending` - /// and register the current task to be notified when the queue has space available. - pub fn poll_join_multicast_group(&self, addr: T, cx: &mut Context<'_>) -> Poll> - where - T: Into, - { - let addr = addr.into(); - - self.with_mut(|s, i| { - let (_hardware_addr, medium) = to_smoltcp_hardware_address(i.device.hardware_address()); - let mut smoldev = DriverAdapter { - cx: Some(cx), - inner: &mut i.device, - medium, - }; - - match s - .iface - .join_multicast_group(&mut smoldev, addr, instant_to_smoltcp(Instant::now())) - { - Ok(announce_sent) => Poll::Ready(Ok(announce_sent)), - Err(MulticastError::Exhausted) => Poll::Pending, - Err(other) => Poll::Ready(Err(other)), - } - }) + pub fn join_multicast_group(&self, addr: impl Into) -> Result<(), MulticastError> { + self.with_mut(|i| i.iface.join_multicast_group(addr)) } /// Leave a multicast group. - pub async fn leave_multicast_group(&self, addr: T) -> Result - where - T: Into, - { - let addr = addr.into(); - - poll_fn(move |cx| self.poll_leave_multicast_group(addr, cx)).await - } - - /// Leave a multicast group. - /// - /// When the send queue is full, this method will return `Poll::Pending` - /// and register the current task to be notified when the queue has space available. - pub fn poll_leave_multicast_group(&self, addr: T, cx: &mut Context<'_>) -> Poll> - where - T: Into, - { - let addr = addr.into(); - - self.with_mut(|s, i| { - let (_hardware_addr, medium) = to_smoltcp_hardware_address(i.device.hardware_address()); - let mut smoldev = DriverAdapter { - cx: Some(cx), - inner: &mut i.device, - medium, - }; - - match s - .iface - .leave_multicast_group(&mut smoldev, addr, instant_to_smoltcp(Instant::now())) - { - Ok(leave_sent) => Poll::Ready(Ok(leave_sent)), - Err(MulticastError::Exhausted) => Poll::Pending, - Err(other) => Poll::Ready(Err(other)), - } - }) + pub fn leave_multicast_group(&self, addr: impl Into) -> Result<(), MulticastError> { + self.with_mut(|i| i.iface.leave_multicast_group(addr)) } /// Get whether the network stack has joined the given multicast group. - pub fn has_multicast_group>(&self, addr: T) -> bool { - self.socket.borrow().iface.has_multicast_group(addr) + pub fn has_multicast_group(&self, addr: impl Into) -> bool { + self.with(|i| i.iface.has_multicast_group(addr)) } } -impl SocketStack { +impl Inner { #[allow(clippy::absurd_extreme_comparisons, dead_code)] pub fn get_local_port(&mut self) -> u16 { let res = self.next_local_port; self.next_local_port = if res >= LOCAL_PORT_MAX { LOCAL_PORT_MIN } else { res + 1 }; res } -} -impl Inner { #[cfg(feature = "proto-ipv4")] - pub fn set_config_v4(&mut self, _s: &mut SocketStack, config: ConfigV4) { + pub fn set_config_v4(&mut self, config: ConfigV4) { // Handle static config. self.static_v4 = match config.clone() { ConfigV4::None => None, @@ -717,12 +651,12 @@ impl Inner { // Create the socket if it doesn't exist. if self.dhcp_socket.is_none() { let socket = smoltcp::socket::dhcpv4::Socket::new(); - let handle = _s.sockets.add(socket); + let handle = self.sockets.add(socket); self.dhcp_socket = Some(handle); } // Configure it - let socket = _s.sockets.get_mut::(unwrap!(self.dhcp_socket)); + let socket = self.sockets.get_mut::(unwrap!(self.dhcp_socket)); socket.set_ignore_naks(c.ignore_naks); socket.set_max_lease_duration(c.max_lease_duration.map(crate::time::duration_to_smoltcp)); socket.set_ports(c.server_port, c.client_port); @@ -731,19 +665,20 @@ impl Inner { socket.set_outgoing_options(&[]); #[cfg(feature = "dhcpv4-hostname")] if let Some(h) = c.hostname { - // safety: we just did set_outgoing_options([]) so we know the socket is no longer holding a reference. - let hostname = unsafe { &mut *self.hostname.get() }; + // safety: + // - we just did set_outgoing_options([]) so we know the socket is no longer holding a reference. + // - we know this pointer lives for as long as the stack exists, because `new()` borrows + // the resources for `'d`. Therefore it's OK to pass a reference to this to smoltcp. + let hostname = unsafe { &mut *self.hostname }; // create data - // safety: we know the buffer lives forever, new borrows the StackResources for 'static. - // also we won't modify it until next call to this function. - hostname.data[..h.len()].copy_from_slice(h.as_bytes()); - let data: &[u8] = &hostname.data[..h.len()]; - let data: &'static [u8] = unsafe { core::mem::transmute(data) }; + let data = hostname.data.write([0; MAX_HOSTNAME_LEN]); + data[..h.len()].copy_from_slice(h.as_bytes()); + let data: &[u8] = &data[..h.len()]; // set the option. - hostname.option = smoltcp::wire::DhcpOption { data, kind: 12 }; - socket.set_outgoing_options(core::slice::from_ref(&hostname.option)); + let option = hostname.option.write(smoltcp::wire::DhcpOption { data, kind: 12 }); + socket.set_outgoing_options(core::slice::from_ref(option)); } socket.reset(); @@ -751,7 +686,7 @@ impl Inner { _ => { // Remove DHCP socket if any. if let Some(socket) = self.dhcp_socket { - _s.sockets.remove(socket); + self.sockets.remove(socket); self.dhcp_socket = None; } } @@ -759,14 +694,14 @@ impl Inner { } #[cfg(feature = "proto-ipv6")] - pub fn set_config_v6(&mut self, _s: &mut SocketStack, config: ConfigV6) { + pub fn set_config_v6(&mut self, config: ConfigV6) { self.static_v6 = match config { ConfigV6::None => None, ConfigV6::Static(c) => Some(c), }; } - fn apply_static_config(&mut self, s: &mut SocketStack) { + fn apply_static_config(&mut self) { let mut addrs = Vec::new(); #[cfg(feature = "dns")] let mut dns_servers: Vec<_, 6> = Vec::new(); @@ -810,20 +745,20 @@ impl Inner { } // Apply addresses - s.iface.update_ip_addrs(|a| *a = addrs); + self.iface.update_ip_addrs(|a| *a = addrs); // Apply gateways #[cfg(feature = "proto-ipv4")] if let Some(gateway) = gateway_v4 { - unwrap!(s.iface.routes_mut().add_default_ipv4_route(gateway)); + unwrap!(self.iface.routes_mut().add_default_ipv4_route(gateway)); } else { - s.iface.routes_mut().remove_default_ipv4_route(); + self.iface.routes_mut().remove_default_ipv4_route(); } #[cfg(feature = "proto-ipv6")] if let Some(gateway) = gateway_v6 { - unwrap!(s.iface.routes_mut().add_default_ipv6_route(gateway)); + unwrap!(self.iface.routes_mut().add_default_ipv6_route(gateway)); } else { - s.iface.routes_mut().remove_default_ipv6_route(); + self.iface.routes_mut().remove_default_ipv6_route(); } // Apply DNS servers @@ -835,7 +770,7 @@ impl Inner { } else { dns_servers.len() }; - s.sockets + self.sockets .get_mut::(self.dns_socket) .update_servers(&dns_servers[..count]); } @@ -843,10 +778,10 @@ impl Inner { self.config_waker.wake(); } - fn poll(&mut self, cx: &mut Context<'_>, s: &mut SocketStack) { - s.waker.register(cx.waker()); + fn poll(&mut self, cx: &mut Context<'_>, driver: &mut D) { + self.waker.register(cx.waker()); - let (_hardware_addr, medium) = to_smoltcp_hardware_address(self.device.hardware_address()); + let (_hardware_addr, medium) = to_smoltcp_hardware_address(driver.hardware_address()); #[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))] { @@ -859,21 +794,21 @@ impl Inner { _ => false, }; if do_set { - s.iface.set_hardware_addr(_hardware_addr); + self.iface.set_hardware_addr(_hardware_addr); } } let timestamp = instant_to_smoltcp(Instant::now()); let mut smoldev = DriverAdapter { cx: Some(cx), - inner: &mut self.device, + inner: driver, medium, }; - s.iface.poll(timestamp, &mut smoldev, &mut s.sockets); + self.iface.poll(timestamp, &mut smoldev, &mut self.sockets); // Update link up let old_link_up = self.link_up; - self.link_up = self.device.link_state(cx) == LinkState::Up; + self.link_up = driver.link_state(cx) == LinkState::Up; // Print when changed if old_link_up != self.link_up { @@ -885,7 +820,7 @@ impl Inner { #[cfg(feature = "dhcpv4")] if let Some(dhcp_handle) = self.dhcp_socket { - let socket = s.sockets.get_mut::(dhcp_handle); + let socket = self.sockets.get_mut::(dhcp_handle); if self.link_up { if old_link_up != self.link_up { @@ -914,10 +849,10 @@ impl Inner { } if apply_config { - self.apply_static_config(s); + self.apply_static_config(); } - if let Some(poll_at) = s.iface.poll_at(timestamp, &mut s.sockets) { + if let Some(poll_at) = self.iface.poll_at(timestamp, &mut self.sockets) { let t = pin!(Timer::at(instant_from_smoltcp(poll_at))); if t.poll(cx).is_ready() { cx.waker().wake_by_ref(); @@ -925,3 +860,17 @@ impl Inner { } } } + +impl<'d, D: Driver> Runner<'d, D> { + /// Run the network stack. + /// + /// You must call this in a background task, to process network events. + pub async fn run(&mut self) -> ! { + poll_fn(|cx| { + self.stack.with_mut(|i| i.poll(cx, &mut self.driver)); + Poll::<()>::Pending + }) + .await; + unreachable!() + } +} diff --git a/embassy-net/src/raw.rs b/embassy-net/src/raw.rs index 7ecd913e7..1098dc208 100644 --- a/embassy-net/src/raw.rs +++ b/embassy-net/src/raw.rs @@ -1,6 +1,5 @@ //! Raw sockets. -use core::cell::RefCell; use core::future::poll_fn; use core::mem; use core::task::{Context, Poll}; @@ -11,7 +10,7 @@ use smoltcp::socket::raw; pub use smoltcp::socket::raw::PacketMetadata; use smoltcp::wire::{IpProtocol, IpVersion}; -use crate::{SocketStack, Stack}; +use crate::Stack; /// Error returned by [`RawSocket::recv`] and [`RawSocket::send`]. #[derive(PartialEq, Eq, Clone, Copy, Debug)] @@ -23,14 +22,14 @@ pub enum RecvError { /// An Raw socket. pub struct RawSocket<'a> { - stack: &'a RefCell, + stack: Stack<'a>, handle: SocketHandle, } impl<'a> RawSocket<'a> { /// Create a new Raw socket using the provided stack and buffers. pub fn new( - stack: &'a Stack, + stack: Stack<'a>, ip_version: IpVersion, ip_protocol: IpProtocol, rx_meta: &'a mut [PacketMetadata], @@ -38,31 +37,29 @@ impl<'a> RawSocket<'a> { tx_meta: &'a mut [PacketMetadata], tx_buffer: &'a mut [u8], ) -> Self { - let s = &mut *stack.socket.borrow_mut(); + let handle = stack.with_mut(|i| { + let rx_meta: &'static mut [PacketMetadata] = unsafe { mem::transmute(rx_meta) }; + let rx_buffer: &'static mut [u8] = unsafe { mem::transmute(rx_buffer) }; + let tx_meta: &'static mut [PacketMetadata] = unsafe { mem::transmute(tx_meta) }; + let tx_buffer: &'static mut [u8] = unsafe { mem::transmute(tx_buffer) }; + i.sockets.add(raw::Socket::new( + ip_version, + ip_protocol, + raw::PacketBuffer::new(rx_meta, rx_buffer), + raw::PacketBuffer::new(tx_meta, tx_buffer), + )) + }); - let rx_meta: &'static mut [PacketMetadata] = unsafe { mem::transmute(rx_meta) }; - let rx_buffer: &'static mut [u8] = unsafe { mem::transmute(rx_buffer) }; - let tx_meta: &'static mut [PacketMetadata] = unsafe { mem::transmute(tx_meta) }; - let tx_buffer: &'static mut [u8] = unsafe { mem::transmute(tx_buffer) }; - let handle = s.sockets.add(raw::Socket::new( - ip_version, - ip_protocol, - raw::PacketBuffer::new(rx_meta, rx_buffer), - raw::PacketBuffer::new(tx_meta, tx_buffer), - )); - - Self { - stack: &stack.socket, - handle, - } + Self { stack, handle } } fn with_mut(&self, f: impl FnOnce(&mut raw::Socket, &mut Interface) -> R) -> R { - let s = &mut *self.stack.borrow_mut(); - let socket = s.sockets.get_mut::(self.handle); - let res = f(socket, &mut s.iface); - s.waker.wake(); - res + self.stack.with_mut(|i| { + let socket = i.sockets.get_mut::(self.handle); + let res = f(socket, &mut i.iface); + i.waker.wake(); + res + }) } /// Receive a datagram. @@ -115,6 +112,10 @@ impl<'a> RawSocket<'a> { impl Drop for RawSocket<'_> { fn drop(&mut self) { - self.stack.borrow_mut().sockets.remove(self.handle); + self.stack.with_mut(|i| i.sockets.remove(self.handle)); } } + +fn _assert_covariant<'a, 'b: 'a>(x: RawSocket<'b>) -> RawSocket<'a> { + x +} diff --git a/embassy-net/src/tcp.rs b/embassy-net/src/tcp.rs index b2e3279cc..bcddbc95b 100644 --- a/embassy-net/src/tcp.rs +++ b/embassy-net/src/tcp.rs @@ -8,12 +8,10 @@ //! Incoming connections when no socket is listening are rejected. To accept many incoming //! connections, create many sockets and put them all into listening mode. -use core::cell::RefCell; use core::future::poll_fn; use core::mem; use core::task::Poll; -use embassy_net_driver::Driver; use embassy_time::Duration; use smoltcp::iface::{Interface, SocketHandle}; use smoltcp::socket::tcp; @@ -21,7 +19,7 @@ pub use smoltcp::socket::tcp::State; use smoltcp::wire::{IpEndpoint, IpListenEndpoint}; use crate::time::duration_to_smoltcp; -use crate::{SocketStack, Stack}; +use crate::Stack; /// Error returned by TcpSocket read/write functions. #[derive(PartialEq, Eq, Clone, Copy, Debug)] @@ -157,20 +155,18 @@ impl<'a> TcpWriter<'a> { impl<'a> TcpSocket<'a> { /// Create a new TCP socket on the given stack, with the given buffers. - pub fn new(stack: &'a Stack, rx_buffer: &'a mut [u8], tx_buffer: &'a mut [u8]) -> Self { - let s = &mut *stack.socket.borrow_mut(); - let rx_buffer: &'static mut [u8] = unsafe { mem::transmute(rx_buffer) }; - let tx_buffer: &'static mut [u8] = unsafe { mem::transmute(tx_buffer) }; - let handle = s.sockets.add(tcp::Socket::new( - tcp::SocketBuffer::new(rx_buffer), - tcp::SocketBuffer::new(tx_buffer), - )); + pub fn new(stack: Stack<'a>, rx_buffer: &'a mut [u8], tx_buffer: &'a mut [u8]) -> Self { + let handle = stack.with_mut(|i| { + let rx_buffer: &'static mut [u8] = unsafe { mem::transmute(rx_buffer) }; + let tx_buffer: &'static mut [u8] = unsafe { mem::transmute(tx_buffer) }; + i.sockets.add(tcp::Socket::new( + tcp::SocketBuffer::new(rx_buffer), + tcp::SocketBuffer::new(tx_buffer), + )) + }); Self { - io: TcpIo { - stack: &stack.socket, - handle, - }, + io: TcpIo { stack: stack, handle }, } } @@ -228,7 +224,7 @@ impl<'a> TcpSocket<'a> { where T: Into, { - let local_port = self.io.stack.borrow_mut().get_local_port(); + let local_port = self.io.stack.with_mut(|i| i.get_local_port()); match { self.io @@ -401,31 +397,43 @@ impl<'a> TcpSocket<'a> { impl<'a> Drop for TcpSocket<'a> { fn drop(&mut self) { - self.io.stack.borrow_mut().sockets.remove(self.io.handle); + self.io.stack.with_mut(|i| i.sockets.remove(self.io.handle)); } } +fn _assert_covariant<'a, 'b: 'a>(x: TcpSocket<'b>) -> TcpSocket<'a> { + x +} +fn _assert_covariant_reader<'a, 'b: 'a>(x: TcpReader<'b>) -> TcpReader<'a> { + x +} +fn _assert_covariant_writer<'a, 'b: 'a>(x: TcpWriter<'b>) -> TcpWriter<'a> { + x +} + // ======================= #[derive(Copy, Clone)] struct TcpIo<'a> { - stack: &'a RefCell, + stack: Stack<'a>, handle: SocketHandle, } impl<'d> TcpIo<'d> { fn with(&self, f: impl FnOnce(&tcp::Socket, &Interface) -> R) -> R { - let s = &*self.stack.borrow(); - let socket = s.sockets.get::(self.handle); - f(socket, &s.iface) + self.stack.with(|i| { + let socket = i.sockets.get::(self.handle); + f(socket, &i.iface) + }) } fn with_mut(&mut self, f: impl FnOnce(&mut tcp::Socket, &mut Interface) -> R) -> R { - let s = &mut *self.stack.borrow_mut(); - let socket = s.sockets.get_mut::(self.handle); - let res = f(socket, &mut s.iface); - s.waker.wake(); - res + self.stack.with_mut(|i| { + let socket = i.sockets.get_mut::(self.handle); + let res = f(socket, &mut i.iface); + i.waker.wake(); + res + }) } async fn read(&mut self, buf: &mut [u8]) -> Result { @@ -676,15 +684,15 @@ pub mod client { /// TCP client connection pool compatible with `embedded-nal-async` traits. /// /// The pool is capable of managing up to N concurrent connections with tx and rx buffers according to TX_SZ and RX_SZ. - pub struct TcpClient<'d, D: Driver, const N: usize, const TX_SZ: usize = 1024, const RX_SZ: usize = 1024> { - stack: &'d Stack, + pub struct TcpClient<'d, const N: usize, const TX_SZ: usize = 1024, const RX_SZ: usize = 1024> { + stack: Stack<'d>, state: &'d TcpClientState, socket_timeout: Option, } - impl<'d, D: Driver, const N: usize, const TX_SZ: usize, const RX_SZ: usize> TcpClient<'d, D, N, TX_SZ, RX_SZ> { + impl<'d, const N: usize, const TX_SZ: usize, const RX_SZ: usize> TcpClient<'d, N, TX_SZ, RX_SZ> { /// Create a new `TcpClient`. - pub fn new(stack: &'d Stack, state: &'d TcpClientState) -> Self { + pub fn new(stack: Stack<'d>, state: &'d TcpClientState) -> Self { Self { stack, state, @@ -701,8 +709,8 @@ pub mod client { } } - impl<'d, D: Driver, const N: usize, const TX_SZ: usize, const RX_SZ: usize> embedded_nal_async::TcpConnect - for TcpClient<'d, D, N, TX_SZ, RX_SZ> + impl<'d, const N: usize, const TX_SZ: usize, const RX_SZ: usize> embedded_nal_async::TcpConnect + for TcpClient<'d, N, TX_SZ, RX_SZ> { type Error = Error; type Connection<'m> = TcpConnection<'m, N, TX_SZ, RX_SZ> where Self: 'm; @@ -722,7 +730,7 @@ pub mod client { IpAddr::V6(_) => panic!("ipv6 support not enabled"), }; let remote_endpoint = (addr, remote.port()); - let mut socket = TcpConnection::new(&self.stack, self.state)?; + let mut socket = TcpConnection::new(self.stack, self.state)?; socket.socket.set_timeout(self.socket_timeout.clone()); socket .socket @@ -741,7 +749,7 @@ pub mod client { } impl<'d, const N: usize, const TX_SZ: usize, const RX_SZ: usize> TcpConnection<'d, N, TX_SZ, RX_SZ> { - fn new(stack: &'d Stack, state: &'d TcpClientState) -> Result { + fn new(stack: Stack<'d>, state: &'d TcpClientState) -> Result { let mut bufs = state.pool.alloc().ok_or(Error::ConnectionReset)?; Ok(Self { socket: unsafe { TcpSocket::new(stack, &mut bufs.as_mut().1, &mut bufs.as_mut().0) }, diff --git a/embassy-net/src/udp.rs b/embassy-net/src/udp.rs index 1d5360187..3eb6e2f83 100644 --- a/embassy-net/src/udp.rs +++ b/embassy-net/src/udp.rs @@ -1,17 +1,15 @@ //! UDP sockets. -use core::cell::RefCell; use core::future::poll_fn; use core::mem; use core::task::{Context, Poll}; -use embassy_net_driver::Driver; use smoltcp::iface::{Interface, SocketHandle}; use smoltcp::socket::udp; pub use smoltcp::socket::udp::{PacketMetadata, UdpMetadata}; use smoltcp::wire::IpListenEndpoint; -use crate::{SocketStack, Stack}; +use crate::Stack; /// Error returned by [`UdpSocket::bind`]. #[derive(PartialEq, Eq, Clone, Copy, Debug)] @@ -43,34 +41,31 @@ pub enum RecvError { /// An UDP socket. pub struct UdpSocket<'a> { - stack: &'a RefCell, + stack: Stack<'a>, handle: SocketHandle, } impl<'a> UdpSocket<'a> { /// Create a new UDP socket using the provided stack and buffers. - pub fn new( - stack: &'a Stack, + pub fn new( + stack: Stack<'a>, rx_meta: &'a mut [PacketMetadata], rx_buffer: &'a mut [u8], tx_meta: &'a mut [PacketMetadata], tx_buffer: &'a mut [u8], ) -> Self { - let s = &mut *stack.socket.borrow_mut(); + let handle = stack.with_mut(|i| { + let rx_meta: &'static mut [PacketMetadata] = unsafe { mem::transmute(rx_meta) }; + let rx_buffer: &'static mut [u8] = unsafe { mem::transmute(rx_buffer) }; + let tx_meta: &'static mut [PacketMetadata] = unsafe { mem::transmute(tx_meta) }; + let tx_buffer: &'static mut [u8] = unsafe { mem::transmute(tx_buffer) }; + i.sockets.add(udp::Socket::new( + udp::PacketBuffer::new(rx_meta, rx_buffer), + udp::PacketBuffer::new(tx_meta, tx_buffer), + )) + }); - let rx_meta: &'static mut [PacketMetadata] = unsafe { mem::transmute(rx_meta) }; - let rx_buffer: &'static mut [u8] = unsafe { mem::transmute(rx_buffer) }; - let tx_meta: &'static mut [PacketMetadata] = unsafe { mem::transmute(tx_meta) }; - let tx_buffer: &'static mut [u8] = unsafe { mem::transmute(tx_buffer) }; - let handle = s.sockets.add(udp::Socket::new( - udp::PacketBuffer::new(rx_meta, rx_buffer), - udp::PacketBuffer::new(tx_meta, tx_buffer), - )); - - Self { - stack: &stack.socket, - handle, - } + Self { stack, handle } } /// Bind the socket to a local endpoint. @@ -82,7 +77,7 @@ impl<'a> UdpSocket<'a> { if endpoint.port == 0 { // If user didn't specify port allocate a dynamic port. - endpoint.port = self.stack.borrow_mut().get_local_port(); + endpoint.port = self.stack.with_mut(|i| i.get_local_port()); } match self.with_mut(|s, _| s.bind(endpoint)) { @@ -93,17 +88,19 @@ impl<'a> UdpSocket<'a> { } fn with(&self, f: impl FnOnce(&udp::Socket, &Interface) -> R) -> R { - let s = &*self.stack.borrow(); - let socket = s.sockets.get::(self.handle); - f(socket, &s.iface) + self.stack.with(|i| { + let socket = i.sockets.get::(self.handle); + f(socket, &i.iface) + }) } fn with_mut(&self, f: impl FnOnce(&mut udp::Socket, &mut Interface) -> R) -> R { - let s = &mut *self.stack.borrow_mut(); - let socket = s.sockets.get_mut::(self.handle); - let res = f(socket, &mut s.iface); - s.waker.wake(); - res + self.stack.with_mut(|i| { + let socket = i.sockets.get_mut::(self.handle); + let res = f(socket, &mut i.iface); + i.waker.wake(); + res + }) } /// Receive a datagram. @@ -298,6 +295,10 @@ impl<'a> UdpSocket<'a> { impl Drop for UdpSocket<'_> { fn drop(&mut self) { - self.stack.borrow_mut().sockets.remove(self.handle); + self.stack.with_mut(|i| i.sockets.remove(self.handle)); } } + +fn _assert_covariant<'a, 'b: 'a>(x: UdpSocket<'b>) -> UdpSocket<'a> { + x +} diff --git a/examples/nrf52840/src/bin/ethernet_enc28j60.rs b/examples/nrf52840/src/bin/ethernet_enc28j60.rs index 94cf09c88..0946492fe 100644 --- a/examples/nrf52840/src/bin/ethernet_enc28j60.rs +++ b/examples/nrf52840/src/bin/ethernet_enc28j60.rs @@ -4,7 +4,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_net::tcp::TcpSocket; -use embassy_net::{Stack, StackResources}; +use embassy_net::StackResources; use embassy_net_enc28j60::Enc28j60; use embassy_nrf::gpio::{Level, Output, OutputDrive}; use embassy_nrf::rng::Rng; @@ -23,11 +23,12 @@ bind_interrupts!(struct Irqs { #[embassy_executor::task] async fn net_task( - stack: &'static Stack< + mut runner: embassy_net::Runner< + 'static, Enc28j60, Output<'static>, Delay>, Output<'static>>, >, ) -> ! { - stack.run().await + runner.run().await } #[embassy_executor::main] @@ -67,12 +68,9 @@ async fn main(spawner: Spawner) { // Init network stack static RESOURCES: StaticCell> = StaticCell::new(); - static STACK: StaticCell< - Stack, Output<'static>, Delay>, Output<'static>>>, - > = StaticCell::new(); - let stack = STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed)); + let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed); - unwrap!(spawner.spawn(net_task(stack))); + unwrap!(spawner.spawn(net_task(runner))); // And now we can use it! diff --git a/examples/nrf52840/src/bin/usb_ethernet.rs b/examples/nrf52840/src/bin/usb_ethernet.rs index e56b215e3..b07adac1f 100644 --- a/examples/nrf52840/src/bin/usb_ethernet.rs +++ b/examples/nrf52840/src/bin/usb_ethernet.rs @@ -6,7 +6,7 @@ use core::mem; use defmt::*; use embassy_executor::Spawner; use embassy_net::tcp::TcpSocket; -use embassy_net::{Stack, StackResources}; +use embassy_net::StackResources; use embassy_nrf::rng::Rng; use embassy_nrf::usb::vbus_detect::HardwareVbusDetect; use embassy_nrf::usb::Driver; @@ -39,8 +39,8 @@ async fn usb_ncm_task(class: Runner<'static, MyDriver, MTU>) -> ! { } #[embassy_executor::task] -async fn net_task(stack: &'static Stack>) -> ! { - stack.run().await +async fn net_task(mut runner: embassy_net::Runner<'static, Device<'static, MTU>>) -> ! { + runner.run().await } #[embassy_executor::main] @@ -116,10 +116,9 @@ async fn main(spawner: Spawner) { // Init network stack static RESOURCES: StaticCell> = StaticCell::new(); - static STACK: StaticCell>> = StaticCell::new(); - let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed)); + let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed); - unwrap!(spawner.spawn(net_task(stack))); + unwrap!(spawner.spawn(net_task(runner))); // And now we can use it! diff --git a/examples/nrf52840/src/bin/wifi_esp_hosted.rs b/examples/nrf52840/src/bin/wifi_esp_hosted.rs index a3b69a99b..26eaf485e 100644 --- a/examples/nrf52840/src/bin/wifi_esp_hosted.rs +++ b/examples/nrf52840/src/bin/wifi_esp_hosted.rs @@ -4,7 +4,7 @@ use defmt::{info, unwrap, warn}; use embassy_executor::Spawner; use embassy_net::tcp::TcpSocket; -use embassy_net::{Stack, StackResources}; +use embassy_net::StackResources; use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pull}; use embassy_nrf::rng::Rng; use embassy_nrf::spim::{self, Spim}; @@ -36,8 +36,8 @@ async fn wifi_task( } #[embassy_executor::task] -async fn net_task(stack: &'static Stack>) -> ! { - stack.run().await +async fn net_task(mut runner: embassy_net::Runner<'static, hosted::NetDriver<'static>>) -> ! { + runner.run().await } #[embassy_executor::main] @@ -90,10 +90,9 @@ async fn main(spawner: Spawner) { // Init network stack static RESOURCES: StaticCell> = StaticCell::new(); - static STACK: StaticCell>> = StaticCell::new(); - let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed)); + let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed); - unwrap!(spawner.spawn(net_task(stack))); + unwrap!(spawner.spawn(net_task(runner))); // And now we can use it! diff --git a/examples/nrf9160/src/bin/modem_tcp_client.rs b/examples/nrf9160/src/bin/modem_tcp_client.rs index 5335b6b51..929883884 100644 --- a/examples/nrf9160/src/bin/modem_tcp_client.rs +++ b/examples/nrf9160/src/bin/modem_tcp_client.rs @@ -46,15 +46,15 @@ async fn modem_task(runner: Runner<'static>) -> ! { } #[embassy_executor::task] -async fn net_task(stack: &'static Stack>) -> ! { - stack.run().await +async fn net_task(mut runner: embassy_net::Runner<'static, embassy_net_nrf91::NetDriver<'static>>) -> ! { + runner.run().await } #[embassy_executor::task] async fn control_task( control: &'static context::Control<'static>, config: context::Config<'static>, - stack: &'static Stack>, + stack: Stack<'static>, ) { unwrap!(control.configure(&config).await); unwrap!( @@ -150,15 +150,9 @@ async fn main(spawner: Spawner) { // Init network stack static RESOURCES: StaticCell> = StaticCell::new(); - static STACK: StaticCell>> = StaticCell::new(); - let stack = &*STACK.init(Stack::new( - device, - config, - RESOURCES.init(StackResources::<2>::new()), - seed, - )); + let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::<2>::new()), seed); - unwrap!(spawner.spawn(net_task(stack))); + unwrap!(spawner.spawn(net_task(runner))); static CONTROL: StaticCell> = StaticCell::new(); let control = CONTROL.init(context::Control::new(control, 0).await); diff --git a/examples/rp/src/bin/ethernet_w5500_multisocket.rs b/examples/rp/src/bin/ethernet_w5500_multisocket.rs index aaa035a72..12003adbe 100644 --- a/examples/rp/src/bin/ethernet_w5500_multisocket.rs +++ b/examples/rp/src/bin/ethernet_w5500_multisocket.rs @@ -36,8 +36,8 @@ async fn ethernet_task( } #[embassy_executor::task] -async fn net_task(stack: &'static Stack>) -> ! { - stack.run().await +async fn net_task(mut runner: embassy_net::Runner<'static, Device<'static>>) -> ! { + runner.run().await } #[embassy_executor::main] @@ -71,17 +71,16 @@ async fn main(spawner: Spawner) { let seed = rng.next_u64(); // Init network stack - static STACK: StaticCell>> = StaticCell::new(); static RESOURCES: StaticCell> = StaticCell::new(); - let stack = &*STACK.init(Stack::new( + let (stack, runner) = embassy_net::new( device, embassy_net::Config::dhcpv4(Default::default()), RESOURCES.init(StackResources::new()), seed, - )); + ); // Launch network task - unwrap!(spawner.spawn(net_task(&stack))); + unwrap!(spawner.spawn(net_task(runner))); info!("Waiting for DHCP..."); let cfg = wait_for_config(stack).await; @@ -89,12 +88,12 @@ async fn main(spawner: Spawner) { info!("IP address: {:?}", local_addr); // Create two sockets listening to the same port, to handle simultaneous connections - unwrap!(spawner.spawn(listen_task(&stack, 0, 1234))); - unwrap!(spawner.spawn(listen_task(&stack, 1, 1234))); + unwrap!(spawner.spawn(listen_task(stack, 0, 1234))); + unwrap!(spawner.spawn(listen_task(stack, 1, 1234))); } #[embassy_executor::task(pool_size = 2)] -async fn listen_task(stack: &'static Stack>, id: u8, port: u16) { +async fn listen_task(stack: Stack<'static>, id: u8, port: u16) { let mut rx_buffer = [0; 4096]; let mut tx_buffer = [0; 4096]; let mut buf = [0; 4096]; @@ -131,7 +130,7 @@ async fn listen_task(stack: &'static Stack>, id: u8, port: u16) } } -async fn wait_for_config(stack: &'static Stack>) -> embassy_net::StaticConfigV4 { +async fn wait_for_config(stack: Stack<'static>) -> embassy_net::StaticConfigV4 { loop { if let Some(config) = stack.config_v4() { return config.clone(); diff --git a/examples/rp/src/bin/ethernet_w5500_tcp_client.rs b/examples/rp/src/bin/ethernet_w5500_tcp_client.rs index 8e96a114c..d66a43a88 100644 --- a/examples/rp/src/bin/ethernet_w5500_tcp_client.rs +++ b/examples/rp/src/bin/ethernet_w5500_tcp_client.rs @@ -38,8 +38,8 @@ async fn ethernet_task( } #[embassy_executor::task] -async fn net_task(stack: &'static Stack>) -> ! { - stack.run().await +async fn net_task(mut runner: embassy_net::Runner<'static, Device<'static>>) -> ! { + runner.run().await } #[embassy_executor::main] @@ -74,17 +74,16 @@ async fn main(spawner: Spawner) { let seed = rng.next_u64(); // Init network stack - static STACK: StaticCell>> = StaticCell::new(); static RESOURCES: StaticCell> = StaticCell::new(); - let stack = &*STACK.init(Stack::new( + let (stack, runner) = embassy_net::new( device, embassy_net::Config::dhcpv4(Default::default()), RESOURCES.init(StackResources::new()), seed, - )); + ); // Launch network task - unwrap!(spawner.spawn(net_task(&stack))); + unwrap!(spawner.spawn(net_task(runner))); info!("Waiting for DHCP..."); let cfg = wait_for_config(stack).await; @@ -119,7 +118,7 @@ async fn main(spawner: Spawner) { } } -async fn wait_for_config(stack: &'static Stack>) -> embassy_net::StaticConfigV4 { +async fn wait_for_config(stack: Stack<'static>) -> embassy_net::StaticConfigV4 { loop { if let Some(config) = stack.config_v4() { return config.clone(); diff --git a/examples/rp/src/bin/ethernet_w5500_tcp_server.rs b/examples/rp/src/bin/ethernet_w5500_tcp_server.rs index 40736bf3c..97d9bd4c9 100644 --- a/examples/rp/src/bin/ethernet_w5500_tcp_server.rs +++ b/examples/rp/src/bin/ethernet_w5500_tcp_server.rs @@ -37,8 +37,8 @@ async fn ethernet_task( } #[embassy_executor::task] -async fn net_task(stack: &'static Stack>) -> ! { - stack.run().await +async fn net_task(mut runner: embassy_net::Runner<'static, Device<'static>>) -> ! { + runner.run().await } #[embassy_executor::main] @@ -73,17 +73,16 @@ async fn main(spawner: Spawner) { let seed = rng.next_u64(); // Init network stack - static STACK: StaticCell>> = StaticCell::new(); static RESOURCES: StaticCell> = StaticCell::new(); - let stack = &*STACK.init(Stack::new( + let (stack, runner) = embassy_net::new( device, embassy_net::Config::dhcpv4(Default::default()), RESOURCES.init(StackResources::new()), seed, - )); + ); // Launch network task - unwrap!(spawner.spawn(net_task(&stack))); + unwrap!(spawner.spawn(net_task(runner))); info!("Waiting for DHCP..."); let cfg = wait_for_config(stack).await; @@ -128,7 +127,7 @@ async fn main(spawner: Spawner) { } } -async fn wait_for_config(stack: &'static Stack>) -> embassy_net::StaticConfigV4 { +async fn wait_for_config(stack: Stack<'static>) -> embassy_net::StaticConfigV4 { loop { if let Some(config) = stack.config_v4() { return config.clone(); diff --git a/examples/rp/src/bin/ethernet_w5500_udp.rs b/examples/rp/src/bin/ethernet_w5500_udp.rs index c79f01538..b1b5f9758 100644 --- a/examples/rp/src/bin/ethernet_w5500_udp.rs +++ b/examples/rp/src/bin/ethernet_w5500_udp.rs @@ -36,8 +36,8 @@ async fn ethernet_task( } #[embassy_executor::task] -async fn net_task(stack: &'static Stack>) -> ! { - stack.run().await +async fn net_task(mut runner: embassy_net::Runner<'static, Device<'static>>) -> ! { + runner.run().await } #[embassy_executor::main] @@ -71,17 +71,16 @@ async fn main(spawner: Spawner) { let seed = rng.next_u64(); // Init network stack - static STACK: StaticCell>> = StaticCell::new(); static RESOURCES: StaticCell> = StaticCell::new(); - let stack = &*STACK.init(Stack::new( + let (stack, runner) = embassy_net::new( device, embassy_net::Config::dhcpv4(Default::default()), RESOURCES.init(StackResources::new()), seed, - )); + ); // Launch network task - unwrap!(spawner.spawn(net_task(&stack))); + unwrap!(spawner.spawn(net_task(runner))); info!("Waiting for DHCP..."); let cfg = wait_for_config(stack).await; @@ -108,7 +107,7 @@ async fn main(spawner: Spawner) { } } -async fn wait_for_config(stack: &'static Stack>) -> embassy_net::StaticConfigV4 { +async fn wait_for_config(stack: Stack<'static>) -> embassy_net::StaticConfigV4 { loop { if let Some(config) = stack.config_v4() { return config.clone(); diff --git a/examples/rp/src/bin/usb_ethernet.rs b/examples/rp/src/bin/usb_ethernet.rs index 03c510f37..9a15125d4 100644 --- a/examples/rp/src/bin/usb_ethernet.rs +++ b/examples/rp/src/bin/usb_ethernet.rs @@ -8,7 +8,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_net::tcp::TcpSocket; -use embassy_net::{Stack, StackResources}; +use embassy_net::StackResources; use embassy_rp::clocks::RoscRng; use embassy_rp::peripherals::USB; use embassy_rp::usb::{Driver, InterruptHandler}; @@ -40,8 +40,8 @@ async fn usb_ncm_task(class: Runner<'static, MyDriver, MTU>) -> ! { } #[embassy_executor::task] -async fn net_task(stack: &'static Stack>) -> ! { - stack.run().await +async fn net_task(mut runner: embassy_net::Runner<'static, Device<'static, MTU>>) -> ! { + runner.run().await } #[embassy_executor::main] @@ -108,11 +108,10 @@ async fn main(spawner: Spawner) { let seed = rng.next_u64(); // Init network stack - static STACK: StaticCell>> = StaticCell::new(); static RESOURCES: StaticCell> = StaticCell::new(); - let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed)); + let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed); - unwrap!(spawner.spawn(net_task(stack))); + unwrap!(spawner.spawn(net_task(runner))); // And now we can use it! diff --git a/examples/rp/src/bin/wifi_ap_tcp_server.rs b/examples/rp/src/bin/wifi_ap_tcp_server.rs index 00f404a9b..4c9651433 100644 --- a/examples/rp/src/bin/wifi_ap_tcp_server.rs +++ b/examples/rp/src/bin/wifi_ap_tcp_server.rs @@ -11,7 +11,7 @@ use cyw43_pio::PioSpi; use defmt::*; use embassy_executor::Spawner; use embassy_net::tcp::TcpSocket; -use embassy_net::{Config, Stack, StackResources}; +use embassy_net::{Config, StackResources}; use embassy_rp::bind_interrupts; use embassy_rp::clocks::RoscRng; use embassy_rp::gpio::{Level, Output}; @@ -33,8 +33,8 @@ async fn cyw43_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'stat } #[embassy_executor::task] -async fn net_task(stack: &'static Stack>) -> ! { - stack.run().await +async fn net_task(mut runner: embassy_net::Runner<'static, cyw43::NetDriver<'static>>) -> ! { + runner.run().await } #[embassy_executor::main] @@ -80,16 +80,10 @@ async fn main(spawner: Spawner) { let seed = rng.next_u64(); // Init network stack - static STACK: StaticCell>> = StaticCell::new(); static RESOURCES: StaticCell> = StaticCell::new(); - let stack = &*STACK.init(Stack::new( - net_device, - config, - RESOURCES.init(StackResources::new()), - seed, - )); + let (stack, runner) = embassy_net::new(net_device, config, RESOURCES.init(StackResources::new()), seed); - unwrap!(spawner.spawn(net_task(stack))); + unwrap!(spawner.spawn(net_task(runner))); //control.start_ap_open("cyw43", 5).await; control.start_ap_wpa2("cyw43", "password", 5).await; diff --git a/examples/rp/src/bin/wifi_scan.rs b/examples/rp/src/bin/wifi_scan.rs index ab3529112..434f0074c 100644 --- a/examples/rp/src/bin/wifi_scan.rs +++ b/examples/rp/src/bin/wifi_scan.rs @@ -10,7 +10,6 @@ use core::str; use cyw43_pio::PioSpi; use defmt::*; use embassy_executor::Spawner; -use embassy_net::Stack; use embassy_rp::bind_interrupts; use embassy_rp::gpio::{Level, Output}; use embassy_rp::peripherals::{DMA_CH0, PIO0}; @@ -28,8 +27,8 @@ async fn cyw43_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'stat } #[embassy_executor::task] -async fn net_task(stack: &'static Stack>) -> ! { - stack.run().await +async fn net_task(mut runner: embassy_net::Runner<'static, cyw43::NetDriver<'static>>) -> ! { + runner.run().await } #[embassy_executor::main] diff --git a/examples/rp/src/bin/wifi_tcp_server.rs b/examples/rp/src/bin/wifi_tcp_server.rs index b2950d98a..7bf546e01 100644 --- a/examples/rp/src/bin/wifi_tcp_server.rs +++ b/examples/rp/src/bin/wifi_tcp_server.rs @@ -12,7 +12,7 @@ use cyw43_pio::PioSpi; use defmt::*; use embassy_executor::Spawner; use embassy_net::tcp::TcpSocket; -use embassy_net::{Config, Stack, StackResources}; +use embassy_net::{Config, StackResources}; use embassy_rp::bind_interrupts; use embassy_rp::clocks::RoscRng; use embassy_rp::gpio::{Level, Output}; @@ -37,8 +37,8 @@ async fn cyw43_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'stat } #[embassy_executor::task] -async fn net_task(stack: &'static Stack>) -> ! { - stack.run().await +async fn net_task(mut runner: embassy_net::Runner<'static, cyw43::NetDriver<'static>>) -> ! { + runner.run().await } #[embassy_executor::main] @@ -84,16 +84,10 @@ async fn main(spawner: Spawner) { let seed = rng.next_u64(); // Init network stack - static STACK: StaticCell>> = StaticCell::new(); static RESOURCES: StaticCell> = StaticCell::new(); - let stack = &*STACK.init(Stack::new( - net_device, - config, - RESOURCES.init(StackResources::new()), - seed, - )); + let (stack, runner) = embassy_net::new(net_device, config, RESOURCES.init(StackResources::new()), seed); - unwrap!(spawner.spawn(net_task(stack))); + unwrap!(spawner.spawn(net_task(runner))); loop { match control diff --git a/examples/rp/src/bin/wifi_webrequest.rs b/examples/rp/src/bin/wifi_webrequest.rs index b43be8905..1ae909917 100644 --- a/examples/rp/src/bin/wifi_webrequest.rs +++ b/examples/rp/src/bin/wifi_webrequest.rs @@ -13,7 +13,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_net::dns::DnsSocket; use embassy_net::tcp::client::{TcpClient, TcpClientState}; -use embassy_net::{Config, Stack, StackResources}; +use embassy_net::{Config, StackResources}; use embassy_rp::bind_interrupts; use embassy_rp::clocks::RoscRng; use embassy_rp::gpio::{Level, Output}; @@ -40,8 +40,8 @@ async fn cyw43_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'stat } #[embassy_executor::task] -async fn net_task(stack: &'static Stack>) -> ! { - stack.run().await +async fn net_task(mut runner: embassy_net::Runner<'static, cyw43::NetDriver<'static>>) -> ! { + runner.run().await } #[embassy_executor::main] @@ -87,16 +87,10 @@ async fn main(spawner: Spawner) { let seed = rng.next_u64(); // Init network stack - static STACK: StaticCell>> = StaticCell::new(); static RESOURCES: StaticCell> = StaticCell::new(); - let stack = &*STACK.init(Stack::new( - net_device, - config, - RESOURCES.init(StackResources::new()), - seed, - )); + let (stack, runner) = embassy_net::new(net_device, config, RESOURCES.init(StackResources::new()), seed); - unwrap!(spawner.spawn(net_task(stack))); + unwrap!(spawner.spawn(net_task(runner))); loop { match control diff --git a/examples/std/src/bin/net.rs b/examples/std/src/bin/net.rs index 310e7264d..cefa5448c 100644 --- a/examples/std/src/bin/net.rs +++ b/examples/std/src/bin/net.rs @@ -1,7 +1,7 @@ use clap::Parser; use embassy_executor::{Executor, Spawner}; use embassy_net::tcp::TcpSocket; -use embassy_net::{Config, Ipv4Address, Ipv4Cidr, Stack, StackResources}; +use embassy_net::{Config, Ipv4Address, Ipv4Cidr, StackResources}; use embassy_net_tuntap::TunTapDevice; use embassy_time::Duration; use embedded_io_async::Write; @@ -22,8 +22,8 @@ struct Opts { } #[embassy_executor::task] -async fn net_task(stack: &'static Stack) -> ! { - stack.run().await +async fn net_task(mut runner: embassy_net::Runner<'static, TunTapDevice>) -> ! { + runner.run().await } #[embassy_executor::task] @@ -50,12 +50,11 @@ async fn main_task(spawner: Spawner) { let seed = u64::from_le_bytes(seed); // Init network stack - static STACK: StaticCell> = StaticCell::new(); static RESOURCES: StaticCell> = StaticCell::new(); - let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed)); + let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed); // Launch network task - spawner.spawn(net_task(stack)).unwrap(); + spawner.spawn(net_task(runner)).unwrap(); // Then we can use it! let mut rx_buffer = [0; 4096]; diff --git a/examples/std/src/bin/net_dns.rs b/examples/std/src/bin/net_dns.rs index c9615ef35..a42c5dbb7 100644 --- a/examples/std/src/bin/net_dns.rs +++ b/examples/std/src/bin/net_dns.rs @@ -1,7 +1,7 @@ use clap::Parser; use embassy_executor::{Executor, Spawner}; use embassy_net::dns::DnsQueryType; -use embassy_net::{Config, Ipv4Address, Ipv4Cidr, Stack, StackResources}; +use embassy_net::{Config, Ipv4Address, Ipv4Cidr, StackResources}; use embassy_net_tuntap::TunTapDevice; use heapless::Vec; use log::*; @@ -20,8 +20,8 @@ struct Opts { } #[embassy_executor::task] -async fn net_task(stack: &'static Stack) -> ! { - stack.run().await +async fn net_task(mut runner: embassy_net::Runner<'static, TunTapDevice>) -> ! { + runner.run().await } #[embassy_executor::task] @@ -49,12 +49,11 @@ async fn main_task(spawner: Spawner) { let seed = u64::from_le_bytes(seed); // Init network stack - static STACK: StaticCell> = StaticCell::new(); static RESOURCES: StaticCell> = StaticCell::new(); - let stack: &Stack<_> = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed)); + let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed); // Launch network task - spawner.spawn(net_task(stack)).unwrap(); + spawner.spawn(net_task(runner)).unwrap(); let host = "example.com"; info!("querying host {:?}...", host); diff --git a/examples/std/src/bin/net_ppp.rs b/examples/std/src/bin/net_ppp.rs index c5c27c4a3..7d0f1327f 100644 --- a/examples/std/src/bin/net_ppp.rs +++ b/examples/std/src/bin/net_ppp.rs @@ -37,16 +37,12 @@ struct Opts { } #[embassy_executor::task] -async fn net_task(stack: &'static Stack>) -> ! { - stack.run().await +async fn net_task(mut runner: embassy_net::Runner<'static, embassy_net_ppp::Device<'static>>) -> ! { + runner.run().await } #[embassy_executor::task] -async fn ppp_task( - stack: &'static Stack>, - mut runner: Runner<'static>, - port: SerialPort, -) -> ! { +async fn ppp_task(stack: Stack<'static>, mut runner: Runner<'static>, port: SerialPort) -> ! { let port = Async::new(port).unwrap(); let port = BufReader::new(port); let port = adapter::FromFutures::new(port); @@ -97,17 +93,16 @@ async fn main_task(spawner: Spawner) { let seed = u64::from_le_bytes(seed); // Init network stack - static STACK: StaticCell>> = StaticCell::new(); static RESOURCES: StaticCell> = StaticCell::new(); - let stack = &*STACK.init(Stack::new( + let (stack, net_runner) = embassy_net::new( device, Config::default(), // don't configure IP yet RESOURCES.init(StackResources::new()), seed, - )); + ); // Launch network task - spawner.spawn(net_task(stack)).unwrap(); + spawner.spawn(net_task(net_runner)).unwrap(); spawner.spawn(ppp_task(stack, runner, port)).unwrap(); // Then we can use it! diff --git a/examples/std/src/bin/net_udp.rs b/examples/std/src/bin/net_udp.rs index b2ba4915a..02d4d3efb 100644 --- a/examples/std/src/bin/net_udp.rs +++ b/examples/std/src/bin/net_udp.rs @@ -1,7 +1,7 @@ use clap::Parser; use embassy_executor::{Executor, Spawner}; use embassy_net::udp::{PacketMetadata, UdpSocket}; -use embassy_net::{Config, Ipv4Address, Ipv4Cidr, Stack, StackResources}; +use embassy_net::{Config, Ipv4Address, Ipv4Cidr, StackResources}; use embassy_net_tuntap::TunTapDevice; use heapless::Vec; use log::*; @@ -20,8 +20,8 @@ struct Opts { } #[embassy_executor::task] -async fn net_task(stack: &'static Stack) -> ! { - stack.run().await +async fn net_task(mut runner: embassy_net::Runner<'static, TunTapDevice>) -> ! { + runner.run().await } #[embassy_executor::task] @@ -48,12 +48,11 @@ async fn main_task(spawner: Spawner) { let seed = u64::from_le_bytes(seed); // Init network stack - static STACK: StaticCell> = StaticCell::new(); static RESOURCES: StaticCell> = StaticCell::new(); - let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed)); + let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed); // Launch network task - spawner.spawn(net_task(stack)).unwrap(); + spawner.spawn(net_task(runner)).unwrap(); // Then we can use it! let mut rx_meta = [PacketMetadata::EMPTY; 16]; diff --git a/examples/std/src/bin/tcp_accept.rs b/examples/std/src/bin/tcp_accept.rs index 39b29a449..5d36b739d 100644 --- a/examples/std/src/bin/tcp_accept.rs +++ b/examples/std/src/bin/tcp_accept.rs @@ -3,7 +3,7 @@ use core::fmt::Write as _; use clap::Parser; use embassy_executor::{Executor, Spawner}; use embassy_net::tcp::TcpSocket; -use embassy_net::{Config, Ipv4Address, Ipv4Cidr, Stack, StackResources}; +use embassy_net::{Config, Ipv4Address, Ipv4Cidr, StackResources}; use embassy_net_tuntap::TunTapDevice; use embassy_time::{Duration, Timer}; use embedded_io_async::Write as _; @@ -24,8 +24,8 @@ struct Opts { } #[embassy_executor::task] -async fn net_task(stack: &'static Stack) -> ! { - stack.run().await +async fn net_task(mut runner: embassy_net::Runner<'static, TunTapDevice>) -> ! { + runner.run().await } #[derive(Default)] @@ -62,12 +62,11 @@ async fn main_task(spawner: Spawner) { let seed = u64::from_le_bytes(seed); // Init network stack - static STACK: StaticCell> = StaticCell::new(); static RESOURCES: StaticCell> = StaticCell::new(); - let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed)); + let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed); // Launch network task - spawner.spawn(net_task(stack)).unwrap(); + spawner.spawn(net_task(runner)).unwrap(); // Then we can use it! let mut rx_buffer = [0; 4096]; diff --git a/examples/stm32f4/src/bin/eth.rs b/examples/stm32f4/src/bin/eth.rs index 9388c64bf..baed96449 100644 --- a/examples/stm32f4/src/bin/eth.rs +++ b/examples/stm32f4/src/bin/eth.rs @@ -4,7 +4,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_net::tcp::TcpSocket; -use embassy_net::{Ipv4Address, Stack, StackResources}; +use embassy_net::{Ipv4Address, StackResources}; use embassy_stm32::eth::generic_smi::GenericSMI; use embassy_stm32::eth::{Ethernet, PacketQueue}; use embassy_stm32::peripherals::ETH; @@ -24,8 +24,8 @@ bind_interrupts!(struct Irqs { type Device = Ethernet<'static, ETH, GenericSMI>; #[embassy_executor::task] -async fn net_task(stack: &'static Stack) -> ! { - stack.run().await +async fn net_task(mut runner: embassy_net::Runner<'static, Device>) -> ! { + runner.run().await } #[embassy_executor::main] @@ -88,12 +88,11 @@ async fn main(spawner: Spawner) -> ! { //}); // Init network stack - static STACK: StaticCell> = StaticCell::new(); static RESOURCES: StaticCell> = StaticCell::new(); - let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed)); + let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed); // Launch network task - unwrap!(spawner.spawn(net_task(stack))); + unwrap!(spawner.spawn(net_task(runner))); // Ensure DHCP configuration is up before trying connect stack.wait_config_up().await; @@ -105,7 +104,7 @@ async fn main(spawner: Spawner) -> ! { let mut tx_buffer = [0; 4096]; loop { - let mut socket = TcpSocket::new(&stack, &mut rx_buffer, &mut tx_buffer); + let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer); socket.set_timeout(Some(embassy_time::Duration::from_secs(10))); diff --git a/examples/stm32f4/src/bin/eth_w5500.rs b/examples/stm32f4/src/bin/eth_w5500.rs index 5c3c6c3ba..6e6bef08c 100644 --- a/examples/stm32f4/src/bin/eth_w5500.rs +++ b/examples/stm32f4/src/bin/eth_w5500.rs @@ -4,7 +4,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_net::tcp::TcpSocket; -use embassy_net::{Ipv4Address, Stack, StackResources}; +use embassy_net::{Ipv4Address, StackResources}; use embassy_net_wiznet::chip::W5500; use embassy_net_wiznet::{Device, Runner, State}; use embassy_stm32::exti::ExtiInput; @@ -31,8 +31,8 @@ async fn ethernet_task(runner: Runner<'static, W5500, EthernetSPI, ExtiInput<'st } #[embassy_executor::task] -async fn net_task(stack: &'static Stack>) -> ! { - stack.run().await +async fn net_task(mut runner: embassy_net::Runner<'static, Device<'static>>) -> ! { + runner.run().await } #[embassy_executor::main] @@ -92,12 +92,11 @@ async fn main(spawner: Spawner) -> ! { // gateway: Some(Ipv4Address::new(10, 42, 0, 1)), //}); - static STACK: StaticCell> = StaticCell::new(); static RESOURCES: StaticCell> = StaticCell::new(); - let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed)); + let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed); // Launch network task - unwrap!(spawner.spawn(net_task(stack))); + unwrap!(spawner.spawn(net_task(runner))); // Ensure DHCP configuration is up before trying connect stack.wait_config_up().await; diff --git a/examples/stm32f4/src/bin/usb_ethernet.rs b/examples/stm32f4/src/bin/usb_ethernet.rs index 94e51c338..a9504ec04 100644 --- a/examples/stm32f4/src/bin/usb_ethernet.rs +++ b/examples/stm32f4/src/bin/usb_ethernet.rs @@ -4,7 +4,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_net::tcp::TcpSocket; -use embassy_net::{Stack, StackResources}; +use embassy_net::StackResources; use embassy_stm32::rng::{self, Rng}; use embassy_stm32::time::Hertz; use embassy_stm32::usb::Driver; @@ -31,8 +31,8 @@ async fn usb_ncm_task(class: Runner<'static, UsbDriver, MTU>) -> ! { } #[embassy_executor::task] -async fn net_task(stack: &'static Stack>) -> ! { - stack.run().await +async fn net_task(mut runner: embassy_net::Runner<'static, Device<'static, MTU>>) -> ! { + runner.run().await } bind_interrupts!(struct Irqs { @@ -144,11 +144,10 @@ async fn main(spawner: Spawner) { let seed = u64::from_le_bytes(seed); // Init network stack - static STACK: StaticCell>> = StaticCell::new(); static RESOURCES: StaticCell> = StaticCell::new(); - let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed)); + let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed); - unwrap!(spawner.spawn(net_task(stack))); + unwrap!(spawner.spawn(net_task(runner))); // And now we can use it! diff --git a/examples/stm32f7/src/bin/eth.rs b/examples/stm32f7/src/bin/eth.rs index 2fd10c8fb..1f1eadf37 100644 --- a/examples/stm32f7/src/bin/eth.rs +++ b/examples/stm32f7/src/bin/eth.rs @@ -4,7 +4,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_net::tcp::TcpSocket; -use embassy_net::{Ipv4Address, Stack, StackResources}; +use embassy_net::{Ipv4Address, StackResources}; use embassy_stm32::eth::generic_smi::GenericSMI; use embassy_stm32::eth::{Ethernet, PacketQueue}; use embassy_stm32::peripherals::ETH; @@ -25,8 +25,8 @@ bind_interrupts!(struct Irqs { type Device = Ethernet<'static, ETH, GenericSMI>; #[embassy_executor::task] -async fn net_task(stack: &'static Stack) -> ! { - stack.run().await +async fn net_task(mut runner: embassy_net::Runner<'static, Device>) -> ! { + runner.run().await } #[embassy_executor::main] @@ -89,12 +89,11 @@ async fn main(spawner: Spawner) -> ! { //}); // Init network stack - static STACK: StaticCell> = StaticCell::new(); static RESOURCES: StaticCell> = StaticCell::new(); - let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed)); + let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed); // Launch network task - unwrap!(spawner.spawn(net_task(stack))); + unwrap!(spawner.spawn(net_task(runner))); // Ensure DHCP configuration is up before trying connect stack.wait_config_up().await; @@ -106,7 +105,7 @@ async fn main(spawner: Spawner) -> ! { let mut tx_buffer = [0; 4096]; loop { - let mut socket = TcpSocket::new(&stack, &mut rx_buffer, &mut tx_buffer); + let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer); socket.set_timeout(Some(embassy_time::Duration::from_secs(10))); diff --git a/examples/stm32h5/src/bin/eth.rs b/examples/stm32h5/src/bin/eth.rs index 65cfad8c9..eee1632f5 100644 --- a/examples/stm32h5/src/bin/eth.rs +++ b/examples/stm32h5/src/bin/eth.rs @@ -4,7 +4,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_net::tcp::TcpSocket; -use embassy_net::{Ipv4Address, Stack, StackResources}; +use embassy_net::{Ipv4Address, StackResources}; use embassy_stm32::eth::generic_smi::GenericSMI; use embassy_stm32::eth::{Ethernet, PacketQueue}; use embassy_stm32::peripherals::ETH; @@ -28,8 +28,8 @@ bind_interrupts!(struct Irqs { type Device = Ethernet<'static, ETH, GenericSMI>; #[embassy_executor::task] -async fn net_task(stack: &'static Stack) -> ! { - stack.run().await +async fn net_task(mut runner: embassy_net::Runner<'static, Device>) -> ! { + runner.run().await } #[embassy_executor::main] @@ -92,12 +92,11 @@ async fn main(spawner: Spawner) -> ! { //}); // Init network stack - static STACK: StaticCell> = StaticCell::new(); static RESOURCES: StaticCell> = StaticCell::new(); - let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed)); + let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed); // Launch network task - unwrap!(spawner.spawn(net_task(&stack))); + unwrap!(spawner.spawn(net_task(runner))); // Ensure DHCP configuration is up before trying connect stack.wait_config_up().await; @@ -109,7 +108,7 @@ async fn main(spawner: Spawner) -> ! { let mut tx_buffer = [0; 1024]; loop { - let mut socket = TcpSocket::new(&stack, &mut rx_buffer, &mut tx_buffer); + let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer); socket.set_timeout(Some(embassy_time::Duration::from_secs(10))); diff --git a/examples/stm32h7/src/bin/eth.rs b/examples/stm32h7/src/bin/eth.rs index b2f8ed91e..ec3f2c000 100644 --- a/examples/stm32h7/src/bin/eth.rs +++ b/examples/stm32h7/src/bin/eth.rs @@ -4,7 +4,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_net::tcp::TcpSocket; -use embassy_net::{Ipv4Address, Stack, StackResources}; +use embassy_net::{Ipv4Address, StackResources}; use embassy_stm32::eth::generic_smi::GenericSMI; use embassy_stm32::eth::{Ethernet, PacketQueue}; use embassy_stm32::peripherals::ETH; @@ -24,8 +24,8 @@ bind_interrupts!(struct Irqs { type Device = Ethernet<'static, ETH, GenericSMI>; #[embassy_executor::task] -async fn net_task(stack: &'static Stack) -> ! { - stack.run().await +async fn net_task(mut runner: embassy_net::Runner<'static, Device>) -> ! { + runner.run().await } #[embassy_executor::main] @@ -91,12 +91,11 @@ async fn main(spawner: Spawner) -> ! { //}); // Init network stack - static STACK: StaticCell> = StaticCell::new(); static RESOURCES: StaticCell> = StaticCell::new(); - let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed)); + let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed); // Launch network task - unwrap!(spawner.spawn(net_task(&stack))); + unwrap!(spawner.spawn(net_task(runner))); // Ensure DHCP configuration is up before trying connect stack.wait_config_up().await; @@ -108,7 +107,7 @@ async fn main(spawner: Spawner) -> ! { let mut tx_buffer = [0; 1024]; loop { - let mut socket = TcpSocket::new(&stack, &mut rx_buffer, &mut tx_buffer); + let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer); socket.set_timeout(Some(embassy_time::Duration::from_secs(10))); diff --git a/examples/stm32h7/src/bin/eth_client.rs b/examples/stm32h7/src/bin/eth_client.rs index 274c24ab1..24983ca85 100644 --- a/examples/stm32h7/src/bin/eth_client.rs +++ b/examples/stm32h7/src/bin/eth_client.rs @@ -4,7 +4,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_net::tcp::client::{TcpClient, TcpClientState}; -use embassy_net::{Stack, StackResources}; +use embassy_net::StackResources; use embassy_stm32::eth::generic_smi::GenericSMI; use embassy_stm32::eth::{Ethernet, PacketQueue}; use embassy_stm32::peripherals::ETH; @@ -25,8 +25,8 @@ bind_interrupts!(struct Irqs { type Device = Ethernet<'static, ETH, GenericSMI>; #[embassy_executor::task] -async fn net_task(stack: &'static Stack) -> ! { - stack.run().await +async fn net_task(mut runner: embassy_net::Runner<'static, Device>) -> ! { + runner.run().await } #[embassy_executor::main] @@ -91,12 +91,11 @@ async fn main(spawner: Spawner) -> ! { //}); // Init network stack - static STACK: StaticCell> = StaticCell::new(); static RESOURCES: StaticCell> = StaticCell::new(); - let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed)); + let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed); // Launch network task - unwrap!(spawner.spawn(net_task(stack))); + unwrap!(spawner.spawn(net_task(runner))); // Ensure DHCP configuration is up before trying connect stack.wait_config_up().await; @@ -104,7 +103,7 @@ async fn main(spawner: Spawner) -> ! { info!("Network task initialized"); let state: TcpClientState<1, 1024, 1024> = TcpClientState::new(); - let client = TcpClient::new(&stack, &state); + let client = TcpClient::new(stack, &state); loop { // You need to start a server on the host machine, for example: `nc -l 8000` diff --git a/examples/stm32h7/src/bin/eth_client_mii.rs b/examples/stm32h7/src/bin/eth_client_mii.rs index aa6544f41..768d85993 100644 --- a/examples/stm32h7/src/bin/eth_client_mii.rs +++ b/examples/stm32h7/src/bin/eth_client_mii.rs @@ -4,7 +4,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_net::tcp::client::{TcpClient, TcpClientState}; -use embassy_net::{Stack, StackResources}; +use embassy_net::StackResources; use embassy_stm32::eth::generic_smi::GenericSMI; use embassy_stm32::eth::{Ethernet, PacketQueue}; use embassy_stm32::peripherals::ETH; @@ -25,8 +25,8 @@ bind_interrupts!(struct Irqs { type Device = Ethernet<'static, ETH, GenericSMI>; #[embassy_executor::task] -async fn net_task(stack: &'static Stack) -> ! { - stack.run().await +async fn net_task(mut runner: embassy_net::Runner<'static, Device>) -> ! { + runner.run().await } #[embassy_executor::main] @@ -97,12 +97,11 @@ async fn main(spawner: Spawner) -> ! { //}); // Init network stack - static STACK: StaticCell> = StaticCell::new(); static RESOURCES: StaticCell> = StaticCell::new(); - let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed)); + let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed); // Launch network task - unwrap!(spawner.spawn(net_task(stack))); + unwrap!(spawner.spawn(net_task(runner))); // Ensure DHCP configuration is up before trying connect stack.wait_config_up().await; @@ -110,7 +109,7 @@ async fn main(spawner: Spawner) -> ! { info!("Network task initialized"); let state: TcpClientState<1, 1024, 1024> = TcpClientState::new(); - let client = TcpClient::new(&stack, &state); + let client = TcpClient::new(stack, &state); loop { // You need to start a server on the host machine, for example: `nc -l 8000` diff --git a/examples/stm32l4/src/bin/spe_adin1110_http_server.rs b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs index bd633cecb..be4270ada 100644 --- a/examples/stm32l4/src/bin/spe_adin1110_http_server.rs +++ b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs @@ -206,12 +206,11 @@ async fn main(spawner: Spawner) { }; // Init network stack - static STACK: StaticCell>> = StaticCell::new(); static RESOURCES: StaticCell> = StaticCell::new(); - let stack = &*STACK.init(Stack::new(device, ip_cfg, RESOURCES.init(StackResources::new()), seed)); + let (stack, runner) = embassy_net::new(device, ip_cfg, RESOURCES.init(StackResources::new()), seed); // Launch network task - unwrap!(spawner.spawn(net_task(stack))); + unwrap!(spawner.spawn(net_task(runner))); let cfg = wait_for_config(stack).await; let local_addr = cfg.address.address(); @@ -274,7 +273,7 @@ async fn main(spawner: Spawner) { } } -async fn wait_for_config(stack: &'static Stack>) -> embassy_net::StaticConfigV4 { +async fn wait_for_config(stack: Stack<'static>) -> embassy_net::StaticConfigV4 { loop { if let Some(config) = stack.config_v4() { return config; @@ -323,8 +322,8 @@ async fn ethernet_task(runner: Runner<'static, SpeSpiCs, SpeInt, SpeRst>) -> ! { } #[embassy_executor::task] -async fn net_task(stack: &'static Stack>) -> ! { - stack.run().await +async fn net_task(mut runner: embassy_net::Runner<'static, Device<'static>>) -> ! { + runner.run().await } // same panicking *behavior* as `panic-probe` but doesn't print a panic message diff --git a/examples/stm32l5/src/bin/usb_ethernet.rs b/examples/stm32l5/src/bin/usb_ethernet.rs index d02bac91d..095d50c73 100644 --- a/examples/stm32l5/src/bin/usb_ethernet.rs +++ b/examples/stm32l5/src/bin/usb_ethernet.rs @@ -4,7 +4,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_net::tcp::TcpSocket; -use embassy_net::{Stack, StackResources}; +use embassy_net::StackResources; use embassy_stm32::rng::Rng; use embassy_stm32::usb::Driver; use embassy_stm32::{bind_interrupts, peripherals, rng, usb, Config}; @@ -36,8 +36,8 @@ async fn usb_ncm_task(class: Runner<'static, MyDriver, MTU>) -> ! { } #[embassy_executor::task] -async fn net_task(stack: &'static Stack>) -> ! { - stack.run().await +async fn net_task(mut runner: embassy_net::Runner<'static, Device<'static, MTU>>) -> ! { + runner.run().await } #[embassy_executor::main] @@ -121,11 +121,10 @@ async fn main(spawner: Spawner) { let seed = rng.next_u64(); // Init network stack - static STACK: StaticCell>> = StaticCell::new(); static RESOURCES: StaticCell> = StaticCell::new(); - let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed)); + let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed); - unwrap!(spawner.spawn(net_task(stack))); + unwrap!(spawner.spawn(net_task(runner))); // And now we can use it! diff --git a/tests/nrf/src/bin/ethernet_enc28j60_perf.rs b/tests/nrf/src/bin/ethernet_enc28j60_perf.rs index 304754c0e..ed58627f1 100644 --- a/tests/nrf/src/bin/ethernet_enc28j60_perf.rs +++ b/tests/nrf/src/bin/ethernet_enc28j60_perf.rs @@ -6,7 +6,7 @@ teleprobe_meta::timeout!(120); use defmt::{info, unwrap}; use embassy_executor::Spawner; -use embassy_net::{Stack, StackResources}; +use embassy_net::StackResources; use embassy_net_enc28j60::Enc28j60; use embassy_nrf::gpio::{Level, Output, OutputDrive}; use embassy_nrf::rng::Rng; @@ -25,8 +25,8 @@ bind_interrupts!(struct Irqs { type MyDriver = Enc28j60, Output<'static>, Delay>, Output<'static>>; #[embassy_executor::task] -async fn net_task(stack: &'static Stack) -> ! { - stack.run().await +async fn net_task(mut runner: embassy_net::Runner<'static, MyDriver>) -> ! { + runner.run().await } #[embassy_executor::main] @@ -65,11 +65,10 @@ async fn main(spawner: Spawner) { let seed = u64::from_le_bytes(seed); // Init network stack - static STACK: StaticCell> = StaticCell::new(); static RESOURCES: StaticCell> = StaticCell::new(); - let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed)); + let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed); - unwrap!(spawner.spawn(net_task(stack))); + unwrap!(spawner.spawn(net_task(runner))); perf_client::run( stack, diff --git a/tests/nrf/src/bin/wifi_esp_hosted_perf.rs b/tests/nrf/src/bin/wifi_esp_hosted_perf.rs index 6632442f1..34fb8103b 100644 --- a/tests/nrf/src/bin/wifi_esp_hosted_perf.rs +++ b/tests/nrf/src/bin/wifi_esp_hosted_perf.rs @@ -6,7 +6,7 @@ teleprobe_meta::timeout!(120); use defmt::{info, unwrap}; use embassy_executor::Spawner; -use embassy_net::{Config, Stack, StackResources}; +use embassy_net::{Config, StackResources}; use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pull}; use embassy_nrf::rng::Rng; use embassy_nrf::spim::{self, Spim}; @@ -40,8 +40,8 @@ async fn wifi_task( type MyDriver = hosted::NetDriver<'static>; #[embassy_executor::task] -async fn net_task(stack: &'static Stack) -> ! { - stack.run().await +async fn net_task(mut runner: embassy_net::Runner<'static, MyDriver>) -> ! { + runner.run().await } #[embassy_executor::main] @@ -86,16 +86,15 @@ async fn main(spawner: Spawner) { let seed = u64::from_le_bytes(seed); // Init network stack - static STACK: StaticCell> = StaticCell::new(); static RESOURCES: StaticCell> = StaticCell::new(); - let stack = &*STACK.init(Stack::new( + let (stack, runner) = embassy_net::new( device, Config::dhcpv4(Default::default()), RESOURCES.init(StackResources::new()), seed, - )); + ); - unwrap!(spawner.spawn(net_task(stack))); + unwrap!(spawner.spawn(net_task(runner))); perf_client::run( stack, diff --git a/tests/perf-client/src/lib.rs b/tests/perf-client/src/lib.rs index 54762379a..4bd9e5674 100644 --- a/tests/perf-client/src/lib.rs +++ b/tests/perf-client/src/lib.rs @@ -2,7 +2,6 @@ use defmt::{assert, *}; use embassy_futures::join::join; -use embassy_net::driver::Driver; use embassy_net::tcp::TcpSocket; use embassy_net::{Ipv4Address, Stack}; use embassy_time::{with_timeout, Duration, Timer}; @@ -13,7 +12,7 @@ pub struct Expected { pub updown_kbps: usize, } -pub async fn run(stack: &Stack, expected: Expected) { +pub async fn run(stack: Stack<'_>, expected: Expected) { info!("Waiting for DHCP up..."); while stack.config_v4().is_none() { Timer::after_millis(100).await; @@ -38,7 +37,7 @@ const DOWNLOAD_PORT: u16 = 4321; const UPLOAD_PORT: u16 = 4322; const UPLOAD_DOWNLOAD_PORT: u16 = 4323; -async fn test_download(stack: &Stack) -> usize { +async fn test_download(stack: Stack<'_>) -> usize { info!("Testing download..."); let mut rx_buffer = [0; RX_BUFFER_SIZE]; @@ -78,7 +77,7 @@ async fn test_download(stack: &Stack) -> usize { kbps } -async fn test_upload(stack: &Stack) -> usize { +async fn test_upload(stack: Stack<'_>) -> usize { info!("Testing upload..."); let mut rx_buffer = [0; RX_BUFFER_SIZE]; @@ -118,7 +117,7 @@ async fn test_upload(stack: &Stack) -> usize { kbps } -async fn test_upload_download(stack: &Stack) -> usize { +async fn test_upload_download(stack: Stack<'_>) -> usize { info!("Testing upload+download..."); let mut rx_buffer = [0; RX_BUFFER_SIZE]; diff --git a/tests/rp/src/bin/cyw43-perf.rs b/tests/rp/src/bin/cyw43-perf.rs index 11c8aa58c..30e4afb07 100644 --- a/tests/rp/src/bin/cyw43-perf.rs +++ b/tests/rp/src/bin/cyw43-perf.rs @@ -6,7 +6,7 @@ use cyw43::JoinOptions; use cyw43_pio::PioSpi; use defmt::{panic, *}; use embassy_executor::Spawner; -use embassy_net::{Config, Stack, StackResources}; +use embassy_net::{Config, StackResources}; use embassy_rp::gpio::{Level, Output}; use embassy_rp::peripherals::{DMA_CH0, PIO0}; use embassy_rp::pio::{InterruptHandler, Pio}; @@ -30,8 +30,8 @@ async fn wifi_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'stati } #[embassy_executor::task] -async fn net_task(stack: &'static Stack>) -> ! { - stack.run().await +async fn net_task(mut runner: embassy_net::Runner<'static, cyw43::NetDriver<'static>>) -> ! { + runner.run().await } #[embassy_executor::main] @@ -70,16 +70,15 @@ async fn main(spawner: Spawner) { let seed = 0x0123_4567_89ab_cdef; // chosen by fair dice roll. guarenteed to be random. // Init network stack - static STACK: StaticCell>> = StaticCell::new(); static RESOURCES: StaticCell> = StaticCell::new(); - let stack = &*STACK.init(Stack::new( + let (stack, runner) = embassy_net::new( net_device, Config::dhcpv4(Default::default()), RESOURCES.init(StackResources::new()), seed, - )); + ); - unwrap!(spawner.spawn(net_task(stack))); + unwrap!(spawner.spawn(net_task(runner))); loop { match control diff --git a/tests/rp/src/bin/ethernet_w5100s_perf.rs b/tests/rp/src/bin/ethernet_w5100s_perf.rs index f15f33743..ae2adfa55 100644 --- a/tests/rp/src/bin/ethernet_w5100s_perf.rs +++ b/tests/rp/src/bin/ethernet_w5100s_perf.rs @@ -5,7 +5,7 @@ teleprobe_meta::timeout!(120); use defmt::*; use embassy_executor::Spawner; -use embassy_net::{Stack, StackResources}; +use embassy_net::StackResources; use embassy_net_wiznet::chip::W5100S; use embassy_net_wiznet::*; use embassy_rp::clocks::RoscRng; @@ -32,8 +32,8 @@ async fn ethernet_task( } #[embassy_executor::task] -async fn net_task(stack: &'static Stack>) -> ! { - stack.run().await +async fn net_task(mut runner: embassy_net::Runner<'static, Device<'static>>) -> ! { + runner.run().await } #[embassy_executor::main] @@ -67,17 +67,16 @@ async fn main(spawner: Spawner) { let seed = rng.next_u64(); // Init network stack - static STACK: StaticCell>> = StaticCell::new(); static RESOURCES: StaticCell> = StaticCell::new(); - let stack = &*STACK.init(Stack::new( + let (stack, runner) = embassy_net::new( device, embassy_net::Config::dhcpv4(Default::default()), RESOURCES.init(StackResources::new()), seed, - )); + ); // Launch network task - unwrap!(spawner.spawn(net_task(&stack))); + unwrap!(spawner.spawn(net_task(runner))); perf_client::run( stack, diff --git a/tests/stm32/src/bin/eth.rs b/tests/stm32/src/bin/eth.rs index 9da514881..bf1922dde 100644 --- a/tests/stm32/src/bin/eth.rs +++ b/tests/stm32/src/bin/eth.rs @@ -6,7 +6,7 @@ mod common; use common::*; use embassy_executor::Spawner; -use embassy_net::{Stack, StackResources}; +use embassy_net::StackResources; use embassy_stm32::eth::generic_smi::GenericSMI; use embassy_stm32::eth::{Ethernet, PacketQueue}; use embassy_stm32::peripherals::ETH; @@ -32,8 +32,8 @@ bind_interrupts!(struct Irqs { type Device = Ethernet<'static, ETH, GenericSMI>; #[embassy_executor::task] -async fn net_task(stack: &'static Stack) -> ! { - stack.run().await +async fn net_task(mut runner: embassy_net::Runner<'static, Device>) -> ! { + runner.run().await } #[embassy_executor::main] @@ -99,12 +99,11 @@ async fn main(spawner: Spawner) { //}); // Init network stack - static STACK: StaticCell> = StaticCell::new(); static RESOURCES: StaticCell> = StaticCell::new(); - let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed)); + let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed); // Launch network task - unwrap!(spawner.spawn(net_task(&stack))); + unwrap!(spawner.spawn(net_task(runner))); perf_client::run( stack, From 73aa40a9b9ab13655aa39969494dd377f57b699e Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 16 Sep 2024 21:27:34 +0200 Subject: [PATCH 0138/1217] Disable nrf52840 hil tests. --- ci.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ci.sh b/ci.sh index 5e8bddb8c..50331bdba 100755 --- a/ci.sh +++ b/ci.sh @@ -290,8 +290,9 @@ cargo batch \ $BUILD_EXTRA -# temporarily disabled, bluepill board got bricked +# temporarily disabled, these boards are dead. rm -rf out/tests/stm32f103c8 +rm -rf out/tests/nrf52840-dk rm out/tests/stm32wb55rg/wpan_mac rm out/tests/stm32wb55rg/wpan_ble From 6d89f2729ab7a6ee3dd78ccaef1b16677b5a9eee Mon Sep 17 00:00:00 2001 From: kingofpayne <43875454+kingofpayne@users.noreply.github.com> Date: Mon, 16 Sep 2024 22:07:56 +0200 Subject: [PATCH 0139/1217] boot: flash-erase-zero (#3344) Allow compatibility with devices whose flash erase set bytes to 0x00 instead of 0xFF, using a new flash-erase-zero feature. See issue #3342. --- docs/pages/bootloader.adoc | 2 ++ embassy-boot/Cargo.toml | 1 + embassy-boot/src/lib.rs | 4 ++++ 3 files changed, 7 insertions(+) diff --git a/docs/pages/bootloader.adoc b/docs/pages/bootloader.adoc index 3b0cdb182..d8d50040b 100644 --- a/docs/pages/bootloader.adoc +++ b/docs/pages/bootloader.adoc @@ -19,6 +19,8 @@ The bootloader supports In general, the bootloader works on any platform that implements the `embedded-storage` traits for its internal flash, but may require custom initialization code to work. +STM32L0x1 devices require the `flash-erase-zero` feature to be enabled. + == Design image::bootloader_flash.png[Bootloader flash layout] diff --git a/embassy-boot/Cargo.toml b/embassy-boot/Cargo.toml index d27fe763e..79ba6456a 100644 --- a/embassy-boot/Cargo.toml +++ b/embassy-boot/Cargo.toml @@ -47,6 +47,7 @@ ed25519-dalek = { version = "2", default-features = false, features = ["std", "r [features] ed25519-dalek = ["dep:ed25519-dalek", "_verify"] ed25519-salty = ["dep:salty", "_verify"] +flash-erase-zero = [] #Internal features _verify = [] diff --git a/embassy-boot/src/lib.rs b/embassy-boot/src/lib.rs index b4f03e01e..8849055e8 100644 --- a/embassy-boot/src/lib.rs +++ b/embassy-boot/src/lib.rs @@ -14,7 +14,11 @@ mod test_flash; // The expected value of the flash after an erase // TODO: Use the value provided by NorFlash when available +#[cfg(not(feature = "flash-erase-zero"))] pub(crate) const STATE_ERASE_VALUE: u8 = 0xFF; +#[cfg(feature = "flash-erase-zero")] +pub(crate) const STATE_ERASE_VALUE: u8 = 0x00; + pub use boot_loader::{BootError, BootLoader, BootLoaderConfig}; pub use firmware_updater::{ BlockingFirmwareState, BlockingFirmwareUpdater, FirmwareState, FirmwareUpdater, FirmwareUpdaterConfig, From 0fe9fa631a8f905809424bd7b31a7b74568eb5b6 Mon Sep 17 00:00:00 2001 From: klownfish Date: Tue, 17 Sep 2024 18:42:26 +0200 Subject: [PATCH 0140/1217] WIP: add u5 adc --- embassy-stm32/src/adc/mod.rs | 20 ++++++++-------- embassy-stm32/src/adc/u5.rs | 45 ++++++++++++++---------------------- 2 files changed, 26 insertions(+), 39 deletions(-) diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index 9bf840f7c..3bd7c793d 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs @@ -4,7 +4,7 @@ #![allow(missing_docs)] // TODO #![cfg_attr(adc_f3_v2, allow(unused))] -#[cfg(not(any(adc_f3_v2, adc_u5)))] +#[cfg(not(any(adc_f3_v2)))] #[cfg_attr(adc_f1, path = "f1.rs")] #[cfg_attr(adc_f3, path = "f3.rs")] #[cfg_attr(adc_f3_v1_1, path = "f3_v1_1.rs")] @@ -20,16 +20,14 @@ mod _version; use core::marker::PhantomData; #[allow(unused)] -#[cfg(not(any(adc_f3_v2, adc_u5)))] +#[cfg(not(any(adc_f3_v2)))] pub use _version::*; #[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))] use embassy_sync::waitqueue::AtomicWaker; -#[cfg(not(any(adc_u5)))] pub use crate::pac::adc::vals; -#[cfg(not(any(adc_f1, adc_f3_v2, adc_u5)))] +#[cfg(not(any(adc_f1, adc_f3_v2)))] pub use crate::pac::adc::vals::Res as Resolution; -#[cfg(not(any(adc_u5)))] pub use crate::pac::adc::vals::SampleTime; use crate::peripherals; @@ -39,7 +37,7 @@ dma_trait!(RxDma, Instance); pub struct Adc<'d, T: Instance> { #[allow(unused)] adc: crate::PeripheralRef<'d, T>, - #[cfg(not(any(adc_f3_v2, adc_f3_v1_1, adc_u5)))] + #[cfg(not(any(adc_f3_v2, adc_f3_v1_1)))] sample_time: SampleTime, } @@ -60,7 +58,7 @@ impl State { trait SealedInstance { #[allow(unused)] fn regs() -> crate::pac::adc::Adc; - #[cfg(not(any(adc_f1, adc_v1, adc_l0, adc_f3_v2, adc_f3_v1_1, adc_g0, adc_u5)))] + #[cfg(not(any(adc_f1, adc_v1, adc_l0, adc_f3_v2, adc_f3_v1_1, adc_g0)))] #[allow(unused)] fn common_regs() -> crate::pac::adccommon::AdcCommon; #[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))] @@ -168,7 +166,7 @@ foreach_adc!( crate::pac::$inst } - #[cfg(not(any(adc_f1, adc_v1, adc_l0, adc_f3_v2, adc_f3_v1_1, adc_g0, adc_u5)))] + #[cfg(not(any(adc_f1, adc_v1, adc_l0, adc_f3_v2, adc_f3_v1_1, adc_g0)))] fn common_regs() -> crate::pac::adccommon::AdcCommon { return crate::pac::$common_inst } @@ -205,12 +203,12 @@ macro_rules! impl_adc_pin { /// Get the maximum reading value for this resolution. /// /// This is `2**n - 1`. -#[cfg(not(any(adc_f1, adc_f3_v2, adc_u5)))] +#[cfg(not(any(adc_f1, adc_f3_v2)))] pub const fn resolution_to_max_count(res: Resolution) -> u32 { match res { #[cfg(adc_v4)] Resolution::BITS16 => (1 << 16) - 1, - #[cfg(adc_v4)] + #[cfg(any(adc_v4, adc_u5))] Resolution::BITS14 => (1 << 14) - 1, #[cfg(adc_v4)] Resolution::BITS14V => (1 << 14) - 1, @@ -224,4 +222,4 @@ pub const fn resolution_to_max_count(res: Resolution) -> u32 { #[allow(unreachable_patterns)] _ => core::unreachable!(), } -} +} \ No newline at end of file diff --git a/embassy-stm32/src/adc/u5.rs b/embassy-stm32/src/adc/u5.rs index 9e6a94e5d..a86638a60 100644 --- a/embassy-stm32/src/adc/u5.rs +++ b/embassy-stm32/src/adc/u5.rs @@ -1,19 +1,19 @@ #[allow(unused)] use pac::adc::vals::{Difsel, Exten, Pcsel}; use pac::adccommon::vals::Presc; -use crate::peripherals::ADC4; +use pac::PWR; use super::{ - blocking_delay_us, Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, SealedAdcChannel + blocking_delay_us, Adc, AdcChannel, Instance, Resolution, SampleTime, SealedAdcChannel }; use crate::time::Hertz; use crate::{pac, rcc, Peripheral}; -// TODO: not correct const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(55); -const VREF_CHANNEL: u8 = 19; -const TEMP_CHANNEL: u8 = 18; -const VBAT_CHANNEL: u8 = 17; + +const VREF_CHANNEL: u8 = 1; +const VBAT_CHANNEL: u8 = 18; +const TEMP_CHANNEL: u8 = 19; /// Default VREF voltage used for sample conversion to millivolts. pub const VREF_DEFAULT_MV: u32 = 3300; @@ -140,9 +140,17 @@ pub enum Averaging { impl<'d, T: Instance> Adc<'d, T> { /// Create a new ADC driver. pub fn new(adc: impl Peripheral

+ 'd) -> Self { + // move to u5 init (RCC)? + PWR.svmcr().modify(|w| { + w.set_avm1en(true); + }); + while !PWR.svmsr().read().vdda1rdy() {} + PWR.svmcr().modify(|w| { + w.set_asv(true); + }); + embassy_hal_internal::into_ref!(adc); rcc::enable_and_reset::(); - let prescaler = Prescaler::from_ker_ck(T::frequency()); T::common_regs().ccr().modify(|w| w.set_presc(prescaler.presc())); @@ -158,26 +166,15 @@ impl<'d, T: Instance> Adc<'d, T> { adc, sample_time: SampleTime::from_bits(0), }; - crate::pac::RCC.ahb2enr1().modify(|w| { - w.set_adc12en(true); - }); - blocking_delay_us(100); - info!("chungus {}", line!()); s.power_up(); - info!("chungus {}", line!()); s.configure_differential_inputs(); - info!("chungus {}", line!()); s.calibrate(); - info!("chungus {}", line!()); blocking_delay_us(1); - info!("chungus {}", line!()); s.enable(); - info!("chungus {}", line!()); s.configure(); - info!("chungus {}", line!()); s } @@ -186,19 +183,11 @@ impl<'d, T: Instance> Adc<'d, T> { T::regs().isr().modify(|reg| { reg.set_ldordy(true); }); - info!("yummmum {}", T::regs().cr().as_ptr() as u32); T::regs().cr().modify(|reg| { - info!("bajssis {}", reg.0); reg.set_deeppwd(false); - info!("bajssis {}", reg.0); reg.set_advregen(true); - info!("bajssis {}", reg.0); }); - info!("kissis {}", T::regs().as_ptr() as u32); - info!("basdsadasadjsisssss{}", T::regs().isr().as_ptr() as u32); - while !T::regs().isr().read().ldordy() { - // info!("bajsisssss{}", T::regs().isr().read().0); - }; + while !T::regs().isr().read().ldordy() { }; T::regs().isr().modify(|reg| { reg.set_ldordy(true); @@ -372,4 +361,4 @@ impl<'d, T: Instance> Adc<'d, T> { while T::regs().cr().read().adstart() {} } } -} +} \ No newline at end of file From 0bfc98a3e526075ad14517589e4879d14f50ad12 Mon Sep 17 00:00:00 2001 From: kalkyl Date: Tue, 17 Sep 2024 19:41:58 +0200 Subject: [PATCH 0141/1217] rp: Add PIO example for one-wire temperature sensor --- examples/rp/src/bin/pio_onewire.rs | 155 +++++++++++++++++++++++++++++ 1 file changed, 155 insertions(+) create mode 100644 examples/rp/src/bin/pio_onewire.rs diff --git a/examples/rp/src/bin/pio_onewire.rs b/examples/rp/src/bin/pio_onewire.rs new file mode 100644 index 000000000..5076101ec --- /dev/null +++ b/examples/rp/src/bin/pio_onewire.rs @@ -0,0 +1,155 @@ +//! This example shows how you can use PIO to read a `DS18B20` one-wire temperature sensor. + +#![no_std] +#![no_main] +use defmt::*; +use embassy_executor::Spawner; +use embassy_rp::bind_interrupts; +use embassy_rp::peripherals::PIO0; +use embassy_rp::pio::{self, Common, Config, InterruptHandler, Pio, PioPin, ShiftConfig, ShiftDirection, StateMachine}; +use embassy_time::Timer; +use {defmt_rtt as _, panic_probe as _}; + +bind_interrupts!(struct Irqs { + PIO0_IRQ_0 => InterruptHandler; +}); + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_rp::init(Default::default()); + let mut pio = Pio::new(p.PIO0, Irqs); + let mut sensor = Ds18b20::new(&mut pio.common, pio.sm0, p.PIN_2); + + loop { + sensor.start().await; // Start a new measurement + Timer::after_secs(1).await; // Allow 1s for the measurement to finish + match sensor.temperature().await { + Ok(temp) => info!("temp = {:?} deg C", temp), + _ => error!("sensor error"), + } + Timer::after_secs(1).await; + } +} + +/// DS18B20 temperature sensor driver +pub struct Ds18b20<'d, PIO: pio::Instance, const SM: usize> { + sm: StateMachine<'d, PIO, SM>, +} + +impl<'d, PIO: pio::Instance, const SM: usize> Ds18b20<'d, PIO, SM> { + /// Create a new instance the driver + pub fn new(common: &mut Common<'d, PIO>, mut sm: StateMachine<'d, PIO, SM>, pin: impl PioPin) -> Self { + let prg = pio_proc::pio_asm!( + r#" + .wrap_target + again: + pull block + mov x, osr + jmp !x, read + write: + set pindirs, 1 + set pins, 0 + loop1: + jmp x--,loop1 + set pindirs, 0 [31] + wait 1 pin 0 [31] + pull block + mov x, osr + bytes1: + pull block + set y, 7 + set pindirs, 1 + bit1: + set pins, 0 [1] + out pins,1 [31] + set pins, 1 [20] + jmp y--,bit1 + jmp x--,bytes1 + set pindirs, 0 [31] + jmp again + read: + pull block + mov x, osr + bytes2: + set y, 7 + bit2: + set pindirs, 1 + set pins, 0 [1] + set pindirs, 0 [5] + in pins,1 [10] + jmp y--,bit2 + jmp x--,bytes2 + .wrap + "#, + ); + + let pin = common.make_pio_pin(pin); + let mut cfg = Config::default(); + cfg.use_program(&common.load_program(&prg.program), &[]); + cfg.set_out_pins(&[&pin]); + cfg.set_in_pins(&[&pin]); + cfg.set_set_pins(&[&pin]); + cfg.shift_in = ShiftConfig { + auto_fill: true, + direction: ShiftDirection::Right, + threshold: 8, + }; + cfg.clock_divider = 255_u8.into(); + sm.set_config(&cfg); + sm.set_enable(true); + Self { sm } + } + + /// Write bytes over the wire + async fn write_bytes(&mut self, bytes: &[u8]) { + self.sm.tx().wait_push(250).await; + self.sm.tx().wait_push(bytes.len() as u32 - 1).await; + for b in bytes { + self.sm.tx().wait_push(*b as u32).await; + } + } + + /// Read bytes from the wire + async fn read_bytes(&mut self, bytes: &mut [u8]) { + self.sm.tx().wait_push(0).await; + self.sm.tx().wait_push(bytes.len() as u32 - 1).await; + for b in bytes.iter_mut() { + *b = (self.sm.rx().wait_pull().await >> 24) as u8; + } + } + + /// Calculate CRC8 of the data + fn crc8(data: &[u8]) -> u8 { + let mut temp; + let mut data_byte; + let mut crc = 0; + for b in data { + data_byte = *b; + for _ in 0..8 { + temp = (crc ^ data_byte) & 0x01; + crc >>= 1; + if temp != 0 { + crc ^= 0x8C; + } + data_byte >>= 1; + } + } + crc + } + + /// Start a new measurement. Allow at least 1000ms before getting `temperature`. + pub async fn start(&mut self) { + self.write_bytes(&[0xCC, 0x44]).await; + } + + /// Read the temperature. Ensure >1000ms has passed since `start` before calling this. + pub async fn temperature(&mut self) -> Result { + self.write_bytes(&[0xCC, 0xBE]).await; + let mut data = [0; 9]; + self.read_bytes(&mut data).await; + match Self::crc8(&data) == 0 { + true => Ok(((data[1] as u32) << 8 | data[0] as u32) as f32 / 16.), + false => Err(()), + } + } +} From 2bc49763c6c36026feeaf681078d06106b73e0b0 Mon Sep 17 00:00:00 2001 From: Ugljesa Jovanovic Date: Sat, 14 Sep 2024 14:57:10 +0200 Subject: [PATCH 0142/1217] TRNG support for 235x --- embassy-rp/src/lib.rs | 4 + embassy-rp/src/trng.rs | 405 ++++++++++++++++++++++++++++++++++ examples/rp23/src/bin/trng.rs | 64 ++++++ 3 files changed, 473 insertions(+) create mode 100644 embassy-rp/src/trng.rs create mode 100644 examples/rp23/src/bin/trng.rs diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs index c357c14c2..d402cf793 100644 --- a/embassy-rp/src/lib.rs +++ b/embassy-rp/src/lib.rs @@ -42,6 +42,8 @@ pub mod rtc; pub mod spi; #[cfg(feature = "time-driver")] pub mod time_driver; +#[cfg(feature = "_rp235x")] +pub mod trng; pub mod uart; pub mod usb; pub mod watchdog; @@ -402,6 +404,8 @@ embassy_hal_internal::peripherals! { WATCHDOG, BOOTSEL, + + TRNG } #[cfg(all(not(feature = "boot2-none"), feature = "rp2040"))] diff --git a/embassy-rp/src/trng.rs b/embassy-rp/src/trng.rs new file mode 100644 index 000000000..9f2f33c4b --- /dev/null +++ b/embassy-rp/src/trng.rs @@ -0,0 +1,405 @@ +//! True Random Number Generator (TRNG) driver. + +use core::future::poll_fn; +use core::marker::PhantomData; +use core::ops::Not; +use core::task::Poll; + +use embassy_hal_internal::Peripheral; +use embassy_sync::waitqueue::AtomicWaker; +use rand_core::Error; + +use crate::interrupt::typelevel::{Binding, Interrupt}; +use crate::peripherals::TRNG; +use crate::{interrupt, pac}; + +trait SealedInstance { + fn regs() -> pac::trng::Trng; + fn waker() -> &'static AtomicWaker; +} + +/// TRNG peripheral instance. +#[allow(private_bounds)] +pub trait Instance: SealedInstance { + /// Interrupt for this peripheral. + type Interrupt: Interrupt; +} + +impl SealedInstance for TRNG { + fn regs() -> rp_pac::trng::Trng { + pac::TRNG + } + + fn waker() -> &'static AtomicWaker { + static WAKER: AtomicWaker = AtomicWaker::new(); + &WAKER + } +} + +impl Instance for TRNG { + type Interrupt = interrupt::typelevel::TRNG_IRQ; +} + +#[derive(Copy, Clone, Debug)] +#[allow(missing_docs)] +/// TRNG ROSC Inverter chain length options. +pub enum InverterChainLength { + None = 0, + One, + Two, + Three, + Four, +} + +impl From for u8 { + fn from(value: InverterChainLength) -> Self { + value as u8 + } +} + +/// Configuration for the TRNG. +/// +/// - Three built in entropy checks +/// - ROSC frequency controlled by selecting one of ROSC chain lengths +/// - Sample period in terms of system clock ticks +/// +/// +/// Default configuration is based on the following from documentation: +/// +/// ---- +/// +/// RP2350 Datasheet 12.12.2 +/// +/// ... +/// +/// When configuring the TRNG block, consider the following principles: +/// • As average generation time increases, result quality increases and failed entropy checks decrease. +/// • A low sample count decreases average generation time, but increases the chance of NIST test-failing results and +/// failed entropy checks. +/// For acceptable results with an average generation time of about 2 milliseconds, use ROSC chain length settings of 0 or +/// 1 and sample count settings of 20-25. +/// +/// --- +/// +/// Note, Pico SDK and Bootrom don't use any of the entropy checks and sample the ROSC directly +/// by setting the sample period to 0. Random data collected this way is then passed through +/// either hardware accelerated SHA256 (Bootrom) or xoroshiro128** (version 1.0!). +#[non_exhaustive] +#[derive(Copy, Clone, Debug)] +pub struct Config { + /// Bypass TRNG autocorrelation test + pub disable_autocorrelation_test: bool, + /// Bypass CRNGT test + pub disable_crngt_test: bool, + /// When set, the Von-Neuman balancer is bypassed (including the + /// 32 consecutive bits test) + pub disable_von_neumann_balancer: bool, + /// Sets the number of rng_clk cycles between two consecutive + /// ring oscillator samples. + /// Note: If the von Neumann decorrelator is bypassed, the minimum value for + /// sample counter must not be less than seventeen + pub sample_count: u32, + /// Selects the number of inverters (out of four possible + /// selections) in the ring oscillator (the entropy source). Higher values select + /// longer inverter chain lengths. + pub inverter_chain_length: InverterChainLength, +} + +impl Default for Config { + fn default() -> Self { + Config { + disable_autocorrelation_test: true, + disable_crngt_test: true, + disable_von_neumann_balancer: true, + sample_count: 25, + inverter_chain_length: InverterChainLength::One, + } + } +} + +/// True Random Number Generator Driver for RP2350 +/// +/// This driver provides async and blocking options. +/// +/// See [Config] for configuration details. +/// +/// Usage example: +/// ```no_run +/// use embassy_executor::Spawner; +/// use embassy_rp::trng::Trng; +/// use embassy_rp::peripherals::TRNG; +/// use embassy_rp::bind_interrupts; +/// +/// bind_interrupts!(struct Irqs { +/// TRNG_IRQ => embassy_rp::trng::InterruptHandler; +/// }); +/// +/// #[embassy_executor::main] +/// async fn main(spawner: Spawner) { +/// let peripherals = embassy_rp::init(Default::default()); +/// let mut trng = Trng::new(peripherals.TRNG, Irqs, embassy_rp::trng::Config::default()); +/// +/// let mut randomness = [0u8; 58]; +/// loop { +/// trng.fill_bytes(&mut randomness).await; +/// assert_ne!(randomness, [0u8; 58]); +/// } +///} +/// ``` +pub struct Trng<'d, T: Instance> { + phantom: PhantomData<&'d mut T>, +} + +/// 12.12.1. Overview +/// On request, the TRNG block generates a block of 192 entropy bits generated by automatically processing a series of +/// periodic samples from the TRNG block’s internal Ring Oscillator (ROSC). +const TRNG_BLOCK_SIZE_BITS: usize = 192; +const TRNG_BLOCK_SIZE_BYTES: usize = TRNG_BLOCK_SIZE_BITS / 8; + +impl<'d, T: Instance> Trng<'d, T> { + /// Create a new TRNG driver. + pub fn new( + _trng: impl Peripheral

+ 'd, + _irq: impl Binding> + 'd, + config: Config, + ) -> Self { + let regs = T::regs(); + + regs.rng_imr().write(|w| w.set_ehr_valid_int_mask(false)); + + let trng_config_register = regs.trng_config(); + trng_config_register.write(|w| { + w.set_rnd_src_sel(config.inverter_chain_length.clone().into()); + }); + + let sample_count_register = regs.sample_cnt1(); + sample_count_register.write(|w| { + *w = config.sample_count; + }); + + let debug_control_register = regs.trng_debug_control(); + debug_control_register.write(|w| { + w.set_auto_correlate_bypass(config.disable_autocorrelation_test); + w.set_trng_crngt_bypass(config.disable_crngt_test); + w.set_vnc_bypass(config.disable_von_neumann_balancer) + }); + + Trng { phantom: PhantomData } + } + + fn start_rng(&self) { + let regs = T::regs(); + let source_enable_register = regs.rnd_source_enable(); + // Enable TRNG ROSC + source_enable_register.write(|w| w.set_rnd_src_en(true)); + } + + fn stop_rng(&self) { + let regs = T::regs(); + let source_enable_register = regs.rnd_source_enable(); + source_enable_register.write(|w| w.set_rnd_src_en(false)); + let reset_bits_counter_register = regs.rst_bits_counter(); + reset_bits_counter_register.write(|w| w.set_rst_bits_counter(true)); + } + + fn enable_irq(&self) { + unsafe { T::Interrupt::enable() } + } + + fn disable_irq(&self) { + T::Interrupt::disable(); + } + + fn blocking_wait_for_successful_generation(&self) { + let regs = T::regs(); + + let trng_busy_register = regs.trng_busy(); + let trng_valid_register = regs.trng_valid(); + + let mut success = false; + while success.not() { + while trng_busy_register.read().trng_busy() {} + if trng_valid_register.read().ehr_valid().not() { + if regs.rng_isr().read().autocorr_err() { + regs.trng_sw_reset().write(|w| w.set_trng_sw_reset(true)); + } else { + panic!("RNG not busy, but ehr is not valid!") + } + } else { + success = true + } + } + } + + fn read_ehr_registers_into_array(&mut self, buffer: &mut [u8; TRNG_BLOCK_SIZE_BYTES]) { + let regs = T::regs(); + let ehr_data_regs = [ + regs.ehr_data0(), + regs.ehr_data1(), + regs.ehr_data2(), + regs.ehr_data3(), + regs.ehr_data4(), + regs.ehr_data5(), + ]; + + for (i, reg) in ehr_data_regs.iter().enumerate() { + buffer[i * 4..i * 4 + 4].copy_from_slice(®.read().to_ne_bytes()); + } + } + + fn blocking_read_ehr_registers_into_array(&mut self, buffer: &mut [u8; TRNG_BLOCK_SIZE_BYTES]) { + self.blocking_wait_for_successful_generation(); + self.read_ehr_registers_into_array(buffer); + } + + /// Fill the buffer with random bytes, async version. + pub async fn fill_bytes(&mut self, destination: &mut [u8]) { + if destination.is_empty() { + return; // Nothing to fill + } + + self.start_rng(); + self.enable_irq(); + + let mut bytes_transferred = 0usize; + let mut buffer = [0u8; TRNG_BLOCK_SIZE_BYTES]; + + let regs = T::regs(); + + let trng_busy_register = regs.trng_busy(); + let trng_valid_register = regs.trng_valid(); + + let waker = T::waker(); + + let destination_length = destination.len(); + + poll_fn(|context| { + waker.register(context.waker()); + if bytes_transferred == destination_length { + self.stop_rng(); + self.disable_irq(); + Poll::Ready(()) + } else { + if trng_busy_register.read().trng_busy() { + Poll::Pending + } else { + if trng_valid_register.read().ehr_valid().not() { + panic!("RNG not busy, but ehr is not valid!") + } + self.read_ehr_registers_into_array(&mut buffer); + let remaining = destination_length - bytes_transferred; + if remaining > TRNG_BLOCK_SIZE_BYTES { + destination[bytes_transferred..bytes_transferred + TRNG_BLOCK_SIZE_BYTES] + .copy_from_slice(&buffer); + bytes_transferred += TRNG_BLOCK_SIZE_BYTES + } else { + destination[bytes_transferred..bytes_transferred + remaining] + .copy_from_slice(&buffer[0..remaining]); + bytes_transferred += remaining + } + if bytes_transferred == destination_length { + self.stop_rng(); + self.disable_irq(); + Poll::Ready(()) + } else { + Poll::Pending + } + } + } + }) + .await + } + + /// Fill the buffer with random bytes, blocking version. + pub fn blocking_fill_bytes(&mut self, destination: &mut [u8]) { + if destination.is_empty() { + return; // Nothing to fill + } + self.start_rng(); + + let mut buffer = [0u8; TRNG_BLOCK_SIZE_BYTES]; + + for chunk in destination.chunks_mut(TRNG_BLOCK_SIZE_BYTES) { + self.blocking_wait_for_successful_generation(); + self.blocking_read_ehr_registers_into_array(&mut buffer); + chunk.copy_from_slice(&buffer[..chunk.len()]) + } + self.stop_rng() + } + + /// Return a random u32, blocking. + pub fn blocking_next_u32(&mut self) -> u32 { + let regs = T::regs(); + self.start_rng(); + self.blocking_wait_for_successful_generation(); + // 12.12.3 After successful generation, read the last result register, EHR_DATA[5] to + // clear all of the result registers. + let result = regs.ehr_data5().read(); + self.stop_rng(); + result + } + + /// Return a random u64, blocking. + pub fn blocking_next_u64(&mut self) -> u64 { + let regs = T::regs(); + self.start_rng(); + self.blocking_wait_for_successful_generation(); + + let low = regs.ehr_data4().read() as u64; + // 12.12.3 After successful generation, read the last result register, EHR_DATA[5] to + // clear all of the result registers. + let result = (regs.ehr_data5().read() as u64) << 32 | low; + self.stop_rng(); + result + } +} + +impl<'d, T: Instance> rand_core::RngCore for Trng<'d, T> { + fn next_u32(&mut self) -> u32 { + self.blocking_next_u32() + } + + fn next_u64(&mut self) -> u64 { + self.blocking_next_u64() + } + + fn fill_bytes(&mut self, dest: &mut [u8]) { + self.blocking_fill_bytes(dest) + } + + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + self.blocking_fill_bytes(dest); + Ok(()) + } +} +/// TRNG interrupt handler. +pub struct InterruptHandler { + _trng: PhantomData, +} + +impl interrupt::typelevel::Handler for InterruptHandler { + unsafe fn on_interrupt() { + let regs = T::regs(); + let isr = regs.rng_isr().read(); + // Clear ehr bit + regs.rng_icr().write(|w| { + w.set_ehr_valid(true); + }); + if isr.ehr_valid() { + T::waker().wake(); + } else { + // 12.12.5. List of Registers + // ... + // TRNG: RNG_ISR Register + // ... + // AUTOCORR_ERR: 1 indicates Autocorrelation test failed four times in a row. + // When set, RNG ceases functioning until next reset + if isr.autocorr_err() { + warn!("TRNG Autocorrect error! Resetting TRNG"); + regs.trng_sw_reset().write(|w| { + w.set_trng_sw_reset(true); + }); + } + } + } +} diff --git a/examples/rp23/src/bin/trng.rs b/examples/rp23/src/bin/trng.rs new file mode 100644 index 000000000..e146baa2e --- /dev/null +++ b/examples/rp23/src/bin/trng.rs @@ -0,0 +1,64 @@ +//! This example shows TRNG usage + +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_rp::bind_interrupts; +use embassy_rp::block::ImageDef; +use embassy_rp::gpio::{Level, Output}; +use embassy_rp::peripherals::TRNG; +use embassy_rp::trng::Trng; +use embassy_time::Timer; +use rand::RngCore; +use {defmt_rtt as _, panic_probe as _}; + +#[link_section = ".start_block"] +#[used] +pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); + +// Program metadata for `picotool info` +#[link_section = ".bi_entries"] +#[used] +pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ + embassy_rp::binary_info::rp_program_name!(c"example"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Blinky"), + embassy_rp::binary_info::rp_program_build_attribute!(), +]; + +bind_interrupts!(struct Irqs { + TRNG_IRQ => embassy_rp::trng::InterruptHandler; +}); + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let peripherals = embassy_rp::init(Default::default()); + + // Initialize the TRNG with default configuration + let mut trng = Trng::new(peripherals.TRNG, Irqs, embassy_rp::trng::Config::default()); + // A buffer to collect random bytes in. + let mut randomness = [0u8; 58]; + + let mut led = Output::new(peripherals.PIN_25, Level::Low); + + loop { + trng.fill_bytes(&mut randomness).await; + info!("Random bytes async {}", &randomness); + trng.blocking_fill_bytes(&mut randomness); + info!("Random bytes blocking {}", &randomness); + let random_u32 = trng.next_u32(); + let random_u64 = trng.next_u64(); + info!("Random u32 {} u64 {}", random_u32, random_u64); + // Random number of blinks between 0 and 31 + let blinks = random_u32 % 32; + for _ in 0..blinks { + led.set_high(); + Timer::after_millis(20).await; + led.set_low(); + Timer::after_millis(20).await; + } + Timer::after_millis(1000).await; + } +} From a406a01459a5c759c044a181ba992fb2bc9e1150 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Wed, 18 Sep 2024 21:24:35 +0200 Subject: [PATCH 0143/1217] net-esp-hosted: remove useless fn init. --- embassy-net-esp-hosted/src/lib.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/embassy-net-esp-hosted/src/lib.rs b/embassy-net-esp-hosted/src/lib.rs index c78578bf1..f05e2a70a 100644 --- a/embassy-net-esp-hosted/src/lib.rs +++ b/embassy-net-esp-hosted/src/lib.rs @@ -137,7 +137,7 @@ where let (ch_runner, device) = ch::new(&mut state.ch, ch::driver::HardwareAddress::Ethernet([0; 6])); let state_ch = ch_runner.state_runner(); - let mut runner = Runner { + let runner = Runner { ch: ch_runner, state_ch, shared: &state.shared, @@ -148,7 +148,6 @@ where spi, heartbeat_deadline: Instant::now() + HEARTBEAT_MAX_GAP, }; - runner.init().await; (device, Control::new(state_ch, &state.shared), runner) } @@ -174,8 +173,6 @@ where IN: InputPin + Wait, OUT: OutputPin, { - async fn init(&mut self) {} - /// Run the packet processing. pub async fn run(mut self) -> ! { debug!("resetting..."); From 60f93b42e262dc30bf7bd3767b1912a92f9e0f43 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Wed, 18 Sep 2024 21:24:50 +0200 Subject: [PATCH 0144/1217] net-esp-hosted: set wpa3_supported=true. I've noticed wpa3 still works without this flag, so I'm not sure what this does tbh... --- embassy-net-esp-hosted/src/control.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-net-esp-hosted/src/control.rs b/embassy-net-esp-hosted/src/control.rs index c8cea8503..b1838a425 100644 --- a/embassy-net-esp-hosted/src/control.rs +++ b/embassy-net-esp-hosted/src/control.rs @@ -120,7 +120,7 @@ impl<'a> Control<'a> { pwd: unwrap!(String::try_from(password)), bssid: String::new(), listen_interval: 3, - is_wpa3_supported: false, + is_wpa3_supported: true, }; ioctl!(self, ReqConnectAp, RespConnectAp, req, resp); self.state_ch.set_link_state(LinkState::Up); From bee53af36a91d984558cd22dd96195537fd61fd6 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Wed, 18 Sep 2024 21:37:42 +0200 Subject: [PATCH 0145/1217] net: add all combinations of wait methods for link/config up/down. --- embassy-net/src/lib.rs | 40 ++++++++++++++++++++++++++++------------ 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/embassy-net/src/lib.rs b/embassy-net/src/lib.rs index ef53fb905..a7b7efa87 100644 --- a/embassy-net/src/lib.rs +++ b/embassy-net/src/lib.rs @@ -260,7 +260,10 @@ pub struct Stack<'d> { pub(crate) struct Inner { pub(crate) sockets: SocketSet<'static>, // Lifetime type-erased. pub(crate) iface: Interface, + /// Waker used for triggering polls. pub(crate) waker: WakerRegistration, + /// Waker used for waiting for link up or config up. + state_waker: WakerRegistration, hardware_address: HardwareAddress, next_local_port: u16, link_up: bool, @@ -270,7 +273,6 @@ pub(crate) struct Inner { static_v6: Option, #[cfg(feature = "dhcpv4")] dhcp_socket: Option, - config_waker: WakerRegistration, #[cfg(feature = "dns")] dns_socket: SocketHandle, #[cfg(feature = "dns")] @@ -326,6 +328,7 @@ pub fn new<'d, D: Driver, const SOCK: usize>( sockets, iface, waker: WakerRegistration::new(), + state_waker: WakerRegistration::new(), next_local_port, hardware_address, link_up: false, @@ -335,7 +338,6 @@ pub fn new<'d, D: Driver, const SOCK: usize>( static_v6: None, #[cfg(feature = "dhcpv4")] dhcp_socket: None, - config_waker: WakerRegistration::new(), #[cfg(feature = "dns")] dns_socket, #[cfg(feature = "dns")] @@ -421,10 +423,20 @@ impl<'d> Stack<'d> { v4_up || v6_up } + /// Wait for the network device to obtain a link signal. + pub async fn wait_link_up(&self) { + self.wait(|| self.is_link_up()).await + } + + /// Wait for the network device to lose link signal. + pub async fn wait_link_down(&self) { + self.wait(|| !self.is_link_up()).await + } + /// Wait for the network stack to obtain a valid IP configuration. /// /// ## Notes: - /// - Ensure [`Stack::run`] has been called before using this function. + /// - Ensure [`Runner::run`] has been started before using this function. /// /// - This function may never return (e.g. if no configuration is obtained through DHCP). /// The caller is supposed to handle a timeout for this case. @@ -451,13 +463,17 @@ impl<'d> Stack<'d> { /// // ... /// ``` pub async fn wait_config_up(&self) { - // If the config is up already, we can return immediately. - if self.is_config_up() { - return; - } + self.wait(|| self.is_config_up()).await + } - poll_fn(|cx| { - if self.is_config_up() { + /// Wait for the network stack to lose a valid IP configuration. + pub async fn wait_config_down(&self) { + self.wait(|| !self.is_config_up()).await + } + + fn wait<'a>(&'a self, mut predicate: impl FnMut() -> bool + 'a) -> impl Future + 'a { + poll_fn(move |cx| { + if predicate() { Poll::Ready(()) } else { // If the config is not up, we register a waker that is woken up @@ -465,13 +481,12 @@ impl<'d> Stack<'d> { trace!("Waiting for config up"); self.with_mut(|i| { - i.config_waker.register(cx.waker()); + i.state_waker.register(cx.waker()); }); Poll::Pending } }) - .await; } /// Get the current IPv4 configuration. @@ -775,7 +790,7 @@ impl Inner { .update_servers(&dns_servers[..count]); } - self.config_waker.wake(); + self.state_waker.wake(); } fn poll(&mut self, cx: &mut Context<'_>, driver: &mut D) { @@ -813,6 +828,7 @@ impl Inner { // Print when changed if old_link_up != self.link_up { info!("link_up = {:?}", self.link_up); + self.state_waker.wake(); } #[allow(unused_mut)] From b1897c58fa617dbab02b39e7f5e399ed1c9d54b4 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Wed, 18 Sep 2024 16:14:53 +0200 Subject: [PATCH 0146/1217] Add revert state in embassy-boot The revert state signals that a firmware revert has taken place, allowing the application to know if a firmware update attempt was reverted. --- embassy-boot/src/boot_loader.rs | 6 ++++-- embassy-boot/src/firmware_updater/asynch.rs | 3 ++- embassy-boot/src/firmware_updater/blocking.rs | 3 ++- embassy-boot/src/lib.rs | 6 ++++++ 4 files changed, 14 insertions(+), 4 deletions(-) diff --git a/embassy-boot/src/boot_loader.rs b/embassy-boot/src/boot_loader.rs index 61d61b96e..5bffdc5ea 100644 --- a/embassy-boot/src/boot_loader.rs +++ b/embassy-boot/src/boot_loader.rs @@ -5,7 +5,7 @@ use embassy_sync::blocking_mutex::raw::NoopRawMutex; use embassy_sync::blocking_mutex::Mutex; use embedded_storage::nor_flash::{NorFlash, NorFlashError, NorFlashErrorKind}; -use crate::{State, BOOT_MAGIC, DFU_DETACH_MAGIC, STATE_ERASE_VALUE, SWAP_MAGIC}; +use crate::{State, DFU_DETACH_MAGIC, REVERT_MAGIC, STATE_ERASE_VALUE, SWAP_MAGIC}; /// Errors returned by bootloader #[derive(PartialEq, Eq, Debug)] @@ -276,7 +276,7 @@ impl BootLoader BootLoader FirmwareState<'d, STATE> { // Make sure we are running a booted firmware to avoid reverting to a bad state. async fn verify_booted(&mut self) -> Result<(), FirmwareUpdaterError> { - if self.get_state().await? == State::Boot { + let state = self.get_state().await?; + if state == State::Boot || state == State::DfuDetach || state == State::Revert { Ok(()) } else { Err(FirmwareUpdaterError::BadState) diff --git a/embassy-boot/src/firmware_updater/blocking.rs b/embassy-boot/src/firmware_updater/blocking.rs index d3c723456..5f64b4be9 100644 --- a/embassy-boot/src/firmware_updater/blocking.rs +++ b/embassy-boot/src/firmware_updater/blocking.rs @@ -324,7 +324,8 @@ impl<'d, STATE: NorFlash> BlockingFirmwareState<'d, STATE> { // Make sure we are running a booted firmware to avoid reverting to a bad state. fn verify_booted(&mut self) -> Result<(), FirmwareUpdaterError> { - if self.get_state()? == State::Boot || self.get_state()? == State::DfuDetach { + let state = self.get_state()?; + if state == State::Boot || state == State::DfuDetach || state == State::Revert { Ok(()) } else { Err(FirmwareUpdaterError::BadState) diff --git a/embassy-boot/src/lib.rs b/embassy-boot/src/lib.rs index 8849055e8..7d5cc58f9 100644 --- a/embassy-boot/src/lib.rs +++ b/embassy-boot/src/lib.rs @@ -25,6 +25,7 @@ pub use firmware_updater::{ FirmwareUpdaterError, }; +pub(crate) const REVERT_MAGIC: u8 = 0xC0; pub(crate) const BOOT_MAGIC: u8 = 0xD0; pub(crate) const SWAP_MAGIC: u8 = 0xF0; pub(crate) const DFU_DETACH_MAGIC: u8 = 0xE0; @@ -37,6 +38,8 @@ pub enum State { Boot, /// Bootloader has swapped the active partition with the dfu partition and will attempt boot. Swap, + /// Bootloader has reverted the active partition with the dfu partition and will attempt boot. + Revert, /// Application has received a request to reboot into DFU mode to apply an update. DfuDetach, } @@ -157,6 +160,9 @@ mod tests { // Running again should cause a revert assert_eq!(State::Swap, bootloader.prepare_boot(&mut page).unwrap()); + // Next time we know it was reverted + assert_eq!(State::Revert, bootloader.prepare_boot(&mut page).unwrap()); + let mut read_buf = [0; FIRMWARE_SIZE]; flash.active().read(0, &mut read_buf).unwrap(); assert_eq!(ORIGINAL, read_buf); From ab0a227e4c02137bc3a621907d17ede0ace4cb1d Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Thu, 19 Sep 2024 09:15:08 +0200 Subject: [PATCH 0147/1217] Ensure bootloader state is parsed correctly --- embassy-boot/src/firmware_updater/asynch.rs | 7 +------ embassy-boot/src/firmware_updater/blocking.rs | 9 +-------- embassy-boot/src/lib.rs | 18 ++++++++++++++++++ 3 files changed, 20 insertions(+), 14 deletions(-) diff --git a/embassy-boot/src/firmware_updater/asynch.rs b/embassy-boot/src/firmware_updater/asynch.rs index b23857e2f..d9d15b004 100644 --- a/embassy-boot/src/firmware_updater/asynch.rs +++ b/embassy-boot/src/firmware_updater/asynch.rs @@ -304,12 +304,7 @@ impl<'d, STATE: NorFlash> FirmwareState<'d, STATE> { /// `mark_booted`. pub async fn get_state(&mut self) -> Result { self.state.read(0, &mut self.aligned).await?; - - if !self.aligned.iter().any(|&b| b != SWAP_MAGIC) { - Ok(State::Swap) - } else { - Ok(State::Boot) - } + Ok(State::from(&self.aligned)) } /// Mark to trigger firmware swap on next boot. diff --git a/embassy-boot/src/firmware_updater/blocking.rs b/embassy-boot/src/firmware_updater/blocking.rs index 5f64b4be9..08062b0d0 100644 --- a/embassy-boot/src/firmware_updater/blocking.rs +++ b/embassy-boot/src/firmware_updater/blocking.rs @@ -339,14 +339,7 @@ impl<'d, STATE: NorFlash> BlockingFirmwareState<'d, STATE> { /// `mark_booted`. pub fn get_state(&mut self) -> Result { self.state.read(0, &mut self.aligned)?; - - if !self.aligned.iter().any(|&b| b != SWAP_MAGIC) { - Ok(State::Swap) - } else if !self.aligned.iter().any(|&b| b != DFU_DETACH_MAGIC) { - Ok(State::DfuDetach) - } else { - Ok(State::Boot) - } + Ok(State::from(&self.aligned)) } /// Mark to trigger firmware swap on next boot. diff --git a/embassy-boot/src/lib.rs b/embassy-boot/src/lib.rs index 7d5cc58f9..e2c4cf771 100644 --- a/embassy-boot/src/lib.rs +++ b/embassy-boot/src/lib.rs @@ -44,6 +44,24 @@ pub enum State { DfuDetach, } +impl From for State +where + T: AsRef<[u8]>, +{ + fn from(magic: T) -> State { + let magic = magic.as_ref(); + if !magic.iter().any(|&b| b != SWAP_MAGIC) { + State::Swap + } else if !magic.iter().any(|&b| b != REVERT_MAGIC) { + State::Revert + } else if !magic.iter().any(|&b| b != DFU_DETACH_MAGIC) { + State::DfuDetach + } else { + State::Boot + } + } +} + /// Buffer aligned to 32 byte boundary, largest known alignment requirement for embassy-boot. #[repr(align(32))] pub struct AlignedBuffer(pub [u8; N]); From df23a77bfc3c8b5d8ab6adbd12842fa4cfe3675d Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Thu, 19 Sep 2024 09:15:35 +0200 Subject: [PATCH 0148/1217] Add led to example to demonstrate revert state detection --- examples/boot/application/nrf/src/bin/a.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/examples/boot/application/nrf/src/bin/a.rs b/examples/boot/application/nrf/src/bin/a.rs index 851a3d721..60cf3cd1a 100644 --- a/examples/boot/application/nrf/src/bin/a.rs +++ b/examples/boot/application/nrf/src/bin/a.rs @@ -8,6 +8,7 @@ use embassy_executor::Spawner; use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pull}; use embassy_nrf::nvmc::Nvmc; use embassy_nrf::wdt::{self, Watchdog}; +use embassy_boot::State; use embassy_sync::mutex::Mutex; use panic_reset as _; @@ -22,6 +23,7 @@ async fn main(_spawner: Spawner) { let mut button = Input::new(p.P0_11, Pull::Up); let mut led = Output::new(p.P0_13, Level::Low, OutputDrive::Standard); + let mut led_reverted = Output::new(p.P0_14, Level::High, OutputDrive::Standard); //let mut led = Output::new(p.P1_10, Level::Low, OutputDrive::Standard); //let mut button = Input::new(p.P1_02, Pull::Up); @@ -53,6 +55,13 @@ async fn main(_spawner: Spawner) { let config = FirmwareUpdaterConfig::from_linkerfile(&nvmc, &nvmc); let mut magic = [0; 4]; let mut updater = FirmwareUpdater::new(config, &mut magic); + let state = updater.get_state().await.unwrap(); + if state == State::Revert { + led_reverted.set_low(); + } else { + led_reverted.set_high(); + } + loop { led.set_low(); button.wait_for_any_edge().await; From 4e1efd93fd4dc8dd692daf419d901ae22413e091 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Thu, 19 Sep 2024 09:15:55 +0200 Subject: [PATCH 0149/1217] Fix defmt support for example boot app --- examples/boot/application/nrf/build.rs | 3 +++ examples/boot/application/nrf/src/bin/a.rs | 4 +++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/examples/boot/application/nrf/build.rs b/examples/boot/application/nrf/build.rs index cd1a264c4..e1da69328 100644 --- a/examples/boot/application/nrf/build.rs +++ b/examples/boot/application/nrf/build.rs @@ -31,4 +31,7 @@ fn main() { println!("cargo:rustc-link-arg-bins=--nmagic"); println!("cargo:rustc-link-arg-bins=-Tlink.x"); + if env::var("CARGO_FEATURE_DEFMT").is_ok() { + println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); + } } diff --git a/examples/boot/application/nrf/src/bin/a.rs b/examples/boot/application/nrf/src/bin/a.rs index 60cf3cd1a..2c1d1a7bb 100644 --- a/examples/boot/application/nrf/src/bin/a.rs +++ b/examples/boot/application/nrf/src/bin/a.rs @@ -2,13 +2,15 @@ #![no_main] #![macro_use] +#[cfg(feature = "defmt")] +use defmt_rtt as _; +use embassy_boot::State; use embassy_boot_nrf::{FirmwareUpdater, FirmwareUpdaterConfig}; use embassy_embedded_hal::adapter::BlockingAsync; use embassy_executor::Spawner; use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pull}; use embassy_nrf::nvmc::Nvmc; use embassy_nrf::wdt::{self, Watchdog}; -use embassy_boot::State; use embassy_sync::mutex::Mutex; use panic_reset as _; From 893b8d79e8bab8dae0f46a0182443df9160592b5 Mon Sep 17 00:00:00 2001 From: Nathan Perry Date: Thu, 19 Sep 2024 08:17:33 -0400 Subject: [PATCH 0150/1217] embassy_sync/pubsub: fix PubSubBehavior visibility https://github.com/embassy-rs/embassy/pull/2969 appears to have broken direct `publish_immediate()` on `pubsub::Channel`, as it functionally made `PubSubBehavior` private and didn't delegate this method to the new (private) `SealedPubSubBehavior`. This change moves `publish_immediate`, `capacity`, and `is_full` from `SealedPubSubBehavior` to `PubSubBehavior` in order to restore them to `pub` visibility. --- embassy-sync/src/pubsub/mod.rs | 56 +++++++++++++++++----------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/embassy-sync/src/pubsub/mod.rs b/embassy-sync/src/pubsub/mod.rs index a97eb7d5b..812302e2b 100644 --- a/embassy-sync/src/pubsub/mod.rs +++ b/embassy-sync/src/pubsub/mod.rs @@ -194,6 +194,25 @@ impl crate::pubsub::PubSubBehavior + for PubSubChannel +{ + fn publish_immediate(&self, message: T) { + self.inner.lock(|s| { + let mut s = s.borrow_mut(); + s.publish_immediate(message) + }) + } + + fn capacity(&self) -> usize { + self.capacity() + } + + fn is_full(&self) -> bool { + self.is_full() + } +} + impl SealedPubSubBehavior for PubSubChannel { @@ -246,13 +265,6 @@ impl usize { - self.capacity() - } - fn free_capacity(&self) -> usize { self.free_capacity() } @@ -286,10 +294,6 @@ impl bool { self.is_empty() } - - fn is_full(&self) -> bool { - self.is_full() - } } /// Internal state for the PubSub channel @@ -445,8 +449,6 @@ pub enum Error { MaximumPublishersReached, } -/// 'Middle level' behaviour of the pubsub channel. -/// This trait is used so that Sub and Pub can be generic over the channel. trait SealedPubSubBehavior { /// Try to get a message from the queue with the given message id. /// @@ -462,12 +464,6 @@ trait SealedPubSubBehavior { /// If the queue is full and a context is given, then its waker is registered in the publisher wakers. fn publish_with_context(&self, message: T, cx: Option<&mut Context<'_>>) -> Result<(), T>; - /// Publish a message immediately - fn publish_immediate(&self, message: T); - - /// Returns the maximum number of elements the channel can hold. - fn capacity(&self) -> usize; - /// Returns the free capacity of the channel. /// /// This is equivalent to `capacity() - len()` @@ -482,9 +478,6 @@ trait SealedPubSubBehavior { /// Returns whether the channel is empty. fn is_empty(&self) -> bool; - /// Returns whether the channel is full. - fn is_full(&self) -> bool; - /// Let the channel know that a subscriber has dropped fn unregister_subscriber(&self, subscriber_next_message_id: u64); @@ -495,9 +488,16 @@ trait SealedPubSubBehavior { /// 'Middle level' behaviour of the pubsub channel. /// This trait is used so that Sub and Pub can be generic over the channel. #[allow(private_bounds)] -pub trait PubSubBehavior: SealedPubSubBehavior {} +pub trait PubSubBehavior: SealedPubSubBehavior { + /// Publish a message immediately + fn publish_immediate(&self, message: T); -impl> PubSubBehavior for C {} + /// Returns the maximum number of elements the channel can hold. + fn capacity(&self) -> usize; + + /// Returns whether the channel is full. + fn is_full(&self) -> bool; +} /// The result of the subscriber wait procedure #[derive(Debug, Clone, PartialEq, Eq)] From 907d55ea82ac09b507afdc7ccb4d5997f827a748 Mon Sep 17 00:00:00 2001 From: Peter Krull Date: Thu, 19 Sep 2024 18:14:09 +0200 Subject: [PATCH 0151/1217] stm32: Added request_pause to DMA, and use it for RingBufferedUartRx --- embassy-stm32/src/dma/dma_bdma.rs | 54 ++++++++++++++++++++++++- embassy-stm32/src/usart/ringbuffered.rs | 2 +- 2 files changed, 53 insertions(+), 3 deletions(-) diff --git a/embassy-stm32/src/dma/dma_bdma.rs b/embassy-stm32/src/dma/dma_bdma.rs index df041c4e9..2887536c3 100644 --- a/embassy-stm32/src/dma/dma_bdma.rs +++ b/embassy-stm32/src/dma/dma_bdma.rs @@ -493,6 +493,26 @@ impl AnyChannel { } } + fn request_pause(&self) { + let info = self.info(); + match self.info().dma { + #[cfg(dma)] + DmaInfo::Dma(r) => { + r.st(info.num).cr().modify(|w| { + // Disable the channel without overwriting the existing configuration + w.set_en(false); + }); + } + #[cfg(bdma)] + DmaInfo::Bdma(r) => { + r.ch(info.num).cr().modify(|w| { + // Disable the channel without overwriting the existing configuration + w.set_en(false); + }); + } + } + } + fn is_running(&self) -> bool { let info = self.info(); match self.info().dma { @@ -667,12 +687,22 @@ impl<'a> Transfer<'a> { } /// Request the transfer to stop. + /// The configuration for this channel will **not be preserved**. If you need to restart the transfer + /// at a later point with the same configuration, see [`request_pause`](Self::request_pause) instead. /// /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false. pub fn request_stop(&mut self) { self.channel.request_stop() } + /// Request the transfer to pause, keeping the existing configuration for this channel. + /// To restart the transfer, call [`start`](Self::start) again. + /// + /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false. + pub fn request_pause(&mut self) { + self.channel.request_pause() + } + /// Return whether this transfer is still running. /// /// If this returns `false`, it can be because either the transfer finished, or @@ -846,13 +876,23 @@ impl<'a, W: Word> ReadableRingBuffer<'a, W> { DmaCtrlImpl(self.channel.reborrow()).set_waker(waker); } - /// Request DMA to stop. + /// Request the DMA to stop. + /// The configuration for this channel will **not be preserved**. If you need to restart the transfer + /// at a later point with the same configuration, see [`request_pause`](Self::request_pause) instead. /// /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false. pub fn request_stop(&mut self) { self.channel.request_stop() } + /// Request the transfer to pause, keeping the existing configuration for this channel. + /// To restart the transfer, call [`start`](Self::start) again. + /// + /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false. + pub fn request_pause(&mut self) { + self.channel.request_pause() + } + /// Return whether DMA is still running. /// /// If this returns `false`, it can be because either the transfer finished, or @@ -977,13 +1017,23 @@ impl<'a, W: Word> WritableRingBuffer<'a, W> { DmaCtrlImpl(self.channel.reborrow()).set_waker(waker); } - /// Request DMA to stop. + /// Request the DMA to stop. + /// The configuration for this channel will **not be preserved**. If you need to restart the transfer + /// at a later point with the same configuration, see [`request_pause`](Self::request_pause) instead. /// /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false. pub fn request_stop(&mut self) { self.channel.request_stop() } + /// Request the transfer to pause, keeping the existing configuration for this channel. + /// To restart the transfer, call [`start`](Self::start) again. + /// + /// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false. + pub fn request_pause(&mut self) { + self.channel.request_pause() + } + /// Return whether DMA is still running. /// /// If this returns `false`, it can be because either the transfer finished, or diff --git a/embassy-stm32/src/usart/ringbuffered.rs b/embassy-stm32/src/usart/ringbuffered.rs index b0652046c..bb95af966 100644 --- a/embassy-stm32/src/usart/ringbuffered.rs +++ b/embassy-stm32/src/usart/ringbuffered.rs @@ -120,7 +120,7 @@ impl<'d> RingBufferedUartRx<'d> { /// Stop uart background receive fn teardown_uart(&mut self) { - self.ring_buf.request_stop(); + self.ring_buf.request_pause(); let r = self.info.regs; // clear all interrupts and DMA Rx Request From 2a9cdaabaa315795722886f94fa553e8f3e3c14d Mon Sep 17 00:00:00 2001 From: Peter Krull Date: Thu, 19 Sep 2024 18:25:08 +0200 Subject: [PATCH 0152/1217] stm32: Moved comment to match request_stop --- embassy-stm32/src/dma/dma_bdma.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/dma/dma_bdma.rs b/embassy-stm32/src/dma/dma_bdma.rs index 2887536c3..d10b5554f 100644 --- a/embassy-stm32/src/dma/dma_bdma.rs +++ b/embassy-stm32/src/dma/dma_bdma.rs @@ -498,15 +498,15 @@ impl AnyChannel { match self.info().dma { #[cfg(dma)] DmaInfo::Dma(r) => { + // Disable the channel without overwriting the existing configuration r.st(info.num).cr().modify(|w| { - // Disable the channel without overwriting the existing configuration w.set_en(false); }); } #[cfg(bdma)] DmaInfo::Bdma(r) => { + // Disable the channel without overwriting the existing configuration r.ch(info.num).cr().modify(|w| { - // Disable the channel without overwriting the existing configuration w.set_en(false); }); } From 4fcc8e39d6b3e486d2b94aa45d255d9c645d028a Mon Sep 17 00:00:00 2001 From: Peter Krull Date: Thu, 19 Sep 2024 19:21:34 +0200 Subject: [PATCH 0153/1217] stm32: Only check errors on running RingBufferedUartRx, reduce number of small one-time functions --- embassy-stm32/src/usart/ringbuffered.rs | 49 ++++++++++--------------- 1 file changed, 19 insertions(+), 30 deletions(-) diff --git a/embassy-stm32/src/usart/ringbuffered.rs b/embassy-stm32/src/usart/ringbuffered.rs index bb95af966..2d9c63820 100644 --- a/embassy-stm32/src/usart/ringbuffered.rs +++ b/embassy-stm32/src/usart/ringbuffered.rs @@ -71,33 +71,18 @@ impl<'d> UartRx<'d, Async> { } impl<'d> RingBufferedUartRx<'d> { - /// Clear the ring buffer and start receiving in the background - pub fn start(&mut self) -> Result<(), Error> { - // Clear the ring buffer so that it is ready to receive data - self.ring_buf.clear(); - - self.setup_uart(); - - Ok(()) - } - - fn stop(&mut self, err: Error) -> Result { - self.teardown_uart(); - - Err(err) - } - /// Reconfigure the driver pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { reconfigure(self.info, self.kernel_clock, config) } - /// Start uart background receive - fn setup_uart(&mut self) { - // fence before starting DMA. + /// Configure and start the DMA backed UART receiver + /// + /// Note: This is also done automatically by [`read()`] if required. + pub fn start_uart(&mut self) { + // Clear the buffer so that it is ready to receive data + self.ring_buf.clear(); compiler_fence(Ordering::SeqCst); - - // start the dma controller self.ring_buf.start(); let r = self.info.regs; @@ -118,8 +103,8 @@ impl<'d> RingBufferedUartRx<'d> { }); } - /// Stop uart background receive - fn teardown_uart(&mut self) { + /// Stop DMA backed UART receiver + fn stop_uart(&mut self) { self.ring_buf.request_pause(); let r = self.info.regs; @@ -153,13 +138,15 @@ impl<'d> RingBufferedUartRx<'d> { pub async fn read(&mut self, buf: &mut [u8]) -> Result { let r = self.info.regs; - // Start background receive if it was not already started + // Start DMA and Uart if it was not already started, + // otherwise check for errors in status register. + let sr = clear_idle_flag(r); if !r.cr3().read().dmar() { - self.start()?; + self.start_uart(); + } else { + check_for_errors(sr)?; } - check_for_errors(clear_idle_flag(r))?; - loop { match self.ring_buf.read(buf) { Ok((0, _)) => {} @@ -167,14 +154,16 @@ impl<'d> RingBufferedUartRx<'d> { return Ok(len); } Err(_) => { - return self.stop(Error::Overrun); + self.stop_uart(); + return Err(Error::Overrun); } } match self.wait_for_data_or_idle().await { Ok(_) => {} Err(err) => { - return self.stop(err); + self.stop_uart(); + return Err(err); } } } @@ -228,7 +217,7 @@ impl<'d> RingBufferedUartRx<'d> { impl Drop for RingBufferedUartRx<'_> { fn drop(&mut self) { - self.teardown_uart(); + self.stop_uart(); self.rx.as_ref().map(|x| x.set_as_disconnected()); self.rts.as_ref().map(|x| x.set_as_disconnected()); super::drop_tx_rx(self.info, self.state); From 3aeeeb0d784d843b521b4b8b222114ef7ba71363 Mon Sep 17 00:00:00 2001 From: Peter Krull Date: Thu, 19 Sep 2024 20:07:08 +0200 Subject: [PATCH 0154/1217] stm32: Start DMA before clearing, avoid panic in updater ringbuffer impl --- embassy-stm32/src/usart/ringbuffered.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/src/usart/ringbuffered.rs b/embassy-stm32/src/usart/ringbuffered.rs index 2d9c63820..75834bf37 100644 --- a/embassy-stm32/src/usart/ringbuffered.rs +++ b/embassy-stm32/src/usart/ringbuffered.rs @@ -81,9 +81,9 @@ impl<'d> RingBufferedUartRx<'d> { /// Note: This is also done automatically by [`read()`] if required. pub fn start_uart(&mut self) { // Clear the buffer so that it is ready to receive data - self.ring_buf.clear(); compiler_fence(Ordering::SeqCst); self.ring_buf.start(); + self.ring_buf.clear(); let r = self.info.regs; // clear all interrupts and DMA Rx Request From 89bad07e817dec482d385f765da5be3b6d2d0e4c Mon Sep 17 00:00:00 2001 From: Nathan Perry Date: Fri, 20 Sep 2024 01:52:59 -0400 Subject: [PATCH 0155/1217] embassy_sync: `Sink` adapter for `pubsub::Pub` Corresponding to the `Stream` impl for `pubsub::Sub`. Notable difference is that we need a separate adapter type to store the pending item, i.e. we can't `impl Sink for Pub` directly. Instead a method `Pub::sink(&self)` is exposed, which constructs a `PubSink`. --- embassy-sync/Cargo.toml | 3 +- embassy-sync/src/pubsub/mod.rs | 26 +++++++++++ embassy-sync/src/pubsub/publisher.rs | 67 ++++++++++++++++++++++++++++ 3 files changed, 95 insertions(+), 1 deletion(-) diff --git a/embassy-sync/Cargo.toml b/embassy-sync/Cargo.toml index 7b7d2bf8e..2f049b6bc 100644 --- a/embassy-sync/Cargo.toml +++ b/embassy-sync/Cargo.toml @@ -27,6 +27,7 @@ turbowakers = [] defmt = { version = "0.3", optional = true } log = { version = "0.4.14", optional = true } +futures-sink = { version = "0.3", default-features = false, features = [] } futures-util = { version = "0.3.17", default-features = false } critical-section = "1.1" heapless = "0.8" @@ -37,7 +38,7 @@ embedded-io-async = { version = "0.6.1" } futures-executor = { version = "0.3.17", features = [ "thread-pool" ] } futures-test = "0.3.17" futures-timer = "3.0.2" -futures-util = { version = "0.3.17", features = [ "channel" ] } +futures-util = { version = "0.3.17", features = [ "channel", "sink" ] } # Enable critical-section implementation for std, for tests critical-section = { version = "1.1", features = ["std"] } diff --git a/embassy-sync/src/pubsub/mod.rs b/embassy-sync/src/pubsub/mod.rs index 812302e2b..1c0f68bd0 100644 --- a/embassy-sync/src/pubsub/mod.rs +++ b/embassy-sync/src/pubsub/mod.rs @@ -755,4 +755,30 @@ mod tests { assert_eq!(1, sub0.try_next_message_pure().unwrap().0); assert_eq!(0, sub1.try_next_message_pure().unwrap().0); } + + #[futures_test::test] + async fn publisher_sink() { + use futures_util::{SinkExt, StreamExt}; + + let channel = PubSubChannel::::new(); + + let mut sub = channel.subscriber().unwrap(); + + let publ = channel.publisher().unwrap(); + let mut sink = publ.sink(); + + sink.send(0).await.unwrap(); + assert_eq!(0, sub.try_next_message_pure().unwrap()); + + sink.send(1).await.unwrap(); + assert_eq!(1, sub.try_next_message_pure().unwrap()); + + sink.send_all(&mut futures_util::stream::iter(0..4).map(Ok)) + .await + .unwrap(); + assert_eq!(0, sub.try_next_message_pure().unwrap()); + assert_eq!(1, sub.try_next_message_pure().unwrap()); + assert_eq!(2, sub.try_next_message_pure().unwrap()); + assert_eq!(3, sub.try_next_message_pure().unwrap()); + } } diff --git a/embassy-sync/src/pubsub/publisher.rs b/embassy-sync/src/pubsub/publisher.rs index e66b3b1db..7a1ab66de 100644 --- a/embassy-sync/src/pubsub/publisher.rs +++ b/embassy-sync/src/pubsub/publisher.rs @@ -74,6 +74,12 @@ impl<'a, PSB: PubSubBehavior + ?Sized, T: Clone> Pub<'a, PSB, T> { pub fn is_full(&self) -> bool { self.channel.is_full() } + + /// Create a [`futures::Sink`] adapter for this publisher. + #[inline] + pub const fn sink(&self) -> PubSink<'a, '_, PSB, T> { + PubSink { publ: self, fut: None } + } } impl<'a, PSB: PubSubBehavior + ?Sized, T: Clone> Drop for Pub<'a, PSB, T> { @@ -221,6 +227,67 @@ impl<'a, M: RawMutex, T: Clone, const CAP: usize, const SUBS: usize, const PUBS: } } +#[must_use = "Sinks do nothing unless polled"] +/// [`futures_sink::Sink`] adapter for [`Pub`]. +pub struct PubSink<'a, 'p, PSB, T> +where + T: Clone, + PSB: PubSubBehavior + ?Sized, +{ + publ: &'p Pub<'a, PSB, T>, + fut: Option>, +} + +impl<'a, 'p, PSB, T> PubSink<'a, 'p, PSB, T> +where + PSB: PubSubBehavior + ?Sized, + T: Clone, +{ + /// Try to make progress on the pending future if we have one. + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> { + let Some(mut fut) = self.fut.take() else { + return Poll::Ready(()); + }; + + if Pin::new(&mut fut).poll(cx).is_pending() { + self.fut = Some(fut); + return Poll::Pending; + } + + Poll::Ready(()) + } +} + +impl<'a, 'p, PSB, T> futures_sink::Sink for PubSink<'a, 'p, PSB, T> +where + PSB: PubSubBehavior + ?Sized, + T: Clone, +{ + type Error = core::convert::Infallible; + + #[inline] + fn poll_ready(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + self.poll(cx).map(Ok) + } + + #[inline] + fn start_send(mut self: Pin<&mut Self>, item: T) -> Result<(), Self::Error> { + self.fut = Some(self.publ.publish(item)); + + Ok(()) + } + + #[inline] + fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + self.poll(cx).map(Ok) + } + + #[inline] + fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + self.poll(cx).map(Ok) + } +} + /// Future for the publisher wait action #[must_use = "futures do nothing unless you `.await` or poll them"] pub struct PublisherWaitFuture<'s, 'a, PSB: PubSubBehavior + ?Sized, T: Clone> { From 5ea934d4ba6f0bc0e5e47b16f17dd8e881b528a3 Mon Sep 17 00:00:00 2001 From: Gerhard de Clercq Date: Fri, 20 Sep 2024 09:57:31 +0200 Subject: [PATCH 0156/1217] embassy_stm32/eth: support compliance testing This change adds the possibility to perform compliance testing with STM32 systems by directly exposing SMI when needed. Users can then use this to configure PHY registers for test modes. --- embassy-stm32/src/eth/mod.rs | 14 ++++ .../stm32f4/src/bin/eth_compliance_test.rs | 77 +++++++++++++++++++ 2 files changed, 91 insertions(+) create mode 100644 examples/stm32f4/src/bin/eth_compliance_test.rs diff --git a/embassy-stm32/src/eth/mod.rs b/embassy-stm32/src/eth/mod.rs index bfe8a60d6..6442176da 100644 --- a/embassy-stm32/src/eth/mod.rs +++ b/embassy-stm32/src/eth/mod.rs @@ -177,6 +177,20 @@ pub unsafe trait PHY { fn poll_link(&mut self, sm: &mut S, cx: &mut Context) -> bool; } +impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> { + /// Directly expose the SMI interface used by the Ethernet driver. + /// + /// This can be used to for example configure special PHY registers for compliance testing. + /// + /// # Safety + /// + /// Revert any temporary PHY register changes such as to enable test modes before handing + /// the Ethernet device over to the networking stack otherwise things likely won't work. + pub unsafe fn station_management(&mut self) -> &mut impl StationManagement { + &mut self.station_management + } +} + trait SealedInstance { fn regs() -> crate::pac::eth::Eth; } diff --git a/examples/stm32f4/src/bin/eth_compliance_test.rs b/examples/stm32f4/src/bin/eth_compliance_test.rs new file mode 100644 index 000000000..5946fed79 --- /dev/null +++ b/examples/stm32f4/src/bin/eth_compliance_test.rs @@ -0,0 +1,77 @@ +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::eth::generic_smi::GenericSMI; +use embassy_stm32::eth::{Ethernet, PacketQueue, StationManagement}; +use embassy_stm32::time::Hertz; +use embassy_stm32::{bind_interrupts, eth, peripherals, rng, Config}; +use embassy_time::Timer; +use static_cell::StaticCell; +use {defmt_rtt as _, panic_probe as _}; + +bind_interrupts!(struct Irqs { + ETH => eth::InterruptHandler; + HASH_RNG => rng::InterruptHandler; +}); + +#[embassy_executor::main] +async fn main(_spawner: Spawner) -> ! { + let mut config = Config::default(); + { + use embassy_stm32::rcc::*; + config.rcc.hse = Some(Hse { + freq: Hertz(8_000_000), + mode: HseMode::Bypass, + }); + config.rcc.pll_src = PllSource::HSE; + config.rcc.pll = Some(Pll { + prediv: PllPreDiv::DIV4, + mul: PllMul::MUL180, + divp: Some(PllPDiv::DIV2), // 8mhz / 4 * 180 / 2 = 180Mhz. + divq: None, + divr: None, + }); + config.rcc.ahb_pre = AHBPrescaler::DIV1; + config.rcc.apb1_pre = APBPrescaler::DIV4; + config.rcc.apb2_pre = APBPrescaler::DIV2; + config.rcc.sys = Sysclk::PLL1_P; + } + let p = embassy_stm32::init(config); + + info!("Hello Compliance World!"); + + let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF]; + + const PHY_ADDR: u8 = 0; + static PACKETS: StaticCell> = StaticCell::new(); + let mut device = Ethernet::new( + PACKETS.init(PacketQueue::<4, 4>::new()), + p.ETH, + Irqs, + p.PA1, + p.PA2, + p.PC1, + p.PA7, + p.PC4, + p.PC5, + p.PG13, + p.PB13, + p.PG11, + GenericSMI::new(PHY_ADDR), + mac_addr, + ); + + let sm = unsafe { device.station_management() }; + + // Just an example. Exact register settings depend on the specific PHY and test. + sm.smi_write(PHY_ADDR, 0, 0x2100); + sm.smi_write(PHY_ADDR, 11, 0xA000); + + // NB: Remember to reset the PHY after testing before starting the networking stack + + loop { + Timer::after_secs(1).await; + } +} From 3328c5d6567bb5b1df7ca26d818a91e0740e56c1 Mon Sep 17 00:00:00 2001 From: Reed Date: Sat, 21 Sep 2024 12:31:38 +1200 Subject: [PATCH 0157/1217] Correctly gate `time` feature of embassy-embedded-hal in embassy-stm32 --- embassy-stm32/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 3c6484c96..3f4a5e3c4 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -47,7 +47,7 @@ embassy-time = { version = "0.3.2", path = "../embassy-time", optional = true } embassy-time-driver = { version = "0.1", path = "../embassy-time-driver", optional = true } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } embassy-hal-internal = {version = "0.2.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-4"] } -embassy-embedded-hal = {version = "0.2.0", path = "../embassy-embedded-hal" } +embassy-embedded-hal = {version = "0.2.0", path = "../embassy-embedded-hal", default-features = false } embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver" } embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver" } embassy-usb-synopsys-otg = {version = "0.1.0", path = "../embassy-usb-synopsys-otg" } @@ -129,7 +129,7 @@ unstable-pac = [] #! ## Time ## Enables additional driver features that depend on embassy-time -time = ["dep:embassy-time"] +time = ["dep:embassy-time", "embassy-embedded-hal/time"] # Features starting with `_` are for internal use only. They're not intended # to be enabled by other crates, and are not covered by semver guarantees. From f2646b29a6b0a741fc424f88c5ca3dc25fce9369 Mon Sep 17 00:00:00 2001 From: Grant Miller Date: Sat, 21 Sep 2024 07:52:54 -0500 Subject: [PATCH 0158/1217] Make clone_unchecked work --- embassy-stm32/src/timer/low_level.rs | 4 +--- embassy-stm32/src/timer/mod.rs | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/embassy-stm32/src/timer/low_level.rs b/embassy-stm32/src/timer/low_level.rs index 6377054c5..3136ea4e9 100644 --- a/embassy-stm32/src/timer/low_level.rs +++ b/embassy-stm32/src/timer/low_level.rs @@ -201,9 +201,7 @@ impl<'d, T: CoreInstance> Timer<'d, T> { } pub(crate) unsafe fn clone_unchecked(&self) -> ManuallyDrop { - // this doesn't work for some reason - // let tim = unsafe { self.tim.clone_unchecked() }; - let tim = todo!(); + let tim = unsafe { self.tim.clone_unchecked() }; ManuallyDrop::new(Self { tim }) } diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs index 6cf22689b..aa9dd91d9 100644 --- a/embassy-stm32/src/timer/mod.rs +++ b/embassy-stm32/src/timer/mod.rs @@ -67,7 +67,7 @@ impl State { } } -trait SealedInstance: RccPeripheral { +trait SealedInstance: RccPeripheral + Peripheral

{ /// Async state for this timer fn state() -> &'static State; } From 2f60d78ea318f51ff59868c348b77cf880012198 Mon Sep 17 00:00:00 2001 From: Kevin Date: Sun, 15 Sep 2024 02:44:16 +0200 Subject: [PATCH 0159/1217] Add OTG_HS support for STM32H7R/S --- embassy-stm32/Cargo.toml | 6 +- embassy-stm32/src/rcc/h.rs | 4 +- embassy-stm32/src/usb/mod.rs | 20 +++ embassy-stm32/src/usb/otg.rs | 53 +++++++ embassy-usb-synopsys-otg/src/lib.rs | 16 +++ embassy-usb-synopsys-otg/src/otg_v1.rs | 171 +++++++++++++++++++++++ examples/stm32h7rs/src/bin/usb_serial.rs | 139 ++++++++++++++++++ 7 files changed, 405 insertions(+), 4 deletions(-) create mode 100644 examples/stm32h7rs/src/bin/usb_serial.rs diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 3f4a5e3c4..2f7f373af 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -72,7 +72,8 @@ rand_core = "0.6.3" sdio-host = "0.5.0" critical-section = "1.1" #stm32-metapac = { version = "15" } -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-ad00827345b4b758b2453082809d6e3b634b5364" } +# stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-ad00827345b4b758b2453082809d6e3b634b5364" } +stm32-metapac = { path = "../../stm32-data/build/stm32-metapac" } vcell = "0.1.3" nb = "1.0.0" @@ -99,7 +100,8 @@ proc-macro2 = "1.0.36" quote = "1.0.15" #stm32-metapac = { version = "15", default-features = false, features = ["metadata"]} -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-ad00827345b4b758b2453082809d6e3b634b5364", default-features = false, features = ["metadata"] } +# stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-ad00827345b4b758b2453082809d6e3b634b5364", default-features = false, features = ["metadata"] } +stm32-metapac = { path = "../../stm32-data/build/stm32-metapac", default-features = false, features = ["metadata"] } [features] default = ["rt"] diff --git a/embassy-stm32/src/rcc/h.rs b/embassy-stm32/src/rcc/h.rs index 376a0b454..27fc2b8d7 100644 --- a/embassy-stm32/src/rcc/h.rs +++ b/embassy-stm32/src/rcc/h.rs @@ -698,7 +698,7 @@ pub(crate) unsafe fn init(config: Config) { #[cfg(stm32h7rs)] clk48mohci: None, // TODO #[cfg(stm32h7rs)] - usb: None, // TODO + usb: Some(Hertz(48_000_000)), ); } @@ -769,7 +769,7 @@ fn init_pll(num: usize, config: Option, input: &PllInput) -> PllOutput { if num == 0 { // on PLL1, DIVP must be even for most series. // The enum value is 1 less than the divider, so check it's odd. - #[cfg(not(pwr_h7rm0468))] + #[cfg(not(any(pwr_h7rm0468, stm32h7rs)))] assert!(div.to_bits() % 2 == 1); #[cfg(pwr_h7rm0468)] assert!(div.to_bits() % 2 == 1 || div.to_bits() == 0); diff --git a/embassy-stm32/src/usb/mod.rs b/embassy-stm32/src/usb/mod.rs index ce9fe0a9b..7d8c79618 100644 --- a/embassy-stm32/src/usb/mod.rs +++ b/embassy-stm32/src/usb/mod.rs @@ -48,6 +48,26 @@ fn common_init() { while !crate::pac::PWR.cr3().read().usb33rdy() {} } + #[cfg(stm32h7rs)] + { + // If true, VDD33USB is generated by internal regulator from VDD50USB + // If false, VDD33USB and VDD50USB must be suplied directly with 3.3V (default on nucleo) + // TODO: unhardcode + let internal_regulator = false; + + // Enable USB power + critical_section::with(|_| { + crate::pac::PWR.csr2().modify(|w| { + w.set_usbregen(internal_regulator); + w.set_usb33den(true); + w.set_usbhsregen(true); + }) + }); + + // Wait for USB power to stabilize + while !crate::pac::PWR.csr2().read().usb33rdy() {} + } + #[cfg(stm32u5)] { // Enable USB power diff --git a/embassy-stm32/src/usb/otg.rs b/embassy-stm32/src/usb/otg.rs index e27b164e4..59b5401cc 100644 --- a/embassy-stm32/src/usb/otg.rs +++ b/embassy-stm32/src/usb/otg.rs @@ -97,6 +97,45 @@ impl<'d, T: Instance> Driver<'d, T> { } } + /// Initializes USB OTG peripheral with internal High-Speed PHY. + /// + /// # Arguments + /// + /// * `ep_out_buffer` - An internal buffer used to temporarily store received packets. + /// Must be large enough to fit all OUT endpoint max packet sizes. + /// Endpoint allocation will fail if it is too small. + pub fn new_hs( + _peri: impl Peripheral

+ 'd, + _irq: impl interrupt::typelevel::Binding> + 'd, + dp: impl Peripheral

> + 'd, + dm: impl Peripheral

> + 'd, + ep_out_buffer: &'d mut [u8], + config: Config, + ) -> Self { + into_ref!(dp, dm); + + dp.set_as_af(dp.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh)); + dm.set_as_af(dm.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh)); + + let regs = T::regs(); + + let instance = OtgInstance { + regs, + state: T::state(), + fifo_depth_words: T::FIFO_DEPTH_WORDS, + extra_rx_fifo_words: RX_FIFO_EXTRA_SIZE_WORDS, + endpoint_count: T::ENDPOINT_COUNT, + phy_type: PhyType::InternalHighSpeed, + quirk_setup_late_cnak: quirk_setup_late_cnak(regs), + calculate_trdt_fn: calculate_trdt::, + }; + + Self { + inner: OtgDriver::new(ep_out_buffer, instance, config), + phantom: PhantomData, + } + } + /// Initializes USB OTG peripheral with external Full-speed PHY (usually, a High-speed PHY in Full-speed mode). /// /// # Arguments @@ -272,6 +311,19 @@ impl<'d, T: Instance> Bus<'d, T> { } }); + #[cfg(stm32h7rs)] + critical_section::with(|_| { + let rcc = crate::pac::RCC; + rcc.ahb1enr().modify(|w| { + w.set_usbphycen(true); + w.set_usb_otg_hsen(true); + }); + rcc.ahb1lpenr().modify(|w| { + w.set_usbphyclpen(true); + w.set_usb_otg_hslpen(true); + }); + }); + let r = T::regs(); let core_id = r.cid().read().0; trace!("Core id {:08x}", core_id); @@ -286,6 +338,7 @@ impl<'d, T: Instance> Bus<'d, T> { match core_id { 0x0000_1200 | 0x0000_1100 => self.inner.config_v1(), 0x0000_2000 | 0x0000_2100 | 0x0000_2300 | 0x0000_3000 | 0x0000_3100 => self.inner.config_v2v3(), + 0x0000_5000 => self.inner.config_v5(), _ => unimplemented!("Unknown USB core id {:X}", core_id), } } diff --git a/embassy-usb-synopsys-otg/src/lib.rs b/embassy-usb-synopsys-otg/src/lib.rs index b145f4aa8..3ff965149 100644 --- a/embassy-usb-synopsys-otg/src/lib.rs +++ b/embassy-usb-synopsys-otg/src/lib.rs @@ -584,6 +584,22 @@ impl<'d, const MAX_EP_COUNT: usize> Bus<'d, MAX_EP_COUNT> { }); } + pub fn config_v5(&mut self) { + let r = self.instance.regs; + + r.gccfg_v3().modify(|w| { + w.set_vbvaloven(true); + w.set_vbvaloval(true); + w.set_vbden(self.config.vbus_detection); + }); + + // Force B-peripheral session + r.gotgctl().modify(|w| { + w.set_vbvaloen(!self.config.vbus_detection); + w.set_bvaloval(true); + }); + } + fn init(&mut self) { let r = self.instance.regs; let phy_type = self.instance.phy_type; diff --git a/embassy-usb-synopsys-otg/src/otg_v1.rs b/embassy-usb-synopsys-otg/src/otg_v1.rs index d3abc328d..18e760fd1 100644 --- a/embassy-usb-synopsys-otg/src/otg_v1.rs +++ b/embassy-usb-synopsys-otg/src/otg_v1.rs @@ -186,6 +186,11 @@ impl Otg { pub const fn gccfg_v2(self) -> Reg { unsafe { Reg::from_ptr(self.ptr.add(0x38usize) as _) } } + #[doc = "General core configuration register, for core_id 0x0000_5xxx"] + #[inline(always)] + pub const fn gccfg_v3(self) -> Reg { + unsafe { Reg::from_ptr(self.ptr.add(0x38usize) as _) } + } #[doc = "Core ID register"] #[inline(always)] pub const fn cid(self) -> Reg { @@ -1831,6 +1836,172 @@ pub mod regs { GccfgV2(0) } } + #[doc = "OTG general core configuration register."] + #[repr(transparent)] + #[derive(Copy, Clone, Eq, PartialEq)] + pub struct GccfgV3(pub u32); + impl GccfgV3 { + #[doc = "Charger detection, result of the current mode (primary or secondary)."] + #[inline(always)] + pub const fn chgdet(&self) -> bool { + let val = (self.0 >> 0usize) & 0x01; + val != 0 + } + #[doc = "Charger detection, result of the current mode (primary or secondary)."] + #[inline(always)] + pub fn set_chgdet(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 0usize)) | (((val as u32) & 0x01) << 0usize); + } + #[doc = "Single-Ended DP indicator This bit gives the voltage level on DP (also result of the comparison with VLGC threshold as defined in BC v1.2 standard)."] + #[inline(always)] + pub const fn fsvplus(&self) -> bool { + let val = (self.0 >> 1usize) & 0x01; + val != 0 + } + #[doc = "Single-Ended DP indicator This bit gives the voltage level on DP (also result of the comparison with VLGC threshold as defined in BC v1.2 standard)."] + #[inline(always)] + pub fn set_fsvplus(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 1usize)) | (((val as u32) & 0x01) << 1usize); + } + #[doc = "Single-Ended DM indicator This bit gives the voltage level on DM (also result of the comparison with VLGC threshold as defined in BC v1.2 standard)."] + #[inline(always)] + pub const fn fsvminus(&self) -> bool { + let val = (self.0 >> 2usize) & 0x01; + val != 0 + } + #[doc = "Single-Ended DM indicator This bit gives the voltage level on DM (also result of the comparison with VLGC threshold as defined in BC v1.2 standard)."] + #[inline(always)] + pub fn set_fsvminus(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 2usize)) | (((val as u32) & 0x01) << 2usize); + } + #[doc = "VBUS session indicator Indicates if VBUS is above VBUS session threshold."] + #[inline(always)] + pub const fn sessvld(&self) -> bool { + let val = (self.0 >> 3usize) & 0x01; + val != 0 + } + #[doc = "VBUS session indicator Indicates if VBUS is above VBUS session threshold."] + #[inline(always)] + pub fn set_sessvld(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 3usize)) | (((val as u32) & 0x01) << 3usize); + } + #[doc = "Host CDP behavior enable."] + #[inline(always)] + pub const fn hcdpen(&self) -> bool { + let val = (self.0 >> 16usize) & 0x01; + val != 0 + } + #[doc = "Host CDP behavior enable."] + #[inline(always)] + pub fn set_hcdpen(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 16usize)) | (((val as u32) & 0x01) << 16usize); + } + #[doc = "Host CDP port voltage detector enable on DP."] + #[inline(always)] + pub const fn hcdpdeten(&self) -> bool { + let val = (self.0 >> 17usize) & 0x01; + val != 0 + } + #[doc = "Host CDP port voltage detector enable on DP."] + #[inline(always)] + pub fn set_hcdpdeten(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 17usize)) | (((val as u32) & 0x01) << 17usize); + } + #[doc = "Host CDP port Voltage source enable on DM."] + #[inline(always)] + pub const fn hvdmsrcen(&self) -> bool { + let val = (self.0 >> 18usize) & 0x01; + val != 0 + } + #[doc = "Host CDP port Voltage source enable on DM."] + #[inline(always)] + pub fn set_hvdmsrcen(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 18usize)) | (((val as u32) & 0x01) << 18usize); + } + #[doc = "Data Contact Detection enable."] + #[inline(always)] + pub const fn dcden(&self) -> bool { + let val = (self.0 >> 19usize) & 0x01; + val != 0 + } + #[doc = "Data Contact Detection enable."] + #[inline(always)] + pub fn set_dcden(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 19usize)) | (((val as u32) & 0x01) << 19usize); + } + #[doc = "Primary detection enable."] + #[inline(always)] + pub const fn pden(&self) -> bool { + let val = (self.0 >> 20usize) & 0x01; + val != 0 + } + #[doc = "Primary detection enable."] + #[inline(always)] + pub fn set_pden(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 20usize)) | (((val as u32) & 0x01) << 20usize); + } + #[doc = "VBUS detection enable Enables VBUS Sensing Comparators in order to detect VBUS presence and/or perform OTG operation."] + #[inline(always)] + pub const fn vbden(&self) -> bool { + let val = (self.0 >> 21usize) & 0x01; + val != 0 + } + #[doc = "VBUS detection enable Enables VBUS Sensing Comparators in order to detect VBUS presence and/or perform OTG operation."] + #[inline(always)] + pub fn set_vbden(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 21usize)) | (((val as u32) & 0x01) << 21usize); + } + #[doc = "Secondary detection enable."] + #[inline(always)] + pub const fn sden(&self) -> bool { + let val = (self.0 >> 22usize) & 0x01; + val != 0 + } + #[doc = "Secondary detection enable."] + #[inline(always)] + pub fn set_sden(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 22usize)) | (((val as u32) & 0x01) << 22usize); + } + #[doc = "Software override value of the VBUS B-session detection."] + #[inline(always)] + pub const fn vbvaloval(&self) -> bool { + let val = (self.0 >> 23usize) & 0x01; + val != 0 + } + #[doc = "Software override value of the VBUS B-session detection."] + #[inline(always)] + pub fn set_vbvaloval(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 23usize)) | (((val as u32) & 0x01) << 23usize); + } + #[doc = "Enables a software override of the VBUS B-session detection."] + #[inline(always)] + pub const fn vbvaloven(&self) -> bool { + let val = (self.0 >> 24usize) & 0x01; + val != 0 + } + #[doc = "Enables a software override of the VBUS B-session detection."] + #[inline(always)] + pub fn set_vbvaloven(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 24usize)) | (((val as u32) & 0x01) << 24usize); + } + #[doc = "Force host mode pull-downs If the ID pin functions are enabled, the host mode pull-downs on DP and DM activate automatically. However, whenever that is not the case, yet host mode is required, this bit must be used to force the pull-downs active."] + #[inline(always)] + pub const fn forcehostpd(&self) -> bool { + let val = (self.0 >> 25usize) & 0x01; + val != 0 + } + #[doc = "Force host mode pull-downs If the ID pin functions are enabled, the host mode pull-downs on DP and DM activate automatically. However, whenever that is not the case, yet host mode is required, this bit must be used to force the pull-downs active."] + #[inline(always)] + pub fn set_forcehostpd(&mut self, val: bool) { + self.0 = (self.0 & !(0x01 << 25usize)) | (((val as u32) & 0x01) << 25usize); + } + } + impl Default for GccfgV3 { + #[inline(always)] + fn default() -> GccfgV3 { + GccfgV3(0) + } + } #[doc = "I2C access register"] #[repr(transparent)] #[derive(Copy, Clone, Eq, PartialEq)] diff --git a/examples/stm32h7rs/src/bin/usb_serial.rs b/examples/stm32h7rs/src/bin/usb_serial.rs new file mode 100644 index 000000000..5a234e898 --- /dev/null +++ b/examples/stm32h7rs/src/bin/usb_serial.rs @@ -0,0 +1,139 @@ +#![no_std] +#![no_main] + +use defmt::{panic, *}; +use embassy_executor::Spawner; +use embassy_futures::join::join; +use embassy_stm32::time::Hertz; +use embassy_stm32::usb::{Driver, Instance}; +use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; +use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; +use embassy_usb::driver::EndpointError; +use embassy_usb::Builder; +use {defmt_rtt as _, panic_probe as _}; + +bind_interrupts!(struct Irqs { + OTG_HS => usb::InterruptHandler; +}); + +// If you are trying this and your USB device doesn't connect, the most +// common issues are the RCC config and vbus_detection +// +// See https://embassy.dev/book/#_the_usb_examples_are_not_working_on_my_board_is_there_anything_else_i_need_to_configure +// for more information. +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + info!("Hello World!"); + + let mut config = Config::default(); + + { + use embassy_stm32::rcc::*; + config.rcc.hse = Some(Hse { + freq: Hertz(24_000_000), + mode: HseMode::Oscillator, + }); + config.rcc.pll1 = Some(Pll { + source: PllSource::HSE, + prediv: PllPreDiv::DIV12, + mul: PllMul::MUL300, + divp: Some(PllDiv::DIV1), //600 MHz + divq: Some(PllDiv::DIV2), // 300 MHz + divr: Some(PllDiv::DIV2), // 300 MHz + }); + config.rcc.sys = Sysclk::PLL1_P; // 600 MHz + config.rcc.ahb_pre = AHBPrescaler::DIV2; // 300 MHz + config.rcc.apb1_pre = APBPrescaler::DIV2; // 150 MHz + config.rcc.apb2_pre = APBPrescaler::DIV2; // 150 MHz + config.rcc.apb4_pre = APBPrescaler::DIV2; // 150 MHz + config.rcc.apb5_pre = APBPrescaler::DIV2; // 150 MHz + config.rcc.voltage_scale = VoltageScale::HIGH; + } + + let p = embassy_stm32::init(config); + + // Create the driver, from the HAL. + let mut ep_out_buffer = [0u8; 256]; + let mut config = embassy_stm32::usb::Config::default(); + + // Do not enable vbus_detection. This is a safe default that works in all boards. + // However, if your USB device is self-powered (can stay powered on if USB is unplugged), you need + // to enable vbus_detection to comply with the USB spec. If you enable it, the board + // has to support it or USB won't work at all. See docs on `vbus_detection` for details. + config.vbus_detection = false; + + let driver = Driver::new_hs(p.USB_OTG_HS, Irqs, p.PM6, p.PM5, &mut ep_out_buffer, config); + + // Create embassy-usb Config + let mut config = embassy_usb::Config::new(0xc0de, 0xcafe); + config.manufacturer = Some("Embassy"); + config.product = Some("USB-serial example"); + config.serial_number = Some("12345678"); + // Required for windows compatibility. + // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help + config.device_class = 0xEF; + config.device_sub_class = 0x02; + config.device_protocol = 0x01; + config.composite_with_iads = true; + + // Create embassy-usb DeviceBuilder using the driver and config. + // It needs some buffers for building the descriptors. + let mut config_descriptor = [0; 256]; + let mut bos_descriptor = [0; 256]; + let mut control_buf = [0; 64]; + + let mut state = State::new(); + + let mut builder = Builder::new( + driver, + config, + &mut config_descriptor, + &mut bos_descriptor, + &mut [], // no msos descriptors + &mut control_buf, + ); + + // Create classes on the builder. + let mut class = CdcAcmClass::new(&mut builder, &mut state, 64); + + // Build the builder. + let mut usb = builder.build(); + + // Run the USB device. + let usb_fut = usb.run(); + + // Do stuff with the class! + let echo_fut = async { + loop { + class.wait_connection().await; + info!("Connected"); + let _ = echo(&mut class).await; + info!("Disconnected"); + } + }; + + // Run everything concurrently. + // If we had made everything `'static` above instead, we could do this using separate tasks instead. + join(usb_fut, echo_fut).await; +} + +struct Disconnected {} + +impl From for Disconnected { + fn from(val: EndpointError) -> Self { + match val { + EndpointError::BufferOverflow => panic!("Buffer overflow"), + EndpointError::Disabled => Disconnected {}, + } + } +} + +async fn echo<'d, T: Instance + 'd>(class: &mut CdcAcmClass<'d, Driver<'d, T>>) -> Result<(), Disconnected> { + let mut buf = [0; 64]; + loop { + let n = class.read_packet(&mut buf).await?; + let data = &buf[..n]; + info!("data: {:x}", data); + class.write_packet(data).await?; + } +} From 6d9af8304cf88dbfa3713acfef4d89ba3a95c2d8 Mon Sep 17 00:00:00 2001 From: Kevin Date: Sun, 15 Sep 2024 20:09:42 +0200 Subject: [PATCH 0160/1217] Add USBPHYC clock configuration for H7RS series --- embassy-stm32/Cargo.toml | 6 ++--- embassy-stm32/src/rcc/h.rs | 32 +++++++++++++++++++++++- embassy-stm32/src/usb/mod.rs | 10 ++++++++ embassy-stm32/src/usb/otg.rs | 2 +- embassy-usb-synopsys-otg/src/lib.rs | 29 +++++++++++++-------- examples/stm32h7rs/src/bin/usb_serial.rs | 1 + 6 files changed, 63 insertions(+), 17 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 2f7f373af..575c4f20c 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -72,8 +72,7 @@ rand_core = "0.6.3" sdio-host = "0.5.0" critical-section = "1.1" #stm32-metapac = { version = "15" } -# stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-ad00827345b4b758b2453082809d6e3b634b5364" } -stm32-metapac = { path = "../../stm32-data/build/stm32-metapac" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-acaf04256034066bd5b3a8426224ccf3e4cb7d19" } vcell = "0.1.3" nb = "1.0.0" @@ -100,8 +99,7 @@ proc-macro2 = "1.0.36" quote = "1.0.15" #stm32-metapac = { version = "15", default-features = false, features = ["metadata"]} -# stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-ad00827345b4b758b2453082809d6e3b634b5364", default-features = false, features = ["metadata"] } -stm32-metapac = { path = "../../stm32-data/build/stm32-metapac", default-features = false, features = ["metadata"] } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-acaf04256034066bd5b3a8426224ccf3e4cb7d19", default-features = false, features = ["metadata"] } [features] default = ["rt"] diff --git a/embassy-stm32/src/rcc/h.rs b/embassy-stm32/src/rcc/h.rs index 27fc2b8d7..cd1c10407 100644 --- a/embassy-stm32/src/rcc/h.rs +++ b/embassy-stm32/src/rcc/h.rs @@ -35,7 +35,10 @@ pub enum VoltageScale { Scale3, } #[cfg(any(stm32h7rs))] -pub use crate::pac::pwr::vals::Vos as VoltageScale; +pub use crate::pac::{ + pwr::vals::Vos as VoltageScale, + rcc::vals::{Usbphycsel, Usbrefcksel}, +}; #[derive(Clone, Copy, Eq, PartialEq)] pub enum HseMode { @@ -557,6 +560,27 @@ pub(crate) unsafe fn init(config: Config) { let rtc = config.ls.init(); + #[cfg(stm32h7rs)] + let usb_refck = match config.mux.usbphycsel { + Usbphycsel::HSE => hse, + Usbphycsel::HSE_DIV_2 => hse.map(|hse_val| hse_val / 2u8), + Usbphycsel::PLL3_Q => pll3.q, + _ => None, + }; + #[cfg(stm32h7rs)] + let usb_refck_sel = match usb_refck { + Some(clk_val) => match clk_val { + Hertz(16_000_000) => Usbrefcksel::MHZ16, + Hertz(19_200_000) => Usbrefcksel::MHZ19_2, + Hertz(20_000_000) => Usbrefcksel::MHZ20, + Hertz(24_000_000) => Usbrefcksel::MHZ24, + Hertz(26_000_000) => Usbrefcksel::MHZ26, + Hertz(32_000_000) => Usbrefcksel::MHZ32, + _ => panic!("cannot select USBPHYC reference clock with source frequency of {} Hz, must be one of 16, 19.2, 20, 24, 26, 32 MHz", clk_val), + }, + None => Usbrefcksel::MHZ24, + }; + #[cfg(stm32h7)] { RCC.d1cfgr().modify(|w| { @@ -593,6 +617,10 @@ pub(crate) unsafe fn init(config: Config) { w.set_ppre4(config.apb4_pre); w.set_ppre5(config.apb5_pre); }); + + RCC.ahbperckselr().modify(|w| { + w.set_usbrefcksel(usb_refck_sel); + }); } #[cfg(stm32h5)] { @@ -698,6 +726,8 @@ pub(crate) unsafe fn init(config: Config) { #[cfg(stm32h7rs)] clk48mohci: None, // TODO #[cfg(stm32h7rs)] + hse_div_2: hse.map(|clk| clk / 2u32), + #[cfg(stm32h7rs)] usb: Some(Hertz(48_000_000)), ); } diff --git a/embassy-stm32/src/usb/mod.rs b/embassy-stm32/src/usb/mod.rs index 7d8c79618..a473285bf 100644 --- a/embassy-stm32/src/usb/mod.rs +++ b/embassy-stm32/src/usb/mod.rs @@ -13,9 +13,19 @@ fn common_init() { // Check the USB clock is enabled and running at exactly 48 MHz. // frequency() will panic if not enabled let freq = T::frequency(); + + // On the H7RS, the USBPHYC embeds a PLL accepting one of the input frequencies listed below and providing 48MHz to OTG_FS and 60MHz to OTG_HS internally + #[cfg(stm32h7rs)] + if ![16_000_000, 19_200_000, 20_000_000, 24_000_000, 26_000_000, 32_000_000].contains(&freq.0) { + panic!( + "USB clock should be one of 16, 19.2, 20, 24, 26, 32Mhz but is {} Hz. Please double-check your RCC settings.", + freq.0 + ) + } // Check frequency is within the 0.25% tolerance allowed by the spec. // Clock might not be exact 48Mhz due to rounding errors in PLL calculation, or if the user // has tight clock restrictions due to something else (like audio). + #[cfg(not(stm32h7rs))] if freq.0.abs_diff(48_000_000) > 120_000 { panic!( "USB clock should be 48Mhz but is {} Hz. Please double-check your RCC settings.", diff --git a/embassy-stm32/src/usb/otg.rs b/embassy-stm32/src/usb/otg.rs index 59b5401cc..00cafe6e4 100644 --- a/embassy-stm32/src/usb/otg.rs +++ b/embassy-stm32/src/usb/otg.rs @@ -554,7 +554,7 @@ fn calculate_trdt(speed: Dspd) -> u8 { match speed { Dspd::HIGH_SPEED => { // From RM0431 (F72xx), RM0090 (F429), RM0390 (F446) - if ahb_freq >= 30_000_000 { + if ahb_freq >= 30_000_000 || cfg!(stm32h7rs) { 0x9 } else { panic!("AHB frequency is too low") diff --git a/embassy-usb-synopsys-otg/src/lib.rs b/embassy-usb-synopsys-otg/src/lib.rs index 3ff965149..f90403936 100644 --- a/embassy-usb-synopsys-otg/src/lib.rs +++ b/embassy-usb-synopsys-otg/src/lib.rs @@ -584,20 +584,27 @@ impl<'d, const MAX_EP_COUNT: usize> Bus<'d, MAX_EP_COUNT> { }); } + /// Applies configuration specific to + /// Core ID 0x0000_5000 pub fn config_v5(&mut self) { let r = self.instance.regs; + let phy_type = self.instance.phy_type; - r.gccfg_v3().modify(|w| { - w.set_vbvaloven(true); - w.set_vbvaloval(true); - w.set_vbden(self.config.vbus_detection); - }); - - // Force B-peripheral session - r.gotgctl().modify(|w| { - w.set_vbvaloen(!self.config.vbus_detection); - w.set_bvaloval(true); - }); + if phy_type == PhyType::InternalHighSpeed { + r.gccfg_v3().modify(|w| { + w.set_vbvaloven(!self.config.vbus_detection); + w.set_vbvaloval(!self.config.vbus_detection); + w.set_vbden(self.config.vbus_detection); + }); + } else { + r.gotgctl().modify(|w| { + w.set_bvaloen(!self.config.vbus_detection); + w.set_bvaloval(!self.config.vbus_detection); + }); + r.gccfg_v3().modify(|w| { + w.set_vbden(self.config.vbus_detection); + }); + } } fn init(&mut self) { diff --git a/examples/stm32h7rs/src/bin/usb_serial.rs b/examples/stm32h7rs/src/bin/usb_serial.rs index 5a234e898..6773f7843 100644 --- a/examples/stm32h7rs/src/bin/usb_serial.rs +++ b/examples/stm32h7rs/src/bin/usb_serial.rs @@ -48,6 +48,7 @@ async fn main(_spawner: Spawner) { config.rcc.apb4_pre = APBPrescaler::DIV2; // 150 MHz config.rcc.apb5_pre = APBPrescaler::DIV2; // 150 MHz config.rcc.voltage_scale = VoltageScale::HIGH; + config.rcc.mux.usbphycsel = mux::Usbphycsel::HSE; } let p = embassy_stm32::init(config); From 85b7c8957cce3fef6011e63d7cb6ff85912ccb50 Mon Sep 17 00:00:00 2001 From: Kevin Date: Sun, 22 Sep 2024 01:11:32 +0200 Subject: [PATCH 0161/1217] Add presence check for OTG_HS peripheral on STM32H7R/S series --- embassy-stm32/build.rs | 4 +++- embassy-stm32/src/rcc/h.rs | 14 +++++++------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 19cf193d9..28c619c6b 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -55,7 +55,7 @@ fn main() { let mut singletons: Vec = Vec::new(); for p in METADATA.peripherals { if let Some(r) = &p.registers { - if r.kind == "adccommon" || r.kind == "sai" || r.kind == "ucpd" { + if r.kind == "adccommon" || r.kind == "sai" || r.kind == "ucpd" || r.kind == "otg" { // TODO: should we emit this for all peripherals? if so, we will need a list of all // possible peripherals across all chips, so that we can declare the configs // (replacing the hard-coded list of `peri_*` cfgs below) @@ -111,6 +111,8 @@ fn main() { "peri_sai4", "peri_ucpd1", "peri_ucpd2", + "peri_usb_otg_fs", + "peri_usb_otg_hs", ]); cfgs.declare_all(&["mco", "mco1", "mco2"]); diff --git a/embassy-stm32/src/rcc/h.rs b/embassy-stm32/src/rcc/h.rs index cd1c10407..55fe8ca9d 100644 --- a/embassy-stm32/src/rcc/h.rs +++ b/embassy-stm32/src/rcc/h.rs @@ -34,11 +34,10 @@ pub enum VoltageScale { Scale2, Scale3, } -#[cfg(any(stm32h7rs))] -pub use crate::pac::{ - pwr::vals::Vos as VoltageScale, - rcc::vals::{Usbphycsel, Usbrefcksel}, -}; +#[cfg(stm32h7rs)] +pub use crate::pac::pwr::vals::Vos as VoltageScale; +#[cfg(all(stm32h7rs, peri_usb_otg_hs))] +pub use crate::pac::rcc::vals::{Usbphycsel, Usbrefcksel}; #[derive(Clone, Copy, Eq, PartialEq)] pub enum HseMode { @@ -560,14 +559,14 @@ pub(crate) unsafe fn init(config: Config) { let rtc = config.ls.init(); - #[cfg(stm32h7rs)] + #[cfg(all(stm32h7rs, peri_usb_otg_hs))] let usb_refck = match config.mux.usbphycsel { Usbphycsel::HSE => hse, Usbphycsel::HSE_DIV_2 => hse.map(|hse_val| hse_val / 2u8), Usbphycsel::PLL3_Q => pll3.q, _ => None, }; - #[cfg(stm32h7rs)] + #[cfg(all(stm32h7rs, peri_usb_otg_hs))] let usb_refck_sel = match usb_refck { Some(clk_val) => match clk_val { Hertz(16_000_000) => Usbrefcksel::MHZ16, @@ -618,6 +617,7 @@ pub(crate) unsafe fn init(config: Config) { w.set_ppre5(config.apb5_pre); }); + #[cfg(peri_usb_otg_hs)] RCC.ahbperckselr().modify(|w| { w.set_usbrefcksel(usb_refck_sel); }); From db31e3648500bc7f36e8ac0d8c101b88cd4b956c Mon Sep 17 00:00:00 2001 From: Shaw Drastin <168159404+showier-drastic@users.noreply.github.com> Date: Sun, 22 Sep 2024 02:05:17 +0800 Subject: [PATCH 0162/1217] stm32/spi: issue correct DMA word length when reading Currently, when calling read() of the SPI bus, DMA always transmits u8, which will cause hang if SPI transfer size > 8bit. Use matching word size for TX DMA instead. --- embassy-stm32/src/spi/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs index 20718147a..dfac4bc89 100644 --- a/embassy-stm32/src/spi/mod.rs +++ b/embassy-stm32/src/spi/mod.rs @@ -783,7 +783,7 @@ impl<'d> Spi<'d, Async> { let rx_f = unsafe { self.rx_dma.as_mut().unwrap().read(rx_src, data, Default::default()) }; let tx_dst = self.info.regs.tx_ptr(); - let clock_byte = 0x00u8; + let clock_byte = W::default(); let tx_f = unsafe { self.tx_dma .as_mut() @@ -1195,7 +1195,7 @@ trait SealedWord { /// Word sizes usable for SPI. #[allow(private_bounds)] -pub trait Word: word::Word + SealedWord {} +pub trait Word: word::Word + SealedWord + Default {} macro_rules! impl_word { ($T:ty, $config:expr) => { From e2d2b0f36281326772678f0e903675927faaaddb Mon Sep 17 00:00:00 2001 From: Hans Josephsen Date: Sun, 22 Sep 2024 12:30:38 +0200 Subject: [PATCH 0163/1217] Currently the return value of `write` is broken, it never returns the previous frame even when present. This happens because a slice of length 64 is always passed to Frame::new from within the `abort_pending_mailbox` function, causing `Frame::new` to return None. The fix is to take a subslice of length `data_length`. --- .gitignore | 1 + embassy-stm32/src/can/fd/peripheral.rs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 1c221e876..a0b5d6a70 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ Cargo.lock third_party /Cargo.toml out/ +.zed diff --git a/embassy-stm32/src/can/fd/peripheral.rs b/embassy-stm32/src/can/fd/peripheral.rs index 07e3dddad..1c7abfcb2 100644 --- a/embassy-stm32/src/can/fd/peripheral.rs +++ b/embassy-stm32/src/can/fd/peripheral.rs @@ -200,7 +200,7 @@ impl Registers { if header_reg.rtr().bit() { F::new_remote(id, len as usize) } else { - F::new(id, &data) + F::new(id, &data[0..(len as usize)]) } } else { // Abort request failed because the frame was already sent (or being sent) on From f2f96a731c1c08045a210083d307bc63814ae6bf Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 23 Sep 2024 00:32:17 +0200 Subject: [PATCH 0164/1217] stm32/gpdma: ensure bndt in bytes doesn't overflow. --- embassy-stm32/src/dma/gpdma.rs | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/embassy-stm32/src/dma/gpdma.rs b/embassy-stm32/src/dma/gpdma.rs index f9d66ca86..792ddc4e8 100644 --- a/embassy-stm32/src/dma/gpdma.rs +++ b/embassy-stm32/src/dma/gpdma.rs @@ -216,7 +216,10 @@ impl<'a> Transfer<'a> { data_size: WordSize, _options: TransferOptions, ) -> Self { - assert!(mem_len > 0 && mem_len <= 0xFFFF); + // BNDT is specified as bytes, not as number of transfers. + let Ok(bndt) = (mem_len * data_size.bytes()).try_into() else { + panic!("DMA transfers may not be larger than 65535 bytes."); + }; let info = channel.info(); let ch = info.dma.ch(info.num); @@ -226,9 +229,6 @@ impl<'a> Transfer<'a> { let this = Self { channel }; - #[cfg(dmamux)] - super::dmamux::configure_dmamux(&*this.channel, request); - ch.cr().write(|w| w.set_reset(true)); ch.fcr().write(|w| w.0 = 0xFFFF_FFFF); // clear all irqs ch.llr().write(|_| {}); // no linked list @@ -245,10 +245,7 @@ impl<'a> Transfer<'a> { }); w.set_reqsel(request); }); - ch.br1().write(|w| { - // BNDT is specified as bytes, not as number of transfers. - w.set_bndt((mem_len * data_size.bytes()) as u16) - }); + ch.br1().write(|w| w.set_bndt(bndt)); match dir { Dir::MemoryToPeripheral => { From 59dcffbc6021ab1aaef1dd546aa7e707b438e45f Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 23 Sep 2024 01:32:55 +0200 Subject: [PATCH 0165/1217] stm32/gpdma: clear tr3 just in case. --- embassy-stm32/src/dma/gpdma.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/embassy-stm32/src/dma/gpdma.rs b/embassy-stm32/src/dma/gpdma.rs index 792ddc4e8..a877bb8d4 100644 --- a/embassy-stm32/src/dma/gpdma.rs +++ b/embassy-stm32/src/dma/gpdma.rs @@ -245,6 +245,7 @@ impl<'a> Transfer<'a> { }); w.set_reqsel(request); }); + ch.tr3().write(|_| {}); // no address offsets. ch.br1().write(|w| w.set_bndt(bndt)); match dir { From 68b783aedfd7c85505d5961ad3030719676210d1 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 23 Sep 2024 01:59:05 +0200 Subject: [PATCH 0166/1217] stm32/spi: fix hang/corruption of word sizes other than 8bit. --- embassy-stm32/src/spi/mod.rs | 72 +++++++++++++----------------------- 1 file changed, 26 insertions(+), 46 deletions(-) diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs index dfac4bc89..d034c028e 100644 --- a/embassy-stm32/src/spi/mod.rs +++ b/embassy-stm32/src/spi/mod.rs @@ -311,51 +311,29 @@ impl<'d, M: PeriMode> Spi<'d, M> { } } + /// Set SPI word size. Disables SPI if needed, you have to enable it back yourself. fn set_word_size(&mut self, word_size: word_impl::Config) { if self.current_word_size == word_size { return; } + self.info.regs.cr1().modify(|w| { + w.set_spe(false); + }); + #[cfg(any(spi_v1, spi_f1))] - { - self.info.regs.cr1().modify(|reg| { - reg.set_spe(false); - reg.set_dff(word_size) - }); - self.info.regs.cr1().modify(|reg| { - reg.set_spe(true); - }); - } + self.info.regs.cr1().modify(|reg| { + reg.set_dff(word_size); + }); #[cfg(spi_v2)] - { - self.info.regs.cr1().modify(|w| { - w.set_spe(false); - }); - self.info.regs.cr2().modify(|w| { - w.set_frxth(word_size.1); - w.set_ds(word_size.0); - }); - self.info.regs.cr1().modify(|w| { - w.set_spe(true); - }); - } + self.info.regs.cr2().modify(|w| { + w.set_frxth(word_size.1); + w.set_ds(word_size.0); + }); #[cfg(any(spi_v3, spi_v4, spi_v5))] - { - self.info.regs.cr1().modify(|w| { - w.set_csusp(true); - }); - while self.info.regs.sr().read().eot() {} - self.info.regs.cr1().modify(|w| { - w.set_spe(false); - }); - self.info.regs.cfg1().modify(|w| { - w.set_dsize(word_size); - }); - self.info.regs.cr1().modify(|w| { - w.set_csusp(false); - w.set_spe(true); - }); - } + self.info.regs.cfg1().modify(|w| { + w.set_dsize(word_size); + }); self.current_word_size = word_size; } @@ -365,9 +343,9 @@ impl<'d, M: PeriMode> Spi<'d, M> { // needed in v3+ to avoid overrun causing the SPI RX state machine to get stuck...? #[cfg(any(spi_v3, spi_v4, spi_v5))] self.info.regs.cr1().modify(|w| w.set_spe(false)); + self.set_word_size(W::CONFIG); self.info.regs.cr1().modify(|w| w.set_spe(true)); flush_rx_fifo(self.info.regs); - self.set_word_size(W::CONFIG); for word in words.iter() { // this cannot use `transfer_word` because on SPIv2 and higher, // the SPI RX state machine hangs if no physical pin is connected to the SCK AF. @@ -402,9 +380,9 @@ impl<'d, M: PeriMode> Spi<'d, M> { // needed in v3+ to avoid overrun causing the SPI RX state machine to get stuck...? #[cfg(any(spi_v3, spi_v4, spi_v5))] self.info.regs.cr1().modify(|w| w.set_spe(false)); + self.set_word_size(W::CONFIG); self.info.regs.cr1().modify(|w| w.set_spe(true)); flush_rx_fifo(self.info.regs); - self.set_word_size(W::CONFIG); for word in words.iter_mut() { *word = transfer_word(self.info.regs, W::default())?; } @@ -418,9 +396,9 @@ impl<'d, M: PeriMode> Spi<'d, M> { // needed in v3+ to avoid overrun causing the SPI RX state machine to get stuck...? #[cfg(any(spi_v3, spi_v4, spi_v5))] self.info.regs.cr1().modify(|w| w.set_spe(false)); + self.set_word_size(W::CONFIG); self.info.regs.cr1().modify(|w| w.set_spe(true)); flush_rx_fifo(self.info.regs); - self.set_word_size(W::CONFIG); for word in words.iter_mut() { *word = transfer_word(self.info.regs, *word)?; } @@ -437,9 +415,9 @@ impl<'d, M: PeriMode> Spi<'d, M> { // needed in v3+ to avoid overrun causing the SPI RX state machine to get stuck...? #[cfg(any(spi_v3, spi_v4, spi_v5))] self.info.regs.cr1().modify(|w| w.set_spe(false)); + self.set_word_size(W::CONFIG); self.info.regs.cr1().modify(|w| w.set_spe(true)); flush_rx_fifo(self.info.regs); - self.set_word_size(W::CONFIG); let len = read.len().max(write.len()); for i in 0..len { let wb = write.get(i).copied().unwrap_or_default(); @@ -648,10 +626,10 @@ impl<'d> Spi<'d, Async> { return Ok(()); } - self.set_word_size(W::CONFIG); self.info.regs.cr1().modify(|w| { w.set_spe(false); }); + self.set_word_size(W::CONFIG); let tx_dst = self.info.regs.tx_ptr(); let tx_f = unsafe { self.tx_dma.as_mut().unwrap().write(data, tx_dst, Default::default()) }; @@ -685,6 +663,8 @@ impl<'d> Spi<'d, Async> { w.set_spe(false); }); + self.set_word_size(W::CONFIG); + let comm = regs.cfg2().modify(|w| { let prev = w.comm(); w.set_comm(vals::Comm::RECEIVER); @@ -707,7 +687,6 @@ impl<'d> Spi<'d, Async> { let rx_src = regs.rx_ptr(); for mut chunk in data.chunks_mut(u16::max_value().into()) { - self.set_word_size(W::CONFIG); set_rxdmaen(regs, true); let tsize = chunk.len(); @@ -765,12 +744,12 @@ impl<'d> Spi<'d, Async> { return Ok(()); } - self.set_word_size(W::CONFIG); - self.info.regs.cr1().modify(|w| { w.set_spe(false); }); + self.set_word_size(W::CONFIG); + // SPIv3 clears rxfifo on SPE=0 #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] flush_rx_fifo(self.info.regs); @@ -813,11 +792,12 @@ impl<'d> Spi<'d, Async> { return Ok(()); } - self.set_word_size(W::CONFIG); self.info.regs.cr1().modify(|w| { w.set_spe(false); }); + self.set_word_size(W::CONFIG); + // SPIv3 clears rxfifo on SPE=0 #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] flush_rx_fifo(self.info.regs); From fb0afa8a0fbc47e76a5f9357da2898e0c7a0ee27 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 23 Sep 2024 02:06:11 +0200 Subject: [PATCH 0167/1217] stm32: update metapac. Fixes SPI version on L0. --- embassy-stm32/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 575c4f20c..8fc8da006 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -72,7 +72,7 @@ rand_core = "0.6.3" sdio-host = "0.5.0" critical-section = "1.1" #stm32-metapac = { version = "15" } -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-acaf04256034066bd5b3a8426224ccf3e4cb7d19" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-9b7414490b10ffbd5beb1b0dcf14adb018cbe37f" } vcell = "0.1.3" nb = "1.0.0" @@ -99,7 +99,7 @@ proc-macro2 = "1.0.36" quote = "1.0.15" #stm32-metapac = { version = "15", default-features = false, features = ["metadata"]} -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-acaf04256034066bd5b3a8426224ccf3e4cb7d19", default-features = false, features = ["metadata"] } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-9b7414490b10ffbd5beb1b0dcf14adb018cbe37f", default-features = false, features = ["metadata"] } [features] default = ["rt"] From a71098d824346a25ab9fb376627c0383d0f9250a Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sun, 22 Sep 2024 10:53:04 +0200 Subject: [PATCH 0168/1217] stm32/tests: test spi u8 and u16 word sizes. --- tests/stm32/src/bin/spi.rs | 100 ++++++++++++++++++---------- tests/stm32/src/bin/spi_dma.rs | 116 +++++++++++++++++++++------------ 2 files changed, 141 insertions(+), 75 deletions(-) diff --git a/tests/stm32/src/bin/spi.rs b/tests/stm32/src/bin/spi.rs index 53d44a94a..9712a8c5a 100644 --- a/tests/stm32/src/bin/spi.rs +++ b/tests/stm32/src/bin/spi.rs @@ -7,7 +7,8 @@ use common::*; use defmt::assert_eq; use embassy_executor::Spawner; use embassy_stm32::gpio::{Level, Output, Speed}; -use embassy_stm32::spi::{self, Spi}; +use embassy_stm32::mode::Blocking; +use embassy_stm32::spi::{self, Spi, Word}; use embassy_stm32::time::Hertz; #[embassy_executor::main] @@ -31,11 +32,58 @@ async fn main(_spawner: Spawner) { spi_config, ); - let data: [u8; 9] = [0x00, 0xFF, 0xAA, 0x55, 0xC0, 0xFF, 0xEE, 0xC0, 0xDE]; + test_txrx::(&mut spi); + test_txrx::(&mut spi); + + // Assert the RCC bit gets disabled on drop. + #[cfg(feature = "stm32f429zi")] + defmt::assert!(embassy_stm32::pac::RCC.apb2enr().read().spi1en()); + drop(spi); + #[cfg(feature = "stm32f429zi")] + defmt::assert!(!embassy_stm32::pac::RCC.apb2enr().read().spi1en()); + + // test rx-only configuration + let mut spi = Spi::new_blocking_rxonly(&mut spi_peri, &mut sck, &mut miso, spi_config); + let mut mosi_out = Output::new(&mut mosi, Level::Low, Speed::VeryHigh); + + test_rx::(&mut spi, &mut mosi_out); + test_rx::(&mut spi, &mut mosi_out); + drop(spi); + drop(mosi_out); + + let mut spi = Spi::new_blocking_txonly(&mut spi_peri, &mut sck, &mut mosi, spi_config); + test_tx::(&mut spi); + test_tx::(&mut spi); + drop(spi); + + let mut spi = Spi::new_blocking_txonly_nosck(&mut spi_peri, &mut mosi, spi_config); + test_tx::(&mut spi); + test_tx::(&mut spi); + drop(spi); + + info!("Test OK"); + cortex_m::asm::bkpt(); +} + +fn test_txrx + defmt::Format + Eq>(spi: &mut Spi<'_, Blocking>) +where + W: core::ops::Not, +{ + let data: [W; 9] = [ + 0x00u8.into(), + 0xFFu8.into(), + 0xAAu8.into(), + 0x55u8.into(), + 0xC0u8.into(), + 0xFFu8.into(), + 0xEEu8.into(), + 0xC0u8.into(), + 0xDEu8.into(), + ]; // Arduino pins D11 and D12 (MOSI-MISO) are connected together with a 1K resistor. // so we should get the data we sent back. - let mut buf = [0; 9]; + let mut buf = [W::default(); 9]; spi.blocking_transfer(&mut buf, &data).unwrap(); assert_eq!(buf, data); @@ -59,47 +107,33 @@ async fn main(_spawner: Spawner) { spi.blocking_transfer_in_place::(&mut []).unwrap(); spi.blocking_read::(&mut []).unwrap(); spi.blocking_write::(&[]).unwrap(); +} - // Assert the RCC bit gets disabled on drop. - #[cfg(feature = "stm32f429zi")] - defmt::assert!(embassy_stm32::pac::RCC.apb2enr().read().spi1en()); - drop(spi); - #[cfg(feature = "stm32f429zi")] - defmt::assert!(!embassy_stm32::pac::RCC.apb2enr().read().spi1en()); +fn test_rx + defmt::Format + Eq>(spi: &mut Spi<'_, Blocking>, mosi_out: &mut Output<'_>) +where + W: core::ops::Not, +{ + let mut buf = [W::default(); 9]; - // test rx-only configuration - let mut spi = Spi::new_blocking_rxonly(&mut spi_peri, &mut sck, &mut miso, spi_config); - let mut mosi_out = Output::new(&mut mosi, Level::Low, Speed::VeryHigh); mosi_out.set_high(); spi.blocking_read(&mut buf).unwrap(); - assert_eq!(buf, [0xff; 9]); + assert_eq!(buf, [!W::default(); 9]); mosi_out.set_low(); spi.blocking_read(&mut buf).unwrap(); - assert_eq!(buf, [0x00; 9]); + assert_eq!(buf, [W::default(); 9]); spi.blocking_read::(&mut []).unwrap(); spi.blocking_read::(&mut []).unwrap(); - drop(mosi_out); - drop(spi); +} + +fn test_tx + defmt::Format + Eq>(spi: &mut Spi<'_, Blocking>) +where + W: core::ops::Not, +{ + let buf = [W::default(); 9]; // Test tx-only. Just check it doesn't hang, not much else we can do without using SPI slave. - let mut spi = Spi::new_blocking_txonly(&mut spi_peri, &mut sck, &mut mosi, spi_config); - spi.blocking_transfer(&mut buf, &data).unwrap(); - spi.blocking_transfer_in_place(&mut buf).unwrap(); - spi.blocking_write(&buf).unwrap(); - spi.blocking_read(&mut buf).unwrap(); - spi.blocking_transfer::(&mut [], &[]).unwrap(); - spi.blocking_transfer_in_place::(&mut []).unwrap(); - spi.blocking_read::(&mut []).unwrap(); - spi.blocking_write::(&[]).unwrap(); - drop(spi); - - // Test tx-only nosck. - let mut spi = Spi::new_blocking_txonly_nosck(&mut spi_peri, &mut mosi, spi_config); spi.blocking_write(&buf).unwrap(); spi.blocking_write::(&[]).unwrap(); spi.blocking_write(&buf).unwrap(); - drop(spi); - - info!("Test OK"); - cortex_m::asm::bkpt(); + spi.blocking_write::(&[]).unwrap(); } diff --git a/tests/stm32/src/bin/spi_dma.rs b/tests/stm32/src/bin/spi_dma.rs index a1cbc0ed1..307409a16 100644 --- a/tests/stm32/src/bin/spi_dma.rs +++ b/tests/stm32/src/bin/spi_dma.rs @@ -7,7 +7,8 @@ use common::*; use defmt::assert_eq; use embassy_executor::Spawner; use embassy_stm32::gpio::{Level, Output, Speed}; -use embassy_stm32::spi::{self, Spi}; +use embassy_stm32::mode::Async; +use embassy_stm32::spi::{self, Spi, Word}; use embassy_stm32::time::Hertz; #[embassy_executor::main] @@ -35,11 +36,61 @@ async fn main(_spawner: Spawner) { spi_config, ); - let data: [u8; 9] = [0x00, 0xFF, 0xAA, 0x55, 0xC0, 0xFF, 0xEE, 0xC0, 0xDE]; + test_txrx::(&mut spi).await; + test_txrx::(&mut spi).await; + drop(spi); + + // test rx-only configuration + let mut spi = Spi::new_rxonly( + &mut spi_peri, + &mut sck, + &mut miso, + // SPIv1/f1 requires txdma even if rxonly. + #[cfg(not(feature = "spi-v345"))] + &mut tx_dma, + &mut rx_dma, + spi_config, + ); + let mut mosi_out = Output::new(&mut mosi, Level::Low, Speed::VeryHigh); + + test_rx::(&mut spi, &mut mosi_out).await; + test_rx::(&mut spi, &mut mosi_out).await; + drop(spi); + drop(mosi_out); + + let mut spi = Spi::new_txonly(&mut spi_peri, &mut sck, &mut mosi, &mut tx_dma, spi_config); + test_tx::(&mut spi).await; + test_tx::(&mut spi).await; + drop(spi); + + let mut spi = Spi::new_txonly_nosck(&mut spi_peri, &mut mosi, &mut tx_dma, spi_config); + test_tx::(&mut spi).await; + test_tx::(&mut spi).await; + drop(spi); + + info!("Test OK"); + cortex_m::asm::bkpt(); +} + +async fn test_txrx + defmt::Format + Eq>(spi: &mut Spi<'_, Async>) +where + W: core::ops::Not, +{ + let data: [W; 9] = [ + 0x00u8.into(), + 0xFFu8.into(), + 0xAAu8.into(), + 0x55u8.into(), + 0xC0u8.into(), + 0xFFu8.into(), + 0xEEu8.into(), + 0xC0u8.into(), + 0xDEu8.into(), + ]; // Arduino pins D11 and D12 (MOSI-MISO) are connected together with a 1K resistor. // so we should get the data we sent back. - let mut buf = [0; 9]; + let mut buf = [W::default(); 9]; spi.transfer(&mut buf, &data).await.unwrap(); assert_eq!(buf, data); @@ -83,44 +134,41 @@ async fn main(_spawner: Spawner) { spi.blocking_write(&buf).unwrap(); spi.blocking_read(&mut buf).unwrap(); spi.write(&buf).await.unwrap(); +} - core::mem::drop(spi); +async fn test_rx + defmt::Format + Eq>(spi: &mut Spi<'_, Async>, mosi_out: &mut Output<'_>) +where + W: core::ops::Not, +{ + let mut buf = [W::default(); 9]; - // test rx-only configuration - let mut spi = Spi::new_rxonly( - &mut spi_peri, - &mut sck, - &mut miso, - // SPIv1/f1 requires txdma even if rxonly. - #[cfg(not(feature = "spi-v345"))] - &mut tx_dma, - &mut rx_dma, - spi_config, - ); - let mut mosi_out = Output::new(&mut mosi, Level::Low, Speed::VeryHigh); mosi_out.set_high(); spi.read(&mut buf).await.unwrap(); - assert_eq!(buf, [0xff; 9]); + assert_eq!(buf, [!W::default(); 9]); spi.blocking_read(&mut buf).unwrap(); - assert_eq!(buf, [0xff; 9]); + assert_eq!(buf, [!W::default(); 9]); spi.read(&mut buf).await.unwrap(); - assert_eq!(buf, [0xff; 9]); + assert_eq!(buf, [!W::default(); 9]); spi.read(&mut buf).await.unwrap(); - assert_eq!(buf, [0xff; 9]); + assert_eq!(buf, [!W::default(); 9]); spi.blocking_read(&mut buf).unwrap(); - assert_eq!(buf, [0xff; 9]); + assert_eq!(buf, [!W::default(); 9]); spi.blocking_read(&mut buf).unwrap(); - assert_eq!(buf, [0xff; 9]); + assert_eq!(buf, [!W::default(); 9]); mosi_out.set_low(); spi.read(&mut buf).await.unwrap(); - assert_eq!(buf, [0x00; 9]); + assert_eq!(buf, [W::default(); 9]); spi.read::(&mut []).await.unwrap(); spi.blocking_read::(&mut []).unwrap(); - drop(mosi_out); - drop(spi); +} + +async fn test_tx + defmt::Format + Eq>(spi: &mut Spi<'_, Async>) +where + W: core::ops::Not, +{ + let buf = [W::default(); 9]; // Test tx-only. Just check it doesn't hang, not much else we can do without using SPI slave. - let mut spi = Spi::new_txonly(&mut spi_peri, &mut sck, &mut mosi, &mut tx_dma, spi_config); spi.blocking_write(&buf).unwrap(); spi.write(&buf).await.unwrap(); spi.blocking_write(&buf).unwrap(); @@ -129,20 +177,4 @@ async fn main(_spawner: Spawner) { spi.write(&buf).await.unwrap(); spi.write::(&[]).await.unwrap(); spi.blocking_write::(&[]).unwrap(); - drop(spi); - - // Test tx-only nosck. - let mut spi = Spi::new_txonly_nosck(&mut spi_peri, &mut mosi, &mut tx_dma, spi_config); - spi.blocking_write(&buf).unwrap(); - spi.write(&buf).await.unwrap(); - spi.blocking_write(&buf).unwrap(); - spi.blocking_write(&buf).unwrap(); - spi.write(&buf).await.unwrap(); - spi.write(&buf).await.unwrap(); - spi.write::(&[]).await.unwrap(); - spi.blocking_write::(&[]).unwrap(); - drop(spi); - - info!("Test OK"); - cortex_m::asm::bkpt(); } From 05d453bfd81bce49d541b2eeee3a8788e5a5fd7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20H=C3=A9riveaux?= Date: Mon, 23 Sep 2024 16:11:45 +0200 Subject: [PATCH 0169/1217] Fixed signature script in bootloader documentation --- docs/pages/bootloader.adoc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/pages/bootloader.adoc b/docs/pages/bootloader.adoc index 3b0cdb182..a80e75c4c 100644 --- a/docs/pages/bootloader.adoc +++ b/docs/pages/bootloader.adoc @@ -86,8 +86,7 @@ Then, to sign your firmware given a declaration of `FIRMWARE_DIR` and a firmware [source, bash] ---- -shasum -a 512 -b $FIRMWARE_DIR/myfirmware > $SECRETS_DIR/message.txt -cat $SECRETS_DIR/message.txt | dd ibs=128 count=1 | xxd -p -r > $SECRETS_DIR/message.txt +shasum -a 512 -b $FIRMWARE_DIR/myfirmware | head -c128 | xxd -p -r > $SECRETS_DIR/message.txt signify -S -s $SECRETS_DIR/key.sec -m $SECRETS_DIR/message.txt -x $SECRETS_DIR/message.txt.sig cp $FIRMWARE_DIR/myfirmware $FIRMWARE_DIR/myfirmware+signed tail -n1 $SECRETS_DIR/message.txt.sig | base64 -d -i - | dd ibs=10 skip=1 >> $FIRMWARE_DIR/myfirmware+signed From 0b8c4587c2726e4dd9186debb515034d687a22d3 Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Mon, 23 Sep 2024 13:38:43 -0400 Subject: [PATCH 0170/1217] Fix rp2350b pins >31 on debug builds --- embassy-rp/src/gpio.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-rp/src/gpio.rs b/embassy-rp/src/gpio.rs index 520043b07..cb54375e4 100644 --- a/embassy-rp/src/gpio.rs +++ b/embassy-rp/src/gpio.rs @@ -603,7 +603,7 @@ impl<'d> Flex<'d> { #[inline] fn bit(&self) -> u32 { - 1 << self.pin.pin() + 1 << (self.pin.pin() % 32) } /// Set the pin's pull. From a669611d7c8fb17666f35086ea20c476b6029854 Mon Sep 17 00:00:00 2001 From: Peter Krull Date: Mon, 23 Sep 2024 20:09:35 +0200 Subject: [PATCH 0171/1217] Discontinue peek, add AnonReceiver --- embassy-sync/src/watch.rs | 440 +++++++++++++++++++++++++------------- 1 file changed, 289 insertions(+), 151 deletions(-) diff --git a/embassy-sync/src/watch.rs b/embassy-sync/src/watch.rs index 298c09d43..1b4a8b589 100644 --- a/embassy-sync/src/watch.rs +++ b/embassy-sync/src/watch.rs @@ -20,7 +20,9 @@ use crate::waitqueue::MultiWakerRegistration; /// always provided with the latest value. /// /// Typically, `Watch` instances are declared as `static`, and a [`Sender`] and [`Receiver`] -/// (or [`DynSender`] and/or [`DynReceiver`]) are obtained and passed to the relevant parts of the program. +/// (or [`DynSender`] and/or [`DynReceiver`]) are obtained where relevant. An [`AnonReceiver`] +/// and [`DynAnonReceiver`] are also available, which do not increase the receiver count for the +/// channel, and unwrapping is therefore not required, but it is not possible to `.await` the channel. /// ``` /// /// use futures_executor::block_on; @@ -41,25 +43,25 @@ use crate::waitqueue::MultiWakerRegistration; /// assert_eq!(rcv1.try_changed(), None); /// /// snd.send(10); -/// +/// /// // Receive the new value (async or try) /// assert_eq!(rcv0.changed().await, 10); /// assert_eq!(rcv1.try_changed(), Some(10)); -/// +/// /// // No update /// assert_eq!(rcv0.try_changed(), None); /// assert_eq!(rcv1.try_changed(), None); /// /// snd.send(20); /// -/// // Peek does not mark the value as seen -/// assert_eq!(rcv0.peek().await, 20); -/// assert_eq!(rcv0.try_changed(), Some(20)); -/// -/// // Get marks the value as seen +/// // Using `get` marks the value as seen /// assert_eq!(rcv1.get().await, 20); /// assert_eq!(rcv1.try_changed(), None); /// +/// // But `get` also returns when unchanged +/// assert_eq!(rcv1.get().await, 20); +/// assert_eq!(rcv1.get().await, 20); +/// /// }; /// block_on(f); /// ``` @@ -82,24 +84,11 @@ pub trait WatchBehavior { /// Clears the value of the `Watch`. fn clear(&self); - /// Poll the `Watch` for the current value, **without** making it as seen. - fn poll_peek(&self, cx: &mut Context<'_>) -> Poll; - - /// Tries to peek the value of the `Watch`, **without** marking it as seen. - fn try_peek(&self) -> Option; - - /// Poll the `Watch` for the value if it matches the predicate function - /// `f`, **without** making it as seen. - fn poll_peek_and(&self, f: &mut dyn Fn(&T) -> bool, cx: &mut Context<'_>) -> Poll; - - /// Tries to peek the value of the `Watch` if it matches the predicate function `f`, **without** marking it as seen. - fn try_peek_and(&self, f: &mut dyn Fn(&T) -> bool) -> Option; - /// Poll the `Watch` for the current value, making it as seen. fn poll_get(&self, id: &mut u64, cx: &mut Context<'_>) -> Poll; - /// Tries to get the value of the `Watch`, marking it as seen. - fn try_get(&self, id: &mut u64) -> Option; + /// Tries to get the value of the `Watch`, marking it as seen, if an id is given. + fn try_get(&self, id: Option<&mut u64>) -> Option; /// Poll the `Watch` for the value if it matches the predicate function /// `f`, making it as seen. @@ -107,9 +96,9 @@ pub trait WatchBehavior { /// Tries to get the value of the `Watch` if it matches the predicate function /// `f`, marking it as seen. - fn try_get_and(&self, id: &mut u64, f: &mut dyn Fn(&T) -> bool) -> Option; + fn try_get_and(&self, id: Option<&mut u64>, f: &mut dyn Fn(&T) -> bool) -> Option; - /// Poll the `Watch` for a changed value, marking it as seen. + /// Poll the `Watch` for a changed value, marking it as seen, if an id is given. fn poll_changed(&self, id: &mut u64, cx: &mut Context<'_>) -> Poll; /// Tries to retrieve the value of the `Watch` if it has changed, marking it as seen. @@ -128,7 +117,11 @@ pub trait WatchBehavior { /// Modify the value of the `Watch` using a closure. Returns `false` if the /// `Watch` does not already contain a value. - fn modify(&self, f: &mut dyn Fn(&mut Option)); + fn send_modify(&self, f: &mut dyn Fn(&mut Option)); + + /// Modify the value of the `Watch` using a closure. Returns `false` if the + /// `Watch` does not already contain a value. + fn send_if_modified(&self, f: &mut dyn Fn(&mut Option) -> bool); /// Used when a receiver is dropped to decrement the receiver count. /// @@ -153,46 +146,6 @@ impl WatchBehavior for Watch }) } - fn poll_peek(&self, cx: &mut Context<'_>) -> Poll { - self.mutex.lock(|state| { - let mut s = state.borrow_mut(); - match &s.data { - Some(data) => Poll::Ready(data.clone()), - None => { - s.wakers.register(cx.waker()); - Poll::Pending - } - } - }) - } - - fn try_peek(&self) -> Option { - self.mutex.lock(|state| state.borrow().data.clone()) - } - - fn poll_peek_and(&self, f: &mut dyn Fn(&T) -> bool, cx: &mut Context<'_>) -> Poll { - self.mutex.lock(|state| { - let mut s = state.borrow_mut(); - match s.data { - Some(ref data) if f(data) => Poll::Ready(data.clone()), - _ => { - s.wakers.register(cx.waker()); - Poll::Pending - } - } - }) - } - - fn try_peek_and(&self, f: &mut dyn Fn(&T) -> bool) -> Option { - self.mutex.lock(|state| { - let s = state.borrow(); - match s.data { - Some(ref data) if f(data) => Some(data.clone()), - _ => None, - } - }) - } - fn poll_get(&self, id: &mut u64, cx: &mut Context<'_>) -> Poll { self.mutex.lock(|state| { let mut s = state.borrow_mut(); @@ -209,11 +162,13 @@ impl WatchBehavior for Watch }) } - fn try_get(&self, id: &mut u64) -> Option { + fn try_get(&self, id: Option<&mut u64>) -> Option { self.mutex.lock(|state| { let s = state.borrow(); - *id = s.current_id; - state.borrow().data.clone() + if let Some(id) = id { + *id = s.current_id; + } + s.data.clone() }) } @@ -233,12 +188,14 @@ impl WatchBehavior for Watch }) } - fn try_get_and(&self, id: &mut u64, f: &mut dyn Fn(&T) -> bool) -> Option { + fn try_get_and(&self, id: Option<&mut u64>, f: &mut dyn Fn(&T) -> bool) -> Option { self.mutex.lock(|state| { let s = state.borrow(); match s.data { Some(ref data) if f(data) => { - *id = s.current_id; + if let Some(id) = id { + *id = s.current_id; + } Some(data.clone()) } _ => None, @@ -315,7 +272,7 @@ impl WatchBehavior for Watch }) } - fn modify(&self, f: &mut dyn Fn(&mut Option)) { + fn send_modify(&self, f: &mut dyn Fn(&mut Option)) { self.mutex.lock(|state| { let mut s = state.borrow_mut(); f(&mut s.data); @@ -323,6 +280,16 @@ impl WatchBehavior for Watch s.wakers.wake(); }) } + + fn send_if_modified(&self, f: &mut dyn Fn(&mut Option) -> bool) { + self.mutex.lock(|state| { + let mut s = state.borrow_mut(); + if f(&mut s.data) { + s.current_id += 1; + s.wakers.wake(); + } + }) + } } impl Watch { @@ -375,6 +342,60 @@ impl Watch { } }) } + + /// Try to create a new [`AnonReceiver`] for the `Watch`. + pub fn anon_receiver(&self) -> AnonReceiver<'_, M, T, N> { + AnonReceiver(AnonRcv::new(self, 0)) + } + + /// Try to create a new [`DynAnonReceiver`] for the `Watch`. + pub fn dyn_anon_receiver(&self) -> DynAnonReceiver<'_, T> { + DynAnonReceiver(AnonRcv::new(self, 0)) + } + + /// Returns the message ID of the latest message sent to the `Watch`. + /// + /// This counter is monotonic, and is incremented every time a new message is sent. + pub fn get_msg_id(&self) -> u64 { + self.mutex.lock(|state| state.borrow().current_id) + } + + /// Waits for the `Watch` to be initialized with a value using a busy-wait mechanism. + /// + /// This is useful for initialization code where receivers may only be interested in + /// awaiting the value once in the lifetime of the program. It is therefore a temporaryily + /// CPU-inefficient operation, while being more memory efficient than using a `Receiver`. + /// + /// **Note** Be careful about using this within an InterruptExecutor, as it will starve + /// tasks in lower-priority executors. + pub async fn spin_get(&self) -> T { + poll_fn(|cx| { + self.mutex.lock(|state| { + let s = state.borrow(); + match &s.data { + Some(data) => Poll::Ready(data.clone()), + None => { + cx.waker().wake_by_ref(); + Poll::Pending + } + } + }) + }) + .await + } + + /// Tries to get the value of the `Watch`. + pub fn try_get(&self) -> Option { + WatchBehavior::try_get(self, None) + } + + /// Tries to get the value of the `Watch` if it matches the predicate function `f`. + pub fn try_get_and(&self, mut f: F) -> Option + where + F: Fn(&T) -> bool, + { + WatchBehavior::try_get_and(self, None, &mut f) + } } /// A receiver can `.await` a change in the `Watch` value. @@ -407,23 +428,23 @@ impl<'a, T: Clone, W: WatchBehavior + ?Sized> Snd<'a, T, W> { } /// Clears the value of the `Watch`. - /// This will cause calls to [`Rcv::get`] and [`Rcv::peek`] to be pending. + /// This will cause calls to [`Rcv::get`] to be pending. pub fn clear(&self) { self.watch.clear() } /// Tries to retrieve the value of the `Watch`. - pub fn try_peek(&self) -> Option { - self.watch.try_peek() + pub fn try_get(&self) -> Option { + self.watch.try_get(None) } /// Tries to peek the current value of the `Watch` if it matches the predicate /// function `f`. - pub fn try_peek_and(&self, mut f: F) -> Option + pub fn try_get_and(&self, mut f: F) -> Option where F: Fn(&T) -> bool, { - self.watch.try_peek_and(&mut f) + self.watch.try_get_and(None, &mut f) } /// Returns true if the `Watch` contains a value. @@ -432,11 +453,20 @@ impl<'a, T: Clone, W: WatchBehavior + ?Sized> Snd<'a, T, W> { } /// Modify the value of the `Watch` using a closure. - pub fn modify(&self, mut f: F) + pub fn send_modify(&self, mut f: F) where F: Fn(&mut Option), { - self.watch.modify(&mut f) + self.watch.send_modify(&mut f) + } + + /// Modify the value of the `Watch` using a closure. The closure must return + /// `true` if the value was modified, which notifies all receivers. + pub fn send_if_modified(&self, mut f: F) + where + F: Fn(&mut Option) -> bool, + { + self.watch.send_if_modified(&mut f) } } @@ -521,38 +551,6 @@ impl<'a, T: Clone, W: WatchBehavior + ?Sized> Rcv<'a, T, W> { } } - /// Returns the current value of the `Watch` once it is initialized, **without** marking it as seen. - /// - /// **Note**: Futures do nothing unless you `.await` or poll them. - pub async fn peek(&self) -> T { - poll_fn(|cx| self.watch.poll_peek(cx)).await - } - - /// Tries to peek the current value of the `Watch` without waiting, and **without** marking it as seen. - pub fn try_peek(&self) -> Option { - self.watch.try_peek() - } - - /// Returns the current value of the `Watch` if it matches the predicate function `f`, - /// or waits for it to match, **without** marking it as seen. - /// - /// **Note**: Futures do nothing unless you `.await` or poll them. - pub async fn peek_and(&self, mut f: F) -> T - where - F: Fn(&T) -> bool, - { - poll_fn(|cx| self.watch.poll_peek_and(&mut f, cx)).await - } - - /// Tries to peek the current value of the `Watch` if it matches the predicate - /// function `f` without waiting, and **without** marking it as seen. - pub fn try_peek_and(&self, mut f: F) -> Option - where - F: Fn(&T) -> bool, - { - self.watch.try_peek_and(&mut f) - } - /// Returns the current value of the `Watch` once it is initialized, marking it as seen. /// /// **Note**: Futures do nothing unless you `.await` or poll them. @@ -562,7 +560,7 @@ impl<'a, T: Clone, W: WatchBehavior + ?Sized> Rcv<'a, T, W> { /// Tries to get the current value of the `Watch` without waiting, marking it as seen. pub fn try_get(&mut self) -> Option { - self.watch.try_get(&mut self.at_id) + self.watch.try_get(Some(&mut self.at_id)) } /// Returns the value of the `Watch` if it matches the predicate function `f`, @@ -582,7 +580,7 @@ impl<'a, T: Clone, W: WatchBehavior + ?Sized> Rcv<'a, T, W> { where F: Fn(&T) -> bool, { - self.watch.try_get_and(&mut self.at_id, &mut f) + self.watch.try_get_and(Some(&mut self.at_id), &mut f) } /// Waits for the `Watch` to change and returns the new value, marking it as seen. @@ -618,7 +616,7 @@ impl<'a, T: Clone, W: WatchBehavior + ?Sized> Rcv<'a, T, W> { } /// Checks if the `Watch` contains a value. If this returns true, - /// then awaiting [`Rcv::get`] and [`Rcv::peek`] will return immediately. + /// then awaiting [`Rcv::get`] will return immediately. pub fn contains_value(&self) -> bool { self.watch.contains_value() } @@ -630,6 +628,58 @@ impl<'a, T: Clone, W: WatchBehavior + ?Sized> Drop for Rcv<'a, T, W> { } } +/// A anonymous receiver can NOT `.await` a change in the `Watch` value. +pub struct AnonRcv<'a, T: Clone, W: WatchBehavior + ?Sized> { + watch: &'a W, + at_id: u64, + _phantom: PhantomData, +} + +impl<'a, T: Clone, W: WatchBehavior + ?Sized> AnonRcv<'a, T, W> { + /// Creates a new `Receiver` with a reference to the `Watch`. + fn new(watch: &'a W, at_id: u64) -> Self { + Self { + watch, + at_id, + _phantom: PhantomData, + } + } + + /// Tries to get the current value of the `Watch` without waiting, marking it as seen. + pub fn try_get(&mut self) -> Option { + self.watch.try_get(Some(&mut self.at_id)) + } + + /// Tries to get the current value of the `Watch` if it matches the predicate + /// function `f` without waiting, marking it as seen. + pub fn try_get_and(&mut self, mut f: F) -> Option + where + F: Fn(&T) -> bool, + { + self.watch.try_get_and(Some(&mut self.at_id), &mut f) + } + + /// Tries to get the new value of the watch without waiting, marking it as seen. + pub fn try_changed(&mut self) -> Option { + self.watch.try_changed(&mut self.at_id) + } + + /// Tries to get the new value of the watch which satisfies the predicate + /// function `f` and returns the new value without waiting, marking it as seen. + pub fn try_changed_and(&mut self, mut f: F) -> Option + where + F: Fn(&T) -> bool, + { + self.watch.try_changed_and(&mut self.at_id, &mut f) + } + + /// Checks if the `Watch` contains a value. If this returns true, + /// then awaiting [`Rcv::get`] will return immediately. + pub fn contains_value(&self) -> bool { + self.watch.contains_value() + } +} + /// A receiver of a `Watch` channel. pub struct Receiver<'a, M: RawMutex, T: Clone, const N: usize>(Rcv<'a, T, Watch>); @@ -682,6 +732,58 @@ impl<'a, T: Clone> DerefMut for DynReceiver<'a, T> { } } +/// A receiver of a `Watch` channel that cannot `.await` values. +pub struct AnonReceiver<'a, M: RawMutex, T: Clone, const N: usize>(AnonRcv<'a, T, Watch>); + +impl<'a, M: RawMutex, T: Clone, const N: usize> AnonReceiver<'a, M, T, N> { + /// Converts the `Receiver` into a [`DynReceiver`]. + pub fn as_dyn(self) -> DynAnonReceiver<'a, T> { + let rcv = DynAnonReceiver(AnonRcv::new(self.0.watch, self.at_id)); + core::mem::forget(self); // Ensures the destructor is not called + rcv + } +} + +impl<'a, M: RawMutex, T: Clone, const N: usize> Into> for AnonReceiver<'a, M, T, N> { + fn into(self) -> DynAnonReceiver<'a, T> { + self.as_dyn() + } +} + +impl<'a, M: RawMutex, T: Clone, const N: usize> Deref for AnonReceiver<'a, M, T, N> { + type Target = AnonRcv<'a, T, Watch>; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl<'a, M: RawMutex, T: Clone, const N: usize> DerefMut for AnonReceiver<'a, M, T, N> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +/// A receiver that cannot `.await` value, which holds a **dynamic** reference to a `Watch` channel. +/// +/// This is an alternative to [`AnonReceiver`] with a simpler type definition, at the expense of +/// some runtime performance due to dynamic dispatch. +pub struct DynAnonReceiver<'a, T: Clone>(AnonRcv<'a, T, dyn WatchBehavior + 'a>); + +impl<'a, T: Clone> Deref for DynAnonReceiver<'a, T> { + type Target = AnonRcv<'a, T, dyn WatchBehavior + 'a>; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl<'a, T: Clone> DerefMut for DynAnonReceiver<'a, T> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + #[cfg(test)] mod tests { use futures_executor::block_on; @@ -715,6 +817,72 @@ mod tests { block_on(f); } + #[test] + fn all_try_get() { + let f = async { + static WATCH: Watch = Watch::new(); + + // Obtain receiver and sender + let mut rcv = WATCH.receiver().unwrap(); + let snd = WATCH.sender(); + + // Not initialized + assert_eq!(WATCH.try_get(), None); + assert_eq!(rcv.try_get(), None); + assert_eq!(snd.try_get(), None); + + // Receive the new value + snd.send(10); + assert_eq!(WATCH.try_get(), Some(10)); + assert_eq!(rcv.try_get(), Some(10)); + assert_eq!(snd.try_get(), Some(10)); + + assert_eq!(WATCH.try_get_and(|x| x > &5), Some(10)); + assert_eq!(rcv.try_get_and(|x| x > &5), Some(10)); + assert_eq!(snd.try_get_and(|x| x > &5), Some(10)); + + assert_eq!(WATCH.try_get_and(|x| x < &5), None); + assert_eq!(rcv.try_get_and(|x| x < &5), None); + assert_eq!(snd.try_get_and(|x| x < &5), None); + }; + block_on(f); + } + + #[test] + fn once_lock_like() { + let f = async { + static CONFIG0: u8 = 10; + static CONFIG1: u8 = 20; + + static WATCH: Watch = Watch::new(); + + // Obtain receiver and sender + let mut rcv = WATCH.receiver().unwrap(); + let snd = WATCH.sender(); + + // Not initialized + assert_eq!(rcv.try_changed(), None); + + // Receive the new value + snd.send(&CONFIG0); + let rcv0 = rcv.changed().await; + assert_eq!(rcv0, &10); + + // Receive another value + snd.send(&CONFIG1); + let rcv1 = rcv.try_changed(); + assert_eq!(rcv1, Some(&20)); + + // No update + assert_eq!(rcv.try_changed(), None); + + // Ensure similarity with original static + assert_eq!(rcv0, &CONFIG0); + assert_eq!(rcv1, Some(&CONFIG1)); + }; + block_on(f); + } + #[test] fn sender_modify() { let f = async { @@ -729,7 +897,7 @@ mod tests { assert_eq!(rcv.try_changed(), Some(10)); // Modify the value inplace - snd.modify(|opt| { + snd.send_modify(|opt| { if let Some(inner) = opt { *inner += 5; } @@ -751,11 +919,6 @@ mod tests { let mut rcv = WATCH.receiver().unwrap(); let snd = WATCH.sender(); - snd.send(10); - assert_eq!(rcv.try_peek_and(|x| x > &5), Some(10)); - assert_eq!(rcv.try_peek_and(|x| x < &5), None); - assert!(rcv.try_changed().is_some()); - snd.send(15); assert_eq!(rcv.try_get_and(|x| x > &5), Some(15)); assert_eq!(rcv.try_get_and(|x| x < &5), None); @@ -771,7 +934,6 @@ mod tests { snd.send(30); assert_eq!(rcv.changed_and(|x| x > &5).await, 30); - assert_eq!(rcv.peek_and(|x| x > &5).await, 30); assert_eq!(rcv.get_and(|x| x > &5).await, 30); }; block_on(f); @@ -825,7 +987,7 @@ mod tests { // Obtain receivers and sender let mut rcv0 = WATCH.receiver().unwrap(); - let mut rcv1 = WATCH.receiver().unwrap(); + let mut rcv1 = WATCH.anon_receiver(); let snd = WATCH.sender(); // No update for both @@ -864,41 +1026,13 @@ mod tests { block_on(f); } - #[test] - fn peek_get_changed() { - let f = async { - static WATCH: Watch = Watch::new(); - - // Obtain receiver and sender - let mut rcv = WATCH.receiver().unwrap(); - let snd = WATCH.sender(); - - // Send a value - snd.send(10); - - // Ensure peek does not mark as seen - assert_eq!(rcv.peek().await, 10); - assert_eq!(rcv.try_changed(), Some(10)); - assert_eq!(rcv.try_changed(), None); - assert_eq!(rcv.try_peek(), Some(10)); - - // Send a value - snd.send(20); - - // Ensure get does mark as seen - assert_eq!(rcv.get().await, 20); - assert_eq!(rcv.try_changed(), None); - assert_eq!(rcv.try_get(), Some(20)); - }; - block_on(f); - } - #[test] fn use_dynamics() { let f = async { static WATCH: Watch = Watch::new(); // Obtain receiver and sender + let mut anon_rcv = WATCH.dyn_anon_receiver(); let mut dyn_rcv = WATCH.dyn_receiver().unwrap(); let dyn_snd = WATCH.dyn_sender(); @@ -906,6 +1040,7 @@ mod tests { dyn_snd.send(10); // Ensure the dynamic receiver receives the value + assert_eq!(anon_rcv.try_changed(), Some(10)); assert_eq!(dyn_rcv.try_changed(), Some(10)); assert_eq!(dyn_rcv.try_changed(), None); }; @@ -918,10 +1053,12 @@ mod tests { static WATCH: Watch = Watch::new(); // Obtain receiver and sender + let anon_rcv = WATCH.anon_receiver(); let rcv = WATCH.receiver().unwrap(); let snd = WATCH.sender(); // Convert to dynamic + let mut dyn_anon_rcv = anon_rcv.as_dyn(); let mut dyn_rcv = rcv.as_dyn(); let dyn_snd = snd.as_dyn(); @@ -929,6 +1066,7 @@ mod tests { dyn_snd.send(10); // Ensure the dynamic receiver receives the value + assert_eq!(dyn_anon_rcv.try_changed(), Some(10)); assert_eq!(dyn_rcv.try_changed(), Some(10)); assert_eq!(dyn_rcv.try_changed(), None); }; From 999807f226623669a9cfc8ca218d3c81f0c04a77 Mon Sep 17 00:00:00 2001 From: Peter Krull Date: Mon, 23 Sep 2024 20:29:50 +0200 Subject: [PATCH 0172/1217] Added SealedWatchBehavior to limit access to core functions --- embassy-sync/src/watch.rs | 137 ++++++++++++++++++++------------------ 1 file changed, 71 insertions(+), 66 deletions(-) diff --git a/embassy-sync/src/watch.rs b/embassy-sync/src/watch.rs index 1b4a8b589..4b7ffa5fc 100644 --- a/embassy-sync/src/watch.rs +++ b/embassy-sync/src/watch.rs @@ -76,28 +76,14 @@ struct WatchState { receiver_count: usize, } -/// A trait representing the 'inner' behavior of the `Watch`. -pub trait WatchBehavior { - /// Sends a new value to the `Watch`. - fn send(&self, val: T); - - /// Clears the value of the `Watch`. - fn clear(&self); - +trait SealedWatchBehavior { /// Poll the `Watch` for the current value, making it as seen. fn poll_get(&self, id: &mut u64, cx: &mut Context<'_>) -> Poll; - /// Tries to get the value of the `Watch`, marking it as seen, if an id is given. - fn try_get(&self, id: Option<&mut u64>) -> Option; - /// Poll the `Watch` for the value if it matches the predicate function /// `f`, making it as seen. fn poll_get_and(&self, id: &mut u64, f: &mut dyn Fn(&T) -> bool, cx: &mut Context<'_>) -> Poll; - /// Tries to get the value of the `Watch` if it matches the predicate function - /// `f`, marking it as seen. - fn try_get_and(&self, id: Option<&mut u64>, f: &mut dyn Fn(&T) -> bool) -> Option; - /// Poll the `Watch` for a changed value, marking it as seen, if an id is given. fn poll_changed(&self, id: &mut u64, cx: &mut Context<'_>) -> Poll; @@ -112,8 +98,16 @@ pub trait WatchBehavior { /// predicate function `f`, marking it as seen. fn try_changed_and(&self, id: &mut u64, f: &mut dyn Fn(&T) -> bool) -> Option; - /// Checks if the `Watch` is been initialized with a value. - fn contains_value(&self) -> bool; + /// Used when a receiver is dropped to decrement the receiver count. + /// + /// ## This method should not be called by the user. + fn drop_receiver(&self); + + /// Clears the value of the `Watch`. + fn clear(&self); + + /// Sends a new value to the `Watch`. + fn send(&self, val: T); /// Modify the value of the `Watch` using a closure. Returns `false` if the /// `Watch` does not already contain a value. @@ -122,30 +116,23 @@ pub trait WatchBehavior { /// Modify the value of the `Watch` using a closure. Returns `false` if the /// `Watch` does not already contain a value. fn send_if_modified(&self, f: &mut dyn Fn(&mut Option) -> bool); - - /// Used when a receiver is dropped to decrement the receiver count. - /// - /// ## This method should not be called by the user. - fn drop_receiver(&self); } -impl WatchBehavior for Watch { - fn send(&self, val: T) { - self.mutex.lock(|state| { - let mut s = state.borrow_mut(); - s.data = Some(val); - s.current_id += 1; - s.wakers.wake(); - }) - } +/// A trait representing the 'inner' behavior of the `Watch`. +#[allow(private_bounds)] +pub trait WatchBehavior: SealedWatchBehavior { + /// Tries to get the value of the `Watch`, marking it as seen, if an id is given. + fn try_get(&self, id: Option<&mut u64>) -> Option; - fn clear(&self) { - self.mutex.lock(|state| { - let mut s = state.borrow_mut(); - s.data = None; - }) - } + /// Tries to get the value of the `Watch` if it matches the predicate function + /// `f`, marking it as seen. + fn try_get_and(&self, id: Option<&mut u64>, f: &mut dyn Fn(&T) -> bool) -> Option; + /// Checks if the `Watch` is been initialized with a value. + fn contains_value(&self) -> bool; +} + +impl SealedWatchBehavior for Watch { fn poll_get(&self, id: &mut u64, cx: &mut Context<'_>) -> Poll { self.mutex.lock(|state| { let mut s = state.borrow_mut(); @@ -162,16 +149,6 @@ impl WatchBehavior for Watch }) } - fn try_get(&self, id: Option<&mut u64>) -> Option { - self.mutex.lock(|state| { - let s = state.borrow(); - if let Some(id) = id { - *id = s.current_id; - } - s.data.clone() - }) - } - fn poll_get_and(&self, id: &mut u64, f: &mut dyn Fn(&T) -> bool, cx: &mut Context<'_>) -> Poll { self.mutex.lock(|state| { let mut s = state.borrow_mut(); @@ -188,21 +165,6 @@ impl WatchBehavior for Watch }) } - fn try_get_and(&self, id: Option<&mut u64>, f: &mut dyn Fn(&T) -> bool) -> Option { - self.mutex.lock(|state| { - let s = state.borrow(); - match s.data { - Some(ref data) if f(data) => { - if let Some(id) = id { - *id = s.current_id; - } - Some(data.clone()) - } - _ => None, - } - }) - } - fn poll_changed(&self, id: &mut u64, cx: &mut Context<'_>) -> Poll { self.mutex.lock(|state| { let mut s = state.borrow_mut(); @@ -261,10 +223,6 @@ impl WatchBehavior for Watch }) } - fn contains_value(&self) -> bool { - self.mutex.lock(|state| state.borrow().data.is_some()) - } - fn drop_receiver(&self) { self.mutex.lock(|state| { let mut s = state.borrow_mut(); @@ -272,6 +230,22 @@ impl WatchBehavior for Watch }) } + fn clear(&self) { + self.mutex.lock(|state| { + let mut s = state.borrow_mut(); + s.data = None; + }) + } + + fn send(&self, val: T) { + self.mutex.lock(|state| { + let mut s = state.borrow_mut(); + s.data = Some(val); + s.current_id += 1; + s.wakers.wake(); + }) + } + fn send_modify(&self, f: &mut dyn Fn(&mut Option)) { self.mutex.lock(|state| { let mut s = state.borrow_mut(); @@ -292,6 +266,37 @@ impl WatchBehavior for Watch } } +impl WatchBehavior for Watch { + fn try_get(&self, id: Option<&mut u64>) -> Option { + self.mutex.lock(|state| { + let s = state.borrow(); + if let Some(id) = id { + *id = s.current_id; + } + s.data.clone() + }) + } + + fn try_get_and(&self, id: Option<&mut u64>, f: &mut dyn Fn(&T) -> bool) -> Option { + self.mutex.lock(|state| { + let s = state.borrow(); + match s.data { + Some(ref data) if f(data) => { + if let Some(id) = id { + *id = s.current_id; + } + Some(data.clone()) + } + _ => None, + } + }) + } + + fn contains_value(&self) -> bool { + self.mutex.lock(|state| state.borrow().data.is_some()) + } +} + impl Watch { /// Create a new `Watch` channel. pub const fn new() -> Self { From 5e1912a2d3adea920039dae3622643f34289290b Mon Sep 17 00:00:00 2001 From: Peter Krull Date: Tue, 24 Sep 2024 12:37:32 +0200 Subject: [PATCH 0173/1217] Reverse generics order, remove spin_get --- embassy-sync/src/watch.rs | 28 ++-------------------------- 1 file changed, 2 insertions(+), 26 deletions(-) diff --git a/embassy-sync/src/watch.rs b/embassy-sync/src/watch.rs index 4b7ffa5fc..336e64ba9 100644 --- a/embassy-sync/src/watch.rs +++ b/embassy-sync/src/watch.rs @@ -66,10 +66,10 @@ use crate::waitqueue::MultiWakerRegistration; /// block_on(f); /// ``` pub struct Watch { - mutex: Mutex>>, + mutex: Mutex>>, } -struct WatchState { +struct WatchState { data: Option, current_id: u64, wakers: MultiWakerRegistration, @@ -365,30 +365,6 @@ impl Watch { self.mutex.lock(|state| state.borrow().current_id) } - /// Waits for the `Watch` to be initialized with a value using a busy-wait mechanism. - /// - /// This is useful for initialization code where receivers may only be interested in - /// awaiting the value once in the lifetime of the program. It is therefore a temporaryily - /// CPU-inefficient operation, while being more memory efficient than using a `Receiver`. - /// - /// **Note** Be careful about using this within an InterruptExecutor, as it will starve - /// tasks in lower-priority executors. - pub async fn spin_get(&self) -> T { - poll_fn(|cx| { - self.mutex.lock(|state| { - let s = state.borrow(); - match &s.data { - Some(data) => Poll::Ready(data.clone()), - None => { - cx.waker().wake_by_ref(); - Poll::Pending - } - } - }) - }) - .await - } - /// Tries to get the value of the `Watch`. pub fn try_get(&self) -> Option { WatchBehavior::try_get(self, None) From 3ce40f41fb25d7e473fc4a9584d6d9273ef08403 Mon Sep 17 00:00:00 2001 From: klownfish Date: Tue, 24 Sep 2024 19:03:20 +0200 Subject: [PATCH 0174/1217] WIP: add u5 adc4 --- embassy-stm32/build.rs | 9 +- embassy-stm32/src/adc/mod.rs | 38 +++ embassy-stm32/src/adc/u5.rs | 16 +- embassy-stm32/src/adc/u5_adc4.rs | 384 +++++++++++++++++++++++++++++++ embassy-stm32/src/lib.rs | 20 ++ 5 files changed, 450 insertions(+), 17 deletions(-) create mode 100644 embassy-stm32/src/adc/u5_adc4.rs diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 19cf193d9..e4cd001e6 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -1188,13 +1188,12 @@ fn main() { // ======== // Generate dma_trait_impl! - let signals: HashMap<_, _> = [ + let mut signals: HashMap<_, _> = [ // (kind, signal) => trait (("adc", "ADC"), quote!(crate::adc::RxDma)), (("adc", "ADC1"), quote!(crate::adc::RxDma)), (("adc", "ADC2"), quote!(crate::adc::RxDma)), (("adc", "ADC3"), quote!(crate::adc::RxDma)), - (("adc", "ADC4"), quote!(crate::adc::RxDma)), (("ucpd", "RX"), quote!(crate::ucpd::RxDma)), (("ucpd", "TX"), quote!(crate::ucpd::TxDma)), (("usart", "RX"), quote!(crate::usart::RxDma)), @@ -1228,6 +1227,12 @@ fn main() { ] .into(); + if chip_name.starts_with("stm32u5") { + signals.insert(("adc", "ADC4"), quote!(crate::adc::RxDma4)); + } else { + signals.insert(("adc", "ADC4"), quote!(crate::adc::RxDma)); + } + for p in METADATA.peripherals { if let Some(regs) = &p.registers { // FIXME: stm32u5a crash on Cordic driver diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index 3bd7c793d..80c942816 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs @@ -25,6 +25,10 @@ pub use _version::*; #[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))] use embassy_sync::waitqueue::AtomicWaker; +#[cfg(adc_u5)] +#[path = "u5_adc4.rs"] +pub mod adc4; + pub use crate::pac::adc::vals; #[cfg(not(any(adc_f1, adc_f3_v2)))] pub use crate::pac::adc::vals::Res as Resolution; @@ -32,6 +36,8 @@ pub use crate::pac::adc::vals::SampleTime; use crate::peripherals; dma_trait!(RxDma, Instance); +#[cfg(adc_u5)] +dma_trait!(RxDma4, adc4::Instance); /// Analog to Digital driver. pub struct Adc<'d, T: Instance> { @@ -159,6 +165,38 @@ impl SealedAdcChannel for AnyAdcChannel { } } +#[cfg(adc_u5)] +foreach_adc!( + (ADC4, $common_inst:ident, $clock:ident) => { + impl crate::adc::adc4::SealedInstance for peripherals::ADC4 { + fn regs() -> crate::pac::adc::Adc4 { + crate::pac::ADC4 + } + } + + impl crate::adc::adc4::Instance for peripherals::ADC4 { + type Interrupt = crate::_generated::peripheral_interrupts::ADC4::GLOBAL; + } + }; + + ($inst:ident, $common_inst:ident, $clock:ident) => { + impl crate::adc::SealedInstance for peripherals::$inst { + fn regs() -> crate::pac::adc::Adc { + crate::pac::$inst + } + + fn common_regs() -> crate::pac::adccommon::AdcCommon { + return crate::pac::$common_inst + } + } + + impl crate::adc::Instance for peripherals::$inst { + type Interrupt = crate::_generated::peripheral_interrupts::$inst::GLOBAL; + } + }; +); + +#[cfg(not(adc_u5))] foreach_adc!( ($inst:ident, $common_inst:ident, $clock:ident) => { impl crate::adc::SealedInstance for peripherals::$inst { diff --git a/embassy-stm32/src/adc/u5.rs b/embassy-stm32/src/adc/u5.rs index a86638a60..314cb02e2 100644 --- a/embassy-stm32/src/adc/u5.rs +++ b/embassy-stm32/src/adc/u5.rs @@ -11,7 +11,7 @@ use crate::{pac, rcc, Peripheral}; const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(55); -const VREF_CHANNEL: u8 = 1; +const VREF_CHANNEL: u8 = 0; const VBAT_CHANNEL: u8 = 18; const TEMP_CHANNEL: u8 = 19; @@ -132,23 +132,9 @@ pub enum Averaging { Samples1024, } -// TODO -// impl Instance for ADC4 { - -// } - impl<'d, T: Instance> Adc<'d, T> { /// Create a new ADC driver. pub fn new(adc: impl Peripheral

+ 'd) -> Self { - // move to u5 init (RCC)? - PWR.svmcr().modify(|w| { - w.set_avm1en(true); - }); - while !PWR.svmsr().read().vdda1rdy() {} - PWR.svmcr().modify(|w| { - w.set_asv(true); - }); - embassy_hal_internal::into_ref!(adc); rcc::enable_and_reset::(); let prescaler = Prescaler::from_ker_ck(T::frequency()); diff --git a/embassy-stm32/src/adc/u5_adc4.rs b/embassy-stm32/src/adc/u5_adc4.rs new file mode 100644 index 000000000..5dec0caa9 --- /dev/null +++ b/embassy-stm32/src/adc/u5_adc4.rs @@ -0,0 +1,384 @@ +pub use crate::pac::adc::vals::Adc4Res as Resolution; +pub use crate::pac::adc::vals::Adc4SampleTime as SampleTime; +pub use crate::pac::adc::vals::Adc4Presc as Presc; +pub use crate::pac::adc::regs::Adc4Chselrmod0; + +#[allow(unused)] +use pac::adc::vals::{Adc4Exten, Adc4OversamplingRatio}; + +use super::{ + blocking_delay_us, AdcChannel, SealedAdcChannel +}; +use crate::time::Hertz; +use crate::{pac, rcc, Peripheral}; + +const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(55); + +/// Default VREF voltage used for sample conversion to millivolts. +pub const VREF_DEFAULT_MV: u32 = 3300; +/// VREF voltage used for factory calibration of VREFINTCAL register. +pub const VREF_CALIB_MV: u32 = 3300; + +const VREF_CHANNEL: u8 = 0; +const VCORE_CHANNEL: u8 = 12; +const TEMP_CHANNEL: u8 = 13; +const VBAT_CHANNEL: u8 = 14; +const DAC_CHANNEL: u8 = 21; + +// NOTE: Vrefint/Temperature/Vbat are not available on all ADCs, this currently cannot be modeled with stm32-data, so these are available from the software on all ADCs +/// Internal voltage reference channel. +pub struct VrefInt; +impl AdcChannel for VrefInt {} +impl SealedAdcChannel for VrefInt { + fn channel(&self) -> u8 { + VREF_CHANNEL + } +} + +/// Internal temperature channel. +pub struct Temperature; +impl AdcChannel for Temperature {} +impl SealedAdcChannel for Temperature { + fn channel(&self) -> u8 { + TEMP_CHANNEL + } +} + +/// Internal battery voltage channel. +pub struct Vbat; +impl AdcChannel for Vbat {} +impl SealedAdcChannel for Vbat { + fn channel(&self) -> u8 { + VBAT_CHANNEL + } +} + +/// Internal DAC channel. +pub struct Dac; +impl AdcChannel for Dac {} +impl SealedAdcChannel for Dac { + fn channel(&self) -> u8 { + DAC_CHANNEL + } +} + +/// Internal Vcore channel. +pub struct Vcore; +impl AdcChannel for Vcore {} +impl SealedAdcChannel for Vcore { + fn channel(&self) -> u8 { + VCORE_CHANNEL + } +} + +pub enum DacChannel { + OUT1, + OUT2 +} + +/// Number of samples used for averaging. +pub enum Averaging { + Disabled, + Samples2, + Samples4, + Samples8, + Samples16, + Samples32, + Samples64, + Samples128, + Samples256, +} + +pub const fn resolution_to_max_count(res: Resolution) -> u32 { + match res { + Resolution::BITS12 => (1 << 12) - 1, + Resolution::BITS10 => (1 << 10) - 1, + Resolution::BITS8 => (1 << 8) - 1, + Resolution::BITS6 => (1 << 6) - 1, + #[allow(unreachable_patterns)] + _ => core::unreachable!(), + } +} + +// NOTE (unused): The prescaler enum closely copies the hardware capabilities, +// but high prescaling doesn't make a lot of sense in the current implementation and is ommited. +#[allow(unused)] +enum Prescaler { + NotDivided, + DividedBy2, + DividedBy4, + DividedBy6, + DividedBy8, + DividedBy10, + DividedBy12, + DividedBy16, + DividedBy32, + DividedBy64, + DividedBy128, + DividedBy256, +} + +impl Prescaler { + fn from_ker_ck(frequency: Hertz) -> Self { + let raw_prescaler = frequency.0 / MAX_ADC_CLK_FREQ.0; + match raw_prescaler { + 0 => Self::NotDivided, + 1 => Self::DividedBy2, + 2..=3 => Self::DividedBy4, + 4..=5 => Self::DividedBy6, + 6..=7 => Self::DividedBy8, + 8..=9 => Self::DividedBy10, + 10..=11 => Self::DividedBy12, + _ => unimplemented!(), + } + } + + fn divisor(&self) -> u32 { + match self { + Prescaler::NotDivided => 1, + Prescaler::DividedBy2 => 2, + Prescaler::DividedBy4 => 4, + Prescaler::DividedBy6 => 6, + Prescaler::DividedBy8 => 8, + Prescaler::DividedBy10 => 10, + Prescaler::DividedBy12 => 12, + Prescaler::DividedBy16 => 16, + Prescaler::DividedBy32 => 32, + Prescaler::DividedBy64 => 64, + Prescaler::DividedBy128 => 128, + Prescaler::DividedBy256 => 256, + } + } + + fn presc(&self) -> Presc { + match self { + Prescaler::NotDivided => Presc::DIV1, + Prescaler::DividedBy2 => Presc::DIV2, + Prescaler::DividedBy4 => Presc::DIV4, + Prescaler::DividedBy6 => Presc::DIV6, + Prescaler::DividedBy8 => Presc::DIV8, + Prescaler::DividedBy10 => Presc::DIV10, + Prescaler::DividedBy12 => Presc::DIV12, + Prescaler::DividedBy16 => Presc::DIV16, + Prescaler::DividedBy32 => Presc::DIV32, + Prescaler::DividedBy64 => Presc::DIV64, + Prescaler::DividedBy128 => Presc::DIV128, + Prescaler::DividedBy256 => Presc::DIV256, + } + } +} + +pub trait SealedInstance { + #[allow(unused)] + fn regs() -> crate::pac::adc::Adc4; +} + +pub trait Instance: SealedInstance + crate::Peripheral

+ crate::rcc::RccPeripheral { + type Interrupt: crate::interrupt::typelevel::Interrupt; +} + +pub struct Adc4<'d, T: Instance> { + adc: crate::PeripheralRef<'d, T>, +} + +impl<'d, T: Instance> Adc4<'d, T> { + /// Create a new ADC driver. + pub fn new(adc: impl Peripheral

+ 'd) -> Self { + embassy_hal_internal::into_ref!(adc); + rcc::enable_and_reset::(); + let prescaler = Prescaler::from_ker_ck(T::frequency()); + + T::regs().ccr().modify(|w| w.set_presc(prescaler.presc())); + + let frequency = Hertz(T::frequency().0 / prescaler.divisor()); + info!("ADC4 frequency set to {} Hz", frequency.0); + + if frequency > MAX_ADC_CLK_FREQ { + panic!("Maximal allowed frequency for ADC4 is {} MHz and it varies with different packages, refer to ST docs for more information.", MAX_ADC_CLK_FREQ.0 / 1_000_000 ); + } + + let mut s = Self { + adc, + }; + + s.power_up(); + + s.calibrate(); + blocking_delay_us(1); + + s.enable(); + s.configure(); + + s + } + + fn power_up(&mut self) { + T::regs().isr().modify(|reg| { + reg.set_ldordy(true); + }); + T::regs().cr().modify(|reg| { + reg.set_advregen(true); + }); + while !T::regs().isr().read().ldordy() { }; + + T::regs().isr().modify(|reg| { + reg.set_ldordy(true); + }); + } + + fn calibrate(&mut self) { + T::regs().cr().modify(|w| w.set_adcal(true)); + while T::regs().cr().read().adcal() {} + T::regs().isr().modify(|w| w.set_eocal(true)); + } + + fn enable(&mut self) { + T::regs().isr().write(|w| w.set_adrdy(true)); + T::regs().cr().modify(|w| w.set_aden(true)); + while !T::regs().isr().read().adrdy() {} + T::regs().isr().write(|w| w.set_adrdy(true)); + } + + fn configure(&mut self) { + // single conversion mode, software trigger + T::regs().cfgr1().modify(|w| { + w.set_cont(false); + w.set_exten(Adc4Exten::DISABLED); + }); + + // only use one channel at the moment + T::regs().smpr().modify(|w| { + for i in 0..24 { + w.set_smpsel(i, false); + } + }); + } + + /// Enable reading the voltage reference internal channel. + pub fn enable_vrefint(&self) -> VrefInt { + T::regs().ccr().modify(|reg| { + reg.set_vrefen(true); + }); + + VrefInt {} + } + + /// Enable reading the temperature internal channel. + pub fn enable_temperature(&self) -> Temperature { + T::regs().ccr().modify(|reg| { + reg.set_vsensesel(true); + }); + + Temperature {} + } + + /// Enable reading the vbat internal channel. + pub fn enable_vbat(&self) -> Vbat { + T::regs().ccr().modify(|reg| { + reg.set_vbaten(true); + }); + + Vbat {} + } + + /// Enable reading the vbat internal channel. + pub fn enable_vcore(&self) -> Vcore { + Vcore {} + } + + /// Enable reading the vbat internal channel. + pub fn enable_dac_channel(&self, dac: DacChannel) -> Dac { + let mux; + match dac { + DacChannel::OUT1 => {mux = false}, + DacChannel::OUT2 => {mux = true} + } + T::regs().or().modify(|w| w.set_chn21sel(mux)); + Dac {} + } + + /// Set the ADC sample time. + pub fn set_sample_time(&mut self, sample_time: SampleTime) { + T::regs().smpr().modify(|w| { + w.set_smp(0, sample_time); + }); + } + + /// Get the ADC sample time. + pub fn sample_time(&self) -> SampleTime { + T::regs().smpr().read().smp(0) + } + + /// Set the ADC resolution. + pub fn set_resolution(&mut self, resolution: Resolution) { + T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into())); + } + + /// Set hardware averaging. + pub fn set_averaging(&mut self, averaging: Averaging) { + let (enable, samples, right_shift) = match averaging { + Averaging::Disabled => (false, Adc4OversamplingRatio::OVERSAMPLE2X, 0), + Averaging::Samples2 => (true, Adc4OversamplingRatio::OVERSAMPLE2X, 1), + Averaging::Samples4 => (true, Adc4OversamplingRatio::OVERSAMPLE4X, 2), + Averaging::Samples8 => (true, Adc4OversamplingRatio::OVERSAMPLE8X, 3), + Averaging::Samples16 => (true, Adc4OversamplingRatio::OVERSAMPLE16X, 4), + Averaging::Samples32 => (true, Adc4OversamplingRatio::OVERSAMPLE32X, 5), + Averaging::Samples64 => (true, Adc4OversamplingRatio::OVERSAMPLE64X, 6), + Averaging::Samples128 => (true, Adc4OversamplingRatio::OVERSAMPLE128X, 7), + Averaging::Samples256 => (true, Adc4OversamplingRatio::OVERSAMPLE256X, 8), + }; + + T::regs().cfgr2().modify(|reg| { + reg.set_ovsr(samples); + reg.set_ovss(right_shift); + reg.set_ovse(enable) + }) + } + + /// Perform a single conversion. + fn convert(&mut self) -> u16 { + T::regs().isr().modify(|reg| { + reg.set_eos(true); + reg.set_eoc(true); + }); + + // Start conversion + T::regs().cr().modify(|reg| { + reg.set_adstart(true); + }); + + while !T::regs().isr().read().eos() { + // spin + } + + T::regs().dr().read().0 as u16 + } + + /// Read an ADC channel. + pub fn blocking_read(&mut self, channel: &mut impl AdcChannel) -> u16 { + self.read_channel(channel) + } + + fn configure_channel(channel: &mut impl AdcChannel) { + channel.setup(); + T::regs().chselrmod0().write_value(Adc4Chselrmod0(0_u32)); + T::regs().chselrmod0().modify(|w| { + w.set_chsel(channel.channel() as usize, true); + }); + } + + fn read_channel(&mut self, channel: &mut impl AdcChannel) -> u16 { + Self::configure_channel(channel); + let ret = self.convert(); + ret + } + + fn cancel_conversions() { + if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() { + T::regs().cr().modify(|reg| { + reg.set_adstp(true); + }); + while T::regs().cr().read().adstart() {} + } + } +} \ No newline at end of file diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 451f595e0..232373087 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -218,6 +218,10 @@ pub struct Config { #[cfg(any(stm32l4, stm32l5, stm32u5))] pub enable_independent_io_supply: bool, + /// On the U5 series all analog peripherals are powere by a separate supply. + #[cfg(stm32u5)] + pub enable_independent_analog_supply: bool, + /// BDMA interrupt priority. /// /// Defaults to P0 (highest). @@ -257,6 +261,8 @@ impl Default for Config { enable_debug_during_sleep: true, #[cfg(any(stm32l4, stm32l5, stm32u5))] enable_independent_io_supply: true, + #[cfg(stm32u5)] + enable_independent_analog_supply: true, #[cfg(bdma)] bdma_interrupt_priority: Priority::P0, #[cfg(dma)] @@ -464,6 +470,20 @@ fn init_hw(config: Config) -> Peripherals { crate::pac::PWR.svmcr().modify(|w| { w.set_io2sv(config.enable_independent_io_supply); }); + if config.enable_independent_analog_supply { + crate::pac::PWR.svmcr().modify(|w| { + w.set_avm1en(true); + }); + while !crate::pac::PWR.svmsr().read().vdda1rdy() {} + crate::pac::PWR.svmcr().modify(|w| { + w.set_asv(true); + }); + } else { + crate::pac::PWR.svmcr().modify(|w| { + w.set_avm1en(false); + w.set_avm2en(false); + }); + } } // dead battery functionality is still present on these From fe868fc1948472666b6d8386a3191a074468a34e Mon Sep 17 00:00:00 2001 From: klownfish Date: Tue, 24 Sep 2024 19:12:41 +0200 Subject: [PATCH 0175/1217] add example for u5 ADC --- examples/stm32u5/src/bin/adc.rs | 69 +++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 examples/stm32u5/src/bin/adc.rs diff --git a/examples/stm32u5/src/bin/adc.rs b/examples/stm32u5/src/bin/adc.rs new file mode 100644 index 000000000..f97facf9e --- /dev/null +++ b/examples/stm32u5/src/bin/adc.rs @@ -0,0 +1,69 @@ +#![no_std] +#![no_main] + + +use defmt::{*}; +use defmt_rtt as _; + +use embassy_stm32::adc; +use embassy_stm32::adc::adc4; +use panic_probe as _; + + +#[embassy_executor::main] +async fn main(spawner: embassy_executor::Spawner) { + let mut config = embassy_stm32::Config::default(); + { + use embassy_stm32::rcc::*; + config.rcc.hsi = true; + + config.rcc.pll1 = Some(Pll { + source: PllSource::HSI, // 16 MHz + prediv: PllPreDiv::DIV1, // 16 MHz + mul: PllMul::MUL10, // 160 MHz + divp: Some(PllDiv::DIV1), // don't care + divq: Some(PllDiv::DIV1), // don't care + divr: Some(PllDiv::DIV1), // 160 MHz + }); + + config.rcc.sys = Sysclk::PLL1_R; + config.rcc.voltage_range = VoltageScale::RANGE1; + config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); // needed for USB + config.rcc.mux.iclksel = mux::Iclksel::HSI48; // USB uses ICLK + + } + + let p = embassy_stm32::init(config); + info!("Hello World!"); + + let mut adc = adc::Adc::new(p.ADC1); + let mut adc_pin = p.PA3; + adc.set_resolution(adc::Resolution::BITS14); + adc.set_averaging(adc::Averaging::Samples1024); + adc.set_sample_time(adc::SampleTime::CYCLES1_5); + + let mut adc2 = adc::Adc::new(p.ADC2); + let mut adc_pin2 = p.PA5; + adc2.set_resolution(adc::Resolution::BITS14); + adc2.set_averaging(adc::Averaging::Samples1024); + adc2.set_sample_time(adc::SampleTime::CYCLES1_5); + + let mut adc4 = adc4::Adc4::new(p.ADC4); + let mut adc_pin4 = p.PD11; + adc4.set_resolution(adc4::Resolution::BITS12); + adc4.set_averaging(adc4::Averaging::Samples256); + adc4.set_sample_time(adc4::SampleTime::CYCLES1_5); + + loop { + embassy_time::Timer::after_millis(100).await; + let raw :u16 = adc.blocking_read(&mut adc_pin); + let max = adc::resolution_to_max_count(adc::Resolution::BITS14); + let volt: f32 = 3.3 * raw as f32 / max as f32; + info!("Read ADC1 {}", volt); + + let raw4 :u16 = adc4.blocking_read(&mut adc_pin4); + let max4 = adc4::resolution_to_max_count(adc4::Resolution::BITS12); + let volt4: f32 = 3.3 * raw4 as f32 / max4 as f32; + info!("Read ADC4 {}", volt4); + } +} \ No newline at end of file From a498bf11af2768b7aca24c3d84d4dfa20711c593 Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Tue, 24 Sep 2024 18:45:20 -0400 Subject: [PATCH 0176/1217] Disable pad isolation on PWM A pins. Also fixes minor bug for 2040 where A pins didn't have their pull up/down enabled. --- embassy-rp/src/pwm.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/embassy-rp/src/pwm.rs b/embassy-rp/src/pwm.rs index 7da3dccb0..9ba3a2be3 100644 --- a/embassy-rp/src/pwm.rs +++ b/embassy-rp/src/pwm.rs @@ -106,6 +106,12 @@ impl<'d> Pwm<'d> { if let Some(pin) = &a { pin.gpio().ctrl().write(|w| w.set_funcsel(4)); + pin.pad_ctrl().modify(|w| { + #[cfg(feature = "_rp235x")] + w.set_iso(false); + w.set_pue(b_pull == Pull::Up); + w.set_pde(b_pull == Pull::Down); + }); } if let Some(pin) = &b { pin.gpio().ctrl().write(|w| w.set_funcsel(4)); From b743dce8e4777a3d1d3c2d1a40501be3af8b07e5 Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Tue, 24 Sep 2024 18:55:05 -0400 Subject: [PATCH 0177/1217] Only B pins can be inputs. --- embassy-rp/src/pwm.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/embassy-rp/src/pwm.rs b/embassy-rp/src/pwm.rs index 9ba3a2be3..027f5504e 100644 --- a/embassy-rp/src/pwm.rs +++ b/embassy-rp/src/pwm.rs @@ -106,11 +106,9 @@ impl<'d> Pwm<'d> { if let Some(pin) = &a { pin.gpio().ctrl().write(|w| w.set_funcsel(4)); + #[cfg(feature = "_rp235x")] pin.pad_ctrl().modify(|w| { - #[cfg(feature = "_rp235x")] w.set_iso(false); - w.set_pue(b_pull == Pull::Up); - w.set_pde(b_pull == Pull::Down); }); } if let Some(pin) = &b { From 8c1b4faae1bd39594e2c331fa4bf9eea3ad22c9e Mon Sep 17 00:00:00 2001 From: klownfish Date: Wed, 25 Sep 2024 01:01:19 +0200 Subject: [PATCH 0178/1217] resuse adc v4 for u5 --- embassy-stm32/src/adc/mod.rs | 3 +- embassy-stm32/src/adc/u5.rs | 350 ----------------------------------- embassy-stm32/src/adc/v4.rs | 19 +- 3 files changed, 19 insertions(+), 353 deletions(-) delete mode 100644 embassy-stm32/src/adc/u5.rs diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index 80c942816..3cf2ca72e 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs @@ -12,9 +12,8 @@ #[cfg_attr(adc_l0, path = "v1.rs")] #[cfg_attr(adc_v2, path = "v2.rs")] #[cfg_attr(any(adc_v3, adc_g0, adc_h5, adc_u0), path = "v3.rs")] -#[cfg_attr(adc_v4, path = "v4.rs")] +#[cfg_attr(any(adc_v4, adc_u5), path = "v4.rs")] #[cfg_attr(adc_g4, path = "g4.rs")] -#[cfg_attr(adc_u5, path = "u5.rs")] mod _version; use core::marker::PhantomData; diff --git a/embassy-stm32/src/adc/u5.rs b/embassy-stm32/src/adc/u5.rs deleted file mode 100644 index 314cb02e2..000000000 --- a/embassy-stm32/src/adc/u5.rs +++ /dev/null @@ -1,350 +0,0 @@ -#[allow(unused)] -use pac::adc::vals::{Difsel, Exten, Pcsel}; -use pac::adccommon::vals::Presc; -use pac::PWR; - -use super::{ - blocking_delay_us, Adc, AdcChannel, Instance, Resolution, SampleTime, SealedAdcChannel -}; -use crate::time::Hertz; -use crate::{pac, rcc, Peripheral}; - -const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(55); - -const VREF_CHANNEL: u8 = 0; -const VBAT_CHANNEL: u8 = 18; -const TEMP_CHANNEL: u8 = 19; - -/// Default VREF voltage used for sample conversion to millivolts. -pub const VREF_DEFAULT_MV: u32 = 3300; -/// VREF voltage used for factory calibration of VREFINTCAL register. -pub const VREF_CALIB_MV: u32 = 3300; - - -// NOTE: Vrefint/Temperature/Vbat are not available on all ADCs, this currently cannot be modeled with stm32-data, so these are available from the software on all ADCs -/// Internal voltage reference channel. -pub struct VrefInt; -impl AdcChannel for VrefInt {} -impl SealedAdcChannel for VrefInt { - fn channel(&self) -> u8 { - VREF_CHANNEL - } -} - -/// Internal temperature channel. -pub struct Temperature; -impl AdcChannel for Temperature {} -impl SealedAdcChannel for Temperature { - fn channel(&self) -> u8 { - TEMP_CHANNEL - } -} - -/// Internal battery voltage channel. -pub struct Vbat; -impl AdcChannel for Vbat {} -impl SealedAdcChannel for Vbat { - fn channel(&self) -> u8 { - VBAT_CHANNEL - } -} - -// NOTE (unused): The prescaler enum closely copies the hardware capabilities, -// but high prescaling doesn't make a lot of sense in the current implementation and is ommited. -#[allow(unused)] -enum Prescaler { - NotDivided, - DividedBy2, - DividedBy4, - DividedBy6, - DividedBy8, - DividedBy10, - DividedBy12, - DividedBy16, - DividedBy32, - DividedBy64, - DividedBy128, - DividedBy256, -} - -impl Prescaler { - fn from_ker_ck(frequency: Hertz) -> Self { - let raw_prescaler = frequency.0 / MAX_ADC_CLK_FREQ.0; - match raw_prescaler { - 0 => Self::NotDivided, - 1 => Self::DividedBy2, - 2..=3 => Self::DividedBy4, - 4..=5 => Self::DividedBy6, - 6..=7 => Self::DividedBy8, - 8..=9 => Self::DividedBy10, - 10..=11 => Self::DividedBy12, - _ => unimplemented!(), - } - } - - fn divisor(&self) -> u32 { - match self { - Prescaler::NotDivided => 1, - Prescaler::DividedBy2 => 2, - Prescaler::DividedBy4 => 4, - Prescaler::DividedBy6 => 6, - Prescaler::DividedBy8 => 8, - Prescaler::DividedBy10 => 10, - Prescaler::DividedBy12 => 12, - Prescaler::DividedBy16 => 16, - Prescaler::DividedBy32 => 32, - Prescaler::DividedBy64 => 64, - Prescaler::DividedBy128 => 128, - Prescaler::DividedBy256 => 256, - } - } - - fn presc(&self) -> Presc { - match self { - Prescaler::NotDivided => Presc::DIV1, - Prescaler::DividedBy2 => Presc::DIV2, - Prescaler::DividedBy4 => Presc::DIV4, - Prescaler::DividedBy6 => Presc::DIV6, - Prescaler::DividedBy8 => Presc::DIV8, - Prescaler::DividedBy10 => Presc::DIV10, - Prescaler::DividedBy12 => Presc::DIV12, - Prescaler::DividedBy16 => Presc::DIV16, - Prescaler::DividedBy32 => Presc::DIV32, - Prescaler::DividedBy64 => Presc::DIV64, - Prescaler::DividedBy128 => Presc::DIV128, - Prescaler::DividedBy256 => Presc::DIV256, - } - } -} - -/// Number of samples used for averaging. -pub enum Averaging { - Disabled, - Samples2, - Samples4, - Samples8, - Samples16, - Samples32, - Samples64, - Samples128, - Samples256, - Samples512, - Samples1024, -} - -impl<'d, T: Instance> Adc<'d, T> { - /// Create a new ADC driver. - pub fn new(adc: impl Peripheral

+ 'd) -> Self { - embassy_hal_internal::into_ref!(adc); - rcc::enable_and_reset::(); - let prescaler = Prescaler::from_ker_ck(T::frequency()); - - T::common_regs().ccr().modify(|w| w.set_presc(prescaler.presc())); - - let frequency = Hertz(T::frequency().0 / prescaler.divisor()); - info!("ADC frequency set to {} Hz", frequency.0); - - if frequency > MAX_ADC_CLK_FREQ { - panic!("Maximal allowed frequency for the ADC is {} MHz and it varies with different packages, refer to ST docs for more information.", MAX_ADC_CLK_FREQ.0 / 1_000_000 ); - } - - let mut s = Self { - adc, - sample_time: SampleTime::from_bits(0), - }; - - s.power_up(); - s.configure_differential_inputs(); - - s.calibrate(); - blocking_delay_us(1); - - s.enable(); - s.configure(); - - s - } - - fn power_up(&mut self) { - T::regs().isr().modify(|reg| { - reg.set_ldordy(true); - }); - T::regs().cr().modify(|reg| { - reg.set_deeppwd(false); - reg.set_advregen(true); - }); - while !T::regs().isr().read().ldordy() { }; - - T::regs().isr().modify(|reg| { - reg.set_ldordy(true); - }); - } - - fn configure_differential_inputs(&mut self) { - T::regs().difsel().modify(|w| { - for n in 0..20 { - w.set_difsel(n, Difsel::SINGLEENDED); - } - }); - } - - fn calibrate(&mut self) { - T::regs().cr().modify(|w| { - w.set_adcallin(true); - w.set_aden(false) - }); - T::regs().calfact().modify(|w| { - w.set_capture_coef(false); - w.set_latch_coef(false) - }); - - T::regs().cr().modify(|w| w.set_adcal(true)); - while T::regs().cr().read().adcal() {} - } - - fn enable(&mut self) { - T::regs().isr().write(|w| w.set_adrdy(true)); - T::regs().cr().modify(|w| w.set_aden(true)); - while !T::regs().isr().read().adrdy() {} - T::regs().isr().write(|w| w.set_adrdy(true)); - } - - fn configure(&mut self) { - // single conversion mode, software trigger - T::regs().cfgr().modify(|w| { - w.set_cont(false); - w.set_exten(Exten::DISABLED); - }); - } - - /// Enable reading the voltage reference internal channel. - pub fn enable_vrefint(&self) -> VrefInt { - T::common_regs().ccr().modify(|reg| { - reg.set_vrefen(true); - }); - - VrefInt {} - } - - /// Enable reading the temperature internal channel. - pub fn enable_temperature(&self) -> Temperature { - T::common_regs().ccr().modify(|reg| { - reg.set_vsenseen(true); - }); - - Temperature {} - } - - /// Enable reading the vbat internal channel. - pub fn enable_vbat(&self) -> Vbat { - T::common_regs().ccr().modify(|reg| { - reg.set_vbaten(true); - }); - - Vbat {} - } - - /// Set the ADC sample time. - pub fn set_sample_time(&mut self, sample_time: SampleTime) { - self.sample_time = sample_time; - } - - /// Get the ADC sample time. - pub fn sample_time(&self) -> SampleTime { - self.sample_time - } - - /// Set the ADC resolution. - pub fn set_resolution(&mut self, resolution: Resolution) { - T::regs().cfgr().modify(|reg| reg.set_res(resolution.into())); - } - - /// Set hardware averaging. - pub fn set_averaging(&mut self, averaging: Averaging) { - let (enable, samples, right_shift) = match averaging { - Averaging::Disabled => (false, 0, 0), - Averaging::Samples2 => (true, 1, 1), - Averaging::Samples4 => (true, 3, 2), - Averaging::Samples8 => (true, 7, 3), - Averaging::Samples16 => (true, 15, 4), - Averaging::Samples32 => (true, 31, 5), - Averaging::Samples64 => (true, 63, 6), - Averaging::Samples128 => (true, 127, 7), - Averaging::Samples256 => (true, 255, 8), - Averaging::Samples512 => (true, 511, 9), - Averaging::Samples1024 => (true, 1023, 10), - }; - - T::regs().cfgr2().modify(|reg| { - reg.set_rovse(enable); - reg.set_osvr(samples); - reg.set_ovss(right_shift); - }) - } - - /// Perform a single conversion. - fn convert(&mut self) -> u16 { - T::regs().isr().modify(|reg| { - reg.set_eos(true); - reg.set_eoc(true); - }); - - // Start conversion - T::regs().cr().modify(|reg| { - reg.set_adstart(true); - }); - - while !T::regs().isr().read().eos() { - // spin - } - - T::regs().dr().read().0 as u16 - } - - /// Read an ADC channel. - pub fn blocking_read(&mut self, channel: &mut impl AdcChannel) -> u16 { - self.read_channel(channel) - } - - fn configure_channel(channel: &mut impl AdcChannel, sample_time: SampleTime) { - channel.setup(); - - let channel = channel.channel(); - - Self::set_channel_sample_time(channel, sample_time); - - T::regs().cfgr2().modify(|w| w.set_lshift(0)); - T::regs() - .pcsel() - .modify(|w| w.set_pcsel(channel as _, Pcsel::PRESELECTED)); - } - - fn read_channel(&mut self, channel: &mut impl AdcChannel) -> u16 { - Self::configure_channel(channel, self.sample_time); - - T::regs().sqr1().modify(|reg| { - reg.set_sq(0, channel.channel()); - reg.set_l(0); - }); - - self.convert() - } - - fn set_channel_sample_time(ch: u8, sample_time: SampleTime) { - let sample_time = sample_time.into(); - if ch <= 9 { - T::regs().smpr(0).modify(|reg| reg.set_smp(ch as _, sample_time)); - } else { - T::regs().smpr(1).modify(|reg| reg.set_smp((ch - 10) as _, sample_time)); - } - } - - fn cancel_conversions() { - if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() { - T::regs().cr().modify(|reg| { - reg.set_adstp(true); - }); - while T::regs().cr().read().adstart() {} - } - } -} \ No newline at end of file diff --git a/embassy-stm32/src/adc/v4.rs b/embassy-stm32/src/adc/v4.rs index 63b5b58ea..d73bdb226 100644 --- a/embassy-stm32/src/adc/v4.rs +++ b/embassy-stm32/src/adc/v4.rs @@ -1,5 +1,9 @@ #[allow(unused)] -use pac::adc::vals::{Adcaldif, Adstp, Boost, Difsel, Dmngt, Exten, Pcsel}; +use pac::adc::vals::{Adstp, Difsel, Exten, Pcsel, Dmngt}; + +#[cfg(not(stm32u5))] +use pac::adc::vals::{Adcaldif, Boost}; + use pac::adccommon::vals::Presc; use super::{ @@ -19,6 +23,9 @@ pub const VREF_CALIB_MV: u32 = 3300; const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(60); #[cfg(stm32h7)] const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(50); +#[cfg(stm32u5)] +const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(55); + #[cfg(stm32g4)] const VREF_CHANNEL: u8 = 18; @@ -31,8 +38,17 @@ const VREF_CHANNEL: u8 = 19; const TEMP_CHANNEL: u8 = 18; // TODO this should be 14 for H7a/b/35 +#[cfg(not(stm32u5))] const VBAT_CHANNEL: u8 = 17; + +#[cfg(stm32u5)] +const VREF_CHANNEL: u8 = 0; +#[cfg(stm32u5)] +const TEMP_CHANNEL: u8 = 19; +#[cfg(stm32u5)] +const VBAT_CHANNEL: u8 = 18; + // NOTE: Vrefint/Temperature/Vbat are not available on all ADCs, this currently cannot be modeled with stm32-data, so these are available from the software on all ADCs /// Internal voltage reference channel. pub struct VrefInt; @@ -209,6 +225,7 @@ impl<'d, T: Instance> Adc<'d, T> { fn calibrate(&mut self) { T::regs().cr().modify(|w| { + #[cfg(not(adc_u5))] w.set_adcaldif(Adcaldif::SINGLEENDED); w.set_adcallin(true); }); From ae5b78b27a9c644850c905c197e216a6cd2ab0b9 Mon Sep 17 00:00:00 2001 From: Anthony Grondin <104731965+AnthonyGrondin@users.noreply.github.com> Date: Mon, 23 Sep 2024 16:30:14 -0400 Subject: [PATCH 0179/1217] feat(embassy-net): Implement `wait_recv_ready()` + `wait_send_ready()` for UdpSocket - Provides `pub async fn wait_recv_ready(&self) -> ()` and `pub fn poll_recv_ready(&self, cx: &mut Context<'_>) -> Poll<()>`. This allows polling / waiting on a socket until it can be read, without dequeuing any packets. - Provides `pub async fn wait_send_ready(&self) -> ()` and `pub fn poll_send_ready(&self, cx: &mut Context<'_> -> Poll<()>` This allows polling / waiting on a socket until it becomes writable. --- embassy-net/src/udp.rs | 53 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/embassy-net/src/udp.rs b/embassy-net/src/udp.rs index 3eb6e2f83..b71037522 100644 --- a/embassy-net/src/udp.rs +++ b/embassy-net/src/udp.rs @@ -103,6 +103,32 @@ impl<'a> UdpSocket<'a> { }) } + /// Wait until the socket becomes readable. + /// + /// A socket is readable when a packet has been received, or when there are queued packets in + /// the buffer. + pub async fn wait_recv_ready(&self) { + poll_fn(move |cx| self.poll_recv_ready(cx)).await + } + + /// Wait until a datagram can be read. + /// + /// When no datagram is readable, this method will return `Poll::Pending` and + /// register the current task to be notified when a datagram is received. + /// + /// When a datagram is received, this method will return `Poll::Ready`. + pub fn poll_recv_ready(&self, cx: &mut Context<'_>) -> Poll<()> { + self.with_mut(|s, _| { + if s.can_recv() { + Poll::Ready(()) + } else { + // socket buffer is empty wait until at least one byte has arrived + s.register_recv_waker(cx.waker()); + Poll::Pending + } + }) + } + /// Receive a datagram. /// /// This method will wait until a datagram is received. @@ -164,6 +190,33 @@ impl<'a> UdpSocket<'a> { .await } + /// Wait until the socket becomes writable. + /// + /// A socket becomes writable when there is space in the buffer, from initial memory or after + /// dispatching datagrams on a full buffer. + pub async fn wait_send_ready(&self) { + poll_fn(move |cx| self.poll_send_ready(cx)).await + } + + /// Wait until a datagram can be sent. + /// + /// When no datagram can be sent (i.e. the buffer is full), this method will return + /// `Poll::Pending` and register the current task to be notified when + /// space is freed in the buffer after a datagram has been dispatched. + /// + /// When a datagram can be sent, this method will return `Poll::Ready`. + pub fn poll_send_ready(&self, cx: &mut Context<'_>) -> Poll<()> { + self.with_mut(|s, _| { + if s.can_send() { + Poll::Ready(()) + } else { + // socket buffer is full wait until a datagram has been dispatched + s.register_send_waker(cx.waker()); + Poll::Pending + } + }) + } + /// Send a datagram to the specified remote endpoint. /// /// This method will wait until the datagram has been sent. From e8da38772641ac19e5ded539144467efc9ed5a7b Mon Sep 17 00:00:00 2001 From: Anthony Grondin <104731965+AnthonyGrondin@users.noreply.github.com> Date: Tue, 24 Sep 2024 10:25:10 -0400 Subject: [PATCH 0180/1217] docs(embassy-net): Update can_send() and may_send() documentation to reflect actual behavior from smoltcp --- embassy-net/src/tcp.rs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/embassy-net/src/tcp.rs b/embassy-net/src/tcp.rs index bcddbc95b..fc66d6192 100644 --- a/embassy-net/src/tcp.rs +++ b/embassy-net/src/tcp.rs @@ -376,11 +376,25 @@ impl<'a> TcpSocket<'a> { self.io.with_mut(|s, _| s.abort()) } - /// Get whether the socket is ready to send data, i.e. whether there is space in the send buffer. + /// Return whether the transmit half of the full-duplex connection is open. + /// + /// This function returns true if it's possible to send data and have it arrive + /// to the remote endpoint. However, it does not make any guarantees about the state + /// of the transmit buffer, and even if it returns true, [write](#method.write) may + /// not be able to enqueue any octets. + /// + /// In terms of the TCP state machine, the socket must be in the `ESTABLISHED` or + /// `CLOSE-WAIT` state. pub fn may_send(&self) -> bool { self.io.with(|s, _| s.may_send()) } + /// Check whether the transmit half of the full-duplex connection is open + /// (see [may_send](#method.may_send)), and the transmit buffer is not full. + pub fn can_send(&self) -> bool { + self.io.with(|s, _| s.can_send()) + } + /// return whether the receive half of the full-duplex connection is open. /// This function returns true if it’s possible to receive data from the remote endpoint. /// It will return true while there is data in the receive buffer, and if there isn’t, From 712fa08363067d0a0e3ff07b3bd0633bee3ba07e Mon Sep 17 00:00:00 2001 From: Anthony Grondin <104731965+AnthonyGrondin@users.noreply.github.com> Date: Tue, 24 Sep 2024 10:42:06 -0400 Subject: [PATCH 0181/1217] feat(embassy-net): Implement `wait_read_ready()` + `wait_write_ready()` for TcpSocket --- embassy-net/src/tcp.rs | 46 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 2 deletions(-) diff --git a/embassy-net/src/tcp.rs b/embassy-net/src/tcp.rs index fc66d6192..8fdad01cc 100644 --- a/embassy-net/src/tcp.rs +++ b/embassy-net/src/tcp.rs @@ -10,7 +10,7 @@ use core::future::poll_fn; use core::mem; -use core::task::Poll; +use core::task::{Context, Poll}; use embassy_time::Duration; use smoltcp::iface::{Interface, SocketHandle}; @@ -274,6 +274,16 @@ impl<'a> TcpSocket<'a> { .await } + /// Wait until the socket becomes readable. + /// + /// A socket becomes readable when the receive half of the full-duplex connection is open + /// (see [may_recv](#method.may_recv)), and there is some pending data in the receive buffer. + /// + /// This is the equivalent of [read](#method.read), without buffering any data. + pub async fn wait_read_ready(&self) { + poll_fn(move |cx| self.io.poll_read_ready(cx)).await + } + /// Read data from the socket. /// /// Returns how many bytes were read, or an error. If no data is available, it waits @@ -285,6 +295,16 @@ impl<'a> TcpSocket<'a> { self.io.read(buf).await } + /// Wait until the socket becomes writable. + /// + /// A socket becomes writable when the transmit half of the full-duplex connection is open + /// (see [may_send](#method.may_send)), and the transmit buffer is not full. + /// + /// This is the equivalent of [write](#method.write), without sending any data. + pub async fn wait_write_ready(&self) { + poll_fn(move |cx| self.io.poll_write_ready(cx)).await + } + /// Write data to the socket. /// /// Returns how many bytes were written, or an error. If the socket is not ready to @@ -441,7 +461,7 @@ impl<'d> TcpIo<'d> { }) } - fn with_mut(&mut self, f: impl FnOnce(&mut tcp::Socket, &mut Interface) -> R) -> R { + fn with_mut(&self, f: impl FnOnce(&mut tcp::Socket, &mut Interface) -> R) -> R { self.stack.with_mut(|i| { let socket = i.sockets.get_mut::(self.handle); let res = f(socket, &mut i.iface); @@ -450,6 +470,17 @@ impl<'d> TcpIo<'d> { }) } + fn poll_read_ready(&self, cx: &mut Context<'_>) -> Poll<()> { + self.with_mut(|s, _| { + if s.can_recv() { + Poll::Ready(()) + } else { + s.register_recv_waker(cx.waker()); + Poll::Pending + } + }) + } + async fn read(&mut self, buf: &mut [u8]) -> Result { poll_fn(move |cx| { // CAUTION: smoltcp semantics around EOF are different to what you'd expect @@ -478,6 +509,17 @@ impl<'d> TcpIo<'d> { .await } + fn poll_write_ready(&self, cx: &mut Context<'_>) -> Poll<()> { + self.with_mut(|s, _| { + if s.can_send() { + Poll::Ready(()) + } else { + s.register_send_waker(cx.waker()); + Poll::Pending + } + }) + } + async fn write(&mut self, buf: &[u8]) -> Result { poll_fn(move |cx| { self.with_mut(|s, _| match s.send_slice(buf) { From 7b45577704c43465587f611da125d86cb3c85207 Mon Sep 17 00:00:00 2001 From: klownfish Date: Wed, 25 Sep 2024 16:55:27 +0200 Subject: [PATCH 0182/1217] fix warnings --- embassy-stm32/src/adc/u5_adc4.rs | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/embassy-stm32/src/adc/u5_adc4.rs b/embassy-stm32/src/adc/u5_adc4.rs index 5dec0caa9..8d0c1abed 100644 --- a/embassy-stm32/src/adc/u5_adc4.rs +++ b/embassy-stm32/src/adc/u5_adc4.rs @@ -178,6 +178,7 @@ pub trait Instance: SealedInstance + crate::Peripheral

+ crate::rcc::R } pub struct Adc4<'d, T: Instance> { + #[allow(unused)] adc: crate::PeripheralRef<'d, T>, } @@ -372,13 +373,4 @@ impl<'d, T: Instance> Adc4<'d, T> { let ret = self.convert(); ret } - - fn cancel_conversions() { - if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() { - T::regs().cr().modify(|reg| { - reg.set_adstp(true); - }); - while T::regs().cr().read().adstart() {} - } - } } \ No newline at end of file From 6e2c5d0b4500762b5a045a166c91f8b0e59db10e Mon Sep 17 00:00:00 2001 From: Romain Reignier Date: Thu, 26 Sep 2024 13:24:50 +0200 Subject: [PATCH 0183/1217] rp23: add missing binary info in linker script See https://github.com/rp-rs/rp-hal/issues/853 And https://github.com/rp-rs/rp-hal/pull/854 --- examples/rp23/memory.x | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/rp23/memory.x b/examples/rp23/memory.x index 777492062..c803896f6 100644 --- a/examples/rp23/memory.x +++ b/examples/rp23/memory.x @@ -31,6 +31,7 @@ SECTIONS { { __start_block_addr = .; KEEP(*(.start_block)); + KEEP(*(.boot_info)); } > FLASH } INSERT AFTER .vector_table; From f19718b4f0400dec4e64d32d649c6b0d9eb554e5 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Thu, 26 Sep 2024 15:41:21 +0200 Subject: [PATCH 0184/1217] Add config option for setting SIM pin --- embassy-net-nrf91/src/context.rs | 12 ++++++++++++ examples/nrf9160/src/bin/modem_tcp_client.rs | 1 + 2 files changed, 13 insertions(+) diff --git a/embassy-net-nrf91/src/context.rs b/embassy-net-nrf91/src/context.rs index 8b45919ef..2dda615c1 100644 --- a/embassy-net-nrf91/src/context.rs +++ b/embassy-net-nrf91/src/context.rs @@ -21,6 +21,8 @@ pub struct Config<'a> { pub auth_prot: AuthProt, /// Credentials. pub auth: Option<(&'a [u8], &'a [u8])>, + /// SIM pin + pub pin: Option<&'a [u8]>, } /// Authentication protocol. @@ -133,6 +135,16 @@ impl<'a> Control<'a> { // info!("RES2: {}", unsafe { core::str::from_utf8_unchecked(&buf[..n]) }); CommandParser::parse(&buf[..n]).expect_identifier(b"OK").finish()?; + if let Some(pin) = config.pin { + let op = CommandBuilder::create_set(&mut cmd, true) + .named("+CPIN") + .with_string_parameter(pin) + .finish() + .map_err(|_| Error::BufferTooSmall)?; + let _ = self.control.at_command(op, &mut buf).await; + // Ignore ERROR which means no pin required + } + Ok(()) } diff --git a/examples/nrf9160/src/bin/modem_tcp_client.rs b/examples/nrf9160/src/bin/modem_tcp_client.rs index 929883884..495ee26dd 100644 --- a/examples/nrf9160/src/bin/modem_tcp_client.rs +++ b/examples/nrf9160/src/bin/modem_tcp_client.rs @@ -163,6 +163,7 @@ async fn main(spawner: Spawner) { apn: b"iot.nat.es", auth_prot: context::AuthProt::Pap, auth: Some((b"orange", b"orange")), + pin: None, }, stack ))); From 3792b14161ded15fe513640d0c1b52f39fb80856 Mon Sep 17 00:00:00 2001 From: Dinu Blanovschi Date: Fri, 27 Sep 2024 10:40:24 +0200 Subject: [PATCH 0185/1217] fix: change duplicate reference to `FirmwareUpdaterConfig::from_linkerfile_blocking` in rustdoc --- embassy-boot/src/firmware_updater/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-boot/src/firmware_updater/mod.rs b/embassy-boot/src/firmware_updater/mod.rs index 4c4f4f10b..4814786bf 100644 --- a/embassy-boot/src/firmware_updater/mod.rs +++ b/embassy-boot/src/firmware_updater/mod.rs @@ -8,7 +8,7 @@ use embedded_storage::nor_flash::{NorFlashError, NorFlashErrorKind}; /// Firmware updater flash configuration holding the two flashes used by the updater /// /// If only a single flash is actually used, then that flash should be partitioned into two partitions before use. -/// The easiest way to do this is to use [`FirmwareUpdaterConfig::from_linkerfile_blocking`] or [`FirmwareUpdaterConfig::from_linkerfile_blocking`] which will partition +/// The easiest way to do this is to use [`FirmwareUpdaterConfig::from_linkerfile`] or [`FirmwareUpdaterConfig::from_linkerfile_blocking`] which will partition /// the provided flash according to symbols defined in the linkerfile. pub struct FirmwareUpdaterConfig { /// The dfu flash partition From bc0180800d751e651c0d15c807285c11cdb4f486 Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Tue, 1 Oct 2024 10:51:18 -0400 Subject: [PATCH 0186/1217] Remove binary_info blocks from most examples. (#3385) --- examples/rp23/src/bin/adc.rs | 12 +----------- examples/rp23/src/bin/adc_dma.rs | 10 ---------- examples/rp23/src/bin/assign_resources.rs | 10 ---------- examples/rp23/src/bin/blinky.rs | 11 +++++++---- examples/rp23/src/bin/blinky_two_channels.rs | 10 ---------- examples/rp23/src/bin/blinky_two_tasks.rs | 10 ---------- examples/rp23/src/bin/button.rs | 10 ---------- examples/rp23/src/bin/debounce.rs | 10 ---------- examples/rp23/src/bin/flash.rs | 10 ---------- examples/rp23/src/bin/gpio_async.rs | 10 ---------- examples/rp23/src/bin/gpout.rs | 10 ---------- examples/rp23/src/bin/i2c_async.rs | 10 ---------- examples/rp23/src/bin/i2c_async_embassy.rs | 10 ---------- examples/rp23/src/bin/i2c_blocking.rs | 10 ---------- examples/rp23/src/bin/i2c_slave.rs | 10 ---------- examples/rp23/src/bin/interrupt.rs | 10 ---------- examples/rp23/src/bin/multicore.rs | 10 ---------- examples/rp23/src/bin/multiprio.rs | 10 ---------- examples/rp23/src/bin/otp.rs | 10 ---------- examples/rp23/src/bin/pio_async.rs | 10 ---------- examples/rp23/src/bin/pio_dma.rs | 10 ---------- examples/rp23/src/bin/pio_hd44780.rs | 10 ---------- examples/rp23/src/bin/pio_i2s.rs | 10 ---------- examples/rp23/src/bin/pio_pwm.rs | 10 ---------- examples/rp23/src/bin/pio_rotary_encoder.rs | 10 ---------- examples/rp23/src/bin/pio_servo.rs | 10 ---------- examples/rp23/src/bin/pio_stepper.rs | 10 ---------- examples/rp23/src/bin/pio_ws2812.rs | 10 ---------- examples/rp23/src/bin/pwm.rs | 10 ---------- examples/rp23/src/bin/pwm_input.rs | 10 ---------- examples/rp23/src/bin/rosc.rs | 10 ---------- examples/rp23/src/bin/shared_bus.rs | 10 ---------- examples/rp23/src/bin/sharing.rs | 10 ---------- examples/rp23/src/bin/spi.rs | 10 ---------- examples/rp23/src/bin/spi_async.rs | 10 ---------- examples/rp23/src/bin/spi_display.rs | 10 ---------- examples/rp23/src/bin/spi_sdmmc.rs | 10 ---------- examples/rp23/src/bin/trng.rs | 10 ---------- examples/rp23/src/bin/uart.rs | 10 ---------- examples/rp23/src/bin/uart_buffered_split.rs | 10 ---------- examples/rp23/src/bin/uart_r503.rs | 10 ---------- examples/rp23/src/bin/uart_unidir.rs | 10 ---------- examples/rp23/src/bin/usb_webusb.rs | 10 ---------- examples/rp23/src/bin/watchdog.rs | 10 ---------- examples/rp23/src/bin/zerocopy.rs | 10 ---------- 45 files changed, 8 insertions(+), 445 deletions(-) diff --git a/examples/rp23/src/bin/adc.rs b/examples/rp23/src/bin/adc.rs index d1f053d39..f7db9653a 100644 --- a/examples/rp23/src/bin/adc.rs +++ b/examples/rp23/src/bin/adc.rs @@ -1,4 +1,4 @@ -//! This example test the ADC (Analog to Digital Conversion) of the RS2040 pin 26, 27 and 28. +//! This example test the ADC (Analog to Digital Conversion) of the RP2350A pins 26, 27 and 28. //! It also reads the temperature sensor in the chip. #![no_std] @@ -17,16 +17,6 @@ use {defmt_rtt as _, panic_probe as _}; #[used] pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); -// Program metadata for `picotool info` -#[link_section = ".bi_entries"] -#[used] -pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info::rp_program_name!(c"example"), - embassy_rp::binary_info::rp_cargo_version!(), - embassy_rp::binary_info::rp_program_description!(c"Blinky"), - embassy_rp::binary_info::rp_program_build_attribute!(), -]; - bind_interrupts!(struct Irqs { ADC_IRQ_FIFO => InterruptHandler; }); diff --git a/examples/rp23/src/bin/adc_dma.rs b/examples/rp23/src/bin/adc_dma.rs index 5046e5530..a6814c23a 100644 --- a/examples/rp23/src/bin/adc_dma.rs +++ b/examples/rp23/src/bin/adc_dma.rs @@ -17,16 +17,6 @@ use {defmt_rtt as _, panic_probe as _}; #[used] pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); -// Program metadata for `picotool info` -#[link_section = ".bi_entries"] -#[used] -pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info::rp_program_name!(c"example"), - embassy_rp::binary_info::rp_cargo_version!(), - embassy_rp::binary_info::rp_program_description!(c"Blinky"), - embassy_rp::binary_info::rp_program_build_attribute!(), -]; - bind_interrupts!(struct Irqs { ADC_IRQ_FIFO => InterruptHandler; }); diff --git a/examples/rp23/src/bin/assign_resources.rs b/examples/rp23/src/bin/assign_resources.rs index 2f9783917..0d4ad8dc3 100644 --- a/examples/rp23/src/bin/assign_resources.rs +++ b/examples/rp23/src/bin/assign_resources.rs @@ -24,16 +24,6 @@ use {defmt_rtt as _, panic_probe as _}; #[used] pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); -// Program metadata for `picotool info` -#[link_section = ".bi_entries"] -#[used] -pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info::rp_program_name!(c"example"), - embassy_rp::binary_info::rp_cargo_version!(), - embassy_rp::binary_info::rp_program_description!(c"Blinky"), - embassy_rp::binary_info::rp_program_build_attribute!(), -]; - #[embassy_executor::main] async fn main(spawner: Spawner) { // initialize the peripherals diff --git a/examples/rp23/src/bin/blinky.rs b/examples/rp23/src/bin/blinky.rs index 9e45679c8..c1ddbb7d2 100644 --- a/examples/rp23/src/bin/blinky.rs +++ b/examples/rp23/src/bin/blinky.rs @@ -17,20 +17,23 @@ use {defmt_rtt as _, panic_probe as _}; #[used] pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); -// Program metadata for `picotool info` +// Program metadata for `picotool info`. +// This isn't needed, but it's recomended to have these minimal entries. #[link_section = ".bi_entries"] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info::rp_program_name!(c"example"), + embassy_rp::binary_info::rp_program_name!(c"Blinky Example"), + embassy_rp::binary_info::rp_program_description!( + c"This example tests the RP Pico on board LED, connected to gpio 25" + ), embassy_rp::binary_info::rp_cargo_version!(), - embassy_rp::binary_info::rp_program_description!(c"Blinky"), embassy_rp::binary_info::rp_program_build_attribute!(), ]; #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_rp::init(Default::default()); - let mut led = Output::new(p.PIN_2, Level::Low); + let mut led = Output::new(p.PIN_25, Level::Low); loop { info!("led on!"); diff --git a/examples/rp23/src/bin/blinky_two_channels.rs b/examples/rp23/src/bin/blinky_two_channels.rs index 87fc58bbc..ce482858e 100644 --- a/examples/rp23/src/bin/blinky_two_channels.rs +++ b/examples/rp23/src/bin/blinky_two_channels.rs @@ -19,16 +19,6 @@ use {defmt_rtt as _, panic_probe as _}; #[used] pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); -// Program metadata for `picotool info` -#[link_section = ".bi_entries"] -#[used] -pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info::rp_program_name!(c"example"), - embassy_rp::binary_info::rp_cargo_version!(), - embassy_rp::binary_info::rp_program_description!(c"Blinky"), - embassy_rp::binary_info::rp_program_build_attribute!(), -]; - enum LedState { Toggle, } diff --git a/examples/rp23/src/bin/blinky_two_tasks.rs b/examples/rp23/src/bin/blinky_two_tasks.rs index 40236c53b..5dc62245d 100644 --- a/examples/rp23/src/bin/blinky_two_tasks.rs +++ b/examples/rp23/src/bin/blinky_two_tasks.rs @@ -19,16 +19,6 @@ use {defmt_rtt as _, panic_probe as _}; #[used] pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); -// Program metadata for `picotool info` -#[link_section = ".bi_entries"] -#[used] -pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info::rp_program_name!(c"example"), - embassy_rp::binary_info::rp_cargo_version!(), - embassy_rp::binary_info::rp_program_description!(c"Blinky"), - embassy_rp::binary_info::rp_program_build_attribute!(), -]; - type LedType = Mutex>>; static LED: LedType = Mutex::new(None); diff --git a/examples/rp23/src/bin/button.rs b/examples/rp23/src/bin/button.rs index fb067a370..85f1bcae3 100644 --- a/examples/rp23/src/bin/button.rs +++ b/examples/rp23/src/bin/button.rs @@ -14,16 +14,6 @@ use {defmt_rtt as _, panic_probe as _}; #[used] pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); -// Program metadata for `picotool info` -#[link_section = ".bi_entries"] -#[used] -pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info::rp_program_name!(c"example"), - embassy_rp::binary_info::rp_cargo_version!(), - embassy_rp::binary_info::rp_program_description!(c"Blinky"), - embassy_rp::binary_info::rp_program_build_attribute!(), -]; - #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_rp::init(Default::default()); diff --git a/examples/rp23/src/bin/debounce.rs b/examples/rp23/src/bin/debounce.rs index e672521ec..4c8b80d92 100644 --- a/examples/rp23/src/bin/debounce.rs +++ b/examples/rp23/src/bin/debounce.rs @@ -15,16 +15,6 @@ use {defmt_rtt as _, panic_probe as _}; #[used] pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); -// Program metadata for `picotool info` -#[link_section = ".bi_entries"] -#[used] -pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info::rp_program_name!(c"example"), - embassy_rp::binary_info::rp_cargo_version!(), - embassy_rp::binary_info::rp_program_description!(c"Blinky"), - embassy_rp::binary_info::rp_program_build_attribute!(), -]; - pub struct Debouncer<'a> { input: Input<'a>, debounce: Duration, diff --git a/examples/rp23/src/bin/flash.rs b/examples/rp23/src/bin/flash.rs index 84011e394..28dec24c9 100644 --- a/examples/rp23/src/bin/flash.rs +++ b/examples/rp23/src/bin/flash.rs @@ -15,16 +15,6 @@ use {defmt_rtt as _, panic_probe as _}; #[used] pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); -// Program metadata for `picotool info` -#[link_section = ".bi_entries"] -#[used] -pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info::rp_program_name!(c"example"), - embassy_rp::binary_info::rp_cargo_version!(), - embassy_rp::binary_info::rp_program_description!(c"Flash"), - embassy_rp::binary_info::rp_program_build_attribute!(), -]; - const ADDR_OFFSET: u32 = 0x100000; const FLASH_SIZE: usize = 2 * 1024 * 1024; diff --git a/examples/rp23/src/bin/gpio_async.rs b/examples/rp23/src/bin/gpio_async.rs index ff12367bf..bfb9a3f95 100644 --- a/examples/rp23/src/bin/gpio_async.rs +++ b/examples/rp23/src/bin/gpio_async.rs @@ -17,16 +17,6 @@ use {defmt_rtt as _, panic_probe as _}; #[used] pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); -// Program metadata for `picotool info` -#[link_section = ".bi_entries"] -#[used] -pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info::rp_program_name!(c"example"), - embassy_rp::binary_info::rp_cargo_version!(), - embassy_rp::binary_info::rp_program_description!(c"Blinky"), - embassy_rp::binary_info::rp_program_build_attribute!(), -]; - /// It requires an external signal to be manually triggered on PIN 16. For /// example, this could be accomplished using an external power source with a /// button so that it is possible to toggle the signal from low to high. diff --git a/examples/rp23/src/bin/gpout.rs b/examples/rp23/src/bin/gpout.rs index d2ee55197..3cc2ea938 100644 --- a/examples/rp23/src/bin/gpout.rs +++ b/examples/rp23/src/bin/gpout.rs @@ -16,16 +16,6 @@ use {defmt_rtt as _, panic_probe as _}; #[used] pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); -// Program metadata for `picotool info` -#[link_section = ".bi_entries"] -#[used] -pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info::rp_program_name!(c"example"), - embassy_rp::binary_info::rp_cargo_version!(), - embassy_rp::binary_info::rp_program_description!(c"Blinky"), - embassy_rp::binary_info::rp_program_build_attribute!(), -]; - #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_rp::init(Default::default()); diff --git a/examples/rp23/src/bin/i2c_async.rs b/examples/rp23/src/bin/i2c_async.rs index c8d918b56..b30088bae 100644 --- a/examples/rp23/src/bin/i2c_async.rs +++ b/examples/rp23/src/bin/i2c_async.rs @@ -20,16 +20,6 @@ use {defmt_rtt as _, panic_probe as _}; #[used] pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); -// Program metadata for `picotool info` -#[link_section = ".bi_entries"] -#[used] -pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info::rp_program_name!(c"example"), - embassy_rp::binary_info::rp_cargo_version!(), - embassy_rp::binary_info::rp_program_description!(c"Blinky"), - embassy_rp::binary_info::rp_program_build_attribute!(), -]; - bind_interrupts!(struct Irqs { I2C1_IRQ => InterruptHandler; }); diff --git a/examples/rp23/src/bin/i2c_async_embassy.rs b/examples/rp23/src/bin/i2c_async_embassy.rs index cce0abcde..c783a80c5 100644 --- a/examples/rp23/src/bin/i2c_async_embassy.rs +++ b/examples/rp23/src/bin/i2c_async_embassy.rs @@ -15,16 +15,6 @@ use {defmt_rtt as _, panic_probe as _}; #[used] pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); -// Program metadata for `picotool info` -#[link_section = ".bi_entries"] -#[used] -pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info::rp_program_name!(c"example"), - embassy_rp::binary_info::rp_cargo_version!(), - embassy_rp::binary_info::rp_program_description!(c"Blinky"), - embassy_rp::binary_info::rp_program_build_attribute!(), -]; - // Our anonymous hypotetical temperature sensor could be: // a 12-bit sensor, with 100ms startup time, range of -40*C - 125*C, and precision 0.25*C // It requires no configuration or calibration, works with all i2c bus speeds, diff --git a/examples/rp23/src/bin/i2c_blocking.rs b/examples/rp23/src/bin/i2c_blocking.rs index 85c33bf0d..a68677311 100644 --- a/examples/rp23/src/bin/i2c_blocking.rs +++ b/examples/rp23/src/bin/i2c_blocking.rs @@ -18,16 +18,6 @@ use {defmt_rtt as _, panic_probe as _}; #[used] pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); -// Program metadata for `picotool info` -#[link_section = ".bi_entries"] -#[used] -pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info::rp_program_name!(c"example"), - embassy_rp::binary_info::rp_cargo_version!(), - embassy_rp::binary_info::rp_program_description!(c"Blinky"), - embassy_rp::binary_info::rp_program_build_attribute!(), -]; - #[allow(dead_code)] mod mcp23017 { pub const ADDR: u8 = 0x20; // default addr diff --git a/examples/rp23/src/bin/i2c_slave.rs b/examples/rp23/src/bin/i2c_slave.rs index fb5f3cda1..8817538c0 100644 --- a/examples/rp23/src/bin/i2c_slave.rs +++ b/examples/rp23/src/bin/i2c_slave.rs @@ -15,16 +15,6 @@ use {defmt_rtt as _, panic_probe as _}; #[used] pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); -// Program metadata for `picotool info` -#[link_section = ".bi_entries"] -#[used] -pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info::rp_program_name!(c"example"), - embassy_rp::binary_info::rp_cargo_version!(), - embassy_rp::binary_info::rp_program_description!(c"Blinky"), - embassy_rp::binary_info::rp_program_build_attribute!(), -]; - bind_interrupts!(struct Irqs { I2C0_IRQ => i2c::InterruptHandler; I2C1_IRQ => i2c::InterruptHandler; diff --git a/examples/rp23/src/bin/interrupt.rs b/examples/rp23/src/bin/interrupt.rs index ee3d9bfe7..d9b662253 100644 --- a/examples/rp23/src/bin/interrupt.rs +++ b/examples/rp23/src/bin/interrupt.rs @@ -29,16 +29,6 @@ use {defmt_rtt as _, panic_probe as _}; #[used] pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); -// Program metadata for `picotool info` -#[link_section = ".bi_entries"] -#[used] -pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info::rp_program_name!(c"example"), - embassy_rp::binary_info::rp_cargo_version!(), - embassy_rp::binary_info::rp_program_description!(c"Blinky"), - embassy_rp::binary_info::rp_program_build_attribute!(), -]; - static COUNTER: AtomicU32 = AtomicU32::new(0); static PWM: Mutex>> = Mutex::new(RefCell::new(None)); static ADC: Mutex, adc::Channel)>>> = diff --git a/examples/rp23/src/bin/multicore.rs b/examples/rp23/src/bin/multicore.rs index 9ab43d7a5..d4d470fa2 100644 --- a/examples/rp23/src/bin/multicore.rs +++ b/examples/rp23/src/bin/multicore.rs @@ -20,16 +20,6 @@ use {defmt_rtt as _, panic_probe as _}; #[used] pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); -// Program metadata for `picotool info` -#[link_section = ".bi_entries"] -#[used] -pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info::rp_program_name!(c"example"), - embassy_rp::binary_info::rp_cargo_version!(), - embassy_rp::binary_info::rp_program_description!(c"Blinky"), - embassy_rp::binary_info::rp_program_build_attribute!(), -]; - static mut CORE1_STACK: Stack<4096> = Stack::new(); static EXECUTOR0: StaticCell = StaticCell::new(); static EXECUTOR1: StaticCell = StaticCell::new(); diff --git a/examples/rp23/src/bin/multiprio.rs b/examples/rp23/src/bin/multiprio.rs index 27cd3656e..787854aa9 100644 --- a/examples/rp23/src/bin/multiprio.rs +++ b/examples/rp23/src/bin/multiprio.rs @@ -70,16 +70,6 @@ use {defmt_rtt as _, panic_probe as _}; #[used] pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); -// Program metadata for `picotool info` -#[link_section = ".bi_entries"] -#[used] -pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info::rp_program_name!(c"example"), - embassy_rp::binary_info::rp_cargo_version!(), - embassy_rp::binary_info::rp_program_description!(c"Blinky"), - embassy_rp::binary_info::rp_program_build_attribute!(), -]; - #[embassy_executor::task] async fn run_high() { loop { diff --git a/examples/rp23/src/bin/otp.rs b/examples/rp23/src/bin/otp.rs index 106e514ca..c67c9821a 100644 --- a/examples/rp23/src/bin/otp.rs +++ b/examples/rp23/src/bin/otp.rs @@ -14,16 +14,6 @@ use {defmt_rtt as _, panic_probe as _}; #[used] pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); -// Program metadata for `picotool info` -#[link_section = ".bi_entries"] -#[used] -pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info::rp_program_name!(c"OTP Read Example"), - embassy_rp::binary_info::rp_cargo_version!(), - embassy_rp::binary_info::rp_program_description!(c"OTP Read Example"), - embassy_rp::binary_info::rp_program_build_attribute!(), -]; - #[embassy_executor::main] async fn main(_spawner: Spawner) { let _ = embassy_rp::init(Default::default()); diff --git a/examples/rp23/src/bin/pio_async.rs b/examples/rp23/src/bin/pio_async.rs index 231afc80e..896447e28 100644 --- a/examples/rp23/src/bin/pio_async.rs +++ b/examples/rp23/src/bin/pio_async.rs @@ -16,16 +16,6 @@ use {defmt_rtt as _, panic_probe as _}; #[used] pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); -// Program metadata for `picotool info` -#[link_section = ".bi_entries"] -#[used] -pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info::rp_program_name!(c"example"), - embassy_rp::binary_info::rp_cargo_version!(), - embassy_rp::binary_info::rp_program_description!(c"Blinky"), - embassy_rp::binary_info::rp_program_build_attribute!(), -]; - bind_interrupts!(struct Irqs { PIO0_IRQ_0 => InterruptHandler; }); diff --git a/examples/rp23/src/bin/pio_dma.rs b/examples/rp23/src/bin/pio_dma.rs index 60fbcb83a..b5f754798 100644 --- a/examples/rp23/src/bin/pio_dma.rs +++ b/examples/rp23/src/bin/pio_dma.rs @@ -17,16 +17,6 @@ use {defmt_rtt as _, panic_probe as _}; #[used] pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); -// Program metadata for `picotool info` -#[link_section = ".bi_entries"] -#[used] -pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info::rp_program_name!(c"example"), - embassy_rp::binary_info::rp_cargo_version!(), - embassy_rp::binary_info::rp_program_description!(c"Blinky"), - embassy_rp::binary_info::rp_program_build_attribute!(), -]; - bind_interrupts!(struct Irqs { PIO0_IRQ_0 => InterruptHandler; }); diff --git a/examples/rp23/src/bin/pio_hd44780.rs b/examples/rp23/src/bin/pio_hd44780.rs index 92aa858f9..5a6d7a9c5 100644 --- a/examples/rp23/src/bin/pio_hd44780.rs +++ b/examples/rp23/src/bin/pio_hd44780.rs @@ -22,16 +22,6 @@ use {defmt_rtt as _, panic_probe as _}; #[used] pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); -// Program metadata for `picotool info` -#[link_section = ".bi_entries"] -#[used] -pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info::rp_program_name!(c"example"), - embassy_rp::binary_info::rp_cargo_version!(), - embassy_rp::binary_info::rp_program_description!(c"Blinky"), - embassy_rp::binary_info::rp_program_build_attribute!(), -]; - bind_interrupts!(pub struct Irqs { PIO0_IRQ_0 => InterruptHandler; }); diff --git a/examples/rp23/src/bin/pio_i2s.rs b/examples/rp23/src/bin/pio_i2s.rs index d6d2d0ade..46e5eac88 100644 --- a/examples/rp23/src/bin/pio_i2s.rs +++ b/examples/rp23/src/bin/pio_i2s.rs @@ -25,16 +25,6 @@ use {defmt_rtt as _, panic_probe as _}; #[used] pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); -// Program metadata for `picotool info` -#[link_section = ".bi_entries"] -#[used] -pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info::rp_program_name!(c"example"), - embassy_rp::binary_info::rp_cargo_version!(), - embassy_rp::binary_info::rp_program_description!(c"Blinky"), - embassy_rp::binary_info::rp_program_build_attribute!(), -]; - bind_interrupts!(struct Irqs { PIO0_IRQ_0 => InterruptHandler; }); diff --git a/examples/rp23/src/bin/pio_pwm.rs b/examples/rp23/src/bin/pio_pwm.rs index 587f91ac3..3cffd213d 100644 --- a/examples/rp23/src/bin/pio_pwm.rs +++ b/examples/rp23/src/bin/pio_pwm.rs @@ -18,16 +18,6 @@ use {defmt_rtt as _, panic_probe as _}; #[used] pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); -// Program metadata for `picotool info` -#[link_section = ".bi_entries"] -#[used] -pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info::rp_program_name!(c"example"), - embassy_rp::binary_info::rp_cargo_version!(), - embassy_rp::binary_info::rp_program_description!(c"Blinky"), - embassy_rp::binary_info::rp_program_build_attribute!(), -]; - const REFRESH_INTERVAL: u64 = 20000; bind_interrupts!(struct Irqs { diff --git a/examples/rp23/src/bin/pio_rotary_encoder.rs b/examples/rp23/src/bin/pio_rotary_encoder.rs index c147351e8..9542d63b7 100644 --- a/examples/rp23/src/bin/pio_rotary_encoder.rs +++ b/examples/rp23/src/bin/pio_rotary_encoder.rs @@ -17,16 +17,6 @@ use {defmt_rtt as _, panic_probe as _}; #[used] pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); -// Program metadata for `picotool info` -#[link_section = ".bi_entries"] -#[used] -pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info::rp_program_name!(c"example"), - embassy_rp::binary_info::rp_cargo_version!(), - embassy_rp::binary_info::rp_program_description!(c"Blinky"), - embassy_rp::binary_info::rp_program_build_attribute!(), -]; - bind_interrupts!(struct Irqs { PIO0_IRQ_0 => InterruptHandler; }); diff --git a/examples/rp23/src/bin/pio_servo.rs b/examples/rp23/src/bin/pio_servo.rs index 5e8714178..3202ab475 100644 --- a/examples/rp23/src/bin/pio_servo.rs +++ b/examples/rp23/src/bin/pio_servo.rs @@ -18,16 +18,6 @@ use {defmt_rtt as _, panic_probe as _}; #[used] pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); -// Program metadata for `picotool info` -#[link_section = ".bi_entries"] -#[used] -pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info::rp_program_name!(c"example"), - embassy_rp::binary_info::rp_cargo_version!(), - embassy_rp::binary_info::rp_program_description!(c"Blinky"), - embassy_rp::binary_info::rp_program_build_attribute!(), -]; - const DEFAULT_MIN_PULSE_WIDTH: u64 = 1000; // uncalibrated default, the shortest duty cycle sent to a servo const DEFAULT_MAX_PULSE_WIDTH: u64 = 2000; // uncalibrated default, the longest duty cycle sent to a servo const DEFAULT_MAX_DEGREE_ROTATION: u64 = 160; // 160 degrees is typical diff --git a/examples/rp23/src/bin/pio_stepper.rs b/examples/rp23/src/bin/pio_stepper.rs index 24785443b..5e87da6eb 100644 --- a/examples/rp23/src/bin/pio_stepper.rs +++ b/examples/rp23/src/bin/pio_stepper.rs @@ -21,16 +21,6 @@ use {defmt_rtt as _, panic_probe as _}; #[used] pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); -// Program metadata for `picotool info` -#[link_section = ".bi_entries"] -#[used] -pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info::rp_program_name!(c"example"), - embassy_rp::binary_info::rp_cargo_version!(), - embassy_rp::binary_info::rp_program_description!(c"Blinky"), - embassy_rp::binary_info::rp_program_build_attribute!(), -]; - bind_interrupts!(struct Irqs { PIO0_IRQ_0 => InterruptHandler; }); diff --git a/examples/rp23/src/bin/pio_ws2812.rs b/examples/rp23/src/bin/pio_ws2812.rs index 00fe5e396..1f1984c4d 100644 --- a/examples/rp23/src/bin/pio_ws2812.rs +++ b/examples/rp23/src/bin/pio_ws2812.rs @@ -23,16 +23,6 @@ use {defmt_rtt as _, panic_probe as _}; #[used] pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); -// Program metadata for `picotool info` -#[link_section = ".bi_entries"] -#[used] -pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info::rp_program_name!(c"example"), - embassy_rp::binary_info::rp_cargo_version!(), - embassy_rp::binary_info::rp_program_description!(c"Blinky"), - embassy_rp::binary_info::rp_program_build_attribute!(), -]; - bind_interrupts!(struct Irqs { PIO0_IRQ_0 => InterruptHandler; }); diff --git a/examples/rp23/src/bin/pwm.rs b/examples/rp23/src/bin/pwm.rs index bfc2c6f67..15eae09ee 100644 --- a/examples/rp23/src/bin/pwm.rs +++ b/examples/rp23/src/bin/pwm.rs @@ -16,16 +16,6 @@ use {defmt_rtt as _, panic_probe as _}; #[used] pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); -// Program metadata for `picotool info` -#[link_section = ".bi_entries"] -#[used] -pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info::rp_program_name!(c"example"), - embassy_rp::binary_info::rp_cargo_version!(), - embassy_rp::binary_info::rp_program_description!(c"Blinky"), - embassy_rp::binary_info::rp_program_build_attribute!(), -]; - #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_rp::init(Default::default()); diff --git a/examples/rp23/src/bin/pwm_input.rs b/examples/rp23/src/bin/pwm_input.rs index b65f2778b..ef87fe8b5 100644 --- a/examples/rp23/src/bin/pwm_input.rs +++ b/examples/rp23/src/bin/pwm_input.rs @@ -15,16 +15,6 @@ use {defmt_rtt as _, panic_probe as _}; #[used] pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); -// Program metadata for `picotool info` -#[link_section = ".bi_entries"] -#[used] -pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info::rp_program_name!(c"example"), - embassy_rp::binary_info::rp_cargo_version!(), - embassy_rp::binary_info::rp_program_description!(c"Blinky"), - embassy_rp::binary_info::rp_program_build_attribute!(), -]; - #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_rp::init(Default::default()); diff --git a/examples/rp23/src/bin/rosc.rs b/examples/rp23/src/bin/rosc.rs index f65b236b1..a096f0b7a 100644 --- a/examples/rp23/src/bin/rosc.rs +++ b/examples/rp23/src/bin/rosc.rs @@ -17,16 +17,6 @@ use {defmt_rtt as _, panic_probe as _}; #[used] pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); -// Program metadata for `picotool info` -#[link_section = ".bi_entries"] -#[used] -pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info::rp_program_name!(c"example"), - embassy_rp::binary_info::rp_cargo_version!(), - embassy_rp::binary_info::rp_program_description!(c"Blinky"), - embassy_rp::binary_info::rp_program_build_attribute!(), -]; - #[embassy_executor::main] async fn main(_spawner: Spawner) { let mut config = embassy_rp::config::Config::default(); diff --git a/examples/rp23/src/bin/shared_bus.rs b/examples/rp23/src/bin/shared_bus.rs index b3fde13e3..2151ccb56 100644 --- a/examples/rp23/src/bin/shared_bus.rs +++ b/examples/rp23/src/bin/shared_bus.rs @@ -23,16 +23,6 @@ use {defmt_rtt as _, panic_probe as _}; #[used] pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); -// Program metadata for `picotool info` -#[link_section = ".bi_entries"] -#[used] -pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info::rp_program_name!(c"example"), - embassy_rp::binary_info::rp_cargo_version!(), - embassy_rp::binary_info::rp_program_description!(c"Blinky"), - embassy_rp::binary_info::rp_program_build_attribute!(), -]; - type Spi1Bus = Mutex>; type I2c1Bus = Mutex>; diff --git a/examples/rp23/src/bin/sharing.rs b/examples/rp23/src/bin/sharing.rs index 4a3301cfd..68eb5d133 100644 --- a/examples/rp23/src/bin/sharing.rs +++ b/examples/rp23/src/bin/sharing.rs @@ -36,16 +36,6 @@ use {defmt_rtt as _, panic_probe as _}; #[used] pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); -// Program metadata for `picotool info` -#[link_section = ".bi_entries"] -#[used] -pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info::rp_program_name!(c"example"), - embassy_rp::binary_info::rp_cargo_version!(), - embassy_rp::binary_info::rp_program_description!(c"Blinky"), - embassy_rp::binary_info::rp_program_build_attribute!(), -]; - type UartAsyncMutex = mutex::Mutex>; struct MyType { diff --git a/examples/rp23/src/bin/spi.rs b/examples/rp23/src/bin/spi.rs index 924873e60..aacb8c7db 100644 --- a/examples/rp23/src/bin/spi.rs +++ b/examples/rp23/src/bin/spi.rs @@ -17,16 +17,6 @@ use {defmt_rtt as _, panic_probe as _}; #[used] pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); -// Program metadata for `picotool info` -#[link_section = ".bi_entries"] -#[used] -pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info::rp_program_name!(c"example"), - embassy_rp::binary_info::rp_cargo_version!(), - embassy_rp::binary_info::rp_program_description!(c"Blinky"), - embassy_rp::binary_info::rp_program_build_attribute!(), -]; - #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_rp::init(Default::default()); diff --git a/examples/rp23/src/bin/spi_async.rs b/examples/rp23/src/bin/spi_async.rs index 4a74f991c..ac7f02fa8 100644 --- a/examples/rp23/src/bin/spi_async.rs +++ b/examples/rp23/src/bin/spi_async.rs @@ -15,16 +15,6 @@ use {defmt_rtt as _, panic_probe as _}; #[used] pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); -// Program metadata for `picotool info` -#[link_section = ".bi_entries"] -#[used] -pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info::rp_program_name!(c"example"), - embassy_rp::binary_info::rp_cargo_version!(), - embassy_rp::binary_info::rp_program_description!(c"Blinky"), - embassy_rp::binary_info::rp_program_build_attribute!(), -]; - #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_rp::init(Default::default()); diff --git a/examples/rp23/src/bin/spi_display.rs b/examples/rp23/src/bin/spi_display.rs index 71dd84658..195db5a97 100644 --- a/examples/rp23/src/bin/spi_display.rs +++ b/examples/rp23/src/bin/spi_display.rs @@ -32,16 +32,6 @@ use {defmt_rtt as _, panic_probe as _}; #[used] pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); -// Program metadata for `picotool info` -#[link_section = ".bi_entries"] -#[used] -pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info::rp_program_name!(c"example"), - embassy_rp::binary_info::rp_cargo_version!(), - embassy_rp::binary_info::rp_program_description!(c"Blinky"), - embassy_rp::binary_info::rp_program_build_attribute!(), -]; - use crate::my_display_interface::SPIDeviceInterface; use crate::touch::Touch; diff --git a/examples/rp23/src/bin/spi_sdmmc.rs b/examples/rp23/src/bin/spi_sdmmc.rs index dabf41ab8..aa6b44ffa 100644 --- a/examples/rp23/src/bin/spi_sdmmc.rs +++ b/examples/rp23/src/bin/spi_sdmmc.rs @@ -21,16 +21,6 @@ use {defmt_rtt as _, panic_probe as _}; #[used] pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); -// Program metadata for `picotool info` -#[link_section = ".bi_entries"] -#[used] -pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info::rp_program_name!(c"example"), - embassy_rp::binary_info::rp_cargo_version!(), - embassy_rp::binary_info::rp_program_description!(c"Blinky"), - embassy_rp::binary_info::rp_program_build_attribute!(), -]; - struct DummyTimesource(); impl embedded_sdmmc::TimeSource for DummyTimesource { diff --git a/examples/rp23/src/bin/trng.rs b/examples/rp23/src/bin/trng.rs index e146baa2e..8251ebd8b 100644 --- a/examples/rp23/src/bin/trng.rs +++ b/examples/rp23/src/bin/trng.rs @@ -18,16 +18,6 @@ use {defmt_rtt as _, panic_probe as _}; #[used] pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); -// Program metadata for `picotool info` -#[link_section = ".bi_entries"] -#[used] -pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info::rp_program_name!(c"example"), - embassy_rp::binary_info::rp_cargo_version!(), - embassy_rp::binary_info::rp_program_description!(c"Blinky"), - embassy_rp::binary_info::rp_program_build_attribute!(), -]; - bind_interrupts!(struct Irqs { TRNG_IRQ => embassy_rp::trng::InterruptHandler; }); diff --git a/examples/rp23/src/bin/uart.rs b/examples/rp23/src/bin/uart.rs index 0ffe0b293..fe28bb046 100644 --- a/examples/rp23/src/bin/uart.rs +++ b/examples/rp23/src/bin/uart.rs @@ -16,16 +16,6 @@ use {defmt_rtt as _, panic_probe as _}; #[used] pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); -// Program metadata for `picotool info` -#[link_section = ".bi_entries"] -#[used] -pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info::rp_program_name!(c"example"), - embassy_rp::binary_info::rp_cargo_version!(), - embassy_rp::binary_info::rp_program_description!(c"Blinky"), - embassy_rp::binary_info::rp_program_build_attribute!(), -]; - #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_rp::init(Default::default()); diff --git a/examples/rp23/src/bin/uart_buffered_split.rs b/examples/rp23/src/bin/uart_buffered_split.rs index 4e69a20c4..9ed130727 100644 --- a/examples/rp23/src/bin/uart_buffered_split.rs +++ b/examples/rp23/src/bin/uart_buffered_split.rs @@ -22,16 +22,6 @@ use {defmt_rtt as _, panic_probe as _}; #[used] pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); -// Program metadata for `picotool info` -#[link_section = ".bi_entries"] -#[used] -pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info::rp_program_name!(c"example"), - embassy_rp::binary_info::rp_cargo_version!(), - embassy_rp::binary_info::rp_program_description!(c"Blinky"), - embassy_rp::binary_info::rp_program_build_attribute!(), -]; - bind_interrupts!(struct Irqs { UART0_IRQ => BufferedInterruptHandler; }); diff --git a/examples/rp23/src/bin/uart_r503.rs b/examples/rp23/src/bin/uart_r503.rs index 5ac8839e3..9aed42785 100644 --- a/examples/rp23/src/bin/uart_r503.rs +++ b/examples/rp23/src/bin/uart_r503.rs @@ -15,16 +15,6 @@ use {defmt_rtt as _, panic_probe as _}; #[used] pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); -// Program metadata for `picotool info` -#[link_section = ".bi_entries"] -#[used] -pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info::rp_program_name!(c"example"), - embassy_rp::binary_info::rp_cargo_version!(), - embassy_rp::binary_info::rp_program_description!(c"Blinky"), - embassy_rp::binary_info::rp_program_build_attribute!(), -]; - bind_interrupts!(pub struct Irqs { UART0_IRQ => UARTInterruptHandler; }); diff --git a/examples/rp23/src/bin/uart_unidir.rs b/examples/rp23/src/bin/uart_unidir.rs index 988e44a79..12214c4c2 100644 --- a/examples/rp23/src/bin/uart_unidir.rs +++ b/examples/rp23/src/bin/uart_unidir.rs @@ -21,16 +21,6 @@ use {defmt_rtt as _, panic_probe as _}; #[used] pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); -// Program metadata for `picotool info` -#[link_section = ".bi_entries"] -#[used] -pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info::rp_program_name!(c"example"), - embassy_rp::binary_info::rp_cargo_version!(), - embassy_rp::binary_info::rp_program_description!(c"Blinky"), - embassy_rp::binary_info::rp_program_build_attribute!(), -]; - bind_interrupts!(struct Irqs { UART1_IRQ => InterruptHandler; }); diff --git a/examples/rp23/src/bin/usb_webusb.rs b/examples/rp23/src/bin/usb_webusb.rs index 3ade2226b..15279cabc 100644 --- a/examples/rp23/src/bin/usb_webusb.rs +++ b/examples/rp23/src/bin/usb_webusb.rs @@ -34,16 +34,6 @@ use {defmt_rtt as _, panic_probe as _}; #[used] pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); -// Program metadata for `picotool info` -#[link_section = ".bi_entries"] -#[used] -pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info::rp_program_name!(c"example"), - embassy_rp::binary_info::rp_cargo_version!(), - embassy_rp::binary_info::rp_program_description!(c"Blinky"), - embassy_rp::binary_info::rp_program_build_attribute!(), -]; - bind_interrupts!(struct Irqs { USBCTRL_IRQ => InterruptHandler; }); diff --git a/examples/rp23/src/bin/watchdog.rs b/examples/rp23/src/bin/watchdog.rs index a901c1164..efc24c4e3 100644 --- a/examples/rp23/src/bin/watchdog.rs +++ b/examples/rp23/src/bin/watchdog.rs @@ -18,16 +18,6 @@ use {defmt_rtt as _, panic_probe as _}; #[used] pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); -// Program metadata for `picotool info` -#[link_section = ".bi_entries"] -#[used] -pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info::rp_program_name!(c"example"), - embassy_rp::binary_info::rp_cargo_version!(), - embassy_rp::binary_info::rp_program_description!(c"Blinky"), - embassy_rp::binary_info::rp_program_build_attribute!(), -]; - #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_rp::init(Default::default()); diff --git a/examples/rp23/src/bin/zerocopy.rs b/examples/rp23/src/bin/zerocopy.rs index 86fca6f12..d317c4b56 100644 --- a/examples/rp23/src/bin/zerocopy.rs +++ b/examples/rp23/src/bin/zerocopy.rs @@ -23,16 +23,6 @@ use {defmt_rtt as _, panic_probe as _}; #[used] pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); -// Program metadata for `picotool info` -#[link_section = ".bi_entries"] -#[used] -pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ - embassy_rp::binary_info::rp_program_name!(c"example"), - embassy_rp::binary_info::rp_cargo_version!(), - embassy_rp::binary_info::rp_program_description!(c"Blinky"), - embassy_rp::binary_info::rp_program_build_attribute!(), -]; - type SampleBuffer = [u16; 512]; bind_interrupts!(struct Irqs { From ce701c3e8ef5f3cd354b74c1a06b6d77a9e812c6 Mon Sep 17 00:00:00 2001 From: Paul Fornage <36117326+paulwrath1223@users.noreply.github.com> Date: Wed, 2 Oct 2024 13:35:59 -0700 Subject: [PATCH 0187/1217] Fixed overflow on `pio_stepper.rs` --- examples/rp/src/bin/pio_stepper.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/rp/src/bin/pio_stepper.rs b/examples/rp/src/bin/pio_stepper.rs index 4952f4fbd..6ee45a414 100644 --- a/examples/rp/src/bin/pio_stepper.rs +++ b/examples/rp/src/bin/pio_stepper.rs @@ -154,7 +154,7 @@ async fn main(_spawner: Spawner) { stepper.step(1000).await; info!("CCW full steps, drop after 1 sec"); - if let Err(_) = with_timeout(Duration::from_secs(1), stepper.step(i32::MIN)).await { + if let Err(_) = with_timeout(Duration::from_secs(1), stepper.step(-i32::MAX)).await { info!("Time's up!"); Timer::after(Duration::from_secs(1)).await; } From b73b3f2da0940907dfc39bec62ff33c976874017 Mon Sep 17 00:00:00 2001 From: Sebastian Quilitz Date: Sat, 5 Oct 2024 12:18:33 +0200 Subject: [PATCH 0188/1217] rp: Run RP235x at 150 MHz instead of 125 --- embassy-rp/src/clocks.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs index f229a5acd..e82beb0f1 100644 --- a/embassy-rp/src/clocks.rs +++ b/embassy-rp/src/clocks.rs @@ -109,7 +109,10 @@ impl ClockConfig { sys_pll: Some(PllConfig { refdiv: 1, fbdiv: 125, + #[cfg(feature = "rp2040")] post_div1: 6, + #[cfg(feature = "_rp235x")] + post_div1: 5, post_div2: 2, }), usb_pll: Some(PllConfig { From d643d50f41cc6091eb573e2845fde48eeed9be4c Mon Sep 17 00:00:00 2001 From: rafael Date: Sat, 5 Oct 2024 12:24:17 +0200 Subject: [PATCH 0189/1217] Add Watch to embassy-sync README --- embassy-sync/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/embassy-sync/README.md b/embassy-sync/README.md index 97a663d6d..3dcd9dcc8 100644 --- a/embassy-sync/README.md +++ b/embassy-sync/README.md @@ -8,6 +8,7 @@ Synchronization primitives and data structures with async support: - [`PriorityChannel`](channel::priority_channel::PriorityChannel) - A Multiple Producer Multiple Consumer (MPMC) channel. Each message is only received by a single consumer. Higher priority items are shifted to the front of the channel. - [`PubSubChannel`](pubsub::PubSubChannel) - A broadcast channel (publish-subscribe) channel. Each message is received by all consumers. - [`Signal`](signal::Signal) - Signalling latest value to a single consumer. +- [`Watch`](watch::Watch) - Signalling latest value to multiple consumers. - [`Mutex`](mutex::Mutex) - Mutex for synchronizing state between asynchronous tasks. - [`Pipe`](pipe::Pipe) - Byte stream implementing `embedded_io` traits. - [`WakerRegistration`](waitqueue::WakerRegistration) - Utility to register and wake a `Waker`. From 383ad72b63b11ed1fc50ad5803534ac69996aff6 Mon Sep 17 00:00:00 2001 From: Oliver Rockstedt Date: Sat, 5 Oct 2024 13:39:27 +0200 Subject: [PATCH 0190/1217] embassy-sync: add clear, len, is_empty and is_full functions to zerocopy_channel --- embassy-sync/CHANGELOG.md | 1 + embassy-sync/src/zerocopy_channel.rs | 76 ++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+) diff --git a/embassy-sync/CHANGELOG.md b/embassy-sync/CHANGELOG.md index 8f2d26fe0..8847e7e88 100644 --- a/embassy-sync/CHANGELOG.md +++ b/embassy-sync/CHANGELOG.md @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased - Add LazyLock sync primitive. +- Add `clear`, `len`, `is_empty` and `is_full` functions to `zerocopy_channel`. ## 0.6.0 - 2024-05-29 diff --git a/embassy-sync/src/zerocopy_channel.rs b/embassy-sync/src/zerocopy_channel.rs index cfce9a571..a2c763294 100644 --- a/embassy-sync/src/zerocopy_channel.rs +++ b/embassy-sync/src/zerocopy_channel.rs @@ -70,6 +70,28 @@ impl<'a, M: RawMutex, T> Channel<'a, M, T> { pub fn split(&mut self) -> (Sender<'_, M, T>, Receiver<'_, M, T>) { (Sender { channel: self }, Receiver { channel: self }) } + + /// Clears all elements in the channel. + pub fn clear(&mut self) { + self.state.lock(|s| { + s.borrow_mut().clear(); + }); + } + + /// Returns the number of elements currently in the channel. + pub fn len(&self) -> usize { + self.state.lock(|s| s.borrow().len()) + } + + /// Returns whether the channel is empty. + pub fn is_empty(&self) -> bool { + self.state.lock(|s| s.borrow().is_empty()) + } + + /// Returns whether the channel is full. + pub fn is_full(&self) -> bool { + self.state.lock(|s| s.borrow().is_full()) + } } /// Send-only access to a [`Channel`]. @@ -130,6 +152,28 @@ impl<'a, M: RawMutex, T> Sender<'a, M, T> { pub fn send_done(&mut self) { self.channel.state.lock(|s| s.borrow_mut().push_done()) } + + /// Clears all elements in the channel. + pub fn clear(&mut self) { + self.channel.state.lock(|s| { + s.borrow_mut().clear(); + }); + } + + /// Returns the number of elements currently in the channel. + pub fn len(&self) -> usize { + self.channel.state.lock(|s| s.borrow().len()) + } + + /// Returns whether the channel is empty. + pub fn is_empty(&self) -> bool { + self.channel.state.lock(|s| s.borrow().is_empty()) + } + + /// Returns whether the channel is full. + pub fn is_full(&self) -> bool { + self.channel.state.lock(|s| s.borrow().is_full()) + } } /// Receive-only access to a [`Channel`]. @@ -190,6 +234,28 @@ impl<'a, M: RawMutex, T> Receiver<'a, M, T> { pub fn receive_done(&mut self) { self.channel.state.lock(|s| s.borrow_mut().pop_done()) } + + /// Clears all elements in the channel. + pub fn clear(&mut self) { + self.channel.state.lock(|s| { + s.borrow_mut().clear(); + }); + } + + /// Returns the number of elements currently in the channel. + pub fn len(&self) -> usize { + self.channel.state.lock(|s| s.borrow().len()) + } + + /// Returns whether the channel is empty. + pub fn is_empty(&self) -> bool { + self.channel.state.lock(|s| s.borrow().is_empty()) + } + + /// Returns whether the channel is full. + pub fn is_full(&self) -> bool { + self.channel.state.lock(|s| s.borrow().is_full()) + } } struct State { @@ -217,6 +283,16 @@ impl State { } } + fn clear(&mut self) { + self.front = 0; + self.back = 0; + self.full = false; + } + + fn len(&self) -> usize { + self.len + } + fn is_full(&self) -> bool { self.full } From 67836f955af133fa2ea7427172bbf352c51e4ab2 Mon Sep 17 00:00:00 2001 From: Chris Maniewski Date: Sat, 5 Oct 2024 14:16:00 +0200 Subject: [PATCH 0191/1217] docs: fix Sender/Receiver typo --- embassy-sync/src/watch.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-sync/src/watch.rs b/embassy-sync/src/watch.rs index 336e64ba9..59798d04f 100644 --- a/embassy-sync/src/watch.rs +++ b/embassy-sync/src/watch.rs @@ -310,12 +310,12 @@ impl Watch { } } - /// Create a new [`Receiver`] for the `Watch`. + /// Create a new [`Sender`] for the `Watch`. pub fn sender(&self) -> Sender<'_, M, T, N> { Sender(Snd::new(self)) } - /// Create a new [`DynReceiver`] for the `Watch`. + /// Create a new [`DynSender`] for the `Watch`. pub fn dyn_sender(&self) -> DynSender<'_, T> { DynSender(Snd::new(self)) } From f3ed0c60265c84ddcc11e4dea980bdc0b8343985 Mon Sep 17 00:00:00 2001 From: Oliver Rockstedt Date: Sun, 6 Oct 2024 17:39:47 +0200 Subject: [PATCH 0192/1217] embassy-sync: fix len calculation for zerocopy_channel --- embassy-sync/src/zerocopy_channel.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/embassy-sync/src/zerocopy_channel.rs b/embassy-sync/src/zerocopy_channel.rs index a2c763294..a669cbd09 100644 --- a/embassy-sync/src/zerocopy_channel.rs +++ b/embassy-sync/src/zerocopy_channel.rs @@ -290,7 +290,15 @@ impl State { } fn len(&self) -> usize { - self.len + if !self.full { + if self.back >= self.front { + self.back - self.front + } else { + self.len + self.back - self.front + } + } else { + self.len + } } fn is_full(&self) -> bool { From 12e6add058b1bbe69660717bdef3d414a04b8b19 Mon Sep 17 00:00:00 2001 From: Oliver Rockstedt Date: Sun, 6 Oct 2024 17:45:03 +0200 Subject: [PATCH 0193/1217] embassy-sync: renamed field len to capacity on zerocopy_channel state --- embassy-sync/src/zerocopy_channel.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/embassy-sync/src/zerocopy_channel.rs b/embassy-sync/src/zerocopy_channel.rs index a669cbd09..fabb69bf6 100644 --- a/embassy-sync/src/zerocopy_channel.rs +++ b/embassy-sync/src/zerocopy_channel.rs @@ -53,7 +53,7 @@ impl<'a, M: RawMutex, T> Channel<'a, M, T> { buf: buf.as_mut_ptr(), phantom: PhantomData, state: Mutex::new(RefCell::new(State { - len, + capacity: len, front: 0, back: 0, full: false, @@ -259,7 +259,8 @@ impl<'a, M: RawMutex, T> Receiver<'a, M, T> { } struct State { - len: usize, + /// Maximum number of elements the channel can hold. + capacity: usize, /// Front index. Always 0..=(N-1) front: usize, @@ -276,7 +277,7 @@ struct State { impl State { fn increment(&self, i: usize) -> usize { - if i + 1 == self.len { + if i + 1 == self.capacity { 0 } else { i + 1 @@ -294,10 +295,10 @@ impl State { if self.back >= self.front { self.back - self.front } else { - self.len + self.back - self.front + self.capacity + self.back - self.front } } else { - self.len + self.capacity } } From f6155cf735678fa1e297baa4ace992af3a871ae7 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sun, 6 Oct 2024 23:47:43 +0200 Subject: [PATCH 0194/1217] Update smoltcp, embedded-nal-async to use the `core::net` IP addr types. --- embassy-net-ppp/Cargo.toml | 2 +- embassy-net/Cargo.toml | 4 ++-- embassy-net/src/dns.rs | 17 ++++++++--------- embassy-net/src/tcp.rs | 12 ++++-------- examples/nrf9160/src/bin/modem_tcp_client.rs | 12 +++++------- examples/rp/Cargo.toml | 4 ++-- examples/rp23/Cargo.toml | 2 -- examples/std/src/bin/net_ppp.rs | 6 +++--- examples/stm32h5/Cargo.toml | 2 +- examples/stm32h7/Cargo.toml | 2 +- examples/stm32h7/src/bin/eth_client.rs | 4 +++- examples/stm32h7/src/bin/eth_client_mii.rs | 4 +++- examples/stm32h755cm4/Cargo.toml | 2 +- examples/stm32h755cm7/Cargo.toml | 2 +- examples/stm32h7rs/Cargo.toml | 2 +- .../stm32l4/src/bin/spe_adin1110_http_server.rs | 2 +- 16 files changed, 37 insertions(+), 42 deletions(-) diff --git a/embassy-net-ppp/Cargo.toml b/embassy-net-ppp/Cargo.toml index f6371f955..d2f43ef45 100644 --- a/embassy-net-ppp/Cargo.toml +++ b/embassy-net-ppp/Cargo.toml @@ -20,7 +20,7 @@ log = { version = "0.4.14", optional = true } embedded-io-async = { version = "0.6.1" } embassy-net-driver-channel = { version = "0.3.0", path = "../embassy-net-driver-channel" } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } -ppproto = { version = "0.1.2"} +ppproto = { version = "0.2.0"} embassy-sync = { version = "0.6.0", path = "../embassy-sync" } [package.metadata.embassy_docs] diff --git a/embassy-net/Cargo.toml b/embassy-net/Cargo.toml index 2e21b4231..a33c693fc 100644 --- a/embassy-net/Cargo.toml +++ b/embassy-net/Cargo.toml @@ -68,7 +68,7 @@ multicast = ["smoltcp/multicast"] defmt = { version = "0.3", optional = true } log = { version = "0.4.14", optional = true } -smoltcp = { git="https://github.com/smoltcp-rs/smoltcp", rev="dd43c8f189178b0ab3bda798ed8578b5b0a6f094", default-features = false, features = [ +smoltcp = { git="https://github.com/smoltcp-rs/smoltcp", rev="b65e1b64dc9b66fa984a2ad34e90685cb0b606de", default-features = false, features = [ "socket", "async", ] } @@ -80,5 +80,5 @@ embedded-io-async = { version = "0.6.1" } managed = { version = "0.8.0", default-features = false, features = [ "map" ] } heapless = { version = "0.8", default-features = false } -embedded-nal-async = { version = "0.7.1" } +embedded-nal-async = "0.8.0" document-features = "0.2.7" diff --git a/embassy-net/src/dns.rs b/embassy-net/src/dns.rs index 1fbaea4f0..dbe73776c 100644 --- a/embassy-net/src/dns.rs +++ b/embassy-net/src/dns.rs @@ -73,8 +73,11 @@ impl<'a> embedded_nal_async::Dns for DnsSocket<'a> { &self, host: &str, addr_type: embedded_nal_async::AddrType, - ) -> Result { - use embedded_nal_async::{AddrType, IpAddr}; + ) -> Result { + use core::net::IpAddr; + + use embedded_nal_async::AddrType; + let (qtype, secondary_qtype) = match addr_type { AddrType::IPv4 => (DnsQueryType::A, None), AddrType::IPv6 => (DnsQueryType::Aaaa, None), @@ -98,20 +101,16 @@ impl<'a> embedded_nal_async::Dns for DnsSocket<'a> { if let Some(first) = addrs.get(0) { Ok(match first { #[cfg(feature = "proto-ipv4")] - IpAddress::Ipv4(addr) => IpAddr::V4(addr.0.into()), + IpAddress::Ipv4(addr) => IpAddr::V4(*addr), #[cfg(feature = "proto-ipv6")] - IpAddress::Ipv6(addr) => IpAddr::V6(addr.0.into()), + IpAddress::Ipv6(addr) => IpAddr::V6(*addr), }) } else { Err(Error::Failed) } } - async fn get_host_by_address( - &self, - _addr: embedded_nal_async::IpAddr, - _result: &mut [u8], - ) -> Result { + async fn get_host_by_address(&self, _addr: core::net::IpAddr, _result: &mut [u8]) -> Result { todo!() } } diff --git a/embassy-net/src/tcp.rs b/embassy-net/src/tcp.rs index bcddbc95b..1bd582b65 100644 --- a/embassy-net/src/tcp.rs +++ b/embassy-net/src/tcp.rs @@ -675,10 +675,9 @@ mod embedded_io_impls { pub mod client { use core::cell::{Cell, UnsafeCell}; use core::mem::MaybeUninit; + use core::net::IpAddr; use core::ptr::NonNull; - use embedded_nal_async::IpAddr; - use super::*; /// TCP client connection pool compatible with `embedded-nal-async` traits. @@ -715,17 +714,14 @@ pub mod client { type Error = Error; type Connection<'m> = TcpConnection<'m, N, TX_SZ, RX_SZ> where Self: 'm; - async fn connect<'a>( - &'a self, - remote: embedded_nal_async::SocketAddr, - ) -> Result, Self::Error> { + async fn connect<'a>(&'a self, remote: core::net::SocketAddr) -> Result, Self::Error> { let addr: crate::IpAddress = match remote.ip() { #[cfg(feature = "proto-ipv4")] - IpAddr::V4(addr) => crate::IpAddress::Ipv4(crate::Ipv4Address::from_bytes(&addr.octets())), + IpAddr::V4(addr) => crate::IpAddress::Ipv4(addr), #[cfg(not(feature = "proto-ipv4"))] IpAddr::V4(_) => panic!("ipv4 support not enabled"), #[cfg(feature = "proto-ipv6")] - IpAddr::V6(addr) => crate::IpAddress::Ipv6(crate::Ipv6Address::from_bytes(&addr.octets())), + IpAddr::V6(addr) => crate::IpAddress::Ipv6(addr), #[cfg(not(feature = "proto-ipv6"))] IpAddr::V6(_) => panic!("ipv6 support not enabled"), }; diff --git a/examples/nrf9160/src/bin/modem_tcp_client.rs b/examples/nrf9160/src/bin/modem_tcp_client.rs index 495ee26dd..067ec4276 100644 --- a/examples/nrf9160/src/bin/modem_tcp_client.rs +++ b/examples/nrf9160/src/bin/modem_tcp_client.rs @@ -9,7 +9,7 @@ use core::str::FromStr; use defmt::{info, unwrap, warn}; use embassy_executor::Spawner; -use embassy_net::{Ipv4Address, Ipv4Cidr, Stack, StackResources}; +use embassy_net::{Ipv4Cidr, Stack, StackResources}; use embassy_net_nrf91::context::Status; use embassy_net_nrf91::{context, Runner, State, TraceBuffer, TraceReader}; use embassy_nrf::buffered_uarte::{self, BufferedUarteTx}; @@ -70,18 +70,16 @@ fn status_to_config(status: &Status) -> embassy_net::ConfigV4 { let Some(IpAddr::V4(addr)) = status.ip else { panic!("Unexpected IP address"); }; - let addr = Ipv4Address(addr.octets()); - let gateway = if let Some(IpAddr::V4(addr)) = status.gateway { - Some(Ipv4Address(addr.octets())) - } else { - None + let gateway = match status.gateway { + Some(IpAddr::V4(addr)) => Some(addr), + _ => None, }; let mut dns_servers = Vec::new(); for dns in status.dns.iter() { if let IpAddr::V4(ip) = dns { - unwrap!(dns_servers.push(Ipv4Address(ip.octets()))); + unwrap!(dns_servers.push(*ip)); } } diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index 04b4c6317..674d331ab 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml @@ -12,7 +12,7 @@ embassy-executor = { version = "0.6.0", path = "../../embassy-executor", feature embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-rp = { version = "0.2.0", path = "../../embassy-rp", features = ["defmt", "unstable-pac", "time-driver", "critical-section-impl", "rp2040"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } -embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "raw", "dhcpv4", "medium-ethernet", "dns"] } +embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "raw", "dhcpv4", "medium-ethernet", "dns", "proto-ipv4", "proto-ipv6", "multicast"] } embassy-net-wiznet = { version = "0.1.0", path = "../../embassy-net-wiznet", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-usb-logger = { version = "0.2.0", path = "../../embassy-usb-logger" } @@ -25,7 +25,7 @@ fixed = "1.23.1" fixed-macro = "1.2" # for web request example -reqwless = { version = "0.12.0", features = ["defmt",]} +reqwless = { git="https://github.com/drogue-iot/reqwless", rev="673e8d2cfbaad79254ec51fa50cc8b697531fbff", features = ["defmt",]} serde = { version = "1.0.203", default-features = false, features = ["derive"] } serde-json-core = "0.5.1" diff --git a/examples/rp23/Cargo.toml b/examples/rp23/Cargo.toml index 087f6fd69..08646463c 100644 --- a/examples/rp23/Cargo.toml +++ b/examples/rp23/Cargo.toml @@ -24,8 +24,6 @@ defmt-rtt = "0.4" fixed = "1.23.1" fixed-macro = "1.2" -# for web request example -reqwless = { version = "0.12.0", features = ["defmt",]} serde = { version = "1.0.203", default-features = false, features = ["derive"] } serde-json-core = "0.5.1" diff --git a/examples/std/src/bin/net_ppp.rs b/examples/std/src/bin/net_ppp.rs index 7d0f1327f..ea3fbebef 100644 --- a/examples/std/src/bin/net_ppp.rs +++ b/examples/std/src/bin/net_ppp.rs @@ -16,7 +16,7 @@ use async_io::Async; use clap::Parser; use embassy_executor::{Executor, Spawner}; use embassy_net::tcp::TcpSocket; -use embassy_net::{Config, ConfigV4, Ipv4Address, Ipv4Cidr, Stack, StackResources}; +use embassy_net::{Config, ConfigV4, Ipv4Cidr, Stack, StackResources}; use embassy_net_ppp::Runner; use embedded_io_async::Write; use futures::io::BufReader; @@ -60,10 +60,10 @@ async fn ppp_task(stack: Stack<'static>, mut runner: Runner<'static>, port: Seri }; let mut dns_servers = Vec::new(); for s in ipv4.dns_servers.iter().flatten() { - let _ = dns_servers.push(Ipv4Address::from_bytes(&s.0)); + let _ = dns_servers.push(*s); } let config = ConfigV4::Static(embassy_net::StaticConfigV4 { - address: Ipv4Cidr::new(Ipv4Address::from_bytes(&addr.0), 0), + address: Ipv4Cidr::new(addr, 0), gateway: None, dns_servers, }); diff --git a/examples/stm32h5/Cargo.toml b/examples/stm32h5/Cargo.toml index 30b1d2be9..1aa264ab2 100644 --- a/examples/stm32h5/Cargo.toml +++ b/examples/stm32h5/Cargo.toml @@ -23,7 +23,7 @@ embedded-hal = "0.2.6" embedded-hal-1 = { package = "embedded-hal", version = "1.0" } embedded-hal-async = { version = "1.0" } embedded-io-async = { version = "0.6.1" } -embedded-nal-async = { version = "0.7.1" } +embedded-nal-async = "0.8.0" panic-probe = { version = "0.3", features = ["print-defmt"] } heapless = { version = "0.8", default-features = false } rand_core = "0.6.3" diff --git a/examples/stm32h7/Cargo.toml b/examples/stm32h7/Cargo.toml index 13fce7dc7..d0f22cf82 100644 --- a/examples/stm32h7/Cargo.toml +++ b/examples/stm32h7/Cargo.toml @@ -23,7 +23,7 @@ cortex-m-rt = "0.7.0" embedded-hal = "0.2.6" embedded-hal-1 = { package = "embedded-hal", version = "1.0" } embedded-hal-async = { version = "1.0" } -embedded-nal-async = { version = "0.7.1" } +embedded-nal-async = "0.8.0" embedded-io-async = { version = "0.6.1" } panic-probe = { version = "0.3", features = ["print-defmt"] } heapless = { version = "0.8", default-features = false } diff --git a/examples/stm32h7/src/bin/eth_client.rs b/examples/stm32h7/src/bin/eth_client.rs index 24983ca85..a1558b079 100644 --- a/examples/stm32h7/src/bin/eth_client.rs +++ b/examples/stm32h7/src/bin/eth_client.rs @@ -1,6 +1,8 @@ #![no_std] #![no_main] +use core::net::{Ipv4Addr, SocketAddr, SocketAddrV4}; + use defmt::*; use embassy_executor::Spawner; use embassy_net::tcp::client::{TcpClient, TcpClientState}; @@ -12,7 +14,7 @@ use embassy_stm32::rng::Rng; use embassy_stm32::{bind_interrupts, eth, peripherals, rng, Config}; use embassy_time::Timer; use embedded_io_async::Write; -use embedded_nal_async::{Ipv4Addr, SocketAddr, SocketAddrV4, TcpConnect}; +use embedded_nal_async::TcpConnect; use rand_core::RngCore; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32h7/src/bin/eth_client_mii.rs b/examples/stm32h7/src/bin/eth_client_mii.rs index 768d85993..a352ef444 100644 --- a/examples/stm32h7/src/bin/eth_client_mii.rs +++ b/examples/stm32h7/src/bin/eth_client_mii.rs @@ -1,6 +1,8 @@ #![no_std] #![no_main] +use core::net::{Ipv4Addr, SocketAddr, SocketAddrV4}; + use defmt::*; use embassy_executor::Spawner; use embassy_net::tcp::client::{TcpClient, TcpClientState}; @@ -12,7 +14,7 @@ use embassy_stm32::rng::Rng; use embassy_stm32::{bind_interrupts, eth, peripherals, rng, Config}; use embassy_time::Timer; use embedded_io_async::Write; -use embedded_nal_async::{Ipv4Addr, SocketAddr, SocketAddrV4, TcpConnect}; +use embedded_nal_async::TcpConnect; use rand_core::RngCore; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32h755cm4/Cargo.toml b/examples/stm32h755cm4/Cargo.toml index 7a42fbdaa..75de40b9a 100644 --- a/examples/stm32h755cm4/Cargo.toml +++ b/examples/stm32h755cm4/Cargo.toml @@ -23,7 +23,7 @@ cortex-m-rt = "0.7.0" embedded-hal = "0.2.6" embedded-hal-1 = { package = "embedded-hal", version = "1.0" } embedded-hal-async = { version = "1.0" } -embedded-nal-async = { version = "0.7.1" } +embedded-nal-async = "0.8.0" embedded-io-async = { version = "0.6.1" } panic-probe = { version = "0.3", features = ["print-defmt"] } heapless = { version = "0.8", default-features = false } diff --git a/examples/stm32h755cm7/Cargo.toml b/examples/stm32h755cm7/Cargo.toml index 4f0f69c3f..911a4e79b 100644 --- a/examples/stm32h755cm7/Cargo.toml +++ b/examples/stm32h755cm7/Cargo.toml @@ -23,7 +23,7 @@ cortex-m-rt = "0.7.0" embedded-hal = "0.2.6" embedded-hal-1 = { package = "embedded-hal", version = "1.0" } embedded-hal-async = { version = "1.0" } -embedded-nal-async = { version = "0.7.1" } +embedded-nal-async = "0.8.0" embedded-io-async = { version = "0.6.1" } panic-probe = { version = "0.3", features = ["print-defmt"] } heapless = { version = "0.8", default-features = false } diff --git a/examples/stm32h7rs/Cargo.toml b/examples/stm32h7rs/Cargo.toml index f97dfd722..05f638408 100644 --- a/examples/stm32h7rs/Cargo.toml +++ b/examples/stm32h7rs/Cargo.toml @@ -22,7 +22,7 @@ cortex-m-rt = "0.7.0" embedded-hal = "0.2.6" embedded-hal-1 = { package = "embedded-hal", version = "1.0" } embedded-hal-async = { version = "1.0" } -embedded-nal-async = { version = "0.7.1" } +embedded-nal-async = "0.8.0" embedded-io-async = { version = "0.6.1" } panic-probe = { version = "0.3", features = ["print-defmt"] } heapless = { version = "0.8", default-features = false } diff --git a/examples/stm32l4/src/bin/spe_adin1110_http_server.rs b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs index be4270ada..4a7c01f9f 100644 --- a/examples/stm32l4/src/bin/spe_adin1110_http_server.rs +++ b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs @@ -51,7 +51,7 @@ bind_interrupts!(struct Irqs { // MAC-address used by the adin1110 const MAC: [u8; 6] = [0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff]; // Static IP settings -const IP_ADDRESS: Ipv4Cidr = Ipv4Cidr::new(Ipv4Address([192, 168, 1, 5]), 24); +const IP_ADDRESS: Ipv4Cidr = Ipv4Cidr::new(Ipv4Address::new(192, 168, 1, 5), 24); // Listen port for the webserver const HTTP_LISTEN_PORT: u16 = 80; From 9e6e09a8d747ec90aae215df8471dfe349993487 Mon Sep 17 00:00:00 2001 From: Dummyc0m Date: Sun, 6 Oct 2024 23:23:33 -0700 Subject: [PATCH 0195/1217] executor/spin: introduce an architecture agnostic executor Spin polls the raw executor and never sleeps. It is useful for disabling any power features associated with wfi/wfe-like instructions. When implementing support for the CH32V30x MCU, the wfi instruction had issues interacting with the USB OTG peripheral and appeared to be non-spec-compliant. 1. When sending a USB Data-in packet, the USB peripheral appears to be unable to read the system main memory while in WFI. This manifests in the USB peripheral sending all or partially zeroed DATA packets. Disabling WFI works around this issue. 2. The WFI instruction does not wake up the processor when MIE is disabled. The MCU provides a WFITOWFE bit to emulate the WFE instruction on arm, which, when enabled, ignores the MIE and allows the processor to wake up. This works around the non-compliant WFI implementation. Co-authored-by: Codetector Co-authored-by: Dummyc0m --- embassy-executor-macros/src/lib.rs | 29 +++++++++++ embassy-executor-macros/src/macros/main.rs | 29 ++++++++++- embassy-executor/Cargo.toml | 2 + embassy-executor/src/arch/spin.rs | 58 ++++++++++++++++++++++ embassy-executor/src/lib.rs | 10 +++- 5 files changed, 126 insertions(+), 2 deletions(-) create mode 100644 embassy-executor/src/arch/spin.rs diff --git a/embassy-executor-macros/src/lib.rs b/embassy-executor-macros/src/lib.rs index 5461fe04c..61d388b9e 100644 --- a/embassy-executor-macros/src/lib.rs +++ b/embassy-executor-macros/src/lib.rs @@ -94,6 +94,35 @@ pub fn main_cortex_m(args: TokenStream, item: TokenStream) -> TokenStream { main::run(&args.meta, f, main::cortex_m()).unwrap_or_else(|x| x).into() } +/// Creates a new `executor` instance and declares an architecture agnostic application entry point spawning +/// the corresponding function body as an async task. +/// +/// The following restrictions apply: +/// +/// * The function must accept exactly 1 parameter, an `embassy_executor::Spawner` handle that it can use to spawn additional tasks. +/// * The function must be declared `async`. +/// * The function must not use generics. +/// * Only a single `main` task may be declared. +/// +/// A user-defined entry macro must provided via the `entry` argument +/// +/// ## Examples +/// Spawning a task: +/// ``` rust +/// #[embassy_executor::main(entry = "qingke_rt::entry")] +/// async fn main(_s: embassy_executor::Spawner) { +/// // Function body +/// } +/// ``` +#[proc_macro_attribute] +pub fn main_spin(args: TokenStream, item: TokenStream) -> TokenStream { + let args = syn::parse_macro_input!(args as Args); + let f = syn::parse_macro_input!(item as syn::ItemFn); + main::run(&args.meta, f, main::spin(&args.meta)) + .unwrap_or_else(|x| x) + .into() +} + /// Creates a new `executor` instance and declares an application entry point for RISC-V spawning the corresponding function body as an async task. /// /// The following restrictions apply: diff --git a/embassy-executor-macros/src/macros/main.rs b/embassy-executor-macros/src/macros/main.rs index 26dfa2397..66a3965d0 100644 --- a/embassy-executor-macros/src/macros/main.rs +++ b/embassy-executor-macros/src/macros/main.rs @@ -1,5 +1,5 @@ use darling::export::NestedMeta; -use darling::FromMeta; +use darling::{Error, FromMeta}; use proc_macro2::TokenStream; use quote::quote; use syn::{Expr, ReturnType, Type}; @@ -50,6 +50,33 @@ pub fn riscv(args: &[NestedMeta]) -> TokenStream { } } +pub fn spin(args: &[NestedMeta]) -> TokenStream { + let maybe_entry = match Args::from_list(args) { + Ok(args) => args.entry, + Err(e) => return e.write_errors(), + }; + + let entry = match maybe_entry { + Some(str) => str, + None => return Error::missing_field("entry").write_errors(), + }; + let entry = match Expr::from_string(&entry) { + Ok(expr) => expr, + Err(e) => return e.write_errors(), + }; + + quote! { + #[#entry] + fn main() -> ! { + let mut executor = ::embassy_executor::Executor::new(); + let executor = unsafe { __make_static(&mut executor) }; + executor.run(|spawner| { + spawner.must_spawn(__embassy_main(spawner)); + }) + } + } +} + pub fn cortex_m() -> TokenStream { quote! { #[cortex_m_rt::entry] diff --git a/embassy-executor/Cargo.toml b/embassy-executor/Cargo.toml index 01fa28b88..e2fedce3c 100644 --- a/embassy-executor/Cargo.toml +++ b/embassy-executor/Cargo.toml @@ -82,6 +82,8 @@ arch-riscv32 = ["_arch"] arch-wasm = ["_arch", "dep:wasm-bindgen", "dep:js-sys", "critical-section/std"] ## AVR arch-avr = ["_arch", "dep:portable-atomic", "dep:avr-device"] +## spin (architecture agnostic; never sleeps) +arch-spin = ["_arch"] #! ### Executor diff --git a/embassy-executor/src/arch/spin.rs b/embassy-executor/src/arch/spin.rs new file mode 100644 index 000000000..340023620 --- /dev/null +++ b/embassy-executor/src/arch/spin.rs @@ -0,0 +1,58 @@ +#[cfg(feature = "executor-interrupt")] +compile_error!("`executor-interrupt` is not supported with `arch-spin`."); + +#[cfg(feature = "executor-thread")] +pub use thread::*; +#[cfg(feature = "executor-thread")] +mod thread { + use core::marker::PhantomData; + + pub use embassy_executor_macros::main_spin as main; + + use crate::{raw, Spawner}; + + #[export_name = "__pender"] + fn __pender(_context: *mut ()) {} + + /// Spin Executor + pub struct Executor { + inner: raw::Executor, + not_send: PhantomData<*mut ()>, + } + + impl Executor { + /// Create a new Executor. + pub fn new() -> Self { + Self { + inner: raw::Executor::new(core::ptr::null_mut()), + not_send: PhantomData, + } + } + + /// Run the executor. + /// + /// The `init` closure is called with a [`Spawner`] that spawns tasks on + /// this executor. Use it to spawn the initial task(s). After `init` returns, + /// the executor starts running the tasks. + /// + /// To spawn more tasks later, you may keep copies of the [`Spawner`] (it is `Copy`), + /// for example by passing it as an argument to the initial tasks. + /// + /// This function requires `&'static mut self`. This means you have to store the + /// Executor instance in a place where it'll live forever and grants you mutable + /// access. There's a few ways to do this: + /// + /// - a [StaticCell](https://docs.rs/static_cell/latest/static_cell/) (safe) + /// - a `static mut` (unsafe) + /// - a local variable in a function you know never returns (like `fn main() -> !`), upgrading its lifetime with `transmute`. (unsafe) + /// + /// This function never returns. + pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! { + init(self.inner.spawner()); + + loop { + unsafe { self.inner.poll() }; + } + } + } +} diff --git a/embassy-executor/src/lib.rs b/embassy-executor/src/lib.rs index 6a2e493a2..d816539ac 100644 --- a/embassy-executor/src/lib.rs +++ b/embassy-executor/src/lib.rs @@ -23,7 +23,14 @@ macro_rules! check_at_most_one { check_at_most_one!(@amo [$($f)*] [$($f)*] []); }; } -check_at_most_one!("arch-avr", "arch-cortex-m", "arch-riscv32", "arch-std", "arch-wasm",); +check_at_most_one!( + "arch-avr", + "arch-cortex-m", + "arch-riscv32", + "arch-std", + "arch-wasm", + "arch-spin", +); #[cfg(feature = "_arch")] #[cfg_attr(feature = "arch-avr", path = "arch/avr.rs")] @@ -31,6 +38,7 @@ check_at_most_one!("arch-avr", "arch-cortex-m", "arch-riscv32", "arch-std", "arc #[cfg_attr(feature = "arch-riscv32", path = "arch/riscv32.rs")] #[cfg_attr(feature = "arch-std", path = "arch/std.rs")] #[cfg_attr(feature = "arch-wasm", path = "arch/wasm.rs")] +#[cfg_attr(feature = "arch-spin", path = "arch/spin.rs")] mod arch; #[cfg(feature = "_arch")] From e7e245eeb77974bf1f374f24cbf5c0bc41f745f1 Mon Sep 17 00:00:00 2001 From: George Cosma Date: Wed, 5 Jun 2024 13:54:00 +0300 Subject: [PATCH 0196/1217] feat: embassy-lpc55 hal with gpio and pint driver --- ci.sh | 2 + embassy-nxp/Cargo.toml | 17 + embassy-nxp/src/gpio.rs | 361 +++++++++++++++ embassy-nxp/src/lib.rs | 95 ++++ embassy-nxp/src/pac_utils.rs | 323 ++++++++++++++ embassy-nxp/src/pint.rs | 440 +++++++++++++++++++ examples/lpc55s69/.cargo/config.toml | 8 + examples/lpc55s69/Cargo.toml | 22 + examples/lpc55s69/build.rs | 35 ++ examples/lpc55s69/memory.x | 28 ++ examples/lpc55s69/src/bin/blinky_nop.rs | 33 ++ examples/lpc55s69/src/bin/button_executor.rs | 25 ++ 12 files changed, 1389 insertions(+) create mode 100644 embassy-nxp/Cargo.toml create mode 100644 embassy-nxp/src/gpio.rs create mode 100644 embassy-nxp/src/lib.rs create mode 100644 embassy-nxp/src/pac_utils.rs create mode 100644 embassy-nxp/src/pint.rs create mode 100644 examples/lpc55s69/.cargo/config.toml create mode 100644 examples/lpc55s69/Cargo.toml create mode 100644 examples/lpc55s69/build.rs create mode 100644 examples/lpc55s69/memory.x create mode 100644 examples/lpc55s69/src/bin/blinky_nop.rs create mode 100644 examples/lpc55s69/src/bin/button_executor.rs diff --git a/ci.sh b/ci.sh index 8fef731a4..503f8c8dc 100755 --- a/ci.sh +++ b/ci.sh @@ -171,6 +171,7 @@ cargo batch \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32u031r8,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32u073mb,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32u083rc,defmt,exti,time-driver-any,time \ + --- build --release --manifest-path embassy-nxp/Cargo.toml --target thumbv8m.main-none-eabihf \ --- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features ''\ --- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'log' \ --- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'defmt' \ @@ -227,6 +228,7 @@ cargo batch \ --- build --release --manifest-path examples/stm32wb/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32wb \ --- build --release --manifest-path examples/stm32wba/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/stm32wba \ --- build --release --manifest-path examples/stm32wl/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32wl \ + --- build --release --manifest-path examples/lpc55s69/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/lpc55s69 \ --- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840,skip-include --out-dir out/examples/boot/nrf52840 \ --- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9160-ns,skip-include --out-dir out/examples/boot/nrf9160 \ --- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9120-ns,skip-include --out-dir out/examples/boot/nrf9120 \ diff --git a/embassy-nxp/Cargo.toml b/embassy-nxp/Cargo.toml new file mode 100644 index 000000000..df329be66 --- /dev/null +++ b/embassy-nxp/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "embassy-nxp" +version = "0.1.0" +edition = "2021" + +[dependencies] +cortex-m = "0.7.7" +cortex-m-rt = "0.7.0" +critical-section = "1.1.2" +embassy-hal-internal = {version = "0.2.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-2"] } +embassy-sync = { version = "0.6.0", path = "../embassy-sync" } +lpc55-pac = "0.5.0" +defmt = "0.3.8" + +[features] +default = ["rt"] +rt = ["lpc55-pac/rt"] \ No newline at end of file diff --git a/embassy-nxp/src/gpio.rs b/embassy-nxp/src/gpio.rs new file mode 100644 index 000000000..d5d04ee69 --- /dev/null +++ b/embassy-nxp/src/gpio.rs @@ -0,0 +1,361 @@ +use embassy_hal_internal::impl_peripheral; + +use crate::pac_utils::*; +use crate::{peripherals, Peripheral, PeripheralRef}; + +pub(crate) fn init() { + // Enable clocks for GPIO, PINT, and IOCON + syscon_reg() + .ahbclkctrl0 + .modify(|_, w| w.gpio0().enable().gpio1().enable().mux().enable().iocon().enable()); +} + +/// The GPIO pin level for pins set on "Digital" mode. +#[derive(Debug, Eq, PartialEq, Clone, Copy)] +pub enum Level { + /// Logical low. Corresponds to 0V. + Low, + /// Logical high. Corresponds to VDD. + High, +} + +/// Pull setting for a GPIO input set on "Digital" mode. +#[derive(Debug, Clone, Copy, Eq, PartialEq)] +pub enum Pull { + /// No pull. + None, + /// Internal pull-up resistor. + Up, + /// Internal pull-down resistor. + Down, +} + +/// The LPC55 boards have two GPIO banks, each with 32 pins. This enum represents the two banks. +#[derive(Debug, Eq, PartialEq, Clone, Copy)] +pub enum Bank { + Bank0 = 0, + Bank1 = 1, +} + +/// GPIO output driver. Internally, this is a specialized [Flex] pin. +pub struct Output<'d> { + pub(crate) pin: Flex<'d>, +} + +impl<'d> Output<'d> { + /// Create GPIO output driver for a [Pin] with the provided [initial output](Level). + #[inline] + pub fn new(pin: impl Peripheral

+ 'd, initial_output: Level) -> Self { + let mut pin = Flex::new(pin); + pin.set_as_output(); + let mut result = Self { pin }; + + match initial_output { + Level::High => result.set_high(), + Level::Low => result.set_low(), + }; + + result + } + + pub fn set_high(&mut self) { + gpio_reg().set[self.pin.pin_bank() as usize].write(|w| unsafe { w.bits(self.pin.bit()) }) + } + + pub fn set_low(&mut self) { + gpio_reg().clr[self.pin.pin_bank() as usize].write(|w| unsafe { w.bits(self.pin.bit()) }) + } + + pub fn toggle(&mut self) { + gpio_reg().not[self.pin.pin_bank() as usize].write(|w| unsafe { w.bits(self.pin.bit()) }) + } + + /// Get the current output level of the pin. Note that the value returned by this function is + /// the voltage level reported by the pin, not the value set by the output driver. + pub fn level(&self) -> Level { + let bits = gpio_reg().pin[self.pin.pin_bank() as usize].read().bits(); + if bits & self.pin.bit() != 0 { + Level::High + } else { + Level::Low + } + } +} + +/// GPIO input driver. Internally, this is a specialized [Flex] pin. +pub struct Input<'d> { + pub(crate) pin: Flex<'d>, +} + +impl<'d> Input<'d> { + /// Create GPIO output driver for a [Pin] with the provided [Pull]. + #[inline] + pub fn new(pin: impl Peripheral

+ 'd, pull: Pull) -> Self { + let mut pin = Flex::new(pin); + pin.set_as_input(); + let mut result = Self { pin }; + result.set_pull(pull); + + result + } + + /// Set the pull configuration for the pin. To disable the pull, use [Pull::None]. + pub fn set_pull(&mut self, pull: Pull) { + match_iocon!(register, iocon_reg(), self.pin.pin_bank(), self.pin.pin_number(), { + register.modify(|_, w| match pull { + Pull::None => w.mode().inactive(), + Pull::Up => w.mode().pull_up(), + Pull::Down => w.mode().pull_down(), + }); + }); + } + + /// Get the current input level of the pin. + pub fn read(&self) -> Level { + let bits = gpio_reg().pin[self.pin.pin_bank() as usize].read().bits(); + if bits & self.pin.bit() != 0 { + Level::High + } else { + Level::Low + } + } +} + +/// A flexible GPIO (digital mode) pin whose mode is not yet determined. Under the hood, this is a +/// reference to a type-erased pin called ["AnyPin"](AnyPin). +pub struct Flex<'d> { + pub(crate) pin: PeripheralRef<'d, AnyPin>, +} + +impl<'d> Flex<'d> { + /// Wrap the pin in a `Flex`. + /// + /// Note: you cannot assume that the pin will be in Digital mode after this call. + #[inline] + pub fn new(pin: impl Peripheral

+ 'd) -> Self { + Self { + pin: pin.into_ref().map_into(), + } + } + + /// Get the bank of this pin. See also [Bank]. + /// + /// # Example + /// + /// ``` + /// use embassy_nxp::gpio::{Bank, Flex}; + /// + /// let p = embassy_nxp::init(Default::default()); + /// let pin = Flex::new(p.PIO1_15); + /// + /// assert_eq!(pin.pin_bank(), Bank::Bank1); + /// ``` + pub fn pin_bank(&self) -> Bank { + self.pin.pin_bank() + } + + /// Get the number of this pin within its bank. See also [Bank]. + /// + /// # Example + /// + /// ``` + /// use embassy_nxp::gpio::Flex; + /// + /// let p = embassy_nxp::init(Default::default()); + /// let pin = Flex::new(p.PIO1_15); + /// + /// assert_eq!(pin.pin_number(), 15 as u8); + /// ``` + pub fn pin_number(&self) -> u8 { + self.pin.pin_number() + } + + /// Get the bit mask for this pin. Useful for setting or clearing bits in a register. Note: + /// PIOx_0 is bit 0, PIOx_1 is bit 1, etc. + /// + /// # Example + /// + /// ``` + /// use embassy_nxp::gpio::Flex; + /// + /// let p = embassy_nxp::init(Default::default()); + /// let pin = Flex::new(p.PIO1_3); + /// + /// assert_eq!(pin.bit(), 0b0000_1000); + /// ``` + pub fn bit(&self) -> u32 { + 1 << self.pin.pin_number() + } + + /// Set the pin to digital mode. This is required for using a pin as a GPIO pin. The default + /// setting for pins is (usually) non-digital. + fn set_as_digital(&mut self) { + match_iocon!(register, iocon_reg(), self.pin_bank(), self.pin_number(), { + register.modify(|_, w| w.digimode().digital()); + }); + } + + /// Set the pin in output mode. This implies setting the pin to digital mode, which this + /// function handles itself. + pub fn set_as_output(&mut self) { + self.set_as_digital(); + gpio_reg().dirset[self.pin.pin_bank() as usize].write(|w| unsafe { w.dirsetp().bits(self.bit()) }) + } + + pub fn set_as_input(&mut self) { + self.set_as_digital(); + gpio_reg().dirclr[self.pin.pin_bank() as usize].write(|w| unsafe { w.dirclrp().bits(self.bit()) }) + } +} + +/// Sealed trait for pins. This trait is sealed and cannot be implemented outside of this crate. +pub(crate) trait SealedPin: Sized { + fn pin_bank(&self) -> Bank; + fn pin_number(&self) -> u8; +} + +/// Interface for a Pin that can be configured by an [Input] or [Output] driver, or converted to an +/// [AnyPin]. By default, this trait is sealed and cannot be implemented outside of the +/// `embassy-nxp` crate due to the [SealedPin] trait. +#[allow(private_bounds)] +pub trait Pin: Peripheral

+ Into + SealedPin + Sized + 'static { + /// Degrade to a generic pin struct + fn degrade(self) -> AnyPin { + AnyPin { + pin_bank: self.pin_bank(), + pin_number: self.pin_number(), + } + } + + /// Returns the pin number within a bank + #[inline] + fn pin(&self) -> u8 { + self.pin_number() + } + + /// Returns the bank of this pin + #[inline] + fn bank(&self) -> Bank { + self.pin_bank() + } +} + +/// Type-erased GPIO pin. +pub struct AnyPin { + pin_bank: Bank, + pin_number: u8, +} + +impl AnyPin { + /// Unsafely create a new type-erased pin. + /// + /// # Safety + /// + /// You must ensure that you’re only using one instance of this type at a time. + pub unsafe fn steal(pin_bank: Bank, pin_number: u8) -> Self { + Self { pin_bank, pin_number } + } +} + +impl_peripheral!(AnyPin); + +impl Pin for AnyPin {} +impl SealedPin for AnyPin { + #[inline] + fn pin_bank(&self) -> Bank { + self.pin_bank + } + + #[inline] + fn pin_number(&self) -> u8 { + self.pin_number + } +} + +macro_rules! impl_pin { + ($name:ident, $bank:expr, $pin_num:expr) => { + impl Pin for peripherals::$name {} + impl SealedPin for peripherals::$name { + #[inline] + fn pin_bank(&self) -> Bank { + $bank + } + + #[inline] + fn pin_number(&self) -> u8 { + $pin_num + } + } + + impl From for crate::gpio::AnyPin { + fn from(val: peripherals::$name) -> Self { + crate::gpio::Pin::degrade(val) + } + } + }; +} + +impl_pin!(PIO0_0, Bank::Bank0, 0); +impl_pin!(PIO0_1, Bank::Bank0, 1); +impl_pin!(PIO0_2, Bank::Bank0, 2); +impl_pin!(PIO0_3, Bank::Bank0, 3); +impl_pin!(PIO0_4, Bank::Bank0, 4); +impl_pin!(PIO0_5, Bank::Bank0, 5); +impl_pin!(PIO0_6, Bank::Bank0, 6); +impl_pin!(PIO0_7, Bank::Bank0, 7); +impl_pin!(PIO0_8, Bank::Bank0, 8); +impl_pin!(PIO0_9, Bank::Bank0, 9); +impl_pin!(PIO0_10, Bank::Bank0, 10); +impl_pin!(PIO0_11, Bank::Bank0, 11); +impl_pin!(PIO0_12, Bank::Bank0, 12); +impl_pin!(PIO0_13, Bank::Bank0, 13); +impl_pin!(PIO0_14, Bank::Bank0, 14); +impl_pin!(PIO0_15, Bank::Bank0, 15); +impl_pin!(PIO0_16, Bank::Bank0, 16); +impl_pin!(PIO0_17, Bank::Bank0, 17); +impl_pin!(PIO0_18, Bank::Bank0, 18); +impl_pin!(PIO0_19, Bank::Bank0, 19); +impl_pin!(PIO0_20, Bank::Bank0, 20); +impl_pin!(PIO0_21, Bank::Bank0, 21); +impl_pin!(PIO0_22, Bank::Bank0, 22); +impl_pin!(PIO0_23, Bank::Bank0, 23); +impl_pin!(PIO0_24, Bank::Bank0, 24); +impl_pin!(PIO0_25, Bank::Bank0, 25); +impl_pin!(PIO0_26, Bank::Bank0, 26); +impl_pin!(PIO0_27, Bank::Bank0, 27); +impl_pin!(PIO0_28, Bank::Bank0, 28); +impl_pin!(PIO0_29, Bank::Bank0, 29); +impl_pin!(PIO0_30, Bank::Bank0, 30); +impl_pin!(PIO0_31, Bank::Bank0, 31); +impl_pin!(PIO1_0, Bank::Bank1, 0); +impl_pin!(PIO1_1, Bank::Bank1, 1); +impl_pin!(PIO1_2, Bank::Bank1, 2); +impl_pin!(PIO1_3, Bank::Bank1, 3); +impl_pin!(PIO1_4, Bank::Bank1, 4); +impl_pin!(PIO1_5, Bank::Bank1, 5); +impl_pin!(PIO1_6, Bank::Bank1, 6); +impl_pin!(PIO1_7, Bank::Bank1, 7); +impl_pin!(PIO1_8, Bank::Bank1, 8); +impl_pin!(PIO1_9, Bank::Bank1, 9); +impl_pin!(PIO1_10, Bank::Bank1, 10); +impl_pin!(PIO1_11, Bank::Bank1, 11); +impl_pin!(PIO1_12, Bank::Bank1, 12); +impl_pin!(PIO1_13, Bank::Bank1, 13); +impl_pin!(PIO1_14, Bank::Bank1, 14); +impl_pin!(PIO1_15, Bank::Bank1, 15); +impl_pin!(PIO1_16, Bank::Bank1, 16); +impl_pin!(PIO1_17, Bank::Bank1, 17); +impl_pin!(PIO1_18, Bank::Bank1, 18); +impl_pin!(PIO1_19, Bank::Bank1, 19); +impl_pin!(PIO1_20, Bank::Bank1, 20); +impl_pin!(PIO1_21, Bank::Bank1, 21); +impl_pin!(PIO1_22, Bank::Bank1, 22); +impl_pin!(PIO1_23, Bank::Bank1, 23); +impl_pin!(PIO1_24, Bank::Bank1, 24); +impl_pin!(PIO1_25, Bank::Bank1, 25); +impl_pin!(PIO1_26, Bank::Bank1, 26); +impl_pin!(PIO1_27, Bank::Bank1, 27); +impl_pin!(PIO1_28, Bank::Bank1, 28); +impl_pin!(PIO1_29, Bank::Bank1, 29); +impl_pin!(PIO1_30, Bank::Bank1, 30); +impl_pin!(PIO1_31, Bank::Bank1, 31); diff --git a/embassy-nxp/src/lib.rs b/embassy-nxp/src/lib.rs new file mode 100644 index 000000000..80fdecb2e --- /dev/null +++ b/embassy-nxp/src/lib.rs @@ -0,0 +1,95 @@ +#![no_std] + +pub mod gpio; +mod pac_utils; +pub mod pint; + +pub use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; +pub use lpc55_pac as pac; + +/// Initialize the `embassy-nxp` HAL with the provided configuration. +/// +/// This returns the peripheral singletons that can be used for creating drivers. +/// +/// This should only be called once and at startup, otherwise it panics. +pub fn init(_config: config::Config) -> Peripherals { + gpio::init(); + pint::init(); + + crate::Peripherals::take() +} + +embassy_hal_internal::peripherals! { + // External pins. These are not only GPIOs, they are multi-purpose pins and can be used by other + // peripheral types (e.g. I2C). + PIO0_0, + PIO0_1, + PIO0_2, + PIO0_3, + PIO0_4, + PIO0_5, + PIO0_6, + PIO0_7, + PIO0_8, + PIO0_9, + PIO0_10, + PIO0_11, + PIO0_12, + PIO0_13, + PIO0_14, + PIO0_15, + PIO0_16, + PIO0_17, + PIO0_18, + PIO0_19, + PIO0_20, + PIO0_21, + PIO0_22, + PIO0_23, + PIO0_24, + PIO0_25, + PIO0_26, + PIO0_27, + PIO0_28, + PIO0_29, + PIO0_30, + PIO0_31, + PIO1_0, + PIO1_1, + PIO1_2, + PIO1_3, + PIO1_4, + PIO1_5, + PIO1_6, + PIO1_7, + PIO1_8, + PIO1_9, + PIO1_10, + PIO1_11, + PIO1_12, + PIO1_13, + PIO1_14, + PIO1_15, + PIO1_16, + PIO1_17, + PIO1_18, + PIO1_19, + PIO1_20, + PIO1_21, + PIO1_22, + PIO1_23, + PIO1_24, + PIO1_25, + PIO1_26, + PIO1_27, + PIO1_28, + PIO1_29, + PIO1_30, + PIO1_31, +} + +/// HAL configuration for the NXP board. +pub mod config { + #[derive(Default)] + pub struct Config {} +} diff --git a/embassy-nxp/src/pac_utils.rs b/embassy-nxp/src/pac_utils.rs new file mode 100644 index 000000000..86a807f6c --- /dev/null +++ b/embassy-nxp/src/pac_utils.rs @@ -0,0 +1,323 @@ +/// Get the GPIO register block. This is used to configure all GPIO pins. +/// +/// # Safety +/// Due to the type system of peripherals, access to the settings of a single pin is possible only +/// by a single thread at a time. Read/Write operations on a single registers are NOT atomic. You +/// must ensure that the GPIO registers are not accessed concurrently by multiple threads. +pub(crate) fn gpio_reg() -> &'static lpc55_pac::gpio::RegisterBlock { + unsafe { &*lpc55_pac::GPIO::ptr() } +} + +/// Get the IOCON register block. +/// +/// # Safety +/// Read/Write operations on a single registers are NOT atomic. You must ensure that the GPIO +/// registers are not accessed concurrently by multiple threads. +pub(crate) fn iocon_reg() -> &'static lpc55_pac::iocon::RegisterBlock { + unsafe { &*lpc55_pac::IOCON::ptr() } +} + +/// Get the INPUTMUX register block. +/// +/// # Safety +/// Read/Write operations on a single registers are NOT atomic. You must ensure that the GPIO +/// registers are not accessed concurrently by multiple threads. +pub(crate) fn inputmux_reg() -> &'static lpc55_pac::inputmux::RegisterBlock { + unsafe { &*lpc55_pac::INPUTMUX::ptr() } +} + +/// Get the SYSCON register block. +/// +/// # Safety +/// Read/Write operations on a single registers are NOT atomic. You must ensure that the GPIO +/// registers are not accessed concurrently by multiple threads. +pub(crate) fn syscon_reg() -> &'static lpc55_pac::syscon::RegisterBlock { + unsafe { &*lpc55_pac::SYSCON::ptr() } +} + +/// Get the PINT register block. +/// +/// # Safety +/// Read/Write operations on a single registers are NOT atomic. You must ensure that the GPIO +/// registers are not accessed concurrently by multiple threads. +pub(crate) fn pint_reg() -> &'static lpc55_pac::pint::RegisterBlock { + unsafe { &*lpc55_pac::PINT::ptr() } +} + +/// Match the pin bank and number of a pin to the corresponding IOCON register. +/// +/// # Example +/// ``` +/// use embassy_nxp::gpio::Bank; +/// use embassy_nxp::pac_utils::{iocon_reg, match_iocon}; +/// +/// // Make pin PIO1_6 digital and set it to pull-down mode. +/// match_iocon!(register, iocon_reg(), Bank::Bank1, 6, { +/// register.modify(|_, w| w.mode().pull_down().digimode().digital()); +/// }); +/// ``` +macro_rules! match_iocon { + ($register:ident, $iocon_register:expr, $pin_bank:expr, $pin_number:expr, $action:expr) => { + match ($pin_bank, $pin_number) { + (Bank::Bank0, 0) => { + let $register = &($iocon_register).pio0_0; + $action; + } + (Bank::Bank0, 1) => { + let $register = &($iocon_register).pio0_1; + $action; + } + (Bank::Bank0, 2) => { + let $register = &($iocon_register).pio0_2; + $action; + } + (Bank::Bank0, 3) => { + let $register = &($iocon_register).pio0_3; + $action; + } + (Bank::Bank0, 4) => { + let $register = &($iocon_register).pio0_4; + $action; + } + (Bank::Bank0, 5) => { + let $register = &($iocon_register).pio0_5; + $action; + } + (Bank::Bank0, 6) => { + let $register = &($iocon_register).pio0_6; + $action; + } + (Bank::Bank0, 7) => { + let $register = &($iocon_register).pio0_7; + $action; + } + (Bank::Bank0, 8) => { + let $register = &($iocon_register).pio0_8; + $action; + } + (Bank::Bank0, 9) => { + let $register = &($iocon_register).pio0_9; + $action; + } + (Bank::Bank0, 10) => { + let $register = &($iocon_register).pio0_10; + $action; + } + (Bank::Bank0, 11) => { + let $register = &($iocon_register).pio0_11; + $action; + } + (Bank::Bank0, 12) => { + let $register = &($iocon_register).pio0_12; + $action; + } + (Bank::Bank0, 13) => { + let $register = &($iocon_register).pio0_13; + $action; + } + (Bank::Bank0, 14) => { + let $register = &($iocon_register).pio0_14; + $action; + } + (Bank::Bank0, 15) => { + let $register = &($iocon_register).pio0_15; + $action; + } + (Bank::Bank0, 16) => { + let $register = &($iocon_register).pio0_16; + $action; + } + (Bank::Bank0, 17) => { + let $register = &($iocon_register).pio0_17; + $action; + } + (Bank::Bank0, 18) => { + let $register = &($iocon_register).pio0_18; + $action; + } + (Bank::Bank0, 19) => { + let $register = &($iocon_register).pio0_19; + $action; + } + (Bank::Bank0, 20) => { + let $register = &($iocon_register).pio0_20; + $action; + } + (Bank::Bank0, 21) => { + let $register = &($iocon_register).pio0_21; + $action; + } + (Bank::Bank0, 22) => { + let $register = &($iocon_register).pio0_22; + $action; + } + (Bank::Bank0, 23) => { + let $register = &($iocon_register).pio0_23; + $action; + } + (Bank::Bank0, 24) => { + let $register = &($iocon_register).pio0_24; + $action; + } + (Bank::Bank0, 25) => { + let $register = &($iocon_register).pio0_25; + $action; + } + (Bank::Bank0, 26) => { + let $register = &($iocon_register).pio0_26; + $action; + } + (Bank::Bank0, 27) => { + let $register = &($iocon_register).pio0_27; + $action; + } + (Bank::Bank0, 28) => { + let $register = &($iocon_register).pio0_28; + $action; + } + (Bank::Bank0, 29) => { + let $register = &($iocon_register).pio0_29; + $action; + } + (Bank::Bank0, 30) => { + let $register = &($iocon_register).pio0_30; + $action; + } + (Bank::Bank0, 31) => { + let $register = &($iocon_register).pio0_31; + $action; + } + (Bank::Bank1, 0) => { + let $register = &($iocon_register).pio1_0; + $action; + } + (Bank::Bank1, 1) => { + let $register = &($iocon_register).pio1_1; + $action; + } + (Bank::Bank1, 2) => { + let $register = &($iocon_register).pio1_2; + $action; + } + (Bank::Bank1, 3) => { + let $register = &($iocon_register).pio1_3; + $action; + } + (Bank::Bank1, 4) => { + let $register = &($iocon_register).pio1_4; + $action; + } + (Bank::Bank1, 5) => { + let $register = &($iocon_register).pio1_5; + $action; + } + (Bank::Bank1, 6) => { + let $register = &($iocon_register).pio1_6; + $action; + } + (Bank::Bank1, 7) => { + let $register = &($iocon_register).pio1_7; + $action; + } + (Bank::Bank1, 8) => { + let $register = &($iocon_register).pio1_8; + $action; + } + (Bank::Bank1, 9) => { + let $register = &($iocon_register).pio1_9; + $action; + } + (Bank::Bank1, 10) => { + let $register = &($iocon_register).pio1_10; + $action; + } + (Bank::Bank1, 11) => { + let $register = &($iocon_register).pio1_11; + $action; + } + (Bank::Bank1, 12) => { + let $register = &($iocon_register).pio1_12; + $action; + } + (Bank::Bank1, 13) => { + let $register = &($iocon_register).pio1_13; + $action; + } + (Bank::Bank1, 14) => { + let $register = &($iocon_register).pio1_14; + $action; + } + (Bank::Bank1, 15) => { + let $register = &($iocon_register).pio1_15; + $action; + } + (Bank::Bank1, 16) => { + let $register = &($iocon_register).pio1_16; + $action; + } + (Bank::Bank1, 17) => { + let $register = &($iocon_register).pio1_17; + $action; + } + (Bank::Bank1, 18) => { + let $register = &($iocon_register).pio1_18; + $action; + } + (Bank::Bank1, 19) => { + let $register = &($iocon_register).pio1_19; + $action; + } + (Bank::Bank1, 20) => { + let $register = &($iocon_register).pio1_20; + $action; + } + (Bank::Bank1, 21) => { + let $register = &($iocon_register).pio1_21; + $action; + } + (Bank::Bank1, 22) => { + let $register = &($iocon_register).pio1_22; + $action; + } + (Bank::Bank1, 23) => { + let $register = &($iocon_register).pio1_23; + $action; + } + (Bank::Bank1, 24) => { + let $register = &($iocon_register).pio1_24; + $action; + } + (Bank::Bank1, 25) => { + let $register = &($iocon_register).pio1_25; + $action; + } + (Bank::Bank1, 26) => { + let $register = &($iocon_register).pio1_26; + $action; + } + (Bank::Bank1, 27) => { + let $register = &($iocon_register).pio1_27; + $action; + } + (Bank::Bank1, 28) => { + let $register = &($iocon_register).pio1_28; + $action; + } + (Bank::Bank1, 29) => { + let $register = &($iocon_register).pio1_29; + $action; + } + (Bank::Bank1, 30) => { + let $register = &($iocon_register).pio1_30; + $action; + } + (Bank::Bank1, 31) => { + let $register = &($iocon_register).pio1_31; + $action; + } + _ => unreachable!(), + } + }; +} + +pub(crate) use match_iocon; diff --git a/embassy-nxp/src/pint.rs b/embassy-nxp/src/pint.rs new file mode 100644 index 000000000..3313f91a6 --- /dev/null +++ b/embassy-nxp/src/pint.rs @@ -0,0 +1,440 @@ +//! Pin Interrupt module. +use core::cell::RefCell; +use core::future::Future; +use core::pin::Pin as FuturePin; +use core::task::{Context, Poll}; + +use critical_section::Mutex; +use embassy_hal_internal::{Peripheral, PeripheralRef}; +use embassy_sync::waitqueue::AtomicWaker; + +use crate::gpio::{self, AnyPin, Level, SealedPin}; +use crate::pac::interrupt; +use crate::pac_utils::*; + +struct PinInterrupt { + assigned: bool, + waker: AtomicWaker, + /// If true, the interrupt was triggered due to this PinInterrupt. This is used to determine if + /// an [InputFuture] should return Poll::Ready. + at_fault: bool, +} + +impl PinInterrupt { + pub fn interrupt_active(&self) -> bool { + self.assigned + } + + /// Mark the interrupt as assigned to a pin. + pub fn enable(&mut self) { + self.assigned = true; + self.at_fault = false; + } + + /// Mark the interrupt as available. + pub fn disable(&mut self) { + self.assigned = false; + self.at_fault = false; + } + + /// Returns true if the interrupt was triggered due to this PinInterrupt. + /// + /// If this function returns true, it will also reset the at_fault flag. + pub fn at_fault(&mut self) -> bool { + let val = self.at_fault; + self.at_fault = false; + val + } + + /// Set the at_fault flag to true. + pub fn fault(&mut self) { + self.at_fault = true; + } +} + +const NEW_PIN_INTERRUPT: PinInterrupt = PinInterrupt { + assigned: false, + waker: AtomicWaker::new(), + at_fault: false, +}; +const INTERUPT_COUNT: usize = 8; +static PIN_INTERRUPTS: Mutex> = + Mutex::new(RefCell::new([NEW_PIN_INTERRUPT; INTERUPT_COUNT])); + +fn next_available_interrupt() -> Option { + critical_section::with(|cs| { + for (i, pin_interrupt) in PIN_INTERRUPTS.borrow(cs).borrow().iter().enumerate() { + if !pin_interrupt.interrupt_active() { + return Some(i); + } + } + + None + }) +} + +#[derive(Clone, Copy, PartialEq, Eq)] +enum Edge { + Rising, + Falling, + Both, +} + +#[derive(Clone, Copy, PartialEq, Eq)] +enum InterruptOn { + Level(Level), + Edge(Edge), +} + +pub(crate) fn init() { + syscon_reg().ahbclkctrl0.modify(|_, w| w.pint().enable()); + + // Enable interrupts + unsafe { + crate::pac::NVIC::unmask(crate::pac::Interrupt::PIN_INT0); + crate::pac::NVIC::unmask(crate::pac::Interrupt::PIN_INT1); + crate::pac::NVIC::unmask(crate::pac::Interrupt::PIN_INT2); + crate::pac::NVIC::unmask(crate::pac::Interrupt::PIN_INT3); + crate::pac::NVIC::unmask(crate::pac::Interrupt::PIN_INT4); + crate::pac::NVIC::unmask(crate::pac::Interrupt::PIN_INT5); + crate::pac::NVIC::unmask(crate::pac::Interrupt::PIN_INT6); + crate::pac::NVIC::unmask(crate::pac::Interrupt::PIN_INT7); + }; +} + +#[must_use = "futures do nothing unless you `.await` or poll them"] +struct InputFuture<'d> { + #[allow(dead_code)] + pin: PeripheralRef<'d, AnyPin>, + interrupt_number: usize, +} + +impl<'d> InputFuture<'d> { + /// Create a new input future. Returns None if all interrupts are in use. + fn new(pin: impl Peripheral

+ 'd, interrupt_on: InterruptOn) -> Option { + let pin = pin.into_ref().map_into(); + let interrupt_number = next_available_interrupt()?; + + // Clear interrupt, just in case + pint_reg() + .rise + .write(|w| unsafe { w.rdet().bits(1 << interrupt_number) }); + pint_reg() + .fall + .write(|w| unsafe { w.fdet().bits(1 << interrupt_number) }); + + // Enable input multiplexing on pin interrupt register 0 for pin (32*bank + pin_number) + inputmux_reg().pintsel[interrupt_number] + .write(|w| unsafe { w.intpin().bits(32 * pin.pin_bank() as u8 + pin.pin_number()) }); + + match interrupt_on { + InterruptOn::Level(level) => { + // Set pin interrupt register to edge sensitive or level sensitive + // 0 = edge sensitive, 1 = level sensitive + pint_reg() + .isel + .modify(|r, w| unsafe { w.bits(r.bits() | (1 << interrupt_number)) }); + + // Enable level interrupt. + // + // Note: Level sensitive interrupts are enabled by the same register as rising edge + // is activated. + + // 0 = no-op, 1 = enable + pint_reg() + .sienr + .write(|w| unsafe { w.setenrl().bits(1 << interrupt_number) }); + + // Set active level + match level { + Level::Low => { + // 0 = no-op, 1 = select LOW + pint_reg() + .cienf + .write(|w| unsafe { w.cenaf().bits(1 << interrupt_number) }); + } + Level::High => { + // 0 = no-op, 1 = select HIGH + pint_reg() + .sienf + .write(|w| unsafe { w.setenaf().bits(1 << interrupt_number) }); + } + } + } + InterruptOn::Edge(edge) => { + // Set pin interrupt register to edge sensitive or level sensitive + // 0 = edge sensitive, 1 = level sensitive + pint_reg() + .isel + .modify(|r, w| unsafe { w.bits(r.bits() & !(1 << interrupt_number)) }); + + // Enable rising/falling edge detection + match edge { + Edge::Rising => { + // 0 = no-op, 1 = enable rising edge + pint_reg() + .sienr + .write(|w| unsafe { w.setenrl().bits(1 << interrupt_number) }); + // 0 = no-op, 1 = disable falling edge + pint_reg() + .cienf + .write(|w| unsafe { w.cenaf().bits(1 << interrupt_number) }); + } + Edge::Falling => { + // 0 = no-op, 1 = enable falling edge + pint_reg() + .sienf + .write(|w| unsafe { w.setenaf().bits(1 << interrupt_number) }); + // 0 = no-op, 1 = disable rising edge + pint_reg() + .cienr + .write(|w| unsafe { w.cenrl().bits(1 << interrupt_number) }); + } + Edge::Both => { + // 0 = no-op, 1 = enable + pint_reg() + .sienr + .write(|w| unsafe { w.setenrl().bits(1 << interrupt_number) }); + pint_reg() + .sienf + .write(|w| unsafe { w.setenaf().bits(1 << interrupt_number) }); + } + } + } + } + + critical_section::with(|cs| { + let mut pin_interrupts = PIN_INTERRUPTS.borrow(cs).borrow_mut(); + let pin_interrupt = &mut pin_interrupts[interrupt_number]; + + pin_interrupt.enable(); + }); + + Some(Self { pin, interrupt_number }) + } + + /// Returns true if the interrupt was triggered for this pin. + fn interrupt_triggered(&self) -> bool { + let interrupt_number = self.interrupt_number; + + // Initially, we determine if the interrupt was triggered by this InputFuture by checking + // the flags of the interrupt_number. However, by the time we get to this point, the + // interrupt may have been triggered again, so we needed to clear the cpu flags immediately. + // As a solution, we mark which [PinInterrupt] is responsible for the interrupt ("at fault") + critical_section::with(|cs| { + let mut pin_interrupts = PIN_INTERRUPTS.borrow(cs).borrow_mut(); + let pin_interrupt = &mut pin_interrupts[interrupt_number]; + + pin_interrupt.at_fault() + }) + } +} + +impl<'d> Drop for InputFuture<'d> { + fn drop(&mut self) { + let interrupt_number = self.interrupt_number; + + // Disable pin interrupt + // 0 = no-op, 1 = disable + pint_reg() + .cienr + .write(|w| unsafe { w.cenrl().bits(1 << interrupt_number) }); + pint_reg() + .cienf + .write(|w| unsafe { w.cenaf().bits(1 << interrupt_number) }); + + critical_section::with(|cs| { + let mut pin_interrupts = PIN_INTERRUPTS.borrow(cs).borrow_mut(); + let pin_interrupt = &mut pin_interrupts[interrupt_number]; + + pin_interrupt.disable(); + }); + } +} + +impl<'d> Future for InputFuture<'d> { + type Output = (); + + fn poll(self: FuturePin<&mut Self>, cx: &mut Context<'_>) -> Poll { + let interrupt_number = self.interrupt_number; + + critical_section::with(|cs| { + let mut pin_interrupts = PIN_INTERRUPTS.borrow(cs).borrow_mut(); + let pin_interrupt = &mut pin_interrupts[interrupt_number]; + + pin_interrupt.waker.register(cx.waker()); + }); + + if self.interrupt_triggered() { + Poll::Ready(()) + } else { + Poll::Pending + } + } +} + +fn handle_interrupt(interrupt_number: usize) { + pint_reg() + .rise + .write(|w| unsafe { w.rdet().bits(1 << interrupt_number) }); + pint_reg() + .fall + .write(|w| unsafe { w.fdet().bits(1 << interrupt_number) }); + + critical_section::with(|cs| { + let mut pin_interrupts = PIN_INTERRUPTS.borrow(cs).borrow_mut(); + let pin_interrupt = &mut pin_interrupts[interrupt_number]; + + pin_interrupt.fault(); + pin_interrupt.waker.wake(); + }); +} + +#[allow(non_snake_case)] +#[interrupt] +fn PIN_INT0() { + handle_interrupt(0); +} + +#[allow(non_snake_case)] +#[interrupt] +fn PIN_INT1() { + handle_interrupt(1); +} + +#[allow(non_snake_case)] +#[interrupt] +fn PIN_INT2() { + handle_interrupt(2); +} + +#[allow(non_snake_case)] +#[interrupt] +fn PIN_INT3() { + handle_interrupt(3); +} + +#[allow(non_snake_case)] +#[interrupt] +fn PIN_INT4() { + handle_interrupt(4); +} + +#[allow(non_snake_case)] +#[interrupt] +fn PIN_INT5() { + handle_interrupt(5); +} + +#[allow(non_snake_case)] +#[interrupt] +fn PIN_INT6() { + handle_interrupt(6); +} + +#[allow(non_snake_case)] +#[interrupt] +fn PIN_INT7() { + handle_interrupt(7); +} + +impl gpio::Flex<'_> { + /// Wait for a falling or rising edge on the pin. You can have at most 8 pins waiting. If you + /// try to wait for more than 8 pins, this function will return `None`. + pub async fn wait_for_any_edge(&mut self) -> Option<()> { + InputFuture::new(&mut self.pin, InterruptOn::Edge(Edge::Both))?.await; + Some(()) + } + + /// Wait for a falling edge on the pin. You can have at most 8 pins waiting. If you try to wait + /// for more than 8 pins, this function will return `None`. + pub async fn wait_for_falling_edge(&mut self) -> Option<()> { + InputFuture::new(&mut self.pin, InterruptOn::Edge(Edge::Falling))?.await; + Some(()) + } + + /// Wait for a rising edge on the pin. You can have at most 8 pins waiting. If you try to wait + /// for more than 8 pins, this function will return `None`. + pub async fn wait_for_rising_edge(&mut self) -> Option<()> { + InputFuture::new(&mut self.pin, InterruptOn::Edge(Edge::Rising))?.await; + Some(()) + } + + /// Wait for a low level on the pin. You can have at most 8 pins waiting. If you try to wait for + /// more than 8 pins, this function will return `None`. + pub async fn wait_for_low(&mut self) -> Option<()> { + InputFuture::new(&mut self.pin, InterruptOn::Level(Level::Low))?.await; + Some(()) + } + + /// Wait for a high level on the pin. You can have at most 8 pins waiting. If you try to wait for + /// more than 8 pins, this function will return `None`. + pub async fn wait_for_high(&mut self) -> Option<()> { + InputFuture::new(&mut self.pin, InterruptOn::Level(Level::High))?.await; + Some(()) + } +} + +impl gpio::Input<'_> { + /// Wait for a falling or rising edge on the pin. You can have at most 8 pins waiting. If you + /// try to wait for more than 8 pins, this function will return `None`. + pub async fn wait_for_any_edge(&mut self) -> Option<()> { + self.pin.wait_for_any_edge().await + } + + /// Wait for a falling edge on the pin. You can have at most 8 pins waiting. If you try to wait + /// for more than 8 pins, this function will return `None`. + pub async fn wait_for_falling_edge(&mut self) -> Option<()> { + self.pin.wait_for_falling_edge().await + } + + /// Wait for a rising edge on the pin. You can have at most 8 pins waiting. If you try to wait + /// for more than 8 pins, this function will return `None`. + pub async fn wait_for_rising_edge(&mut self) -> Option<()> { + self.pin.wait_for_rising_edge().await + } + + /// Wait for a low level on the pin. You can have at most 8 pins waiting. If you try to wait for + /// more than 8 pins, this function will return `None`. + pub async fn wait_for_low(&mut self) -> Option<()> { + self.pin.wait_for_low().await + } + + /// Wait for a high level on the pin. You can have at most 8 pins waiting. If you try to wait for + /// more than 8 pins, this function will return `None`. + pub async fn wait_for_high(&mut self) -> Option<()> { + self.pin.wait_for_high().await + } +} + +impl gpio::Output<'_> { + /// Wait for a falling or rising edge on the pin. You can have at most 8 pins waiting. If you + /// try to wait for more than 8 pins, this function will return `None`. + pub async fn wait_for_any_edge(&mut self) -> Option<()> { + self.pin.wait_for_any_edge().await + } + + /// Wait for a falling edge on the pin. You can have at most 8 pins waiting. If you try to wait + /// for more than 8 pins, this function will return `None`. + pub async fn wait_for_falling_edge(&mut self) -> Option<()> { + self.pin.wait_for_falling_edge().await + } + + /// Wait for a rising edge on the pin. You can have at most 8 pins waiting. If you try to wait + /// for more than 8 pins, this function will return `None`. + pub async fn wait_for_rising_edge(&mut self) -> Option<()> { + self.pin.wait_for_rising_edge().await + } + + /// Wait for a low level on the pin. You can have at most 8 pins waiting. If you try to wait for + /// more than 8 pins, this function will return `None`. + pub async fn wait_for_low(&mut self) -> Option<()> { + self.pin.wait_for_low().await + } + + /// Wait for a high level on the pin. You can have at most 8 pins waiting. If you try to wait for + /// more than 8 pins, this function will return `None`. + pub async fn wait_for_high(&mut self) -> Option<()> { + self.pin.wait_for_high().await + } +} diff --git a/examples/lpc55s69/.cargo/config.toml b/examples/lpc55s69/.cargo/config.toml new file mode 100644 index 000000000..9556de72f --- /dev/null +++ b/examples/lpc55s69/.cargo/config.toml @@ -0,0 +1,8 @@ +[target.'cfg(all(target_arch = "arm", target_os = "none"))'] +runner = "probe-rs run --chip LPC55S69JBD100" + +[build] +target = "thumbv8m.main-none-eabihf" + +[env] +DEFMT_LOG = "debug" diff --git a/examples/lpc55s69/Cargo.toml b/examples/lpc55s69/Cargo.toml new file mode 100644 index 000000000..14ec2d47e --- /dev/null +++ b/examples/lpc55s69/Cargo.toml @@ -0,0 +1,22 @@ +[package] +edition = "2021" +name = "embassy-nxp-lpc55s69-examples" +version = "0.1.0" +license = "MIT OR Apache-2.0" + + +[dependencies] +embassy-nxp = { version = "0.1.0", path = "../../embassy-nxp", features = ["rt"] } +embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt"] } +embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt"] } +panic-halt = "0.2.0" +cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } +cortex-m-rt = {version = "0.7.0"} +defmt = "0.3" +defmt-rtt = "0.4" +panic-probe = { version = "0.3.2", features = ["print-defmt"] } +panic-semihosting = "0.6.0" + +[profile.release] +debug = 2 diff --git a/examples/lpc55s69/build.rs b/examples/lpc55s69/build.rs new file mode 100644 index 000000000..30691aa97 --- /dev/null +++ b/examples/lpc55s69/build.rs @@ -0,0 +1,35 @@ +//! This build script copies the `memory.x` file from the crate root into +//! a directory where the linker can always find it at build time. +//! For many projects this is optional, as the linker always searches the +//! project root directory -- wherever `Cargo.toml` is. However, if you +//! are using a workspace or have a more complicated build setup, this +//! build script becomes required. Additionally, by requesting that +//! Cargo re-run the build script whenever `memory.x` is changed, +//! updating `memory.x` ensures a rebuild of the application with the +//! new memory settings. + +use std::env; +use std::fs::File; +use std::io::Write; +use std::path::PathBuf; + +fn main() { + // Put `memory.x` in our output directory and ensure it's + // on the linker search path. + let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); + File::create(out.join("memory.x")) + .unwrap() + .write_all(include_bytes!("memory.x")) + .unwrap(); + println!("cargo:rustc-link-search={}", out.display()); + + // By default, Cargo will re-run a build script whenever + // any file in the project changes. By specifying `memory.x` + // here, we ensure the build script is only re-run when + // `memory.x` is changed. + println!("cargo:rerun-if-changed=memory.x"); + + println!("cargo:rustc-link-arg-bins=--nmagic"); + println!("cargo:rustc-link-arg-bins=-Tlink.x"); + println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); +} diff --git a/examples/lpc55s69/memory.x b/examples/lpc55s69/memory.x new file mode 100644 index 000000000..1483b2fad --- /dev/null +++ b/examples/lpc55s69/memory.x @@ -0,0 +1,28 @@ +/* File originally from lpc55-hal repo: https://github.com/lpc55/lpc55-hal/blob/main/memory.x */ +MEMORY +{ + FLASH : ORIGIN = 0x00000000, LENGTH = 512K + + /* for use with standard link.x */ + RAM : ORIGIN = 0x20000000, LENGTH = 256K + + /* would be used with proper link.x */ + /* needs changes to r0 (initialization code) */ + /* SRAM0 : ORIGIN = 0x20000000, LENGTH = 64K */ + /* SRAM1 : ORIGIN = 0x20010000, LENGTH = 64K */ + /* SRAM2 : ORIGIN = 0x20020000, LENGTH = 64K */ + /* SRAM3 : ORIGIN = 0x20030000, LENGTH = 64K */ + + /* CASPER SRAM regions */ + /* SRAMX0: ORIGIN = 0x1400_0000, LENGTH = 4K /1* to 0x1400_0FFF *1/ */ + /* SRAMX1: ORIGIN = 0x1400_4000, LENGTH = 4K /1* to 0x1400_4FFF *1/ */ + + /* USB1 SRAM regin */ + /* USB1_SRAM : ORIGIN = 0x40100000, LENGTH = 16K */ + + /* To define our own USB RAM section in one regular */ + /* RAM, probably easiest to shorten length of RAM */ + /* above, and use this freed RAM section */ + +} + diff --git a/examples/lpc55s69/src/bin/blinky_nop.rs b/examples/lpc55s69/src/bin/blinky_nop.rs new file mode 100644 index 000000000..58e2d9808 --- /dev/null +++ b/examples/lpc55s69/src/bin/blinky_nop.rs @@ -0,0 +1,33 @@ +//! This example has been made with the LPCXpresso55S69 board in mind, which has a built-in LED on PIO1_6. + +#![no_std] +#![no_main] + +use cortex_m::asm::nop; +use defmt::*; +use embassy_executor::Spawner; +use embassy_nxp::gpio::{Level, Output}; +use {defmt_rtt as _, panic_halt as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_nxp::init(Default::default()); + + let mut led = Output::new(p.PIO1_6, Level::Low); + + loop { + info!("led off!"); + led.set_high(); + + for _ in 0..200_000 { + nop(); + } + + info!("led on!"); + led.set_low(); + + for _ in 0..200_000 { + nop(); + } + } +} diff --git a/examples/lpc55s69/src/bin/button_executor.rs b/examples/lpc55s69/src/bin/button_executor.rs new file mode 100644 index 000000000..836b1c9eb --- /dev/null +++ b/examples/lpc55s69/src/bin/button_executor.rs @@ -0,0 +1,25 @@ +//! This example has been made with the LPCXpresso55S69 board in mind, which has a built-in LED on +//! PIO1_6 and a button (labeled "user") on PIO1_9. + +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_nxp::gpio::{Input, Level, Output, Pull}; +use {defmt_rtt as _, panic_halt as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) -> ! { + let p = embassy_nxp::init(Default::default()); + + let mut led = Output::new(p.PIO1_6, Level::Low); + let mut button = Input::new(p.PIO1_9, Pull::Up); + + info!("Entered main loop"); + loop { + button.wait_for_rising_edge().await; + info!("Button pressed"); + led.toggle(); + } +} From baef775f6b33b4fd45dd3a4bb1122a52c6d22c67 Mon Sep 17 00:00:00 2001 From: Oliver Rockstedt Date: Mon, 7 Oct 2024 13:30:46 +0200 Subject: [PATCH 0197/1217] Add capacity, free_capacity, clear, len, is_empty and is_full functions to Channel::{Sender, Receiver} --- embassy-sync/CHANGELOG.md | 1 + embassy-sync/src/channel.rs | 84 +++++++++++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+) diff --git a/embassy-sync/CHANGELOG.md b/embassy-sync/CHANGELOG.md index 8847e7e88..253a6cc82 100644 --- a/embassy-sync/CHANGELOG.md +++ b/embassy-sync/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Add LazyLock sync primitive. - Add `clear`, `len`, `is_empty` and `is_full` functions to `zerocopy_channel`. +- Add `capacity`, `free_capacity`, `clear`, `len`, `is_empty` and `is_full` functions to `Channel::{Sender, Receiver}`. ## 0.6.0 - 2024-05-29 diff --git a/embassy-sync/src/channel.rs b/embassy-sync/src/channel.rs index 55ac5fb66..18b053111 100644 --- a/embassy-sync/src/channel.rs +++ b/embassy-sync/src/channel.rs @@ -72,6 +72,48 @@ where pub fn poll_ready_to_send(&self, cx: &mut Context<'_>) -> Poll<()> { self.channel.poll_ready_to_send(cx) } + + /// Returns the maximum number of elements the channel can hold. + /// + /// See [`Channel::capacity()`] + pub const fn capacity(&self) -> usize { + self.channel.capacity() + } + + /// Returns the free capacity of the channel. + /// + /// See [`Channel::free_capacity()`] + pub fn free_capacity(&self) -> usize { + self.channel.free_capacity() + } + + /// Clears all elements in the channel. + /// + /// See [`Channel::clear()`] + pub fn clear(&self) { + self.channel.clear(); + } + + /// Returns the number of elements currently in the channel. + /// + /// See [`Channel::len()`] + pub fn len(&self) -> usize { + self.channel.len() + } + + /// Returns whether the channel is empty. + /// + /// See [`Channel::is_empty()`] + pub fn is_empty(&self) -> bool { + self.channel.is_empty() + } + + /// Returns whether the channel is full. + /// + /// See [`Channel::is_full()`] + pub fn is_full(&self) -> bool { + self.channel.is_full() + } } /// Send-only access to a [`Channel`] without knowing channel size. @@ -179,6 +221,48 @@ where pub fn poll_receive(&self, cx: &mut Context<'_>) -> Poll { self.channel.poll_receive(cx) } + + /// Returns the maximum number of elements the channel can hold. + /// + /// See [`Channel::capacity()`] + pub const fn capacity(&self) -> usize { + self.channel.capacity() + } + + /// Returns the free capacity of the channel. + /// + /// See [`Channel::free_capacity()`] + pub fn free_capacity(&self) -> usize { + self.channel.free_capacity() + } + + /// Clears all elements in the channel. + /// + /// See [`Channel::clear()`] + pub fn clear(&self) { + self.channel.clear(); + } + + /// Returns the number of elements currently in the channel. + /// + /// See [`Channel::len()`] + pub fn len(&self) -> usize { + self.channel.len() + } + + /// Returns whether the channel is empty. + /// + /// See [`Channel::is_empty()`] + pub fn is_empty(&self) -> bool { + self.channel.is_empty() + } + + /// Returns whether the channel is full. + /// + /// See [`Channel::is_full()`] + pub fn is_full(&self) -> bool { + self.channel.is_full() + } } /// Receive-only access to a [`Channel`] without knowing channel size. From e3fd33d372b96cd32007dbffe5755150c3df22f2 Mon Sep 17 00:00:00 2001 From: Oliver Rockstedt Date: Mon, 7 Oct 2024 13:41:15 +0200 Subject: [PATCH 0198/1217] Minor changelog fix --- embassy-sync/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-sync/CHANGELOG.md b/embassy-sync/CHANGELOG.md index 253a6cc82..83fd666ac 100644 --- a/embassy-sync/CHANGELOG.md +++ b/embassy-sync/CHANGELOG.md @@ -9,7 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Add LazyLock sync primitive. - Add `clear`, `len`, `is_empty` and `is_full` functions to `zerocopy_channel`. -- Add `capacity`, `free_capacity`, `clear`, `len`, `is_empty` and `is_full` functions to `Channel::{Sender, Receiver}`. +- Add `capacity`, `free_capacity`, `clear`, `len`, `is_empty` and `is_full` functions to `channel::{Sender, Receiver}`. ## 0.6.0 - 2024-05-29 From 07748131dde887d214c1d9373ec642907d547dcd Mon Sep 17 00:00:00 2001 From: Oliver Rockstedt Date: Mon, 7 Oct 2024 17:24:56 +0200 Subject: [PATCH 0199/1217] embassy-sync: fixed link to priority_channel in README --- embassy-sync/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-sync/README.md b/embassy-sync/README.md index 3dcd9dcc8..6871bcabc 100644 --- a/embassy-sync/README.md +++ b/embassy-sync/README.md @@ -5,7 +5,7 @@ An [Embassy](https://embassy.dev) project. Synchronization primitives and data structures with async support: - [`Channel`](channel::Channel) - A Multiple Producer Multiple Consumer (MPMC) channel. Each message is only received by a single consumer. -- [`PriorityChannel`](channel::priority_channel::PriorityChannel) - A Multiple Producer Multiple Consumer (MPMC) channel. Each message is only received by a single consumer. Higher priority items are shifted to the front of the channel. +- [`PriorityChannel`](priority_channel::PriorityChannel) - A Multiple Producer Multiple Consumer (MPMC) channel. Each message is only received by a single consumer. Higher priority items are shifted to the front of the channel. - [`PubSubChannel`](pubsub::PubSubChannel) - A broadcast channel (publish-subscribe) channel. Each message is received by all consumers. - [`Signal`](signal::Signal) - Signalling latest value to a single consumer. - [`Watch`](watch::Watch) - Signalling latest value to multiple consumers. From 2704ac3d289650173b60e1a29d70e8903bea4cf1 Mon Sep 17 00:00:00 2001 From: Oliver Rockstedt Date: Mon, 7 Oct 2024 17:35:11 +0200 Subject: [PATCH 0200/1217] Add capacity, free_capacity, clear, len, is_empty and is_full functions to priority_channel::{Sender, Receiver} --- embassy-sync/CHANGELOG.md | 1 + embassy-sync/src/priority_channel.rs | 84 ++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+) diff --git a/embassy-sync/CHANGELOG.md b/embassy-sync/CHANGELOG.md index 83fd666ac..1668c9319 100644 --- a/embassy-sync/CHANGELOG.md +++ b/embassy-sync/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Add LazyLock sync primitive. - Add `clear`, `len`, `is_empty` and `is_full` functions to `zerocopy_channel`. - Add `capacity`, `free_capacity`, `clear`, `len`, `is_empty` and `is_full` functions to `channel::{Sender, Receiver}`. +- Add `capacity`, `free_capacity`, `clear`, `len`, `is_empty` and `is_full` functions to `priority_channel::{Sender, Receiver}`. ## 0.6.0 - 2024-05-29 diff --git a/embassy-sync/src/priority_channel.rs b/embassy-sync/src/priority_channel.rs index 24c6c5a7f..1f4d8667c 100644 --- a/embassy-sync/src/priority_channel.rs +++ b/embassy-sync/src/priority_channel.rs @@ -71,6 +71,48 @@ where pub fn poll_ready_to_send(&self, cx: &mut Context<'_>) -> Poll<()> { self.channel.poll_ready_to_send(cx) } + + /// Returns the maximum number of elements the channel can hold. + /// + /// See [`PriorityChannel::capacity()`] + pub const fn capacity(&self) -> usize { + self.channel.capacity() + } + + /// Returns the free capacity of the channel. + /// + /// See [`PriorityChannel::free_capacity()`] + pub fn free_capacity(&self) -> usize { + self.channel.free_capacity() + } + + /// Clears all elements in the channel. + /// + /// See [`PriorityChannel::clear()`] + pub fn clear(&self) { + self.channel.clear(); + } + + /// Returns the number of elements currently in the channel. + /// + /// See [`PriorityChannel::len()`] + pub fn len(&self) -> usize { + self.channel.len() + } + + /// Returns whether the channel is empty. + /// + /// See [`PriorityChannel::is_empty()`] + pub fn is_empty(&self) -> bool { + self.channel.is_empty() + } + + /// Returns whether the channel is full. + /// + /// See [`PriorityChannel::is_full()`] + pub fn is_full(&self) -> bool { + self.channel.is_full() + } } impl<'ch, M, T, K, const N: usize> From> for DynamicSender<'ch, T> @@ -146,6 +188,48 @@ where pub fn poll_receive(&self, cx: &mut Context<'_>) -> Poll { self.channel.poll_receive(cx) } + + /// Returns the maximum number of elements the channel can hold. + /// + /// See [`PriorityChannel::capacity()`] + pub const fn capacity(&self) -> usize { + self.channel.capacity() + } + + /// Returns the free capacity of the channel. + /// + /// See [`PriorityChannel::free_capacity()`] + pub fn free_capacity(&self) -> usize { + self.channel.free_capacity() + } + + /// Clears all elements in the channel. + /// + /// See [`PriorityChannel::clear()`] + pub fn clear(&self) { + self.channel.clear(); + } + + /// Returns the number of elements currently in the channel. + /// + /// See [`PriorityChannel::len()`] + pub fn len(&self) -> usize { + self.channel.len() + } + + /// Returns whether the channel is empty. + /// + /// See [`PriorityChannel::is_empty()`] + pub fn is_empty(&self) -> bool { + self.channel.is_empty() + } + + /// Returns whether the channel is full. + /// + /// See [`PriorityChannel::is_full()`] + pub fn is_full(&self) -> bool { + self.channel.is_full() + } } impl<'ch, M, T, K, const N: usize> From> for DynamicReceiver<'ch, T> From bf60b239e87faa0b9905a42013d8ae9a9f4162ea Mon Sep 17 00:00:00 2001 From: Oliver Rockstedt Date: Mon, 7 Oct 2024 18:05:15 +0200 Subject: [PATCH 0201/1217] embassy-sync: fixed some clippy warnings --- embassy-sync/src/blocking_mutex/mod.rs | 1 + embassy-sync/src/mutex.rs | 2 +- embassy-sync/src/pubsub/mod.rs | 4 ++-- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/embassy-sync/src/blocking_mutex/mod.rs b/embassy-sync/src/blocking_mutex/mod.rs index 8a4a4c642..beafdb43d 100644 --- a/embassy-sync/src/blocking_mutex/mod.rs +++ b/embassy-sync/src/blocking_mutex/mod.rs @@ -104,6 +104,7 @@ impl Mutex { impl Mutex { /// Borrows the data + #[allow(clippy::should_implement_trait)] pub fn borrow(&self) -> &T { let ptr = self.data.get() as *const T; unsafe { &*ptr } diff --git a/embassy-sync/src/mutex.rs b/embassy-sync/src/mutex.rs index 8c3a3af9f..08f66e374 100644 --- a/embassy-sync/src/mutex.rs +++ b/embassy-sync/src/mutex.rs @@ -138,7 +138,7 @@ impl From for Mutex { impl Default for Mutex where M: RawMutex, - T: ?Sized + Default, + T: Default, { fn default() -> Self { Self::new(Default::default()) diff --git a/embassy-sync/src/pubsub/mod.rs b/embassy-sync/src/pubsub/mod.rs index 812302e2b..ae5951829 100644 --- a/embassy-sync/src/pubsub/mod.rs +++ b/embassy-sync/src/pubsub/mod.rs @@ -27,8 +27,8 @@ pub use subscriber::{DynSubscriber, Subscriber}; /// /// - With [Pub::publish()] the publisher has to wait until there is space in the internal message queue. /// - With [Pub::publish_immediate()] the publisher doesn't await and instead lets the oldest message -/// in the queue drop if necessary. This will cause any [Subscriber] that missed the message to receive -/// an error to indicate that it has lagged. +/// in the queue drop if necessary. This will cause any [Subscriber] that missed the message to receive +/// an error to indicate that it has lagged. /// /// ## Example /// From 4110cb494fa21184f46dbbc2fd81baaeb3d0dc26 Mon Sep 17 00:00:00 2001 From: Oliver Rockstedt Date: Mon, 7 Oct 2024 18:12:45 +0200 Subject: [PATCH 0202/1217] embassy-sync: added Watch primitive to changelog --- embassy-sync/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/embassy-sync/CHANGELOG.md b/embassy-sync/CHANGELOG.md index 1668c9319..af5682560 100644 --- a/embassy-sync/CHANGELOG.md +++ b/embassy-sync/CHANGELOG.md @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased - Add LazyLock sync primitive. +- Add `Watch` sync primitive. - Add `clear`, `len`, `is_empty` and `is_full` functions to `zerocopy_channel`. - Add `capacity`, `free_capacity`, `clear`, `len`, `is_empty` and `is_full` functions to `channel::{Sender, Receiver}`. - Add `capacity`, `free_capacity`, `clear`, `len`, `is_empty` and `is_full` functions to `priority_channel::{Sender, Receiver}`. From 592bb5a8ca8138b95ba878cd6e509c0a21d088d5 Mon Sep 17 00:00:00 2001 From: Oliver Rockstedt Date: Mon, 7 Oct 2024 18:16:47 +0200 Subject: [PATCH 0203/1217] embassy-sync: made changelog formatting more consistent --- embassy-sync/CHANGELOG.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/embassy-sync/CHANGELOG.md b/embassy-sync/CHANGELOG.md index af5682560..a7dd6f66e 100644 --- a/embassy-sync/CHANGELOG.md +++ b/embassy-sync/CHANGELOG.md @@ -7,7 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased -- Add LazyLock sync primitive. +- Add `LazyLock` sync primitive. - Add `Watch` sync primitive. - Add `clear`, `len`, `is_empty` and `is_full` functions to `zerocopy_channel`. - Add `capacity`, `free_capacity`, `clear`, `len`, `is_empty` and `is_full` functions to `channel::{Sender, Receiver}`. @@ -20,20 +20,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Add `capacity`, `free_capacity`, `clear`, `len`, `is_empty` and `is_full` functions to `PubSubChannel`. - Made `PubSubBehavior` sealed - If you called `.publish_immediate(...)` on the queue directly before, then now call `.immediate_publisher().publish_immediate(...)` -- Add OnceLock sync primitive. -- Add constructor for DynamicChannel -- Add ready_to_receive functions to Channel and Receiver. +- Add `OnceLock` sync primitive. +- Add constructor for `DynamicChannel` +- Add ready_to_receive functions to `Channel` and `Receiver`. ## 0.5.0 - 2023-12-04 -- Add a PriorityChannel. -- Remove nightly and unstable-traits features in preparation for 1.75. -- Upgrade heapless to 0.8. -- Upgrade static-cell to 2.0. +- Add a `PriorityChannel`. +- Remove `nightly` and `unstable-traits` features in preparation for 1.75. +- Upgrade `heapless` to 0.8. +- Upgrade `static-cell` to 2.0. ## 0.4.0 - 2023-10-31 -- Re-add impl_trait_projections +- Re-add `impl_trait_projections` - switch to `embedded-io 0.6` ## 0.3.0 - 2023-09-14 From df0fc041981105a19beb690e30c3ab1f532d7298 Mon Sep 17 00:00:00 2001 From: Lena Berlin Date: Wed, 11 Sep 2024 11:36:24 -0400 Subject: [PATCH 0204/1217] fix: stm32l0 low-power EXTI IRQ handler wiped pending bits before they were checked --- embassy-stm32/src/exti.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/embassy-stm32/src/exti.rs b/embassy-stm32/src/exti.rs index 224d51b84..87512c92d 100644 --- a/embassy-stm32/src/exti.rs +++ b/embassy-stm32/src/exti.rs @@ -41,9 +41,6 @@ fn exticr_regs() -> pac::afio::Afio { } unsafe fn on_irq() { - #[cfg(feature = "low-power")] - crate::low_power::on_wakeup_irq(); - #[cfg(not(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50)))] let bits = EXTI.pr(0).read().0; #[cfg(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50))] @@ -68,6 +65,9 @@ unsafe fn on_irq() { EXTI.rpr(0).write_value(Lines(bits)); EXTI.fpr(0).write_value(Lines(bits)); } + + #[cfg(feature = "low-power")] + crate::low_power::on_wakeup_irq(); } struct BitIter(u32); From 57c1fbf3089e2a2dc9fe5b7d1f1e094596566395 Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Wed, 9 Oct 2024 10:04:35 -0400 Subject: [PATCH 0205/1217] Move pio programs into embassy-rp --- embassy-rp/Cargo.toml | 1 + embassy-rp/src/lib.rs | 1 + embassy-rp/src/pio_programs/hd44780.rs | 203 ++++++++++++++++ embassy-rp/src/pio_programs/i2s.rs | 97 ++++++++ embassy-rp/src/pio_programs/mod.rs | 10 + embassy-rp/src/pio_programs/onewire.rs | 109 +++++++++ embassy-rp/src/pio_programs/pwm.rs | 114 +++++++++ embassy-rp/src/pio_programs/rotary_encoder.rs | 72 ++++++ embassy-rp/src/pio_programs/stepper.rs | 146 ++++++++++++ embassy-rp/src/pio_programs/uart.rs | 186 +++++++++++++++ embassy-rp/src/pio_programs/ws2812.rs | 118 ++++++++++ examples/rp/Cargo.toml | 2 +- examples/rp/src/bin/pio_hd44780.rs | 201 ++-------------- examples/rp/src/bin/pio_i2s.rs | 71 ++---- examples/rp/src/bin/pio_onewire.rs | 98 +------- examples/rp/src/bin/pio_pwm.rs | 90 +------ examples/rp/src/bin/pio_rotary_encoder.rs | 91 +++---- examples/rp/src/bin/pio_servo.rs | 96 +------- examples/rp/src/bin/pio_stepper.rs | 135 +---------- examples/rp/src/bin/pio_uart.rs | 222 ++---------------- examples/rp/src/bin/pio_ws2812.rs | 105 +-------- examples/rp23/src/bin/pio_hd44780.rs | 201 ++-------------- examples/rp23/src/bin/pio_i2s.rs | 77 ++---- examples/rp23/src/bin/pio_onewire.rs | 88 +++++++ examples/rp23/src/bin/pio_pwm.rs | 90 +------ examples/rp23/src/bin/pio_rotary_encoder.rs | 91 +++---- examples/rp23/src/bin/pio_servo.rs | 96 +------- examples/rp23/src/bin/pio_stepper.rs | 135 +---------- examples/rp23/src/bin/pio_uart.rs | 203 ++++++++++++++++ examples/rp23/src/bin/pio_ws2812.rs | 105 +-------- 30 files changed, 1590 insertions(+), 1664 deletions(-) create mode 100644 embassy-rp/src/pio_programs/hd44780.rs create mode 100644 embassy-rp/src/pio_programs/i2s.rs create mode 100644 embassy-rp/src/pio_programs/mod.rs create mode 100644 embassy-rp/src/pio_programs/onewire.rs create mode 100644 embassy-rp/src/pio_programs/pwm.rs create mode 100644 embassy-rp/src/pio_programs/rotary_encoder.rs create mode 100644 embassy-rp/src/pio_programs/stepper.rs create mode 100644 embassy-rp/src/pio_programs/uart.rs create mode 100644 embassy-rp/src/pio_programs/ws2812.rs create mode 100644 examples/rp23/src/bin/pio_onewire.rs create mode 100644 examples/rp23/src/bin/pio_uart.rs diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index 29a8a3c53..54de238b3 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml @@ -144,6 +144,7 @@ rp2040-boot2 = "0.3" document-features = "0.2.7" sha2-const-stable = "0.1" rp-binary-info = { version = "0.1.0", optional = true } +smart-leds = "0.4.0" [dev-dependencies] embassy-executor = { version = "0.6.0", path = "../embassy-executor", features = ["arch-std", "executor-thread"] } diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs index d402cf793..7ac18c1f8 100644 --- a/embassy-rp/src/lib.rs +++ b/embassy-rp/src/lib.rs @@ -34,6 +34,7 @@ pub mod i2c_slave; pub mod multicore; #[cfg(feature = "_rp235x")] pub mod otp; +pub mod pio_programs; pub mod pwm; mod reset; pub mod rom_data; diff --git a/embassy-rp/src/pio_programs/hd44780.rs b/embassy-rp/src/pio_programs/hd44780.rs new file mode 100644 index 000000000..9bbf44fc4 --- /dev/null +++ b/embassy-rp/src/pio_programs/hd44780.rs @@ -0,0 +1,203 @@ +//! [HD44780 display driver](https://www.sparkfun.com/datasheets/LCD/HD44780.pdf) + +use crate::dma::{AnyChannel, Channel}; +use crate::pio::{ + Common, Config, Direction, FifoJoin, Instance, Irq, LoadedProgram, PioPin, ShiftConfig, ShiftDirection, + StateMachine, +}; +use crate::{into_ref, Peripheral, PeripheralRef}; + +/// This struct represents a HD44780 program that takes command words ( <0:4>) +pub struct PioHD44780CommandWordProgram<'a, PIO: Instance> { + prg: LoadedProgram<'a, PIO>, +} + +impl<'a, PIO: Instance> PioHD44780CommandWordProgram<'a, PIO> { + /// Load the program into the given pio + pub fn new(common: &mut Common<'a, PIO>) -> Self { + let prg = pio_proc::pio_asm!( + r#" + .side_set 1 opt + .origin 20 + + loop: + out x, 24 + delay: + jmp x--, delay + out pins, 4 side 1 + out null, 4 side 0 + jmp !osre, loop + irq 0 + "#, + ); + + let prg = common.load_program(&prg.program); + + Self { prg } + } +} + +/// This struct represents a HD44780 program that takes command sequences ( , data...) +pub struct PioHD44780CommandSequenceProgram<'a, PIO: Instance> { + prg: LoadedProgram<'a, PIO>, +} + +impl<'a, PIO: Instance> PioHD44780CommandSequenceProgram<'a, PIO> { + /// Load the program into the given pio + pub fn new(common: &mut Common<'a, PIO>) -> Self { + // many side sets are only there to free up a delay bit! + let prg = pio_proc::pio_asm!( + r#" + .origin 27 + .side_set 1 + + .wrap_target + pull side 0 + out x 1 side 0 ; !rs + out y 7 side 0 ; #data - 1 + + ; rs/rw to e: >= 60ns + ; e high time: >= 500ns + ; e low time: >= 500ns + ; read data valid after e falling: ~5ns + ; write data hold after e falling: ~10ns + + loop: + pull side 0 + jmp !x data side 0 + command: + set pins 0b00 side 0 + jmp shift side 0 + data: + set pins 0b01 side 0 + shift: + out pins 4 side 1 [9] + nop side 0 [9] + out pins 4 side 1 [9] + mov osr null side 0 [7] + out pindirs 4 side 0 + set pins 0b10 side 0 + busy: + nop side 1 [9] + jmp pin more side 0 [9] + mov osr ~osr side 1 [9] + nop side 0 [4] + out pindirs 4 side 0 + jmp y-- loop side 0 + .wrap + more: + nop side 1 [9] + jmp busy side 0 [9] + "# + ); + + let prg = common.load_program(&prg.program); + + Self { prg } + } +} + +/// Pio backed HD44780 driver +pub struct PioHD44780<'l, P: Instance, const S: usize> { + dma: PeripheralRef<'l, AnyChannel>, + sm: StateMachine<'l, P, S>, + + buf: [u8; 40], +} + +impl<'l, P: Instance, const S: usize> PioHD44780<'l, P, S> { + /// Configure the given state machine to first init, then write data to, a HD44780 display. + pub async fn new( + common: &mut Common<'l, P>, + mut sm: StateMachine<'l, P, S>, + mut irq: Irq<'l, P, S>, + dma: impl Peripheral

+ 'l, + rs: impl PioPin, + rw: impl PioPin, + e: impl PioPin, + db4: impl PioPin, + db5: impl PioPin, + db6: impl PioPin, + db7: impl PioPin, + word_prg: &PioHD44780CommandWordProgram<'l, P>, + seq_prg: &PioHD44780CommandSequenceProgram<'l, P>, + ) -> PioHD44780<'l, P, S> { + into_ref!(dma); + + let rs = common.make_pio_pin(rs); + let rw = common.make_pio_pin(rw); + let e = common.make_pio_pin(e); + let db4 = common.make_pio_pin(db4); + let db5 = common.make_pio_pin(db5); + let db6 = common.make_pio_pin(db6); + let db7 = common.make_pio_pin(db7); + + sm.set_pin_dirs(Direction::Out, &[&rs, &rw, &e, &db4, &db5, &db6, &db7]); + + let mut cfg = Config::default(); + cfg.use_program(&word_prg.prg, &[&e]); + cfg.clock_divider = 125u8.into(); + cfg.set_out_pins(&[&db4, &db5, &db6, &db7]); + cfg.shift_out = ShiftConfig { + auto_fill: true, + direction: ShiftDirection::Left, + threshold: 32, + }; + cfg.fifo_join = FifoJoin::TxOnly; + sm.set_config(&cfg); + + sm.set_enable(true); + // init to 8 bit thrice + sm.tx().push((50000 << 8) | 0x30); + sm.tx().push((5000 << 8) | 0x30); + sm.tx().push((200 << 8) | 0x30); + // init 4 bit + sm.tx().push((200 << 8) | 0x20); + // set font and lines + sm.tx().push((50 << 8) | 0x20); + sm.tx().push(0b1100_0000); + + irq.wait().await; + sm.set_enable(false); + + let mut cfg = Config::default(); + cfg.use_program(&seq_prg.prg, &[&e]); + cfg.clock_divider = 8u8.into(); // ~64ns/insn + cfg.set_jmp_pin(&db7); + cfg.set_set_pins(&[&rs, &rw]); + cfg.set_out_pins(&[&db4, &db5, &db6, &db7]); + cfg.shift_out.direction = ShiftDirection::Left; + cfg.fifo_join = FifoJoin::TxOnly; + sm.set_config(&cfg); + + sm.set_enable(true); + + // display on and cursor on and blinking, reset display + sm.tx().dma_push(dma.reborrow(), &[0x81u8, 0x0f, 1]).await; + + Self { + dma: dma.map_into(), + sm, + buf: [0x20; 40], + } + } + + /// Write a line to the display + pub async fn add_line(&mut self, s: &[u8]) { + // move cursor to 0:0, prepare 16 characters + self.buf[..3].copy_from_slice(&[0x80, 0x80, 15]); + // move line 2 up + self.buf.copy_within(22..38, 3); + // move cursor to 1:0, prepare 16 characters + self.buf[19..22].copy_from_slice(&[0x80, 0xc0, 15]); + // file line 2 with spaces + self.buf[22..38].fill(0x20); + // copy input line + let len = s.len().min(16); + self.buf[22..22 + len].copy_from_slice(&s[0..len]); + // set cursor to 1:15 + self.buf[38..].copy_from_slice(&[0x80, 0xcf]); + + self.sm.tx().dma_push(self.dma.reborrow(), &self.buf).await; + } +} diff --git a/embassy-rp/src/pio_programs/i2s.rs b/embassy-rp/src/pio_programs/i2s.rs new file mode 100644 index 000000000..3c8ef8bb6 --- /dev/null +++ b/embassy-rp/src/pio_programs/i2s.rs @@ -0,0 +1,97 @@ +//! Pio backed I2s output + +use crate::{ + dma::{AnyChannel, Channel, Transfer}, + into_ref, + pio::{ + Common, Config, Direction, FifoJoin, Instance, LoadedProgram, PioPin, ShiftConfig, ShiftDirection, StateMachine, + }, + Peripheral, PeripheralRef, +}; +use fixed::traits::ToFixed; + +/// This struct represents an i2s output driver program +pub struct PioI2sOutProgram<'a, PIO: Instance> { + prg: LoadedProgram<'a, PIO>, +} + +impl<'a, PIO: Instance> PioI2sOutProgram<'a, PIO> { + /// Load the program into the given pio + pub fn new(common: &mut Common<'a, PIO>) -> Self { + let prg = pio_proc::pio_asm!( + ".side_set 2", + " set x, 14 side 0b01", // side 0bWB - W = Word Clock, B = Bit Clock + "left_data:", + " out pins, 1 side 0b00", + " jmp x-- left_data side 0b01", + " out pins 1 side 0b10", + " set x, 14 side 0b11", + "right_data:", + " out pins 1 side 0b10", + " jmp x-- right_data side 0b11", + " out pins 1 side 0b00", + ); + + let prg = common.load_program(&prg.program); + + Self { prg } + } +} + +/// Pio backed I2s output driver +pub struct PioI2sOut<'a, P: Instance, const S: usize> { + dma: PeripheralRef<'a, AnyChannel>, + sm: StateMachine<'a, P, S>, +} + +impl<'a, P: Instance, const S: usize> PioI2sOut<'a, P, S> { + /// Configure a state machine to output I2s + pub fn new( + common: &mut Common<'a, P>, + mut sm: StateMachine<'a, P, S>, + dma: impl Peripheral

+ 'a, + data_pin: impl PioPin, + bit_clock_pin: impl PioPin, + lr_clock_pin: impl PioPin, + sample_rate: u32, + bit_depth: u32, + channels: u32, + program: &PioI2sOutProgram<'a, P>, + ) -> Self { + into_ref!(dma); + + let data_pin = common.make_pio_pin(data_pin); + let bit_clock_pin = common.make_pio_pin(bit_clock_pin); + let left_right_clock_pin = common.make_pio_pin(lr_clock_pin); + + let cfg = { + let mut cfg = Config::default(); + cfg.use_program(&program.prg, &[&bit_clock_pin, &left_right_clock_pin]); + cfg.set_out_pins(&[&data_pin]); + let clock_frequency = sample_rate * bit_depth * channels; + cfg.clock_divider = (125_000_000. / clock_frequency as f64 / 2.).to_fixed(); + cfg.shift_out = ShiftConfig { + threshold: 32, + direction: ShiftDirection::Left, + auto_fill: true, + }; + // join fifos to have twice the time to start the next dma transfer + cfg.fifo_join = FifoJoin::TxOnly; + cfg + }; + sm.set_config(&cfg); + sm.set_pin_dirs(Direction::Out, &[&data_pin, &left_right_clock_pin, &bit_clock_pin]); + + sm.set_enable(true); + + Self { + dma: dma.map_into(), + sm, + } + } + + /// Return an in-prograss dma transfer future. Awaiting it will guarentee a complete transfer. + pub fn write<'b>(&'b mut self, buff: &'b [u32]) -> Transfer<'b, AnyChannel> { + self.sm.tx().dma_push(self.dma.reborrow(), buff) + } +} diff --git a/embassy-rp/src/pio_programs/mod.rs b/embassy-rp/src/pio_programs/mod.rs new file mode 100644 index 000000000..74537825b --- /dev/null +++ b/embassy-rp/src/pio_programs/mod.rs @@ -0,0 +1,10 @@ +//! Pre-built pio programs for common interfaces + +pub mod hd44780; +pub mod i2s; +pub mod onewire; +pub mod pwm; +pub mod rotary_encoder; +pub mod stepper; +pub mod uart; +pub mod ws2812; diff --git a/embassy-rp/src/pio_programs/onewire.rs b/embassy-rp/src/pio_programs/onewire.rs new file mode 100644 index 000000000..f3bc5fcd7 --- /dev/null +++ b/embassy-rp/src/pio_programs/onewire.rs @@ -0,0 +1,109 @@ +//! OneWire pio driver + +use crate::pio::{self, Common, Config, Instance, LoadedProgram, PioPin, ShiftConfig, ShiftDirection, StateMachine}; + +/// This struct represents an onewire driver program +pub struct PioOneWireProgram<'a, PIO: Instance> { + prg: LoadedProgram<'a, PIO>, +} + +impl<'a, PIO: Instance> PioOneWireProgram<'a, PIO> { + /// Load the program into the given pio + pub fn new(common: &mut Common<'a, PIO>) -> Self { + let prg = pio_proc::pio_asm!( + r#" + .wrap_target + again: + pull block + mov x, osr + jmp !x, read + write: + set pindirs, 1 + set pins, 0 + loop1: + jmp x--,loop1 + set pindirs, 0 [31] + wait 1 pin 0 [31] + pull block + mov x, osr + bytes1: + pull block + set y, 7 + set pindirs, 1 + bit1: + set pins, 0 [1] + out pins,1 [31] + set pins, 1 [20] + jmp y--,bit1 + jmp x--,bytes1 + set pindirs, 0 [31] + jmp again + read: + pull block + mov x, osr + bytes2: + set y, 7 + bit2: + set pindirs, 1 + set pins, 0 [1] + set pindirs, 0 [5] + in pins,1 [10] + jmp y--,bit2 + jmp x--,bytes2 + .wrap + "#, + ); + let prg = common.load_program(&prg.program); + + Self { prg } + } +} + +/// Pio backed OneWire driver +pub struct PioOneWire<'d, PIO: pio::Instance, const SM: usize> { + sm: StateMachine<'d, PIO, SM>, +} + +impl<'d, PIO: pio::Instance, const SM: usize> PioOneWire<'d, PIO, SM> { + /// Create a new instance the driver + pub fn new( + common: &mut Common<'d, PIO>, + mut sm: StateMachine<'d, PIO, SM>, + pin: impl PioPin, + program: &PioOneWireProgram<'d, PIO>, + ) -> Self { + let pin = common.make_pio_pin(pin); + let mut cfg = Config::default(); + cfg.use_program(&program.prg, &[]); + cfg.set_out_pins(&[&pin]); + cfg.set_in_pins(&[&pin]); + cfg.set_set_pins(&[&pin]); + cfg.shift_in = ShiftConfig { + auto_fill: true, + direction: ShiftDirection::Right, + threshold: 8, + }; + cfg.clock_divider = 255_u8.into(); + sm.set_config(&cfg); + sm.set_enable(true); + Self { sm } + } + + /// Write bytes over the wire + pub async fn write_bytes(&mut self, bytes: &[u8]) { + self.sm.tx().wait_push(250).await; + self.sm.tx().wait_push(bytes.len() as u32 - 1).await; + for b in bytes { + self.sm.tx().wait_push(*b as u32).await; + } + } + + /// Read bytes from the wire + pub async fn read_bytes(&mut self, bytes: &mut [u8]) { + self.sm.tx().wait_push(0).await; + self.sm.tx().wait_push(bytes.len() as u32 - 1).await; + for b in bytes.iter_mut() { + *b = (self.sm.rx().wait_pull().await >> 24) as u8; + } + } +} diff --git a/embassy-rp/src/pio_programs/pwm.rs b/embassy-rp/src/pio_programs/pwm.rs new file mode 100644 index 000000000..5dfd70cc9 --- /dev/null +++ b/embassy-rp/src/pio_programs/pwm.rs @@ -0,0 +1,114 @@ +//! PIO backed PWM driver + +use core::time::Duration; + +use crate::{ + clocks, + gpio::Level, + pio::{Common, Config, Direction, Instance, LoadedProgram, PioPin, StateMachine}, +}; +use pio::InstructionOperands; + +fn to_pio_cycles(duration: Duration) -> u32 { + (clocks::clk_sys_freq() / 1_000_000) / 3 * duration.as_micros() as u32 // parentheses are required to prevent overflow +} + +/// This struct represents a PWM program loaded into pio instruction memory. +pub struct PioPwmProgram<'a, PIO: Instance> { + prg: LoadedProgram<'a, PIO>, +} + +impl<'a, PIO: Instance> PioPwmProgram<'a, PIO> { + /// Load the program into the given pio + pub fn new(common: &mut Common<'a, PIO>) -> Self { + let prg = pio_proc::pio_asm!( + ".side_set 1 opt" + "pull noblock side 0" + "mov x, osr" + "mov y, isr" + "countloop:" + "jmp x!=y noset" + "jmp skip side 1" + "noset:" + "nop" + "skip:" + "jmp y-- countloop" + ); + + let prg = common.load_program(&prg.program); + + Self { prg } + } +} + +/// Pio backed PWM output +pub struct PioPwm<'d, T: Instance, const SM: usize> { + sm: StateMachine<'d, T, SM>, +} + +impl<'d, T: Instance, const SM: usize> PioPwm<'d, T, SM> { + /// Configure a state machine as a PWM output + pub fn new( + pio: &mut Common<'d, T>, + mut sm: StateMachine<'d, T, SM>, + pin: impl PioPin, + program: &PioPwmProgram<'d, T>, + ) -> Self { + let pin = pio.make_pio_pin(pin); + sm.set_pins(Level::High, &[&pin]); + sm.set_pin_dirs(Direction::Out, &[&pin]); + + let mut cfg = Config::default(); + cfg.use_program(&program.prg, &[&pin]); + + sm.set_config(&cfg); + + Self { sm } + } + + /// Enable PWM output + pub fn start(&mut self) { + self.sm.set_enable(true); + } + + /// Disable PWM output + pub fn stop(&mut self) { + self.sm.set_enable(false); + } + + /// Set pwm period + pub fn set_period(&mut self, duration: Duration) { + let is_enabled = self.sm.is_enabled(); + while !self.sm.tx().empty() {} // Make sure that the queue is empty + self.sm.set_enable(false); + self.sm.tx().push(to_pio_cycles(duration)); + unsafe { + self.sm.exec_instr( + InstructionOperands::PULL { + if_empty: false, + block: false, + } + .encode(), + ); + self.sm.exec_instr( + InstructionOperands::OUT { + destination: ::pio::OutDestination::ISR, + bit_count: 32, + } + .encode(), + ); + }; + if is_enabled { + self.sm.set_enable(true) // Enable if previously enabled + } + } + + fn set_level(&mut self, level: u32) { + self.sm.tx().push(level); + } + + /// Set the pulse width high time + pub fn write(&mut self, duration: Duration) { + self.set_level(to_pio_cycles(duration)); + } +} diff --git a/embassy-rp/src/pio_programs/rotary_encoder.rs b/embassy-rp/src/pio_programs/rotary_encoder.rs new file mode 100644 index 000000000..323f839bc --- /dev/null +++ b/embassy-rp/src/pio_programs/rotary_encoder.rs @@ -0,0 +1,72 @@ +//! PIO backed quadrature encoder + +use crate::gpio::Pull; +use crate::pio::{self, Common, Config, FifoJoin, Instance, LoadedProgram, PioPin, ShiftDirection, StateMachine}; +use fixed::traits::ToFixed; + +/// This struct represents an Encoder program loaded into pio instruction memory. +pub struct PioEncoderProgram<'a, PIO: Instance> { + prg: LoadedProgram<'a, PIO>, +} + +impl<'a, PIO: Instance> PioEncoderProgram<'a, PIO> { + /// Load the program into the given pio + pub fn new(common: &mut Common<'a, PIO>) -> Self { + let prg = pio_proc::pio_asm!("wait 1 pin 1", "wait 0 pin 1", "in pins, 2", "push",); + + let prg = common.load_program(&prg.program); + + Self { prg } + } +} + +/// Pio Backed quadrature encoder reader +pub struct PioEncoder<'d, T: Instance, const SM: usize> { + sm: StateMachine<'d, T, SM>, +} + +impl<'d, T: Instance, const SM: usize> PioEncoder<'d, T, SM> { + /// Configure a state machine with the loaded [PioEncoderProgram] + pub fn new( + pio: &mut Common<'d, T>, + mut sm: StateMachine<'d, T, SM>, + pin_a: impl PioPin, + pin_b: impl PioPin, + program: &PioEncoderProgram<'d, T>, + ) -> Self { + let mut pin_a = pio.make_pio_pin(pin_a); + let mut pin_b = pio.make_pio_pin(pin_b); + pin_a.set_pull(Pull::Up); + pin_b.set_pull(Pull::Up); + sm.set_pin_dirs(pio::Direction::In, &[&pin_a, &pin_b]); + + let mut cfg = Config::default(); + cfg.set_in_pins(&[&pin_a, &pin_b]); + cfg.fifo_join = FifoJoin::RxOnly; + cfg.shift_in.direction = ShiftDirection::Left; + cfg.clock_divider = 10_000.to_fixed(); + cfg.use_program(&program.prg, &[]); + sm.set_config(&cfg); + sm.set_enable(true); + Self { sm } + } + + /// Read a single count from the encoder + pub async fn read(&mut self) -> Direction { + loop { + match self.sm.rx().wait_pull().await { + 0 => return Direction::CounterClockwise, + 1 => return Direction::Clockwise, + _ => {} + } + } + } +} + +/// Encoder Count Direction +pub enum Direction { + /// Encoder turned clockwise + Clockwise, + /// Encoder turned counter clockwise + CounterClockwise, +} diff --git a/embassy-rp/src/pio_programs/stepper.rs b/embassy-rp/src/pio_programs/stepper.rs new file mode 100644 index 000000000..0ecc4eff0 --- /dev/null +++ b/embassy-rp/src/pio_programs/stepper.rs @@ -0,0 +1,146 @@ +//! Pio Stepper Driver for 5-wire steppers + +use core::mem::{self, MaybeUninit}; + +use crate::pio::{Common, Config, Direction, Instance, Irq, LoadedProgram, PioPin, StateMachine}; +use fixed::traits::ToFixed; +use fixed::types::extra::U8; +use fixed::FixedU32; + +/// This struct represents a Stepper driver program loaded into pio instruction memory. +pub struct PioStepperProgram<'a, PIO: Instance> { + prg: LoadedProgram<'a, PIO>, +} + +impl<'a, PIO: Instance> PioStepperProgram<'a, PIO> { + /// Load the program into the given pio + pub fn new(common: &mut Common<'a, PIO>) -> Self { + let prg = pio_proc::pio_asm!( + "pull block", + "mov x, osr", + "pull block", + "mov y, osr", + "jmp !x end", + "loop:", + "jmp !osre step", + "mov osr, y", + "step:", + "out pins, 4 [31]" + "jmp x-- loop", + "end:", + "irq 0 rel" + ); + + let prg = common.load_program(&prg.program); + + Self { prg } + } +} + +/// Pio backed Stepper driver +pub struct PioStepper<'d, T: Instance, const SM: usize> { + irq: Irq<'d, T, SM>, + sm: StateMachine<'d, T, SM>, +} + +impl<'d, T: Instance, const SM: usize> PioStepper<'d, T, SM> { + /// Configure a state machine to drive a stepper + pub fn new( + pio: &mut Common<'d, T>, + mut sm: StateMachine<'d, T, SM>, + irq: Irq<'d, T, SM>, + pin0: impl PioPin, + pin1: impl PioPin, + pin2: impl PioPin, + pin3: impl PioPin, + program: &PioStepperProgram<'d, T>, + ) -> Self { + let pin0 = pio.make_pio_pin(pin0); + let pin1 = pio.make_pio_pin(pin1); + let pin2 = pio.make_pio_pin(pin2); + let pin3 = pio.make_pio_pin(pin3); + sm.set_pin_dirs(Direction::Out, &[&pin0, &pin1, &pin2, &pin3]); + let mut cfg = Config::default(); + cfg.set_out_pins(&[&pin0, &pin1, &pin2, &pin3]); + cfg.clock_divider = (125_000_000 / (100 * 136)).to_fixed(); + cfg.use_program(&program.prg, &[]); + sm.set_config(&cfg); + sm.set_enable(true); + Self { irq, sm } + } + + /// Set pulse frequency + pub fn set_frequency(&mut self, freq: u32) { + let clock_divider: FixedU32 = (125_000_000 / (freq * 136)).to_fixed(); + assert!(clock_divider <= 65536, "clkdiv must be <= 65536"); + assert!(clock_divider >= 1, "clkdiv must be >= 1"); + self.sm.set_clock_divider(clock_divider); + self.sm.clkdiv_restart(); + } + + /// Full step, one phase + pub async fn step(&mut self, steps: i32) { + if steps > 0 { + self.run(steps, 0b1000_0100_0010_0001_1000_0100_0010_0001).await + } else { + self.run(-steps, 0b0001_0010_0100_1000_0001_0010_0100_1000).await + } + } + + /// Full step, two phase + pub async fn step2(&mut self, steps: i32) { + if steps > 0 { + self.run(steps, 0b1001_1100_0110_0011_1001_1100_0110_0011).await + } else { + self.run(-steps, 0b0011_0110_1100_1001_0011_0110_1100_1001).await + } + } + + /// Half step + pub async fn step_half(&mut self, steps: i32) { + if steps > 0 { + self.run(steps, 0b1001_1000_1100_0100_0110_0010_0011_0001).await + } else { + self.run(-steps, 0b0001_0011_0010_0110_0100_1100_1000_1001).await + } + } + + async fn run(&mut self, steps: i32, pattern: u32) { + self.sm.tx().wait_push(steps as u32).await; + self.sm.tx().wait_push(pattern).await; + let drop = OnDrop::new(|| { + self.sm.clear_fifos(); + unsafe { + self.sm.exec_instr( + pio::InstructionOperands::JMP { + address: 0, + condition: pio::JmpCondition::Always, + } + .encode(), + ); + } + }); + self.irq.wait().await; + drop.defuse(); + } +} + +struct OnDrop { + f: MaybeUninit, +} + +impl OnDrop { + pub fn new(f: F) -> Self { + Self { f: MaybeUninit::new(f) } + } + + pub fn defuse(self) { + mem::forget(self) + } +} + +impl Drop for OnDrop { + fn drop(&mut self) { + unsafe { self.f.as_ptr().read()() } + } +} diff --git a/embassy-rp/src/pio_programs/uart.rs b/embassy-rp/src/pio_programs/uart.rs new file mode 100644 index 000000000..f4b3b204e --- /dev/null +++ b/embassy-rp/src/pio_programs/uart.rs @@ -0,0 +1,186 @@ +//! Pio backed uart drivers + +use crate::{ + clocks::clk_sys_freq, + gpio::Level, + pio::{ + Common, Config, Direction as PioDirection, FifoJoin, Instance, LoadedProgram, PioPin, ShiftDirection, + StateMachine, + }, +}; +use core::convert::Infallible; +use embedded_io_async::{ErrorType, Read, Write}; +use fixed::traits::ToFixed; + +/// This struct represents a uart tx program loaded into pio instruction memory. +pub struct PioUartTxProgram<'a, PIO: Instance> { + prg: LoadedProgram<'a, PIO>, +} + +impl<'a, PIO: Instance> PioUartTxProgram<'a, PIO> { + /// Load the uart tx program into the given pio + pub fn new(common: &mut Common<'a, PIO>) -> Self { + let prg = pio_proc::pio_asm!( + r#" + .side_set 1 opt + + ; An 8n1 UART transmit program. + ; OUT pin 0 and side-set pin 0 are both mapped to UART TX pin. + + pull side 1 [7] ; Assert stop bit, or stall with line in idle state + set x, 7 side 0 [7] ; Preload bit counter, assert start bit for 8 clocks + bitloop: ; This loop will run 8 times (8n1 UART) + out pins, 1 ; Shift 1 bit from OSR to the first OUT pin + jmp x-- bitloop [6] ; Each loop iteration is 8 cycles. + "# + ); + + let prg = common.load_program(&prg.program); + + Self { prg } + } +} + +/// PIO backed Uart transmitter +pub struct PioUartTx<'a, PIO: Instance, const SM: usize> { + sm_tx: StateMachine<'a, PIO, SM>, +} + +impl<'a, PIO: Instance, const SM: usize> PioUartTx<'a, PIO, SM> { + /// Configure a pio state machine to use the loaded tx program. + pub fn new( + baud: u32, + common: &mut Common<'a, PIO>, + mut sm_tx: StateMachine<'a, PIO, SM>, + tx_pin: impl PioPin, + program: &PioUartTxProgram<'a, PIO>, + ) -> Self { + let tx_pin = common.make_pio_pin(tx_pin); + sm_tx.set_pins(Level::High, &[&tx_pin]); + sm_tx.set_pin_dirs(PioDirection::Out, &[&tx_pin]); + + let mut cfg = Config::default(); + + cfg.set_out_pins(&[&tx_pin]); + cfg.use_program(&program.prg, &[&tx_pin]); + cfg.shift_out.auto_fill = false; + cfg.shift_out.direction = ShiftDirection::Right; + cfg.fifo_join = FifoJoin::TxOnly; + cfg.clock_divider = (clk_sys_freq() / (8 * baud)).to_fixed(); + sm_tx.set_config(&cfg); + sm_tx.set_enable(true); + + Self { sm_tx } + } + + /// Write a single u8 + pub async fn write_u8(&mut self, data: u8) { + self.sm_tx.tx().wait_push(data as u32).await; + } +} + +impl ErrorType for PioUartTx<'_, PIO, SM> { + type Error = Infallible; +} + +impl Write for PioUartTx<'_, PIO, SM> { + async fn write(&mut self, buf: &[u8]) -> Result { + for byte in buf { + self.write_u8(*byte).await; + } + Ok(buf.len()) + } +} + +/// This struct represents a Uart Rx program loaded into pio instruction memory. +pub struct PioUartRxProgram<'a, PIO: Instance> { + prg: LoadedProgram<'a, PIO>, +} + +impl<'a, PIO: Instance> PioUartRxProgram<'a, PIO> { + /// Load the uart rx program into the given pio + pub fn new(common: &mut Common<'a, PIO>) -> Self { + let prg = pio_proc::pio_asm!( + r#" + ; Slightly more fleshed-out 8n1 UART receiver which handles framing errors and + ; break conditions more gracefully. + ; IN pin 0 and JMP pin are both mapped to the GPIO used as UART RX. + + start: + wait 0 pin 0 ; Stall until start bit is asserted + set x, 7 [10] ; Preload bit counter, then delay until halfway through + rx_bitloop: ; the first data bit (12 cycles incl wait, set). + in pins, 1 ; Shift data bit into ISR + jmp x-- rx_bitloop [6] ; Loop 8 times, each loop iteration is 8 cycles + jmp pin good_rx_stop ; Check stop bit (should be high) + + irq 4 rel ; Either a framing error or a break. Set a sticky flag, + wait 1 pin 0 ; and wait for line to return to idle state. + jmp start ; Don't push data if we didn't see good framing. + + good_rx_stop: ; No delay before returning to start; a little slack is + in null 24 + push ; important in case the TX clock is slightly too fast. + "# + ); + + let prg = common.load_program(&prg.program); + + Self { prg } + } +} + +/// PIO backed Uart reciever +pub struct PioUartRx<'a, PIO: Instance, const SM: usize> { + sm_rx: StateMachine<'a, PIO, SM>, +} + +impl<'a, PIO: Instance, const SM: usize> PioUartRx<'a, PIO, SM> { + /// Configure a pio state machine to use the loaded rx program. + pub fn new( + baud: u32, + common: &mut Common<'a, PIO>, + mut sm_rx: StateMachine<'a, PIO, SM>, + rx_pin: impl PioPin, + program: &PioUartRxProgram<'a, PIO>, + ) -> Self { + let mut cfg = Config::default(); + cfg.use_program(&program.prg, &[]); + + let rx_pin = common.make_pio_pin(rx_pin); + sm_rx.set_pins(Level::High, &[&rx_pin]); + cfg.set_in_pins(&[&rx_pin]); + cfg.set_jmp_pin(&rx_pin); + sm_rx.set_pin_dirs(PioDirection::In, &[&rx_pin]); + + cfg.clock_divider = (clk_sys_freq() / (8 * baud)).to_fixed(); + cfg.shift_in.auto_fill = false; + cfg.shift_in.direction = ShiftDirection::Right; + cfg.shift_in.threshold = 32; + cfg.fifo_join = FifoJoin::RxOnly; + sm_rx.set_config(&cfg); + sm_rx.set_enable(true); + + Self { sm_rx } + } + + /// Wait for a single u8 + pub async fn read_u8(&mut self) -> u8 { + self.sm_rx.rx().wait_pull().await as u8 + } +} + +impl ErrorType for PioUartRx<'_, PIO, SM> { + type Error = Infallible; +} + +impl Read for PioUartRx<'_, PIO, SM> { + async fn read(&mut self, buf: &mut [u8]) -> Result { + let mut i = 0; + while i < buf.len() { + buf[i] = self.read_u8().await; + i += 1; + } + Ok(i) + } +} diff --git a/embassy-rp/src/pio_programs/ws2812.rs b/embassy-rp/src/pio_programs/ws2812.rs new file mode 100644 index 000000000..3fc7e1017 --- /dev/null +++ b/embassy-rp/src/pio_programs/ws2812.rs @@ -0,0 +1,118 @@ +//! [ws2812](https://www.sparkfun.com/datasheets/LCD/HD44780.pdf) + +use crate::{ + clocks::clk_sys_freq, + dma::{AnyChannel, Channel}, + into_ref, + pio::{Common, Config, FifoJoin, Instance, LoadedProgram, PioPin, ShiftConfig, ShiftDirection, StateMachine}, + Peripheral, PeripheralRef, +}; +use embassy_time::Timer; +use fixed::types::U24F8; +use smart_leds::RGB8; + +const T1: u8 = 2; // start bit +const T2: u8 = 5; // data bit +const T3: u8 = 3; // stop bit +const CYCLES_PER_BIT: u32 = (T1 + T2 + T3) as u32; + +/// This struct represents a ws2812 program loaded into pio instruction memory. +pub struct PioWs2812Program<'a, PIO: Instance> { + prg: LoadedProgram<'a, PIO>, +} + +impl<'a, PIO: Instance> PioWs2812Program<'a, PIO> { + /// Load the ws2812 program into the given pio + pub fn new(common: &mut Common<'a, PIO>) -> Self { + let side_set = pio::SideSet::new(false, 1, false); + let mut a: pio::Assembler<32> = pio::Assembler::new_with_side_set(side_set); + + let mut wrap_target = a.label(); + let mut wrap_source = a.label(); + let mut do_zero = a.label(); + a.set_with_side_set(pio::SetDestination::PINDIRS, 1, 0); + a.bind(&mut wrap_target); + // Do stop bit + a.out_with_delay_and_side_set(pio::OutDestination::X, 1, T3 - 1, 0); + // Do start bit + a.jmp_with_delay_and_side_set(pio::JmpCondition::XIsZero, &mut do_zero, T1 - 1, 1); + // Do data bit = 1 + a.jmp_with_delay_and_side_set(pio::JmpCondition::Always, &mut wrap_target, T2 - 1, 1); + a.bind(&mut do_zero); + // Do data bit = 0 + a.nop_with_delay_and_side_set(T2 - 1, 0); + a.bind(&mut wrap_source); + + let prg = a.assemble_with_wrap(wrap_source, wrap_target); + let prg = common.load_program(&prg); + + Self { prg } + } +} + +/// Pio backed ws2812 driver +/// Const N is the number of ws2812 leds attached to this pin +pub struct PioWs2812<'d, P: Instance, const S: usize, const N: usize> { + dma: PeripheralRef<'d, AnyChannel>, + sm: StateMachine<'d, P, S>, +} + +impl<'d, P: Instance, const S: usize, const N: usize> PioWs2812<'d, P, S, N> { + /// Configure a pio state machine to use the loaded ws2812 program. + pub fn new( + pio: &mut Common<'d, P>, + mut sm: StateMachine<'d, P, S>, + dma: impl Peripheral

+ 'd, + pin: impl PioPin, + program: &PioWs2812Program<'d, P>, + ) -> Self { + into_ref!(dma); + + // Setup sm0 + let mut cfg = Config::default(); + + // Pin config + let out_pin = pio.make_pio_pin(pin); + cfg.set_out_pins(&[&out_pin]); + cfg.set_set_pins(&[&out_pin]); + + cfg.use_program(&program.prg, &[&out_pin]); + + // Clock config, measured in kHz to avoid overflows + let clock_freq = U24F8::from_num(clk_sys_freq() / 1000); + let ws2812_freq = U24F8::from_num(800); + let bit_freq = ws2812_freq * CYCLES_PER_BIT; + cfg.clock_divider = clock_freq / bit_freq; + + // FIFO config + cfg.fifo_join = FifoJoin::TxOnly; + cfg.shift_out = ShiftConfig { + auto_fill: true, + threshold: 24, + direction: ShiftDirection::Left, + }; + + sm.set_config(&cfg); + sm.set_enable(true); + + Self { + dma: dma.map_into(), + sm, + } + } + + /// Write a buffer of [smart_leds::RGB8] to the ws2812 string + pub async fn write(&mut self, colors: &[RGB8; N]) { + // Precompute the word bytes from the colors + let mut words = [0u32; N]; + for i in 0..N { + let word = (u32::from(colors[i].g) << 24) | (u32::from(colors[i].r) << 16) | (u32::from(colors[i].b) << 8); + words[i] = word; + } + + // DMA transfer + self.sm.tx().dma_push(self.dma.reborrow(), &words).await; + + Timer::after_micros(55).await; + } +} diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index 04b4c6317..264b40750 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml @@ -42,7 +42,7 @@ embedded-graphics = "0.7.1" st7789 = "0.6.1" display-interface = "0.4.1" byte-slice-cast = { version = "1.2.0", default-features = false } -smart-leds = "0.3.0" +smart-leds = "0.4.0" heapless = "0.8" usbd-hid = "0.8.1" diff --git a/examples/rp/src/bin/pio_hd44780.rs b/examples/rp/src/bin/pio_hd44780.rs index 6c02630e0..164e6f8d3 100644 --- a/examples/rp/src/bin/pio_hd44780.rs +++ b/examples/rp/src/bin/pio_hd44780.rs @@ -7,13 +7,11 @@ use core::fmt::Write; use embassy_executor::Spawner; -use embassy_rp::dma::{AnyChannel, Channel}; +use embassy_rp::bind_interrupts; use embassy_rp::peripherals::PIO0; -use embassy_rp::pio::{ - Config, Direction, FifoJoin, InterruptHandler, Pio, PioPin, ShiftConfig, ShiftDirection, StateMachine, -}; +use embassy_rp::pio::{InterruptHandler, Pio}; +use embassy_rp::pio_programs::hd44780::{PioHD44780, PioHD44780CommandSequenceProgram, PioHD44780CommandWordProgram}; use embassy_rp::pwm::{self, Pwm}; -use embassy_rp::{bind_interrupts, into_ref, Peripheral, PeripheralRef}; use embassy_time::{Instant, Timer}; use {defmt_rtt as _, panic_probe as _}; @@ -43,8 +41,27 @@ async fn main(_spawner: Spawner) { c }); - let mut hd = HD44780::new( - p.PIO0, Irqs, p.DMA_CH3, p.PIN_0, p.PIN_1, p.PIN_2, p.PIN_3, p.PIN_4, p.PIN_5, p.PIN_6, + let Pio { + mut common, sm0, irq0, .. + } = Pio::new(p.PIO0, Irqs); + + let word_prg = PioHD44780CommandWordProgram::new(&mut common); + let seq_prg = PioHD44780CommandSequenceProgram::new(&mut common); + + let mut hd = PioHD44780::new( + &mut common, + sm0, + irq0, + p.DMA_CH3, + p.PIN_0, + p.PIN_1, + p.PIN_2, + p.PIN_3, + p.PIN_4, + p.PIN_5, + p.PIN_6, + &word_prg, + &seq_prg, ) .await; @@ -68,173 +85,3 @@ async fn main(_spawner: Spawner) { Timer::after_secs(1).await; } } - -pub struct HD44780<'l> { - dma: PeripheralRef<'l, AnyChannel>, - sm: StateMachine<'l, PIO0, 0>, - - buf: [u8; 40], -} - -impl<'l> HD44780<'l> { - pub async fn new( - pio: impl Peripheral

+ 'l, - irq: Irqs, - dma: impl Peripheral

+ 'l, - rs: impl PioPin, - rw: impl PioPin, - e: impl PioPin, - db4: impl PioPin, - db5: impl PioPin, - db6: impl PioPin, - db7: impl PioPin, - ) -> HD44780<'l> { - into_ref!(dma); - - let Pio { - mut common, - mut irq0, - mut sm0, - .. - } = Pio::new(pio, irq); - - // takes command words ( <0:4>) - let prg = pio_proc::pio_asm!( - r#" - .side_set 1 opt - .origin 20 - - loop: - out x, 24 - delay: - jmp x--, delay - out pins, 4 side 1 - out null, 4 side 0 - jmp !osre, loop - irq 0 - "#, - ); - - let rs = common.make_pio_pin(rs); - let rw = common.make_pio_pin(rw); - let e = common.make_pio_pin(e); - let db4 = common.make_pio_pin(db4); - let db5 = common.make_pio_pin(db5); - let db6 = common.make_pio_pin(db6); - let db7 = common.make_pio_pin(db7); - - sm0.set_pin_dirs(Direction::Out, &[&rs, &rw, &e, &db4, &db5, &db6, &db7]); - - let mut cfg = Config::default(); - cfg.use_program(&common.load_program(&prg.program), &[&e]); - cfg.clock_divider = 125u8.into(); - cfg.set_out_pins(&[&db4, &db5, &db6, &db7]); - cfg.shift_out = ShiftConfig { - auto_fill: true, - direction: ShiftDirection::Left, - threshold: 32, - }; - cfg.fifo_join = FifoJoin::TxOnly; - sm0.set_config(&cfg); - - sm0.set_enable(true); - // init to 8 bit thrice - sm0.tx().push((50000 << 8) | 0x30); - sm0.tx().push((5000 << 8) | 0x30); - sm0.tx().push((200 << 8) | 0x30); - // init 4 bit - sm0.tx().push((200 << 8) | 0x20); - // set font and lines - sm0.tx().push((50 << 8) | 0x20); - sm0.tx().push(0b1100_0000); - - irq0.wait().await; - sm0.set_enable(false); - - // takes command sequences ( , data...) - // many side sets are only there to free up a delay bit! - let prg = pio_proc::pio_asm!( - r#" - .origin 27 - .side_set 1 - - .wrap_target - pull side 0 - out x 1 side 0 ; !rs - out y 7 side 0 ; #data - 1 - - ; rs/rw to e: >= 60ns - ; e high time: >= 500ns - ; e low time: >= 500ns - ; read data valid after e falling: ~5ns - ; write data hold after e falling: ~10ns - - loop: - pull side 0 - jmp !x data side 0 - command: - set pins 0b00 side 0 - jmp shift side 0 - data: - set pins 0b01 side 0 - shift: - out pins 4 side 1 [9] - nop side 0 [9] - out pins 4 side 1 [9] - mov osr null side 0 [7] - out pindirs 4 side 0 - set pins 0b10 side 0 - busy: - nop side 1 [9] - jmp pin more side 0 [9] - mov osr ~osr side 1 [9] - nop side 0 [4] - out pindirs 4 side 0 - jmp y-- loop side 0 - .wrap - more: - nop side 1 [9] - jmp busy side 0 [9] - "# - ); - - let mut cfg = Config::default(); - cfg.use_program(&common.load_program(&prg.program), &[&e]); - cfg.clock_divider = 8u8.into(); // ~64ns/insn - cfg.set_jmp_pin(&db7); - cfg.set_set_pins(&[&rs, &rw]); - cfg.set_out_pins(&[&db4, &db5, &db6, &db7]); - cfg.shift_out.direction = ShiftDirection::Left; - cfg.fifo_join = FifoJoin::TxOnly; - sm0.set_config(&cfg); - - sm0.set_enable(true); - - // display on and cursor on and blinking, reset display - sm0.tx().dma_push(dma.reborrow(), &[0x81u8, 0x0f, 1]).await; - - Self { - dma: dma.map_into(), - sm: sm0, - buf: [0x20; 40], - } - } - - pub async fn add_line(&mut self, s: &[u8]) { - // move cursor to 0:0, prepare 16 characters - self.buf[..3].copy_from_slice(&[0x80, 0x80, 15]); - // move line 2 up - self.buf.copy_within(22..38, 3); - // move cursor to 1:0, prepare 16 characters - self.buf[19..22].copy_from_slice(&[0x80, 0xc0, 15]); - // file line 2 with spaces - self.buf[22..38].fill(0x20); - // copy input line - let len = s.len().min(16); - self.buf[22..22 + len].copy_from_slice(&s[0..len]); - // set cursor to 1:15 - self.buf[38..].copy_from_slice(&[0x80, 0xcf]); - - self.sm.tx().dma_push(self.dma.reborrow(), &self.buf).await; - } -} diff --git a/examples/rp/src/bin/pio_i2s.rs b/examples/rp/src/bin/pio_i2s.rs index cf60e5b30..447100ddf 100644 --- a/examples/rp/src/bin/pio_i2s.rs +++ b/examples/rp/src/bin/pio_i2s.rs @@ -13,10 +13,10 @@ use core::mem; use embassy_executor::Spawner; +use embassy_rp::bind_interrupts; use embassy_rp::peripherals::PIO0; -use embassy_rp::pio::{Config, FifoJoin, InterruptHandler, Pio, ShiftConfig, ShiftDirection}; -use embassy_rp::{bind_interrupts, Peripheral}; -use fixed::traits::ToFixed; +use embassy_rp::pio::{InterruptHandler, Pio}; +use embassy_rp::pio_programs::i2s::{PioI2sOut, PioI2sOutProgram}; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; @@ -25,61 +25,32 @@ bind_interrupts!(struct Irqs { }); const SAMPLE_RATE: u32 = 48_000; +const BIT_DEPTH: u32 = 16; +const CHANNELS: u32 = 2; #[embassy_executor::main] async fn main(_spawner: Spawner) { let mut p = embassy_rp::init(Default::default()); // Setup pio state machine for i2s output - let mut pio = Pio::new(p.PIO0, Irqs); - - #[rustfmt::skip] - let pio_program = pio_proc::pio_asm!( - ".side_set 2", - " set x, 14 side 0b01", // side 0bWB - W = Word Clock, B = Bit Clock - "left_data:", - " out pins, 1 side 0b00", - " jmp x-- left_data side 0b01", - " out pins 1 side 0b10", - " set x, 14 side 0b11", - "right_data:", - " out pins 1 side 0b10", - " jmp x-- right_data side 0b11", - " out pins 1 side 0b00", - ); + let Pio { mut common, sm0, .. } = Pio::new(p.PIO0, Irqs); let bit_clock_pin = p.PIN_18; let left_right_clock_pin = p.PIN_19; let data_pin = p.PIN_20; - let data_pin = pio.common.make_pio_pin(data_pin); - let bit_clock_pin = pio.common.make_pio_pin(bit_clock_pin); - let left_right_clock_pin = pio.common.make_pio_pin(left_right_clock_pin); - - let cfg = { - let mut cfg = Config::default(); - cfg.use_program( - &pio.common.load_program(&pio_program.program), - &[&bit_clock_pin, &left_right_clock_pin], - ); - cfg.set_out_pins(&[&data_pin]); - const BIT_DEPTH: u32 = 16; - const CHANNELS: u32 = 2; - let clock_frequency = SAMPLE_RATE * BIT_DEPTH * CHANNELS; - cfg.clock_divider = (125_000_000. / clock_frequency as f64 / 2.).to_fixed(); - cfg.shift_out = ShiftConfig { - threshold: 32, - direction: ShiftDirection::Left, - auto_fill: true, - }; - // join fifos to have twice the time to start the next dma transfer - cfg.fifo_join = FifoJoin::TxOnly; - cfg - }; - pio.sm0.set_config(&cfg); - pio.sm0.set_pin_dirs( - embassy_rp::pio::Direction::Out, - &[&data_pin, &left_right_clock_pin, &bit_clock_pin], + let program = PioI2sOutProgram::new(&mut common); + let mut i2s = PioI2sOut::new( + &mut common, + sm0, + p.DMA_CH0, + data_pin, + bit_clock_pin, + left_right_clock_pin, + SAMPLE_RATE, + BIT_DEPTH, + CHANNELS, + &program, ); // create two audio buffers (back and front) which will take turns being @@ -90,17 +61,13 @@ async fn main(_spawner: Spawner) { let (mut back_buffer, mut front_buffer) = dma_buffer.split_at_mut(BUFFER_SIZE); // start pio state machine - pio.sm0.set_enable(true); - let tx = pio.sm0.tx(); - let mut dma_ref = p.DMA_CH0.into_ref(); - let mut fade_value: i32 = 0; let mut phase: i32 = 0; loop { // trigger transfer of front buffer data to the pio fifo // but don't await the returned future, yet - let dma_future = tx.dma_push(dma_ref.reborrow(), front_buffer); + let dma_future = i2s.write(front_buffer); // fade in audio when bootsel is pressed let fade_target = if p.BOOTSEL.is_pressed() { i32::MAX } else { 0 }; diff --git a/examples/rp/src/bin/pio_onewire.rs b/examples/rp/src/bin/pio_onewire.rs index 5076101ec..991510851 100644 --- a/examples/rp/src/bin/pio_onewire.rs +++ b/examples/rp/src/bin/pio_onewire.rs @@ -6,7 +6,8 @@ use defmt::*; use embassy_executor::Spawner; use embassy_rp::bind_interrupts; use embassy_rp::peripherals::PIO0; -use embassy_rp::pio::{self, Common, Config, InterruptHandler, Pio, PioPin, ShiftConfig, ShiftDirection, StateMachine}; +use embassy_rp::pio::{self, InterruptHandler, Pio}; +use embassy_rp::pio_programs::onewire::{PioOneWire, PioOneWireProgram}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; @@ -18,7 +19,11 @@ bind_interrupts!(struct Irqs { async fn main(_spawner: Spawner) { let p = embassy_rp::init(Default::default()); let mut pio = Pio::new(p.PIO0, Irqs); - let mut sensor = Ds18b20::new(&mut pio.common, pio.sm0, p.PIN_2); + + let prg = PioOneWireProgram::new(&mut pio.common); + let onewire = PioOneWire::new(&mut pio.common, pio.sm0, p.PIN_2, &prg); + + let mut sensor = Ds18b20::new(onewire); loop { sensor.start().await; // Start a new measurement @@ -33,89 +38,12 @@ async fn main(_spawner: Spawner) { /// DS18B20 temperature sensor driver pub struct Ds18b20<'d, PIO: pio::Instance, const SM: usize> { - sm: StateMachine<'d, PIO, SM>, + wire: PioOneWire<'d, PIO, SM>, } impl<'d, PIO: pio::Instance, const SM: usize> Ds18b20<'d, PIO, SM> { - /// Create a new instance the driver - pub fn new(common: &mut Common<'d, PIO>, mut sm: StateMachine<'d, PIO, SM>, pin: impl PioPin) -> Self { - let prg = pio_proc::pio_asm!( - r#" - .wrap_target - again: - pull block - mov x, osr - jmp !x, read - write: - set pindirs, 1 - set pins, 0 - loop1: - jmp x--,loop1 - set pindirs, 0 [31] - wait 1 pin 0 [31] - pull block - mov x, osr - bytes1: - pull block - set y, 7 - set pindirs, 1 - bit1: - set pins, 0 [1] - out pins,1 [31] - set pins, 1 [20] - jmp y--,bit1 - jmp x--,bytes1 - set pindirs, 0 [31] - jmp again - read: - pull block - mov x, osr - bytes2: - set y, 7 - bit2: - set pindirs, 1 - set pins, 0 [1] - set pindirs, 0 [5] - in pins,1 [10] - jmp y--,bit2 - jmp x--,bytes2 - .wrap - "#, - ); - - let pin = common.make_pio_pin(pin); - let mut cfg = Config::default(); - cfg.use_program(&common.load_program(&prg.program), &[]); - cfg.set_out_pins(&[&pin]); - cfg.set_in_pins(&[&pin]); - cfg.set_set_pins(&[&pin]); - cfg.shift_in = ShiftConfig { - auto_fill: true, - direction: ShiftDirection::Right, - threshold: 8, - }; - cfg.clock_divider = 255_u8.into(); - sm.set_config(&cfg); - sm.set_enable(true); - Self { sm } - } - - /// Write bytes over the wire - async fn write_bytes(&mut self, bytes: &[u8]) { - self.sm.tx().wait_push(250).await; - self.sm.tx().wait_push(bytes.len() as u32 - 1).await; - for b in bytes { - self.sm.tx().wait_push(*b as u32).await; - } - } - - /// Read bytes from the wire - async fn read_bytes(&mut self, bytes: &mut [u8]) { - self.sm.tx().wait_push(0).await; - self.sm.tx().wait_push(bytes.len() as u32 - 1).await; - for b in bytes.iter_mut() { - *b = (self.sm.rx().wait_pull().await >> 24) as u8; - } + pub fn new(wire: PioOneWire<'d, PIO, SM>) -> Self { + Self { wire } } /// Calculate CRC8 of the data @@ -139,14 +67,14 @@ impl<'d, PIO: pio::Instance, const SM: usize> Ds18b20<'d, PIO, SM> { /// Start a new measurement. Allow at least 1000ms before getting `temperature`. pub async fn start(&mut self) { - self.write_bytes(&[0xCC, 0x44]).await; + self.wire.write_bytes(&[0xCC, 0x44]).await; } /// Read the temperature. Ensure >1000ms has passed since `start` before calling this. pub async fn temperature(&mut self) -> Result { - self.write_bytes(&[0xCC, 0xBE]).await; + self.wire.write_bytes(&[0xCC, 0xBE]).await; let mut data = [0; 9]; - self.read_bytes(&mut data).await; + self.wire.read_bytes(&mut data).await; match Self::crc8(&data) == 0 { true => Ok(((data[1] as u32) << 8 | data[0] as u32) as f32 / 16.), false => Err(()), diff --git a/examples/rp/src/bin/pio_pwm.rs b/examples/rp/src/bin/pio_pwm.rs index 23d63d435..7eabb2289 100644 --- a/examples/rp/src/bin/pio_pwm.rs +++ b/examples/rp/src/bin/pio_pwm.rs @@ -5,12 +5,11 @@ use core::time::Duration; use embassy_executor::Spawner; -use embassy_rp::gpio::Level; +use embassy_rp::bind_interrupts; use embassy_rp::peripherals::PIO0; -use embassy_rp::pio::{Common, Config, Direction, Instance, InterruptHandler, Pio, PioPin, StateMachine}; -use embassy_rp::{bind_interrupts, clocks}; +use embassy_rp::pio::{InterruptHandler, Pio}; +use embassy_rp::pio_programs::pwm::{PioPwm, PioPwmProgram}; use embassy_time::Timer; -use pio::InstructionOperands; use {defmt_rtt as _, panic_probe as _}; const REFRESH_INTERVAL: u64 = 20000; @@ -19,93 +18,14 @@ bind_interrupts!(struct Irqs { PIO0_IRQ_0 => InterruptHandler; }); -pub fn to_pio_cycles(duration: Duration) -> u32 { - (clocks::clk_sys_freq() / 1_000_000) / 3 * duration.as_micros() as u32 // parentheses are required to prevent overflow -} - -pub struct PwmPio<'d, T: Instance, const SM: usize> { - sm: StateMachine<'d, T, SM>, -} - -impl<'d, T: Instance, const SM: usize> PwmPio<'d, T, SM> { - pub fn new(pio: &mut Common<'d, T>, mut sm: StateMachine<'d, T, SM>, pin: impl PioPin) -> Self { - let prg = pio_proc::pio_asm!( - ".side_set 1 opt" - "pull noblock side 0" - "mov x, osr" - "mov y, isr" - "countloop:" - "jmp x!=y noset" - "jmp skip side 1" - "noset:" - "nop" - "skip:" - "jmp y-- countloop" - ); - - pio.load_program(&prg.program); - let pin = pio.make_pio_pin(pin); - sm.set_pins(Level::High, &[&pin]); - sm.set_pin_dirs(Direction::Out, &[&pin]); - - let mut cfg = Config::default(); - cfg.use_program(&pio.load_program(&prg.program), &[&pin]); - - sm.set_config(&cfg); - - Self { sm } - } - - pub fn start(&mut self) { - self.sm.set_enable(true); - } - - pub fn stop(&mut self) { - self.sm.set_enable(false); - } - - pub fn set_period(&mut self, duration: Duration) { - let is_enabled = self.sm.is_enabled(); - while !self.sm.tx().empty() {} // Make sure that the queue is empty - self.sm.set_enable(false); - self.sm.tx().push(to_pio_cycles(duration)); - unsafe { - self.sm.exec_instr( - InstructionOperands::PULL { - if_empty: false, - block: false, - } - .encode(), - ); - self.sm.exec_instr( - InstructionOperands::OUT { - destination: ::pio::OutDestination::ISR, - bit_count: 32, - } - .encode(), - ); - }; - if is_enabled { - self.sm.set_enable(true) // Enable if previously enabled - } - } - - pub fn set_level(&mut self, level: u32) { - self.sm.tx().push(level); - } - - pub fn write(&mut self, duration: Duration) { - self.set_level(to_pio_cycles(duration)); - } -} - #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_rp::init(Default::default()); let Pio { mut common, sm0, .. } = Pio::new(p.PIO0, Irqs); // Note that PIN_25 is the led pin on the Pico - let mut pwm_pio = PwmPio::new(&mut common, sm0, p.PIN_25); + let prg = PioPwmProgram::new(&mut common); + let mut pwm_pio = PioPwm::new(&mut common, sm0, p.PIN_25, &prg); pwm_pio.set_period(Duration::from_micros(REFRESH_INTERVAL)); pwm_pio.start(); diff --git a/examples/rp/src/bin/pio_rotary_encoder.rs b/examples/rp/src/bin/pio_rotary_encoder.rs index 58bdadbc0..a7ecc8d0e 100644 --- a/examples/rp/src/bin/pio_rotary_encoder.rs +++ b/examples/rp/src/bin/pio_rotary_encoder.rs @@ -5,70 +5,20 @@ use defmt::info; use embassy_executor::Spawner; -use embassy_rp::gpio::Pull; use embassy_rp::peripherals::PIO0; -use embassy_rp::{bind_interrupts, pio}; -use fixed::traits::ToFixed; -use pio::{Common, Config, FifoJoin, Instance, InterruptHandler, Pio, PioPin, ShiftDirection, StateMachine}; +use embassy_rp::{ + bind_interrupts, + pio::{InterruptHandler, Pio}, + pio_programs::rotary_encoder::{Direction, PioEncoder, PioEncoderProgram}, +}; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { PIO0_IRQ_0 => InterruptHandler; }); -pub struct PioEncoder<'d, T: Instance, const SM: usize> { - sm: StateMachine<'d, T, SM>, -} - -impl<'d, T: Instance, const SM: usize> PioEncoder<'d, T, SM> { - pub fn new( - pio: &mut Common<'d, T>, - mut sm: StateMachine<'d, T, SM>, - pin_a: impl PioPin, - pin_b: impl PioPin, - ) -> Self { - let mut pin_a = pio.make_pio_pin(pin_a); - let mut pin_b = pio.make_pio_pin(pin_b); - pin_a.set_pull(Pull::Up); - pin_b.set_pull(Pull::Up); - sm.set_pin_dirs(pio::Direction::In, &[&pin_a, &pin_b]); - - let prg = pio_proc::pio_asm!("wait 1 pin 1", "wait 0 pin 1", "in pins, 2", "push",); - - let mut cfg = Config::default(); - cfg.set_in_pins(&[&pin_a, &pin_b]); - cfg.fifo_join = FifoJoin::RxOnly; - cfg.shift_in.direction = ShiftDirection::Left; - cfg.clock_divider = 10_000.to_fixed(); - cfg.use_program(&pio.load_program(&prg.program), &[]); - sm.set_config(&cfg); - sm.set_enable(true); - Self { sm } - } - - pub async fn read(&mut self) -> Direction { - loop { - match self.sm.rx().wait_pull().await { - 0 => return Direction::CounterClockwise, - 1 => return Direction::Clockwise, - _ => {} - } - } - } -} - -pub enum Direction { - Clockwise, - CounterClockwise, -} - -#[embassy_executor::main] -async fn main(_spawner: Spawner) { - let p = embassy_rp::init(Default::default()); - let Pio { mut common, sm0, .. } = Pio::new(p.PIO0, Irqs); - - let mut encoder = PioEncoder::new(&mut common, sm0, p.PIN_4, p.PIN_5); - +#[embassy_executor::task] +async fn encoder_0(mut encoder: PioEncoder<'static, PIO0, 0>) { let mut count = 0; loop { info!("Count: {}", count); @@ -78,3 +28,30 @@ async fn main(_spawner: Spawner) { }; } } + +#[embassy_executor::task] +async fn encoder_1(mut encoder: PioEncoder<'static, PIO0, 1>) { + let mut count = 0; + loop { + info!("Count: {}", count); + count += match encoder.read().await { + Direction::Clockwise => 1, + Direction::CounterClockwise => -1, + }; + } +} + +#[embassy_executor::main] +async fn main(spawner: Spawner) { + let p = embassy_rp::init(Default::default()); + let Pio { + mut common, sm0, sm1, .. + } = Pio::new(p.PIO0, Irqs); + + let prg = PioEncoderProgram::new(&mut common); + let encoder0 = PioEncoder::new(&mut common, sm0, p.PIN_4, p.PIN_5, &prg); + let encoder1 = PioEncoder::new(&mut common, sm1, p.PIN_6, p.PIN_7, &prg); + + spawner.must_spawn(encoder_0(encoder0)); + spawner.must_spawn(encoder_1(encoder1)); +} diff --git a/examples/rp/src/bin/pio_servo.rs b/examples/rp/src/bin/pio_servo.rs index a79540479..c52ee7492 100644 --- a/examples/rp/src/bin/pio_servo.rs +++ b/examples/rp/src/bin/pio_servo.rs @@ -5,12 +5,11 @@ use core::time::Duration; use embassy_executor::Spawner; -use embassy_rp::gpio::Level; +use embassy_rp::bind_interrupts; use embassy_rp::peripherals::PIO0; -use embassy_rp::pio::{Common, Config, Direction, Instance, InterruptHandler, Pio, PioPin, StateMachine}; -use embassy_rp::{bind_interrupts, clocks}; +use embassy_rp::pio::{Instance, InterruptHandler, Pio}; +use embassy_rp::pio_programs::pwm::{PioPwm, PioPwmProgram}; use embassy_time::Timer; -use pio::InstructionOperands; use {defmt_rtt as _, panic_probe as _}; const DEFAULT_MIN_PULSE_WIDTH: u64 = 1000; // uncalibrated default, the shortest duty cycle sent to a servo @@ -22,88 +21,8 @@ bind_interrupts!(struct Irqs { PIO0_IRQ_0 => InterruptHandler; }); -pub fn to_pio_cycles(duration: Duration) -> u32 { - (clocks::clk_sys_freq() / 1_000_000) / 3 * duration.as_micros() as u32 // parentheses are required to prevent overflow -} - -pub struct PwmPio<'d, T: Instance, const SM: usize> { - sm: StateMachine<'d, T, SM>, -} - -impl<'d, T: Instance, const SM: usize> PwmPio<'d, T, SM> { - pub fn new(pio: &mut Common<'d, T>, mut sm: StateMachine<'d, T, SM>, pin: impl PioPin) -> Self { - let prg = pio_proc::pio_asm!( - ".side_set 1 opt" - "pull noblock side 0" - "mov x, osr" - "mov y, isr" - "countloop:" - "jmp x!=y noset" - "jmp skip side 1" - "noset:" - "nop" - "skip:" - "jmp y-- countloop" - ); - - pio.load_program(&prg.program); - let pin = pio.make_pio_pin(pin); - sm.set_pins(Level::High, &[&pin]); - sm.set_pin_dirs(Direction::Out, &[&pin]); - - let mut cfg = Config::default(); - cfg.use_program(&pio.load_program(&prg.program), &[&pin]); - - sm.set_config(&cfg); - - Self { sm } - } - - pub fn start(&mut self) { - self.sm.set_enable(true); - } - - pub fn stop(&mut self) { - self.sm.set_enable(false); - } - - pub fn set_period(&mut self, duration: Duration) { - let is_enabled = self.sm.is_enabled(); - while !self.sm.tx().empty() {} // Make sure that the queue is empty - self.sm.set_enable(false); - self.sm.tx().push(to_pio_cycles(duration)); - unsafe { - self.sm.exec_instr( - InstructionOperands::PULL { - if_empty: false, - block: false, - } - .encode(), - ); - self.sm.exec_instr( - InstructionOperands::OUT { - destination: ::pio::OutDestination::ISR, - bit_count: 32, - } - .encode(), - ); - }; - if is_enabled { - self.sm.set_enable(true) // Enable if previously enabled - } - } - - pub fn set_level(&mut self, level: u32) { - self.sm.tx().push(level); - } - - pub fn write(&mut self, duration: Duration) { - self.set_level(to_pio_cycles(duration)); - } -} - pub struct ServoBuilder<'d, T: Instance, const SM: usize> { - pwm: PwmPio<'d, T, SM>, + pwm: PioPwm<'d, T, SM>, period: Duration, min_pulse_width: Duration, max_pulse_width: Duration, @@ -111,7 +30,7 @@ pub struct ServoBuilder<'d, T: Instance, const SM: usize> { } impl<'d, T: Instance, const SM: usize> ServoBuilder<'d, T, SM> { - pub fn new(pwm: PwmPio<'d, T, SM>) -> Self { + pub fn new(pwm: PioPwm<'d, T, SM>) -> Self { Self { pwm, period: Duration::from_micros(REFRESH_INTERVAL), @@ -153,7 +72,7 @@ impl<'d, T: Instance, const SM: usize> ServoBuilder<'d, T, SM> { } pub struct Servo<'d, T: Instance, const SM: usize> { - pwm: PwmPio<'d, T, SM>, + pwm: PioPwm<'d, T, SM>, min_pulse_width: Duration, max_pulse_width: Duration, max_degree_rotation: u64, @@ -190,7 +109,8 @@ async fn main(_spawner: Spawner) { let p = embassy_rp::init(Default::default()); let Pio { mut common, sm0, .. } = Pio::new(p.PIO0, Irqs); - let pwm_pio = PwmPio::new(&mut common, sm0, p.PIN_1); + let prg = PioPwmProgram::new(&mut common); + let pwm_pio = PioPwm::new(&mut common, sm0, p.PIN_1, &prg); let mut servo = ServoBuilder::new(pwm_pio) .set_max_degree_rotation(120) // Example of adjusting values for MG996R servo .set_min_pulse_width(Duration::from_micros(350)) // This value was detemined by a rough experiment. diff --git a/examples/rp/src/bin/pio_stepper.rs b/examples/rp/src/bin/pio_stepper.rs index 6ee45a414..3862c248b 100644 --- a/examples/rp/src/bin/pio_stepper.rs +++ b/examples/rp/src/bin/pio_stepper.rs @@ -3,143 +3,20 @@ #![no_std] #![no_main] -use core::mem::{self, MaybeUninit}; use defmt::info; use embassy_executor::Spawner; use embassy_rp::bind_interrupts; use embassy_rp::peripherals::PIO0; -use embassy_rp::pio::{Common, Config, Direction, Instance, InterruptHandler, Irq, Pio, PioPin, StateMachine}; +use embassy_rp::pio::{InterruptHandler, Pio}; +use embassy_rp::pio_programs::stepper::{PioStepper, PioStepperProgram}; use embassy_time::{with_timeout, Duration, Timer}; -use fixed::traits::ToFixed; -use fixed::types::extra::U8; -use fixed::FixedU32; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { PIO0_IRQ_0 => InterruptHandler; }); -pub struct PioStepper<'d, T: Instance, const SM: usize> { - irq: Irq<'d, T, SM>, - sm: StateMachine<'d, T, SM>, -} - -impl<'d, T: Instance, const SM: usize> PioStepper<'d, T, SM> { - pub fn new( - pio: &mut Common<'d, T>, - mut sm: StateMachine<'d, T, SM>, - irq: Irq<'d, T, SM>, - pin0: impl PioPin, - pin1: impl PioPin, - pin2: impl PioPin, - pin3: impl PioPin, - ) -> Self { - let prg = pio_proc::pio_asm!( - "pull block", - "mov x, osr", - "pull block", - "mov y, osr", - "jmp !x end", - "loop:", - "jmp !osre step", - "mov osr, y", - "step:", - "out pins, 4 [31]" - "jmp x-- loop", - "end:", - "irq 0 rel" - ); - let pin0 = pio.make_pio_pin(pin0); - let pin1 = pio.make_pio_pin(pin1); - let pin2 = pio.make_pio_pin(pin2); - let pin3 = pio.make_pio_pin(pin3); - sm.set_pin_dirs(Direction::Out, &[&pin0, &pin1, &pin2, &pin3]); - let mut cfg = Config::default(); - cfg.set_out_pins(&[&pin0, &pin1, &pin2, &pin3]); - cfg.clock_divider = (125_000_000 / (100 * 136)).to_fixed(); - cfg.use_program(&pio.load_program(&prg.program), &[]); - sm.set_config(&cfg); - sm.set_enable(true); - Self { irq, sm } - } - - // Set pulse frequency - pub fn set_frequency(&mut self, freq: u32) { - let clock_divider: FixedU32 = (125_000_000 / (freq * 136)).to_fixed(); - assert!(clock_divider <= 65536, "clkdiv must be <= 65536"); - assert!(clock_divider >= 1, "clkdiv must be >= 1"); - self.sm.set_clock_divider(clock_divider); - self.sm.clkdiv_restart(); - } - - // Full step, one phase - pub async fn step(&mut self, steps: i32) { - if steps > 0 { - self.run(steps, 0b1000_0100_0010_0001_1000_0100_0010_0001).await - } else { - self.run(-steps, 0b0001_0010_0100_1000_0001_0010_0100_1000).await - } - } - - // Full step, two phase - pub async fn step2(&mut self, steps: i32) { - if steps > 0 { - self.run(steps, 0b1001_1100_0110_0011_1001_1100_0110_0011).await - } else { - self.run(-steps, 0b0011_0110_1100_1001_0011_0110_1100_1001).await - } - } - - // Half step - pub async fn step_half(&mut self, steps: i32) { - if steps > 0 { - self.run(steps, 0b1001_1000_1100_0100_0110_0010_0011_0001).await - } else { - self.run(-steps, 0b0001_0011_0010_0110_0100_1100_1000_1001).await - } - } - - async fn run(&mut self, steps: i32, pattern: u32) { - self.sm.tx().wait_push(steps as u32).await; - self.sm.tx().wait_push(pattern).await; - let drop = OnDrop::new(|| { - self.sm.clear_fifos(); - unsafe { - self.sm.exec_instr( - pio::InstructionOperands::JMP { - address: 0, - condition: pio::JmpCondition::Always, - } - .encode(), - ); - } - }); - self.irq.wait().await; - drop.defuse(); - } -} - -struct OnDrop { - f: MaybeUninit, -} - -impl OnDrop { - pub fn new(f: F) -> Self { - Self { f: MaybeUninit::new(f) } - } - - pub fn defuse(self) { - mem::forget(self) - } -} - -impl Drop for OnDrop { - fn drop(&mut self) { - unsafe { self.f.as_ptr().read()() } - } -} - #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_rp::init(Default::default()); @@ -147,14 +24,18 @@ async fn main(_spawner: Spawner) { mut common, irq0, sm0, .. } = Pio::new(p.PIO0, Irqs); - let mut stepper = PioStepper::new(&mut common, sm0, irq0, p.PIN_4, p.PIN_5, p.PIN_6, p.PIN_7); + let prg = PioStepperProgram::new(&mut common); + let mut stepper = PioStepper::new(&mut common, sm0, irq0, p.PIN_4, p.PIN_5, p.PIN_6, p.PIN_7, &prg); stepper.set_frequency(120); loop { info!("CW full steps"); stepper.step(1000).await; info!("CCW full steps, drop after 1 sec"); - if let Err(_) = with_timeout(Duration::from_secs(1), stepper.step(-i32::MAX)).await { + if with_timeout(Duration::from_secs(1), stepper.step(-i32::MAX)) + .await + .is_err() + { info!("Time's up!"); Timer::after(Duration::from_secs(1)).await; } diff --git a/examples/rp/src/bin/pio_uart.rs b/examples/rp/src/bin/pio_uart.rs index 53b696309..b9e01b0ac 100644 --- a/examples/rp/src/bin/pio_uart.rs +++ b/examples/rp/src/bin/pio_uart.rs @@ -15,7 +15,8 @@ use embassy_executor::Spawner; use embassy_futures::join::{join, join3}; use embassy_rp::bind_interrupts; use embassy_rp::peripherals::{PIO0, USB}; -use embassy_rp::pio::InterruptHandler as PioInterruptHandler; +use embassy_rp::pio; +use embassy_rp::pio_programs::uart::{PioUartRx, PioUartRxProgram, PioUartTx, PioUartTxProgram}; use embassy_rp::usb::{Driver, Instance, InterruptHandler}; use embassy_sync::blocking_mutex::raw::NoopRawMutex; use embassy_sync::pipe::Pipe; @@ -25,13 +26,11 @@ use embassy_usb::{Builder, Config}; use embedded_io_async::{Read, Write}; use {defmt_rtt as _, panic_probe as _}; -use crate::uart::PioUart; -use crate::uart_rx::PioUartRx; -use crate::uart_tx::PioUartTx; +//use crate::uart::PioUart; bind_interrupts!(struct Irqs { USBCTRL_IRQ => InterruptHandler; - PIO0_IRQ_0 => PioInterruptHandler; + PIO0_IRQ_0 => pio::InterruptHandler; }); #[embassy_executor::main] @@ -85,8 +84,15 @@ async fn main(_spawner: Spawner) { let usb_fut = usb.run(); // PIO UART setup - let uart = PioUart::new(9600, p.PIO0, p.PIN_4, p.PIN_5); - let (mut uart_tx, mut uart_rx) = uart.split(); + let pio::Pio { + mut common, sm0, sm1, .. + } = pio::Pio::new(p.PIO0, Irqs); + + let tx_program = PioUartTxProgram::new(&mut common); + let mut uart_tx = PioUartTx::new(9600, &mut common, sm0, p.PIN_4, &tx_program); + + let rx_program = PioUartRxProgram::new(&mut common); + let mut uart_rx = PioUartRx::new(9600, &mut common, sm1, p.PIN_5, &rx_program); // Pipe setup let mut usb_pipe: Pipe = Pipe::new(); @@ -163,8 +169,8 @@ async fn usb_write<'d, T: Instance + 'd>( } /// Read from the UART and write it to the USB TX pipe -async fn uart_read( - uart_rx: &mut PioUartRx<'_>, +async fn uart_read( + uart_rx: &mut PioUartRx<'_, PIO, SM>, usb_pipe_writer: &mut embassy_sync::pipe::Writer<'_, NoopRawMutex, 20>, ) -> ! { let mut buf = [0; 64]; @@ -180,8 +186,8 @@ async fn uart_read( } /// Read from the UART TX pipe and write it to the UART -async fn uart_write( - uart_tx: &mut PioUartTx<'_>, +async fn uart_write( + uart_tx: &mut PioUartTx<'_, PIO, SM>, uart_pipe_reader: &mut embassy_sync::pipe::Reader<'_, NoopRawMutex, 20>, ) -> ! { let mut buf = [0; 64]; @@ -192,197 +198,3 @@ async fn uart_write( let _ = uart_tx.write(&data).await; } } - -mod uart { - use embassy_rp::peripherals::PIO0; - use embassy_rp::pio::{Pio, PioPin}; - use embassy_rp::Peripheral; - - use crate::uart_rx::PioUartRx; - use crate::uart_tx::PioUartTx; - use crate::Irqs; - - pub struct PioUart<'a> { - tx: PioUartTx<'a>, - rx: PioUartRx<'a>, - } - - impl<'a> PioUart<'a> { - pub fn new( - baud: u64, - pio: impl Peripheral

+ 'a, - tx_pin: impl PioPin, - rx_pin: impl PioPin, - ) -> PioUart<'a> { - let Pio { - mut common, sm0, sm1, .. - } = Pio::new(pio, Irqs); - - let tx = PioUartTx::new(&mut common, sm0, tx_pin, baud); - let rx = PioUartRx::new(&mut common, sm1, rx_pin, baud); - - PioUart { tx, rx } - } - - pub fn split(self) -> (PioUartTx<'a>, PioUartRx<'a>) { - (self.tx, self.rx) - } - } -} - -mod uart_tx { - use core::convert::Infallible; - - use embassy_rp::gpio::Level; - use embassy_rp::peripherals::PIO0; - use embassy_rp::pio::{Common, Config, Direction, FifoJoin, PioPin, ShiftDirection, StateMachine}; - use embedded_io_async::{ErrorType, Write}; - use fixed::traits::ToFixed; - use fixed_macro::types::U56F8; - - pub struct PioUartTx<'a> { - sm_tx: StateMachine<'a, PIO0, 0>, - } - - impl<'a> PioUartTx<'a> { - pub fn new( - common: &mut Common<'a, PIO0>, - mut sm_tx: StateMachine<'a, PIO0, 0>, - tx_pin: impl PioPin, - baud: u64, - ) -> Self { - let prg = pio_proc::pio_asm!( - r#" - .side_set 1 opt - - ; An 8n1 UART transmit program. - ; OUT pin 0 and side-set pin 0 are both mapped to UART TX pin. - - pull side 1 [7] ; Assert stop bit, or stall with line in idle state - set x, 7 side 0 [7] ; Preload bit counter, assert start bit for 8 clocks - bitloop: ; This loop will run 8 times (8n1 UART) - out pins, 1 ; Shift 1 bit from OSR to the first OUT pin - jmp x-- bitloop [6] ; Each loop iteration is 8 cycles. - "# - ); - let tx_pin = common.make_pio_pin(tx_pin); - sm_tx.set_pins(Level::High, &[&tx_pin]); - sm_tx.set_pin_dirs(Direction::Out, &[&tx_pin]); - - let mut cfg = Config::default(); - - cfg.set_out_pins(&[&tx_pin]); - cfg.use_program(&common.load_program(&prg.program), &[&tx_pin]); - cfg.shift_out.auto_fill = false; - cfg.shift_out.direction = ShiftDirection::Right; - cfg.fifo_join = FifoJoin::TxOnly; - cfg.clock_divider = (U56F8!(125_000_000) / (8 * baud)).to_fixed(); - sm_tx.set_config(&cfg); - sm_tx.set_enable(true); - - Self { sm_tx } - } - - pub async fn write_u8(&mut self, data: u8) { - self.sm_tx.tx().wait_push(data as u32).await; - } - } - - impl ErrorType for PioUartTx<'_> { - type Error = Infallible; - } - - impl Write for PioUartTx<'_> { - async fn write(&mut self, buf: &[u8]) -> Result { - for byte in buf { - self.write_u8(*byte).await; - } - Ok(buf.len()) - } - } -} - -mod uart_rx { - use core::convert::Infallible; - - use embassy_rp::gpio::Level; - use embassy_rp::peripherals::PIO0; - use embassy_rp::pio::{Common, Config, Direction, FifoJoin, PioPin, ShiftDirection, StateMachine}; - use embedded_io_async::{ErrorType, Read}; - use fixed::traits::ToFixed; - use fixed_macro::types::U56F8; - - pub struct PioUartRx<'a> { - sm_rx: StateMachine<'a, PIO0, 1>, - } - - impl<'a> PioUartRx<'a> { - pub fn new( - common: &mut Common<'a, PIO0>, - mut sm_rx: StateMachine<'a, PIO0, 1>, - rx_pin: impl PioPin, - baud: u64, - ) -> Self { - let prg = pio_proc::pio_asm!( - r#" - ; Slightly more fleshed-out 8n1 UART receiver which handles framing errors and - ; break conditions more gracefully. - ; IN pin 0 and JMP pin are both mapped to the GPIO used as UART RX. - - start: - wait 0 pin 0 ; Stall until start bit is asserted - set x, 7 [10] ; Preload bit counter, then delay until halfway through - rx_bitloop: ; the first data bit (12 cycles incl wait, set). - in pins, 1 ; Shift data bit into ISR - jmp x-- rx_bitloop [6] ; Loop 8 times, each loop iteration is 8 cycles - jmp pin good_rx_stop ; Check stop bit (should be high) - - irq 4 rel ; Either a framing error or a break. Set a sticky flag, - wait 1 pin 0 ; and wait for line to return to idle state. - jmp start ; Don't push data if we didn't see good framing. - - good_rx_stop: ; No delay before returning to start; a little slack is - in null 24 - push ; important in case the TX clock is slightly too fast. - "# - ); - let mut cfg = Config::default(); - cfg.use_program(&common.load_program(&prg.program), &[]); - - let rx_pin = common.make_pio_pin(rx_pin); - sm_rx.set_pins(Level::High, &[&rx_pin]); - cfg.set_in_pins(&[&rx_pin]); - cfg.set_jmp_pin(&rx_pin); - sm_rx.set_pin_dirs(Direction::In, &[&rx_pin]); - - cfg.clock_divider = (U56F8!(125_000_000) / (8 * baud)).to_fixed(); - cfg.shift_in.auto_fill = false; - cfg.shift_in.direction = ShiftDirection::Right; - cfg.shift_in.threshold = 32; - cfg.fifo_join = FifoJoin::RxOnly; - sm_rx.set_config(&cfg); - sm_rx.set_enable(true); - - Self { sm_rx } - } - - pub async fn read_u8(&mut self) -> u8 { - self.sm_rx.rx().wait_pull().await as u8 - } - } - - impl ErrorType for PioUartRx<'_> { - type Error = Infallible; - } - - impl Read for PioUartRx<'_> { - async fn read(&mut self, buf: &mut [u8]) -> Result { - let mut i = 0; - while i < buf.len() { - buf[i] = self.read_u8().await; - i += 1; - } - Ok(i) - } - } -} diff --git a/examples/rp/src/bin/pio_ws2812.rs b/examples/rp/src/bin/pio_ws2812.rs index ac145933c..d1fcfc471 100644 --- a/examples/rp/src/bin/pio_ws2812.rs +++ b/examples/rp/src/bin/pio_ws2812.rs @@ -6,15 +6,11 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_rp::dma::{AnyChannel, Channel}; +use embassy_rp::bind_interrupts; use embassy_rp::peripherals::PIO0; -use embassy_rp::pio::{ - Common, Config, FifoJoin, Instance, InterruptHandler, Pio, PioPin, ShiftConfig, ShiftDirection, StateMachine, -}; -use embassy_rp::{bind_interrupts, clocks, into_ref, Peripheral, PeripheralRef}; -use embassy_time::{Duration, Ticker, Timer}; -use fixed::types::U24F8; -use fixed_macro::fixed; +use embassy_rp::pio::{InterruptHandler, Pio}; +use embassy_rp::pio_programs::ws2812::{PioWs2812, PioWs2812Program}; +use embassy_time::{Duration, Ticker}; use smart_leds::RGB8; use {defmt_rtt as _, panic_probe as _}; @@ -22,96 +18,6 @@ bind_interrupts!(struct Irqs { PIO0_IRQ_0 => InterruptHandler; }); -pub struct Ws2812<'d, P: Instance, const S: usize, const N: usize> { - dma: PeripheralRef<'d, AnyChannel>, - sm: StateMachine<'d, P, S>, -} - -impl<'d, P: Instance, const S: usize, const N: usize> Ws2812<'d, P, S, N> { - pub fn new( - pio: &mut Common<'d, P>, - mut sm: StateMachine<'d, P, S>, - dma: impl Peripheral

+ 'd, - pin: impl PioPin, - ) -> Self { - into_ref!(dma); - - // Setup sm0 - - // prepare the PIO program - let side_set = pio::SideSet::new(false, 1, false); - let mut a: pio::Assembler<32> = pio::Assembler::new_with_side_set(side_set); - - const T1: u8 = 2; // start bit - const T2: u8 = 5; // data bit - const T3: u8 = 3; // stop bit - const CYCLES_PER_BIT: u32 = (T1 + T2 + T3) as u32; - - let mut wrap_target = a.label(); - let mut wrap_source = a.label(); - let mut do_zero = a.label(); - a.set_with_side_set(pio::SetDestination::PINDIRS, 1, 0); - a.bind(&mut wrap_target); - // Do stop bit - a.out_with_delay_and_side_set(pio::OutDestination::X, 1, T3 - 1, 0); - // Do start bit - a.jmp_with_delay_and_side_set(pio::JmpCondition::XIsZero, &mut do_zero, T1 - 1, 1); - // Do data bit = 1 - a.jmp_with_delay_and_side_set(pio::JmpCondition::Always, &mut wrap_target, T2 - 1, 1); - a.bind(&mut do_zero); - // Do data bit = 0 - a.nop_with_delay_and_side_set(T2 - 1, 0); - a.bind(&mut wrap_source); - - let prg = a.assemble_with_wrap(wrap_source, wrap_target); - let mut cfg = Config::default(); - - // Pin config - let out_pin = pio.make_pio_pin(pin); - cfg.set_out_pins(&[&out_pin]); - cfg.set_set_pins(&[&out_pin]); - - cfg.use_program(&pio.load_program(&prg), &[&out_pin]); - - // Clock config, measured in kHz to avoid overflows - // TODO CLOCK_FREQ should come from embassy_rp - let clock_freq = U24F8::from_num(clocks::clk_sys_freq() / 1000); - let ws2812_freq = fixed!(800: U24F8); - let bit_freq = ws2812_freq * CYCLES_PER_BIT; - cfg.clock_divider = clock_freq / bit_freq; - - // FIFO config - cfg.fifo_join = FifoJoin::TxOnly; - cfg.shift_out = ShiftConfig { - auto_fill: true, - threshold: 24, - direction: ShiftDirection::Left, - }; - - sm.set_config(&cfg); - sm.set_enable(true); - - Self { - dma: dma.map_into(), - sm, - } - } - - pub async fn write(&mut self, colors: &[RGB8; N]) { - // Precompute the word bytes from the colors - let mut words = [0u32; N]; - for i in 0..N { - let word = (u32::from(colors[i].g) << 24) | (u32::from(colors[i].r) << 16) | (u32::from(colors[i].b) << 8); - words[i] = word; - } - - // DMA transfer - self.sm.tx().dma_push(self.dma.reborrow(), &words).await; - - Timer::after_micros(55).await; - } -} - /// Input a value 0 to 255 to get a color value /// The colours are a transition r - g - b - back to r. fn wheel(mut wheel_pos: u8) -> RGB8 { @@ -142,7 +48,8 @@ async fn main(_spawner: Spawner) { // Common neopixel pins: // Thing plus: 8 // Adafruit Feather: 16; Adafruit Feather+RFM95: 4 - let mut ws2812 = Ws2812::new(&mut common, sm0, p.DMA_CH0, p.PIN_16); + let program = PioWs2812Program::new(&mut common); + let mut ws2812 = PioWs2812::new(&mut common, sm0, p.DMA_CH0, p.PIN_16, &program); // Loop forever making RGB values and pushing them out to the WS2812. let mut ticker = Ticker::every(Duration::from_millis(10)); diff --git a/examples/rp23/src/bin/pio_hd44780.rs b/examples/rp23/src/bin/pio_hd44780.rs index 5a6d7a9c5..c6f5f6db0 100644 --- a/examples/rp23/src/bin/pio_hd44780.rs +++ b/examples/rp23/src/bin/pio_hd44780.rs @@ -7,14 +7,12 @@ use core::fmt::Write; use embassy_executor::Spawner; +use embassy_rp::bind_interrupts; use embassy_rp::block::ImageDef; -use embassy_rp::dma::{AnyChannel, Channel}; use embassy_rp::peripherals::PIO0; -use embassy_rp::pio::{ - Config, Direction, FifoJoin, InterruptHandler, Pio, PioPin, ShiftConfig, ShiftDirection, StateMachine, -}; +use embassy_rp::pio::{InterruptHandler, Pio}; +use embassy_rp::pio_programs::hd44780::{PioHD44780, PioHD44780CommandSequenceProgram, PioHD44780CommandWordProgram}; use embassy_rp::pwm::{self, Pwm}; -use embassy_rp::{bind_interrupts, into_ref, Peripheral, PeripheralRef}; use embassy_time::{Instant, Timer}; use {defmt_rtt as _, panic_probe as _}; @@ -48,8 +46,27 @@ async fn main(_spawner: Spawner) { c }); - let mut hd = HD44780::new( - p.PIO0, Irqs, p.DMA_CH3, p.PIN_0, p.PIN_1, p.PIN_2, p.PIN_3, p.PIN_4, p.PIN_5, p.PIN_6, + let Pio { + mut common, sm0, irq0, .. + } = Pio::new(p.PIO0, Irqs); + + let word_prg = PioHD44780CommandWordProgram::new(&mut common); + let seq_prg = PioHD44780CommandSequenceProgram::new(&mut common); + + let mut hd = PioHD44780::new( + &mut common, + sm0, + irq0, + p.DMA_CH3, + p.PIN_0, + p.PIN_1, + p.PIN_2, + p.PIN_3, + p.PIN_4, + p.PIN_5, + p.PIN_6, + &word_prg, + &seq_prg, ) .await; @@ -73,173 +90,3 @@ async fn main(_spawner: Spawner) { Timer::after_secs(1).await; } } - -pub struct HD44780<'l> { - dma: PeripheralRef<'l, AnyChannel>, - sm: StateMachine<'l, PIO0, 0>, - - buf: [u8; 40], -} - -impl<'l> HD44780<'l> { - pub async fn new( - pio: impl Peripheral

+ 'l, - irq: Irqs, - dma: impl Peripheral

+ 'l, - rs: impl PioPin, - rw: impl PioPin, - e: impl PioPin, - db4: impl PioPin, - db5: impl PioPin, - db6: impl PioPin, - db7: impl PioPin, - ) -> HD44780<'l> { - into_ref!(dma); - - let Pio { - mut common, - mut irq0, - mut sm0, - .. - } = Pio::new(pio, irq); - - // takes command words ( <0:4>) - let prg = pio_proc::pio_asm!( - r#" - .side_set 1 opt - .origin 20 - - loop: - out x, 24 - delay: - jmp x--, delay - out pins, 4 side 1 - out null, 4 side 0 - jmp !osre, loop - irq 0 - "#, - ); - - let rs = common.make_pio_pin(rs); - let rw = common.make_pio_pin(rw); - let e = common.make_pio_pin(e); - let db4 = common.make_pio_pin(db4); - let db5 = common.make_pio_pin(db5); - let db6 = common.make_pio_pin(db6); - let db7 = common.make_pio_pin(db7); - - sm0.set_pin_dirs(Direction::Out, &[&rs, &rw, &e, &db4, &db5, &db6, &db7]); - - let mut cfg = Config::default(); - cfg.use_program(&common.load_program(&prg.program), &[&e]); - cfg.clock_divider = 125u8.into(); - cfg.set_out_pins(&[&db4, &db5, &db6, &db7]); - cfg.shift_out = ShiftConfig { - auto_fill: true, - direction: ShiftDirection::Left, - threshold: 32, - }; - cfg.fifo_join = FifoJoin::TxOnly; - sm0.set_config(&cfg); - - sm0.set_enable(true); - // init to 8 bit thrice - sm0.tx().push((50000 << 8) | 0x30); - sm0.tx().push((5000 << 8) | 0x30); - sm0.tx().push((200 << 8) | 0x30); - // init 4 bit - sm0.tx().push((200 << 8) | 0x20); - // set font and lines - sm0.tx().push((50 << 8) | 0x20); - sm0.tx().push(0b1100_0000); - - irq0.wait().await; - sm0.set_enable(false); - - // takes command sequences ( , data...) - // many side sets are only there to free up a delay bit! - let prg = pio_proc::pio_asm!( - r#" - .origin 27 - .side_set 1 - - .wrap_target - pull side 0 - out x 1 side 0 ; !rs - out y 7 side 0 ; #data - 1 - - ; rs/rw to e: >= 60ns - ; e high time: >= 500ns - ; e low time: >= 500ns - ; read data valid after e falling: ~5ns - ; write data hold after e falling: ~10ns - - loop: - pull side 0 - jmp !x data side 0 - command: - set pins 0b00 side 0 - jmp shift side 0 - data: - set pins 0b01 side 0 - shift: - out pins 4 side 1 [9] - nop side 0 [9] - out pins 4 side 1 [9] - mov osr null side 0 [7] - out pindirs 4 side 0 - set pins 0b10 side 0 - busy: - nop side 1 [9] - jmp pin more side 0 [9] - mov osr ~osr side 1 [9] - nop side 0 [4] - out pindirs 4 side 0 - jmp y-- loop side 0 - .wrap - more: - nop side 1 [9] - jmp busy side 0 [9] - "# - ); - - let mut cfg = Config::default(); - cfg.use_program(&common.load_program(&prg.program), &[&e]); - cfg.clock_divider = 8u8.into(); // ~64ns/insn - cfg.set_jmp_pin(&db7); - cfg.set_set_pins(&[&rs, &rw]); - cfg.set_out_pins(&[&db4, &db5, &db6, &db7]); - cfg.shift_out.direction = ShiftDirection::Left; - cfg.fifo_join = FifoJoin::TxOnly; - sm0.set_config(&cfg); - - sm0.set_enable(true); - - // display on and cursor on and blinking, reset display - sm0.tx().dma_push(dma.reborrow(), &[0x81u8, 0x0f, 1]).await; - - Self { - dma: dma.map_into(), - sm: sm0, - buf: [0x20; 40], - } - } - - pub async fn add_line(&mut self, s: &[u8]) { - // move cursor to 0:0, prepare 16 characters - self.buf[..3].copy_from_slice(&[0x80, 0x80, 15]); - // move line 2 up - self.buf.copy_within(22..38, 3); - // move cursor to 1:0, prepare 16 characters - self.buf[19..22].copy_from_slice(&[0x80, 0xc0, 15]); - // file line 2 with spaces - self.buf[22..38].fill(0x20); - // copy input line - let len = s.len().min(16); - self.buf[22..22 + len].copy_from_slice(&s[0..len]); - // set cursor to 1:15 - self.buf[38..].copy_from_slice(&[0x80, 0xcf]); - - self.sm.tx().dma_push(self.dma.reborrow(), &self.buf).await; - } -} diff --git a/examples/rp23/src/bin/pio_i2s.rs b/examples/rp23/src/bin/pio_i2s.rs index 46e5eac88..90491fb45 100644 --- a/examples/rp23/src/bin/pio_i2s.rs +++ b/examples/rp23/src/bin/pio_i2s.rs @@ -13,11 +13,11 @@ use core::mem; use embassy_executor::Spawner; +use embassy_rp::bind_interrupts; use embassy_rp::block::ImageDef; use embassy_rp::peripherals::PIO0; -use embassy_rp::pio::{Config, FifoJoin, InterruptHandler, Pio, ShiftConfig, ShiftDirection}; -use embassy_rp::{bind_interrupts, Peripheral}; -use fixed::traits::ToFixed; +use embassy_rp::pio::{InterruptHandler, Pio}; +use embassy_rp::pio_programs::i2s::{PioI2sOut, PioI2sOutProgram}; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; @@ -30,61 +30,32 @@ bind_interrupts!(struct Irqs { }); const SAMPLE_RATE: u32 = 48_000; +const BIT_DEPTH: u32 = 16; +const CHANNELS: u32 = 2; #[embassy_executor::main] async fn main(_spawner: Spawner) { - let p = embassy_rp::init(Default::default()); + let mut p = embassy_rp::init(Default::default()); // Setup pio state machine for i2s output - let mut pio = Pio::new(p.PIO0, Irqs); - - #[rustfmt::skip] - let pio_program = pio_proc::pio_asm!( - ".side_set 2", - " set x, 14 side 0b01", // side 0bWB - W = Word Clock, B = Bit Clock - "left_data:", - " out pins, 1 side 0b00", - " jmp x-- left_data side 0b01", - " out pins 1 side 0b10", - " set x, 14 side 0b11", - "right_data:", - " out pins 1 side 0b10", - " jmp x-- right_data side 0b11", - " out pins 1 side 0b00", - ); + let Pio { mut common, sm0, .. } = Pio::new(p.PIO0, Irqs); let bit_clock_pin = p.PIN_18; let left_right_clock_pin = p.PIN_19; let data_pin = p.PIN_20; - let data_pin = pio.common.make_pio_pin(data_pin); - let bit_clock_pin = pio.common.make_pio_pin(bit_clock_pin); - let left_right_clock_pin = pio.common.make_pio_pin(left_right_clock_pin); - - let cfg = { - let mut cfg = Config::default(); - cfg.use_program( - &pio.common.load_program(&pio_program.program), - &[&bit_clock_pin, &left_right_clock_pin], - ); - cfg.set_out_pins(&[&data_pin]); - const BIT_DEPTH: u32 = 16; - const CHANNELS: u32 = 2; - let clock_frequency = SAMPLE_RATE * BIT_DEPTH * CHANNELS; - cfg.clock_divider = (125_000_000. / clock_frequency as f64 / 2.).to_fixed(); - cfg.shift_out = ShiftConfig { - threshold: 32, - direction: ShiftDirection::Left, - auto_fill: true, - }; - // join fifos to have twice the time to start the next dma transfer - cfg.fifo_join = FifoJoin::TxOnly; - cfg - }; - pio.sm0.set_config(&cfg); - pio.sm0.set_pin_dirs( - embassy_rp::pio::Direction::Out, - &[&data_pin, &left_right_clock_pin, &bit_clock_pin], + let program = PioI2sOutProgram::new(&mut common); + let mut i2s = PioI2sOut::new( + &mut common, + sm0, + p.DMA_CH0, + data_pin, + bit_clock_pin, + left_right_clock_pin, + SAMPLE_RATE, + BIT_DEPTH, + CHANNELS, + &program, ); // create two audio buffers (back and front) which will take turns being @@ -95,20 +66,16 @@ async fn main(_spawner: Spawner) { let (mut back_buffer, mut front_buffer) = dma_buffer.split_at_mut(BUFFER_SIZE); // start pio state machine - pio.sm0.set_enable(true); - let tx = pio.sm0.tx(); - let mut dma_ref = p.DMA_CH0.into_ref(); - let mut fade_value: i32 = 0; let mut phase: i32 = 0; loop { // trigger transfer of front buffer data to the pio fifo // but don't await the returned future, yet - let dma_future = tx.dma_push(dma_ref.reborrow(), front_buffer); + let dma_future = i2s.write(front_buffer); - // fade in audio - let fade_target = i32::MAX; + // fade in audio when bootsel is pressed + let fade_target = if p.BOOTSEL.is_pressed() { i32::MAX } else { 0 }; // fill back buffer with fresh audio samples before awaiting the dma future for s in back_buffer.iter_mut() { diff --git a/examples/rp23/src/bin/pio_onewire.rs b/examples/rp23/src/bin/pio_onewire.rs new file mode 100644 index 000000000..7f227d04b --- /dev/null +++ b/examples/rp23/src/bin/pio_onewire.rs @@ -0,0 +1,88 @@ +//! This example shows how you can use PIO to read a `DS18B20` one-wire temperature sensor. + +#![no_std] +#![no_main] +use defmt::*; +use embassy_executor::Spawner; +use embassy_rp::bind_interrupts; +use embassy_rp::block::ImageDef; +use embassy_rp::peripherals::PIO0; +use embassy_rp::pio::{self, InterruptHandler, Pio}; +use embassy_rp::pio_programs::onewire::{PioOneWire, PioOneWireProgram}; +use embassy_time::Timer; +use {defmt_rtt as _, panic_probe as _}; + +#[link_section = ".start_block"] +#[used] +pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); + +bind_interrupts!(struct Irqs { + PIO0_IRQ_0 => InterruptHandler; +}); + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_rp::init(Default::default()); + let mut pio = Pio::new(p.PIO0, Irqs); + + let prg = PioOneWireProgram::new(&mut pio.common); + let onewire = PioOneWire::new(&mut pio.common, pio.sm0, p.PIN_2, &prg); + + let mut sensor = Ds18b20::new(onewire); + + loop { + sensor.start().await; // Start a new measurement + Timer::after_secs(1).await; // Allow 1s for the measurement to finish + match sensor.temperature().await { + Ok(temp) => info!("temp = {:?} deg C", temp), + _ => error!("sensor error"), + } + Timer::after_secs(1).await; + } +} + +/// DS18B20 temperature sensor driver +pub struct Ds18b20<'d, PIO: pio::Instance, const SM: usize> { + wire: PioOneWire<'d, PIO, SM>, +} + +impl<'d, PIO: pio::Instance, const SM: usize> Ds18b20<'d, PIO, SM> { + pub fn new(wire: PioOneWire<'d, PIO, SM>) -> Self { + Self { wire } + } + + /// Calculate CRC8 of the data + fn crc8(data: &[u8]) -> u8 { + let mut temp; + let mut data_byte; + let mut crc = 0; + for b in data { + data_byte = *b; + for _ in 0..8 { + temp = (crc ^ data_byte) & 0x01; + crc >>= 1; + if temp != 0 { + crc ^= 0x8C; + } + data_byte >>= 1; + } + } + crc + } + + /// Start a new measurement. Allow at least 1000ms before getting `temperature`. + pub async fn start(&mut self) { + self.wire.write_bytes(&[0xCC, 0x44]).await; + } + + /// Read the temperature. Ensure >1000ms has passed since `start` before calling this. + pub async fn temperature(&mut self) -> Result { + self.wire.write_bytes(&[0xCC, 0xBE]).await; + let mut data = [0; 9]; + self.wire.read_bytes(&mut data).await; + match Self::crc8(&data) == 0 { + true => Ok(((data[1] as u32) << 8 | data[0] as u32) as f32 / 16.), + false => Err(()), + } + } +} diff --git a/examples/rp23/src/bin/pio_pwm.rs b/examples/rp23/src/bin/pio_pwm.rs index 3cffd213d..11af62a7a 100644 --- a/examples/rp23/src/bin/pio_pwm.rs +++ b/examples/rp23/src/bin/pio_pwm.rs @@ -5,13 +5,12 @@ use core::time::Duration; use embassy_executor::Spawner; +use embassy_rp::bind_interrupts; use embassy_rp::block::ImageDef; -use embassy_rp::gpio::Level; use embassy_rp::peripherals::PIO0; -use embassy_rp::pio::{Common, Config, Direction, Instance, InterruptHandler, Pio, PioPin, StateMachine}; -use embassy_rp::{bind_interrupts, clocks}; +use embassy_rp::pio::{InterruptHandler, Pio}; +use embassy_rp::pio_programs::pwm::{PioPwm, PioPwmProgram}; use embassy_time::Timer; -use pio::InstructionOperands; use {defmt_rtt as _, panic_probe as _}; #[link_section = ".start_block"] @@ -24,93 +23,14 @@ bind_interrupts!(struct Irqs { PIO0_IRQ_0 => InterruptHandler; }); -pub fn to_pio_cycles(duration: Duration) -> u32 { - (clocks::clk_sys_freq() / 1_000_000) / 3 * duration.as_micros() as u32 // parentheses are required to prevent overflow -} - -pub struct PwmPio<'d, T: Instance, const SM: usize> { - sm: StateMachine<'d, T, SM>, -} - -impl<'d, T: Instance, const SM: usize> PwmPio<'d, T, SM> { - pub fn new(pio: &mut Common<'d, T>, mut sm: StateMachine<'d, T, SM>, pin: impl PioPin) -> Self { - let prg = pio_proc::pio_asm!( - ".side_set 1 opt" - "pull noblock side 0" - "mov x, osr" - "mov y, isr" - "countloop:" - "jmp x!=y noset" - "jmp skip side 1" - "noset:" - "nop" - "skip:" - "jmp y-- countloop" - ); - - pio.load_program(&prg.program); - let pin = pio.make_pio_pin(pin); - sm.set_pins(Level::High, &[&pin]); - sm.set_pin_dirs(Direction::Out, &[&pin]); - - let mut cfg = Config::default(); - cfg.use_program(&pio.load_program(&prg.program), &[&pin]); - - sm.set_config(&cfg); - - Self { sm } - } - - pub fn start(&mut self) { - self.sm.set_enable(true); - } - - pub fn stop(&mut self) { - self.sm.set_enable(false); - } - - pub fn set_period(&mut self, duration: Duration) { - let is_enabled = self.sm.is_enabled(); - while !self.sm.tx().empty() {} // Make sure that the queue is empty - self.sm.set_enable(false); - self.sm.tx().push(to_pio_cycles(duration)); - unsafe { - self.sm.exec_instr( - InstructionOperands::PULL { - if_empty: false, - block: false, - } - .encode(), - ); - self.sm.exec_instr( - InstructionOperands::OUT { - destination: ::pio::OutDestination::ISR, - bit_count: 32, - } - .encode(), - ); - }; - if is_enabled { - self.sm.set_enable(true) // Enable if previously enabled - } - } - - pub fn set_level(&mut self, level: u32) { - self.sm.tx().push(level); - } - - pub fn write(&mut self, duration: Duration) { - self.set_level(to_pio_cycles(duration)); - } -} - #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_rp::init(Default::default()); let Pio { mut common, sm0, .. } = Pio::new(p.PIO0, Irqs); // Note that PIN_25 is the led pin on the Pico - let mut pwm_pio = PwmPio::new(&mut common, sm0, p.PIN_25); + let prg = PioPwmProgram::new(&mut common); + let mut pwm_pio = PioPwm::new(&mut common, sm0, p.PIN_25, &prg); pwm_pio.set_period(Duration::from_micros(REFRESH_INTERVAL)); pwm_pio.start(); diff --git a/examples/rp23/src/bin/pio_rotary_encoder.rs b/examples/rp23/src/bin/pio_rotary_encoder.rs index 9542d63b7..9a953951f 100644 --- a/examples/rp23/src/bin/pio_rotary_encoder.rs +++ b/examples/rp23/src/bin/pio_rotary_encoder.rs @@ -6,11 +6,12 @@ use defmt::info; use embassy_executor::Spawner; use embassy_rp::block::ImageDef; -use embassy_rp::gpio::Pull; use embassy_rp::peripherals::PIO0; -use embassy_rp::{bind_interrupts, pio}; -use fixed::traits::ToFixed; -use pio::{Common, Config, FifoJoin, Instance, InterruptHandler, Pio, PioPin, ShiftDirection, StateMachine}; +use embassy_rp::{ + bind_interrupts, + pio::{InterruptHandler, Pio}, + pio_programs::rotary_encoder::{Direction, PioEncoder, PioEncoderProgram}, +}; use {defmt_rtt as _, panic_probe as _}; #[link_section = ".start_block"] @@ -21,59 +22,8 @@ bind_interrupts!(struct Irqs { PIO0_IRQ_0 => InterruptHandler; }); -pub struct PioEncoder<'d, T: Instance, const SM: usize> { - sm: StateMachine<'d, T, SM>, -} - -impl<'d, T: Instance, const SM: usize> PioEncoder<'d, T, SM> { - pub fn new( - pio: &mut Common<'d, T>, - mut sm: StateMachine<'d, T, SM>, - pin_a: impl PioPin, - pin_b: impl PioPin, - ) -> Self { - let mut pin_a = pio.make_pio_pin(pin_a); - let mut pin_b = pio.make_pio_pin(pin_b); - pin_a.set_pull(Pull::Up); - pin_b.set_pull(Pull::Up); - sm.set_pin_dirs(pio::Direction::In, &[&pin_a, &pin_b]); - - let prg = pio_proc::pio_asm!("wait 1 pin 1", "wait 0 pin 1", "in pins, 2", "push",); - - let mut cfg = Config::default(); - cfg.set_in_pins(&[&pin_a, &pin_b]); - cfg.fifo_join = FifoJoin::RxOnly; - cfg.shift_in.direction = ShiftDirection::Left; - cfg.clock_divider = 10_000.to_fixed(); - cfg.use_program(&pio.load_program(&prg.program), &[]); - sm.set_config(&cfg); - sm.set_enable(true); - Self { sm } - } - - pub async fn read(&mut self) -> Direction { - loop { - match self.sm.rx().wait_pull().await { - 0 => return Direction::CounterClockwise, - 1 => return Direction::Clockwise, - _ => {} - } - } - } -} - -pub enum Direction { - Clockwise, - CounterClockwise, -} - -#[embassy_executor::main] -async fn main(_spawner: Spawner) { - let p = embassy_rp::init(Default::default()); - let Pio { mut common, sm0, .. } = Pio::new(p.PIO0, Irqs); - - let mut encoder = PioEncoder::new(&mut common, sm0, p.PIN_4, p.PIN_5); - +#[embassy_executor::task] +async fn encoder_0(mut encoder: PioEncoder<'static, PIO0, 0>) { let mut count = 0; loop { info!("Count: {}", count); @@ -83,3 +33,30 @@ async fn main(_spawner: Spawner) { }; } } + +#[embassy_executor::task] +async fn encoder_1(mut encoder: PioEncoder<'static, PIO0, 1>) { + let mut count = 0; + loop { + info!("Count: {}", count); + count += match encoder.read().await { + Direction::Clockwise => 1, + Direction::CounterClockwise => -1, + }; + } +} + +#[embassy_executor::main] +async fn main(spawner: Spawner) { + let p = embassy_rp::init(Default::default()); + let Pio { + mut common, sm0, sm1, .. + } = Pio::new(p.PIO0, Irqs); + + let prg = PioEncoderProgram::new(&mut common); + let encoder0 = PioEncoder::new(&mut common, sm0, p.PIN_4, p.PIN_5, &prg); + let encoder1 = PioEncoder::new(&mut common, sm1, p.PIN_6, p.PIN_7, &prg); + + spawner.must_spawn(encoder_0(encoder0)); + spawner.must_spawn(encoder_1(encoder1)); +} diff --git a/examples/rp23/src/bin/pio_servo.rs b/examples/rp23/src/bin/pio_servo.rs index 3202ab475..4e94103f1 100644 --- a/examples/rp23/src/bin/pio_servo.rs +++ b/examples/rp23/src/bin/pio_servo.rs @@ -5,13 +5,12 @@ use core::time::Duration; use embassy_executor::Spawner; +use embassy_rp::bind_interrupts; use embassy_rp::block::ImageDef; -use embassy_rp::gpio::Level; use embassy_rp::peripherals::PIO0; -use embassy_rp::pio::{Common, Config, Direction, Instance, InterruptHandler, Pio, PioPin, StateMachine}; -use embassy_rp::{bind_interrupts, clocks}; +use embassy_rp::pio::{Instance, InterruptHandler, Pio}; +use embassy_rp::pio_programs::pwm::{PioPwm, PioPwmProgram}; use embassy_time::Timer; -use pio::InstructionOperands; use {defmt_rtt as _, panic_probe as _}; #[link_section = ".start_block"] @@ -27,88 +26,8 @@ bind_interrupts!(struct Irqs { PIO0_IRQ_0 => InterruptHandler; }); -pub fn to_pio_cycles(duration: Duration) -> u32 { - (clocks::clk_sys_freq() / 1_000_000) / 3 * duration.as_micros() as u32 // parentheses are required to prevent overflow -} - -pub struct PwmPio<'d, T: Instance, const SM: usize> { - sm: StateMachine<'d, T, SM>, -} - -impl<'d, T: Instance, const SM: usize> PwmPio<'d, T, SM> { - pub fn new(pio: &mut Common<'d, T>, mut sm: StateMachine<'d, T, SM>, pin: impl PioPin) -> Self { - let prg = pio_proc::pio_asm!( - ".side_set 1 opt" - "pull noblock side 0" - "mov x, osr" - "mov y, isr" - "countloop:" - "jmp x!=y noset" - "jmp skip side 1" - "noset:" - "nop" - "skip:" - "jmp y-- countloop" - ); - - pio.load_program(&prg.program); - let pin = pio.make_pio_pin(pin); - sm.set_pins(Level::High, &[&pin]); - sm.set_pin_dirs(Direction::Out, &[&pin]); - - let mut cfg = Config::default(); - cfg.use_program(&pio.load_program(&prg.program), &[&pin]); - - sm.set_config(&cfg); - - Self { sm } - } - - pub fn start(&mut self) { - self.sm.set_enable(true); - } - - pub fn stop(&mut self) { - self.sm.set_enable(false); - } - - pub fn set_period(&mut self, duration: Duration) { - let is_enabled = self.sm.is_enabled(); - while !self.sm.tx().empty() {} // Make sure that the queue is empty - self.sm.set_enable(false); - self.sm.tx().push(to_pio_cycles(duration)); - unsafe { - self.sm.exec_instr( - InstructionOperands::PULL { - if_empty: false, - block: false, - } - .encode(), - ); - self.sm.exec_instr( - InstructionOperands::OUT { - destination: ::pio::OutDestination::ISR, - bit_count: 32, - } - .encode(), - ); - }; - if is_enabled { - self.sm.set_enable(true) // Enable if previously enabled - } - } - - pub fn set_level(&mut self, level: u32) { - self.sm.tx().push(level); - } - - pub fn write(&mut self, duration: Duration) { - self.set_level(to_pio_cycles(duration)); - } -} - pub struct ServoBuilder<'d, T: Instance, const SM: usize> { - pwm: PwmPio<'d, T, SM>, + pwm: PioPwm<'d, T, SM>, period: Duration, min_pulse_width: Duration, max_pulse_width: Duration, @@ -116,7 +35,7 @@ pub struct ServoBuilder<'d, T: Instance, const SM: usize> { } impl<'d, T: Instance, const SM: usize> ServoBuilder<'d, T, SM> { - pub fn new(pwm: PwmPio<'d, T, SM>) -> Self { + pub fn new(pwm: PioPwm<'d, T, SM>) -> Self { Self { pwm, period: Duration::from_micros(REFRESH_INTERVAL), @@ -158,7 +77,7 @@ impl<'d, T: Instance, const SM: usize> ServoBuilder<'d, T, SM> { } pub struct Servo<'d, T: Instance, const SM: usize> { - pwm: PwmPio<'d, T, SM>, + pwm: PioPwm<'d, T, SM>, min_pulse_width: Duration, max_pulse_width: Duration, max_degree_rotation: u64, @@ -195,7 +114,8 @@ async fn main(_spawner: Spawner) { let p = embassy_rp::init(Default::default()); let Pio { mut common, sm0, .. } = Pio::new(p.PIO0, Irqs); - let pwm_pio = PwmPio::new(&mut common, sm0, p.PIN_1); + let prg = PioPwmProgram::new(&mut common); + let pwm_pio = PioPwm::new(&mut common, sm0, p.PIN_1, &prg); let mut servo = ServoBuilder::new(pwm_pio) .set_max_degree_rotation(120) // Example of adjusting values for MG996R servo .set_min_pulse_width(Duration::from_micros(350)) // This value was detemined by a rough experiment. diff --git a/examples/rp23/src/bin/pio_stepper.rs b/examples/rp23/src/bin/pio_stepper.rs index 5e87da6eb..4fabe78ca 100644 --- a/examples/rp23/src/bin/pio_stepper.rs +++ b/examples/rp23/src/bin/pio_stepper.rs @@ -3,18 +3,15 @@ #![no_std] #![no_main] -use core::mem::{self, MaybeUninit}; use defmt::info; use embassy_executor::Spawner; use embassy_rp::bind_interrupts; use embassy_rp::block::ImageDef; use embassy_rp::peripherals::PIO0; -use embassy_rp::pio::{Common, Config, Direction, Instance, InterruptHandler, Irq, Pio, PioPin, StateMachine}; +use embassy_rp::pio::{InterruptHandler, Pio}; +use embassy_rp::pio_programs::stepper::{PioStepper, PioStepperProgram}; use embassy_time::{with_timeout, Duration, Timer}; -use fixed::traits::ToFixed; -use fixed::types::extra::U8; -use fixed::FixedU32; use {defmt_rtt as _, panic_probe as _}; #[link_section = ".start_block"] @@ -25,126 +22,6 @@ bind_interrupts!(struct Irqs { PIO0_IRQ_0 => InterruptHandler; }); -pub struct PioStepper<'d, T: Instance, const SM: usize> { - irq: Irq<'d, T, SM>, - sm: StateMachine<'d, T, SM>, -} - -impl<'d, T: Instance, const SM: usize> PioStepper<'d, T, SM> { - pub fn new( - pio: &mut Common<'d, T>, - mut sm: StateMachine<'d, T, SM>, - irq: Irq<'d, T, SM>, - pin0: impl PioPin, - pin1: impl PioPin, - pin2: impl PioPin, - pin3: impl PioPin, - ) -> Self { - let prg = pio_proc::pio_asm!( - "pull block", - "mov x, osr", - "pull block", - "mov y, osr", - "jmp !x end", - "loop:", - "jmp !osre step", - "mov osr, y", - "step:", - "out pins, 4 [31]" - "jmp x-- loop", - "end:", - "irq 0 rel" - ); - let pin0 = pio.make_pio_pin(pin0); - let pin1 = pio.make_pio_pin(pin1); - let pin2 = pio.make_pio_pin(pin2); - let pin3 = pio.make_pio_pin(pin3); - sm.set_pin_dirs(Direction::Out, &[&pin0, &pin1, &pin2, &pin3]); - let mut cfg = Config::default(); - cfg.set_out_pins(&[&pin0, &pin1, &pin2, &pin3]); - cfg.clock_divider = (125_000_000 / (100 * 136)).to_fixed(); - cfg.use_program(&pio.load_program(&prg.program), &[]); - sm.set_config(&cfg); - sm.set_enable(true); - Self { irq, sm } - } - - // Set pulse frequency - pub fn set_frequency(&mut self, freq: u32) { - let clock_divider: FixedU32 = (125_000_000 / (freq * 136)).to_fixed(); - assert!(clock_divider <= 65536, "clkdiv must be <= 65536"); - assert!(clock_divider >= 1, "clkdiv must be >= 1"); - self.sm.set_clock_divider(clock_divider); - self.sm.clkdiv_restart(); - } - - // Full step, one phase - pub async fn step(&mut self, steps: i32) { - if steps > 0 { - self.run(steps, 0b1000_0100_0010_0001_1000_0100_0010_0001).await - } else { - self.run(-steps, 0b0001_0010_0100_1000_0001_0010_0100_1000).await - } - } - - // Full step, two phase - pub async fn step2(&mut self, steps: i32) { - if steps > 0 { - self.run(steps, 0b1001_1100_0110_0011_1001_1100_0110_0011).await - } else { - self.run(-steps, 0b0011_0110_1100_1001_0011_0110_1100_1001).await - } - } - - // Half step - pub async fn step_half(&mut self, steps: i32) { - if steps > 0 { - self.run(steps, 0b1001_1000_1100_0100_0110_0010_0011_0001).await - } else { - self.run(-steps, 0b0001_0011_0010_0110_0100_1100_1000_1001).await - } - } - - async fn run(&mut self, steps: i32, pattern: u32) { - self.sm.tx().wait_push(steps as u32).await; - self.sm.tx().wait_push(pattern).await; - let drop = OnDrop::new(|| { - self.sm.clear_fifos(); - unsafe { - self.sm.exec_instr( - pio::InstructionOperands::JMP { - address: 0, - condition: pio::JmpCondition::Always, - } - .encode(), - ); - } - }); - self.irq.wait().await; - drop.defuse(); - } -} - -struct OnDrop { - f: MaybeUninit, -} - -impl OnDrop { - pub fn new(f: F) -> Self { - Self { f: MaybeUninit::new(f) } - } - - pub fn defuse(self) { - mem::forget(self) - } -} - -impl Drop for OnDrop { - fn drop(&mut self) { - unsafe { self.f.as_ptr().read()() } - } -} - #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_rp::init(Default::default()); @@ -152,14 +29,18 @@ async fn main(_spawner: Spawner) { mut common, irq0, sm0, .. } = Pio::new(p.PIO0, Irqs); - let mut stepper = PioStepper::new(&mut common, sm0, irq0, p.PIN_4, p.PIN_5, p.PIN_6, p.PIN_7); + let prg = PioStepperProgram::new(&mut common); + let mut stepper = PioStepper::new(&mut common, sm0, irq0, p.PIN_4, p.PIN_5, p.PIN_6, p.PIN_7, &prg); stepper.set_frequency(120); loop { info!("CW full steps"); stepper.step(1000).await; info!("CCW full steps, drop after 1 sec"); - if let Err(_) = with_timeout(Duration::from_secs(1), stepper.step(i32::MIN)).await { + if with_timeout(Duration::from_secs(1), stepper.step(-i32::MAX)) + .await + .is_err() + { info!("Time's up!"); Timer::after(Duration::from_secs(1)).await; } diff --git a/examples/rp23/src/bin/pio_uart.rs b/examples/rp23/src/bin/pio_uart.rs new file mode 100644 index 000000000..6899a5d7c --- /dev/null +++ b/examples/rp23/src/bin/pio_uart.rs @@ -0,0 +1,203 @@ +//! This example shows how to use the PIO module in the RP2040 chip to implement a duplex UART. +//! The PIO module is a very powerful peripheral that can be used to implement many different +//! protocols. It is a very flexible state machine that can be programmed to do almost anything. +//! +//! This example opens up a USB device that implements a CDC ACM serial port. It then uses the +//! PIO module to implement a UART that is connected to the USB serial port. This allows you to +//! communicate with a device connected to the RP2040 over USB serial. + +#![no_std] +#![no_main] +#![allow(async_fn_in_trait)] + +use defmt::{info, panic, trace}; +use embassy_executor::Spawner; +use embassy_futures::join::{join, join3}; +use embassy_rp::bind_interrupts; +use embassy_rp::block::ImageDef; +use embassy_rp::peripherals::{PIO0, USB}; +use embassy_rp::pio; +use embassy_rp::pio_programs::uart::{PioUartRx, PioUartRxProgram, PioUartTx, PioUartTxProgram}; +use embassy_rp::usb::{Driver, Instance, InterruptHandler}; +use embassy_sync::blocking_mutex::raw::NoopRawMutex; +use embassy_sync::pipe::Pipe; +use embassy_usb::class::cdc_acm::{CdcAcmClass, Receiver, Sender, State}; +use embassy_usb::driver::EndpointError; +use embassy_usb::{Builder, Config}; +use embedded_io_async::{Read, Write}; +use {defmt_rtt as _, panic_probe as _}; + +#[link_section = ".start_block"] +#[used] +pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); + +bind_interrupts!(struct Irqs { + USBCTRL_IRQ => InterruptHandler; + PIO0_IRQ_0 => pio::InterruptHandler; +}); + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + info!("Hello there!"); + + let p = embassy_rp::init(Default::default()); + + // Create the driver, from the HAL. + let driver = Driver::new(p.USB, Irqs); + + // Create embassy-usb Config + let mut config = Config::new(0xc0de, 0xcafe); + config.manufacturer = Some("Embassy"); + config.product = Some("PIO UART example"); + config.serial_number = Some("12345678"); + config.max_power = 100; + config.max_packet_size_0 = 64; + + // Required for windows compatibility. + // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help + config.device_class = 0xEF; + config.device_sub_class = 0x02; + config.device_protocol = 0x01; + config.composite_with_iads = true; + + // Create embassy-usb DeviceBuilder using the driver and config. + // It needs some buffers for building the descriptors. + let mut config_descriptor = [0; 256]; + let mut bos_descriptor = [0; 256]; + let mut control_buf = [0; 64]; + + let mut state = State::new(); + + let mut builder = Builder::new( + driver, + config, + &mut config_descriptor, + &mut bos_descriptor, + &mut [], // no msos descriptors + &mut control_buf, + ); + + // Create classes on the builder. + let class = CdcAcmClass::new(&mut builder, &mut state, 64); + + // Build the builder. + let mut usb = builder.build(); + + // Run the USB device. + let usb_fut = usb.run(); + + // PIO UART setup + let pio::Pio { + mut common, sm0, sm1, .. + } = pio::Pio::new(p.PIO0, Irqs); + + let tx_program = PioUartTxProgram::new(&mut common); + let mut uart_tx = PioUartTx::new(9600, &mut common, sm0, p.PIN_4, &tx_program); + + let rx_program = PioUartRxProgram::new(&mut common); + let mut uart_rx = PioUartRx::new(9600, &mut common, sm1, p.PIN_5, &rx_program); + + // Pipe setup + let mut usb_pipe: Pipe = Pipe::new(); + let (mut usb_pipe_reader, mut usb_pipe_writer) = usb_pipe.split(); + + let mut uart_pipe: Pipe = Pipe::new(); + let (mut uart_pipe_reader, mut uart_pipe_writer) = uart_pipe.split(); + + let (mut usb_tx, mut usb_rx) = class.split(); + + // Read + write from USB + let usb_future = async { + loop { + info!("Wait for USB connection"); + usb_rx.wait_connection().await; + info!("Connected"); + let _ = join( + usb_read(&mut usb_rx, &mut uart_pipe_writer), + usb_write(&mut usb_tx, &mut usb_pipe_reader), + ) + .await; + info!("Disconnected"); + } + }; + + // Read + write from UART + let uart_future = join( + uart_read(&mut uart_rx, &mut usb_pipe_writer), + uart_write(&mut uart_tx, &mut uart_pipe_reader), + ); + + // Run everything concurrently. + // If we had made everything `'static` above instead, we could do this using separate tasks instead. + join3(usb_fut, usb_future, uart_future).await; +} + +struct Disconnected {} + +impl From for Disconnected { + fn from(val: EndpointError) -> Self { + match val { + EndpointError::BufferOverflow => panic!("Buffer overflow"), + EndpointError::Disabled => Disconnected {}, + } + } +} + +/// Read from the USB and write it to the UART TX pipe +async fn usb_read<'d, T: Instance + 'd>( + usb_rx: &mut Receiver<'d, Driver<'d, T>>, + uart_pipe_writer: &mut embassy_sync::pipe::Writer<'_, NoopRawMutex, 20>, +) -> Result<(), Disconnected> { + let mut buf = [0; 64]; + loop { + let n = usb_rx.read_packet(&mut buf).await?; + let data = &buf[..n]; + trace!("USB IN: {:x}", data); + (*uart_pipe_writer).write(data).await; + } +} + +/// Read from the USB TX pipe and write it to the USB +async fn usb_write<'d, T: Instance + 'd>( + usb_tx: &mut Sender<'d, Driver<'d, T>>, + usb_pipe_reader: &mut embassy_sync::pipe::Reader<'_, NoopRawMutex, 20>, +) -> Result<(), Disconnected> { + let mut buf = [0; 64]; + loop { + let n = (*usb_pipe_reader).read(&mut buf).await; + let data = &buf[..n]; + trace!("USB OUT: {:x}", data); + usb_tx.write_packet(&data).await?; + } +} + +/// Read from the UART and write it to the USB TX pipe +async fn uart_read( + uart_rx: &mut PioUartRx<'_, PIO, SM>, + usb_pipe_writer: &mut embassy_sync::pipe::Writer<'_, NoopRawMutex, 20>, +) -> ! { + let mut buf = [0; 64]; + loop { + let n = uart_rx.read(&mut buf).await.expect("UART read error"); + if n == 0 { + continue; + } + let data = &buf[..n]; + trace!("UART IN: {:x}", buf); + (*usb_pipe_writer).write(data).await; + } +} + +/// Read from the UART TX pipe and write it to the UART +async fn uart_write( + uart_tx: &mut PioUartTx<'_, PIO, SM>, + uart_pipe_reader: &mut embassy_sync::pipe::Reader<'_, NoopRawMutex, 20>, +) -> ! { + let mut buf = [0; 64]; + loop { + let n = (*uart_pipe_reader).read(&mut buf).await; + let data = &buf[..n]; + trace!("UART OUT: {:x}", data); + let _ = uart_tx.write(&data).await; + } +} diff --git a/examples/rp23/src/bin/pio_ws2812.rs b/examples/rp23/src/bin/pio_ws2812.rs index 1f1984c4d..4d258234e 100644 --- a/examples/rp23/src/bin/pio_ws2812.rs +++ b/examples/rp23/src/bin/pio_ws2812.rs @@ -6,16 +6,12 @@ use defmt::*; use embassy_executor::Spawner; +use embassy_rp::bind_interrupts; use embassy_rp::block::ImageDef; -use embassy_rp::dma::{AnyChannel, Channel}; use embassy_rp::peripherals::PIO0; -use embassy_rp::pio::{ - Common, Config, FifoJoin, Instance, InterruptHandler, Pio, PioPin, ShiftConfig, ShiftDirection, StateMachine, -}; -use embassy_rp::{bind_interrupts, clocks, into_ref, Peripheral, PeripheralRef}; -use embassy_time::{Duration, Ticker, Timer}; -use fixed::types::U24F8; -use fixed_macro::fixed; +use embassy_rp::pio::{InterruptHandler, Pio}; +use embassy_rp::pio_programs::ws2812::{PioWs2812, PioWs2812Program}; +use embassy_time::{Duration, Ticker}; use smart_leds::RGB8; use {defmt_rtt as _, panic_probe as _}; @@ -27,96 +23,6 @@ bind_interrupts!(struct Irqs { PIO0_IRQ_0 => InterruptHandler; }); -pub struct Ws2812<'d, P: Instance, const S: usize, const N: usize> { - dma: PeripheralRef<'d, AnyChannel>, - sm: StateMachine<'d, P, S>, -} - -impl<'d, P: Instance, const S: usize, const N: usize> Ws2812<'d, P, S, N> { - pub fn new( - pio: &mut Common<'d, P>, - mut sm: StateMachine<'d, P, S>, - dma: impl Peripheral

+ 'd, - pin: impl PioPin, - ) -> Self { - into_ref!(dma); - - // Setup sm0 - - // prepare the PIO program - let side_set = pio::SideSet::new(false, 1, false); - let mut a: pio::Assembler<32> = pio::Assembler::new_with_side_set(side_set); - - const T1: u8 = 2; // start bit - const T2: u8 = 5; // data bit - const T3: u8 = 3; // stop bit - const CYCLES_PER_BIT: u32 = (T1 + T2 + T3) as u32; - - let mut wrap_target = a.label(); - let mut wrap_source = a.label(); - let mut do_zero = a.label(); - a.set_with_side_set(pio::SetDestination::PINDIRS, 1, 0); - a.bind(&mut wrap_target); - // Do stop bit - a.out_with_delay_and_side_set(pio::OutDestination::X, 1, T3 - 1, 0); - // Do start bit - a.jmp_with_delay_and_side_set(pio::JmpCondition::XIsZero, &mut do_zero, T1 - 1, 1); - // Do data bit = 1 - a.jmp_with_delay_and_side_set(pio::JmpCondition::Always, &mut wrap_target, T2 - 1, 1); - a.bind(&mut do_zero); - // Do data bit = 0 - a.nop_with_delay_and_side_set(T2 - 1, 0); - a.bind(&mut wrap_source); - - let prg = a.assemble_with_wrap(wrap_source, wrap_target); - let mut cfg = Config::default(); - - // Pin config - let out_pin = pio.make_pio_pin(pin); - cfg.set_out_pins(&[&out_pin]); - cfg.set_set_pins(&[&out_pin]); - - cfg.use_program(&pio.load_program(&prg), &[&out_pin]); - - // Clock config, measured in kHz to avoid overflows - // TODO CLOCK_FREQ should come from embassy_rp - let clock_freq = U24F8::from_num(clocks::clk_sys_freq() / 1000); - let ws2812_freq = fixed!(800: U24F8); - let bit_freq = ws2812_freq * CYCLES_PER_BIT; - cfg.clock_divider = clock_freq / bit_freq; - - // FIFO config - cfg.fifo_join = FifoJoin::TxOnly; - cfg.shift_out = ShiftConfig { - auto_fill: true, - threshold: 24, - direction: ShiftDirection::Left, - }; - - sm.set_config(&cfg); - sm.set_enable(true); - - Self { - dma: dma.map_into(), - sm, - } - } - - pub async fn write(&mut self, colors: &[RGB8; N]) { - // Precompute the word bytes from the colors - let mut words = [0u32; N]; - for i in 0..N { - let word = (u32::from(colors[i].g) << 24) | (u32::from(colors[i].r) << 16) | (u32::from(colors[i].b) << 8); - words[i] = word; - } - - // DMA transfer - self.sm.tx().dma_push(self.dma.reborrow(), &words).await; - - Timer::after_micros(55).await; - } -} - /// Input a value 0 to 255 to get a color value /// The colours are a transition r - g - b - back to r. fn wheel(mut wheel_pos: u8) -> RGB8 { @@ -147,7 +53,8 @@ async fn main(_spawner: Spawner) { // Common neopixel pins: // Thing plus: 8 // Adafruit Feather: 16; Adafruit Feather+RFM95: 4 - let mut ws2812 = Ws2812::new(&mut common, sm0, p.DMA_CH0, p.PIN_16); + let program = PioWs2812Program::new(&mut common); + let mut ws2812 = PioWs2812::new(&mut common, sm0, p.DMA_CH0, p.PIN_16, &program); // Loop forever making RGB values and pushing them out to the WS2812. let mut ticker = Ticker::every(Duration::from_millis(10)); From fc978c2ee9dda07b9fe7113e2aa0f2d3fb33fd1b Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Wed, 9 Oct 2024 11:37:15 -0400 Subject: [PATCH 0206/1217] Fix rp23 i2s example, boot_sel isn't supported yet. --- examples/rp23/src/bin/pio_i2s.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/examples/rp23/src/bin/pio_i2s.rs b/examples/rp23/src/bin/pio_i2s.rs index 90491fb45..1fd34357b 100644 --- a/examples/rp23/src/bin/pio_i2s.rs +++ b/examples/rp23/src/bin/pio_i2s.rs @@ -15,6 +15,7 @@ use core::mem; use embassy_executor::Spawner; use embassy_rp::bind_interrupts; use embassy_rp::block::ImageDef; +use embassy_rp::gpio::{Input, Pull}; use embassy_rp::peripherals::PIO0; use embassy_rp::pio::{InterruptHandler, Pio}; use embassy_rp::pio_programs::i2s::{PioI2sOut, PioI2sOutProgram}; @@ -35,7 +36,7 @@ const CHANNELS: u32 = 2; #[embassy_executor::main] async fn main(_spawner: Spawner) { - let mut p = embassy_rp::init(Default::default()); + let p = embassy_rp::init(Default::default()); // Setup pio state machine for i2s output let Pio { mut common, sm0, .. } = Pio::new(p.PIO0, Irqs); @@ -58,6 +59,8 @@ async fn main(_spawner: Spawner) { &program, ); + let fade_input = Input::new(p.PIN_0, Pull::Up); + // create two audio buffers (back and front) which will take turns being // filled with new audio data and being sent to the pio fifo using dma const BUFFER_SIZE: usize = 960; @@ -75,7 +78,7 @@ async fn main(_spawner: Spawner) { let dma_future = i2s.write(front_buffer); // fade in audio when bootsel is pressed - let fade_target = if p.BOOTSEL.is_pressed() { i32::MAX } else { 0 }; + let fade_target = if fade_input.is_low() { i32::MAX } else { 0 }; // fill back buffer with fresh audio samples before awaiting the dma future for s in back_buffer.iter_mut() { From c7f7728eb164edea2f8041d2511a976f9ebc17ca Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Wed, 9 Oct 2024 11:44:58 -0400 Subject: [PATCH 0207/1217] cargo +nightly fmt --- embassy-rp/src/pio_programs/i2s.rs | 14 ++++++-------- embassy-rp/src/pio_programs/pwm.rs | 9 ++++----- embassy-rp/src/pio_programs/rotary_encoder.rs | 3 ++- embassy-rp/src/pio_programs/stepper.rs | 3 ++- embassy-rp/src/pio_programs/uart.rs | 15 +++++++-------- embassy-rp/src/pio_programs/ws2812.rs | 14 +++++++------- 6 files changed, 28 insertions(+), 30 deletions(-) diff --git a/embassy-rp/src/pio_programs/i2s.rs b/embassy-rp/src/pio_programs/i2s.rs index 3c8ef8bb6..e3f1f89d4 100644 --- a/embassy-rp/src/pio_programs/i2s.rs +++ b/embassy-rp/src/pio_programs/i2s.rs @@ -1,15 +1,13 @@ //! Pio backed I2s output -use crate::{ - dma::{AnyChannel, Channel, Transfer}, - into_ref, - pio::{ - Common, Config, Direction, FifoJoin, Instance, LoadedProgram, PioPin, ShiftConfig, ShiftDirection, StateMachine, - }, - Peripheral, PeripheralRef, -}; use fixed::traits::ToFixed; +use crate::dma::{AnyChannel, Channel, Transfer}; +use crate::pio::{ + Common, Config, Direction, FifoJoin, Instance, LoadedProgram, PioPin, ShiftConfig, ShiftDirection, StateMachine, +}; +use crate::{into_ref, Peripheral, PeripheralRef}; + /// This struct represents an i2s output driver program pub struct PioI2sOutProgram<'a, PIO: Instance> { prg: LoadedProgram<'a, PIO>, diff --git a/embassy-rp/src/pio_programs/pwm.rs b/embassy-rp/src/pio_programs/pwm.rs index 5dfd70cc9..8a0f3d5ee 100644 --- a/embassy-rp/src/pio_programs/pwm.rs +++ b/embassy-rp/src/pio_programs/pwm.rs @@ -2,13 +2,12 @@ use core::time::Duration; -use crate::{ - clocks, - gpio::Level, - pio::{Common, Config, Direction, Instance, LoadedProgram, PioPin, StateMachine}, -}; use pio::InstructionOperands; +use crate::clocks; +use crate::gpio::Level; +use crate::pio::{Common, Config, Direction, Instance, LoadedProgram, PioPin, StateMachine}; + fn to_pio_cycles(duration: Duration) -> u32 { (clocks::clk_sys_freq() / 1_000_000) / 3 * duration.as_micros() as u32 // parentheses are required to prevent overflow } diff --git a/embassy-rp/src/pio_programs/rotary_encoder.rs b/embassy-rp/src/pio_programs/rotary_encoder.rs index 323f839bc..86423fd31 100644 --- a/embassy-rp/src/pio_programs/rotary_encoder.rs +++ b/embassy-rp/src/pio_programs/rotary_encoder.rs @@ -1,8 +1,9 @@ //! PIO backed quadrature encoder +use fixed::traits::ToFixed; + use crate::gpio::Pull; use crate::pio::{self, Common, Config, FifoJoin, Instance, LoadedProgram, PioPin, ShiftDirection, StateMachine}; -use fixed::traits::ToFixed; /// This struct represents an Encoder program loaded into pio instruction memory. pub struct PioEncoderProgram<'a, PIO: Instance> { diff --git a/embassy-rp/src/pio_programs/stepper.rs b/embassy-rp/src/pio_programs/stepper.rs index 0ecc4eff0..0d58c754c 100644 --- a/embassy-rp/src/pio_programs/stepper.rs +++ b/embassy-rp/src/pio_programs/stepper.rs @@ -2,11 +2,12 @@ use core::mem::{self, MaybeUninit}; -use crate::pio::{Common, Config, Direction, Instance, Irq, LoadedProgram, PioPin, StateMachine}; use fixed::traits::ToFixed; use fixed::types::extra::U8; use fixed::FixedU32; +use crate::pio::{Common, Config, Direction, Instance, Irq, LoadedProgram, PioPin, StateMachine}; + /// This struct represents a Stepper driver program loaded into pio instruction memory. pub struct PioStepperProgram<'a, PIO: Instance> { prg: LoadedProgram<'a, PIO>, diff --git a/embassy-rp/src/pio_programs/uart.rs b/embassy-rp/src/pio_programs/uart.rs index f4b3b204e..c643f1063 100644 --- a/embassy-rp/src/pio_programs/uart.rs +++ b/embassy-rp/src/pio_programs/uart.rs @@ -1,17 +1,16 @@ //! Pio backed uart drivers -use crate::{ - clocks::clk_sys_freq, - gpio::Level, - pio::{ - Common, Config, Direction as PioDirection, FifoJoin, Instance, LoadedProgram, PioPin, ShiftDirection, - StateMachine, - }, -}; use core::convert::Infallible; + use embedded_io_async::{ErrorType, Read, Write}; use fixed::traits::ToFixed; +use crate::clocks::clk_sys_freq; +use crate::gpio::Level; +use crate::pio::{ + Common, Config, Direction as PioDirection, FifoJoin, Instance, LoadedProgram, PioPin, ShiftDirection, StateMachine, +}; + /// This struct represents a uart tx program loaded into pio instruction memory. pub struct PioUartTxProgram<'a, PIO: Instance> { prg: LoadedProgram<'a, PIO>, diff --git a/embassy-rp/src/pio_programs/ws2812.rs b/embassy-rp/src/pio_programs/ws2812.rs index 3fc7e1017..875f0209f 100644 --- a/embassy-rp/src/pio_programs/ws2812.rs +++ b/embassy-rp/src/pio_programs/ws2812.rs @@ -1,16 +1,16 @@ //! [ws2812](https://www.sparkfun.com/datasheets/LCD/HD44780.pdf) -use crate::{ - clocks::clk_sys_freq, - dma::{AnyChannel, Channel}, - into_ref, - pio::{Common, Config, FifoJoin, Instance, LoadedProgram, PioPin, ShiftConfig, ShiftDirection, StateMachine}, - Peripheral, PeripheralRef, -}; use embassy_time::Timer; use fixed::types::U24F8; use smart_leds::RGB8; +use crate::clocks::clk_sys_freq; +use crate::dma::{AnyChannel, Channel}; +use crate::pio::{ + Common, Config, FifoJoin, Instance, LoadedProgram, PioPin, ShiftConfig, ShiftDirection, StateMachine, +}; +use crate::{into_ref, Peripheral, PeripheralRef}; + const T1: u8 = 2; // start bit const T2: u8 = 5; // data bit const T3: u8 = 3; // stop bit From e47c031b671555f3fffe6b128cbb9d3f8bfec534 Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Wed, 9 Oct 2024 11:47:04 -0400 Subject: [PATCH 0208/1217] fmt examples too --- examples/rp/src/bin/pio_rotary_encoder.rs | 8 +++----- examples/rp/src/bin/pio_uart.rs | 3 +-- examples/rp23/src/bin/pio_rotary_encoder.rs | 8 +++----- examples/rp23/src/bin/pio_uart.rs | 3 +-- 4 files changed, 8 insertions(+), 14 deletions(-) diff --git a/examples/rp/src/bin/pio_rotary_encoder.rs b/examples/rp/src/bin/pio_rotary_encoder.rs index a7ecc8d0e..2750f61ae 100644 --- a/examples/rp/src/bin/pio_rotary_encoder.rs +++ b/examples/rp/src/bin/pio_rotary_encoder.rs @@ -5,12 +5,10 @@ use defmt::info; use embassy_executor::Spawner; +use embassy_rp::bind_interrupts; use embassy_rp::peripherals::PIO0; -use embassy_rp::{ - bind_interrupts, - pio::{InterruptHandler, Pio}, - pio_programs::rotary_encoder::{Direction, PioEncoder, PioEncoderProgram}, -}; +use embassy_rp::pio::{InterruptHandler, Pio}; +use embassy_rp::pio_programs::rotary_encoder::{Direction, PioEncoder, PioEncoderProgram}; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { diff --git a/examples/rp/src/bin/pio_uart.rs b/examples/rp/src/bin/pio_uart.rs index b9e01b0ac..aaf2a524f 100644 --- a/examples/rp/src/bin/pio_uart.rs +++ b/examples/rp/src/bin/pio_uart.rs @@ -13,11 +13,10 @@ use defmt::{info, panic, trace}; use embassy_executor::Spawner; use embassy_futures::join::{join, join3}; -use embassy_rp::bind_interrupts; use embassy_rp::peripherals::{PIO0, USB}; -use embassy_rp::pio; use embassy_rp::pio_programs::uart::{PioUartRx, PioUartRxProgram, PioUartTx, PioUartTxProgram}; use embassy_rp::usb::{Driver, Instance, InterruptHandler}; +use embassy_rp::{bind_interrupts, pio}; use embassy_sync::blocking_mutex::raw::NoopRawMutex; use embassy_sync::pipe::Pipe; use embassy_usb::class::cdc_acm::{CdcAcmClass, Receiver, Sender, State}; diff --git a/examples/rp23/src/bin/pio_rotary_encoder.rs b/examples/rp23/src/bin/pio_rotary_encoder.rs index 9a953951f..2bb0e67f9 100644 --- a/examples/rp23/src/bin/pio_rotary_encoder.rs +++ b/examples/rp23/src/bin/pio_rotary_encoder.rs @@ -5,13 +5,11 @@ use defmt::info; use embassy_executor::Spawner; +use embassy_rp::bind_interrupts; use embassy_rp::block::ImageDef; use embassy_rp::peripherals::PIO0; -use embassy_rp::{ - bind_interrupts, - pio::{InterruptHandler, Pio}, - pio_programs::rotary_encoder::{Direction, PioEncoder, PioEncoderProgram}, -}; +use embassy_rp::pio::{InterruptHandler, Pio}; +use embassy_rp::pio_programs::rotary_encoder::{Direction, PioEncoder, PioEncoderProgram}; use {defmt_rtt as _, panic_probe as _}; #[link_section = ".start_block"] diff --git a/examples/rp23/src/bin/pio_uart.rs b/examples/rp23/src/bin/pio_uart.rs index 6899a5d7c..f8398c22a 100644 --- a/examples/rp23/src/bin/pio_uart.rs +++ b/examples/rp23/src/bin/pio_uart.rs @@ -13,12 +13,11 @@ use defmt::{info, panic, trace}; use embassy_executor::Spawner; use embassy_futures::join::{join, join3}; -use embassy_rp::bind_interrupts; use embassy_rp::block::ImageDef; use embassy_rp::peripherals::{PIO0, USB}; -use embassy_rp::pio; use embassy_rp::pio_programs::uart::{PioUartRx, PioUartRxProgram, PioUartTx, PioUartTxProgram}; use embassy_rp::usb::{Driver, Instance, InterruptHandler}; +use embassy_rp::{bind_interrupts, pio}; use embassy_sync::blocking_mutex::raw::NoopRawMutex; use embassy_sync::pipe::Pipe; use embassy_usb::class::cdc_acm::{CdcAcmClass, Receiver, Sender, State}; From 22fe4932577cf261a561e33c2a8378c168fab1dd Mon Sep 17 00:00:00 2001 From: Bjorn <75190918+BjornTheProgrammer@users.noreply.github.com> Date: Wed, 9 Oct 2024 10:12:43 -0700 Subject: [PATCH 0209/1217] Better docs and adding of release for PioPwm --- embassy-rp/src/pio_programs/pwm.rs | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/embassy-rp/src/pio_programs/pwm.rs b/embassy-rp/src/pio_programs/pwm.rs index 8a0f3d5ee..7b3157877 100644 --- a/embassy-rp/src/pio_programs/pwm.rs +++ b/embassy-rp/src/pio_programs/pwm.rs @@ -1,6 +1,7 @@ //! PIO backed PWM driver use core::time::Duration; +use crate::pio::Pin; use pio::InstructionOperands; @@ -8,6 +9,7 @@ use crate::clocks; use crate::gpio::Level; use crate::pio::{Common, Config, Direction, Instance, LoadedProgram, PioPin, StateMachine}; +/// This converts the duration provided into the number of cycles the PIO needs to run to make it take the same time fn to_pio_cycles(duration: Duration) -> u32 { (clocks::clk_sys_freq() / 1_000_000) / 3 * duration.as_micros() as u32 // parentheses are required to prevent overflow } @@ -43,6 +45,7 @@ impl<'a, PIO: Instance> PioPwmProgram<'a, PIO> { /// Pio backed PWM output pub struct PioPwm<'d, T: Instance, const SM: usize> { sm: StateMachine<'d, T, SM>, + pin: Pin<'d, T> } impl<'d, T: Instance, const SM: usize> PioPwm<'d, T, SM> { @@ -62,20 +65,20 @@ impl<'d, T: Instance, const SM: usize> PioPwm<'d, T, SM> { sm.set_config(&cfg); - Self { sm } + Self { sm, pin } } - /// Enable PWM output + /// Enable's the PIO program, continuing the wave generation from the PIO program. pub fn start(&mut self) { self.sm.set_enable(true); } - /// Disable PWM output + /// Stops the PIO program, ceasing all signals from the PIN that were generated via PIO. pub fn stop(&mut self) { self.sm.set_enable(false); } - /// Set pwm period + /// Sets the pwm period, which is the length of time for each pio wave until reset. pub fn set_period(&mut self, duration: Duration) { let is_enabled = self.sm.is_enabled(); while !self.sm.tx().empty() {} // Make sure that the queue is empty @@ -102,7 +105,8 @@ impl<'d, T: Instance, const SM: usize> PioPwm<'d, T, SM> { } } - fn set_level(&mut self, level: u32) { + /// Set the number of pio cycles to set the wave on high to. + pub fn set_level(&mut self, level: u32) { self.sm.tx().push(level); } @@ -110,4 +114,9 @@ impl<'d, T: Instance, const SM: usize> PioPwm<'d, T, SM> { pub fn write(&mut self, duration: Duration) { self.set_level(to_pio_cycles(duration)); } + + // Return the state machine and pin. + pub fn release(self) -> (StateMachine<'d, T, SM>, Pin<'d, T>) { + (self.sm, self.pin) + } } From 1b32b7bcb44a9df149bb9194cb83e6c1f370db12 Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Wed, 9 Oct 2024 16:51:52 -0400 Subject: [PATCH 0210/1217] fmt --- embassy-rp/src/pio_programs/pwm.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/embassy-rp/src/pio_programs/pwm.rs b/embassy-rp/src/pio_programs/pwm.rs index 7b3157877..dfc5feb19 100644 --- a/embassy-rp/src/pio_programs/pwm.rs +++ b/embassy-rp/src/pio_programs/pwm.rs @@ -1,13 +1,12 @@ //! PIO backed PWM driver use core::time::Duration; -use crate::pio::Pin; use pio::InstructionOperands; use crate::clocks; use crate::gpio::Level; -use crate::pio::{Common, Config, Direction, Instance, LoadedProgram, PioPin, StateMachine}; +use crate::pio::{Common, Config, Direction, Instance, LoadedProgram, Pin, PioPin, StateMachine}; /// This converts the duration provided into the number of cycles the PIO needs to run to make it take the same time fn to_pio_cycles(duration: Duration) -> u32 { @@ -45,7 +44,7 @@ impl<'a, PIO: Instance> PioPwmProgram<'a, PIO> { /// Pio backed PWM output pub struct PioPwm<'d, T: Instance, const SM: usize> { sm: StateMachine<'d, T, SM>, - pin: Pin<'d, T> + pin: Pin<'d, T>, } impl<'d, T: Instance, const SM: usize> PioPwm<'d, T, SM> { From 70bd158d03afa92edb0ce23d05860bde1651cf61 Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Wed, 9 Oct 2024 16:57:02 -0400 Subject: [PATCH 0211/1217] Make the docs be docs --- embassy-rp/src/pio_programs/pwm.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-rp/src/pio_programs/pwm.rs b/embassy-rp/src/pio_programs/pwm.rs index dfc5feb19..c6502387a 100644 --- a/embassy-rp/src/pio_programs/pwm.rs +++ b/embassy-rp/src/pio_programs/pwm.rs @@ -114,7 +114,7 @@ impl<'d, T: Instance, const SM: usize> PioPwm<'d, T, SM> { self.set_level(to_pio_cycles(duration)); } - // Return the state machine and pin. + /// Return the state machine and pin. pub fn release(self) -> (StateMachine<'d, T, SM>, Pin<'d, T>) { (self.sm, self.pin) } From 3870411a4a4546f814140b178609a86d5209d734 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabian=20Vi=C3=B6l?= Date: Thu, 10 Oct 2024 16:12:51 +0200 Subject: [PATCH 0212/1217] stm32/i2c: disable pullup instead of pulldown --- embassy-stm32/src/i2c/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/i2c/mod.rs b/embassy-stm32/src/i2c/mod.rs index 739e960b9..1fc91f1ef 100644 --- a/embassy-stm32/src/i2c/mod.rs +++ b/embassy-stm32/src/i2c/mod.rs @@ -88,7 +88,7 @@ impl Config { Speed::Medium, match self.scl_pullup { true => Pull::Up, - false => Pull::Down, + false => Pull::None, }, ); } @@ -102,7 +102,7 @@ impl Config { Speed::Medium, match self.sda_pullup { true => Pull::Up, - false => Pull::Down, + false => Pull::None, }, ); } From 350a15a0cd72dc1d8ef65d2c398f279d571f5193 Mon Sep 17 00:00:00 2001 From: Joost Buijgers Date: Fri, 11 Oct 2024 12:18:04 +0200 Subject: [PATCH 0213/1217] make bluetooth module public --- cyw43/src/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cyw43/src/lib.rs b/cyw43/src/lib.rs index 6b71c18e6..3cd0e4988 100644 --- a/cyw43/src/lib.rs +++ b/cyw43/src/lib.rs @@ -9,7 +9,8 @@ pub(crate) mod fmt; #[cfg(feature = "bluetooth")] -mod bluetooth; +/// Bluetooth module. +pub mod bluetooth; mod bus; mod consts; mod control; From 0bf99820f3e5efaba821652fe33e99ed621ece7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beat=20K=C3=BCng?= Date: Sat, 12 Oct 2024 10:35:43 +0200 Subject: [PATCH 0214/1217] stm32: add RX Pull configuration option to USART --- embassy-stm32/src/usart/buffered.rs | 4 ++-- embassy-stm32/src/usart/mod.rs | 18 +++++++++++------- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs index 86f56eb7c..4fbe33b2e 100644 --- a/embassy-stm32/src/usart/buffered.rs +++ b/embassy-stm32/src/usart/buffered.rs @@ -210,7 +210,7 @@ impl<'d> BufferedUart<'d> { ) -> Result { Self::new_inner( peri, - new_pin!(rx, AfType::input(Pull::None)), + new_pin!(rx, AfType::input(config.rx_pull)), new_pin!(tx, AfType::output(OutputType::PushPull, Speed::Medium)), None, None, @@ -260,7 +260,7 @@ impl<'d> BufferedUart<'d> { ) -> Result { Self::new_inner( peri, - new_pin!(rx, AfType::input(Pull::None)), + new_pin!(rx, AfType::input(config.rx_pull)), new_pin!(tx, AfType::output(OutputType::PushPull, Speed::Medium)), None, None, diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index e7f2f890a..5c96e202d 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -167,6 +167,9 @@ pub struct Config { #[cfg(any(usart_v3, usart_v4))] pub invert_rx: bool, + /// Set the pull configuration for the RX pin. + pub rx_pull: Pull, + // private: set by new_half_duplex, not by the user. half_duplex: bool, } @@ -175,7 +178,7 @@ impl Config { fn tx_af(&self) -> AfType { #[cfg(any(usart_v3, usart_v4))] if self.swap_rx_tx { - return AfType::input(Pull::None); + return AfType::input(self.rx_pull); }; AfType::output(OutputType::PushPull, Speed::Medium) } @@ -185,7 +188,7 @@ impl Config { if self.swap_rx_tx { return AfType::output(OutputType::PushPull, Speed::Medium); }; - AfType::input(Pull::None) + AfType::input(self.rx_pull) } } @@ -206,6 +209,7 @@ impl Default for Config { invert_tx: false, #[cfg(any(usart_v3, usart_v4))] invert_rx: false, + rx_pull: Pull::None, half_duplex: false, } } @@ -448,7 +452,7 @@ impl<'d> UartTx<'d, Blocking> { Self::new_inner( peri, new_pin!(tx, AfType::output(OutputType::PushPull, Speed::Medium)), - new_pin!(cts, AfType::input(Pull::None)), + new_pin!(cts, AfType::input(config.rx_pull)), None, config, ) @@ -567,7 +571,7 @@ impl<'d> UartRx<'d, Async> { ) -> Result { Self::new_inner( peri, - new_pin!(rx, AfType::input(Pull::None)), + new_pin!(rx, AfType::input(config.rx_pull)), None, new_dma!(rx_dma), config, @@ -585,7 +589,7 @@ impl<'d> UartRx<'d, Async> { ) -> Result { Self::new_inner( peri, - new_pin!(rx, AfType::input(Pull::None)), + new_pin!(rx, AfType::input(config.rx_pull)), new_pin!(rts, AfType::output(OutputType::PushPull, Speed::Medium)), new_dma!(rx_dma), config, @@ -815,7 +819,7 @@ impl<'d> UartRx<'d, Blocking> { rx: impl Peripheral

> + 'd, config: Config, ) -> Result { - Self::new_inner(peri, new_pin!(rx, AfType::input(Pull::None)), None, None, config) + Self::new_inner(peri, new_pin!(rx, AfType::input(config.rx_pull)), None, None, config) } /// Create a new rx-only UART with a request-to-send pin @@ -827,7 +831,7 @@ impl<'d> UartRx<'d, Blocking> { ) -> Result { Self::new_inner( peri, - new_pin!(rx, AfType::input(Pull::None)), + new_pin!(rx, AfType::input(config.rx_pull)), new_pin!(rts, AfType::output(OutputType::PushPull, Speed::Medium)), None, config, From cdcd9de05143827c0c138359e0b43887d64cf98f Mon Sep 17 00:00:00 2001 From: Keisuke Tottori Date: Fri, 27 Sep 2024 17:19:35 +0900 Subject: [PATCH 0215/1217] Enable FPU for RP235X Core1 --- embassy-rp/src/multicore.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/embassy-rp/src/multicore.rs b/embassy-rp/src/multicore.rs index 9f7d77bf5..7e2e776ea 100644 --- a/embassy-rp/src/multicore.rs +++ b/embassy-rp/src/multicore.rs @@ -169,6 +169,13 @@ where interrupt::SIO_IRQ_FIFO.enable() }; + // Enable FPU + #[cfg(feature = "_rp235x")] + unsafe { + let p = cortex_m::Peripherals::steal(); + p.SCB.cpacr.modify(|cpacr| cpacr | (3 << 20) | (3 << 22)); + } + entry() } From 0222faa8a1f3afbc60eb455989fc581ec9adfac1 Mon Sep 17 00:00:00 2001 From: HaoboGu Date: Mon, 14 Oct 2024 04:32:22 +0800 Subject: [PATCH 0216/1217] Add octospim support for octospi (#3102) * feat: add octospim to ospi Signed-off-by: Haobo Gu * feat: make octospim behind feature gate Signed-off-by: Haobo Gu * refactor: fix fmt issue Signed-off-by: Haobo Gu * refactor: fix ci failure Signed-off-by: Haobo Gu * feat: add octospim reg writing code Signed-off-by: Haobo Gu * feat(octospi): enable rcc for octospim at the initialization Signed-off-by: Haobo Gu * fix: add octospim feature gate Signed-off-by: Haobo Gu * fix: fix cfg flag Signed-off-by: Haobo Gu * fix: fix rcc register on stm32l4 and stm32u5 Signed-off-by: Haobo Gu * feat(ospi): support OCTOSPI2 in build.rs Signed-off-by: Haobo Gu * feat(ospi): add OCTOSPI2 pin impls Signed-off-by: HaoboGu * feat(ospi): support both ospi instances in stm32 OCTOSPIM Signed-off-by: Haobo Gu --------- Signed-off-by: Haobo Gu Signed-off-by: HaoboGu --- embassy-stm32/build.rs | 33 ++++++++++ embassy-stm32/src/ospi/mod.rs | 118 ++++++++++++++++++++++++++++++++++ 2 files changed, 151 insertions(+) diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 28c619c6b..966dce121 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -1054,6 +1054,30 @@ fn main() { (("octospi", "NCS"), quote!(crate::ospi::NSSPin)), (("octospi", "CLK"), quote!(crate::ospi::SckPin)), (("octospi", "NCLK"), quote!(crate::ospi::NckPin)), + (("octospim", "P1_IO0"), quote!(crate::ospi::D0Pin)), + (("octospim", "P1_IO1"), quote!(crate::ospi::D1Pin)), + (("octospim", "P1_IO2"), quote!(crate::ospi::D2Pin)), + (("octospim", "P1_IO3"), quote!(crate::ospi::D3Pin)), + (("octospim", "P1_IO4"), quote!(crate::ospi::D4Pin)), + (("octospim", "P1_IO5"), quote!(crate::ospi::D5Pin)), + (("octospim", "P1_IO6"), quote!(crate::ospi::D6Pin)), + (("octospim", "P1_IO7"), quote!(crate::ospi::D7Pin)), + (("octospim", "P1_DQS"), quote!(crate::ospi::DQSPin)), + (("octospim", "P1_NCS"), quote!(crate::ospi::NSSPin)), + (("octospim", "P1_CLK"), quote!(crate::ospi::SckPin)), + (("octospim", "P1_NCLK"), quote!(crate::ospi::NckPin)), + (("octospim", "P2_IO0"), quote!(crate::ospi::D0Pin)), + (("octospim", "P2_IO1"), quote!(crate::ospi::D1Pin)), + (("octospim", "P2_IO2"), quote!(crate::ospi::D2Pin)), + (("octospim", "P2_IO3"), quote!(crate::ospi::D3Pin)), + (("octospim", "P2_IO4"), quote!(crate::ospi::D4Pin)), + (("octospim", "P2_IO5"), quote!(crate::ospi::D5Pin)), + (("octospim", "P2_IO6"), quote!(crate::ospi::D6Pin)), + (("octospim", "P2_IO7"), quote!(crate::ospi::D7Pin)), + (("octospim", "P2_DQS"), quote!(crate::ospi::DQSPin)), + (("octospim", "P2_NCS"), quote!(crate::ospi::NSSPin)), + (("octospim", "P2_CLK"), quote!(crate::ospi::SckPin)), + (("octospim", "P2_NCLK"), quote!(crate::ospi::NckPin)), (("tsc", "G1_IO1"), quote!(crate::tsc::G1IO1Pin)), (("tsc", "G1_IO2"), quote!(crate::tsc::G1IO2Pin)), (("tsc", "G1_IO3"), quote!(crate::tsc::G1IO3Pin)), @@ -1111,6 +1135,15 @@ fn main() { peri = format_ident!("{}", pin.signal.replace('_', "")); } + // OCTOSPIM is special + if p.name == "OCTOSPIM" { + peri = format_ident!("{}", "OCTOSPI1"); + g.extend(quote! { + pin_trait_impl!(#tr, #peri, #pin_name, #af); + }); + peri = format_ident!("{}", "OCTOSPI2"); + } + g.extend(quote! { pin_trait_impl!(#tr, #peri, #pin_name, #af); }) diff --git a/embassy-stm32/src/ospi/mod.rs b/embassy-stm32/src/ospi/mod.rs index 289bfa672..48a1ea5e6 100644 --- a/embassy-stm32/src/ospi/mod.rs +++ b/embassy-stm32/src/ospi/mod.rs @@ -16,6 +16,8 @@ use crate::dma::{word, ChannelAndRequest}; use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed}; use crate::mode::{Async, Blocking, Mode as PeriMode}; use crate::pac::octospi::{vals, Octospi as Regs}; +#[cfg(octospim_v1)] +use crate::pac::octospim::Octospim; use crate::rcc::{self, RccPeripheral}; use crate::{peripherals, Peripheral}; @@ -197,6 +199,83 @@ impl<'d, T: Instance, M: PeriMode> Ospi<'d, T, M> { ) -> Self { into_ref!(peri); + #[cfg(octospim_v1)] + { + // RCC for octospim should be enabled before writing register + #[cfg(stm32l4)] + crate::pac::RCC.ahb2smenr().modify(|w| w.set_octospimsmen(true)); + #[cfg(stm32u5)] + crate::pac::RCC.ahb2enr1().modify(|w| w.set_octospimen(true)); + #[cfg(not(any(stm32l4, stm32u5)))] + crate::pac::RCC.ahb3enr().modify(|w| w.set_iomngren(true)); + + // Disable OctoSPI peripheral first + T::REGS.cr().modify(|w| { + w.set_en(false); + }); + + // OctoSPI IO Manager has been enabled before + T::OCTOSPIM_REGS.cr().modify(|w| { + w.set_muxen(false); + w.set_req2ack_time(0xff); + }); + + // Clear config + T::OCTOSPIM_REGS.p1cr().modify(|w| { + w.set_clksrc(false); + w.set_dqssrc(false); + w.set_ncssrc(false); + w.set_clken(false); + w.set_dqsen(false); + w.set_ncsen(false); + w.set_iolsrc(0); + w.set_iohsrc(0); + }); + + T::OCTOSPIM_REGS.p1cr().modify(|w| { + let octospi_src = if T::OCTOSPI_IDX == 1 { false } else { true }; + w.set_ncsen(true); + w.set_ncssrc(octospi_src); + w.set_clken(true); + w.set_clksrc(octospi_src); + if dqs.is_some() { + w.set_dqsen(true); + w.set_dqssrc(octospi_src); + } + + // Set OCTOSPIM IOL and IOH according to the index of OCTOSPI instance + if T::OCTOSPI_IDX == 1 { + w.set_iolen(true); + w.set_iolsrc(0); + // Enable IOH in octo and dual quad mode + if let OspiWidth::OCTO = width { + w.set_iohen(true); + w.set_iohsrc(0b01); + } else if dual_quad { + w.set_iohen(true); + w.set_iohsrc(0b00); + } else { + w.set_iohen(false); + w.set_iohsrc(0b00); + } + } else { + w.set_iolen(true); + w.set_iolsrc(0b10); + // Enable IOH in octo and dual quad mode + if let OspiWidth::OCTO = width { + w.set_iohen(true); + w.set_iohsrc(0b11); + } else if dual_quad { + w.set_iohen(true); + w.set_iohsrc(0b10); + } else { + w.set_iohen(false); + w.set_iohsrc(0b00); + } + } + }); + } + // System configuration rcc::enable_and_reset::(); while T::REGS.sr().read().busy() {} @@ -1056,11 +1135,25 @@ fn finish_dma(regs: Regs) { }); } +#[cfg(octospim_v1)] +/// OctoSPI I/O manager instance trait. +pub(crate) trait SealedOctospimInstance { + const OCTOSPIM_REGS: Octospim; + const OCTOSPI_IDX: u8; +} + +/// OctoSPI instance trait. pub(crate) trait SealedInstance { const REGS: Regs; } /// OSPI instance trait. +#[cfg(octospim_v1)] +#[allow(private_bounds)] +pub trait Instance: Peripheral

+ SealedInstance + RccPeripheral + SealedOctospimInstance {} + +/// OSPI instance trait. +#[cfg(not(octospim_v1))] #[allow(private_bounds)] pub trait Instance: Peripheral

+ SealedInstance + RccPeripheral {} @@ -1078,6 +1171,31 @@ pin_trait!(DQSPin, Instance); pin_trait!(NSSPin, Instance); dma_trait!(OctoDma, Instance); +// Hard-coded the octospi index, for OCTOSPIM +#[cfg(octospim_v1)] +impl SealedOctospimInstance for peripherals::OCTOSPI1 { + const OCTOSPIM_REGS: Octospim = crate::pac::OCTOSPIM; + const OCTOSPI_IDX: u8 = 1; +} + +#[cfg(octospim_v1)] +impl SealedOctospimInstance for peripherals::OCTOSPI2 { + const OCTOSPIM_REGS: Octospim = crate::pac::OCTOSPIM; + const OCTOSPI_IDX: u8 = 2; +} + +#[cfg(octospim_v1)] +foreach_peripheral!( + (octospi, $inst:ident) => { + impl SealedInstance for peripherals::$inst { + const REGS: Regs = crate::pac::$inst; + } + + impl Instance for peripherals::$inst {} + }; +); + +#[cfg(not(octospim_v1))] foreach_peripheral!( (octospi, $inst:ident) => { impl SealedInstance for peripherals::$inst { From a4636d819f4b98a781cc88a05c2e89397c71e1ed Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sun, 13 Oct 2024 21:47:40 +0200 Subject: [PATCH 0217/1217] rp/multicore: enable fpu on second core only if building for -eabihf targets. --- embassy-rp/build.rs | 22 +++++++++++++++++++++- embassy-rp/src/multicore.rs | 2 +- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/embassy-rp/build.rs b/embassy-rp/build.rs index 3216a3826..a8d387611 100644 --- a/embassy-rp/build.rs +++ b/embassy-rp/build.rs @@ -1,7 +1,8 @@ use std::env; +use std::ffi::OsStr; use std::fs::File; use std::io::Write; -use std::path::PathBuf; +use std::path::{Path, PathBuf}; fn main() { if env::var("CARGO_FEATURE_RP2040").is_ok() { @@ -16,4 +17,23 @@ fn main() { println!("cargo:rerun-if-changed=build.rs"); println!("cargo:rerun-if-changed=link-rp.x.in"); } + + // code below taken from https://github.com/rust-embedded/cortex-m/blob/master/cortex-m-rt/build.rs + + let mut target = env::var("TARGET").unwrap(); + + // When using a custom target JSON, `$TARGET` contains the path to that JSON file. By + // convention, these files are named after the actual target triple, eg. + // `thumbv7m-customos-elf.json`, so we extract the file stem here to allow custom target specs. + let path = Path::new(&target); + if path.extension() == Some(OsStr::new("json")) { + target = path + .file_stem() + .map_or(target.clone(), |stem| stem.to_str().unwrap().to_string()); + } + + println!("cargo::rustc-check-cfg=cfg(has_fpu)"); + if target.ends_with("-eabihf") { + println!("cargo:rustc-cfg=has_fpu"); + } } diff --git a/embassy-rp/src/multicore.rs b/embassy-rp/src/multicore.rs index 7e2e776ea..81de84907 100644 --- a/embassy-rp/src/multicore.rs +++ b/embassy-rp/src/multicore.rs @@ -170,7 +170,7 @@ where }; // Enable FPU - #[cfg(feature = "_rp235x")] + #[cfg(all(feature = "_rp235x", has_fpu))] unsafe { let p = cortex_m::Peripherals::steal(); p.SCB.cpacr.modify(|cpacr| cpacr | (3 << 20) | (3 << 22)); From ee669ee5c57851ade034beca7cfaf81825c4c21b Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 14 Oct 2024 00:01:49 +0200 Subject: [PATCH 0218/1217] Update nighlty, fix warnings. Fixes #2599 --- embassy-rp/src/lib.rs | 6 +++--- embassy-rp/src/multicore.rs | 4 ++-- embassy-stm32-wpan/src/lib.rs | 1 + embassy-stm32-wpan/src/mac/commands.rs | 2 +- embassy-stm32/src/low_power.rs | 3 +++ embassy-stm32/src/rcc/mod.rs | 10 +++++++--- examples/stm32h7/src/bin/sai.rs | 10 ++++++---- examples/stm32h7/src/bin/spi_bdma.rs | 7 ++++--- rust-toolchain-nightly.toml | 2 +- tests/nrf/src/bin/buffered_uart_spam.rs | 2 +- tests/stm32/src/bin/usart_rx_ringbuffered.rs | 3 +-- 11 files changed, 30 insertions(+), 20 deletions(-) diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs index 7ac18c1f8..f56cfba27 100644 --- a/embassy-rp/src/lib.rs +++ b/embassy-rp/src/lib.rs @@ -480,7 +480,7 @@ pub fn install_core0_stack_guard() -> Result<(), ()> { #[cfg(all(feature = "rp2040", not(feature = "_test")))] #[inline(always)] -fn install_stack_guard(stack_bottom: *mut usize) -> Result<(), ()> { +unsafe fn install_stack_guard(stack_bottom: *mut usize) -> Result<(), ()> { let core = unsafe { cortex_m::Peripherals::steal() }; // Fail if MPU is already configured @@ -508,7 +508,7 @@ fn install_stack_guard(stack_bottom: *mut usize) -> Result<(), ()> { #[cfg(all(feature = "_rp235x", not(feature = "_test")))] #[inline(always)] -fn install_stack_guard(stack_bottom: *mut usize) -> Result<(), ()> { +unsafe fn install_stack_guard(stack_bottom: *mut usize) -> Result<(), ()> { let core = unsafe { cortex_m::Peripherals::steal() }; // Fail if MPU is already configured @@ -528,7 +528,7 @@ fn install_stack_guard(stack_bottom: *mut usize) -> Result<(), ()> { // so the compile fails when we try to use ARMv8 peripherals. #[cfg(feature = "_test")] #[inline(always)] -fn install_stack_guard(_stack_bottom: *mut usize) -> Result<(), ()> { +unsafe fn install_stack_guard(_stack_bottom: *mut usize) -> Result<(), ()> { Ok(()) } diff --git a/embassy-rp/src/multicore.rs b/embassy-rp/src/multicore.rs index 81de84907..ea0a29a36 100644 --- a/embassy-rp/src/multicore.rs +++ b/embassy-rp/src/multicore.rs @@ -58,7 +58,7 @@ const RESUME_TOKEN: u32 = !0xDEADBEEF; static IS_CORE1_INIT: AtomicBool = AtomicBool::new(false); #[inline(always)] -fn core1_setup(stack_bottom: *mut usize) { +unsafe fn core1_setup(stack_bottom: *mut usize) { if install_stack_guard(stack_bottom).is_err() { // currently only happens if the MPU was already set up, which // would indicate that the core is already in use from outside @@ -148,7 +148,7 @@ where entry: *mut ManuallyDrop, stack_bottom: *mut usize, ) -> ! { - core1_setup(stack_bottom); + unsafe { core1_setup(stack_bottom) }; let entry = unsafe { ManuallyDrop::take(&mut *entry) }; diff --git a/embassy-stm32-wpan/src/lib.rs b/embassy-stm32-wpan/src/lib.rs index f9560d235..fb34d4ba0 100644 --- a/embassy-stm32-wpan/src/lib.rs +++ b/embassy-stm32-wpan/src/lib.rs @@ -2,6 +2,7 @@ #![allow(async_fn_in_trait)] #![doc = include_str!("../README.md")] // #![warn(missing_docs)] +#![allow(static_mut_refs)] // TODO: Fix // This must go FIRST so that all the other modules see its macros. mod fmt; diff --git a/embassy-stm32-wpan/src/mac/commands.rs b/embassy-stm32-wpan/src/mac/commands.rs index c97c609c3..82b9d2772 100644 --- a/embassy-stm32-wpan/src/mac/commands.rs +++ b/embassy-stm32-wpan/src/mac/commands.rs @@ -371,7 +371,7 @@ pub struct DataRequest { } impl DataRequest { - pub fn set_buffer<'a>(&'a mut self, buf: &'a [u8]) -> &mut Self { + pub fn set_buffer<'a>(&'a mut self, buf: &'a [u8]) -> &'a mut Self { self.msdu_ptr = buf as *const _ as *const u8; self.msdu_length = buf.len() as u8; diff --git a/embassy-stm32/src/low_power.rs b/embassy-stm32/src/low_power.rs index f3e4c6994..2be1a42b7 100644 --- a/embassy-stm32/src/low_power.rs +++ b/embassy-stm32/src/low_power.rs @@ -51,6 +51,9 @@ //! } //! ``` +// TODO: Usage of `static mut` here is unsound. Fix then remove this `allow`.` +#![allow(static_mut_refs)] + use core::arch::asm; use core::marker::PhantomData; use core::sync::atomic::{compiler_fence, Ordering}; diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index 8022a35a4..4f43d3748 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs @@ -86,7 +86,7 @@ pub(crate) unsafe fn set_freqs(freqs: Clocks) { #[cfg(not(feature = "_dual-core"))] /// Safety: Reads a mutable global. pub(crate) unsafe fn get_freqs() -> &'static Clocks { - CLOCK_FREQS.assume_init_ref() + (*core::ptr::addr_of_mut!(CLOCK_FREQS)).assume_init_ref() } #[cfg(feature = "_dual-core")] @@ -171,7 +171,9 @@ impl RccInfo { // Use .get_mut instead of []-operator so that we control how bounds checks happen. // Otherwise, core::fmt will be pulled in here in order to format the integer in the // out-of-bounds error. - if let Some(refcount) = unsafe { crate::_generated::REFCOUNTS.get_mut(refcount_idx) } { + if let Some(refcount) = + unsafe { (*core::ptr::addr_of_mut!(crate::_generated::REFCOUNTS)).get_mut(refcount_idx) } + { *refcount += 1; if *refcount > 1 { return; @@ -235,7 +237,9 @@ impl RccInfo { // Use .get_mut instead of []-operator so that we control how bounds checks happen. // Otherwise, core::fmt will be pulled in here in order to format the integer in the // out-of-bounds error. - if let Some(refcount) = unsafe { crate::_generated::REFCOUNTS.get_mut(refcount_idx) } { + if let Some(refcount) = + unsafe { (*core::ptr::addr_of_mut!(crate::_generated::REFCOUNTS)).get_mut(refcount_idx) } + { *refcount -= 1; if *refcount > 0 { return; diff --git a/examples/stm32h7/src/bin/sai.rs b/examples/stm32h7/src/bin/sai.rs index f6735e235..04d14bd6b 100644 --- a/examples/stm32h7/src/bin/sai.rs +++ b/examples/stm32h7/src/bin/sai.rs @@ -81,8 +81,9 @@ async fn main(_spawner: Spawner) { rx_config.sync_output = false; let tx_buffer: &mut [u32] = unsafe { - TX_BUFFER.initialize_all_copied(0); - let (ptr, len) = TX_BUFFER.get_ptr_len(); + let buf = &mut *core::ptr::addr_of_mut!(TX_BUFFER); + buf.initialize_all_copied(0); + let (ptr, len) = buf.get_ptr_len(); core::slice::from_raw_parts_mut(ptr, len) }; @@ -98,8 +99,9 @@ async fn main(_spawner: Spawner) { ); let rx_buffer: &mut [u32] = unsafe { - RX_BUFFER.initialize_all_copied(0); - let (ptr, len) = RX_BUFFER.get_ptr_len(); + let buf = &mut *core::ptr::addr_of_mut!(RX_BUFFER); + buf.initialize_all_copied(0); + let (ptr, len) = buf.get_ptr_len(); core::slice::from_raw_parts_mut(ptr, len) }; diff --git a/examples/stm32h7/src/bin/spi_bdma.rs b/examples/stm32h7/src/bin/spi_bdma.rs index 43fb6b41c..9166fe9b6 100644 --- a/examples/stm32h7/src/bin/spi_bdma.rs +++ b/examples/stm32h7/src/bin/spi_bdma.rs @@ -22,10 +22,11 @@ static mut RAM_D3: GroundedArrayCell = GroundedArrayCell::uninit(); #[embassy_executor::task] async fn main_task(mut spi: spi::Spi<'static, Async>) { let (read_buffer, write_buffer) = unsafe { - RAM_D3.initialize_all_copied(0); + let ram = &mut *core::ptr::addr_of_mut!(RAM_D3); + ram.initialize_all_copied(0); ( - RAM_D3.get_subslice_mut_unchecked(0, 128), - RAM_D3.get_subslice_mut_unchecked(128, 128), + ram.get_subslice_mut_unchecked(0, 128), + ram.get_subslice_mut_unchecked(128, 128), ) }; diff --git a/rust-toolchain-nightly.toml b/rust-toolchain-nightly.toml index 0b10d7194..acab9d615 100644 --- a/rust-toolchain-nightly.toml +++ b/rust-toolchain-nightly.toml @@ -1,5 +1,5 @@ [toolchain] -channel = "nightly-2024-09-06" +channel = "nightly-2024-10-13" components = [ "rust-src", "rustfmt", "llvm-tools", "miri" ] targets = [ "thumbv7em-none-eabi", diff --git a/tests/nrf/src/bin/buffered_uart_spam.rs b/tests/nrf/src/bin/buffered_uart_spam.rs index e8fca452e..843313537 100644 --- a/tests/nrf/src/bin/buffered_uart_spam.rs +++ b/tests/nrf/src/bin/buffered_uart_spam.rs @@ -55,7 +55,7 @@ async fn main(_spawner: Spawner) { let task = unsafe { Task::new_unchecked(NonNull::new_unchecked(&spam_peri.tasks_starttx as *const _ as _)) }; let mut spam_ppi = Ppi::new_one_to_one(p.PPI_CH2, event, task); spam_ppi.enable(); - let p = unsafe { TX_BUF.as_mut_ptr() }; + let p = unsafe { core::ptr::addr_of_mut!(TX_BUF) } as *mut u8; spam_peri.txd.ptr.write(|w| unsafe { w.ptr().bits(p as u32) }); spam_peri.txd.maxcnt.write(|w| unsafe { w.maxcnt().bits(NSPAM as _) }); spam_peri.tasks_starttx.write(|w| unsafe { w.bits(1) }); diff --git a/tests/stm32/src/bin/usart_rx_ringbuffered.rs b/tests/stm32/src/bin/usart_rx_ringbuffered.rs index 98c7ef312..83c0887ac 100644 --- a/tests/stm32/src/bin/usart_rx_ringbuffered.rs +++ b/tests/stm32/src/bin/usart_rx_ringbuffered.rs @@ -43,8 +43,7 @@ async fn main(spawner: Spawner) { let usart = Uart::new(usart, rx, tx, irq, tx_dma, rx_dma, config).unwrap(); let (tx, rx) = usart.split(); static mut DMA_BUF: [u8; DMA_BUF_SIZE] = [0; DMA_BUF_SIZE]; - let dma_buf = unsafe { DMA_BUF.as_mut() }; - let rx = rx.into_ring_buffered(dma_buf); + let rx = rx.into_ring_buffered(unsafe { &mut *core::ptr::addr_of_mut!(DMA_BUF) }); info!("Spawning tasks"); spawner.spawn(transmit_task(tx)).unwrap(); From 9a45d776d870582cda3db0db233e3f5aea15d34e Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 14 Oct 2024 00:12:45 +0200 Subject: [PATCH 0219/1217] rustfmt for new nightly. --- embassy-net-driver-channel/src/lib.rs | 10 ++++++++-- embassy-net-driver/src/lib.rs | 6 ++++-- embassy-net-enc28j60/src/lib.rs | 6 ++++-- embassy-net-tuntap/src/lib.rs | 10 ++++++++-- embassy-net/src/driver_util.rs | 10 ++++++++-- embassy-net/src/tcp.rs | 5 ++++- embassy-stm32-wpan/src/mac/driver.rs | 10 ++++++++-- embassy-stm32/src/eth/mod.rs | 10 ++++++++-- 8 files changed, 52 insertions(+), 15 deletions(-) diff --git a/embassy-net-driver-channel/src/lib.rs b/embassy-net-driver-channel/src/lib.rs index 7ad4d449e..6390502a8 100644 --- a/embassy-net-driver-channel/src/lib.rs +++ b/embassy-net-driver-channel/src/lib.rs @@ -326,8 +326,14 @@ pub struct Device<'d, const MTU: usize> { } impl<'d, const MTU: usize> embassy_net_driver::Driver for Device<'d, MTU> { - type RxToken<'a> = RxToken<'a, MTU> where Self: 'a ; - type TxToken<'a> = TxToken<'a, MTU> where Self: 'a ; + type RxToken<'a> + = RxToken<'a, MTU> + where + Self: 'a; + type TxToken<'a> + = TxToken<'a, MTU> + where + Self: 'a; fn receive(&mut self, cx: &mut Context) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> { if self.rx.poll_receive(cx).is_ready() && self.tx.poll_send(cx).is_ready() { diff --git a/embassy-net-driver/src/lib.rs b/embassy-net-driver/src/lib.rs index 87f9f6ed1..4c847718d 100644 --- a/embassy-net-driver/src/lib.rs +++ b/embassy-net-driver/src/lib.rs @@ -83,10 +83,12 @@ pub trait Driver { } impl Driver for &mut T { - type RxToken<'a> = T::RxToken<'a> + type RxToken<'a> + = T::RxToken<'a> where Self: 'a; - type TxToken<'a> = T::TxToken<'a> + type TxToken<'a> + = T::TxToken<'a> where Self: 'a; diff --git a/embassy-net-enc28j60/src/lib.rs b/embassy-net-enc28j60/src/lib.rs index dda35f498..c1f32719a 100644 --- a/embassy-net-enc28j60/src/lib.rs +++ b/embassy-net-enc28j60/src/lib.rs @@ -635,11 +635,13 @@ where S: SpiDevice, O: OutputPin, { - type RxToken<'a> = RxToken<'a> + type RxToken<'a> + = RxToken<'a> where Self: 'a; - type TxToken<'a> = TxToken<'a, S, O> + type TxToken<'a> + = TxToken<'a, S, O> where Self: 'a; diff --git a/embassy-net-tuntap/src/lib.rs b/embassy-net-tuntap/src/lib.rs index 56f55fba1..2ff23f462 100644 --- a/embassy-net-tuntap/src/lib.rs +++ b/embassy-net-tuntap/src/lib.rs @@ -152,8 +152,14 @@ impl TunTapDevice { } impl Driver for TunTapDevice { - type RxToken<'a> = RxToken where Self: 'a; - type TxToken<'a> = TxToken<'a> where Self: 'a; + type RxToken<'a> + = RxToken + where + Self: 'a; + type TxToken<'a> + = TxToken<'a> + where + Self: 'a; fn receive(&mut self, cx: &mut Context) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> { let mut buf = vec![0; self.device.get_ref().mtu]; diff --git a/embassy-net/src/driver_util.rs b/embassy-net/src/driver_util.rs index b2af1d499..f51641425 100644 --- a/embassy-net/src/driver_util.rs +++ b/embassy-net/src/driver_util.rs @@ -18,8 +18,14 @@ impl<'d, 'c, T> phy::Device for DriverAdapter<'d, 'c, T> where T: Driver, { - type RxToken<'a> = RxTokenAdapter> where Self: 'a; - type TxToken<'a> = TxTokenAdapter> where Self: 'a; + type RxToken<'a> + = RxTokenAdapter> + where + Self: 'a; + type TxToken<'a> + = TxTokenAdapter> + where + Self: 'a; fn receive(&mut self, _timestamp: Instant) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> { self.inner diff --git a/embassy-net/src/tcp.rs b/embassy-net/src/tcp.rs index 1bd582b65..043062e06 100644 --- a/embassy-net/src/tcp.rs +++ b/embassy-net/src/tcp.rs @@ -712,7 +712,10 @@ pub mod client { for TcpClient<'d, N, TX_SZ, RX_SZ> { type Error = Error; - type Connection<'m> = TcpConnection<'m, N, TX_SZ, RX_SZ> where Self: 'm; + type Connection<'m> + = TcpConnection<'m, N, TX_SZ, RX_SZ> + where + Self: 'm; async fn connect<'a>(&'a self, remote: core::net::SocketAddr) -> Result, Self::Error> { let addr: crate::IpAddress = match remote.ip() { diff --git a/embassy-stm32-wpan/src/mac/driver.rs b/embassy-stm32-wpan/src/mac/driver.rs index 5b9d5daf4..41cca09e3 100644 --- a/embassy-stm32-wpan/src/mac/driver.rs +++ b/embassy-stm32-wpan/src/mac/driver.rs @@ -23,8 +23,14 @@ impl<'d> Driver<'d> { impl<'d> embassy_net_driver::Driver for Driver<'d> { // type RxToken<'a> = RxToken<'a, 'd> where Self: 'a; // type TxToken<'a> = TxToken<'a, 'd> where Self: 'a; - type RxToken<'a> = RxToken<'d> where Self: 'a; - type TxToken<'a> = TxToken<'d> where Self: 'a; + type RxToken<'a> + = RxToken<'d> + where + Self: 'a; + type TxToken<'a> + = TxToken<'d> + where + Self: 'a; fn receive(&mut self, cx: &mut Context) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> { if self.runner.rx_channel.poll_ready_to_receive(cx).is_ready() diff --git a/embassy-stm32/src/eth/mod.rs b/embassy-stm32/src/eth/mod.rs index 6442176da..1b875b71a 100644 --- a/embassy-stm32/src/eth/mod.rs +++ b/embassy-stm32/src/eth/mod.rs @@ -74,8 +74,14 @@ impl PacketQueue { static WAKER: AtomicWaker = AtomicWaker::new(); impl<'d, T: Instance, P: PHY> embassy_net_driver::Driver for Ethernet<'d, T, P> { - type RxToken<'a> = RxToken<'a, 'd> where Self: 'a; - type TxToken<'a> = TxToken<'a, 'd> where Self: 'a; + type RxToken<'a> + = RxToken<'a, 'd> + where + Self: 'a; + type TxToken<'a> + = TxToken<'a, 'd> + where + Self: 'a; fn receive(&mut self, cx: &mut Context) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> { WAKER.register(cx.waker()); From 6862ac56cb1c1a29bad3e872b45386774c8edd58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A0=D0=BE=D0=BC=D0=B0=D0=BD=20=D0=9A=D1=80=D0=B8=D0=B2?= =?UTF-8?q?=D0=B5=D0=BD=D0=BA=D0=BE=D0=B2?= Date: Mon, 16 Sep 2024 11:02:27 +0400 Subject: [PATCH 0220/1217] Stm32: implement async flush for UART --- embassy-stm32/src/usart/mod.rs | 71 ++++++++++++++++++++++++++++------ 1 file changed, 59 insertions(+), 12 deletions(-) diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index 6f838cce5..333e01e36 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -69,6 +69,12 @@ unsafe fn on_interrupt(r: Regs, s: &'static State) { // disable idle line detection w.set_idleie(false); }); + } else if cr1.tcie() && sr.tc() { + // Transmission complete detected + r.cr1().modify(|w| { + // disable Transmission complete interrupt + w.set_tcie(false); + }); } else if cr1.rxneie() { // We cannot check the RXNE flag as it is auto-cleared by the DMA controller @@ -420,7 +426,7 @@ impl<'d> UartTx<'d, Async> { /// Wait until transmission complete pub async fn flush(&mut self) -> Result<(), Error> { - self.blocking_flush() + flush(&self.info, &self.state).await } } @@ -531,16 +537,40 @@ impl<'d, M: Mode> UartTx<'d, M> { } } +/// Wait until transmission complete +async fn flush(info: &Info, state: &State) -> Result<(), Error> { + let r = info.regs; + if r.cr1().read().te() && !sr(r).read().tc() { + r.cr1().modify(|w| { + // enable Transmission Complete interrupt + w.set_tcie(true); + }); + + compiler_fence(Ordering::SeqCst); + + // future which completes when Transmission complete is detected + let abort = poll_fn(move |cx| { + state.rx_waker.register(cx.waker()); + + let sr = sr(r).read(); + if sr.tc() { + // Transmission complete detected + return Poll::Ready(()); + } + + Poll::Pending + }); + + abort.await; + } + + Ok(()) +} + fn blocking_flush(info: &Info) -> Result<(), Error> { let r = info.regs; - while !sr(r).read().tc() {} - - // Disable Transmitter and enable receiver after transmission complete for Half-Duplex mode - if r.cr3().read().hdsel() { - r.cr1().modify(|reg| { - reg.set_te(false); - reg.set_re(true); - }); + if r.cr1().read().te() { + while !sr(r).read().tc() {} } Ok(()) @@ -621,7 +651,13 @@ impl<'d> UartRx<'d, Async> { // Call flush for Half-Duplex mode if some bytes were written and flush was not called. // It prevents reading of bytes which have just been written. if r.cr3().read().hdsel() && r.cr1().read().te() { - blocking_flush(self.info)?; + flush(&self.info, &self.state).await?; + + // Disable Transmitter and enable Receiver after flush + r.cr1().modify(|reg| { + reg.set_re(true); + reg.set_te(false); + }); } // make sure USART state is restored to neutral state when this future is dropped @@ -960,6 +996,12 @@ impl<'d, M: Mode> UartRx<'d, M> { // It prevents reading of bytes which have just been written. if r.cr3().read().hdsel() && r.cr1().read().te() { blocking_flush(self.info)?; + + // Disable Transmitter and enable Receiver after flush + r.cr1().modify(|reg| { + reg.set_re(true); + reg.set_te(false); + }); } for b in buffer { @@ -1155,6 +1197,11 @@ impl<'d> Uart<'d, Async> { self.tx.write(buffer).await } + /// Wait until transmission complete + pub async fn flush(&mut self) -> Result<(), Error> { + self.tx.flush().await + } + /// Perform an asynchronous read into `buffer` pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { self.rx.read(buffer).await @@ -1733,7 +1780,7 @@ impl embedded_io_async::Write for Uart<'_, Async> { } async fn flush(&mut self) -> Result<(), Self::Error> { - self.blocking_flush() + self.flush().await } } @@ -1744,7 +1791,7 @@ impl embedded_io_async::Write for UartTx<'_, Async> { } async fn flush(&mut self) -> Result<(), Self::Error> { - self.blocking_flush() + self.flush().await } } From ad5f7bf6f72f6e1ff512b29eaa843b0dae58d931 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 14 Oct 2024 12:43:38 +0200 Subject: [PATCH 0221/1217] tests: remove deprecated -Cinline-threshold. --- tests/rp/.cargo/config.toml | 1 - tests/stm32/.cargo/config.toml | 1 - 2 files changed, 2 deletions(-) diff --git a/tests/rp/.cargo/config.toml b/tests/rp/.cargo/config.toml index de7bb0e56..4337924cc 100644 --- a/tests/rp/.cargo/config.toml +++ b/tests/rp/.cargo/config.toml @@ -11,7 +11,6 @@ runner = "teleprobe client run" rustflags = [ # Code-size optimizations. #"-Z", "trap-unreachable=no", - "-C", "inline-threshold=5", "-C", "no-vectorize-loops", ] diff --git a/tests/stm32/.cargo/config.toml b/tests/stm32/.cargo/config.toml index 8752da59b..d94342598 100644 --- a/tests/stm32/.cargo/config.toml +++ b/tests/stm32/.cargo/config.toml @@ -9,7 +9,6 @@ runner = "teleprobe client run" rustflags = [ # Code-size optimizations. #"-Z", "trap-unreachable=no", - "-C", "inline-threshold=5", "-C", "no-vectorize-loops", ] From 014583aaa5dd10d4580aa24ec9b9f2ddb963559a Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 14 Oct 2024 12:43:59 +0200 Subject: [PATCH 0222/1217] tests/stm32: add uart async and blocking flush test. --- tests/stm32/src/bin/usart.rs | 7 +++++++ tests/stm32/src/bin/usart_dma.rs | 17 +++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/tests/stm32/src/bin/usart.rs b/tests/stm32/src/bin/usart.rs index 53da30fff..2f601ad0e 100644 --- a/tests/stm32/src/bin/usart.rs +++ b/tests/stm32/src/bin/usart.rs @@ -33,6 +33,13 @@ async fn main(_spawner: Spawner) { let mut buf = [0; 2]; usart.blocking_read(&mut buf).unwrap(); assert_eq!(buf, data); + + // Test flush doesn't hang. + usart.blocking_write(&data).unwrap(); + usart.blocking_flush().unwrap(); + + // Test flush doesn't hang if there's nothing to flush + usart.blocking_flush().unwrap(); } // Test error handling with with an overflow error diff --git a/tests/stm32/src/bin/usart_dma.rs b/tests/stm32/src/bin/usart_dma.rs index 266b81809..a34498376 100644 --- a/tests/stm32/src/bin/usart_dma.rs +++ b/tests/stm32/src/bin/usart_dma.rs @@ -51,6 +51,23 @@ async fn main(_spawner: Spawner) { assert_eq!(tx_buf, rx_buf); } + // Test flush doesn't hang. Check multiple combinations of async+blocking. + tx.write(&tx_buf).await.unwrap(); + tx.flush().await.unwrap(); + tx.flush().await.unwrap(); + + tx.write(&tx_buf).await.unwrap(); + tx.blocking_flush().unwrap(); + tx.flush().await.unwrap(); + + tx.blocking_write(&tx_buf).unwrap(); + tx.blocking_flush().unwrap(); + tx.flush().await.unwrap(); + + tx.blocking_write(&tx_buf).unwrap(); + tx.flush().await.unwrap(); + tx.blocking_flush().unwrap(); + info!("Test OK"); cortex_m::asm::bkpt(); } From 2b10caafd488987b6cf9a2cd69820c81d0a0826e Mon Sep 17 00:00:00 2001 From: Alexandros Liarokapis Date: Sun, 15 Sep 2024 18:47:33 +0300 Subject: [PATCH 0223/1217] stm32: initial support for alternative ringbuffer implementation --- embassy-stm32/Cargo.toml | 2 + embassy-stm32/src/dma/dma_bdma.rs | 4 - embassy-stm32/src/dma/ringbuffer.rs | 668 ------------------ embassy-stm32/src/dma/ringbuffer/mod.rs | 293 ++++++++ embassy-stm32/src/dma/ringbuffer/tests/mod.rs | 165 +++++ .../src/dma/ringbuffer/tests/prop_test/mod.rs | 50 ++ .../dma/ringbuffer/tests/prop_test/reader.rs | 122 ++++ .../dma/ringbuffer/tests/prop_test/writer.rs | 121 ++++ 8 files changed, 753 insertions(+), 672 deletions(-) delete mode 100644 embassy-stm32/src/dma/ringbuffer.rs create mode 100644 embassy-stm32/src/dma/ringbuffer/mod.rs create mode 100644 embassy-stm32/src/dma/ringbuffer/tests/mod.rs create mode 100644 embassy-stm32/src/dma/ringbuffer/tests/prop_test/mod.rs create mode 100644 embassy-stm32/src/dma/ringbuffer/tests/prop_test/reader.rs create mode 100644 embassy-stm32/src/dma/ringbuffer/tests/prop_test/writer.rs diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 8fc8da006..53ec1b27f 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -93,6 +93,8 @@ aligned = "0.4.1" [dev-dependencies] critical-section = { version = "1.1", features = ["std"] } +proptest = "1.5.0" +proptest-state-machine = "0.3.0" [build-dependencies] proc-macro2 = "1.0.36" diff --git a/embassy-stm32/src/dma/dma_bdma.rs b/embassy-stm32/src/dma/dma_bdma.rs index d10b5554f..a43137c6e 100644 --- a/embassy-stm32/src/dma/dma_bdma.rs +++ b/embassy-stm32/src/dma/dma_bdma.rs @@ -763,10 +763,6 @@ impl<'a> DmaCtrl for DmaCtrlImpl<'a> { self.0.get_remaining_transfers() as _ } - fn get_complete_count(&self) -> usize { - STATE[self.0.id as usize].complete_count.load(Ordering::Acquire) - } - fn reset_complete_count(&mut self) -> usize { let state = &STATE[self.0.id as usize]; #[cfg(not(armv6m))] diff --git a/embassy-stm32/src/dma/ringbuffer.rs b/embassy-stm32/src/dma/ringbuffer.rs deleted file mode 100644 index 23f1d67d5..000000000 --- a/embassy-stm32/src/dma/ringbuffer.rs +++ /dev/null @@ -1,668 +0,0 @@ -#![cfg_attr(gpdma, allow(unused))] - -use core::future::poll_fn; -use core::ops::Range; -use core::sync::atomic::{compiler_fence, Ordering}; -use core::task::{Poll, Waker}; - -use super::word::Word; - -/// A "read-only" ring-buffer to be used together with the DMA controller which -/// writes in a circular way, "uncontrolled" to the buffer. -/// -/// A snapshot of the ring buffer state can be attained by setting the `ndtr` field -/// to the current register value. `ndtr` describes the current position of the DMA -/// write. -/// -/// # Buffer layout -/// -/// ```text -/// Without wraparound: With wraparound: -/// -/// + buf +--- NDTR ---+ + buf +---------- NDTR ----------+ -/// | | | | | | -/// v v v v v v -/// +-----------------------------------------+ +-----------------------------------------+ -/// |oooooooooooXXXXXXXXXXXXXXXXoooooooooooooo| |XXXXXXXXXXXXXooooooooooooXXXXXXXXXXXXXXXX| -/// +-----------------------------------------+ +-----------------------------------------+ -/// ^ ^ ^ ^ ^ ^ -/// | | | | | | -/// +- start --+ | +- end ------+ | -/// | | | | -/// +- end --------------------+ +- start ----------------+ -/// ``` -pub struct ReadableDmaRingBuffer<'a, W: Word> { - pub(crate) dma_buf: &'a mut [W], - start: usize, -} - -#[derive(Debug, PartialEq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct OverrunError; - -pub trait DmaCtrl { - /// Get the NDTR register value, i.e. the space left in the underlying - /// buffer until the dma writer wraps. - fn get_remaining_transfers(&self) -> usize; - - /// Get the transfer completed counter. - /// This counter is incremented by the dma controller when NDTR is reloaded, - /// i.e. when the writing wraps. - fn get_complete_count(&self) -> usize; - - /// Reset the transfer completed counter to 0 and return the value just prior to the reset. - fn reset_complete_count(&mut self) -> usize; - - /// Set the waker for a running poll_fn - fn set_waker(&mut self, waker: &Waker); -} - -impl<'a, W: Word> ReadableDmaRingBuffer<'a, W> { - pub fn new(dma_buf: &'a mut [W]) -> Self { - Self { dma_buf, start: 0 } - } - - /// Reset the ring buffer to its initial state - pub fn clear(&mut self, dma: &mut impl DmaCtrl) { - self.start = 0; - dma.reset_complete_count(); - } - - /// The capacity of the ringbuffer - pub const fn cap(&self) -> usize { - self.dma_buf.len() - } - - /// The current position of the ringbuffer - fn pos(&self, dma: &mut impl DmaCtrl) -> usize { - self.cap() - dma.get_remaining_transfers() - } - - /// Read an exact number of elements from the ringbuffer. - /// - /// Returns the remaining number of elements available for immediate reading. - /// OverrunError is returned if the portion to be read was overwritten by the DMA controller. - /// - /// Async/Wake Behavior: - /// The underlying DMA peripheral only can wake us when its buffer pointer has reached the halfway point, - /// and when it wraps around. This means that when called with a buffer of length 'M', when this - /// ring buffer was created with a buffer of size 'N': - /// - If M equals N/2 or N/2 divides evenly into M, this function will return every N/2 elements read on the DMA source. - /// - Otherwise, this function may need up to N/2 extra elements to arrive before returning. - pub async fn read_exact(&mut self, dma: &mut impl DmaCtrl, buffer: &mut [W]) -> Result { - let mut read_data = 0; - let buffer_len = buffer.len(); - - poll_fn(|cx| { - dma.set_waker(cx.waker()); - - compiler_fence(Ordering::SeqCst); - - match self.read(dma, &mut buffer[read_data..buffer_len]) { - Ok((len, remaining)) => { - read_data += len; - if read_data == buffer_len { - Poll::Ready(Ok(remaining)) - } else { - Poll::Pending - } - } - Err(e) => Poll::Ready(Err(e)), - } - }) - .await - } - - /// Read elements from the ring buffer - /// Return a tuple of the length read and the length remaining in the buffer - /// If not all of the elements were read, then there will be some elements in the buffer remaining - /// The length remaining is the capacity, ring_buf.len(), less the elements remaining after the read - /// OverrunError is returned if the portion to be read was overwritten by the DMA controller. - pub fn read(&mut self, dma: &mut impl DmaCtrl, buf: &mut [W]) -> Result<(usize, usize), OverrunError> { - /* - This algorithm is optimistic: we assume we haven't overrun more than a full buffer and then check - after we've done our work to see we have. This is because on stm32, an interrupt is not guaranteed - to fire in the same clock cycle that a register is read, so checking get_complete_count early does - not yield relevant information. - - Therefore, the only variable we really need to know is ndtr. If the dma has overrun by more than a full - buffer, we will do a bit more work than we have to, but algorithms should not be optimized for error - conditions. - - After we've done our work, we confirm that we haven't overrun more than a full buffer, and also that - the dma has not overrun within the data we could have copied. We check the data we could have copied - rather than the data we actually copied because it costs nothing and confirms an error condition - earlier. - */ - let end = self.pos(dma); - if self.start == end && dma.get_complete_count() == 0 { - // No elements are available in the buffer - Ok((0, self.cap())) - } else if self.start < end { - // The available, unread portion in the ring buffer DOES NOT wrap - // Copy out the elements from the dma buffer - let len = self.copy_to(buf, self.start..end); - - compiler_fence(Ordering::SeqCst); - - /* - first, check if the dma has wrapped at all if it's after end - or more than once if it's before start - - this is in a critical section to try to reduce mushy behavior. - it's not ideal but it's the best we can do - - then, get the current position of of the dma write and check - if it's inside data we could have copied - */ - let (pos, complete_count) = critical_section::with(|_| (self.pos(dma), dma.get_complete_count())); - if (pos >= self.start && pos < end) || (complete_count > 0 && pos >= end) || complete_count > 1 { - Err(OverrunError) - } else { - self.start = (self.start + len) % self.cap(); - - Ok((len, self.cap() - self.start)) - } - } else if self.start + buf.len() < self.cap() { - // The available, unread portion in the ring buffer DOES wrap - // The DMA writer has wrapped since we last read and is currently - // writing (or the next byte added will be) in the beginning of the ring buffer. - - // The provided read buffer is not large enough to include all elements from the tail of the dma buffer. - - // Copy out from the dma buffer - let len = self.copy_to(buf, self.start..self.cap()); - - compiler_fence(Ordering::SeqCst); - - /* - first, check if the dma has wrapped around more than once - - then, get the current position of of the dma write and check - if it's inside data we could have copied - */ - let pos = self.pos(dma); - if pos > self.start || pos < end || dma.get_complete_count() > 1 { - Err(OverrunError) - } else { - self.start = (self.start + len) % self.cap(); - - Ok((len, self.start + end)) - } - } else { - // The available, unread portion in the ring buffer DOES wrap - // The DMA writer has wrapped since we last read and is currently - // writing (or the next byte added will be) in the beginning of the ring buffer. - - // The provided read buffer is large enough to include all elements from the tail of the dma buffer, - // so the next read will not have any unread tail elements in the ring buffer. - - // Copy out from the dma buffer - let tail = self.copy_to(buf, self.start..self.cap()); - let head = self.copy_to(&mut buf[tail..], 0..end); - - compiler_fence(Ordering::SeqCst); - - /* - first, check if the dma has wrapped around more than once - - then, get the current position of of the dma write and check - if it's inside data we could have copied - */ - let pos = self.pos(dma); - if pos > self.start || pos < end || dma.reset_complete_count() > 1 { - Err(OverrunError) - } else { - self.start = head; - Ok((tail + head, self.cap() - self.start)) - } - } - } - /// Copy from the dma buffer at `data_range` into `buf` - fn copy_to(&mut self, buf: &mut [W], data_range: Range) -> usize { - // Limit the number of elements that can be copied - let length = usize::min(data_range.len(), buf.len()); - - // Copy from dma buffer into read buffer - // We need to do it like this instead of a simple copy_from_slice() because - // reading from a part of memory that may be simultaneously written to is unsafe - unsafe { - let dma_buf = self.dma_buf.as_ptr(); - - for i in 0..length { - buf[i] = core::ptr::read_volatile(dma_buf.offset((data_range.start + i) as isize)); - } - } - - length - } -} - -pub struct WritableDmaRingBuffer<'a, W: Word> { - pub(crate) dma_buf: &'a mut [W], - end: usize, -} - -impl<'a, W: Word> WritableDmaRingBuffer<'a, W> { - pub fn new(dma_buf: &'a mut [W]) -> Self { - Self { dma_buf, end: 0 } - } - - /// Reset the ring buffer to its initial state - pub fn clear(&mut self, dma: &mut impl DmaCtrl) { - self.end = 0; - dma.reset_complete_count(); - } - - /// The capacity of the ringbuffer - pub const fn cap(&self) -> usize { - self.dma_buf.len() - } - - /// The current position of the ringbuffer - fn pos(&self, dma: &mut impl DmaCtrl) -> usize { - self.cap() - dma.get_remaining_transfers() - } - - /// Write elements directly to the buffer. This must be done before the DMA is started - /// or after the buffer has been cleared using `clear()`. - pub fn write_immediate(&mut self, buffer: &[W]) -> Result<(usize, usize), OverrunError> { - if self.end != 0 { - return Err(OverrunError); - } - let written = self.copy_from(buffer, 0..self.cap()); - self.end = written % self.cap(); - Ok((written, self.cap() - written)) - } - - /// Write an exact number of elements to the ringbuffer. - pub async fn write_exact(&mut self, dma: &mut impl DmaCtrl, buffer: &[W]) -> Result { - let mut written_data = 0; - let buffer_len = buffer.len(); - - poll_fn(|cx| { - dma.set_waker(cx.waker()); - - compiler_fence(Ordering::SeqCst); - - match self.write(dma, &buffer[written_data..buffer_len]) { - Ok((len, remaining)) => { - written_data += len; - if written_data == buffer_len { - Poll::Ready(Ok(remaining)) - } else { - Poll::Pending - } - } - Err(e) => Poll::Ready(Err(e)), - } - }) - .await - } - - /// Write elements from the ring buffer - /// Return a tuple of the length written and the capacity remaining to be written in the buffer - pub fn write(&mut self, dma: &mut impl DmaCtrl, buf: &[W]) -> Result<(usize, usize), OverrunError> { - let start = self.pos(dma); - if start > self.end { - // The occupied portion in the ring buffer DOES wrap - let len = self.copy_from(buf, self.end..start); - - compiler_fence(Ordering::SeqCst); - - // Confirm that the DMA is not inside data we could have written - let (pos, complete_count) = critical_section::with(|_| (self.pos(dma), dma.get_complete_count())); - if (pos >= self.end && pos < start) || (complete_count > 0 && pos >= start) || complete_count > 1 { - Err(OverrunError) - } else { - self.end = (self.end + len) % self.cap(); - - Ok((len, self.cap() - (start - self.end))) - } - } else if start == self.end && dma.get_complete_count() == 0 { - Ok((0, 0)) - } else if start <= self.end && self.end + buf.len() < self.cap() { - // The occupied portion in the ring buffer DOES NOT wrap - // and copying elements into the buffer WILL NOT cause it to - - // Copy into the dma buffer - let len = self.copy_from(buf, self.end..self.cap()); - - compiler_fence(Ordering::SeqCst); - - // Confirm that the DMA is not inside data we could have written - let pos = self.pos(dma); - if pos > self.end || pos < start || dma.get_complete_count() > 1 { - Err(OverrunError) - } else { - self.end = (self.end + len) % self.cap(); - - Ok((len, self.cap() - (self.end - start))) - } - } else { - // The occupied portion in the ring buffer DOES NOT wrap - // and copying elements into the buffer WILL cause it to - - let tail = self.copy_from(buf, self.end..self.cap()); - let head = self.copy_from(&buf[tail..], 0..start); - - compiler_fence(Ordering::SeqCst); - - // Confirm that the DMA is not inside data we could have written - let pos = self.pos(dma); - if pos > self.end || pos < start || dma.reset_complete_count() > 1 { - Err(OverrunError) - } else { - self.end = head; - - Ok((tail + head, self.cap() - (start - self.end))) - } - } - } - /// Copy into the dma buffer at `data_range` from `buf` - fn copy_from(&mut self, buf: &[W], data_range: Range) -> usize { - // Limit the number of elements that can be copied - let length = usize::min(data_range.len(), buf.len()); - - // Copy into dma buffer from read buffer - // We need to do it like this instead of a simple copy_from_slice() because - // reading from a part of memory that may be simultaneously written to is unsafe - unsafe { - let dma_buf = self.dma_buf.as_mut_ptr(); - - for i in 0..length { - core::ptr::write_volatile(dma_buf.offset((data_range.start + i) as isize), buf[i]); - } - } - - length - } -} -#[cfg(test)] -mod tests { - use core::array; - use std::{cell, vec}; - - use super::*; - - #[allow(dead_code)] - #[derive(PartialEq, Debug)] - enum TestCircularTransferRequest { - GetCompleteCount(usize), - ResetCompleteCount(usize), - PositionRequest(usize), - } - - struct TestCircularTransfer { - len: usize, - requests: cell::RefCell>, - } - - impl DmaCtrl for TestCircularTransfer { - fn get_remaining_transfers(&self) -> usize { - match self.requests.borrow_mut().pop().unwrap() { - TestCircularTransferRequest::PositionRequest(pos) => { - let len = self.len; - - assert!(len >= pos); - - len - pos - } - _ => unreachable!(), - } - } - - fn get_complete_count(&self) -> usize { - match self.requests.borrow_mut().pop().unwrap() { - TestCircularTransferRequest::GetCompleteCount(complete_count) => complete_count, - _ => unreachable!(), - } - } - - fn reset_complete_count(&mut self) -> usize { - match self.requests.get_mut().pop().unwrap() { - TestCircularTransferRequest::ResetCompleteCount(complete_count) => complete_count, - _ => unreachable!(), - } - } - - fn set_waker(&mut self, waker: &Waker) {} - } - - impl TestCircularTransfer { - pub fn new(len: usize) -> Self { - Self { - requests: cell::RefCell::new(vec![]), - len, - } - } - - pub fn setup(&self, mut requests: vec::Vec) { - requests.reverse(); - self.requests.replace(requests); - } - } - - #[test] - fn empty_and_read_not_started() { - let mut dma_buf = [0u8; 16]; - let ringbuf = ReadableDmaRingBuffer::new(&mut dma_buf); - - assert_eq!(0, ringbuf.start); - } - - #[test] - fn can_read() { - let mut dma = TestCircularTransfer::new(16); - - let mut dma_buf: [u8; 16] = array::from_fn(|idx| idx as u8); // 0, 1, ..., 15 - let mut ringbuf = ReadableDmaRingBuffer::new(&mut dma_buf); - - assert_eq!(0, ringbuf.start); - assert_eq!(16, ringbuf.cap()); - - dma.setup(vec![ - TestCircularTransferRequest::PositionRequest(8), - TestCircularTransferRequest::PositionRequest(10), - TestCircularTransferRequest::GetCompleteCount(0), - ]); - let mut buf = [0; 2]; - assert_eq!(2, ringbuf.read(&mut dma, &mut buf).unwrap().0); - assert_eq!([0, 1], buf); - assert_eq!(2, ringbuf.start); - - dma.setup(vec![ - TestCircularTransferRequest::PositionRequest(10), - TestCircularTransferRequest::PositionRequest(12), - TestCircularTransferRequest::GetCompleteCount(0), - ]); - let mut buf = [0; 2]; - assert_eq!(2, ringbuf.read(&mut dma, &mut buf).unwrap().0); - assert_eq!([2, 3], buf); - assert_eq!(4, ringbuf.start); - - dma.setup(vec![ - TestCircularTransferRequest::PositionRequest(12), - TestCircularTransferRequest::PositionRequest(14), - TestCircularTransferRequest::GetCompleteCount(0), - ]); - let mut buf = [0; 8]; - assert_eq!(8, ringbuf.read(&mut dma, &mut buf).unwrap().0); - assert_eq!([4, 5, 6, 7, 8, 9], buf[..6]); - assert_eq!(12, ringbuf.start); - } - - #[test] - fn can_read_with_wrap() { - let mut dma = TestCircularTransfer::new(16); - - let mut dma_buf: [u8; 16] = array::from_fn(|idx| idx as u8); // 0, 1, ..., 15 - let mut ringbuf = ReadableDmaRingBuffer::new(&mut dma_buf); - - assert_eq!(0, ringbuf.start); - assert_eq!(16, ringbuf.cap()); - - /* - Read to close to the end of the buffer - */ - dma.setup(vec![ - TestCircularTransferRequest::PositionRequest(14), - TestCircularTransferRequest::PositionRequest(16), - TestCircularTransferRequest::GetCompleteCount(0), - ]); - let mut buf = [0; 14]; - assert_eq!(14, ringbuf.read(&mut dma, &mut buf).unwrap().0); - assert_eq!(14, ringbuf.start); - - /* - Now, read around the buffer - */ - dma.setup(vec![ - TestCircularTransferRequest::PositionRequest(6), - TestCircularTransferRequest::PositionRequest(8), - TestCircularTransferRequest::ResetCompleteCount(1), - ]); - let mut buf = [0; 6]; - assert_eq!(6, ringbuf.read(&mut dma, &mut buf).unwrap().0); - assert_eq!(4, ringbuf.start); - } - - #[test] - fn can_read_when_dma_writer_is_wrapped_and_read_does_not_wrap() { - let mut dma = TestCircularTransfer::new(16); - - let mut dma_buf: [u8; 16] = array::from_fn(|idx| idx as u8); // 0, 1, ..., 15 - let mut ringbuf = ReadableDmaRingBuffer::new(&mut dma_buf); - - assert_eq!(0, ringbuf.start); - assert_eq!(16, ringbuf.cap()); - - /* - Read to close to the end of the buffer - */ - dma.setup(vec![ - TestCircularTransferRequest::PositionRequest(14), - TestCircularTransferRequest::PositionRequest(16), - TestCircularTransferRequest::GetCompleteCount(0), - ]); - let mut buf = [0; 14]; - assert_eq!(14, ringbuf.read(&mut dma, &mut buf).unwrap().0); - assert_eq!(14, ringbuf.start); - - /* - Now, read to the end of the buffer - */ - dma.setup(vec![ - TestCircularTransferRequest::PositionRequest(6), - TestCircularTransferRequest::PositionRequest(8), - TestCircularTransferRequest::ResetCompleteCount(1), - ]); - let mut buf = [0; 2]; - assert_eq!(2, ringbuf.read(&mut dma, &mut buf).unwrap().0); - assert_eq!(0, ringbuf.start); - } - - #[test] - fn can_read_when_dma_writer_wraps_once_with_same_ndtr() { - let mut dma = TestCircularTransfer::new(16); - - let mut dma_buf: [u8; 16] = array::from_fn(|idx| idx as u8); // 0, 1, ..., 15 - let mut ringbuf = ReadableDmaRingBuffer::new(&mut dma_buf); - - assert_eq!(0, ringbuf.start); - assert_eq!(16, ringbuf.cap()); - - /* - Read to about the middle of the buffer - */ - dma.setup(vec![ - TestCircularTransferRequest::PositionRequest(6), - TestCircularTransferRequest::PositionRequest(6), - TestCircularTransferRequest::GetCompleteCount(0), - ]); - let mut buf = [0; 6]; - assert_eq!(6, ringbuf.read(&mut dma, &mut buf).unwrap().0); - assert_eq!(6, ringbuf.start); - - /* - Now, wrap the DMA controller around - */ - dma.setup(vec![ - TestCircularTransferRequest::PositionRequest(6), - TestCircularTransferRequest::GetCompleteCount(1), - TestCircularTransferRequest::PositionRequest(6), - TestCircularTransferRequest::GetCompleteCount(1), - ]); - let mut buf = [0; 6]; - assert_eq!(6, ringbuf.read(&mut dma, &mut buf).unwrap().0); - assert_eq!(12, ringbuf.start); - } - - #[test] - fn cannot_read_when_dma_writer_overwrites_during_not_wrapping_read() { - let mut dma = TestCircularTransfer::new(16); - - let mut dma_buf: [u8; 16] = array::from_fn(|idx| idx as u8); // 0, 1, ..., 15 - let mut ringbuf = ReadableDmaRingBuffer::new(&mut dma_buf); - - assert_eq!(0, ringbuf.start); - assert_eq!(16, ringbuf.cap()); - - /* - Read a few bytes - */ - dma.setup(vec![ - TestCircularTransferRequest::PositionRequest(2), - TestCircularTransferRequest::PositionRequest(2), - TestCircularTransferRequest::GetCompleteCount(0), - ]); - let mut buf = [0; 6]; - assert_eq!(2, ringbuf.read(&mut dma, &mut buf).unwrap().0); - assert_eq!(2, ringbuf.start); - - /* - Now, overtake the reader - */ - dma.setup(vec![ - TestCircularTransferRequest::PositionRequest(4), - TestCircularTransferRequest::PositionRequest(6), - TestCircularTransferRequest::GetCompleteCount(1), - ]); - let mut buf = [0; 6]; - assert_eq!(OverrunError, ringbuf.read(&mut dma, &mut buf).unwrap_err()); - } - - #[test] - fn cannot_read_when_dma_writer_overwrites_during_wrapping_read() { - let mut dma = TestCircularTransfer::new(16); - - let mut dma_buf: [u8; 16] = array::from_fn(|idx| idx as u8); // 0, 1, ..., 15 - let mut ringbuf = ReadableDmaRingBuffer::new(&mut dma_buf); - - assert_eq!(0, ringbuf.start); - assert_eq!(16, ringbuf.cap()); - - /* - Read to close to the end of the buffer - */ - dma.setup(vec![ - TestCircularTransferRequest::PositionRequest(14), - TestCircularTransferRequest::PositionRequest(16), - TestCircularTransferRequest::GetCompleteCount(0), - ]); - let mut buf = [0; 14]; - assert_eq!(14, ringbuf.read(&mut dma, &mut buf).unwrap().0); - assert_eq!(14, ringbuf.start); - - /* - Now, overtake the reader - */ - dma.setup(vec![ - TestCircularTransferRequest::PositionRequest(8), - TestCircularTransferRequest::PositionRequest(10), - TestCircularTransferRequest::ResetCompleteCount(2), - ]); - let mut buf = [0; 6]; - assert_eq!(OverrunError, ringbuf.read(&mut dma, &mut buf).unwrap_err()); - } -} diff --git a/embassy-stm32/src/dma/ringbuffer/mod.rs b/embassy-stm32/src/dma/ringbuffer/mod.rs new file mode 100644 index 000000000..10a9ff975 --- /dev/null +++ b/embassy-stm32/src/dma/ringbuffer/mod.rs @@ -0,0 +1,293 @@ +#![cfg_attr(gpdma, allow(unused))] + +use core::future::poll_fn; +use core::task::{Poll, Waker}; + +use crate::dma::word::Word; + +pub trait DmaCtrl { + /// Get the NDTR register value, i.e. the space left in the underlying + /// buffer until the dma writer wraps. + fn get_remaining_transfers(&self) -> usize; + + /// Reset the transfer completed counter to 0 and return the value just prior to the reset. + fn reset_complete_count(&mut self) -> usize; + + /// Set the waker for a running poll_fn + fn set_waker(&mut self, waker: &Waker); +} + +#[derive(Debug, PartialEq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct OverrunError; + +#[derive(Debug, Clone, Copy, Default)] +struct DmaIndex { + completion_count: usize, + pos: usize, +} + +fn pos(cap: usize, dma: &impl DmaCtrl) -> usize { + cap - dma.get_remaining_transfers() +} + +impl DmaIndex { + fn reset(&mut self) { + self.pos = 0; + self.completion_count = 0; + } + + fn as_index(&self, cap: usize, offset: usize) -> usize { + (self.pos + offset) % cap + } + + fn dma_sync(&mut self, cap: usize, dma: &mut impl DmaCtrl) { + let fst_pos = pos(cap, dma); + let fst_count = dma.reset_complete_count(); + let pos = pos(cap, dma); + + let wrap_count = if pos >= fst_pos { + fst_count + } else { + fst_count + dma.reset_complete_count() + }; + + self.pos = pos; + self.completion_count += wrap_count; + } + + fn advance(&mut self, cap: usize, steps: usize) { + let next = self.pos + steps; + self.completion_count += next / cap; + self.pos = next % cap; + } + + fn normalize(lhs: &mut DmaIndex, rhs: &mut DmaIndex) { + let min_count = lhs.completion_count.min(rhs.completion_count); + lhs.completion_count -= min_count; + rhs.completion_count -= min_count; + } + + fn diff(&mut self, cap: usize, rhs: &mut DmaIndex) -> isize { + Self::normalize(self, rhs); + (self.completion_count * cap + self.pos) as isize - (rhs.completion_count * cap + rhs.pos) as isize + } +} + +pub struct ReadableDmaRingBuffer<'a, W: Word> { + dma_buf: &'a mut [W], + write_index: DmaIndex, + read_index: DmaIndex, +} + +impl<'a, W: Word> ReadableDmaRingBuffer<'a, W> { + /// Construct an empty buffer. + pub fn new(dma_buf: &'a mut [W]) -> Self { + Self { + dma_buf, + write_index: Default::default(), + read_index: Default::default(), + } + } + + /// Reset the ring buffer to its initial state + pub fn clear(&mut self, dma: &mut impl DmaCtrl) { + dma.reset_complete_count(); + self.write_index.reset(); + self.update_dma_index(dma); + self.read_index = self.write_index; + } + + /// The capacity of the ringbuffer + pub const fn cap(&self) -> usize { + self.dma_buf.len() + } + + /// Read elements from the ring buffer + /// Return a tuple of the length read and the length remaining in the buffer + /// If not all of the elements were read, then there will be some elements in the buffer remaining + /// The length remaining is the capacity, ring_buf.len(), less the elements remaining after the read + /// OverrunError is returned if the portion to be read was overwritten by the DMA controller. + pub fn read(&mut self, dma: &mut impl DmaCtrl, buf: &mut [W]) -> Result<(usize, usize), OverrunError> { + let readable = self.margin(dma)?.min(buf.len()); + for i in 0..readable { + buf[i] = self.read_buf(i); + } + let available = self.margin(dma)?; + self.read_index.advance(self.cap(), readable); + Ok((readable, available - readable)) + } + + /// Read an exact number of elements from the ringbuffer. + /// + /// Returns the remaining number of elements available for immediate reading. + /// OverrunError is returned if the portion to be read was overwritten by the DMA controller. + /// + /// Async/Wake Behavior: + /// The underlying DMA peripheral only can wake us when its buffer pointer has reached the halfway point, + /// and when it wraps around. This means that when called with a buffer of length 'M', when this + /// ring buffer was created with a buffer of size 'N': + /// - If M equals N/2 or N/2 divides evenly into M, this function will return every N/2 elements read on the DMA source. + /// - Otherwise, this function may need up to N/2 extra elements to arrive before returning. + pub async fn read_exact(&mut self, dma: &mut impl DmaCtrl, buffer: &mut [W]) -> Result { + let mut read_data = 0; + let buffer_len = buffer.len(); + + poll_fn(|cx| { + dma.set_waker(cx.waker()); + + match self.read(dma, &mut buffer[read_data..buffer_len]) { + Ok((len, remaining)) => { + read_data += len; + if read_data == buffer_len { + Poll::Ready(Ok(remaining)) + } else { + Poll::Pending + } + } + Err(e) => Poll::Ready(Err(e)), + } + }) + .await + } + + fn update_dma_index(&mut self, dma: &mut impl DmaCtrl) { + self.write_index.dma_sync(self.cap(), dma) + } + + fn read_buf(&self, offset: usize) -> W { + unsafe { + core::ptr::read_volatile( + self.dma_buf + .as_ptr() + .offset(self.read_index.as_index(self.cap(), offset) as isize), + ) + } + } + + /// Returns available dma samples + fn margin(&mut self, dma: &mut impl DmaCtrl) -> Result { + self.update_dma_index(dma); + + let diff: usize = self + .write_index + .diff(self.cap(), &mut self.read_index) + .try_into() + .unwrap(); + + if diff > self.cap() { + Err(OverrunError) + } else { + Ok(diff) + } + } +} + +pub struct WritableDmaRingBuffer<'a, W: Word> { + dma_buf: &'a mut [W], + read_index: DmaIndex, + write_index: DmaIndex, +} + +impl<'a, W: Word> WritableDmaRingBuffer<'a, W> { + /// Construct a ringbuffer filled with the given buffer data. + pub fn new(dma_buf: &'a mut [W]) -> Self { + let len = dma_buf.len(); + Self { + dma_buf, + read_index: Default::default(), + write_index: DmaIndex { + completion_count: 0, + pos: len, + }, + } + } + + /// Reset the ring buffer to its initial state. The buffer after the reset will be full. + pub fn clear(&mut self, dma: &mut impl DmaCtrl) { + dma.reset_complete_count(); + self.read_index.reset(); + self.update_dma_index(dma); + self.write_index = self.read_index; + self.write_index.advance(self.cap(), self.cap()); + } + + /// Get the capacity of the ringbuffer. + pub const fn cap(&self) -> usize { + self.dma_buf.len() + } + + /// Append data to the ring buffer. + /// Returns a tuple of the data written and the remaining write capacity in the buffer. + pub fn write(&mut self, dma: &mut impl DmaCtrl, buf: &[W]) -> Result<(usize, usize), OverrunError> { + let writable = self.margin(dma)?.min(buf.len()); + for i in 0..writable { + self.write_buf(i, buf[i]); + } + let available = self.margin(dma)?; + self.write_index.advance(self.cap(), writable); + Ok((writable, available - writable)) + } + + /// Write elements directly to the buffer. + pub fn write_immediate(&mut self, buf: &[W]) -> Result<(usize, usize), OverrunError> { + for (i, data) in buf.iter().enumerate() { + self.write_buf(i, *data) + } + let written = buf.len().min(self.cap()); + Ok((written, self.cap() - written)) + } + + /// Write an exact number of elements to the ringbuffer. + pub async fn write_exact(&mut self, dma: &mut impl DmaCtrl, buffer: &[W]) -> Result { + let mut written_data = 0; + let buffer_len = buffer.len(); + + poll_fn(|cx| { + dma.set_waker(cx.waker()); + + match self.write(dma, &buffer[written_data..buffer_len]) { + Ok((len, remaining)) => { + written_data += len; + if written_data == buffer_len { + Poll::Ready(Ok(remaining)) + } else { + Poll::Pending + } + } + Err(e) => Poll::Ready(Err(e)), + } + }) + .await + } + + fn update_dma_index(&mut self, dma: &mut impl DmaCtrl) { + self.read_index.dma_sync(self.cap(), dma); + } + + fn write_buf(&mut self, offset: usize, value: W) { + unsafe { + core::ptr::write_volatile( + self.dma_buf + .as_mut_ptr() + .offset(self.write_index.as_index(self.cap(), offset) as isize), + value, + ) + } + } + + fn margin(&mut self, dma: &mut impl DmaCtrl) -> Result { + self.update_dma_index(dma); + + let diff = self.write_index.diff(self.cap(), &mut self.read_index); + + if diff < 0 { + Err(OverrunError) + } else { + Ok(self.cap().saturating_sub(diff as usize)) + } + } +} + +#[cfg(test)] +mod tests; diff --git a/embassy-stm32/src/dma/ringbuffer/tests/mod.rs b/embassy-stm32/src/dma/ringbuffer/tests/mod.rs new file mode 100644 index 000000000..9768e1df8 --- /dev/null +++ b/embassy-stm32/src/dma/ringbuffer/tests/mod.rs @@ -0,0 +1,165 @@ +use std::{cell, vec}; + +use super::*; + +#[allow(dead_code)] +#[derive(PartialEq, Debug)] +enum TestCircularTransferRequest { + ResetCompleteCount(usize), + PositionRequest(usize), +} + +struct TestCircularTransfer { + len: usize, + requests: cell::RefCell>, +} + +impl DmaCtrl for TestCircularTransfer { + fn get_remaining_transfers(&self) -> usize { + match self.requests.borrow_mut().pop().unwrap() { + TestCircularTransferRequest::PositionRequest(pos) => { + let len = self.len; + + assert!(len >= pos); + + len - pos + } + _ => unreachable!(), + } + } + + fn reset_complete_count(&mut self) -> usize { + match self.requests.get_mut().pop().unwrap() { + TestCircularTransferRequest::ResetCompleteCount(complete_count) => complete_count, + _ => unreachable!(), + } + } + + fn set_waker(&mut self, _waker: &Waker) {} +} + +impl TestCircularTransfer { + pub fn new(len: usize) -> Self { + Self { + requests: cell::RefCell::new(vec![]), + len, + } + } + + pub fn setup(&self, mut requests: vec::Vec) { + requests.reverse(); + self.requests.replace(requests); + } +} + +const CAP: usize = 16; + +#[test] +fn dma_index_dma_sync_syncs_position_to_last_read_if_sync_takes_place_on_same_dma_cycle() { + let mut dma = TestCircularTransfer::new(CAP); + dma.setup(vec![ + TestCircularTransferRequest::PositionRequest(4), + TestCircularTransferRequest::ResetCompleteCount(0), + TestCircularTransferRequest::PositionRequest(7), + ]); + let mut index = DmaIndex::default(); + index.dma_sync(CAP, &mut dma); + assert_eq!(index.completion_count, 0); + assert_eq!(index.pos, 7); +} + +#[test] +fn dma_index_dma_sync_updates_completion_count_properly_if_sync_takes_place_on_same_dma_cycle() { + let mut dma = TestCircularTransfer::new(CAP); + dma.setup(vec![ + TestCircularTransferRequest::PositionRequest(4), + TestCircularTransferRequest::ResetCompleteCount(2), + TestCircularTransferRequest::PositionRequest(7), + ]); + let mut index = DmaIndex::default(); + index.completion_count = 1; + index.dma_sync(CAP, &mut dma); + assert_eq!(index.completion_count, 3); + assert_eq!(index.pos, 7); +} + +#[test] +fn dma_index_dma_sync_syncs_to_last_position_if_reads_occur_on_different_dma_cycles() { + let mut dma = TestCircularTransfer::new(CAP); + dma.setup(vec![ + TestCircularTransferRequest::PositionRequest(10), + TestCircularTransferRequest::ResetCompleteCount(1), + TestCircularTransferRequest::PositionRequest(5), + TestCircularTransferRequest::ResetCompleteCount(0), + ]); + let mut index = DmaIndex::default(); + index.dma_sync(CAP, &mut dma); + assert_eq!(index.completion_count, 1); + assert_eq!(index.pos, 5); +} + +#[test] +fn dma_index_dma_sync_detects_new_cycle_if_later_position_is_less_than_first_and_first_completion_count_occurs_on_first_cycle( +) { + let mut dma = TestCircularTransfer::new(CAP); + dma.setup(vec![ + TestCircularTransferRequest::PositionRequest(10), + TestCircularTransferRequest::ResetCompleteCount(1), + TestCircularTransferRequest::PositionRequest(5), + TestCircularTransferRequest::ResetCompleteCount(1), + ]); + let mut index = DmaIndex::default(); + index.completion_count = 1; + index.dma_sync(CAP, &mut dma); + assert_eq!(index.completion_count, 3); + assert_eq!(index.pos, 5); +} + +#[test] +fn dma_index_dma_sync_detects_new_cycle_if_later_position_is_less_than_first_and_first_completion_count_occurs_on_later_cycle( +) { + let mut dma = TestCircularTransfer::new(CAP); + dma.setup(vec![ + TestCircularTransferRequest::PositionRequest(10), + TestCircularTransferRequest::ResetCompleteCount(2), + TestCircularTransferRequest::PositionRequest(5), + TestCircularTransferRequest::ResetCompleteCount(0), + ]); + let mut index = DmaIndex::default(); + index.completion_count = 1; + index.dma_sync(CAP, &mut dma); + assert_eq!(index.completion_count, 3); + assert_eq!(index.pos, 5); +} + +#[test] +fn dma_index_as_index_returns_index_mod_cap_by_default() { + let index = DmaIndex::default(); + assert_eq!(index.as_index(CAP, 0), 0); + assert_eq!(index.as_index(CAP, 1), 1); + assert_eq!(index.as_index(CAP, 2), 2); + assert_eq!(index.as_index(CAP, 3), 3); + assert_eq!(index.as_index(CAP, 4), 4); + assert_eq!(index.as_index(CAP, CAP), 0); + assert_eq!(index.as_index(CAP, CAP + 1), 1); +} + +#[test] +fn dma_index_advancing_increases_as_index() { + let mut index = DmaIndex::default(); + assert_eq!(index.as_index(CAP, 0), 0); + index.advance(CAP, 1); + assert_eq!(index.as_index(CAP, 0), 1); + index.advance(CAP, 1); + assert_eq!(index.as_index(CAP, 0), 2); + index.advance(CAP, 1); + assert_eq!(index.as_index(CAP, 0), 3); + index.advance(CAP, 1); + assert_eq!(index.as_index(CAP, 0), 4); + index.advance(CAP, CAP - 4); + assert_eq!(index.as_index(CAP, 0), 0); + index.advance(CAP, 1); + assert_eq!(index.as_index(CAP, 0), 1); +} + +mod prop_test; diff --git a/embassy-stm32/src/dma/ringbuffer/tests/prop_test/mod.rs b/embassy-stm32/src/dma/ringbuffer/tests/prop_test/mod.rs new file mode 100644 index 000000000..661fb1728 --- /dev/null +++ b/embassy-stm32/src/dma/ringbuffer/tests/prop_test/mod.rs @@ -0,0 +1,50 @@ +use std::task::Waker; + +use proptest::prop_oneof; +use proptest::strategy::{self, BoxedStrategy, Strategy as _}; +use proptest_state_machine::{prop_state_machine, ReferenceStateMachine, StateMachineTest}; + +use super::*; + +const CAP: usize = 128; + +#[derive(Debug, Default)] +struct DmaMock { + pos: usize, + wraps: usize, +} + +impl DmaMock { + pub fn advance(&mut self, steps: usize) { + let next = self.pos + steps; + self.pos = next % CAP; + self.wraps += next / CAP; + } +} + +impl DmaCtrl for DmaMock { + fn get_remaining_transfers(&self) -> usize { + CAP - self.pos + } + + fn reset_complete_count(&mut self) -> usize { + core::mem::replace(&mut self.wraps, 0) + } + + fn set_waker(&mut self, _waker: &Waker) {} +} + +#[derive(Debug, Clone)] +enum Status { + Available(usize), + Failed, +} + +impl Status { + pub fn new(capacity: usize) -> Self { + Self::Available(capacity) + } +} + +mod reader; +mod writer; diff --git a/embassy-stm32/src/dma/ringbuffer/tests/prop_test/reader.rs b/embassy-stm32/src/dma/ringbuffer/tests/prop_test/reader.rs new file mode 100644 index 000000000..6555ebfb0 --- /dev/null +++ b/embassy-stm32/src/dma/ringbuffer/tests/prop_test/reader.rs @@ -0,0 +1,122 @@ +use core::fmt::Debug; + +use super::*; + +#[derive(Debug, Clone)] +enum ReaderTransition { + Write(usize), + Clear, + ReadUpTo(usize), +} + +struct ReaderSM; + +impl ReferenceStateMachine for ReaderSM { + type State = Status; + type Transition = ReaderTransition; + + fn init_state() -> BoxedStrategy { + strategy::Just(Status::new(0)).boxed() + } + + fn transitions(_state: &Self::State) -> BoxedStrategy { + prop_oneof![ + (1..50_usize).prop_map(ReaderTransition::Write), + (1..50_usize).prop_map(ReaderTransition::ReadUpTo), + strategy::Just(ReaderTransition::Clear), + ] + .boxed() + } + + fn apply(status: Self::State, transition: &Self::Transition) -> Self::State { + match (status, transition) { + (_, ReaderTransition::Clear) => Status::Available(0), + (Status::Available(x), ReaderTransition::Write(y)) => { + if x + y > CAP { + Status::Failed + } else { + Status::Available(x + y) + } + } + (Status::Available(x), ReaderTransition::ReadUpTo(y)) => Status::Available(x.saturating_sub(*y)), + (Status::Failed, _) => Status::Failed, + } + } +} + +struct ReaderSut { + status: Status, + buffer: *mut [u8], + producer: DmaMock, + consumer: ReadableDmaRingBuffer<'static, u8>, +} + +impl Debug for ReaderSut { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + ::fmt(&self.producer, f) + } +} + +struct ReaderTest; + +impl StateMachineTest for ReaderTest { + type SystemUnderTest = ReaderSut; + type Reference = ReaderSM; + + fn init_test(ref_status: &::State) -> Self::SystemUnderTest { + let buffer = Box::into_raw(Box::new([0; CAP])); + ReaderSut { + status: ref_status.clone(), + buffer, + producer: DmaMock::default(), + consumer: ReadableDmaRingBuffer::new(unsafe { &mut *buffer }), + } + } + + fn teardown(state: Self::SystemUnderTest) { + unsafe { + let _ = Box::from_raw(state.buffer); + }; + } + + fn apply( + mut sut: Self::SystemUnderTest, + ref_state: &::State, + transition: ::Transition, + ) -> Self::SystemUnderTest { + match transition { + ReaderTransition::Write(x) => sut.producer.advance(x), + ReaderTransition::Clear => { + sut.consumer.clear(&mut sut.producer); + } + ReaderTransition::ReadUpTo(x) => { + let status = sut.status; + let ReaderSut { + ref mut producer, + ref mut consumer, + .. + } = sut; + let mut buf = vec![0; x]; + let res = consumer.read(producer, &mut buf); + match status { + Status::Available(n) => { + let readable = x.min(n); + + assert_eq!(res.unwrap().0, readable); + } + Status::Failed => assert!(res.is_err()), + } + } + } + + ReaderSut { + status: ref_state.clone(), + ..sut + } + } +} + +prop_state_machine! { + #[test] + fn reader_state_test(sequential 1..20 => ReaderTest); +} diff --git a/embassy-stm32/src/dma/ringbuffer/tests/prop_test/writer.rs b/embassy-stm32/src/dma/ringbuffer/tests/prop_test/writer.rs new file mode 100644 index 000000000..15f54c672 --- /dev/null +++ b/embassy-stm32/src/dma/ringbuffer/tests/prop_test/writer.rs @@ -0,0 +1,121 @@ +use core::fmt::Debug; + +use super::*; + +#[derive(Debug, Clone)] +enum WriterTransition { + Read(usize), + WriteUpTo(usize), + Clear, +} + +struct WriterSM; + +impl ReferenceStateMachine for WriterSM { + type State = Status; + type Transition = WriterTransition; + + fn init_state() -> BoxedStrategy { + strategy::Just(Status::new(CAP)).boxed() + } + + fn transitions(_state: &Self::State) -> BoxedStrategy { + prop_oneof![ + (1..50_usize).prop_map(WriterTransition::Read), + (1..50_usize).prop_map(WriterTransition::WriteUpTo), + strategy::Just(WriterTransition::Clear), + ] + .boxed() + } + + fn apply(status: Self::State, transition: &Self::Transition) -> Self::State { + match (status, transition) { + (_, WriterTransition::Clear) => Status::Available(CAP), + (Status::Available(x), WriterTransition::Read(y)) => { + if x < *y { + Status::Failed + } else { + Status::Available(x - y) + } + } + (Status::Available(x), WriterTransition::WriteUpTo(y)) => Status::Available((x + *y).min(CAP)), + (Status::Failed, _) => Status::Failed, + } + } +} + +struct WriterSut { + status: Status, + buffer: *mut [u8], + producer: WritableDmaRingBuffer<'static, u8>, + consumer: DmaMock, +} + +impl Debug for WriterSut { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + ::fmt(&self.consumer, f) + } +} + +struct WriterTest; + +impl StateMachineTest for WriterTest { + type SystemUnderTest = WriterSut; + type Reference = WriterSM; + + fn init_test(ref_status: &::State) -> Self::SystemUnderTest { + let buffer = Box::into_raw(Box::new([0; CAP])); + WriterSut { + status: ref_status.clone(), + buffer, + producer: WritableDmaRingBuffer::new(unsafe { &mut *buffer }), + consumer: DmaMock::default(), + } + } + + fn teardown(state: Self::SystemUnderTest) { + unsafe { + let _ = Box::from_raw(state.buffer); + }; + } + + fn apply( + mut sut: Self::SystemUnderTest, + ref_status: &::State, + transition: ::Transition, + ) -> Self::SystemUnderTest { + match transition { + WriterTransition::Read(x) => sut.consumer.advance(x), + WriterTransition::Clear => { + sut.producer.clear(&mut sut.consumer); + } + WriterTransition::WriteUpTo(x) => { + let status = sut.status; + let WriterSut { + ref mut producer, + ref mut consumer, + .. + } = sut; + let mut buf = vec![0; x]; + let res = producer.write(consumer, &mut buf); + match status { + Status::Available(n) => { + let writable = x.min(CAP - n.min(CAP)); + assert_eq!(res.unwrap().0, writable); + } + Status::Failed => assert!(res.is_err()), + } + } + } + + WriterSut { + status: ref_status.clone(), + ..sut + } + } +} + +prop_state_machine! { + #[test] + fn writer_state_test(sequential 1..20 => WriterTest); +} From f4ec0cb4d4d16bd4e1c242864c5ca828745704c0 Mon Sep 17 00:00:00 2001 From: Alexandros Liarokapis Date: Mon, 23 Sep 2024 02:01:44 +0300 Subject: [PATCH 0224/1217] simplify and rename ringbuffer methods, make len available --- embassy-stm32/src/dma/ringbuffer/mod.rs | 92 ++++++++++++------------- 1 file changed, 43 insertions(+), 49 deletions(-) diff --git a/embassy-stm32/src/dma/ringbuffer/mod.rs b/embassy-stm32/src/dma/ringbuffer/mod.rs index 10a9ff975..d4d119a69 100644 --- a/embassy-stm32/src/dma/ringbuffer/mod.rs +++ b/embassy-stm32/src/dma/ringbuffer/mod.rs @@ -27,10 +27,6 @@ struct DmaIndex { pos: usize, } -fn pos(cap: usize, dma: &impl DmaCtrl) -> usize { - cap - dma.get_remaining_transfers() -} - impl DmaIndex { fn reset(&mut self) { self.pos = 0; @@ -42,9 +38,9 @@ impl DmaIndex { } fn dma_sync(&mut self, cap: usize, dma: &mut impl DmaCtrl) { - let fst_pos = pos(cap, dma); + let fst_pos = cap - dma.get_remaining_transfers(); let fst_count = dma.reset_complete_count(); - let pos = pos(cap, dma); + let pos = cap - dma.get_remaining_transfers(); let wrap_count = if pos >= fst_pos { fst_count @@ -68,8 +64,7 @@ impl DmaIndex { rhs.completion_count -= min_count; } - fn diff(&mut self, cap: usize, rhs: &mut DmaIndex) -> isize { - Self::normalize(self, rhs); + fn diff(&self, cap: usize, rhs: &DmaIndex) -> isize { (self.completion_count * cap + self.pos) as isize - (rhs.completion_count * cap + rhs.pos) as isize } } @@ -94,26 +89,39 @@ impl<'a, W: Word> ReadableDmaRingBuffer<'a, W> { pub fn clear(&mut self, dma: &mut impl DmaCtrl) { dma.reset_complete_count(); self.write_index.reset(); - self.update_dma_index(dma); + self.write_index.dma_sync(self.cap(), dma); self.read_index = self.write_index; } - /// The capacity of the ringbuffer + /// Get the full ringbuffer capacity. pub const fn cap(&self) -> usize { self.dma_buf.len() } + /// Get the available readable dma samples. + pub fn len(&self) -> Result { + let diff: usize = self.write_index.diff(self.cap(), &self.read_index).try_into().unwrap(); + + if diff > self.cap() { + Err(OverrunError) + } else { + Ok(diff) + } + } + /// Read elements from the ring buffer /// Return a tuple of the length read and the length remaining in the buffer /// If not all of the elements were read, then there will be some elements in the buffer remaining /// The length remaining is the capacity, ring_buf.len(), less the elements remaining after the read /// OverrunError is returned if the portion to be read was overwritten by the DMA controller. pub fn read(&mut self, dma: &mut impl DmaCtrl, buf: &mut [W]) -> Result<(usize, usize), OverrunError> { - let readable = self.margin(dma)?.min(buf.len()); + self.sync_write_index(dma); + let readable = self.len()?.min(buf.len()); for i in 0..readable { buf[i] = self.read_buf(i); } - let available = self.margin(dma)?; + self.sync_write_index(dma); + let available = self.len()?; self.read_index.advance(self.cap(), readable); Ok((readable, available - readable)) } @@ -151,10 +159,6 @@ impl<'a, W: Word> ReadableDmaRingBuffer<'a, W> { .await } - fn update_dma_index(&mut self, dma: &mut impl DmaCtrl) { - self.write_index.dma_sync(self.cap(), dma) - } - fn read_buf(&self, offset: usize) -> W { unsafe { core::ptr::read_volatile( @@ -165,21 +169,9 @@ impl<'a, W: Word> ReadableDmaRingBuffer<'a, W> { } } - /// Returns available dma samples - fn margin(&mut self, dma: &mut impl DmaCtrl) -> Result { - self.update_dma_index(dma); - - let diff: usize = self - .write_index - .diff(self.cap(), &mut self.read_index) - .try_into() - .unwrap(); - - if diff > self.cap() { - Err(OverrunError) - } else { - Ok(diff) - } + fn sync_write_index(&mut self, dma: &mut impl DmaCtrl) { + self.write_index.dma_sync(self.cap(), dma); + DmaIndex::normalize(&mut self.write_index, &mut self.read_index); } } @@ -207,12 +199,23 @@ impl<'a, W: Word> WritableDmaRingBuffer<'a, W> { pub fn clear(&mut self, dma: &mut impl DmaCtrl) { dma.reset_complete_count(); self.read_index.reset(); - self.update_dma_index(dma); + self.read_index.dma_sync(self.cap(), dma); self.write_index = self.read_index; self.write_index.advance(self.cap(), self.cap()); } - /// Get the capacity of the ringbuffer. + /// Get the remaining writable dma samples. + pub fn len(&self) -> Result { + let diff = self.write_index.diff(self.cap(), &self.read_index); + + if diff < 0 { + Err(OverrunError) + } else { + Ok(self.cap().saturating_sub(diff as usize)) + } + } + + /// Get the full ringbuffer capacity. pub const fn cap(&self) -> usize { self.dma_buf.len() } @@ -220,11 +223,13 @@ impl<'a, W: Word> WritableDmaRingBuffer<'a, W> { /// Append data to the ring buffer. /// Returns a tuple of the data written and the remaining write capacity in the buffer. pub fn write(&mut self, dma: &mut impl DmaCtrl, buf: &[W]) -> Result<(usize, usize), OverrunError> { - let writable = self.margin(dma)?.min(buf.len()); + self.sync_read_index(dma); + let writable = self.len()?.min(buf.len()); for i in 0..writable { self.write_buf(i, buf[i]); } - let available = self.margin(dma)?; + self.sync_read_index(dma); + let available = self.len()?; self.write_index.advance(self.cap(), writable); Ok((writable, available - writable)) } @@ -261,10 +266,6 @@ impl<'a, W: Word> WritableDmaRingBuffer<'a, W> { .await } - fn update_dma_index(&mut self, dma: &mut impl DmaCtrl) { - self.read_index.dma_sync(self.cap(), dma); - } - fn write_buf(&mut self, offset: usize, value: W) { unsafe { core::ptr::write_volatile( @@ -276,16 +277,9 @@ impl<'a, W: Word> WritableDmaRingBuffer<'a, W> { } } - fn margin(&mut self, dma: &mut impl DmaCtrl) -> Result { - self.update_dma_index(dma); - - let diff = self.write_index.diff(self.cap(), &mut self.read_index); - - if diff < 0 { - Err(OverrunError) - } else { - Ok(self.cap().saturating_sub(diff as usize)) - } + fn sync_read_index(&mut self, dma: &mut impl DmaCtrl) { + self.read_index.dma_sync(self.cap(), dma); + DmaIndex::normalize(&mut self.read_index, &mut self.write_index); } } From 85fb890b0025db386459f8b6a573c29f00bf3ed1 Mon Sep 17 00:00:00 2001 From: Alexandros Liarokapis Date: Mon, 23 Sep 2024 02:49:05 +0300 Subject: [PATCH 0225/1217] add auto-clear functionality to ringbuffer --- embassy-stm32/src/dma/ringbuffer/mod.rs | 56 ++++++++++++------- .../dma/ringbuffer/tests/prop_test/reader.rs | 3 +- .../dma/ringbuffer/tests/prop_test/writer.rs | 3 +- 3 files changed, 40 insertions(+), 22 deletions(-) diff --git a/embassy-stm32/src/dma/ringbuffer/mod.rs b/embassy-stm32/src/dma/ringbuffer/mod.rs index d4d119a69..abc01e3cc 100644 --- a/embassy-stm32/src/dma/ringbuffer/mod.rs +++ b/embassy-stm32/src/dma/ringbuffer/mod.rs @@ -85,7 +85,7 @@ impl<'a, W: Word> ReadableDmaRingBuffer<'a, W> { } } - /// Reset the ring buffer to its initial state + /// Reset the ring buffer to its initial state. pub fn clear(&mut self, dma: &mut impl DmaCtrl) { dma.reset_complete_count(); self.write_index.reset(); @@ -113,17 +113,12 @@ impl<'a, W: Word> ReadableDmaRingBuffer<'a, W> { /// Return a tuple of the length read and the length remaining in the buffer /// If not all of the elements were read, then there will be some elements in the buffer remaining /// The length remaining is the capacity, ring_buf.len(), less the elements remaining after the read - /// OverrunError is returned if the portion to be read was overwritten by the DMA controller. + /// OverrunError is returned if the portion to be read was overwritten by the DMA controller, + /// in which case the rinbuffer will automatically clear itself. pub fn read(&mut self, dma: &mut impl DmaCtrl, buf: &mut [W]) -> Result<(usize, usize), OverrunError> { - self.sync_write_index(dma); - let readable = self.len()?.min(buf.len()); - for i in 0..readable { - buf[i] = self.read_buf(i); - } - self.sync_write_index(dma); - let available = self.len()?; - self.read_index.advance(self.cap(), readable); - Ok((readable, available - readable)) + self.read_raw(dma, buf).inspect_err(|_e| { + self.clear(dma); + }) } /// Read an exact number of elements from the ringbuffer. @@ -159,6 +154,18 @@ impl<'a, W: Word> ReadableDmaRingBuffer<'a, W> { .await } + fn read_raw(&mut self, dma: &mut impl DmaCtrl, buf: &mut [W]) -> Result<(usize, usize), OverrunError> { + self.sync_write_index(dma); + let readable = self.len()?.min(buf.len()); + for i in 0..readable { + buf[i] = self.read_buf(i); + } + self.sync_write_index(dma); + let available = self.len()?; + self.read_index.advance(self.cap(), readable); + Ok((readable, available - readable)) + } + fn read_buf(&self, offset: usize) -> W { unsafe { core::ptr::read_volatile( @@ -222,16 +229,13 @@ impl<'a, W: Word> WritableDmaRingBuffer<'a, W> { /// Append data to the ring buffer. /// Returns a tuple of the data written and the remaining write capacity in the buffer. + /// OverrunError is returned if the portion to be written was previously read by the DMA controller. + /// In this case, the ringbuffer will automatically reset itself, giving a full buffer worth of + /// leeway between the write index and the DMA. pub fn write(&mut self, dma: &mut impl DmaCtrl, buf: &[W]) -> Result<(usize, usize), OverrunError> { - self.sync_read_index(dma); - let writable = self.len()?.min(buf.len()); - for i in 0..writable { - self.write_buf(i, buf[i]); - } - self.sync_read_index(dma); - let available = self.len()?; - self.write_index.advance(self.cap(), writable); - Ok((writable, available - writable)) + self.write_raw(dma, buf).inspect_err(|_e| { + self.clear(dma); + }) } /// Write elements directly to the buffer. @@ -266,6 +270,18 @@ impl<'a, W: Word> WritableDmaRingBuffer<'a, W> { .await } + pub fn write_raw(&mut self, dma: &mut impl DmaCtrl, buf: &[W]) -> Result<(usize, usize), OverrunError> { + self.sync_read_index(dma); + let writable = self.len()?.min(buf.len()); + for i in 0..writable { + self.write_buf(i, buf[i]); + } + self.sync_read_index(dma); + let available = self.len()?; + self.write_index.advance(self.cap(), writable); + Ok((writable, available - writable)) + } + fn write_buf(&mut self, offset: usize, value: W) { unsafe { core::ptr::write_volatile( diff --git a/embassy-stm32/src/dma/ringbuffer/tests/prop_test/reader.rs b/embassy-stm32/src/dma/ringbuffer/tests/prop_test/reader.rs index 6555ebfb0..6e640a813 100644 --- a/embassy-stm32/src/dma/ringbuffer/tests/prop_test/reader.rs +++ b/embassy-stm32/src/dma/ringbuffer/tests/prop_test/reader.rs @@ -38,8 +38,9 @@ impl ReferenceStateMachine for ReaderSM { Status::Available(x + y) } } + (Status::Failed, ReaderTransition::Write(_)) => Status::Failed, (Status::Available(x), ReaderTransition::ReadUpTo(y)) => Status::Available(x.saturating_sub(*y)), - (Status::Failed, _) => Status::Failed, + (Status::Failed, ReaderTransition::ReadUpTo(_)) => Status::Available(0), } } } diff --git a/embassy-stm32/src/dma/ringbuffer/tests/prop_test/writer.rs b/embassy-stm32/src/dma/ringbuffer/tests/prop_test/writer.rs index 15f54c672..c1b3859b2 100644 --- a/embassy-stm32/src/dma/ringbuffer/tests/prop_test/writer.rs +++ b/embassy-stm32/src/dma/ringbuffer/tests/prop_test/writer.rs @@ -38,8 +38,9 @@ impl ReferenceStateMachine for WriterSM { Status::Available(x - y) } } + (Status::Failed, WriterTransition::Read(_)) => Status::Failed, (Status::Available(x), WriterTransition::WriteUpTo(y)) => Status::Available((x + *y).min(CAP)), - (Status::Failed, _) => Status::Failed, + (Status::Failed, WriterTransition::WriteUpTo(_)) => Status::Available(CAP), } } } From 82712252166a274c1499c3680b63f86cdfbb8dfb Mon Sep 17 00:00:00 2001 From: Alexandros Liarokapis Date: Mon, 23 Sep 2024 16:50:26 +0300 Subject: [PATCH 0226/1217] make len method take mut self and remove sync index calls --- embassy-stm32/src/dma/ringbuffer/mod.rs | 32 ++++++++++--------------- 1 file changed, 12 insertions(+), 20 deletions(-) diff --git a/embassy-stm32/src/dma/ringbuffer/mod.rs b/embassy-stm32/src/dma/ringbuffer/mod.rs index abc01e3cc..76f7f36ec 100644 --- a/embassy-stm32/src/dma/ringbuffer/mod.rs +++ b/embassy-stm32/src/dma/ringbuffer/mod.rs @@ -99,7 +99,10 @@ impl<'a, W: Word> ReadableDmaRingBuffer<'a, W> { } /// Get the available readable dma samples. - pub fn len(&self) -> Result { + pub fn len(&mut self, dma: &mut impl DmaCtrl) -> Result { + self.write_index.dma_sync(self.cap(), dma); + DmaIndex::normalize(&mut self.write_index, &mut self.read_index); + let diff: usize = self.write_index.diff(self.cap(), &self.read_index).try_into().unwrap(); if diff > self.cap() { @@ -155,13 +158,11 @@ impl<'a, W: Word> ReadableDmaRingBuffer<'a, W> { } fn read_raw(&mut self, dma: &mut impl DmaCtrl, buf: &mut [W]) -> Result<(usize, usize), OverrunError> { - self.sync_write_index(dma); - let readable = self.len()?.min(buf.len()); + let readable = self.len(dma)?.min(buf.len()); for i in 0..readable { buf[i] = self.read_buf(i); } - self.sync_write_index(dma); - let available = self.len()?; + let available = self.len(dma)?; self.read_index.advance(self.cap(), readable); Ok((readable, available - readable)) } @@ -175,11 +176,6 @@ impl<'a, W: Word> ReadableDmaRingBuffer<'a, W> { ) } } - - fn sync_write_index(&mut self, dma: &mut impl DmaCtrl) { - self.write_index.dma_sync(self.cap(), dma); - DmaIndex::normalize(&mut self.write_index, &mut self.read_index); - } } pub struct WritableDmaRingBuffer<'a, W: Word> { @@ -212,7 +208,10 @@ impl<'a, W: Word> WritableDmaRingBuffer<'a, W> { } /// Get the remaining writable dma samples. - pub fn len(&self) -> Result { + pub fn len(&mut self, dma: &mut impl DmaCtrl) -> Result { + self.read_index.dma_sync(self.cap(), dma); + DmaIndex::normalize(&mut self.read_index, &mut self.write_index); + let diff = self.write_index.diff(self.cap(), &self.read_index); if diff < 0 { @@ -271,13 +270,11 @@ impl<'a, W: Word> WritableDmaRingBuffer<'a, W> { } pub fn write_raw(&mut self, dma: &mut impl DmaCtrl, buf: &[W]) -> Result<(usize, usize), OverrunError> { - self.sync_read_index(dma); - let writable = self.len()?.min(buf.len()); + let writable = self.len(dma)?.min(buf.len()); for i in 0..writable { self.write_buf(i, buf[i]); } - self.sync_read_index(dma); - let available = self.len()?; + let available = self.len(dma)?; self.write_index.advance(self.cap(), writable); Ok((writable, available - writable)) } @@ -292,11 +289,6 @@ impl<'a, W: Word> WritableDmaRingBuffer<'a, W> { ) } } - - fn sync_read_index(&mut self, dma: &mut impl DmaCtrl) { - self.read_index.dma_sync(self.cap(), dma); - DmaIndex::normalize(&mut self.read_index, &mut self.write_index); - } } #[cfg(test)] From 9c7b296432af40ac44e5e65a3742c691f1414444 Mon Sep 17 00:00:00 2001 From: Alexandros Liarokapis Date: Tue, 24 Sep 2024 00:59:34 +0300 Subject: [PATCH 0227/1217] overrun at invalid diffs, rename clear to reset, simplify dma_sync method --- embassy-stm32/src/adc/ringbuffered_v2.rs | 3 +- embassy-stm32/src/dma/dma_bdma.rs | 4 +- embassy-stm32/src/dma/ringbuffer/mod.rs | 53 +++++++++---------- embassy-stm32/src/dma/ringbuffer/tests/mod.rs | 22 ++++---- .../dma/ringbuffer/tests/prop_test/reader.rs | 10 ++-- .../dma/ringbuffer/tests/prop_test/writer.rs | 10 ++-- 6 files changed, 49 insertions(+), 53 deletions(-) diff --git a/embassy-stm32/src/adc/ringbuffered_v2.rs b/embassy-stm32/src/adc/ringbuffered_v2.rs index 3b064044e..9fc233222 100644 --- a/embassy-stm32/src/adc/ringbuffered_v2.rs +++ b/embassy-stm32/src/adc/ringbuffered_v2.rs @@ -226,9 +226,8 @@ impl<'d, T: Instance> RingBufferedAdc<'d, T> { /// Turns on ADC if it is not already turned on and starts continuous DMA transfer. pub fn start(&mut self) -> Result<(), OverrunError> { - self.ring_buf.clear(); - self.setup_adc(); + self.ring_buf.clear(); Ok(()) } diff --git a/embassy-stm32/src/dma/dma_bdma.rs b/embassy-stm32/src/dma/dma_bdma.rs index a43137c6e..59ad4d988 100644 --- a/embassy-stm32/src/dma/dma_bdma.rs +++ b/embassy-stm32/src/dma/dma_bdma.rs @@ -833,7 +833,7 @@ impl<'a, W: Word> ReadableRingBuffer<'a, W> { /// Clear all data in the ring buffer. pub fn clear(&mut self) { - self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow())); + self.ringbuf.reset(&mut DmaCtrlImpl(self.channel.reborrow())); } /// Read elements from the ring buffer @@ -980,7 +980,7 @@ impl<'a, W: Word> WritableRingBuffer<'a, W> { /// Clear all data in the ring buffer. pub fn clear(&mut self) { - self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow())); + self.ringbuf.reset(&mut DmaCtrlImpl(self.channel.reborrow())); } /// Write elements directly to the raw buffer. diff --git a/embassy-stm32/src/dma/ringbuffer/mod.rs b/embassy-stm32/src/dma/ringbuffer/mod.rs index 76f7f36ec..eb64ad016 100644 --- a/embassy-stm32/src/dma/ringbuffer/mod.rs +++ b/embassy-stm32/src/dma/ringbuffer/mod.rs @@ -23,14 +23,14 @@ pub struct OverrunError; #[derive(Debug, Clone, Copy, Default)] struct DmaIndex { - completion_count: usize, + complete_count: usize, pos: usize, } impl DmaIndex { fn reset(&mut self) { self.pos = 0; - self.completion_count = 0; + self.complete_count = 0; } fn as_index(&self, cap: usize, offset: usize) -> usize { @@ -38,34 +38,31 @@ impl DmaIndex { } fn dma_sync(&mut self, cap: usize, dma: &mut impl DmaCtrl) { - let fst_pos = cap - dma.get_remaining_transfers(); - let fst_count = dma.reset_complete_count(); - let pos = cap - dma.get_remaining_transfers(); + let first_pos = cap - dma.get_remaining_transfers(); + self.complete_count += dma.reset_complete_count(); + self.pos = cap - dma.get_remaining_transfers(); - let wrap_count = if pos >= fst_pos { - fst_count - } else { - fst_count + dma.reset_complete_count() - }; - - self.pos = pos; - self.completion_count += wrap_count; + // If the latter call to get_remaining_transfers() returned a smaller value than the first, the dma + // has wrapped around between calls and we must check if the complete count also incremented. + if self.pos < first_pos { + self.complete_count += dma.reset_complete_count(); + } } fn advance(&mut self, cap: usize, steps: usize) { let next = self.pos + steps; - self.completion_count += next / cap; + self.complete_count += next / cap; self.pos = next % cap; } fn normalize(lhs: &mut DmaIndex, rhs: &mut DmaIndex) { - let min_count = lhs.completion_count.min(rhs.completion_count); - lhs.completion_count -= min_count; - rhs.completion_count -= min_count; + let min_count = lhs.complete_count.min(rhs.complete_count); + lhs.complete_count -= min_count; + rhs.complete_count -= min_count; } fn diff(&self, cap: usize, rhs: &DmaIndex) -> isize { - (self.completion_count * cap + self.pos) as isize - (rhs.completion_count * cap + rhs.pos) as isize + (self.complete_count * cap + self.pos) as isize - (rhs.complete_count * cap + rhs.pos) as isize } } @@ -86,7 +83,7 @@ impl<'a, W: Word> ReadableDmaRingBuffer<'a, W> { } /// Reset the ring buffer to its initial state. - pub fn clear(&mut self, dma: &mut impl DmaCtrl) { + pub fn reset(&mut self, dma: &mut impl DmaCtrl) { dma.reset_complete_count(); self.write_index.reset(); self.write_index.dma_sync(self.cap(), dma); @@ -103,12 +100,12 @@ impl<'a, W: Word> ReadableDmaRingBuffer<'a, W> { self.write_index.dma_sync(self.cap(), dma); DmaIndex::normalize(&mut self.write_index, &mut self.read_index); - let diff: usize = self.write_index.diff(self.cap(), &self.read_index).try_into().unwrap(); + let diff = self.write_index.diff(self.cap(), &self.read_index); - if diff > self.cap() { + if diff < 0 || diff > self.cap() as isize { Err(OverrunError) } else { - Ok(diff) + Ok(diff as usize) } } @@ -117,10 +114,10 @@ impl<'a, W: Word> ReadableDmaRingBuffer<'a, W> { /// If not all of the elements were read, then there will be some elements in the buffer remaining /// The length remaining is the capacity, ring_buf.len(), less the elements remaining after the read /// OverrunError is returned if the portion to be read was overwritten by the DMA controller, - /// in which case the rinbuffer will automatically clear itself. + /// in which case the rinbuffer will automatically reset itself. pub fn read(&mut self, dma: &mut impl DmaCtrl, buf: &mut [W]) -> Result<(usize, usize), OverrunError> { self.read_raw(dma, buf).inspect_err(|_e| { - self.clear(dma); + self.reset(dma); }) } @@ -192,14 +189,14 @@ impl<'a, W: Word> WritableDmaRingBuffer<'a, W> { dma_buf, read_index: Default::default(), write_index: DmaIndex { - completion_count: 0, + complete_count: 0, pos: len, }, } } /// Reset the ring buffer to its initial state. The buffer after the reset will be full. - pub fn clear(&mut self, dma: &mut impl DmaCtrl) { + pub fn reset(&mut self, dma: &mut impl DmaCtrl) { dma.reset_complete_count(); self.read_index.reset(); self.read_index.dma_sync(self.cap(), dma); @@ -214,7 +211,7 @@ impl<'a, W: Word> WritableDmaRingBuffer<'a, W> { let diff = self.write_index.diff(self.cap(), &self.read_index); - if diff < 0 { + if diff < 0 || diff > self.cap() as isize { Err(OverrunError) } else { Ok(self.cap().saturating_sub(diff as usize)) @@ -233,7 +230,7 @@ impl<'a, W: Word> WritableDmaRingBuffer<'a, W> { /// leeway between the write index and the DMA. pub fn write(&mut self, dma: &mut impl DmaCtrl, buf: &[W]) -> Result<(usize, usize), OverrunError> { self.write_raw(dma, buf).inspect_err(|_e| { - self.clear(dma); + self.reset(dma); }) } diff --git a/embassy-stm32/src/dma/ringbuffer/tests/mod.rs b/embassy-stm32/src/dma/ringbuffer/tests/mod.rs index 9768e1df8..1800eae69 100644 --- a/embassy-stm32/src/dma/ringbuffer/tests/mod.rs +++ b/embassy-stm32/src/dma/ringbuffer/tests/mod.rs @@ -64,12 +64,12 @@ fn dma_index_dma_sync_syncs_position_to_last_read_if_sync_takes_place_on_same_dm ]); let mut index = DmaIndex::default(); index.dma_sync(CAP, &mut dma); - assert_eq!(index.completion_count, 0); + assert_eq!(index.complete_count, 0); assert_eq!(index.pos, 7); } #[test] -fn dma_index_dma_sync_updates_completion_count_properly_if_sync_takes_place_on_same_dma_cycle() { +fn dma_index_dma_sync_updates_complete_count_properly_if_sync_takes_place_on_same_dma_cycle() { let mut dma = TestCircularTransfer::new(CAP); dma.setup(vec![ TestCircularTransferRequest::PositionRequest(4), @@ -77,9 +77,9 @@ fn dma_index_dma_sync_updates_completion_count_properly_if_sync_takes_place_on_s TestCircularTransferRequest::PositionRequest(7), ]); let mut index = DmaIndex::default(); - index.completion_count = 1; + index.complete_count = 1; index.dma_sync(CAP, &mut dma); - assert_eq!(index.completion_count, 3); + assert_eq!(index.complete_count, 3); assert_eq!(index.pos, 7); } @@ -94,12 +94,12 @@ fn dma_index_dma_sync_syncs_to_last_position_if_reads_occur_on_different_dma_cyc ]); let mut index = DmaIndex::default(); index.dma_sync(CAP, &mut dma); - assert_eq!(index.completion_count, 1); + assert_eq!(index.complete_count, 1); assert_eq!(index.pos, 5); } #[test] -fn dma_index_dma_sync_detects_new_cycle_if_later_position_is_less_than_first_and_first_completion_count_occurs_on_first_cycle( +fn dma_index_dma_sync_detects_new_cycle_if_later_position_is_less_than_first_and_first_complete_count_occurs_on_first_cycle( ) { let mut dma = TestCircularTransfer::new(CAP); dma.setup(vec![ @@ -109,14 +109,14 @@ fn dma_index_dma_sync_detects_new_cycle_if_later_position_is_less_than_first_and TestCircularTransferRequest::ResetCompleteCount(1), ]); let mut index = DmaIndex::default(); - index.completion_count = 1; + index.complete_count = 1; index.dma_sync(CAP, &mut dma); - assert_eq!(index.completion_count, 3); + assert_eq!(index.complete_count, 3); assert_eq!(index.pos, 5); } #[test] -fn dma_index_dma_sync_detects_new_cycle_if_later_position_is_less_than_first_and_first_completion_count_occurs_on_later_cycle( +fn dma_index_dma_sync_detects_new_cycle_if_later_position_is_less_than_first_and_first_complete_count_occurs_on_later_cycle( ) { let mut dma = TestCircularTransfer::new(CAP); dma.setup(vec![ @@ -126,9 +126,9 @@ fn dma_index_dma_sync_detects_new_cycle_if_later_position_is_less_than_first_and TestCircularTransferRequest::ResetCompleteCount(0), ]); let mut index = DmaIndex::default(); - index.completion_count = 1; + index.complete_count = 1; index.dma_sync(CAP, &mut dma); - assert_eq!(index.completion_count, 3); + assert_eq!(index.complete_count, 3); assert_eq!(index.pos, 5); } diff --git a/embassy-stm32/src/dma/ringbuffer/tests/prop_test/reader.rs b/embassy-stm32/src/dma/ringbuffer/tests/prop_test/reader.rs index 6e640a813..4f3957a68 100644 --- a/embassy-stm32/src/dma/ringbuffer/tests/prop_test/reader.rs +++ b/embassy-stm32/src/dma/ringbuffer/tests/prop_test/reader.rs @@ -5,7 +5,7 @@ use super::*; #[derive(Debug, Clone)] enum ReaderTransition { Write(usize), - Clear, + Reset, ReadUpTo(usize), } @@ -23,14 +23,14 @@ impl ReferenceStateMachine for ReaderSM { prop_oneof![ (1..50_usize).prop_map(ReaderTransition::Write), (1..50_usize).prop_map(ReaderTransition::ReadUpTo), - strategy::Just(ReaderTransition::Clear), + strategy::Just(ReaderTransition::Reset), ] .boxed() } fn apply(status: Self::State, transition: &Self::Transition) -> Self::State { match (status, transition) { - (_, ReaderTransition::Clear) => Status::Available(0), + (_, ReaderTransition::Reset) => Status::Available(0), (Status::Available(x), ReaderTransition::Write(y)) => { if x + y > CAP { Status::Failed @@ -87,8 +87,8 @@ impl StateMachineTest for ReaderTest { ) -> Self::SystemUnderTest { match transition { ReaderTransition::Write(x) => sut.producer.advance(x), - ReaderTransition::Clear => { - sut.consumer.clear(&mut sut.producer); + ReaderTransition::Reset => { + sut.consumer.reset(&mut sut.producer); } ReaderTransition::ReadUpTo(x) => { let status = sut.status; diff --git a/embassy-stm32/src/dma/ringbuffer/tests/prop_test/writer.rs b/embassy-stm32/src/dma/ringbuffer/tests/prop_test/writer.rs index c1b3859b2..15433c0ee 100644 --- a/embassy-stm32/src/dma/ringbuffer/tests/prop_test/writer.rs +++ b/embassy-stm32/src/dma/ringbuffer/tests/prop_test/writer.rs @@ -6,7 +6,7 @@ use super::*; enum WriterTransition { Read(usize), WriteUpTo(usize), - Clear, + Reset, } struct WriterSM; @@ -23,14 +23,14 @@ impl ReferenceStateMachine for WriterSM { prop_oneof![ (1..50_usize).prop_map(WriterTransition::Read), (1..50_usize).prop_map(WriterTransition::WriteUpTo), - strategy::Just(WriterTransition::Clear), + strategy::Just(WriterTransition::Reset), ] .boxed() } fn apply(status: Self::State, transition: &Self::Transition) -> Self::State { match (status, transition) { - (_, WriterTransition::Clear) => Status::Available(CAP), + (_, WriterTransition::Reset) => Status::Available(CAP), (Status::Available(x), WriterTransition::Read(y)) => { if x < *y { Status::Failed @@ -87,8 +87,8 @@ impl StateMachineTest for WriterTest { ) -> Self::SystemUnderTest { match transition { WriterTransition::Read(x) => sut.consumer.advance(x), - WriterTransition::Clear => { - sut.producer.clear(&mut sut.consumer); + WriterTransition::Reset => { + sut.producer.reset(&mut sut.consumer); } WriterTransition::WriteUpTo(x) => { let status = sut.status; From c991ddb76662cc7da5e847f33c1a446f17822887 Mon Sep 17 00:00:00 2001 From: Alexandros Liarokapis Date: Tue, 24 Sep 2024 17:46:53 +0300 Subject: [PATCH 0228/1217] use request_pause instead of request_stop at adc shutdown --- embassy-stm32/src/adc/ringbuffered_v2.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/src/adc/ringbuffered_v2.rs b/embassy-stm32/src/adc/ringbuffered_v2.rs index 9fc233222..9c114e463 100644 --- a/embassy-stm32/src/adc/ringbuffered_v2.rs +++ b/embassy-stm32/src/adc/ringbuffered_v2.rs @@ -244,7 +244,7 @@ impl<'d, T: Instance> RingBufferedAdc<'d, T> { /// [`start`]: #method.start pub fn teardown_adc(&mut self) { // Stop the DMA transfer - self.ring_buf.request_stop(); + self.ring_buf.request_pause(); let r = T::regs(); From f0d2ebdc7ead41307155b083790b8450ca2b7eac Mon Sep 17 00:00:00 2001 From: Alexandros Liarokapis Date: Tue, 1 Oct 2024 17:59:04 +0300 Subject: [PATCH 0229/1217] stm32: fix ringbugger overrun errors due to bad dma wrap-around behavior --- embassy-stm32/src/dma/dma_bdma.rs | 30 ++++--- embassy-stm32/src/dma/ringbuffer/mod.rs | 65 +++++++++------ embassy-stm32/src/dma/ringbuffer/tests/mod.rs | 83 +------------------ embassy-stm32/src/sai/mod.rs | 10 ++- embassy-stm32/src/usart/ringbuffered.rs | 1 - 5 files changed, 72 insertions(+), 117 deletions(-) diff --git a/embassy-stm32/src/dma/dma_bdma.rs b/embassy-stm32/src/dma/dma_bdma.rs index 59ad4d988..3f047a9a4 100644 --- a/embassy-stm32/src/dma/dma_bdma.rs +++ b/embassy-stm32/src/dma/dma_bdma.rs @@ -6,7 +6,7 @@ use core::task::{Context, Poll, Waker}; use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; use embassy_sync::waitqueue::AtomicWaker; -use super::ringbuffer::{DmaCtrl, OverrunError, ReadableDmaRingBuffer, WritableDmaRingBuffer}; +use super::ringbuffer::{DmaCtrl, Error, ReadableDmaRingBuffer, WritableDmaRingBuffer}; use super::word::{Word, WordSize}; use super::{AnyChannel, Channel, Dir, Request, STATE}; use crate::interrupt::typelevel::Interrupt; @@ -299,7 +299,6 @@ impl AnyChannel { } else { return; } - state.waker.wake(); } #[cfg(bdma)] @@ -828,7 +827,8 @@ impl<'a, W: Word> ReadableRingBuffer<'a, W> { /// /// You must call this after creating it for it to work. pub fn start(&mut self) { - self.channel.start() + self.channel.start(); + self.clear(); } /// Clear all data in the ring buffer. @@ -840,15 +840,15 @@ impl<'a, W: Word> ReadableRingBuffer<'a, W> { /// Return a tuple of the length read and the length remaining in the buffer /// If not all of the elements were read, then there will be some elements in the buffer remaining /// The length remaining is the capacity, ring_buf.len(), less the elements remaining after the read - /// OverrunError is returned if the portion to be read was overwritten by the DMA controller. - pub fn read(&mut self, buf: &mut [W]) -> Result<(usize, usize), OverrunError> { + /// Error is returned if the portion to be read was overwritten by the DMA controller. + pub fn read(&mut self, buf: &mut [W]) -> Result<(usize, usize), Error> { self.ringbuf.read(&mut DmaCtrlImpl(self.channel.reborrow()), buf) } /// Read an exact number of elements from the ringbuffer. /// /// Returns the remaining number of elements available for immediate reading. - /// OverrunError is returned if the portion to be read was overwritten by the DMA controller. + /// Error is returned if the portion to be read was overwritten by the DMA controller. /// /// Async/Wake Behavior: /// The underlying DMA peripheral only can wake us when its buffer pointer has reached the halfway point, @@ -856,12 +856,17 @@ impl<'a, W: Word> ReadableRingBuffer<'a, W> { /// ring buffer was created with a buffer of size 'N': /// - If M equals N/2 or N/2 divides evenly into M, this function will return every N/2 elements read on the DMA source. /// - Otherwise, this function may need up to N/2 extra elements to arrive before returning. - pub async fn read_exact(&mut self, buffer: &mut [W]) -> Result { + pub async fn read_exact(&mut self, buffer: &mut [W]) -> Result { self.ringbuf .read_exact(&mut DmaCtrlImpl(self.channel.reborrow()), buffer) .await } + /// The current length of the ringbuffer + pub fn len(&mut self) -> Result { + Ok(self.ringbuf.len(&mut DmaCtrlImpl(self.channel.reborrow()))?) + } + /// The capacity of the ringbuffer pub const fn capacity(&self) -> usize { self.ringbuf.cap() @@ -986,23 +991,28 @@ impl<'a, W: Word> WritableRingBuffer<'a, W> { /// Write elements directly to the raw buffer. /// This can be used to fill the buffer before starting the DMA transfer. #[allow(dead_code)] - pub fn write_immediate(&mut self, buf: &[W]) -> Result<(usize, usize), OverrunError> { + pub fn write_immediate(&mut self, buf: &[W]) -> Result<(usize, usize), Error> { self.ringbuf.write_immediate(buf) } /// Write elements from the ring buffer /// Return a tuple of the length written and the length remaining in the buffer - pub fn write(&mut self, buf: &[W]) -> Result<(usize, usize), OverrunError> { + pub fn write(&mut self, buf: &[W]) -> Result<(usize, usize), Error> { self.ringbuf.write(&mut DmaCtrlImpl(self.channel.reborrow()), buf) } /// Write an exact number of elements to the ringbuffer. - pub async fn write_exact(&mut self, buffer: &[W]) -> Result { + pub async fn write_exact(&mut self, buffer: &[W]) -> Result { self.ringbuf .write_exact(&mut DmaCtrlImpl(self.channel.reborrow()), buffer) .await } + /// The current length of the ringbuffer + pub fn len(&mut self) -> Result { + Ok(self.ringbuf.len(&mut DmaCtrlImpl(self.channel.reborrow()))?) + } + /// The capacity of the ringbuffer pub const fn capacity(&self) -> usize { self.ringbuf.cap() diff --git a/embassy-stm32/src/dma/ringbuffer/mod.rs b/embassy-stm32/src/dma/ringbuffer/mod.rs index eb64ad016..a257faa5b 100644 --- a/embassy-stm32/src/dma/ringbuffer/mod.rs +++ b/embassy-stm32/src/dma/ringbuffer/mod.rs @@ -19,9 +19,13 @@ pub trait DmaCtrl { #[derive(Debug, PartialEq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct OverrunError; +pub enum Error { + Overrun, + DmaUnsynced, +} #[derive(Debug, Clone, Copy, Default)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] struct DmaIndex { complete_count: usize, pos: usize, @@ -38,15 +42,19 @@ impl DmaIndex { } fn dma_sync(&mut self, cap: usize, dma: &mut impl DmaCtrl) { - let first_pos = cap - dma.get_remaining_transfers(); - self.complete_count += dma.reset_complete_count(); - self.pos = cap - dma.get_remaining_transfers(); + // Important! + // The ordering of the first two lines matters! + // If changed, the code will detect a wrong +capacity + // jump at wrap-around. + let count_diff = dma.reset_complete_count(); + let pos = cap - dma.get_remaining_transfers(); + self.pos = if pos < self.pos && count_diff == 0 { + cap - 1 + } else { + pos + }; - // If the latter call to get_remaining_transfers() returned a smaller value than the first, the dma - // has wrapped around between calls and we must check if the complete count also incremented. - if self.pos < first_pos { - self.complete_count += dma.reset_complete_count(); - } + self.complete_count += count_diff; } fn advance(&mut self, cap: usize, steps: usize) { @@ -96,14 +104,18 @@ impl<'a, W: Word> ReadableDmaRingBuffer<'a, W> { } /// Get the available readable dma samples. - pub fn len(&mut self, dma: &mut impl DmaCtrl) -> Result { + pub fn len(&mut self, dma: &mut impl DmaCtrl) -> Result { self.write_index.dma_sync(self.cap(), dma); DmaIndex::normalize(&mut self.write_index, &mut self.read_index); let diff = self.write_index.diff(self.cap(), &self.read_index); - if diff < 0 || diff > self.cap() as isize { - Err(OverrunError) + if diff < 0 { + return Err(Error::DmaUnsynced); + } + + if diff > self.cap() as isize { + Err(Error::Overrun) } else { Ok(diff as usize) } @@ -113,9 +125,9 @@ impl<'a, W: Word> ReadableDmaRingBuffer<'a, W> { /// Return a tuple of the length read and the length remaining in the buffer /// If not all of the elements were read, then there will be some elements in the buffer remaining /// The length remaining is the capacity, ring_buf.len(), less the elements remaining after the read - /// OverrunError is returned if the portion to be read was overwritten by the DMA controller, + /// Error is returned if the portion to be read was overwritten by the DMA controller, /// in which case the rinbuffer will automatically reset itself. - pub fn read(&mut self, dma: &mut impl DmaCtrl, buf: &mut [W]) -> Result<(usize, usize), OverrunError> { + pub fn read(&mut self, dma: &mut impl DmaCtrl, buf: &mut [W]) -> Result<(usize, usize), Error> { self.read_raw(dma, buf).inspect_err(|_e| { self.reset(dma); }) @@ -124,7 +136,7 @@ impl<'a, W: Word> ReadableDmaRingBuffer<'a, W> { /// Read an exact number of elements from the ringbuffer. /// /// Returns the remaining number of elements available for immediate reading. - /// OverrunError is returned if the portion to be read was overwritten by the DMA controller. + /// Error is returned if the portion to be read was overwritten by the DMA controller. /// /// Async/Wake Behavior: /// The underlying DMA peripheral only can wake us when its buffer pointer has reached the halfway point, @@ -132,7 +144,7 @@ impl<'a, W: Word> ReadableDmaRingBuffer<'a, W> { /// ring buffer was created with a buffer of size 'N': /// - If M equals N/2 or N/2 divides evenly into M, this function will return every N/2 elements read on the DMA source. /// - Otherwise, this function may need up to N/2 extra elements to arrive before returning. - pub async fn read_exact(&mut self, dma: &mut impl DmaCtrl, buffer: &mut [W]) -> Result { + pub async fn read_exact(&mut self, dma: &mut impl DmaCtrl, buffer: &mut [W]) -> Result { let mut read_data = 0; let buffer_len = buffer.len(); @@ -154,7 +166,7 @@ impl<'a, W: Word> ReadableDmaRingBuffer<'a, W> { .await } - fn read_raw(&mut self, dma: &mut impl DmaCtrl, buf: &mut [W]) -> Result<(usize, usize), OverrunError> { + fn read_raw(&mut self, dma: &mut impl DmaCtrl, buf: &mut [W]) -> Result<(usize, usize), Error> { let readable = self.len(dma)?.min(buf.len()); for i in 0..readable { buf[i] = self.read_buf(i); @@ -205,14 +217,17 @@ impl<'a, W: Word> WritableDmaRingBuffer<'a, W> { } /// Get the remaining writable dma samples. - pub fn len(&mut self, dma: &mut impl DmaCtrl) -> Result { + pub fn len(&mut self, dma: &mut impl DmaCtrl) -> Result { self.read_index.dma_sync(self.cap(), dma); DmaIndex::normalize(&mut self.read_index, &mut self.write_index); let diff = self.write_index.diff(self.cap(), &self.read_index); - if diff < 0 || diff > self.cap() as isize { - Err(OverrunError) + if diff > self.cap() as isize { + return Err(Error::DmaUnsynced); + } + if diff < 0 { + Err(Error::Overrun) } else { Ok(self.cap().saturating_sub(diff as usize)) } @@ -225,17 +240,17 @@ impl<'a, W: Word> WritableDmaRingBuffer<'a, W> { /// Append data to the ring buffer. /// Returns a tuple of the data written and the remaining write capacity in the buffer. - /// OverrunError is returned if the portion to be written was previously read by the DMA controller. + /// Error is returned if the portion to be written was previously read by the DMA controller. /// In this case, the ringbuffer will automatically reset itself, giving a full buffer worth of /// leeway between the write index and the DMA. - pub fn write(&mut self, dma: &mut impl DmaCtrl, buf: &[W]) -> Result<(usize, usize), OverrunError> { + pub fn write(&mut self, dma: &mut impl DmaCtrl, buf: &[W]) -> Result<(usize, usize), Error> { self.write_raw(dma, buf).inspect_err(|_e| { self.reset(dma); }) } /// Write elements directly to the buffer. - pub fn write_immediate(&mut self, buf: &[W]) -> Result<(usize, usize), OverrunError> { + pub fn write_immediate(&mut self, buf: &[W]) -> Result<(usize, usize), Error> { for (i, data) in buf.iter().enumerate() { self.write_buf(i, *data) } @@ -244,7 +259,7 @@ impl<'a, W: Word> WritableDmaRingBuffer<'a, W> { } /// Write an exact number of elements to the ringbuffer. - pub async fn write_exact(&mut self, dma: &mut impl DmaCtrl, buffer: &[W]) -> Result { + pub async fn write_exact(&mut self, dma: &mut impl DmaCtrl, buffer: &[W]) -> Result { let mut written_data = 0; let buffer_len = buffer.len(); @@ -266,7 +281,7 @@ impl<'a, W: Word> WritableDmaRingBuffer<'a, W> { .await } - pub fn write_raw(&mut self, dma: &mut impl DmaCtrl, buf: &[W]) -> Result<(usize, usize), OverrunError> { + fn write_raw(&mut self, dma: &mut impl DmaCtrl, buf: &[W]) -> Result<(usize, usize), Error> { let writable = self.len(dma)?.min(buf.len()); for i in 0..writable { self.write_buf(i, buf[i]); diff --git a/embassy-stm32/src/dma/ringbuffer/tests/mod.rs b/embassy-stm32/src/dma/ringbuffer/tests/mod.rs index 1800eae69..6fabedb83 100644 --- a/embassy-stm32/src/dma/ringbuffer/tests/mod.rs +++ b/embassy-stm32/src/dma/ringbuffer/tests/mod.rs @@ -2,13 +2,14 @@ use std::{cell, vec}; use super::*; -#[allow(dead_code)] +#[allow(unused)] #[derive(PartialEq, Debug)] enum TestCircularTransferRequest { ResetCompleteCount(usize), PositionRequest(usize), } +#[allow(unused)] struct TestCircularTransfer { len: usize, requests: cell::RefCell>, @@ -39,6 +40,7 @@ impl DmaCtrl for TestCircularTransfer { } impl TestCircularTransfer { + #[allow(unused)] pub fn new(len: usize) -> Self { Self { requests: cell::RefCell::new(vec![]), @@ -46,6 +48,7 @@ impl TestCircularTransfer { } } + #[allow(unused)] pub fn setup(&self, mut requests: vec::Vec) { requests.reverse(); self.requests.replace(requests); @@ -54,84 +57,6 @@ impl TestCircularTransfer { const CAP: usize = 16; -#[test] -fn dma_index_dma_sync_syncs_position_to_last_read_if_sync_takes_place_on_same_dma_cycle() { - let mut dma = TestCircularTransfer::new(CAP); - dma.setup(vec![ - TestCircularTransferRequest::PositionRequest(4), - TestCircularTransferRequest::ResetCompleteCount(0), - TestCircularTransferRequest::PositionRequest(7), - ]); - let mut index = DmaIndex::default(); - index.dma_sync(CAP, &mut dma); - assert_eq!(index.complete_count, 0); - assert_eq!(index.pos, 7); -} - -#[test] -fn dma_index_dma_sync_updates_complete_count_properly_if_sync_takes_place_on_same_dma_cycle() { - let mut dma = TestCircularTransfer::new(CAP); - dma.setup(vec![ - TestCircularTransferRequest::PositionRequest(4), - TestCircularTransferRequest::ResetCompleteCount(2), - TestCircularTransferRequest::PositionRequest(7), - ]); - let mut index = DmaIndex::default(); - index.complete_count = 1; - index.dma_sync(CAP, &mut dma); - assert_eq!(index.complete_count, 3); - assert_eq!(index.pos, 7); -} - -#[test] -fn dma_index_dma_sync_syncs_to_last_position_if_reads_occur_on_different_dma_cycles() { - let mut dma = TestCircularTransfer::new(CAP); - dma.setup(vec![ - TestCircularTransferRequest::PositionRequest(10), - TestCircularTransferRequest::ResetCompleteCount(1), - TestCircularTransferRequest::PositionRequest(5), - TestCircularTransferRequest::ResetCompleteCount(0), - ]); - let mut index = DmaIndex::default(); - index.dma_sync(CAP, &mut dma); - assert_eq!(index.complete_count, 1); - assert_eq!(index.pos, 5); -} - -#[test] -fn dma_index_dma_sync_detects_new_cycle_if_later_position_is_less_than_first_and_first_complete_count_occurs_on_first_cycle( -) { - let mut dma = TestCircularTransfer::new(CAP); - dma.setup(vec![ - TestCircularTransferRequest::PositionRequest(10), - TestCircularTransferRequest::ResetCompleteCount(1), - TestCircularTransferRequest::PositionRequest(5), - TestCircularTransferRequest::ResetCompleteCount(1), - ]); - let mut index = DmaIndex::default(); - index.complete_count = 1; - index.dma_sync(CAP, &mut dma); - assert_eq!(index.complete_count, 3); - assert_eq!(index.pos, 5); -} - -#[test] -fn dma_index_dma_sync_detects_new_cycle_if_later_position_is_less_than_first_and_first_complete_count_occurs_on_later_cycle( -) { - let mut dma = TestCircularTransfer::new(CAP); - dma.setup(vec![ - TestCircularTransferRequest::PositionRequest(10), - TestCircularTransferRequest::ResetCompleteCount(2), - TestCircularTransferRequest::PositionRequest(5), - TestCircularTransferRequest::ResetCompleteCount(0), - ]); - let mut index = DmaIndex::default(); - index.complete_count = 1; - index.dma_sync(CAP, &mut dma); - assert_eq!(index.complete_count, 3); - assert_eq!(index.pos, 5); -} - #[test] fn dma_index_as_index_returns_index_mod_cap_by_default() { let index = DmaIndex::default(); diff --git a/embassy-stm32/src/sai/mod.rs b/embassy-stm32/src/sai/mod.rs index 63f48ace0..7d2f071de 100644 --- a/embassy-stm32/src/sai/mod.rs +++ b/embassy-stm32/src/sai/mod.rs @@ -27,8 +27,14 @@ pub enum Error { } #[cfg(not(gpdma))] -impl From for Error { - fn from(_: ringbuffer::OverrunError) -> Self { +impl From for Error { + fn from(#[allow(unused)] err: ringbuffer::Error) -> Self { + #[cfg(feature = "defmt")] + { + if err == ringbuffer::Error::DmaUnsynced { + defmt::error!("Ringbuffer broken invariants detected!"); + } + } Self::Overrun } } diff --git a/embassy-stm32/src/usart/ringbuffered.rs b/embassy-stm32/src/usart/ringbuffered.rs index 75834bf37..eb2399d9c 100644 --- a/embassy-stm32/src/usart/ringbuffered.rs +++ b/embassy-stm32/src/usart/ringbuffered.rs @@ -83,7 +83,6 @@ impl<'d> RingBufferedUartRx<'d> { // Clear the buffer so that it is ready to receive data compiler_fence(Ordering::SeqCst); self.ring_buf.start(); - self.ring_buf.clear(); let r = self.info.regs; // clear all interrupts and DMA Rx Request From 2ec05da5ddadad9b34c72e8ef1a57a7662a6f0e0 Mon Sep 17 00:00:00 2001 From: Alexandros Liarokapis Date: Wed, 2 Oct 2024 13:10:07 +0300 Subject: [PATCH 0230/1217] simplify if/else handling on ringbuffer --- embassy-stm32/src/dma/ringbuffer/mod.rs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/embassy-stm32/src/dma/ringbuffer/mod.rs b/embassy-stm32/src/dma/ringbuffer/mod.rs index a257faa5b..ac4be3e18 100644 --- a/embassy-stm32/src/dma/ringbuffer/mod.rs +++ b/embassy-stm32/src/dma/ringbuffer/mod.rs @@ -111,10 +111,8 @@ impl<'a, W: Word> ReadableDmaRingBuffer<'a, W> { let diff = self.write_index.diff(self.cap(), &self.read_index); if diff < 0 { - return Err(Error::DmaUnsynced); - } - - if diff > self.cap() as isize { + Err(Error::DmaUnsynced) + } else if diff > self.cap() as isize { Err(Error::Overrun) } else { Ok(diff as usize) @@ -223,11 +221,10 @@ impl<'a, W: Word> WritableDmaRingBuffer<'a, W> { let diff = self.write_index.diff(self.cap(), &self.read_index); - if diff > self.cap() as isize { - return Err(Error::DmaUnsynced); - } if diff < 0 { Err(Error::Overrun) + } else if diff > self.cap() as isize { + Err(Error::DmaUnsynced) } else { Ok(self.cap().saturating_sub(diff as usize)) } From d280b234283d3c65e7ba6087e52005160a538ad2 Mon Sep 17 00:00:00 2001 From: Alexandros Liarokapis Date: Thu, 3 Oct 2024 13:04:15 +0300 Subject: [PATCH 0231/1217] fix adc/ringbuffered_v2.rs --- embassy-stm32/src/adc/ringbuffered_v2.rs | 4 +++- embassy-stm32/src/dma/ringbuffer/mod.rs | 3 ++- embassy-stm32/src/lib.rs | 3 +++ 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/adc/ringbuffered_v2.rs b/embassy-stm32/src/adc/ringbuffered_v2.rs index 9c114e463..3f0c1a57a 100644 --- a/embassy-stm32/src/adc/ringbuffered_v2.rs +++ b/embassy-stm32/src/adc/ringbuffered_v2.rs @@ -6,11 +6,13 @@ use embassy_hal_internal::{into_ref, Peripheral}; use stm32_metapac::adc::vals::SampleTime; use crate::adc::{Adc, AdcChannel, Instance, RxDma}; -use crate::dma::ringbuffer::OverrunError; use crate::dma::{Priority, ReadableRingBuffer, TransferOptions}; use crate::pac::adc::vals; use crate::rcc; +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct OverrunError; + fn clear_interrupt_flags(r: crate::pac::adc::Adc) { r.sr().modify(|regs| { regs.set_eoc(false); diff --git a/embassy-stm32/src/dma/ringbuffer/mod.rs b/embassy-stm32/src/dma/ringbuffer/mod.rs index ac4be3e18..12d418414 100644 --- a/embassy-stm32/src/dma/ringbuffer/mod.rs +++ b/embassy-stm32/src/dma/ringbuffer/mod.rs @@ -119,7 +119,8 @@ impl<'a, W: Word> ReadableDmaRingBuffer<'a, W> { } } - /// Read elements from the ring buffer + /// Read elements from the ring buffer. + /// /// Return a tuple of the length read and the length remaining in the buffer /// If not all of the elements were read, then there will be some elements in the buffer remaining /// The length remaining is the capacity, ring_buf.len(), less the elements remaining after the read diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 451f595e0..5f103e652 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -296,6 +296,9 @@ mod dual_core { /// It cannot be initialized by the user. The intended use is: /// /// ``` + /// use core::mem::MaybeUninit; + /// use embassy_stm32::{init_secondary, SharedData}; + /// /// #[link_section = ".ram_d3"] /// static SHARED_DATA: MaybeUninit = MaybeUninit::uninit(); /// From 4f810e47f5244b0cb7780ae1eebdba108d9e88c9 Mon Sep 17 00:00:00 2001 From: Alexandros Liarokapis Date: Thu, 3 Oct 2024 21:54:47 +0300 Subject: [PATCH 0232/1217] enable ci usart tests --- ci.sh | 5 ----- 1 file changed, 5 deletions(-) diff --git a/ci.sh b/ci.sh index ee47ee1c5..aa078be31 100755 --- a/ci.sh +++ b/ci.sh @@ -305,11 +305,6 @@ rm out/tests/stm32f207zg/eth # doesn't work, gives "noise error", no idea why. usart_dma does pass. rm out/tests/stm32u5a5zj/usart -# flaky, probably due to bad ringbuffered dma code. -rm out/tests/stm32l152re/usart_rx_ringbuffered -rm out/tests/stm32f207zg/usart_rx_ringbuffered -rm out/tests/stm32wl55jc/usart_rx_ringbuffered - if [[ -z "${TELEPROBE_TOKEN-}" ]]; then echo No teleprobe token found, skipping running HIL tests exit From 28d03537e958213dab345ad4502dad2b32256135 Mon Sep 17 00:00:00 2001 From: Alexandros Liarokapis Date: Mon, 7 Oct 2024 23:12:35 +0300 Subject: [PATCH 0233/1217] stm32: Automatically clear on WritableRingBuffer start --- embassy-stm32/src/dma/dma_bdma.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/embassy-stm32/src/dma/dma_bdma.rs b/embassy-stm32/src/dma/dma_bdma.rs index 3f047a9a4..cdc603e2c 100644 --- a/embassy-stm32/src/dma/dma_bdma.rs +++ b/embassy-stm32/src/dma/dma_bdma.rs @@ -980,7 +980,8 @@ impl<'a, W: Word> WritableRingBuffer<'a, W> { /// /// You must call this after creating it for it to work. pub fn start(&mut self) { - self.channel.start() + self.channel.start(); + self.clear(); } /// Clear all data in the ring buffer. From e350ca836a985829b7548b8ac3009f38573b4215 Mon Sep 17 00:00:00 2001 From: Dion Dokter Date: Tue, 15 Oct 2024 13:23:57 +0200 Subject: [PATCH 0234/1217] STM32 QSPI typo (#3418) --- embassy-stm32/src/qspi/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/src/qspi/mod.rs b/embassy-stm32/src/qspi/mod.rs index 308947e99..1dfd0e918 100644 --- a/embassy-stm32/src/qspi/mod.rs +++ b/embassy-stm32/src/qspi/mod.rs @@ -18,7 +18,7 @@ use crate::{peripherals, Peripheral}; /// QSPI transfer configuration. pub struct TransferConfig { - /// Instraction width (IMODE) + /// Instruction width (IMODE) pub iwidth: QspiWidth, /// Address width (ADMODE) pub awidth: QspiWidth, From 8af52488e7668897ecdf6a77f76a0003978d04e4 Mon Sep 17 00:00:00 2001 From: Tu Nguyen Date: Wed, 16 Oct 2024 17:45:40 +0700 Subject: [PATCH 0235/1217] add RTR flag if it is remote frame --- embassy-stm32/src/can/bxcan/registers.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/embassy-stm32/src/can/bxcan/registers.rs b/embassy-stm32/src/can/bxcan/registers.rs index c5de1c683..9798a058b 100644 --- a/embassy-stm32/src/can/bxcan/registers.rs +++ b/embassy-stm32/src/can/bxcan/registers.rs @@ -2,7 +2,7 @@ use core::cmp::Ordering; use core::convert::Infallible; pub use embedded_can::{ExtendedId, Id, StandardId}; -use stm32_metapac::can::vals::Lec; +use stm32_metapac::can::vals::{Lec, Rtr}; use super::{Mailbox, TransmitStatus}; use crate::can::enums::BusError; @@ -306,6 +306,9 @@ impl Registers { mb.tir().write(|w| { w.0 = id.0; w.set_txrq(true); + if frame.header().rtr() { + w.set_rtr(Rtr::REMOTE); + } }); } From 9f1b6b47916126fba7b5968106b5fd25006fc4c2 Mon Sep 17 00:00:00 2001 From: Alexandros Liarokapis Date: Mon, 20 May 2024 16:15:41 +0300 Subject: [PATCH 0236/1217] Revise I2S interface to ring-buffered. --- embassy-stm32/src/i2s.rs | 337 ++++++++++++++++++++++------ embassy-stm32/src/spi/mod.rs | 13 +- examples/stm32f4/src/bin/i2s_dma.rs | 13 +- 3 files changed, 278 insertions(+), 85 deletions(-) diff --git a/embassy-stm32/src/i2s.rs b/embassy-stm32/src/i2s.rs index 094de2461..f11371f98 100644 --- a/embassy-stm32/src/i2s.rs +++ b/embassy-stm32/src/i2s.rs @@ -1,12 +1,13 @@ //! Inter-IC Sound (I2S) +use embassy_futures::join::join; use embassy_hal_internal::into_ref; +use stm32_metapac::spi::vals; -use crate::dma::ChannelAndRequest; +use crate::dma::{ringbuffer, ChannelAndRequest, ReadableRingBuffer, TransferOptions, WritableRingBuffer}; use crate::gpio::{AfType, AnyPin, OutputType, SealedPin, Speed}; use crate::mode::Async; -use crate::pac::spi::vals; -use crate::spi::{Config as SpiConfig, *}; +use crate::spi::{Config as SpiConfig, RegsExt as _, *}; use crate::time::Hertz; use crate::{Peripheral, PeripheralRef}; @@ -19,6 +20,19 @@ pub enum Mode { Slave, } +/// I2S function +#[derive(Copy, Clone)] +#[allow(dead_code)] +enum Function { + /// Transmit audio data + Transmit, + /// Receive audio data + Receive, + #[cfg(spi_v3)] + /// Transmit and Receive audio data + FullDuplex, +} + /// I2C standard #[derive(Copy, Clone)] pub enum Standard { @@ -34,6 +48,30 @@ pub enum Standard { PcmShortSync, } +/// SAI error +#[derive(Debug, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum Error { + /// `write` called on a SAI in receive mode. + NotATransmitter, + /// `read` called on a SAI in transmit mode. + NotAReceiver, + /// Overrun + Overrun, +} + +impl From for Error { + fn from(#[allow(unused)] err: ringbuffer::Error) -> Self { + #[cfg(feature = "defmt")] + { + if err == ringbuffer::Error::DmaUnsynced { + defmt::error!("Ringbuffer broken invariants detected!"); + } + } + Self::Overrun + } +} + impl Standard { #[cfg(any(spi_v1, spi_v3, spi_f1))] const fn i2sstd(&self) -> vals::I2sstd { @@ -142,31 +180,62 @@ impl Default for Config { } } +/// I2S driver writer. Useful for moving write functionality across tasks. +pub struct Writer<'s, 'd, W: Word>(&'s mut WritableRingBuffer<'d, W>); + +impl<'s, 'd, W: Word> Writer<'s, 'd, W> { + /// Write data to the I2S ringbuffer. + /// This appends the data to the buffer and returns immediately. The data will be transmitted in the background. + /// If thfre’s no space in the buffer, this waits until there is. + pub async fn write(&mut self, data: &[W]) -> Result<(), Error> { + self.0.write_exact(data).await?; + Ok(()) + } + + /// Reset the ring buffer to its initial state. + /// Can be used to recover from overrun. + /// The ringbuffer will always auto-reset on Overrun in any case. + pub fn reset(&mut self) { + self.0.clear(); + } +} + +/// I2S driver reader. Useful for moving read functionality across tasks. +pub struct Reader<'s, 'd, W: Word>(&'s mut ReadableRingBuffer<'d, W>); + +impl<'s, 'd, W: Word> Reader<'s, 'd, W> { + /// Read data from the I2S ringbuffer. + /// SAI is always receiving data in the background. This function pops already-received data from the buffer. + /// If there’s less than data.len() data in the buffer, this waits until there is. + pub async fn read(&mut self, data: &mut [W]) -> Result<(), Error> { + self.0.read_exact(data).await?; + Ok(()) + } + + /// Reset the ring buffer to its initial state. + /// Can be used to prevent overrun. + /// The ringbuffer will always auto-reset on Overrun in any case. + pub fn reset(&mut self) { + self.0.clear(); + } +} + /// I2S driver. -pub struct I2S<'d> { - _peri: Spi<'d, Async>, +pub struct I2S<'d, W: Word> { + #[allow(dead_code)] + mode: Mode, + spi: Spi<'d, Async>, txsd: Option>, rxsd: Option>, ws: Option>, ck: Option>, mck: Option>, + tx_ring_buffer: Option>, + rx_ring_buffer: Option>, } -/// I2S function -#[derive(Copy, Clone)] -#[allow(dead_code)] -enum Function { - /// Transmit audio data - Transmit, - /// Receive audio data - Receive, - #[cfg(spi_v3)] - /// Transmit and Receive audio data - FullDuplex, -} - -impl<'d> I2S<'d> { - /// Create a transmitter driver +impl<'d, W: Word> I2S<'d, W> { + /// Create a transmitter driver. pub fn new_txonly( peri: impl Peripheral

+ 'd, sd: impl Peripheral

> + 'd, @@ -174,18 +243,18 @@ impl<'d> I2S<'d> { ck: impl Peripheral

> + 'd, mck: impl Peripheral

> + 'd, txdma: impl Peripheral

> + 'd, + txdma_buf: &'d mut [W], freq: Hertz, config: Config, ) -> Self { - into_ref!(sd); Self::new_inner( peri, new_pin!(sd, AfType::output(OutputType::PushPull, Speed::VeryHigh)), None, ws, ck, - mck, - new_dma!(txdma), + new_pin!(mck, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + new_dma!(txdma).map(|d| (d, txdma_buf)), None, freq, config, @@ -193,42 +262,61 @@ impl<'d> I2S<'d> { ) } - /// Create a receiver driver + /// Create a transmitter driver without a master clock pin. + pub fn new_txonly_nomck( + peri: impl Peripheral

+ 'd, + sd: impl Peripheral

> + 'd, + ws: impl Peripheral

> + 'd, + ck: impl Peripheral

> + 'd, + txdma: impl Peripheral

> + 'd, + txdma_buf: &'d mut [W], + freq: Hertz, + config: Config, + ) -> Self { + Self::new_inner( + peri, + new_pin!(sd, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + None, + ws, + ck, + None, + new_dma!(txdma).map(|d| (d, txdma_buf)), + None, + freq, + config, + Function::Transmit, + ) + } + + /// Create a receiver driver. pub fn new_rxonly( peri: impl Peripheral

+ 'd, sd: impl Peripheral

> + 'd, ws: impl Peripheral

> + 'd, ck: impl Peripheral

> + 'd, mck: impl Peripheral

> + 'd, - #[cfg(not(spi_v3))] txdma: impl Peripheral

> + 'd, rxdma: impl Peripheral

> + 'd, + rxdma_buf: &'d mut [W], freq: Hertz, config: Config, ) -> Self { - into_ref!(sd); Self::new_inner( peri, None, new_pin!(sd, AfType::output(OutputType::PushPull, Speed::VeryHigh)), ws, ck, - mck, - #[cfg(not(spi_v3))] - new_dma!(txdma), - #[cfg(spi_v3)] + new_pin!(mck, AfType::output(OutputType::PushPull, Speed::VeryHigh)), None, - new_dma!(rxdma), + new_dma!(rxdma).map(|d| (d, rxdma_buf)), freq, config, - #[cfg(not(spi_v3))] - Function::Transmit, - #[cfg(spi_v3)] Function::Receive, ) } #[cfg(spi_v3)] - /// Create a full duplex transmitter driver + /// Create a full duplex driver. pub fn new_full_duplex( peri: impl Peripheral

+ 'd, txsd: impl Peripheral

> + 'd, @@ -237,44 +325,144 @@ impl<'d> I2S<'d> { ck: impl Peripheral

> + 'd, mck: impl Peripheral

> + 'd, txdma: impl Peripheral

> + 'd, + txdma_buf: &'d mut [W], rxdma: impl Peripheral

> + 'd, + rxdma_buf: &'d mut [W], freq: Hertz, config: Config, ) -> Self { - into_ref!(txsd, rxsd); Self::new_inner( peri, new_pin!(txsd, AfType::output(OutputType::PushPull, Speed::VeryHigh)), new_pin!(rxsd, AfType::output(OutputType::PushPull, Speed::VeryHigh)), ws, ck, - mck, - new_dma!(txdma), - new_dma!(rxdma), + new_pin!(mck, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + new_dma!(txdma).map(|d| (d, txdma_buf)), + new_dma!(rxdma).map(|d| (d, rxdma_buf)), freq, config, Function::FullDuplex, ) } - /// Write audio data. - pub async fn read(&mut self, data: &mut [W]) -> Result<(), Error> { - self._peri.read(data).await + /// Start I2S driver. + pub fn start(&mut self) { + self.spi.info.regs.cr1().modify(|w| { + w.set_spe(false); + }); + self.spi.set_word_size(W::CONFIG); + if let Some(tx_ring_buffer) = &mut self.tx_ring_buffer { + tx_ring_buffer.start(); + + set_txdmaen(self.spi.info.regs, true); + } + if let Some(rx_ring_buffer) = &mut self.rx_ring_buffer { + rx_ring_buffer.start(); + // SPIv3 clears rxfifo on SPE=0 + #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] + flush_rx_fifo(self.spi.info.regs); + + set_rxdmaen(self.spi.info.regs, true); + } + self.spi.info.regs.cr1().modify(|w| { + w.set_spe(true); + }); + #[cfg(any(spi_v3, spi_v4, spi_v5))] + self.spi.info.regs.cr1().modify(|w| { + w.set_cstart(true); + }); } - /// Write audio data. - pub async fn write(&mut self, data: &[W]) -> Result<(), Error> { - self._peri.write(data).await + /// Reset the ring buffer to its initial state. + /// Can be used to recover from overrun. + pub fn clear(&mut self) { + if let Some(rx_ring_buffer) = &mut self.rx_ring_buffer { + rx_ring_buffer.clear(); + } + if let Some(tx_ring_buffer) = &mut self.tx_ring_buffer { + tx_ring_buffer.clear(); + } } - /// Transfer audio data. - pub async fn transfer(&mut self, read: &mut [W], write: &[W]) -> Result<(), Error> { - self._peri.transfer(read, write).await + /// Stop I2S driver. + pub async fn stop(&mut self) { + let regs = self.spi.info.regs; + + let tx_f = async { + if let Some(tx_ring_buffer) = &mut self.tx_ring_buffer { + tx_ring_buffer.stop().await; + + set_txdmaen(regs, false); + } + }; + + let rx_f = async { + if let Some(rx_ring_buffer) = &mut self.rx_ring_buffer { + rx_ring_buffer.stop().await; + + set_rxdmaen(regs, false); + } + }; + + join(rx_f, tx_f).await; + + #[cfg(any(spi_v3, spi_v4, spi_v5))] + { + if let Mode::Master = self.mode { + regs.cr1().modify(|w| { + w.set_csusp(true); + }); + + while regs.cr1().read().cstart() {} + } + } + + regs.cr1().modify(|w| { + w.set_spe(false); + }); + + self.clear(); } - /// Transfer audio data in place. - pub async fn transfer_in_place(&mut self, data: &mut [W]) -> Result<(), Error> { - self._peri.transfer_in_place(data).await + /// Split the driver into a Reader/Writer pair. + /// Useful for splitting the reader/writer functionality across tasks or + /// for calling the read/write methods in parallel. + pub fn split<'s>(&'s mut self) -> Result<(Reader<'s, 'd, W>, Writer<'s, 'd, W>), Error> { + match (&mut self.rx_ring_buffer, &mut self.tx_ring_buffer) { + (None, _) => Err(Error::NotAReceiver), + (_, None) => Err(Error::NotATransmitter), + (Some(rx_ring), Some(tx_ring)) => Ok((Reader(rx_ring), Writer(tx_ring))), + } + } + + /// Read data from the I2S ringbuffer. + /// SAI is always receiving data in the background. This function pops already-received data from the buffer. + /// If there’s less than data.len() data in the buffer, this waits until there is. + pub async fn read(&mut self, data: &mut [W]) -> Result<(), Error> { + match &mut self.rx_ring_buffer { + Some(ring) => Reader(ring).read(data).await, + _ => Err(Error::NotAReceiver), + } + } + + /// Write data to the I2S ringbuffer. + /// This appends the data to the buffer and returns immediately. The data will be transmitted in the background. + /// If thfre’s no space in the buffer, this waits until there is. + pub async fn write(&mut self, data: &[W]) -> Result<(), Error> { + match &mut self.tx_ring_buffer { + Some(ring) => Writer(ring).write(data).await, + _ => Err(Error::NotATransmitter), + } + } + + /// Write data directly to the raw I2S ringbuffer. + /// This can be used to fill the buffer before starting the DMA transfer. + pub async fn write_immediate(&mut self, data: &mut [W]) -> Result<(usize, usize), Error> { + match &mut self.tx_ring_buffer { + Some(ring) => Ok(ring.write_immediate(data)?), + _ => return Err(Error::NotATransmitter), + } } fn new_inner( @@ -283,23 +471,23 @@ impl<'d> I2S<'d> { rxsd: Option>, ws: impl Peripheral

> + 'd, ck: impl Peripheral

> + 'd, - mck: impl Peripheral

> + 'd, - txdma: Option>, - rxdma: Option>, + mck: Option>, + txdma: Option<(ChannelAndRequest<'d>, &'d mut [W])>, + rxdma: Option<(ChannelAndRequest<'d>, &'d mut [W])>, freq: Hertz, config: Config, function: Function, ) -> Self { - into_ref!(ws, ck, mck); + into_ref!(ws, ck); ws.set_as_af(ws.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh)); ck.set_as_af(ck.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh)); - mck.set_as_af(mck.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh)); - let mut spi_cfg = SpiConfig::default(); - spi_cfg.frequency = freq; - - let spi = Spi::new_internal(peri, txdma, rxdma, spi_cfg); + let spi = Spi::new_internal(peri, None, None, { + let mut config = SpiConfig::default(); + config.frequency = freq; + config + }); let regs = T::info().regs; @@ -390,22 +578,29 @@ impl<'d> I2S<'d> { w.set_i2se(true); }); - #[cfg(spi_v3)] - regs.cr1().modify(|w| w.set_spe(true)); - } + let mut opts = TransferOptions::default(); + opts.half_transfer_ir = true; - Self { - _peri: spi, - txsd: txsd.map(|w| w.map_into()), - rxsd: rxsd.map(|w| w.map_into()), - ws: Some(ws.map_into()), - ck: Some(ck.map_into()), - mck: Some(mck.map_into()), + Self { + mode: config.mode, + spi, + txsd: txsd.map(|w| w.map_into()), + rxsd: rxsd.map(|w| w.map_into()), + ws: Some(ws.map_into()), + ck: Some(ck.map_into()), + mck: mck.map(|w| w.map_into()), + tx_ring_buffer: txdma.map(|(ch, buf)| unsafe { + WritableRingBuffer::new(ch.channel, ch.request, regs.tx_ptr(), buf, opts) + }), + rx_ring_buffer: rxdma.map(|(ch, buf)| unsafe { + ReadableRingBuffer::new(ch.channel, ch.request, regs.rx_ptr(), buf, opts) + }), + } } } } -impl<'d> Drop for I2S<'d> { +impl<'d, W: Word> Drop for I2S<'d, W> { fn drop(&mut self) { self.txsd.as_ref().map(|x| x.set_as_disconnected()); self.rxsd.as_ref().map(|x| x.set_as_disconnected()); diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs index d034c028e..a65b0cc64 100644 --- a/embassy-stm32/src/spi/mod.rs +++ b/embassy-stm32/src/spi/mod.rs @@ -311,8 +311,7 @@ impl<'d, M: PeriMode> Spi<'d, M> { } } - /// Set SPI word size. Disables SPI if needed, you have to enable it back yourself. - fn set_word_size(&mut self, word_size: word_impl::Config) { + pub(crate) fn set_word_size(&mut self, word_size: word_impl::Config) { if self.current_word_size == word_size { return; } @@ -895,7 +894,7 @@ fn compute_frequency(kernel_clock: Hertz, br: Br) -> Hertz { kernel_clock / div } -trait RegsExt { +pub(crate) trait RegsExt { fn tx_ptr(&self) -> *mut W; fn rx_ptr(&self) -> *mut W; } @@ -983,7 +982,7 @@ fn spin_until_rx_ready(regs: Regs) -> Result<(), Error> { } } -fn flush_rx_fifo(regs: Regs) { +pub(crate) fn flush_rx_fifo(regs: Regs) { #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] while regs.sr().read().rxne() { #[cfg(not(spi_v2))] @@ -997,7 +996,7 @@ fn flush_rx_fifo(regs: Regs) { } } -fn set_txdmaen(regs: Regs, val: bool) { +pub(crate) fn set_txdmaen(regs: Regs, val: bool) { #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] regs.cr2().modify(|reg| { reg.set_txdmaen(val); @@ -1008,7 +1007,7 @@ fn set_txdmaen(regs: Regs, val: bool) { }); } -fn set_rxdmaen(regs: Regs, val: bool) { +pub(crate) fn set_rxdmaen(regs: Regs, val: bool) { #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] regs.cr2().modify(|reg| { reg.set_rxdmaen(val); @@ -1169,7 +1168,7 @@ impl<'d, W: Word> embedded_hal_async::spi::SpiBus for Spi<'d, Async> { } } -trait SealedWord { +pub(crate) trait SealedWord { const CONFIG: word_impl::Config; } diff --git a/examples/stm32f4/src/bin/i2s_dma.rs b/examples/stm32f4/src/bin/i2s_dma.rs index 27b165f1b..68392847b 100644 --- a/examples/stm32f4/src/bin/i2s_dma.rs +++ b/examples/stm32f4/src/bin/i2s_dma.rs @@ -1,13 +1,10 @@ #![no_std] #![no_main] -use core::fmt::Write; - use defmt::*; use embassy_executor::Spawner; use embassy_stm32::i2s::{Config, I2S}; use embassy_stm32::time::Hertz; -use heapless::String; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] @@ -15,6 +12,8 @@ async fn main(_spawner: Spawner) { let p = embassy_stm32::init(Default::default()); info!("Hello World!"); + let mut dma_buffer = [0x00_u16; 128]; + let mut i2s = I2S::new_txonly( p.SPI2, p.PC3, // sd @@ -22,13 +21,13 @@ async fn main(_spawner: Spawner) { p.PB10, // ck p.PC6, // mck p.DMA1_CH4, + &mut dma_buffer, Hertz(1_000_000), Config::default(), ); - for n in 0u32.. { - let mut write: String<128> = String::new(); - core::write!(&mut write, "Hello DMA World {}!\r\n", n).unwrap(); - i2s.write(&mut write.as_bytes()).await.ok(); + for i in 0_u16.. { + i2s.write(&mut [i * 2; 64]).await.ok(); + i2s.write(&mut [i * 2 + 1; 64]).await.ok(); } } From 9cf75d7eac11cacf545f1848d06808fc9fb745e1 Mon Sep 17 00:00:00 2001 From: Christian Enderle Date: Thu, 17 Oct 2024 19:40:27 +0200 Subject: [PATCH 0237/1217] stm32/flash: add support for l5 --- embassy-stm32/src/flash/l.rs | 134 ++++++++++++++++++++++++++------- embassy-stm32/src/flash/mod.rs | 7 +- 2 files changed, 110 insertions(+), 31 deletions(-) diff --git a/embassy-stm32/src/flash/l.rs b/embassy-stm32/src/flash/l.rs index a0bfeb395..ea00bf499 100644 --- a/embassy-stm32/src/flash/l.rs +++ b/embassy-stm32/src/flash/l.rs @@ -23,6 +23,9 @@ pub(crate) unsafe fn lock() { w.set_prglock(true); w.set_pelock(true); }); + + #[cfg(any(flash_l5))] + pac::FLASH.nscr().modify(|w| w.set_nslock(true)); } pub(crate) unsafe fn unlock() { @@ -46,6 +49,14 @@ pub(crate) unsafe fn unlock() { pac::FLASH.prgkeyr().write_value(0x1314_1516); } } + + #[cfg(any(flash_l5))] + { + if pac::FLASH.nscr().read().nslock() { + pac::FLASH.nskeyr().write_value(0x4567_0123); + pac::FLASH.nskeyr().write_value(0xCDEF_89AB); + } + } } pub(crate) unsafe fn enable_blocking_write() { @@ -53,11 +64,17 @@ pub(crate) unsafe fn enable_blocking_write() { #[cfg(any(flash_wl, flash_wb, flash_l4))] pac::FLASH.cr().write(|w| w.set_pg(true)); + + #[cfg(any(flash_l5))] + pac::FLASH.nscr().write(|w| w.set_nspg(true)); } pub(crate) unsafe fn disable_blocking_write() { #[cfg(any(flash_wl, flash_wb, flash_l4))] pac::FLASH.cr().write(|w| w.set_pg(false)); + + #[cfg(any(flash_l5))] + pac::FLASH.nscr().write(|w| w.set_nspg(false)); } pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> { @@ -84,13 +101,25 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E write_volatile(sector.start as *mut u32, 0xFFFFFFFF); } - #[cfg(any(flash_wl, flash_wb, flash_l4))] + #[cfg(any(flash_wl, flash_wb, flash_l4, flash_l5))] { let idx = (sector.start - super::FLASH_BASE as u32) / super::BANK1_REGION.erase_size as u32; #[cfg(flash_l4)] let (idx, bank) = if idx > 255 { (idx - 256, true) } else { (idx, false) }; + #[cfg(flash_l5)] + let (idx, bank) = if pac::FLASH.optr().read().dbank() { + if idx > 255 { + (idx - 256, Some(true)) + } else { + (idx, Some(false)) + } + } else { + (idx, None) + }; + + #[cfg(not(flash_l5))] pac::FLASH.cr().modify(|w| { w.set_per(true); w.set_pnb(idx as u8); @@ -101,6 +130,16 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E #[cfg(any(flash_l4))] w.set_bker(bank); }); + + #[cfg(flash_l5)] + pac::FLASH.nscr().modify(|w| { + w.set_nsper(true); + w.set_nspnb(idx as u8); + if let Some(bank) = bank { + w.set_nsbker(bank); + } + w.set_nsstrt(true); + }); } let ret: Result<(), Error> = wait_ready_blocking(); @@ -108,6 +147,9 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E #[cfg(any(flash_wl, flash_wb, flash_l4))] pac::FLASH.cr().modify(|w| w.set_per(false)); + #[cfg(any(flash_l5))] + pac::FLASH.nscr().modify(|w| w.set_nsper(false)); + #[cfg(any(flash_l0, flash_l1))] pac::FLASH.pecr().modify(|w| { w.set_erase(false); @@ -121,42 +163,78 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E pub(crate) unsafe fn clear_all_err() { // read and write back the same value. // This clears all "write 1 to clear" bits. + #[cfg(not(flash_l5))] pac::FLASH.sr().modify(|_| {}); + + #[cfg(flash_l5)] + pac::FLASH.nssr().modify(|_| {}); } unsafe fn wait_ready_blocking() -> Result<(), Error> { loop { - let sr = pac::FLASH.sr().read(); + #[cfg(not(flash_l5))] + { + let sr = pac::FLASH.sr().read(); - if !sr.bsy() { - #[cfg(any(flash_wl, flash_wb, flash_l4))] - if sr.progerr() { - return Err(Error::Prog); + if !sr.bsy() { + #[cfg(any(flash_wl, flash_wb, flash_l4))] + if sr.progerr() { + return Err(Error::Prog); + } + + if sr.wrperr() { + return Err(Error::Protected); + } + + if sr.pgaerr() { + return Err(Error::Unaligned); + } + + if sr.sizerr() { + return Err(Error::Size); + } + + #[cfg(any(flash_wl, flash_wb, flash_l4))] + if sr.miserr() { + return Err(Error::Miss); + } + + #[cfg(any(flash_wl, flash_wb, flash_l4))] + if sr.pgserr() { + return Err(Error::Seq); + } + + return Ok(()); } + } - if sr.wrperr() { - return Err(Error::Protected); + #[cfg(flash_l5)] + { + let nssr = pac::FLASH.nssr().read(); + + if !nssr.nsbsy() { + if nssr.nsprogerr() { + return Err(Error::Prog); + } + + if nssr.nswrperr() { + return Err(Error::Protected); + } + + if nssr.nspgaerr() { + return Err(Error::Unaligned); + } + + if nssr.nssizerr() { + return Err(Error::Size); + } + + if nssr.nspgserr() { + return Err(Error::Seq); + } + + return Ok(()); } - - if sr.pgaerr() { - return Err(Error::Unaligned); - } - - if sr.sizerr() { - return Err(Error::Size); - } - - #[cfg(any(flash_wl, flash_wb, flash_l4))] - if sr.miserr() { - return Err(Error::Miss); - } - - #[cfg(any(flash_wl, flash_wb, flash_l4))] - if sr.pgserr() { - return Err(Error::Seq); - } - - return Ok(()); } } } diff --git a/embassy-stm32/src/flash/mod.rs b/embassy-stm32/src/flash/mod.rs index bce638db0..d64a1c28a 100644 --- a/embassy-stm32/src/flash/mod.rs +++ b/embassy-stm32/src/flash/mod.rs @@ -91,7 +91,7 @@ pub enum FlashBank { Bank2 = 1, } -#[cfg_attr(any(flash_l0, flash_l1, flash_l4, flash_wl, flash_wb), path = "l.rs")] +#[cfg_attr(any(flash_l0, flash_l1, flash_l4, flash_l5, flash_wl, flash_wb), path = "l.rs")] #[cfg_attr(flash_f0, path = "f0.rs")] #[cfg_attr(any(flash_f1, flash_f3), path = "f1f3.rs")] #[cfg_attr(flash_f2, path = "f2.rs")] @@ -105,8 +105,9 @@ pub enum FlashBank { #[cfg_attr(flash_u0, path = "u0.rs")] #[cfg_attr( not(any( - flash_l0, flash_l1, flash_l4, flash_wl, flash_wb, flash_f0, flash_f1, flash_f2, flash_f3, flash_f4, flash_f7, - flash_g0, flash_g4c2, flash_g4c3, flash_g4c4, flash_h7, flash_h7ab, flash_u5, flash_h50, flash_u0 + flash_l0, flash_l1, flash_l4, flash_l5, flash_wl, flash_wb, flash_f0, flash_f1, flash_f2, flash_f3, flash_f4, + flash_f7, flash_g0, flash_g0, flash_g4c2, flash_g4c3, flash_g4c4, flash_h7, flash_h7ab, flash_u5, flash_h50, + flash_u0 )), path = "other.rs" )] From dcdc0638b6fbec5b68055a5592d71458f83da875 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Fri, 18 Oct 2024 00:31:42 +0200 Subject: [PATCH 0238/1217] Update to rust 1.82. --- rust-toolchain.toml | 2 +- tests/nrf/src/bin/buffered_uart_spam.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 80acb3b5e..69a964040 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,5 +1,5 @@ [toolchain] -channel = "1.81" +channel = "1.82" components = [ "rust-src", "rustfmt", "llvm-tools" ] targets = [ "thumbv7em-none-eabi", diff --git a/tests/nrf/src/bin/buffered_uart_spam.rs b/tests/nrf/src/bin/buffered_uart_spam.rs index 843313537..45daaae0c 100644 --- a/tests/nrf/src/bin/buffered_uart_spam.rs +++ b/tests/nrf/src/bin/buffered_uart_spam.rs @@ -55,7 +55,7 @@ async fn main(_spawner: Spawner) { let task = unsafe { Task::new_unchecked(NonNull::new_unchecked(&spam_peri.tasks_starttx as *const _ as _)) }; let mut spam_ppi = Ppi::new_one_to_one(p.PPI_CH2, event, task); spam_ppi.enable(); - let p = unsafe { core::ptr::addr_of_mut!(TX_BUF) } as *mut u8; + let p = (&raw mut TX_BUF) as *mut u8; spam_peri.txd.ptr.write(|w| unsafe { w.ptr().bits(p as u32) }); spam_peri.txd.maxcnt.write(|w| unsafe { w.maxcnt().bits(NSPAM as _) }); spam_peri.tasks_starttx.write(|w| unsafe { w.bits(1) }); From 1f58e0efd05e5c96409db301e4d481098038aedf Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Fri, 18 Oct 2024 03:18:59 +0200 Subject: [PATCH 0239/1217] executor: fix unsoundness due to `impl Trait`, improve macro error handling. (#3425) * executor-macros: don't parse function bodies. * executor-macros: refactor for better recovery and ide-friendliness on errors. * executor-macros: disallow `impl Trait` in task arguments. Fixes #3420 * Fix example using `impl Trait` in tasks. --- embassy-executor-macros/Cargo.toml | 2 +- embassy-executor-macros/src/lib.rs | 50 +---- embassy-executor-macros/src/macros/main.rs | 240 ++++++++++----------- embassy-executor-macros/src/macros/task.rs | 155 ++++++++----- embassy-executor-macros/src/util.rs | 74 +++++++ embassy-executor-macros/src/util/ctxt.rs | 72 ------- embassy-executor-macros/src/util/mod.rs | 1 - examples/stm32h7/src/bin/i2c_shared.rs | 6 +- 8 files changed, 309 insertions(+), 291 deletions(-) create mode 100644 embassy-executor-macros/src/util.rs delete mode 100644 embassy-executor-macros/src/util/ctxt.rs delete mode 100644 embassy-executor-macros/src/util/mod.rs diff --git a/embassy-executor-macros/Cargo.toml b/embassy-executor-macros/Cargo.toml index 218e820ce..ef509c3f9 100644 --- a/embassy-executor-macros/Cargo.toml +++ b/embassy-executor-macros/Cargo.toml @@ -13,7 +13,7 @@ categories = [ ] [dependencies] -syn = { version = "2.0.15", features = ["full", "extra-traits"] } +syn = { version = "2.0.15", features = ["full", "visit"] } quote = "1.0.9" darling = "0.20.1" proc-macro2 = "1.0.29" diff --git a/embassy-executor-macros/src/lib.rs b/embassy-executor-macros/src/lib.rs index 61d388b9e..5f2182f10 100644 --- a/embassy-executor-macros/src/lib.rs +++ b/embassy-executor-macros/src/lib.rs @@ -1,28 +1,11 @@ #![doc = include_str!("../README.md")] extern crate proc_macro; -use darling::ast::NestedMeta; use proc_macro::TokenStream; mod macros; mod util; use macros::*; -use syn::parse::{Parse, ParseBuffer}; -use syn::punctuated::Punctuated; -use syn::Token; - -struct Args { - meta: Vec, -} - -impl Parse for Args { - fn parse(input: &ParseBuffer) -> syn::Result { - let meta = Punctuated::::parse_terminated(input)?; - Ok(Args { - meta: meta.into_iter().collect(), - }) - } -} /// Declares an async task that can be run by `embassy-executor`. The optional `pool_size` parameter can be used to specify how /// many concurrent tasks can be spawned (default is 1) for the function. @@ -56,17 +39,12 @@ impl Parse for Args { /// ``` #[proc_macro_attribute] pub fn task(args: TokenStream, item: TokenStream) -> TokenStream { - let args = syn::parse_macro_input!(args as Args); - let f = syn::parse_macro_input!(item as syn::ItemFn); - - task::run(&args.meta, f).unwrap_or_else(|x| x).into() + task::run(args.into(), item.into()).into() } #[proc_macro_attribute] pub fn main_avr(args: TokenStream, item: TokenStream) -> TokenStream { - let args = syn::parse_macro_input!(args as Args); - let f = syn::parse_macro_input!(item as syn::ItemFn); - main::run(&args.meta, f, main::avr()).unwrap_or_else(|x| x).into() + main::run(args.into(), item.into(), &main::ARCH_AVR).into() } /// Creates a new `executor` instance and declares an application entry point for Cortex-M spawning the corresponding function body as an async task. @@ -89,9 +67,7 @@ pub fn main_avr(args: TokenStream, item: TokenStream) -> TokenStream { /// ``` #[proc_macro_attribute] pub fn main_cortex_m(args: TokenStream, item: TokenStream) -> TokenStream { - let args = syn::parse_macro_input!(args as Args); - let f = syn::parse_macro_input!(item as syn::ItemFn); - main::run(&args.meta, f, main::cortex_m()).unwrap_or_else(|x| x).into() + main::run(args.into(), item.into(), &main::ARCH_CORTEX_M).into() } /// Creates a new `executor` instance and declares an architecture agnostic application entry point spawning @@ -116,11 +92,7 @@ pub fn main_cortex_m(args: TokenStream, item: TokenStream) -> TokenStream { /// ``` #[proc_macro_attribute] pub fn main_spin(args: TokenStream, item: TokenStream) -> TokenStream { - let args = syn::parse_macro_input!(args as Args); - let f = syn::parse_macro_input!(item as syn::ItemFn); - main::run(&args.meta, f, main::spin(&args.meta)) - .unwrap_or_else(|x| x) - .into() + main::run(args.into(), item.into(), &main::ARCH_SPIN).into() } /// Creates a new `executor` instance and declares an application entry point for RISC-V spawning the corresponding function body as an async task. @@ -153,11 +125,7 @@ pub fn main_spin(args: TokenStream, item: TokenStream) -> TokenStream { /// ``` #[proc_macro_attribute] pub fn main_riscv(args: TokenStream, item: TokenStream) -> TokenStream { - let args = syn::parse_macro_input!(args as Args); - let f = syn::parse_macro_input!(item as syn::ItemFn); - main::run(&args.meta, f, main::riscv(&args.meta)) - .unwrap_or_else(|x| x) - .into() + main::run(args.into(), item.into(), &main::ARCH_RISCV).into() } /// Creates a new `executor` instance and declares an application entry point for STD spawning the corresponding function body as an async task. @@ -180,9 +148,7 @@ pub fn main_riscv(args: TokenStream, item: TokenStream) -> TokenStream { /// ``` #[proc_macro_attribute] pub fn main_std(args: TokenStream, item: TokenStream) -> TokenStream { - let args = syn::parse_macro_input!(args as Args); - let f = syn::parse_macro_input!(item as syn::ItemFn); - main::run(&args.meta, f, main::std()).unwrap_or_else(|x| x).into() + main::run(args.into(), item.into(), &main::ARCH_STD).into() } /// Creates a new `executor` instance and declares an application entry point for WASM spawning the corresponding function body as an async task. @@ -205,7 +171,5 @@ pub fn main_std(args: TokenStream, item: TokenStream) -> TokenStream { /// ``` #[proc_macro_attribute] pub fn main_wasm(args: TokenStream, item: TokenStream) -> TokenStream { - let args = syn::parse_macro_input!(args as Args); - let f = syn::parse_macro_input!(item as syn::ItemFn); - main::run(&args.meta, f, main::wasm()).unwrap_or_else(|x| x).into() + main::run(args.into(), item.into(), &main::ARCH_WASM).into() } diff --git a/embassy-executor-macros/src/macros/main.rs b/embassy-executor-macros/src/macros/main.rs index 66a3965d0..14b1d9de2 100644 --- a/embassy-executor-macros/src/macros/main.rs +++ b/embassy-executor-macros/src/macros/main.rs @@ -1,152 +1,107 @@ +use std::str::FromStr; + use darling::export::NestedMeta; -use darling::{Error, FromMeta}; +use darling::FromMeta; use proc_macro2::TokenStream; use quote::quote; -use syn::{Expr, ReturnType, Type}; +use syn::{ReturnType, Type}; -use crate::util::ctxt::Ctxt; +use crate::util::*; -#[derive(Debug, FromMeta)] +enum Flavor { + Standard, + Wasm, +} + +pub(crate) struct Arch { + default_entry: Option<&'static str>, + flavor: Flavor, +} + +pub static ARCH_AVR: Arch = Arch { + default_entry: Some("avr_device::entry"), + flavor: Flavor::Standard, +}; + +pub static ARCH_RISCV: Arch = Arch { + default_entry: Some("riscv_rt::entry"), + flavor: Flavor::Standard, +}; + +pub static ARCH_CORTEX_M: Arch = Arch { + default_entry: Some("cortex_m_rt::entry"), + flavor: Flavor::Standard, +}; + +pub static ARCH_SPIN: Arch = Arch { + default_entry: None, + flavor: Flavor::Standard, +}; + +pub static ARCH_STD: Arch = Arch { + default_entry: None, + flavor: Flavor::Standard, +}; + +pub static ARCH_WASM: Arch = Arch { + default_entry: Some("wasm_bindgen::prelude::wasm_bindgen(start)"), + flavor: Flavor::Wasm, +}; + +#[derive(Debug, FromMeta, Default)] struct Args { #[darling(default)] entry: Option, } -pub fn avr() -> TokenStream { - quote! { - #[avr_device::entry] - fn main() -> ! { - let mut executor = ::embassy_executor::Executor::new(); - let executor = unsafe { __make_static(&mut executor) }; +pub fn run(args: TokenStream, item: TokenStream, arch: &Arch) -> TokenStream { + let mut errors = TokenStream::new(); - executor.run(|spawner| { - spawner.must_spawn(__embassy_main(spawner)); - }) - } - } -} - -pub fn riscv(args: &[NestedMeta]) -> TokenStream { - let maybe_entry = match Args::from_list(args) { - Ok(args) => args.entry, - Err(e) => return e.write_errors(), + // If any of the steps for this macro fail, we still want to expand to an item that is as close + // to the expected output as possible. This helps out IDEs such that completions and other + // related features keep working. + let f: ItemFn = match syn::parse2(item.clone()) { + Ok(x) => x, + Err(e) => return token_stream_with_error(item, e), }; - let entry = maybe_entry.unwrap_or("riscv_rt::entry".into()); - let entry = match Expr::from_string(&entry) { - Ok(expr) => expr, - Err(e) => return e.write_errors(), + let args = match NestedMeta::parse_meta_list(args) { + Ok(x) => x, + Err(e) => return token_stream_with_error(item, e), }; - quote! { - #[#entry] - fn main() -> ! { - let mut executor = ::embassy_executor::Executor::new(); - let executor = unsafe { __make_static(&mut executor) }; - executor.run(|spawner| { - spawner.must_spawn(__embassy_main(spawner)); - }) + let args = match Args::from_list(&args) { + Ok(x) => x, + Err(e) => { + errors.extend(e.write_errors()); + Args::default() } - } -} - -pub fn spin(args: &[NestedMeta]) -> TokenStream { - let maybe_entry = match Args::from_list(args) { - Ok(args) => args.entry, - Err(e) => return e.write_errors(), }; - let entry = match maybe_entry { - Some(str) => str, - None => return Error::missing_field("entry").write_errors(), - }; - let entry = match Expr::from_string(&entry) { - Ok(expr) => expr, - Err(e) => return e.write_errors(), - }; - - quote! { - #[#entry] - fn main() -> ! { - let mut executor = ::embassy_executor::Executor::new(); - let executor = unsafe { __make_static(&mut executor) }; - executor.run(|spawner| { - spawner.must_spawn(__embassy_main(spawner)); - }) - } - } -} - -pub fn cortex_m() -> TokenStream { - quote! { - #[cortex_m_rt::entry] - fn main() -> ! { - let mut executor = ::embassy_executor::Executor::new(); - let executor = unsafe { __make_static(&mut executor) }; - executor.run(|spawner| { - spawner.must_spawn(__embassy_main(spawner)); - }) - } - } -} - -pub fn wasm() -> TokenStream { - quote! { - #[wasm_bindgen::prelude::wasm_bindgen(start)] - pub fn main() -> Result<(), wasm_bindgen::JsValue> { - let executor = ::std::boxed::Box::leak(::std::boxed::Box::new(::embassy_executor::Executor::new())); - - executor.start(|spawner| { - spawner.must_spawn(__embassy_main(spawner)); - }); - - Ok(()) - } - } -} - -pub fn std() -> TokenStream { - quote! { - fn main() -> ! { - let mut executor = ::embassy_executor::Executor::new(); - let executor = unsafe { __make_static(&mut executor) }; - - executor.run(|spawner| { - spawner.must_spawn(__embassy_main(spawner)); - }) - } - } -} - -pub fn run(args: &[NestedMeta], f: syn::ItemFn, main: TokenStream) -> Result { - #[allow(unused_variables)] - let args = Args::from_list(args).map_err(|e| e.write_errors())?; - let fargs = f.sig.inputs.clone(); - let ctxt = Ctxt::new(); - if f.sig.asyncness.is_none() { - ctxt.error_spanned_by(&f.sig, "main function must be async"); + error(&mut errors, &f.sig, "main function must be async"); } if !f.sig.generics.params.is_empty() { - ctxt.error_spanned_by(&f.sig, "main function must not be generic"); + error(&mut errors, &f.sig, "main function must not be generic"); } if !f.sig.generics.where_clause.is_none() { - ctxt.error_spanned_by(&f.sig, "main function must not have `where` clauses"); + error(&mut errors, &f.sig, "main function must not have `where` clauses"); } if !f.sig.abi.is_none() { - ctxt.error_spanned_by(&f.sig, "main function must not have an ABI qualifier"); + error(&mut errors, &f.sig, "main function must not have an ABI qualifier"); } if !f.sig.variadic.is_none() { - ctxt.error_spanned_by(&f.sig, "main function must not be variadic"); + error(&mut errors, &f.sig, "main function must not be variadic"); } match &f.sig.output { ReturnType::Default => {} ReturnType::Type(_, ty) => match &**ty { Type::Tuple(tuple) if tuple.elems.is_empty() => {} Type::Never(_) => {} - _ => ctxt.error_spanned_by( + _ => error( + &mut errors, &f.sig, "main function must either not return a value, return `()` or return `!`", ), @@ -154,26 +109,69 @@ pub fn run(args: &[NestedMeta], f: syn::ItemFn, main: TokenStream) -> Result TokenStream::new(), + Some(x) => match TokenStream::from_str(x) { + Ok(x) => quote!(#[#x]), + Err(e) => { + error(&mut errors, &f.sig, e); + TokenStream::new() + } + }, + }; - let f_body = f.block; + let f_body = f.body; let out = &f.sig.output; + let (main_ret, mut main_body) = match arch.flavor { + Flavor::Standard => ( + quote!(!), + quote! { + unsafe fn __make_static(t: &mut T) -> &'static mut T { + ::core::mem::transmute(t) + } + + let mut executor = ::embassy_executor::Executor::new(); + let executor = unsafe { __make_static(&mut executor) }; + executor.run(|spawner| { + spawner.must_spawn(__embassy_main(spawner)); + }) + }, + ), + Flavor::Wasm => ( + quote!(Result<(), wasm_bindgen::JsValue>), + quote! { + let executor = ::std::boxed::Box::leak(::std::boxed::Box::new(::embassy_executor::Executor::new())); + + executor.start(|spawner| { + spawner.must_spawn(__embassy_main(spawner)); + }); + + Ok(()) + }, + ), + }; + + if !errors.is_empty() { + main_body = quote! {loop{}}; + } + let result = quote! { #[::embassy_executor::task()] async fn __embassy_main(#fargs) #out { #f_body } - unsafe fn __make_static(t: &mut T) -> &'static mut T { - ::core::mem::transmute(t) + #entry + fn main() -> #main_ret { + #main_body } - #main + #errors }; - Ok(result) + result } diff --git a/embassy-executor-macros/src/macros/task.rs b/embassy-executor-macros/src/macros/task.rs index 96c6267b2..0404dba64 100644 --- a/embassy-executor-macros/src/macros/task.rs +++ b/embassy-executor-macros/src/macros/task.rs @@ -2,47 +2,68 @@ use darling::export::NestedMeta; use darling::FromMeta; use proc_macro2::{Span, TokenStream}; use quote::{format_ident, quote}; -use syn::{parse_quote, Expr, ExprLit, ItemFn, Lit, LitInt, ReturnType, Type}; +use syn::visit::Visit; +use syn::{Expr, ExprLit, Lit, LitInt, ReturnType, Type}; -use crate::util::ctxt::Ctxt; +use crate::util::*; -#[derive(Debug, FromMeta)] +#[derive(Debug, FromMeta, Default)] struct Args { #[darling(default)] pool_size: Option, } -pub fn run(args: &[NestedMeta], f: syn::ItemFn) -> Result { - let args = Args::from_list(args).map_err(|e| e.write_errors())?; +pub fn run(args: TokenStream, item: TokenStream) -> TokenStream { + let mut errors = TokenStream::new(); + + // If any of the steps for this macro fail, we still want to expand to an item that is as close + // to the expected output as possible. This helps out IDEs such that completions and other + // related features keep working. + let f: ItemFn = match syn::parse2(item.clone()) { + Ok(x) => x, + Err(e) => return token_stream_with_error(item, e), + }; + + let args = match NestedMeta::parse_meta_list(args) { + Ok(x) => x, + Err(e) => return token_stream_with_error(item, e), + }; + + let args = match Args::from_list(&args) { + Ok(x) => x, + Err(e) => { + errors.extend(e.write_errors()); + Args::default() + } + }; let pool_size = args.pool_size.unwrap_or(Expr::Lit(ExprLit { attrs: vec![], lit: Lit::Int(LitInt::new("1", Span::call_site())), })); - let ctxt = Ctxt::new(); - if f.sig.asyncness.is_none() { - ctxt.error_spanned_by(&f.sig, "task functions must be async"); + error(&mut errors, &f.sig, "task functions must be async"); } if !f.sig.generics.params.is_empty() { - ctxt.error_spanned_by(&f.sig, "task functions must not be generic"); + error(&mut errors, &f.sig, "task functions must not be generic"); } if !f.sig.generics.where_clause.is_none() { - ctxt.error_spanned_by(&f.sig, "task functions must not have `where` clauses"); + error(&mut errors, &f.sig, "task functions must not have `where` clauses"); } if !f.sig.abi.is_none() { - ctxt.error_spanned_by(&f.sig, "task functions must not have an ABI qualifier"); + error(&mut errors, &f.sig, "task functions must not have an ABI qualifier"); } if !f.sig.variadic.is_none() { - ctxt.error_spanned_by(&f.sig, "task functions must not be variadic"); + error(&mut errors, &f.sig, "task functions must not be variadic"); } match &f.sig.output { ReturnType::Default => {} ReturnType::Type(_, ty) => match &**ty { Type::Tuple(tuple) if tuple.elems.is_empty() => {} Type::Never(_) => {} - _ => ctxt.error_spanned_by( + _ => error( + &mut errors, &f.sig, "task functions must either not return a value, return `()` or return `!`", ), @@ -55,26 +76,31 @@ pub fn run(args: &[NestedMeta], f: syn::ItemFn) -> Result { - ctxt.error_spanned_by(arg, "task functions must not have receiver arguments"); + error(&mut errors, arg, "task functions must not have receiver arguments"); } - syn::FnArg::Typed(t) => match t.pat.as_mut() { - syn::Pat::Ident(id) => { - id.mutability = None; - args.push((id.clone(), t.attrs.clone())); + syn::FnArg::Typed(t) => { + check_arg_ty(&mut errors, &t.ty); + match t.pat.as_mut() { + syn::Pat::Ident(id) => { + id.mutability = None; + args.push((id.clone(), t.attrs.clone())); + } + _ => { + error( + &mut errors, + arg, + "pattern matching in task arguments is not yet supported", + ); + } } - _ => { - ctxt.error_spanned_by(arg, "pattern matching in task arguments is not yet supported"); - } - }, + } } } - ctxt.check()?; - let task_ident = f.sig.ident.clone(); let task_inner_ident = format_ident!("__{}_task", task_ident); - let mut task_inner = f; + let mut task_inner = f.clone(); let visibility = task_inner.vis.clone(); task_inner.vis = syn::Visibility::Inherited; task_inner.sig.ident = task_inner_ident.clone(); @@ -91,35 +117,43 @@ pub fn run(args: &[NestedMeta], f: syn::ItemFn) -> Result ::embassy_executor::SpawnToken { - trait _EmbassyInternalTaskTrait { - type Fut: ::core::future::Future + 'static; - fn construct(#fargs) -> Self::Fut; - } - - impl _EmbassyInternalTaskTrait for () { - type Fut = impl core::future::Future + 'static; - fn construct(#fargs) -> Self::Fut { - #task_inner_ident(#(#full_args,)*) - } - } - - const POOL_SIZE: usize = #pool_size; - static POOL: ::embassy_executor::raw::TaskPool<<() as _EmbassyInternalTaskTrait>::Fut, POOL_SIZE> = ::embassy_executor::raw::TaskPool::new(); - unsafe { POOL._spawn_async_fn(move || <() as _EmbassyInternalTaskTrait>::construct(#(#full_args,)*)) } + let mut task_outer_body = quote! { + trait _EmbassyInternalTaskTrait { + type Fut: ::core::future::Future + 'static; + fn construct(#fargs) -> Self::Fut; } + + impl _EmbassyInternalTaskTrait for () { + type Fut = impl core::future::Future + 'static; + fn construct(#fargs) -> Self::Fut { + #task_inner_ident(#(#full_args,)*) + } + } + + const POOL_SIZE: usize = #pool_size; + static POOL: ::embassy_executor::raw::TaskPool<<() as _EmbassyInternalTaskTrait>::Fut, POOL_SIZE> = ::embassy_executor::raw::TaskPool::new(); + unsafe { POOL._spawn_async_fn(move || <() as _EmbassyInternalTaskTrait>::construct(#(#full_args,)*)) } }; #[cfg(not(feature = "nightly"))] - let mut task_outer: ItemFn = parse_quote! { - #visibility fn #task_ident(#fargs) -> ::embassy_executor::SpawnToken { - const POOL_SIZE: usize = #pool_size; - static POOL: ::embassy_executor::_export::TaskPoolRef = ::embassy_executor::_export::TaskPoolRef::new(); - unsafe { POOL.get::<_, POOL_SIZE>()._spawn_async_fn(move || #task_inner_ident(#(#full_args,)*)) } - } + let mut task_outer_body = quote! { + const POOL_SIZE: usize = #pool_size; + static POOL: ::embassy_executor::_export::TaskPoolRef = ::embassy_executor::_export::TaskPoolRef::new(); + unsafe { POOL.get::<_, POOL_SIZE>()._spawn_async_fn(move || #task_inner_ident(#(#full_args,)*)) } }; - task_outer.attrs.append(&mut task_inner.attrs.clone()); + let task_outer_attrs = task_inner.attrs.clone(); + + if !errors.is_empty() { + task_outer_body = quote! { + #![allow(unused_variables, unreachable_code)] + let _x: ::embassy_executor::SpawnToken<()> = ::core::todo!(); + _x + }; + } + + // Copy the generics + where clause to avoid more spurious errors. + let generics = &f.sig.generics; + let where_clause = &f.sig.generics.where_clause; let result = quote! { // This is the user's task function, renamed. @@ -129,8 +163,27 @@ pub fn run(args: &[NestedMeta], f: syn::ItemFn) -> Result ::embassy_executor::SpawnToken #where_clause{ + #task_outer_body + } + + #errors }; - Ok(result) + result +} + +fn check_arg_ty(errors: &mut TokenStream, ty: &Type) { + struct Visitor<'a> { + errors: &'a mut TokenStream, + } + + impl<'a, 'ast> Visit<'ast> for Visitor<'a> { + fn visit_type_impl_trait(&mut self, i: &'ast syn::TypeImplTrait) { + error(self.errors, i, "`impl Trait` is not allowed in task arguments. It is syntax sugar for generics, and tasks can't be generic."); + } + } + + Visit::visit_type(&mut Visitor { errors }, ty); } diff --git a/embassy-executor-macros/src/util.rs b/embassy-executor-macros/src/util.rs new file mode 100644 index 000000000..ebd032a62 --- /dev/null +++ b/embassy-executor-macros/src/util.rs @@ -0,0 +1,74 @@ +use std::fmt::Display; + +use proc_macro2::{TokenStream, TokenTree}; +use quote::{ToTokens, TokenStreamExt}; +use syn::parse::{Parse, ParseStream}; +use syn::{braced, bracketed, token, AttrStyle, Attribute, Signature, Token, Visibility}; + +pub fn token_stream_with_error(mut tokens: TokenStream, error: syn::Error) -> TokenStream { + tokens.extend(error.into_compile_error()); + tokens +} + +pub fn error(s: &mut TokenStream, obj: A, msg: T) { + s.extend(syn::Error::new_spanned(obj.into_token_stream(), msg).into_compile_error()) +} + +/// Function signature and body. +/// +/// Same as `syn`'s `ItemFn` except we keep the body as a TokenStream instead of +/// parsing it. This makes the macro not error if there's a syntax error in the body, +/// which helps IDE autocomplete work better. +#[derive(Debug, Clone)] +pub struct ItemFn { + pub attrs: Vec, + pub vis: Visibility, + pub sig: Signature, + pub brace_token: token::Brace, + pub body: TokenStream, +} + +impl Parse for ItemFn { + fn parse(input: ParseStream) -> syn::Result { + let mut attrs = input.call(Attribute::parse_outer)?; + let vis: Visibility = input.parse()?; + let sig: Signature = input.parse()?; + + let content; + let brace_token = braced!(content in input); + while content.peek(Token![#]) && content.peek2(Token![!]) { + let content2; + attrs.push(Attribute { + pound_token: content.parse()?, + style: AttrStyle::Inner(content.parse()?), + bracket_token: bracketed!(content2 in content), + meta: content2.parse()?, + }); + } + + let mut body = Vec::new(); + while !content.is_empty() { + body.push(content.parse::()?); + } + let body = body.into_iter().collect(); + + Ok(ItemFn { + attrs, + vis, + sig, + brace_token, + body, + }) + } +} + +impl ToTokens for ItemFn { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append_all(self.attrs.iter().filter(|a| matches!(a.style, AttrStyle::Outer))); + self.vis.to_tokens(tokens); + self.sig.to_tokens(tokens); + self.brace_token.surround(tokens, |tokens| { + tokens.append_all(self.body.clone()); + }); + } +} diff --git a/embassy-executor-macros/src/util/ctxt.rs b/embassy-executor-macros/src/util/ctxt.rs deleted file mode 100644 index 9c78cda01..000000000 --- a/embassy-executor-macros/src/util/ctxt.rs +++ /dev/null @@ -1,72 +0,0 @@ -// nifty utility borrowed from serde :) -// https://github.com/serde-rs/serde/blob/master/serde_derive/src/internals/ctxt.rs - -use std::cell::RefCell; -use std::fmt::Display; -use std::thread; - -use proc_macro2::TokenStream; -use quote::{quote, ToTokens}; - -/// A type to collect errors together and format them. -/// -/// Dropping this object will cause a panic. It must be consumed using `check`. -/// -/// References can be shared since this type uses run-time exclusive mut checking. -#[derive(Default)] -pub struct Ctxt { - // The contents will be set to `None` during checking. This is so that checking can be - // enforced. - errors: RefCell>>, -} - -impl Ctxt { - /// Create a new context object. - /// - /// This object contains no errors, but will still trigger a panic if it is not `check`ed. - pub fn new() -> Self { - Ctxt { - errors: RefCell::new(Some(Vec::new())), - } - } - - /// Add an error to the context object with a tokenenizable object. - /// - /// The object is used for spanning in error messages. - pub fn error_spanned_by(&self, obj: A, msg: T) { - self.errors - .borrow_mut() - .as_mut() - .unwrap() - // Curb monomorphization from generating too many identical methods. - .push(syn::Error::new_spanned(obj.into_token_stream(), msg)); - } - - /// Add one of Syn's parse errors. - #[allow(unused)] - pub fn syn_error(&self, err: syn::Error) { - self.errors.borrow_mut().as_mut().unwrap().push(err); - } - - /// Consume this object, producing a formatted error string if there are errors. - pub fn check(self) -> Result<(), TokenStream> { - let errors = self.errors.borrow_mut().take().unwrap(); - match errors.len() { - 0 => Ok(()), - _ => Err(to_compile_errors(errors)), - } - } -} - -fn to_compile_errors(errors: Vec) -> proc_macro2::TokenStream { - let compile_errors = errors.iter().map(syn::Error::to_compile_error); - quote!(#(#compile_errors)*) -} - -impl Drop for Ctxt { - fn drop(&mut self) { - if !thread::panicking() && self.errors.borrow().is_some() { - panic!("forgot to check for errors"); - } - } -} diff --git a/embassy-executor-macros/src/util/mod.rs b/embassy-executor-macros/src/util/mod.rs deleted file mode 100644 index 28702809e..000000000 --- a/embassy-executor-macros/src/util/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod ctxt; diff --git a/examples/stm32h7/src/bin/i2c_shared.rs b/examples/stm32h7/src/bin/i2c_shared.rs index 6f4815582..136b91eeb 100644 --- a/examples/stm32h7/src/bin/i2c_shared.rs +++ b/examples/stm32h7/src/bin/i2c_shared.rs @@ -10,8 +10,10 @@ use embassy_stm32::i2c::{self, I2c}; use embassy_stm32::mode::Async; use embassy_stm32::time::Hertz; use embassy_stm32::{bind_interrupts, peripherals}; +use embassy_sync::blocking_mutex::raw::NoopRawMutex; use embassy_sync::blocking_mutex::NoopMutex; use embassy_time::{Duration, Timer}; +use embedded_hal_1::i2c::I2c as _; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; @@ -31,7 +33,7 @@ bind_interrupts!(struct Irqs { }); #[embassy_executor::task] -async fn temperature(mut i2c: impl embedded_hal_1::i2c::I2c + 'static) { +async fn temperature(mut i2c: I2cDevice<'static, NoopRawMutex, I2c<'static, Async>>) { let mut data = [0u8; 2]; loop { @@ -48,7 +50,7 @@ async fn temperature(mut i2c: impl embedded_hal_1::i2c::I2c + 'static) { } #[embassy_executor::task] -async fn humidity(mut i2c: impl embedded_hal_1::i2c::I2c + 'static) { +async fn humidity(mut i2c: I2cDevice<'static, NoopRawMutex, I2c<'static, Async>>) { let mut data = [0u8; 6]; loop { From f21b19164be17df930aa557a90b3c5ab1dc39b9e Mon Sep 17 00:00:00 2001 From: Christian Enderle Date: Sat, 19 Oct 2024 15:36:56 +0200 Subject: [PATCH 0240/1217] embassy-futures: add select 5 and 6 --- embassy-futures/src/select.rs | 163 ++++++++++++++++++++++++++++++++++ 1 file changed, 163 insertions(+) diff --git a/embassy-futures/src/select.rs b/embassy-futures/src/select.rs index 57f0cb41f..bb175253b 100644 --- a/embassy-futures/src/select.rs +++ b/embassy-futures/src/select.rs @@ -188,6 +188,169 @@ where // ==================================================================== +/// Result for [`select5`]. +#[derive(Debug, Clone)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum Either5 { + /// First future finished first. + First(A), + /// Second future finished first. + Second(B), + /// Third future finished first. + Third(C), + /// Fourth future finished first. + Fourth(D), + /// Fifth future finished first. + Fifth(E), +} + +/// Same as [`select`], but with more futures. +pub fn select5(a: A, b: B, c: C, d: D, e: E) -> Select5 +where + A: Future, + B: Future, + C: Future, + D: Future, + E: Future, +{ + Select5 { a, b, c, d, e } +} + +/// Future for the [`select5`] function. +#[derive(Debug)] +#[must_use = "futures do nothing unless you `.await` or poll them"] +pub struct Select5 { + a: A, + b: B, + c: C, + d: D, + e: E, +} + +impl Future for Select5 +where + A: Future, + B: Future, + C: Future, + D: Future, + E: Future, +{ + type Output = Either5; + + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + let this = unsafe { self.get_unchecked_mut() }; + let a = unsafe { Pin::new_unchecked(&mut this.a) }; + let b = unsafe { Pin::new_unchecked(&mut this.b) }; + let c = unsafe { Pin::new_unchecked(&mut this.c) }; + let d = unsafe { Pin::new_unchecked(&mut this.d) }; + let e = unsafe { Pin::new_unchecked(&mut this.e) }; + if let Poll::Ready(x) = a.poll(cx) { + return Poll::Ready(Either5::First(x)); + } + if let Poll::Ready(x) = b.poll(cx) { + return Poll::Ready(Either5::Second(x)); + } + if let Poll::Ready(x) = c.poll(cx) { + return Poll::Ready(Either5::Third(x)); + } + if let Poll::Ready(x) = d.poll(cx) { + return Poll::Ready(Either5::Fourth(x)); + } + if let Poll::Ready(x) = e.poll(cx) { + return Poll::Ready(Either5::Fifth(x)); + } + Poll::Pending + } +} + +// ==================================================================== + +/// Result for [`select6`]. +#[derive(Debug, Clone)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum Either6 { + /// First future finished first. + First(A), + /// Second future finished first. + Second(B), + /// Third future finished first. + Third(C), + /// Fourth future finished first. + Fourth(D), + /// Fifth future finished first. + Fifth(E), + /// Sixth future finished first. + Sixth(F), +} + +/// Same as [`select`], but with more futures. +pub fn select6(a: A, b: B, c: C, d: D, e: E, f: F) -> Select6 +where + A: Future, + B: Future, + C: Future, + D: Future, + E: Future, + F: Future, +{ + Select6 { a, b, c, d, e, f } +} + +/// Future for the [`select6`] function. +#[derive(Debug)] +#[must_use = "futures do nothing unless you `.await` or poll them"] +pub struct Select6 { + a: A, + b: B, + c: C, + d: D, + e: E, + f: F, +} + +impl Future for Select6 +where + A: Future, + B: Future, + C: Future, + D: Future, + E: Future, + F: Future, +{ + type Output = Either6; + + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + let this = unsafe { self.get_unchecked_mut() }; + let a = unsafe { Pin::new_unchecked(&mut this.a) }; + let b = unsafe { Pin::new_unchecked(&mut this.b) }; + let c = unsafe { Pin::new_unchecked(&mut this.c) }; + let d = unsafe { Pin::new_unchecked(&mut this.d) }; + let e = unsafe { Pin::new_unchecked(&mut this.e) }; + let f = unsafe { Pin::new_unchecked(&mut this.f) }; + if let Poll::Ready(x) = a.poll(cx) { + return Poll::Ready(Either6::First(x)); + } + if let Poll::Ready(x) = b.poll(cx) { + return Poll::Ready(Either6::Second(x)); + } + if let Poll::Ready(x) = c.poll(cx) { + return Poll::Ready(Either6::Third(x)); + } + if let Poll::Ready(x) = d.poll(cx) { + return Poll::Ready(Either6::Fourth(x)); + } + if let Poll::Ready(x) = e.poll(cx) { + return Poll::Ready(Either6::Fifth(x)); + } + if let Poll::Ready(x) = f.poll(cx) { + return Poll::Ready(Either6::Sixth(x)); + } + Poll::Pending + } +} + +// ==================================================================== + /// Future for the [`select_array`] function. #[derive(Debug)] #[must_use = "futures do nothing unless you `.await` or poll them"] From 7fc09f89e8e4b611a868bc986104762b1c5ba81a Mon Sep 17 00:00:00 2001 From: rafael Date: Sun, 20 Oct 2024 23:28:47 +0200 Subject: [PATCH 0241/1217] embassy_rp: implement pwm traits from embedded_hal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit • Update crate versions • Implement embedded-hal PWM traits • Add TB6612FNG motor driver example --- embassy-rp/Cargo.toml | 8 +- embassy-rp/src/pwm.rs | 42 +++++++ examples/rp23/Cargo.toml | 3 + .../src/bin/pwm_tb6612fng_motor_driver.rs | 114 ++++++++++++++++++ 4 files changed, 163 insertions(+), 4 deletions(-) create mode 100644 examples/rp23/src/bin/pwm_tb6612fng_motor_driver.rs diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index 54de238b3..baa92398b 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml @@ -118,18 +118,18 @@ embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver" } atomic-polyfill = "1.0.1" defmt = { version = "0.3", optional = true } log = { version = "0.4.14", optional = true } -nb = "1.0.0" +nb = "1.1.0" cfg-if = "1.0.0" cortex-m-rt = ">=0.6.15,<0.8" cortex-m = "0.7.6" -critical-section = "1.1" +critical-section = "1.2.0" chrono = { version = "0.4", default-features = false, optional = true } embedded-io = { version = "0.6.1" } embedded-io-async = { version = "0.6.1" } embedded-storage = { version = "0.3" } embedded-storage-async = { version = "0.4.1" } rand_core = "0.6.4" -fixed = "1.23.1" +fixed = "1.28.0" rp-pac = { git = "https://github.com/embassy-rs/rp-pac.git", rev = "a7f42d25517f7124ad3b4ed492dec8b0f50a0e6c", feature = ["rt"] } @@ -141,7 +141,7 @@ embedded-hal-nb = { version = "1.0" } pio-proc = {version= "0.2" } pio = {version= "0.2.1" } rp2040-boot2 = "0.3" -document-features = "0.2.7" +document-features = "0.2.10" sha2-const-stable = "0.1" rp-binary-info = { version = "0.1.0", optional = true } smart-leds = "0.4.0" diff --git a/embassy-rp/src/pwm.rs b/embassy-rp/src/pwm.rs index 027f5504e..79e626802 100644 --- a/embassy-rp/src/pwm.rs +++ b/embassy-rp/src/pwm.rs @@ -1,6 +1,7 @@ //! Pulse Width Modulation (PWM) use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; +use embedded_hal_1::pwm::{Error, ErrorKind, ErrorType, SetDutyCycle}; use fixed::traits::ToFixed; use fixed::FixedU16; use pac::pwm::regs::{ChDiv, Intr}; @@ -80,6 +81,21 @@ impl From for Divmode { } } +/// PWM error. +#[derive(Debug)] +pub enum PwmError { + /// Invalid Duty Cycle. + InvalidDutyCycle, +} + +impl Error for PwmError { + fn kind(&self) -> ErrorKind { + match self { + PwmError::InvalidDutyCycle => ErrorKind::Other, + } + } +} + /// PWM driver. pub struct Pwm<'d> { pin_a: Option>, @@ -87,6 +103,32 @@ pub struct Pwm<'d> { slice: usize, } +impl<'d> ErrorType for Pwm<'d> { + type Error = PwmError; +} + +impl<'d> SetDutyCycle for Pwm<'d> { + fn max_duty_cycle(&self) -> u16 { + pac::PWM.ch(self.slice).top().read().top() + } + + fn set_duty_cycle(&mut self, duty: u16) -> Result<(), Self::Error> { + info!("duty {}",&duty); + let max_duty = self.max_duty_cycle(); + info!("max duty {}", &max_duty); + if duty > max_duty { + return Err(PwmError::InvalidDutyCycle); + } + + let p = pac::PWM.ch(self.slice); + p.cc().modify(|w| { + w.set_a(duty); + w.set_b(duty); + }); + Ok(()) + } +} + impl<'d> Pwm<'d> { fn new_inner( slice: usize, diff --git a/examples/rp23/Cargo.toml b/examples/rp23/Cargo.toml index 08646463c..f35e3a11d 100644 --- a/examples/rp23/Cargo.toml +++ b/examples/rp23/Cargo.toml @@ -30,6 +30,9 @@ serde-json-core = "0.5.1" # for assign resources example assign-resources = { git = "https://github.com/adamgreig/assign-resources", rev = "94ad10e2729afdf0fd5a77cd12e68409a982f58a" } +# for TB6612FNG example +tb6612fng = "1.0.0" + #cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } cortex-m = { version = "0.7.6", features = ["inline-asm"] } cortex-m-rt = "0.7.0" diff --git a/examples/rp23/src/bin/pwm_tb6612fng_motor_driver.rs b/examples/rp23/src/bin/pwm_tb6612fng_motor_driver.rs new file mode 100644 index 000000000..92c1ff6ba --- /dev/null +++ b/examples/rp23/src/bin/pwm_tb6612fng_motor_driver.rs @@ -0,0 +1,114 @@ +//! # PWM TB6612FNG motor driver +//! +//! This example shows the use of a TB6612FNG motor driver. The driver is built on top of embedded_hal and the example demonstrates how embassy_rp can be used to interact with ist. + +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_rp::block::ImageDef; +use embassy_rp::config::Config; +use embassy_rp::gpio::Output; +use embassy_rp::peripherals; +use embassy_rp::gpio; +use embassy_rp::pwm; +use embassy_time::Duration; +use embassy_time::Timer; +use {defmt_rtt as _, panic_probe as _}; +use tb6612fng::{DriveCommand, Motor, Tb6612fng}; +use assign_resources::assign_resources; + +/// Maximum PWM value (fully on) +const PWM_MAX: u16 = 50000; + +/// Minimum PWM value (fully off) +const PWM_MIN: u16 = 0; + +#[link_section = ".start_block"] +#[used] +pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); + +assign_resources! { + motor: MotorResources { + standby_pin: PIN_22, + left_slice: PWM_SLICE6, + left_pwm_pin: PIN_28, + left_forward_pin: PIN_21, + left_backward_pin: PIN_20, + right_slice: PWM_SLICE5, + right_pwm_pin: PIN_27, + right_forward_pin: PIN_19, + right_backward_pin: PIN_18, + }, +} + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_rp::init(Config::default()); + let s = split_resources!(p); + let r = s.motor; + + // we need a standby output and two motors to construct a full TB6612FNG + + // standby pin + let stby = Output::new(r.standby_pin, gpio::Level::Low); + + // motor A, here defined to be the left motor + let left_fwd = gpio::Output::new(r.left_forward_pin, gpio::Level::Low); + let left_bckw = gpio::Output::new(r.left_backward_pin, gpio::Level::Low); + let mut left_speed = pwm::Config::default(); + left_speed.top = PWM_MAX; + left_speed.compare_a = PWM_MIN; + let left_pwm = pwm::Pwm::new_output_a(r.left_slice, r.left_pwm_pin, left_speed); + let left_motor = Motor::new(left_fwd, left_bckw, left_pwm).unwrap(); + + // motor B, here defined to be the right motor + let right_fwd = gpio::Output::new(r.right_forward_pin, gpio::Level::Low); + let right_bckw = gpio::Output::new(r.right_backward_pin, gpio::Level::Low); + let mut right_speed = pwm::Config::default(); + right_speed.top = PWM_MAX; + right_speed.compare_b = PWM_MIN; + let right_pwm = pwm::Pwm::new_output_b(r.right_slice, r.right_pwm_pin, right_speed); + let right_motor = Motor::new(right_fwd, right_bckw, right_pwm).unwrap(); + + // construct the motor driver + let mut control = Tb6612fng::new(left_motor, right_motor, stby).unwrap(); + + loop { + // wake up the motor driver + info!("end standby"); + control.disable_standby().unwrap(); + Timer::after(Duration::from_millis(100)).await; + + // drive a straight line forward at 20% speed for 5s + info!("drive straight"); + control.motor_a.drive(DriveCommand::Forward(20)).unwrap(); + control.motor_b.drive(DriveCommand::Forward(20)).unwrap(); + Timer::after(Duration::from_secs(5)).await; + + // coast for 2s + info!("coast"); + control.motor_a.drive(DriveCommand::Stop).unwrap(); + control.motor_b.drive(DriveCommand::Stop).unwrap(); + Timer::after(Duration::from_secs(2)).await; + + // actively brake + info!("brake"); + control.motor_a.drive(DriveCommand::Brake).unwrap(); + control.motor_b.drive(DriveCommand::Brake).unwrap(); + Timer::after(Duration::from_secs(1)).await; + + // slowly turn for 3s + info!( "turn"); + control.motor_a.drive(DriveCommand::Backward(10)).unwrap(); + control.motor_b.drive(DriveCommand::Forward(10)).unwrap(); + Timer::after(Duration::from_secs(3)).await; + + // and put the driver in standby mode and wait for 5s + info!( "standby"); + control.enable_standby().unwrap(); + Timer::after(Duration::from_secs(5)).await; + } +} + From 8baf88f8f4668bdb54c1415bdb8ad62cf2fa5f24 Mon Sep 17 00:00:00 2001 From: rafael Date: Sun, 20 Oct 2024 23:31:53 +0200 Subject: [PATCH 0242/1217] rustfmt --- .../rp23/src/bin/pwm_tb6612fng_motor_driver.rs | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/examples/rp23/src/bin/pwm_tb6612fng_motor_driver.rs b/examples/rp23/src/bin/pwm_tb6612fng_motor_driver.rs index 92c1ff6ba..36b8d9620 100644 --- a/examples/rp23/src/bin/pwm_tb6612fng_motor_driver.rs +++ b/examples/rp23/src/bin/pwm_tb6612fng_motor_driver.rs @@ -1,23 +1,23 @@ //! # PWM TB6612FNG motor driver -//! +//! //! This example shows the use of a TB6612FNG motor driver. The driver is built on top of embedded_hal and the example demonstrates how embassy_rp can be used to interact with ist. #![no_std] #![no_main] +use assign_resources::assign_resources; use defmt::*; use embassy_executor::Spawner; use embassy_rp::block::ImageDef; use embassy_rp::config::Config; +use embassy_rp::gpio; use embassy_rp::gpio::Output; use embassy_rp::peripherals; -use embassy_rp::gpio; use embassy_rp::pwm; use embassy_time::Duration; use embassy_time::Timer; -use {defmt_rtt as _, panic_probe as _}; use tb6612fng::{DriveCommand, Motor, Tb6612fng}; -use assign_resources::assign_resources; +use {defmt_rtt as _, panic_probe as _}; /// Maximum PWM value (fully on) const PWM_MAX: u16 = 50000; @@ -94,21 +94,20 @@ async fn main(_spawner: Spawner) { Timer::after(Duration::from_secs(2)).await; // actively brake - info!("brake"); + info!("brake"); control.motor_a.drive(DriveCommand::Brake).unwrap(); control.motor_b.drive(DriveCommand::Brake).unwrap(); Timer::after(Duration::from_secs(1)).await; // slowly turn for 3s - info!( "turn"); + info!("turn"); control.motor_a.drive(DriveCommand::Backward(10)).unwrap(); control.motor_b.drive(DriveCommand::Forward(10)).unwrap(); Timer::after(Duration::from_secs(3)).await; // and put the driver in standby mode and wait for 5s - info!( "standby"); + info!("standby"); control.enable_standby().unwrap(); Timer::after(Duration::from_secs(5)).await; } } - From f0de0493084759a5e7310c816919996b201f0bc4 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sun, 20 Oct 2024 23:45:10 +0200 Subject: [PATCH 0243/1217] executor-macros: improve error messages. --- embassy-executor-macros/src/macros/task.rs | 26 ++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/embassy-executor-macros/src/macros/task.rs b/embassy-executor-macros/src/macros/task.rs index 0404dba64..2f2aeda76 100644 --- a/embassy-executor-macros/src/macros/task.rs +++ b/embassy-executor-macros/src/macros/task.rs @@ -2,7 +2,7 @@ use darling::export::NestedMeta; use darling::FromMeta; use proc_macro2::{Span, TokenStream}; use quote::{format_ident, quote}; -use syn::visit::Visit; +use syn::visit::{self, Visit}; use syn::{Expr, ExprLit, Lit, LitInt, ReturnType, Type}; use crate::util::*; @@ -76,7 +76,7 @@ pub fn run(args: TokenStream, item: TokenStream) -> TokenStream { for arg in fargs.iter_mut() { match arg { syn::FnArg::Receiver(_) => { - error(&mut errors, arg, "task functions must not have receiver arguments"); + error(&mut errors, arg, "task functions must not have `self` arguments"); } syn::FnArg::Typed(t) => { check_arg_ty(&mut errors, &t.ty); @@ -180,6 +180,28 @@ fn check_arg_ty(errors: &mut TokenStream, ty: &Type) { } impl<'a, 'ast> Visit<'ast> for Visitor<'a> { + fn visit_type_reference(&mut self, i: &'ast syn::TypeReference) { + // only check for elided lifetime here. If not elided, it's checked by `visit_lifetime`. + if i.lifetime.is_none() { + error( + self.errors, + i.and_token, + "Arguments for tasks must live forever. Try using the `'static` lifetime.", + ) + } + visit::visit_type_reference(self, i); + } + + fn visit_lifetime(&mut self, i: &'ast syn::Lifetime) { + if i.ident.to_string() != "static" { + error( + self.errors, + i, + "Arguments for tasks must live forever. Try using the `'static` lifetime.", + ) + } + } + fn visit_type_impl_trait(&mut self, i: &'ast syn::TypeImplTrait) { error(self.errors, i, "`impl Trait` is not allowed in task arguments. It is syntax sugar for generics, and tasks can't be generic."); } From 8f9826872332fb0d2abd3ffc3889ff4c0e1c3909 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sun, 20 Oct 2024 23:48:58 +0200 Subject: [PATCH 0244/1217] executor: add compile-fail / ui tests. --- .github/ci/test-nightly.sh | 3 +++ .github/ci/test.sh | 1 + embassy-executor/Cargo.toml | 2 +- embassy-executor/tests/ui.rs | 23 +++++++++++++++++++ embassy-executor/tests/ui/abi.rs | 8 +++++++ embassy-executor/tests/ui/abi.stderr | 5 ++++ embassy-executor/tests/ui/bad_return.rs | 10 ++++++++ embassy-executor/tests/ui/bad_return.stderr | 5 ++++ embassy-executor/tests/ui/generics.rs | 8 +++++++ embassy-executor/tests/ui/generics.stderr | 5 ++++ embassy-executor/tests/ui/impl_trait.rs | 6 +++++ embassy-executor/tests/ui/impl_trait.stderr | 5 ++++ .../tests/ui/impl_trait_nested.rs | 8 +++++++ .../tests/ui/impl_trait_nested.stderr | 5 ++++ .../tests/ui/impl_trait_static.rs | 6 +++++ .../tests/ui/impl_trait_static.stderr | 5 ++++ .../tests/ui/nonstatic_ref_anon.rs | 6 +++++ .../tests/ui/nonstatic_ref_anon.stderr | 5 ++++ .../tests/ui/nonstatic_ref_anon_nested.rs | 6 +++++ .../tests/ui/nonstatic_ref_anon_nested.stderr | 5 ++++ .../tests/ui/nonstatic_ref_elided.rs | 6 +++++ .../tests/ui/nonstatic_ref_elided.stderr | 5 ++++ .../tests/ui/nonstatic_ref_generic.rs | 6 +++++ .../tests/ui/nonstatic_ref_generic.stderr | 11 +++++++++ .../tests/ui/nonstatic_struct_anon.rs | 8 +++++++ .../tests/ui/nonstatic_struct_anon.stderr | 5 ++++ .../tests/ui/nonstatic_struct_elided.rs | 8 +++++++ .../tests/ui/nonstatic_struct_elided.stderr | 10 ++++++++ .../tests/ui/nonstatic_struct_generic.rs | 8 +++++++ .../tests/ui/nonstatic_struct_generic.stderr | 11 +++++++++ embassy-executor/tests/ui/not_async.rs | 8 +++++++ embassy-executor/tests/ui/not_async.stderr | 5 ++++ embassy-executor/tests/ui/self.rs | 8 +++++++ embassy-executor/tests/ui/self.stderr | 13 +++++++++++ embassy-executor/tests/ui/self_ref.rs | 8 +++++++ embassy-executor/tests/ui/self_ref.stderr | 13 +++++++++++ embassy-executor/tests/ui/where_clause.rs | 12 ++++++++++ embassy-executor/tests/ui/where_clause.stderr | 7 ++++++ 38 files changed, 278 insertions(+), 1 deletion(-) create mode 100644 embassy-executor/tests/ui.rs create mode 100644 embassy-executor/tests/ui/abi.rs create mode 100644 embassy-executor/tests/ui/abi.stderr create mode 100644 embassy-executor/tests/ui/bad_return.rs create mode 100644 embassy-executor/tests/ui/bad_return.stderr create mode 100644 embassy-executor/tests/ui/generics.rs create mode 100644 embassy-executor/tests/ui/generics.stderr create mode 100644 embassy-executor/tests/ui/impl_trait.rs create mode 100644 embassy-executor/tests/ui/impl_trait.stderr create mode 100644 embassy-executor/tests/ui/impl_trait_nested.rs create mode 100644 embassy-executor/tests/ui/impl_trait_nested.stderr create mode 100644 embassy-executor/tests/ui/impl_trait_static.rs create mode 100644 embassy-executor/tests/ui/impl_trait_static.stderr create mode 100644 embassy-executor/tests/ui/nonstatic_ref_anon.rs create mode 100644 embassy-executor/tests/ui/nonstatic_ref_anon.stderr create mode 100644 embassy-executor/tests/ui/nonstatic_ref_anon_nested.rs create mode 100644 embassy-executor/tests/ui/nonstatic_ref_anon_nested.stderr create mode 100644 embassy-executor/tests/ui/nonstatic_ref_elided.rs create mode 100644 embassy-executor/tests/ui/nonstatic_ref_elided.stderr create mode 100644 embassy-executor/tests/ui/nonstatic_ref_generic.rs create mode 100644 embassy-executor/tests/ui/nonstatic_ref_generic.stderr create mode 100644 embassy-executor/tests/ui/nonstatic_struct_anon.rs create mode 100644 embassy-executor/tests/ui/nonstatic_struct_anon.stderr create mode 100644 embassy-executor/tests/ui/nonstatic_struct_elided.rs create mode 100644 embassy-executor/tests/ui/nonstatic_struct_elided.stderr create mode 100644 embassy-executor/tests/ui/nonstatic_struct_generic.rs create mode 100644 embassy-executor/tests/ui/nonstatic_struct_generic.stderr create mode 100644 embassy-executor/tests/ui/not_async.rs create mode 100644 embassy-executor/tests/ui/not_async.stderr create mode 100644 embassy-executor/tests/ui/self.rs create mode 100644 embassy-executor/tests/ui/self.stderr create mode 100644 embassy-executor/tests/ui/self_ref.rs create mode 100644 embassy-executor/tests/ui/self_ref.stderr create mode 100644 embassy-executor/tests/ui/where_clause.rs create mode 100644 embassy-executor/tests/ui/where_clause.stderr diff --git a/.github/ci/test-nightly.sh b/.github/ci/test-nightly.sh index 1724ffe89..a03b55e8d 100755 --- a/.github/ci/test-nightly.sh +++ b/.github/ci/test-nightly.sh @@ -9,6 +9,9 @@ export CARGO_HOME=/ci/cache/cargo export CARGO_TARGET_DIR=/ci/cache/target mv rust-toolchain-nightly.toml rust-toolchain.toml +cargo test --manifest-path ./embassy-executor/Cargo.toml +cargo test --manifest-path ./embassy-executor/Cargo.toml --features nightly + MIRIFLAGS=-Zmiri-ignore-leaks cargo miri test --manifest-path ./embassy-executor/Cargo.toml MIRIFLAGS=-Zmiri-ignore-leaks cargo miri test --manifest-path ./embassy-executor/Cargo.toml --features nightly MIRIFLAGS=-Zmiri-ignore-leaks cargo miri test --manifest-path ./embassy-sync/Cargo.toml diff --git a/.github/ci/test.sh b/.github/ci/test.sh index 0de265049..0fe088bfe 100755 --- a/.github/ci/test.sh +++ b/.github/ci/test.sh @@ -12,6 +12,7 @@ export CARGO_TARGET_DIR=/ci/cache/target # used when pointing stm32-metapac to a CI-built one. export CARGO_NET_GIT_FETCH_WITH_CLI=true +cargo test --manifest-path ./embassy-executor/Cargo.toml cargo test --manifest-path ./embassy-futures/Cargo.toml cargo test --manifest-path ./embassy-sync/Cargo.toml cargo test --manifest-path ./embassy-embedded-hal/Cargo.toml diff --git a/embassy-executor/Cargo.toml b/embassy-executor/Cargo.toml index e2fedce3c..e138f93b0 100644 --- a/embassy-executor/Cargo.toml +++ b/embassy-executor/Cargo.toml @@ -55,7 +55,7 @@ avr-device = { version = "0.5.3", optional = true } [dev-dependencies] critical-section = { version = "1.1", features = ["std"] } - +trybuild = "1.0" [features] diff --git a/embassy-executor/tests/ui.rs b/embassy-executor/tests/ui.rs new file mode 100644 index 000000000..be4679485 --- /dev/null +++ b/embassy-executor/tests/ui.rs @@ -0,0 +1,23 @@ +#[cfg(not(miri))] +#[test] +fn ui() { + let t = trybuild::TestCases::new(); + t.compile_fail("tests/ui/abi.rs"); + t.compile_fail("tests/ui/bad_return.rs"); + t.compile_fail("tests/ui/generics.rs"); + t.compile_fail("tests/ui/impl_trait_nested.rs"); + t.compile_fail("tests/ui/impl_trait.rs"); + t.compile_fail("tests/ui/impl_trait_static.rs"); + t.compile_fail("tests/ui/nonstatic_ref_anon_nested.rs"); + t.compile_fail("tests/ui/nonstatic_ref_anon.rs"); + t.compile_fail("tests/ui/nonstatic_ref_elided.rs"); + t.compile_fail("tests/ui/nonstatic_ref_generic.rs"); + t.compile_fail("tests/ui/nonstatic_struct_anon.rs"); + #[cfg(not(feature = "nightly"))] // we can't catch this case with the macro, so the output changes on nightly. + t.compile_fail("tests/ui/nonstatic_struct_elided.rs"); + t.compile_fail("tests/ui/nonstatic_struct_generic.rs"); + t.compile_fail("tests/ui/not_async.rs"); + t.compile_fail("tests/ui/self_ref.rs"); + t.compile_fail("tests/ui/self.rs"); + t.compile_fail("tests/ui/where_clause.rs"); +} diff --git a/embassy-executor/tests/ui/abi.rs b/embassy-executor/tests/ui/abi.rs new file mode 100644 index 000000000..fd52f7e41 --- /dev/null +++ b/embassy-executor/tests/ui/abi.rs @@ -0,0 +1,8 @@ +#![cfg_attr(feature = "nightly", feature(impl_trait_in_assoc_type))] + +struct Foo<'a>(&'a ()); + +#[embassy_executor::task] +async extern "C" fn task() {} + +fn main() {} diff --git a/embassy-executor/tests/ui/abi.stderr b/embassy-executor/tests/ui/abi.stderr new file mode 100644 index 000000000..e264e371a --- /dev/null +++ b/embassy-executor/tests/ui/abi.stderr @@ -0,0 +1,5 @@ +error: task functions must not have an ABI qualifier + --> tests/ui/abi.rs:6:1 + | +6 | async extern "C" fn task() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/embassy-executor/tests/ui/bad_return.rs b/embassy-executor/tests/ui/bad_return.rs new file mode 100644 index 000000000..f09a5205b --- /dev/null +++ b/embassy-executor/tests/ui/bad_return.rs @@ -0,0 +1,10 @@ +#![cfg_attr(feature = "nightly", feature(impl_trait_in_assoc_type))] + +struct Foo<'a>(&'a ()); + +#[embassy_executor::task] +async fn task() -> u32 { + 5 +} + +fn main() {} diff --git a/embassy-executor/tests/ui/bad_return.stderr b/embassy-executor/tests/ui/bad_return.stderr new file mode 100644 index 000000000..e9d94dff8 --- /dev/null +++ b/embassy-executor/tests/ui/bad_return.stderr @@ -0,0 +1,5 @@ +error: task functions must either not return a value, return `()` or return `!` + --> tests/ui/bad_return.rs:6:1 + | +6 | async fn task() -> u32 { + | ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/embassy-executor/tests/ui/generics.rs b/embassy-executor/tests/ui/generics.rs new file mode 100644 index 000000000..b83123bb1 --- /dev/null +++ b/embassy-executor/tests/ui/generics.rs @@ -0,0 +1,8 @@ +#![cfg_attr(feature = "nightly", feature(impl_trait_in_assoc_type))] + +struct Foo<'a>(&'a ()); + +#[embassy_executor::task] +async fn task(_t: T) {} + +fn main() {} diff --git a/embassy-executor/tests/ui/generics.stderr b/embassy-executor/tests/ui/generics.stderr new file mode 100644 index 000000000..197719a7b --- /dev/null +++ b/embassy-executor/tests/ui/generics.stderr @@ -0,0 +1,5 @@ +error: task functions must not be generic + --> tests/ui/generics.rs:6:1 + | +6 | async fn task(_t: T) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/embassy-executor/tests/ui/impl_trait.rs b/embassy-executor/tests/ui/impl_trait.rs new file mode 100644 index 000000000..a21402aa0 --- /dev/null +++ b/embassy-executor/tests/ui/impl_trait.rs @@ -0,0 +1,6 @@ +#![cfg_attr(feature = "nightly", feature(impl_trait_in_assoc_type))] + +#[embassy_executor::task] +async fn foo(_x: impl Sized) {} + +fn main() {} diff --git a/embassy-executor/tests/ui/impl_trait.stderr b/embassy-executor/tests/ui/impl_trait.stderr new file mode 100644 index 000000000..099b1828f --- /dev/null +++ b/embassy-executor/tests/ui/impl_trait.stderr @@ -0,0 +1,5 @@ +error: `impl Trait` is not allowed in task arguments. It is syntax sugar for generics, and tasks can't be generic. + --> tests/ui/impl_trait.rs:4:18 + | +4 | async fn foo(_x: impl Sized) {} + | ^^^^^^^^^^ diff --git a/embassy-executor/tests/ui/impl_trait_nested.rs b/embassy-executor/tests/ui/impl_trait_nested.rs new file mode 100644 index 000000000..07442b8fa --- /dev/null +++ b/embassy-executor/tests/ui/impl_trait_nested.rs @@ -0,0 +1,8 @@ +#![cfg_attr(feature = "nightly", feature(impl_trait_in_assoc_type))] + +struct Foo(T); + +#[embassy_executor::task] +async fn foo(_x: Foo) {} + +fn main() {} diff --git a/embassy-executor/tests/ui/impl_trait_nested.stderr b/embassy-executor/tests/ui/impl_trait_nested.stderr new file mode 100644 index 000000000..39592f958 --- /dev/null +++ b/embassy-executor/tests/ui/impl_trait_nested.stderr @@ -0,0 +1,5 @@ +error: `impl Trait` is not allowed in task arguments. It is syntax sugar for generics, and tasks can't be generic. + --> tests/ui/impl_trait_nested.rs:6:22 + | +6 | async fn foo(_x: Foo) {} + | ^^^^^^^^^^^^^^^^^^^^ diff --git a/embassy-executor/tests/ui/impl_trait_static.rs b/embassy-executor/tests/ui/impl_trait_static.rs new file mode 100644 index 000000000..272470f98 --- /dev/null +++ b/embassy-executor/tests/ui/impl_trait_static.rs @@ -0,0 +1,6 @@ +#![cfg_attr(feature = "nightly", feature(impl_trait_in_assoc_type))] + +#[embassy_executor::task] +async fn foo(_x: impl Sized + 'static) {} + +fn main() {} diff --git a/embassy-executor/tests/ui/impl_trait_static.stderr b/embassy-executor/tests/ui/impl_trait_static.stderr new file mode 100644 index 000000000..0032a20c9 --- /dev/null +++ b/embassy-executor/tests/ui/impl_trait_static.stderr @@ -0,0 +1,5 @@ +error: `impl Trait` is not allowed in task arguments. It is syntax sugar for generics, and tasks can't be generic. + --> tests/ui/impl_trait_static.rs:4:18 + | +4 | async fn foo(_x: impl Sized + 'static) {} + | ^^^^^^^^^^^^^^^^^^^^ diff --git a/embassy-executor/tests/ui/nonstatic_ref_anon.rs b/embassy-executor/tests/ui/nonstatic_ref_anon.rs new file mode 100644 index 000000000..417c360a1 --- /dev/null +++ b/embassy-executor/tests/ui/nonstatic_ref_anon.rs @@ -0,0 +1,6 @@ +#![cfg_attr(feature = "nightly", feature(impl_trait_in_assoc_type))] + +#[embassy_executor::task] +async fn foo(_x: &'_ u32) {} + +fn main() {} diff --git a/embassy-executor/tests/ui/nonstatic_ref_anon.stderr b/embassy-executor/tests/ui/nonstatic_ref_anon.stderr new file mode 100644 index 000000000..0544de843 --- /dev/null +++ b/embassy-executor/tests/ui/nonstatic_ref_anon.stderr @@ -0,0 +1,5 @@ +error: Arguments for tasks must live forever. Try using the `'static` lifetime. + --> tests/ui/nonstatic_ref_anon.rs:4:19 + | +4 | async fn foo(_x: &'_ u32) {} + | ^^ diff --git a/embassy-executor/tests/ui/nonstatic_ref_anon_nested.rs b/embassy-executor/tests/ui/nonstatic_ref_anon_nested.rs new file mode 100644 index 000000000..175ebccc1 --- /dev/null +++ b/embassy-executor/tests/ui/nonstatic_ref_anon_nested.rs @@ -0,0 +1,6 @@ +#![cfg_attr(feature = "nightly", feature(impl_trait_in_assoc_type))] + +#[embassy_executor::task] +async fn foo(_x: &'static &'_ u32) {} + +fn main() {} diff --git a/embassy-executor/tests/ui/nonstatic_ref_anon_nested.stderr b/embassy-executor/tests/ui/nonstatic_ref_anon_nested.stderr new file mode 100644 index 000000000..79f262e6b --- /dev/null +++ b/embassy-executor/tests/ui/nonstatic_ref_anon_nested.stderr @@ -0,0 +1,5 @@ +error: Arguments for tasks must live forever. Try using the `'static` lifetime. + --> tests/ui/nonstatic_ref_anon_nested.rs:4:28 + | +4 | async fn foo(_x: &'static &'_ u32) {} + | ^^ diff --git a/embassy-executor/tests/ui/nonstatic_ref_elided.rs b/embassy-executor/tests/ui/nonstatic_ref_elided.rs new file mode 100644 index 000000000..cf49ad709 --- /dev/null +++ b/embassy-executor/tests/ui/nonstatic_ref_elided.rs @@ -0,0 +1,6 @@ +#![cfg_attr(feature = "nightly", feature(impl_trait_in_assoc_type))] + +#[embassy_executor::task] +async fn foo(_x: &u32) {} + +fn main() {} diff --git a/embassy-executor/tests/ui/nonstatic_ref_elided.stderr b/embassy-executor/tests/ui/nonstatic_ref_elided.stderr new file mode 100644 index 000000000..7e2b9eb7c --- /dev/null +++ b/embassy-executor/tests/ui/nonstatic_ref_elided.stderr @@ -0,0 +1,5 @@ +error: Arguments for tasks must live forever. Try using the `'static` lifetime. + --> tests/ui/nonstatic_ref_elided.rs:4:18 + | +4 | async fn foo(_x: &u32) {} + | ^ diff --git a/embassy-executor/tests/ui/nonstatic_ref_generic.rs b/embassy-executor/tests/ui/nonstatic_ref_generic.rs new file mode 100644 index 000000000..3f8a26cf8 --- /dev/null +++ b/embassy-executor/tests/ui/nonstatic_ref_generic.rs @@ -0,0 +1,6 @@ +#![cfg_attr(feature = "nightly", feature(impl_trait_in_assoc_type))] + +#[embassy_executor::task] +async fn foo<'a>(_x: &'a u32) {} + +fn main() {} diff --git a/embassy-executor/tests/ui/nonstatic_ref_generic.stderr b/embassy-executor/tests/ui/nonstatic_ref_generic.stderr new file mode 100644 index 000000000..af8491ad7 --- /dev/null +++ b/embassy-executor/tests/ui/nonstatic_ref_generic.stderr @@ -0,0 +1,11 @@ +error: task functions must not be generic + --> tests/ui/nonstatic_ref_generic.rs:4:1 + | +4 | async fn foo<'a>(_x: &'a u32) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: Arguments for tasks must live forever. Try using the `'static` lifetime. + --> tests/ui/nonstatic_ref_generic.rs:4:23 + | +4 | async fn foo<'a>(_x: &'a u32) {} + | ^^ diff --git a/embassy-executor/tests/ui/nonstatic_struct_anon.rs b/embassy-executor/tests/ui/nonstatic_struct_anon.rs new file mode 100644 index 000000000..ba95d1459 --- /dev/null +++ b/embassy-executor/tests/ui/nonstatic_struct_anon.rs @@ -0,0 +1,8 @@ +#![cfg_attr(feature = "nightly", feature(impl_trait_in_assoc_type))] + +struct Foo<'a>(&'a ()); + +#[embassy_executor::task] +async fn task(_x: Foo<'_>) {} + +fn main() {} diff --git a/embassy-executor/tests/ui/nonstatic_struct_anon.stderr b/embassy-executor/tests/ui/nonstatic_struct_anon.stderr new file mode 100644 index 000000000..5df2a6e06 --- /dev/null +++ b/embassy-executor/tests/ui/nonstatic_struct_anon.stderr @@ -0,0 +1,5 @@ +error: Arguments for tasks must live forever. Try using the `'static` lifetime. + --> tests/ui/nonstatic_struct_anon.rs:6:23 + | +6 | async fn task(_x: Foo<'_>) {} + | ^^ diff --git a/embassy-executor/tests/ui/nonstatic_struct_elided.rs b/embassy-executor/tests/ui/nonstatic_struct_elided.rs new file mode 100644 index 000000000..4cfe2966a --- /dev/null +++ b/embassy-executor/tests/ui/nonstatic_struct_elided.rs @@ -0,0 +1,8 @@ +#![cfg_attr(feature = "nightly", feature(impl_trait_in_assoc_type))] + +struct Foo<'a>(&'a ()); + +#[embassy_executor::task] +async fn task(_x: Foo) {} + +fn main() {} diff --git a/embassy-executor/tests/ui/nonstatic_struct_elided.stderr b/embassy-executor/tests/ui/nonstatic_struct_elided.stderr new file mode 100644 index 000000000..099ef8b4e --- /dev/null +++ b/embassy-executor/tests/ui/nonstatic_struct_elided.stderr @@ -0,0 +1,10 @@ +error[E0726]: implicit elided lifetime not allowed here + --> tests/ui/nonstatic_struct_elided.rs:6:19 + | +6 | async fn task(_x: Foo) {} + | ^^^ expected lifetime parameter + | +help: indicate the anonymous lifetime + | +6 | async fn task(_x: Foo<'_>) {} + | ++++ diff --git a/embassy-executor/tests/ui/nonstatic_struct_generic.rs b/embassy-executor/tests/ui/nonstatic_struct_generic.rs new file mode 100644 index 000000000..ec3d908f6 --- /dev/null +++ b/embassy-executor/tests/ui/nonstatic_struct_generic.rs @@ -0,0 +1,8 @@ +#![cfg_attr(feature = "nightly", feature(impl_trait_in_assoc_type))] + +struct Foo<'a>(&'a ()); + +#[embassy_executor::task] +async fn task<'a>(_x: Foo<'a>) {} + +fn main() {} diff --git a/embassy-executor/tests/ui/nonstatic_struct_generic.stderr b/embassy-executor/tests/ui/nonstatic_struct_generic.stderr new file mode 100644 index 000000000..61d5231bc --- /dev/null +++ b/embassy-executor/tests/ui/nonstatic_struct_generic.stderr @@ -0,0 +1,11 @@ +error: task functions must not be generic + --> tests/ui/nonstatic_struct_generic.rs:6:1 + | +6 | async fn task<'a>(_x: Foo<'a>) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: Arguments for tasks must live forever. Try using the `'static` lifetime. + --> tests/ui/nonstatic_struct_generic.rs:6:27 + | +6 | async fn task<'a>(_x: Foo<'a>) {} + | ^^ diff --git a/embassy-executor/tests/ui/not_async.rs b/embassy-executor/tests/ui/not_async.rs new file mode 100644 index 000000000..f3f7e9bd2 --- /dev/null +++ b/embassy-executor/tests/ui/not_async.rs @@ -0,0 +1,8 @@ +#![cfg_attr(feature = "nightly", feature(impl_trait_in_assoc_type))] + +struct Foo<'a>(&'a ()); + +#[embassy_executor::task] +fn task() {} + +fn main() {} diff --git a/embassy-executor/tests/ui/not_async.stderr b/embassy-executor/tests/ui/not_async.stderr new file mode 100644 index 000000000..27f040d9c --- /dev/null +++ b/embassy-executor/tests/ui/not_async.stderr @@ -0,0 +1,5 @@ +error: task functions must be async + --> tests/ui/not_async.rs:6:1 + | +6 | fn task() {} + | ^^^^^^^^^ diff --git a/embassy-executor/tests/ui/self.rs b/embassy-executor/tests/ui/self.rs new file mode 100644 index 000000000..f83a962d1 --- /dev/null +++ b/embassy-executor/tests/ui/self.rs @@ -0,0 +1,8 @@ +#![cfg_attr(feature = "nightly", feature(impl_trait_in_assoc_type))] + +struct Foo<'a>(&'a ()); + +#[embassy_executor::task] +async fn task(self) {} + +fn main() {} diff --git a/embassy-executor/tests/ui/self.stderr b/embassy-executor/tests/ui/self.stderr new file mode 100644 index 000000000..aaf031573 --- /dev/null +++ b/embassy-executor/tests/ui/self.stderr @@ -0,0 +1,13 @@ +error: task functions must not have `self` arguments + --> tests/ui/self.rs:6:15 + | +6 | async fn task(self) {} + | ^^^^ + +error: `self` parameter is only allowed in associated functions + --> tests/ui/self.rs:6:15 + | +6 | async fn task(self) {} + | ^^^^ not semantically valid as function parameter + | + = note: associated functions are those in `impl` or `trait` definitions diff --git a/embassy-executor/tests/ui/self_ref.rs b/embassy-executor/tests/ui/self_ref.rs new file mode 100644 index 000000000..5e49bba5e --- /dev/null +++ b/embassy-executor/tests/ui/self_ref.rs @@ -0,0 +1,8 @@ +#![cfg_attr(feature = "nightly", feature(impl_trait_in_assoc_type))] + +struct Foo<'a>(&'a ()); + +#[embassy_executor::task] +async fn task(&mut self) {} + +fn main() {} diff --git a/embassy-executor/tests/ui/self_ref.stderr b/embassy-executor/tests/ui/self_ref.stderr new file mode 100644 index 000000000..dd2052977 --- /dev/null +++ b/embassy-executor/tests/ui/self_ref.stderr @@ -0,0 +1,13 @@ +error: task functions must not have `self` arguments + --> tests/ui/self_ref.rs:6:15 + | +6 | async fn task(&mut self) {} + | ^^^^^^^^^ + +error: `self` parameter is only allowed in associated functions + --> tests/ui/self_ref.rs:6:15 + | +6 | async fn task(&mut self) {} + | ^^^^^^^^^ not semantically valid as function parameter + | + = note: associated functions are those in `impl` or `trait` definitions diff --git a/embassy-executor/tests/ui/where_clause.rs b/embassy-executor/tests/ui/where_clause.rs new file mode 100644 index 000000000..848d78149 --- /dev/null +++ b/embassy-executor/tests/ui/where_clause.rs @@ -0,0 +1,12 @@ +#![cfg_attr(feature = "nightly", feature(impl_trait_in_assoc_type))] + +struct Foo<'a>(&'a ()); + +#[embassy_executor::task] +async fn task() +where + (): Sized, +{ +} + +fn main() {} diff --git a/embassy-executor/tests/ui/where_clause.stderr b/embassy-executor/tests/ui/where_clause.stderr new file mode 100644 index 000000000..eba45af40 --- /dev/null +++ b/embassy-executor/tests/ui/where_clause.stderr @@ -0,0 +1,7 @@ +error: task functions must not have `where` clauses + --> tests/ui/where_clause.rs:6:1 + | +6 | / async fn task() +7 | | where +8 | | (): Sized, + | |______________^ From 1a24b4f018cd6e807a02a5b55343d33a9213c8ab Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 21 Oct 2024 01:26:02 +0200 Subject: [PATCH 0245/1217] Release embassy-executor v0.6.1, embassy-executor-macros v0.6.1 --- embassy-executor-macros/Cargo.toml | 2 +- embassy-executor/CHANGELOG.md | 11 ++++++++++- embassy-executor/Cargo.toml | 4 ++-- embassy-rp/Cargo.toml | 2 +- embassy-stm32/Cargo.toml | 2 +- embassy-time/Cargo.toml | 2 +- examples/boot/application/nrf/Cargo.toml | 2 +- examples/boot/application/rp/Cargo.toml | 2 +- examples/boot/application/stm32f3/Cargo.toml | 2 +- examples/boot/application/stm32f7/Cargo.toml | 2 +- examples/boot/application/stm32h7/Cargo.toml | 2 +- examples/boot/application/stm32l0/Cargo.toml | 2 +- examples/boot/application/stm32l1/Cargo.toml | 2 +- examples/boot/application/stm32l4/Cargo.toml | 2 +- examples/boot/application/stm32wb-dfu/Cargo.toml | 2 +- examples/boot/application/stm32wl/Cargo.toml | 2 +- examples/lpc55s69/Cargo.toml | 2 +- examples/nrf-rtos-trace/Cargo.toml | 2 +- examples/nrf51/Cargo.toml | 2 +- examples/nrf52810/Cargo.toml | 2 +- examples/nrf52840/Cargo.toml | 2 +- examples/nrf5340/Cargo.toml | 2 +- examples/nrf9151/ns/Cargo.toml | 2 +- examples/nrf9151/s/Cargo.toml | 2 +- examples/nrf9160/Cargo.toml | 2 +- examples/rp/Cargo.toml | 2 +- examples/rp23/Cargo.toml | 2 +- examples/std/Cargo.toml | 2 +- examples/stm32c0/Cargo.toml | 2 +- examples/stm32f0/Cargo.toml | 2 +- examples/stm32f1/Cargo.toml | 2 +- examples/stm32f2/Cargo.toml | 2 +- examples/stm32f3/Cargo.toml | 2 +- examples/stm32f334/Cargo.toml | 2 +- examples/stm32f4/Cargo.toml | 2 +- examples/stm32f469/Cargo.toml | 2 +- examples/stm32f7/Cargo.toml | 2 +- examples/stm32g0/Cargo.toml | 2 +- examples/stm32g4/Cargo.toml | 2 +- examples/stm32h5/Cargo.toml | 2 +- examples/stm32h7/Cargo.toml | 2 +- examples/stm32h735/Cargo.toml | 2 +- examples/stm32h755cm4/Cargo.toml | 2 +- examples/stm32h755cm7/Cargo.toml | 2 +- examples/stm32h7rs/Cargo.toml | 2 +- examples/stm32l0/Cargo.toml | 2 +- examples/stm32l1/Cargo.toml | 2 +- examples/stm32l4/Cargo.toml | 2 +- examples/stm32l5/Cargo.toml | 2 +- examples/stm32u0/Cargo.toml | 2 +- examples/stm32u5/Cargo.toml | 2 +- examples/stm32wb/Cargo.toml | 2 +- examples/stm32wba/Cargo.toml | 2 +- examples/stm32wl/Cargo.toml | 2 +- examples/wasm/Cargo.toml | 2 +- tests/nrf/Cargo.toml | 2 +- tests/riscv32/Cargo.toml | 2 +- tests/rp/Cargo.toml | 2 +- tests/stm32/Cargo.toml | 2 +- 59 files changed, 69 insertions(+), 60 deletions(-) diff --git a/embassy-executor-macros/Cargo.toml b/embassy-executor-macros/Cargo.toml index ef509c3f9..306cf8352 100644 --- a/embassy-executor-macros/Cargo.toml +++ b/embassy-executor-macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "embassy-executor-macros" -version = "0.5.0" +version = "0.6.1" edition = "2021" license = "MIT OR Apache-2.0" description = "macros for creating the entry point and tasks for embassy-executor" diff --git a/embassy-executor/CHANGELOG.md b/embassy-executor/CHANGELOG.md index 5582b56ec..ac1c8cb0c 100644 --- a/embassy-executor/CHANGELOG.md +++ b/embassy-executor/CHANGELOG.md @@ -7,10 +7,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +## 0.6.1 - 2024-10-21 + +- Soundness fix: Deny using `impl Trait` in task arguments. This was previously accidentally allowed when not using the `nightly` feature, + and could cause out of bounds memory accesses if spawning the same task mulitple times with different underlying types + for the `impl Trait`. Affected versions are 0.4.x, 0.5.x and 0.6.0, which have been yanked. +- Add an architecture-agnostic executor that spins waiting for tasks to run, enabled with the `arch-spin` feature. +- Update for breaking change in the nightly waker_getters API. The `nightly` feature now requires`nightly-2024-09-06` or newer. +- Improve macro error messages. + ## 0.6.0 - 2024-08-05 - Add collapse_debuginfo to fmt.rs macros. -- initial support for avr +- initial support for AVR - use nightly waker_getters APIs ## 0.5.0 - 2024-01-11 diff --git a/embassy-executor/Cargo.toml b/embassy-executor/Cargo.toml index e138f93b0..22a176621 100644 --- a/embassy-executor/Cargo.toml +++ b/embassy-executor/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "embassy-executor" -version = "0.6.0" +version = "0.6.1" edition = "2021" license = "MIT OR Apache-2.0" description = "async/await executor designed for embedded usage" @@ -33,7 +33,7 @@ defmt = { version = "0.3", optional = true } log = { version = "0.4.14", optional = true } rtos-trace = { version = "0.1.2", optional = true } -embassy-executor-macros = { version = "0.5.0", path = "../embassy-executor-macros" } +embassy-executor-macros = { version = "0.6.1", path = "../embassy-executor-macros" } embassy-time-driver = { version = "0.1.0", path = "../embassy-time-driver", optional = true } embassy-time-queue-driver = { version = "0.1.0", path = "../embassy-time-queue-driver", optional = true } critical-section = "1.1" diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index 54de238b3..547d64e43 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml @@ -147,5 +147,5 @@ rp-binary-info = { version = "0.1.0", optional = true } smart-leds = "0.4.0" [dev-dependencies] -embassy-executor = { version = "0.6.0", path = "../embassy-executor", features = ["arch-std", "executor-thread"] } +embassy-executor = { version = "0.6.1", path = "../embassy-executor", features = ["arch-std", "executor-thread"] } static_cell = { version = "2" } diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 53ec1b27f..9fdc799d8 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -51,7 +51,7 @@ embassy-embedded-hal = {version = "0.2.0", path = "../embassy-embedded-hal", def embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver" } embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver" } embassy-usb-synopsys-otg = {version = "0.1.0", path = "../embassy-usb-synopsys-otg" } -embassy-executor = { version = "0.6.0", path = "../embassy-executor", optional = true } +embassy-executor = { version = "0.6.1", path = "../embassy-executor", optional = true } embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } embedded-hal-1 = { package = "embedded-hal", version = "1.0" } diff --git a/embassy-time/Cargo.toml b/embassy-time/Cargo.toml index c3b4e4e3a..dc3561145 100644 --- a/embassy-time/Cargo.toml +++ b/embassy-time/Cargo.toml @@ -431,4 +431,4 @@ wasm-timer = { version = "0.2.5", optional = true } [dev-dependencies] serial_test = "0.9" critical-section = { version = "1.1", features = ["std"] } -embassy-executor = { version = "0.6.0", path = "../embassy-executor" } +embassy-executor = { version = "0.6.1", path = "../embassy-executor" } diff --git a/examples/boot/application/nrf/Cargo.toml b/examples/boot/application/nrf/Cargo.toml index 93e49faef..3815ac196 100644 --- a/examples/boot/application/nrf/Cargo.toml +++ b/examples/boot/application/nrf/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.6.0", path = "../../../../embassy-executor", features = ["task-arena-size-16384", "arch-cortex-m", "executor-thread", "integrated-timers", "arch-cortex-m", "executor-thread"] } +embassy-executor = { version = "0.6.1", path = "../../../../embassy-executor", features = ["task-arena-size-16384", "arch-cortex-m", "executor-thread", "integrated-timers", "arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [] } embassy-nrf = { version = "0.2.0", path = "../../../../embassy-nrf", features = ["time-driver-rtc1", "gpiote", ] } embassy-boot = { version = "0.3.0", path = "../../../../embassy-boot", features = [] } diff --git a/examples/boot/application/rp/Cargo.toml b/examples/boot/application/rp/Cargo.toml index 8bb8afdfe..86ea9fc2a 100644 --- a/examples/boot/application/rp/Cargo.toml +++ b/examples/boot/application/rp/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.6.0", path = "../../../../embassy-executor", features = ["task-arena-size-16384", "arch-cortex-m", "executor-thread", "integrated-timers", "arch-cortex-m", "executor-thread"] } +embassy-executor = { version = "0.6.1", path = "../../../../embassy-executor", features = ["task-arena-size-16384", "arch-cortex-m", "executor-thread", "integrated-timers", "arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [] } embassy-rp = { version = "0.2.0", path = "../../../../embassy-rp", features = ["time-driver", "rp2040"] } embassy-boot-rp = { version = "0.3.0", path = "../../../../embassy-boot-rp", features = [] } diff --git a/examples/boot/application/stm32f3/Cargo.toml b/examples/boot/application/stm32f3/Cargo.toml index 1c2934298..29049e58c 100644 --- a/examples/boot/application/stm32f3/Cargo.toml +++ b/examples/boot/application/stm32f3/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.6.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } +embassy-executor = { version = "0.6.1", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32f303re", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32" } diff --git a/examples/boot/application/stm32f7/Cargo.toml b/examples/boot/application/stm32f7/Cargo.toml index 09e34c7df..ed102b073 100644 --- a/examples/boot/application/stm32f7/Cargo.toml +++ b/examples/boot/application/stm32f7/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.6.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } +embassy-executor = { version = "0.6.1", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32f767zi", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } diff --git a/examples/boot/application/stm32h7/Cargo.toml b/examples/boot/application/stm32h7/Cargo.toml index 5e7f4d5e7..cc705b1d6 100644 --- a/examples/boot/application/stm32h7/Cargo.toml +++ b/examples/boot/application/stm32h7/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.6.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } +embassy-executor = { version = "0.6.1", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32h743zi", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } diff --git a/examples/boot/application/stm32l0/Cargo.toml b/examples/boot/application/stm32l0/Cargo.toml index 60fdcfafb..17fc1d7d0 100644 --- a/examples/boot/application/stm32l0/Cargo.toml +++ b/examples/boot/application/stm32l0/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.6.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } +embassy-executor = { version = "0.6.1", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l072cz", "time-driver-any", "exti", "memory-x"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } diff --git a/examples/boot/application/stm32l1/Cargo.toml b/examples/boot/application/stm32l1/Cargo.toml index fe3ab2c04..fd2c19f99 100644 --- a/examples/boot/application/stm32l1/Cargo.toml +++ b/examples/boot/application/stm32l1/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.6.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } +embassy-executor = { version = "0.6.1", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l151cb-a", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } diff --git a/examples/boot/application/stm32l4/Cargo.toml b/examples/boot/application/stm32l4/Cargo.toml index 169856358..3852261ac 100644 --- a/examples/boot/application/stm32l4/Cargo.toml +++ b/examples/boot/application/stm32l4/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.6.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } +embassy-executor = { version = "0.6.1", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l475vg", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } diff --git a/examples/boot/application/stm32wb-dfu/Cargo.toml b/examples/boot/application/stm32wb-dfu/Cargo.toml index 7cef8fe0d..2d89f6d42 100644 --- a/examples/boot/application/stm32wb-dfu/Cargo.toml +++ b/examples/boot/application/stm32wb-dfu/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.6.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } +embassy-executor = { version = "0.6.1", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32wb55rg", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } diff --git a/examples/boot/application/stm32wl/Cargo.toml b/examples/boot/application/stm32wl/Cargo.toml index 860a835a9..e07d97d86 100644 --- a/examples/boot/application/stm32wl/Cargo.toml +++ b/examples/boot/application/stm32wl/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.6.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } +embassy-executor = { version = "0.6.1", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32wl55jc-cm4", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } diff --git a/examples/lpc55s69/Cargo.toml b/examples/lpc55s69/Cargo.toml index 14ec2d47e..a69007a2c 100644 --- a/examples/lpc55s69/Cargo.toml +++ b/examples/lpc55s69/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-nxp = { version = "0.1.0", path = "../../embassy-nxp", features = ["rt"] } -embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt"] } +embassy-executor = { version = "0.6.1", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt"] } panic-halt = "0.2.0" diff --git a/examples/nrf-rtos-trace/Cargo.toml b/examples/nrf-rtos-trace/Cargo.toml index 98a678815..2358ced56 100644 --- a/examples/nrf-rtos-trace/Cargo.toml +++ b/examples/nrf-rtos-trace/Cargo.toml @@ -16,7 +16,7 @@ log = [ [dependencies] embassy-sync = { version = "0.6.0", path = "../../embassy-sync" } -embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "rtos-trace", "integrated-timers"] } +embassy-executor = { version = "0.6.1", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "rtos-trace", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time" } embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] } diff --git a/examples/nrf51/Cargo.toml b/examples/nrf51/Cargo.toml index 93a19bea7..f94026158 100644 --- a/examples/nrf51/Cargo.toml +++ b/examples/nrf51/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-4096", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.1", path = "../../embassy-executor", features = ["task-arena-size-4096", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf51", "gpiote", "time-driver-rtc1", "unstable-pac", "time", "rt"] } diff --git a/examples/nrf52810/Cargo.toml b/examples/nrf52810/Cargo.toml index 0e3e81c3f..867ead6d8 100644 --- a/examples/nrf52810/Cargo.toml +++ b/examples/nrf52810/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.1", path = "../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf52810", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } diff --git a/examples/nrf52840/Cargo.toml b/examples/nrf52840/Cargo.toml index 17fa6234d..cb05b7204 100644 --- a/examples/nrf52840/Cargo.toml +++ b/examples/nrf52840/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.1", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } diff --git a/examples/nrf5340/Cargo.toml b/examples/nrf5340/Cargo.toml index 0da85be07..2387eaa58 100644 --- a/examples/nrf5340/Cargo.toml +++ b/examples/nrf5340/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.1", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf5340-app-s", "time-driver-rtc1", "gpiote", "unstable-pac"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } diff --git a/examples/nrf9151/ns/Cargo.toml b/examples/nrf9151/ns/Cargo.toml index 17fe27b67..78260dae3 100644 --- a/examples/nrf9151/ns/Cargo.toml +++ b/examples/nrf9151/ns/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-executor = { version = "0.6.0", path = "../../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.1", path = "../../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.2.0", path = "../../../embassy-nrf", features = ["defmt", "nrf9120-ns", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } diff --git a/examples/nrf9151/s/Cargo.toml b/examples/nrf9151/s/Cargo.toml index 7253fc4be..17ead4ab4 100644 --- a/examples/nrf9151/s/Cargo.toml +++ b/examples/nrf9151/s/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-executor = { version = "0.6.0", path = "../../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.1", path = "../../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.2.0", path = "../../../embassy-nrf", features = ["defmt", "nrf9120-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } diff --git a/examples/nrf9160/Cargo.toml b/examples/nrf9160/Cargo.toml index 9aeb99317..2572f3353 100644 --- a/examples/nrf9160/Cargo.toml +++ b/examples/nrf9160/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.1", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf9160-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } embassy-net-nrf91 = { version = "0.1.0", path = "../../embassy-net-nrf91", features = ["defmt"] } diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index a220b9a77..8e5f81b7e 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal", features = ["defmt"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-98304", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.1", path = "../../embassy-executor", features = ["task-arena-size-98304", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-rp = { version = "0.2.0", path = "../../embassy-rp", features = ["defmt", "unstable-pac", "time-driver", "critical-section-impl", "rp2040"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/rp23/Cargo.toml b/examples/rp23/Cargo.toml index 08646463c..9ae75e16c 100644 --- a/examples/rp23/Cargo.toml +++ b/examples/rp23/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal", features = ["defmt"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-98304", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.1", path = "../../embassy-executor", features = ["task-arena-size-98304", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-rp = { version = "0.2.0", path = "../../embassy-rp", features = ["defmt", "unstable-pac", "time-driver", "critical-section-impl", "rp235xa", "binary-info"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/std/Cargo.toml b/examples/std/Cargo.toml index 87491b1d2..27d0062fb 100644 --- a/examples/std/Cargo.toml +++ b/examples/std/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["log"] } -embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-std", "executor-thread", "log", "integrated-timers"] } +embassy-executor = { version = "0.6.1", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-std", "executor-thread", "log", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["log", "std", ] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features=[ "std", "log", "medium-ethernet", "medium-ip", "tcp", "udp", "dns", "dhcpv4", "proto-ipv6"] } embassy-net-tuntap = { version = "0.1.0", path = "../../embassy-net-tuntap" } diff --git a/examples/stm32c0/Cargo.toml b/examples/stm32c0/Cargo.toml index 9102467eb..46a25cc4d 100644 --- a/examples/stm32c0/Cargo.toml +++ b/examples/stm32c0/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32c031c6 to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32c031c6", "memory-x", "unstable-pac", "exti"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.1", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } defmt = "0.3" diff --git a/examples/stm32f0/Cargo.toml b/examples/stm32f0/Cargo.toml index 724efdaff..93d9ab7ce 100644 --- a/examples/stm32f0/Cargo.toml +++ b/examples/stm32f0/Cargo.toml @@ -13,7 +13,7 @@ defmt = "0.3" defmt-rtt = "0.4" panic-probe = { version = "0.3", features = ["print-defmt"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.1", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } static_cell = "2" portable-atomic = { version = "1.5", features = ["unsafe-assume-single-core"] } diff --git a/examples/stm32f1/Cargo.toml b/examples/stm32f1/Cargo.toml index 0084651a3..a75d0fe4c 100644 --- a/examples/stm32f1/Cargo.toml +++ b/examples/stm32f1/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32f103c8 to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f103c8", "unstable-pac", "memory-x", "time-driver-any" ] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.1", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32f2/Cargo.toml b/examples/stm32f2/Cargo.toml index 60eb0eb93..166729211 100644 --- a/examples/stm32f2/Cargo.toml +++ b/examples/stm32f2/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32f207zg to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f207zg", "unstable-pac", "memory-x", "time-driver-any", "exti"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.1", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } defmt = "0.3" diff --git a/examples/stm32f3/Cargo.toml b/examples/stm32f3/Cargo.toml index 7fda410d9..e60ea80c6 100644 --- a/examples/stm32f3/Cargo.toml +++ b/examples/stm32f3/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32f303ze to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f303ze", "unstable-pac", "memory-x", "time-driver-any", "exti"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.1", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32f334/Cargo.toml b/examples/stm32f334/Cargo.toml index 1cc0a97da..4ba993009 100644 --- a/examples/stm32f334/Cargo.toml +++ b/examples/stm32f334/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.1", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f334r8", "unstable-pac", "memory-x", "time-driver-any", "exti"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/stm32f4/Cargo.toml b/examples/stm32f4/Cargo.toml index b85361596..975e47398 100644 --- a/examples/stm32f4/Cargo.toml +++ b/examples/stm32f4/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32f429zi to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32f429zi", "unstable-pac", "memory-x", "time-driver-any", "exti", "chrono"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.1", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt" ] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", ] } diff --git a/examples/stm32f469/Cargo.toml b/examples/stm32f469/Cargo.toml index 6a5bd0b29..4e1a778cd 100644 --- a/examples/stm32f469/Cargo.toml +++ b/examples/stm32f469/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Specific examples only for stm32f469 embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32f469ni", "unstable-pac", "memory-x", "time-driver-any", "exti", "chrono"] } -embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.1", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } defmt = "0.3" diff --git a/examples/stm32f7/Cargo.toml b/examples/stm32f7/Cargo.toml index 8c591ebd2..879b05d91 100644 --- a/examples/stm32f7/Cargo.toml +++ b/examples/stm32f7/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32f777zi to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32f777zi", "memory-x", "unstable-pac", "time-driver-any", "exti"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.1", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } embedded-io-async = { version = "0.6.1" } diff --git a/examples/stm32g0/Cargo.toml b/examples/stm32g0/Cargo.toml index a50074ce0..77f70e57d 100644 --- a/examples/stm32g0/Cargo.toml +++ b/examples/stm32g0/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32g0b1re to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32g0b1re", "memory-x", "unstable-pac", "exti"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.1", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", default-features = false, features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32g4/Cargo.toml b/examples/stm32g4/Cargo.toml index 2768147a1..86d29f94e 100644 --- a/examples/stm32g4/Cargo.toml +++ b/examples/stm32g4/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32g491re to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32g491re", "memory-x", "unstable-pac", "exti"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.1", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32h5/Cargo.toml b/examples/stm32h5/Cargo.toml index 1aa264ab2..9ca8bc969 100644 --- a/examples/stm32h5/Cargo.toml +++ b/examples/stm32h5/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32h563zi to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h563zi", "memory-x", "time-driver-any", "exti", "unstable-pac", "low-power"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.1", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/stm32h7/Cargo.toml b/examples/stm32h7/Cargo.toml index d0f22cf82..f2f207395 100644 --- a/examples/stm32h7/Cargo.toml +++ b/examples/stm32h7/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h743bi", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } -embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.1", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/stm32h735/Cargo.toml b/examples/stm32h735/Cargo.toml index 93e9575b6..bac76ddfb 100644 --- a/examples/stm32h735/Cargo.toml +++ b/examples/stm32h735/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h735ig", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } -embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.1", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32h755cm4/Cargo.toml b/examples/stm32h755cm4/Cargo.toml index 75de40b9a..1fbceddde 100644 --- a/examples/stm32h755cm4/Cargo.toml +++ b/examples/stm32h755cm4/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h755zi-cm4", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } -embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.1", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/stm32h755cm7/Cargo.toml b/examples/stm32h755cm7/Cargo.toml index 911a4e79b..8b864169b 100644 --- a/examples/stm32h755cm7/Cargo.toml +++ b/examples/stm32h755cm7/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h755zi-cm7", "time-driver-tim3", "exti", "memory-x", "unstable-pac", "chrono"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } -embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.1", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/stm32h7rs/Cargo.toml b/examples/stm32h7rs/Cargo.toml index 05f638408..29881bf8b 100644 --- a/examples/stm32h7rs/Cargo.toml +++ b/examples/stm32h7rs/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32h743bi to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h7s3l8", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.1", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/stm32l0/Cargo.toml b/examples/stm32l0/Cargo.toml index 2577f19e0..273cdce1d 100644 --- a/examples/stm32l0/Cargo.toml +++ b/examples/stm32l0/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32l072cz to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32l072cz", "unstable-pac", "time-driver-any", "exti", "memory-x"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.1", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } defmt = "0.3" diff --git a/examples/stm32l1/Cargo.toml b/examples/stm32l1/Cargo.toml index 062044f32..af4775a74 100644 --- a/examples/stm32l1/Cargo.toml +++ b/examples/stm32l1/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.1", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32l151cb-a", "time-driver-any", "memory-x"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/stm32l4/Cargo.toml b/examples/stm32l4/Cargo.toml index c5478b17b..70c5c5e26 100644 --- a/examples/stm32l4/Cargo.toml +++ b/examples/stm32l4/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32l4s5vi to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32l4s5qi", "memory-x", "time-driver-any", "exti", "chrono"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.1", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768", ] } embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/stm32l5/Cargo.toml b/examples/stm32l5/Cargo.toml index 16c184de2..78cb79eac 100644 --- a/examples/stm32l5/Cargo.toml +++ b/examples/stm32l5/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32l552ze to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32l552ze", "time-driver-any", "exti", "memory-x", "low-power"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.1", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } diff --git a/examples/stm32u0/Cargo.toml b/examples/stm32u0/Cargo.toml index 2e890cdb5..931409b51 100644 --- a/examples/stm32u0/Cargo.toml +++ b/examples/stm32u0/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32u083rc to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32u083rc", "memory-x", "unstable-pac", "exti", "chrono"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.1", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", default-features = false, features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32u5/Cargo.toml b/examples/stm32u5/Cargo.toml index 20d64c6f7..ad7db4c32 100644 --- a/examples/stm32u5/Cargo.toml +++ b/examples/stm32u5/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32u585ai to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "unstable-pac", "stm32u585ai", "time-driver-any", "memory-x" ] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.1", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32wb/Cargo.toml b/examples/stm32wb/Cargo.toml index 1e1a0efe2..8cea2ace8 100644 --- a/examples/stm32wb/Cargo.toml +++ b/examples/stm32wb/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32wb55rg", "time-driver-any", "memory-x", "exti"] } embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", features = ["defmt", "stm32wb55rg"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.1", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", ], optional=true } diff --git a/examples/stm32wba/Cargo.toml b/examples/stm32wba/Cargo.toml index 401281c0b..4261564dd 100644 --- a/examples/stm32wba/Cargo.toml +++ b/examples/stm32wba/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32wba52cg", "time-driver-any", "memory-x", "exti"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.1", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", ], optional=true } diff --git a/examples/stm32wl/Cargo.toml b/examples/stm32wl/Cargo.toml index 46af5218c..f8d5afb86 100644 --- a/examples/stm32wl/Cargo.toml +++ b/examples/stm32wl/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32wl55jc-cm4 to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32wl55jc-cm4", "time-driver-any", "memory-x", "unstable-pac", "exti", "chrono"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-4096", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.1", path = "../../embassy-executor", features = ["task-arena-size-4096", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } diff --git a/examples/wasm/Cargo.toml b/examples/wasm/Cargo.toml index 75de079b7..f8db71233 100644 --- a/examples/wasm/Cargo.toml +++ b/examples/wasm/Cargo.toml @@ -9,7 +9,7 @@ crate-type = ["cdylib"] [dependencies] embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["log"] } -embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["arch-wasm", "executor-thread", "log", "integrated-timers"] } +embassy-executor = { version = "0.6.1", path = "../../embassy-executor", features = ["arch-wasm", "executor-thread", "log", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["log", "wasm", ] } wasm-logger = "0.2.0" diff --git a/tests/nrf/Cargo.toml b/tests/nrf/Cargo.toml index f666634d5..d36ab9c67 100644 --- a/tests/nrf/Cargo.toml +++ b/tests/nrf/Cargo.toml @@ -9,7 +9,7 @@ teleprobe-meta = "1" embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt", ] } -embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "task-arena-size-16384", "integrated-timers"] } +embassy-executor = { version = "0.6.1", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "task-arena-size-16384", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "time-driver-rtc1", "gpiote", "unstable-pac"] } embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } diff --git a/tests/riscv32/Cargo.toml b/tests/riscv32/Cargo.toml index ae2b0e180..0ee7f5a00 100644 --- a/tests/riscv32/Cargo.toml +++ b/tests/riscv32/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] critical-section = { version = "1.1.1", features = ["restore-state-bool"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync" } -embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["arch-riscv32", "executor-thread"] } +embassy-executor = { version = "0.6.1", path = "../../embassy-executor", features = ["arch-riscv32", "executor-thread"] } embassy-time = { version = "0.3.2", path = "../../embassy-time" } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/tests/rp/Cargo.toml b/tests/rp/Cargo.toml index 12f1ec3ce..ce812af78 100644 --- a/tests/rp/Cargo.toml +++ b/tests/rp/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" teleprobe-meta = "1.1" embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.1", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", ] } embassy-rp = { version = "0.2.0", path = "../../embassy-rp", features = [ "defmt", "unstable-pac", "time-driver", "critical-section-impl", "intrinsics", "rom-v2-intrinsics", "run-from-ram", "rp2040"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml index 2eac636e5..468d2ed54 100644 --- a/tests/stm32/Cargo.toml +++ b/tests/stm32/Cargo.toml @@ -60,7 +60,7 @@ cm0 = ["portable-atomic/unsafe-assume-single-core"] teleprobe-meta = "1" embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.1", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "tick-hz-131_072", "defmt-timestamp-uptime"] } embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "memory-x", "time-driver-any"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } From ecac24a1c7283ab3e3a10df801270eea5491ef3a Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 21 Oct 2024 01:10:55 +0200 Subject: [PATCH 0246/1217] stm32: Fix build for chips with octospim but not octospi2. --- ci.sh | 1 + embassy-stm32/build.rs | 14 +++++++++----- embassy-stm32/src/ospi/mod.rs | 2 +- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/ci.sh b/ci.sh index aa078be31..b04a4b288 100755 --- a/ci.sh +++ b/ci.sh @@ -166,6 +166,7 @@ cargo batch \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32h562ag,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32wba50ke,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32wba55ug,defmt,exti,time-driver-any,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32u5f9zj,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32u5g9nj,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wb35ce,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32u031r8,defmt,exti,time-driver-any,time \ diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 966dce121..71bfb3747 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -55,7 +55,7 @@ fn main() { let mut singletons: Vec = Vec::new(); for p in METADATA.peripherals { if let Some(r) = &p.registers { - if r.kind == "adccommon" || r.kind == "sai" || r.kind == "ucpd" || r.kind == "otg" { + if r.kind == "adccommon" || r.kind == "sai" || r.kind == "ucpd" || r.kind == "otg" || r.kind == "octospi" { // TODO: should we emit this for all peripherals? if so, we will need a list of all // possible peripherals across all chips, so that we can declare the configs // (replacing the hard-coded list of `peri_*` cfgs below) @@ -113,6 +113,7 @@ fn main() { "peri_ucpd2", "peri_usb_otg_fs", "peri_usb_otg_hs", + "peri_octospi2", ]); cfgs.declare_all(&["mco", "mco1", "mco2"]); @@ -1137,11 +1138,14 @@ fn main() { // OCTOSPIM is special if p.name == "OCTOSPIM" { + // Some chips have OCTOSPIM but not OCTOSPI2. + if METADATA.peripherals.iter().any(|p| p.name == "OCTOSPI2") { + peri = format_ident!("{}", "OCTOSPI2"); + g.extend(quote! { + pin_trait_impl!(#tr, #peri, #pin_name, #af); + }); + } peri = format_ident!("{}", "OCTOSPI1"); - g.extend(quote! { - pin_trait_impl!(#tr, #peri, #pin_name, #af); - }); - peri = format_ident!("{}", "OCTOSPI2"); } g.extend(quote! { diff --git a/embassy-stm32/src/ospi/mod.rs b/embassy-stm32/src/ospi/mod.rs index 48a1ea5e6..e4adc4b09 100644 --- a/embassy-stm32/src/ospi/mod.rs +++ b/embassy-stm32/src/ospi/mod.rs @@ -1178,7 +1178,7 @@ impl SealedOctospimInstance for peripherals::OCTOSPI1 { const OCTOSPI_IDX: u8 = 1; } -#[cfg(octospim_v1)] +#[cfg(all(octospim_v1, peri_octospi2))] impl SealedOctospimInstance for peripherals::OCTOSPI2 { const OCTOSPIM_REGS: Octospim = crate::pac::OCTOSPIM; const OCTOSPI_IDX: u8 = 2; From b4ee17fb4f1a77c26fc08e9fe9e0d343d1c059b4 Mon Sep 17 00:00:00 2001 From: Fan Jiang Date: Sun, 20 Oct 2024 12:29:38 -0400 Subject: [PATCH 0247/1217] net: Add flush for UDP and Raw sockets. --- embassy-net/Cargo.toml | 2 +- embassy-net/src/raw.rs | 17 +++++++++++++++++ embassy-net/src/udp.rs | 17 +++++++++++++++++ 3 files changed, 35 insertions(+), 1 deletion(-) diff --git a/embassy-net/Cargo.toml b/embassy-net/Cargo.toml index a33c693fc..8a29aca79 100644 --- a/embassy-net/Cargo.toml +++ b/embassy-net/Cargo.toml @@ -68,7 +68,7 @@ multicast = ["smoltcp/multicast"] defmt = { version = "0.3", optional = true } log = { version = "0.4.14", optional = true } -smoltcp = { git="https://github.com/smoltcp-rs/smoltcp", rev="b65e1b64dc9b66fa984a2ad34e90685cb0b606de", default-features = false, features = [ +smoltcp = { git="https://github.com/smoltcp-rs/smoltcp", rev="fe0b4d102253465850cd1cf39cd33d4721a4a8d5", default-features = false, features = [ "socket", "async", ] } diff --git a/embassy-net/src/raw.rs b/embassy-net/src/raw.rs index 1098dc208..ace325a46 100644 --- a/embassy-net/src/raw.rs +++ b/embassy-net/src/raw.rs @@ -108,6 +108,23 @@ impl<'a> RawSocket<'a> { } }) } + + /// Flush the socket. + /// + /// This method will wait until the socket is flushed. + pub async fn flush(&mut self) { + poll_fn(move |cx| { + self.with_mut(|s, _| { + if s.send_queue() == 0 { + Poll::Ready(()) + } else { + s.register_send_waker(cx.waker()); + Poll::Pending + } + }) + }) + .await + } } impl Drop for RawSocket<'_> { diff --git a/embassy-net/src/udp.rs b/embassy-net/src/udp.rs index 3eb6e2f83..ac650364e 100644 --- a/embassy-net/src/udp.rs +++ b/embassy-net/src/udp.rs @@ -241,6 +241,23 @@ impl<'a> UdpSocket<'a> { .await } + /// Flush the socket. + /// + /// This method will wait until the socket is flushed. + pub async fn flush(&mut self) { + poll_fn(move |cx| { + self.with_mut(|s, _| { + if s.send_queue() == 0 { + Poll::Ready(()) + } else { + s.register_send_waker(cx.waker()); + Poll::Pending + } + }) + }) + .await + } + /// Returns the local endpoint of the socket. pub fn endpoint(&self) -> IpListenEndpoint { self.with(|s, _| s.endpoint()) From 1d395fc2b6e5d3d870afb90593de9f03d47b0efa Mon Sep 17 00:00:00 2001 From: Lucas Martins Date: Tue, 3 Sep 2024 14:38:22 -0300 Subject: [PATCH 0248/1217] stm32/flash: add stm32f2, stm32h5 flash driver --- embassy-stm32/src/flash/h5.rs | 177 +++++++++++++++++++++++++++++++++ embassy-stm32/src/flash/mod.rs | 5 +- 2 files changed, 180 insertions(+), 2 deletions(-) create mode 100644 embassy-stm32/src/flash/h5.rs diff --git a/embassy-stm32/src/flash/h5.rs b/embassy-stm32/src/flash/h5.rs new file mode 100644 index 000000000..9e131ca2b --- /dev/null +++ b/embassy-stm32/src/flash/h5.rs @@ -0,0 +1,177 @@ +use core::ptr::write_volatile; +use core::sync::atomic::{fence, Ordering}; + +use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; +use crate::flash::Error; +use crate::pac; + +pub(crate) const fn is_default_layout() -> bool { + true +} + +// const fn is_dual_bank() -> bool { +// FLASH_REGIONS.len() >= 2 +// } + +pub(crate) fn get_flash_regions() -> &'static [&'static FlashRegion] { + &FLASH_REGIONS +} + +pub(crate) unsafe fn lock() { + if !pac::FLASH.nscr().read().lock() { + pac::FLASH.nscr().modify(|r| { + r.set_lock(true); + }); + } +} + +pub(crate) unsafe fn unlock() { + // TODO: check locked first + while pac::FLASH.nssr().read().bsy() { + #[cfg(feature = "defmt")] + defmt::trace!("busy") + } + + // only unlock if locked to begin with + if pac::FLASH.nscr().read().lock() { + pac::FLASH.nskeyr().write_value(0x4567_0123); + pac::FLASH.nskeyr().write_value(0xCDEF_89AB); + } +} + +pub(crate) unsafe fn enable_blocking_write() { + assert_eq!(0, WRITE_SIZE % 4); +} + +pub(crate) unsafe fn disable_blocking_write() {} + +pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> { + // // We cannot have the write setup sequence in begin_write as it depends on the address + // let bank = if start_address < BANK1_REGION.end() { + // pac::FLASH.bank(0) + // } else { + // pac::FLASH.bank(1) + // }; + + cortex_m::asm::isb(); + cortex_m::asm::dsb(); + fence(Ordering::SeqCst); + + clear_all_err(); + + pac::FLASH.nscr().write(|w| { + w.set_pg(true); + // w.set_psize(2); // 32 bits at once + }); + + let mut res = None; + let mut address = start_address; + // TODO: see write size + for val in buf.chunks(4) { + write_volatile(address as *mut u32, u32::from_le_bytes(unwrap!(val.try_into()))); + address += val.len() as u32; + + res = Some(blocking_wait_ready().map_err(|e| { + error!("write err"); + e + })); + pac::FLASH.nssr().modify(|w| { + if w.eop() { + w.set_eop(true); + } + }); + if unwrap!(res).is_err() { + break; + } + } + + cortex_m::asm::isb(); + cortex_m::asm::dsb(); + fence(Ordering::SeqCst); + + pac::FLASH.nscr().write(|w| w.set_pg(false)); + + unwrap!(res) +} + +pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> { + // pac::FLASH.wrp2r_cur().read().wrpsg() + // TODO: write protection check + if pac::FLASH.nscr().read().lock() == true { + error!("flash locked"); + } + + loop { + let sr = pac::FLASH.nssr().read(); + if !sr.bsy() && !sr.dbne() { + break; + } + } + clear_all_err(); + + pac::FLASH.nscr().modify(|r| { + // TODO: later check bank swap + r.set_bksel(match sector.bank { + crate::flash::FlashBank::Bank1 => stm32_metapac::flash::vals::NscrBksel::B_0X0, + crate::flash::FlashBank::Bank2 => stm32_metapac::flash::vals::NscrBksel::B_0X1, + }); + r.set_snb(sector.index_in_bank); + r.set_ser(true); + }); + + pac::FLASH.nscr().modify(|r| { + r.set_strt(true); + }); + + cortex_m::asm::isb(); + cortex_m::asm::dsb(); + fence(Ordering::SeqCst); + + let ret: Result<(), Error> = blocking_wait_ready().map_err(|e| { + error!("erase err"); + e + }); + + pac::FLASH.nscr().modify(|w| w.set_ser(false)); + clear_all_err(); + ret +} + +pub(crate) unsafe fn clear_all_err() { + pac::FLASH.nssr().modify(|_| {}) +} + +unsafe fn blocking_wait_ready() -> Result<(), Error> { + loop { + let sr = pac::FLASH.nssr().read(); + + if !sr.bsy() { + if sr.optchangeerr() { + error!("optchangeerr"); + return Err(Error::Prog); + } + if sr.obkwerr() { + error!("obkwerr"); + return Err(Error::Seq); + } + if sr.obkerr() { + error!("obkerr"); + return Err(Error::Seq); + } + if sr.incerr() { + error!("incerr"); + return Err(Error::Unaligned); + } + if sr.strberr() { + error!("strberr"); + return Err(Error::Parallelism); + } + if sr.wrperr() { + error!("protected"); + return Err(Error::Protected); + } + + return Ok(()); + } + } +} diff --git a/embassy-stm32/src/flash/mod.rs b/embassy-stm32/src/flash/mod.rs index d64a1c28a..88fe6a291 100644 --- a/embassy-stm32/src/flash/mod.rs +++ b/embassy-stm32/src/flash/mod.rs @@ -101,13 +101,14 @@ pub enum FlashBank { #[cfg_attr(flash_h7, path = "h7.rs")] #[cfg_attr(flash_h7ab, path = "h7.rs")] #[cfg_attr(flash_u5, path = "u5.rs")] +#[cfg_attr(flash_h5, path = "h5.rs")] #[cfg_attr(flash_h50, path = "h50.rs")] #[cfg_attr(flash_u0, path = "u0.rs")] #[cfg_attr( not(any( flash_l0, flash_l1, flash_l4, flash_l5, flash_wl, flash_wb, flash_f0, flash_f1, flash_f2, flash_f3, flash_f4, - flash_f7, flash_g0, flash_g0, flash_g4c2, flash_g4c3, flash_g4c4, flash_h7, flash_h7ab, flash_u5, flash_h50, - flash_u0 + flash_f7, flash_g0, flash_g4c2, flash_g4c3, flash_g4c4, flash_h7, flash_h7ab, flash_u5, flash_h50, flash_u0, + flash_h5, )), path = "other.rs" )] From 693bd8c6ded003f78ae89fa2700ba7282fee64d0 Mon Sep 17 00:00:00 2001 From: rafael Date: Mon, 21 Oct 2024 11:54:17 +0200 Subject: [PATCH 0249/1217] re-export SetDutyCycle for user convenience --- embassy-rp/src/pwm.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/embassy-rp/src/pwm.rs b/embassy-rp/src/pwm.rs index 79e626802..de2c2f81e 100644 --- a/embassy-rp/src/pwm.rs +++ b/embassy-rp/src/pwm.rs @@ -1,7 +1,7 @@ //! Pulse Width Modulation (PWM) use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; -use embedded_hal_1::pwm::{Error, ErrorKind, ErrorType, SetDutyCycle}; +use embedded_hal_1::pwm::{Error, ErrorKind, ErrorType}; use fixed::traits::ToFixed; use fixed::FixedU16; use pac::pwm::regs::{ChDiv, Intr}; @@ -10,6 +10,8 @@ use pac::pwm::vals::Divmode; use crate::gpio::{AnyPin, Pin as GpioPin, Pull, SealedPin as _}; use crate::{pac, peripherals, RegExt}; +pub use embedded_hal_1::pwm::SetDutyCycle; + /// The configuration of a PWM slice. /// Note the period in clock cycles of a slice can be computed as: /// `(top + 1) * (phase_correct ? 1 : 2) * divider` @@ -113,9 +115,7 @@ impl<'d> SetDutyCycle for Pwm<'d> { } fn set_duty_cycle(&mut self, duty: u16) -> Result<(), Self::Error> { - info!("duty {}",&duty); let max_duty = self.max_duty_cycle(); - info!("max duty {}", &max_duty); if duty > max_duty { return Err(PwmError::InvalidDutyCycle); } From f32b0fbc3b614ab79b7756b49e44a380e5e60192 Mon Sep 17 00:00:00 2001 From: rafael Date: Mon, 21 Oct 2024 11:55:10 +0200 Subject: [PATCH 0250/1217] change existing pwm example to reflect both existing ways to use pwm output --- examples/rp23/src/bin/pwm.rs | 55 +++++++++++++++++++++++++++++++----- 1 file changed, 48 insertions(+), 7 deletions(-) diff --git a/examples/rp23/src/bin/pwm.rs b/examples/rp23/src/bin/pwm.rs index 15eae09ee..7314ee637 100644 --- a/examples/rp23/src/bin/pwm.rs +++ b/examples/rp23/src/bin/pwm.rs @@ -1,6 +1,8 @@ -//! This example shows how to use PWM (Pulse Width Modulation) in the RP2040 chip. +//! This example shows how to use PWM (Pulse Width Modulation) in the RP235x chip. //! -//! The LED on the RP Pico W board is connected differently. Add a LED and resistor to another pin. +//! We demonstrate two ways of using PWM: +//! 1. Via config +//! 2. Via setting a duty cycle #![no_std] #![no_main] @@ -8,8 +10,10 @@ use defmt::*; use embassy_executor::Spawner; use embassy_rp::block::ImageDef; -use embassy_rp::pwm::{Config, Pwm}; +use embassy_rp::peripherals::{PIN_25, PIN_4, PWM_SLICE2, PWM_SLICE4}; +use embassy_rp::pwm::{Config, Pwm, SetDutyCycle}; use embassy_time::Timer; +// use embedded_hal_1::pwm::SetDutyCycle; use {defmt_rtt as _, panic_probe as _}; #[link_section = ".start_block"] @@ -17,13 +21,22 @@ use {defmt_rtt as _, panic_probe as _}; pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); #[embassy_executor::main] -async fn main(_spawner: Spawner) { +async fn main(spawner: Spawner) { let p = embassy_rp::init(Default::default()); + spawner.spawn(pwm_set_config(p.PWM_SLICE4, p.PIN_25)).unwrap(); + spawner.spawn(pwm_set_dutycycle(p.PWM_SLICE2, p.PIN_4)).unwrap(); +} - let mut c: Config = Default::default(); - c.top = 0x8000; +/// Demonstrate PWM by modifying & applying the config +/// +/// Using the onboard led, if You are using a different Board than plain Pico2 (i.e. W variant) +/// you must use another slice & pin and an appropriate resistor. +#[embassy_executor::task] +async fn pwm_set_config(slice4: PWM_SLICE4, pin25: PIN_25) { + let mut c = Config::default(); + c.top = 32_768; c.compare_b = 8; - let mut pwm = Pwm::new_output_b(p.PWM_SLICE4, p.PIN_25, c.clone()); + let mut pwm = Pwm::new_output_b(slice4, pin25, c.clone()); loop { info!("current LED duty cycle: {}/32768", c.compare_b); @@ -32,3 +45,31 @@ async fn main(_spawner: Spawner) { pwm.set_config(&c); } } + +/// Demonstrate PWM by setting duty cycle +/// +/// Using GP4 in Slice2, make sure to use an appropriate resistor. +#[embassy_executor::task] +async fn pwm_set_dutycycle(slice2: PWM_SLICE2, pin4: PIN_4) { + let mut c = Config::default(); + c.top = 32_768; + let mut pwm = Pwm::new_output_a(slice2, pin4, c.clone()); + + loop { + // 100% duty cycle, fully on + pwm.set_duty_cycle_fully_on().unwrap(); + Timer::after_secs(1).await; + + // 50% duty cycle, half on. Expressed as simple percentage. + pwm.set_duty_cycle_percent(50).unwrap(); + Timer::after_secs(1).await; + + // 25% duty cycle, quarter on. Expressed as (duty / max_duty) + pwm.set_duty_cycle(8_192 / c.top).unwrap(); + Timer::after_secs(1).await; + + // 0% duty cycle, fully off. + pwm.set_duty_cycle_fully_off().unwrap(); + Timer::after_secs(1).await; + } +} From d7db8fbab9a2bc363520505757386500d5710735 Mon Sep 17 00:00:00 2001 From: rafael Date: Mon, 21 Oct 2024 11:59:03 +0200 Subject: [PATCH 0251/1217] rustfmt --- embassy-rp/src/pwm.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/embassy-rp/src/pwm.rs b/embassy-rp/src/pwm.rs index de2c2f81e..cfb99c569 100644 --- a/embassy-rp/src/pwm.rs +++ b/embassy-rp/src/pwm.rs @@ -1,6 +1,7 @@ //! Pulse Width Modulation (PWM) use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; +pub use embedded_hal_1::pwm::SetDutyCycle; use embedded_hal_1::pwm::{Error, ErrorKind, ErrorType}; use fixed::traits::ToFixed; use fixed::FixedU16; @@ -10,8 +11,6 @@ use pac::pwm::vals::Divmode; use crate::gpio::{AnyPin, Pin as GpioPin, Pull, SealedPin as _}; use crate::{pac, peripherals, RegExt}; -pub use embedded_hal_1::pwm::SetDutyCycle; - /// The configuration of a PWM slice. /// Note the period in clock cycles of a slice can be computed as: /// `(top + 1) * (phase_correct ? 1 : 2) * divider` From d92fb002ecc3ff4dcac51d8e74927d977b2343b0 Mon Sep 17 00:00:00 2001 From: rafael Date: Mon, 21 Oct 2024 12:19:10 +0200 Subject: [PATCH 0252/1217] rustfmt --- examples/rp23/src/bin/pwm.rs | 1 - examples/rp23/src/bin/pwm_tb6612fng_motor_driver.rs | 7 ++----- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/examples/rp23/src/bin/pwm.rs b/examples/rp23/src/bin/pwm.rs index 7314ee637..1dd5ca3de 100644 --- a/examples/rp23/src/bin/pwm.rs +++ b/examples/rp23/src/bin/pwm.rs @@ -13,7 +13,6 @@ use embassy_rp::block::ImageDef; use embassy_rp::peripherals::{PIN_25, PIN_4, PWM_SLICE2, PWM_SLICE4}; use embassy_rp::pwm::{Config, Pwm, SetDutyCycle}; use embassy_time::Timer; -// use embedded_hal_1::pwm::SetDutyCycle; use {defmt_rtt as _, panic_probe as _}; #[link_section = ".start_block"] diff --git a/examples/rp23/src/bin/pwm_tb6612fng_motor_driver.rs b/examples/rp23/src/bin/pwm_tb6612fng_motor_driver.rs index 36b8d9620..6c3a8998c 100644 --- a/examples/rp23/src/bin/pwm_tb6612fng_motor_driver.rs +++ b/examples/rp23/src/bin/pwm_tb6612fng_motor_driver.rs @@ -10,12 +10,9 @@ use defmt::*; use embassy_executor::Spawner; use embassy_rp::block::ImageDef; use embassy_rp::config::Config; -use embassy_rp::gpio; use embassy_rp::gpio::Output; -use embassy_rp::peripherals; -use embassy_rp::pwm; -use embassy_time::Duration; -use embassy_time::Timer; +use embassy_rp::{gpio, peripherals, pwm}; +use embassy_time::{Duration, Timer}; use tb6612fng::{DriveCommand, Motor, Tb6612fng}; use {defmt_rtt as _, panic_probe as _}; From e782eabff743175b34489401574d1988c370f06f Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 21 Oct 2024 16:20:40 +0200 Subject: [PATCH 0253/1217] Changelog executor v0.5.1 release. --- embassy-executor/CHANGELOG.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/embassy-executor/CHANGELOG.md b/embassy-executor/CHANGELOG.md index ac1c8cb0c..3d8c48676 100644 --- a/embassy-executor/CHANGELOG.md +++ b/embassy-executor/CHANGELOG.md @@ -11,7 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Soundness fix: Deny using `impl Trait` in task arguments. This was previously accidentally allowed when not using the `nightly` feature, and could cause out of bounds memory accesses if spawning the same task mulitple times with different underlying types - for the `impl Trait`. Affected versions are 0.4.x, 0.5.x and 0.6.0, which have been yanked. + for the `impl Trait`. Affected versions are 0.4.x, 0.5.0 and 0.6.0, which have been yanked. - Add an architecture-agnostic executor that spins waiting for tasks to run, enabled with the `arch-spin` feature. - Update for breaking change in the nightly waker_getters API. The `nightly` feature now requires`nightly-2024-09-06` or newer. - Improve macro error messages. @@ -22,6 +22,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - initial support for AVR - use nightly waker_getters APIs +## 0.5.1 - 2024-10-21 + +- Soundness fix: Deny using `impl Trait` in task arguments. This was previously accidentally allowed when not using the `nightly` feature, + and could cause out of bounds memory accesses if spawning the same task mulitple times with different underlying types + for the `impl Trait`. Affected versions are 0.4.x, 0.5.0 and 0.6.0, which have been yanked. + ## 0.5.0 - 2024-01-11 - Updated to `embassy-time-driver 0.1`, `embassy-time-queue-driver 0.1`, compatible with `embassy-time v0.3` and higher. From 61f55be92ae11805ae233d9c2526b41b605b3f8e Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Mon, 21 Oct 2024 19:41:28 +0200 Subject: [PATCH 0254/1217] Use released version of reqwless for examples --- examples/rp/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index 8e5f81b7e..6a2c99716 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml @@ -25,7 +25,7 @@ fixed = "1.23.1" fixed-macro = "1.2" # for web request example -reqwless = { git="https://github.com/drogue-iot/reqwless", rev="673e8d2cfbaad79254ec51fa50cc8b697531fbff", features = ["defmt",]} +reqwless = { version = "0.13.0", features = ["defmt"] } serde = { version = "1.0.203", default-features = false, features = ["derive"] } serde-json-core = "0.5.1" From c0addc005bb3859436cb1c2931b41a7065703077 Mon Sep 17 00:00:00 2001 From: Lucas Martins Date: Mon, 21 Oct 2024 14:48:57 -0300 Subject: [PATCH 0255/1217] add uart permutations usefull for rs485 --- embassy-stm32/src/usart/buffered.rs | 49 +++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs index 4fbe33b2e..03c0934f9 100644 --- a/embassy-stm32/src/usart/buffered.rs +++ b/embassy-stm32/src/usart/buffered.rs @@ -246,6 +246,55 @@ impl<'d> BufferedUart<'d> { ) } + + /// Create a new bidirectional buffered UART driver with only RTS pin as the DE pin + pub fn new_with_rts_as_de( + peri: impl Peripheral

+ 'd, + _irq: impl interrupt::typelevel::Binding> + 'd, + rx: impl Peripheral

> + 'd, + tx: impl Peripheral

> + 'd, + rts: impl Peripheral

> + 'd, + tx_buffer: &'d mut [u8], + rx_buffer: &'d mut [u8], + config: Config, + ) -> Result { + Self::new_inner( + peri, + new_pin!(rx, AfType::input(Pull::None)), + new_pin!(tx, AfType::output(OutputType::PushPull, Speed::Medium)), + None, + None, + new_pin!(rts, AfType::input(Pull::None)), // RTS mapped used as DE + tx_buffer, + rx_buffer, + config, + ) + } + + /// Create a new bidirectional buffered UART driver with only the request-to-send pin + pub fn new_with_rts( + peri: impl Peripheral

+ 'd, + _irq: impl interrupt::typelevel::Binding> + 'd, + rx: impl Peripheral

> + 'd, + tx: impl Peripheral

> + 'd, + rts: impl Peripheral

> + 'd, + tx_buffer: &'d mut [u8], + rx_buffer: &'d mut [u8], + config: Config, + ) -> Result { + Self::new_inner( + peri, + new_pin!(rx, AfType::input(Pull::None)), + new_pin!(tx, AfType::output(OutputType::PushPull, Speed::Medium)), + new_pin!(rts, AfType::input(Pull::None)), + None, // no RTS + None, // no DE + tx_buffer, + rx_buffer, + config, + ) + } + /// Create a new bidirectional buffered UART driver with a driver-enable pin #[cfg(not(any(usart_v1, usart_v2)))] pub fn new_with_de( From 2c9b528edde491ca1ed02234805212c78e2a6bd7 Mon Sep 17 00:00:00 2001 From: Lucas Martins Date: Mon, 21 Oct 2024 15:06:06 -0300 Subject: [PATCH 0256/1217] fmt --- embassy-stm32/src/usart/buffered.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs index 03c0934f9..edaf41be9 100644 --- a/embassy-stm32/src/usart/buffered.rs +++ b/embassy-stm32/src/usart/buffered.rs @@ -246,7 +246,6 @@ impl<'d> BufferedUart<'d> { ) } - /// Create a new bidirectional buffered UART driver with only RTS pin as the DE pin pub fn new_with_rts_as_de( peri: impl Peripheral

+ 'd, From 8dfc9ba1a3e3f69aedf5bce748783fb6a8f5e92e Mon Sep 17 00:00:00 2001 From: rafael Date: Mon, 21 Oct 2024 21:14:49 +0200 Subject: [PATCH 0257/1217] also add to the rp pwm example --- examples/rp/src/bin/pwm.rs | 52 +++++++++++++++++++++++++++++++----- examples/rp23/src/bin/pwm.rs | 8 +++--- 2 files changed, 50 insertions(+), 10 deletions(-) diff --git a/examples/rp/src/bin/pwm.rs b/examples/rp/src/bin/pwm.rs index 26e233260..862a7da22 100644 --- a/examples/rp/src/bin/pwm.rs +++ b/examples/rp/src/bin/pwm.rs @@ -1,24 +1,36 @@ //! This example shows how to use PWM (Pulse Width Modulation) in the RP2040 chip. //! -//! The LED on the RP Pico W board is connected differently. Add a LED and resistor to another pin. +//! We demonstrate two ways of using PWM: +//! 1. Via config +//! 2. Via setting a duty cycle #![no_std] #![no_main] use defmt::*; use embassy_executor::Spawner; -use embassy_rp::pwm::{Config, Pwm}; +use embassy_rp::peripherals::{PIN_25, PIN_4, PWM_SLICE2, PWM_SLICE4}; +use embassy_rp::pwm::{Config, Pwm, SetDutyCycle}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] -async fn main(_spawner: Spawner) { +async fn main(spawner: Spawner) { let p = embassy_rp::init(Default::default()); + spawner.spawn(pwm_set_config(p.PWM_SLICE4, p.PIN_25)).unwrap(); + spawner.spawn(pwm_set_dutycycle(p.PWM_SLICE2, p.PIN_4)).unwrap(); +} - let mut c: Config = Default::default(); - c.top = 0x8000; +/// Demonstrate PWM by modifying & applying the config +/// +/// Using the onboard led, if You are using a different Board than plain Pico2 (i.e. W variant) +/// you must use another slice & pin and an appropriate resistor. +#[embassy_executor::task] +async fn pwm_set_config(slice4: PWM_SLICE4, pin25: PIN_25) { + let mut c = Config::default(); + c.top = 32_768; c.compare_b = 8; - let mut pwm = Pwm::new_output_b(p.PWM_SLICE4, p.PIN_25, c.clone()); + let mut pwm = Pwm::new_output_b(slice4, pin25, c.clone()); loop { info!("current LED duty cycle: {}/32768", c.compare_b); @@ -27,3 +39,31 @@ async fn main(_spawner: Spawner) { pwm.set_config(&c); } } + +/// Demonstrate PWM by setting duty cycle +/// +/// Using GP4 in Slice2, make sure to use an appropriate resistor. +#[embassy_executor::task] +async fn pwm_set_dutycycle(slice2: PWM_SLICE2, pin4: PIN_4) { + let mut c = Config::default(); + c.top = 32_768; + let mut pwm = Pwm::new_output_a(slice2, pin4, c.clone()); + + loop { + // 100% duty cycle, fully on + pwm.set_duty_cycle_fully_on().unwrap(); + Timer::after_secs(1).await; + + // 66% duty cycle. Expressed as simple percentage. + pwm.set_duty_cycle_percent(66).unwrap(); + Timer::after_secs(1).await; + + // 25% duty cycle. Expressed as 32768/4 = 8192. + pwm.set_duty_cycle(8_192).unwrap(); + Timer::after_secs(1).await; + + // 0% duty cycle, fully off. + pwm.set_duty_cycle_fully_off().unwrap(); + Timer::after_secs(1).await; + } +} diff --git a/examples/rp23/src/bin/pwm.rs b/examples/rp23/src/bin/pwm.rs index 1dd5ca3de..838eee625 100644 --- a/examples/rp23/src/bin/pwm.rs +++ b/examples/rp23/src/bin/pwm.rs @@ -59,12 +59,12 @@ async fn pwm_set_dutycycle(slice2: PWM_SLICE2, pin4: PIN_4) { pwm.set_duty_cycle_fully_on().unwrap(); Timer::after_secs(1).await; - // 50% duty cycle, half on. Expressed as simple percentage. - pwm.set_duty_cycle_percent(50).unwrap(); + // 66% duty cycle. Expressed as simple percentage. + pwm.set_duty_cycle_percent(66).unwrap(); Timer::after_secs(1).await; - // 25% duty cycle, quarter on. Expressed as (duty / max_duty) - pwm.set_duty_cycle(8_192 / c.top).unwrap(); + // 25% duty cycle. Expressed as 32768/4 = 8192. + pwm.set_duty_cycle(8_192).unwrap(); Timer::after_secs(1).await; // 0% duty cycle, fully off. From 14e69309ebe25a76f67c38411c7a80a4d83da5ed Mon Sep 17 00:00:00 2001 From: rafael Date: Mon, 21 Oct 2024 22:42:18 +0200 Subject: [PATCH 0258/1217] add pwm frequency to examples --- examples/rp/src/bin/pwm.rs | 10 ++++++++-- examples/rp23/src/bin/pwm.rs | 10 ++++++++-- .../rp23/src/bin/pwm_tb6612fng_motor_driver.rs | 17 +++++++---------- 3 files changed, 23 insertions(+), 14 deletions(-) diff --git a/examples/rp/src/bin/pwm.rs b/examples/rp/src/bin/pwm.rs index 862a7da22..791b88b5b 100644 --- a/examples/rp/src/bin/pwm.rs +++ b/examples/rp/src/bin/pwm.rs @@ -45,8 +45,14 @@ async fn pwm_set_config(slice4: PWM_SLICE4, pin25: PIN_25) { /// Using GP4 in Slice2, make sure to use an appropriate resistor. #[embassy_executor::task] async fn pwm_set_dutycycle(slice2: PWM_SLICE2, pin4: PIN_4) { + // If we aim for a specific frequency, here is how we can calculate the top value. + // The top value sets the period of the PWM cycle, so a counter goes from 0 to top and then wraps around to 0. + // Every such wraparound is one PWM cycle. So here is how we get 25KHz: let mut c = Config::default(); - c.top = 32_768; + let pwm_freq = 25_000; // Hz, our desired frequency + let clock_freq = embassy_rp::clocks::clk_sys_freq(); + c.top = (clock_freq / pwm_freq) as u16 - 1; + let mut pwm = Pwm::new_output_a(slice2, pin4, c.clone()); loop { @@ -59,7 +65,7 @@ async fn pwm_set_dutycycle(slice2: PWM_SLICE2, pin4: PIN_4) { Timer::after_secs(1).await; // 25% duty cycle. Expressed as 32768/4 = 8192. - pwm.set_duty_cycle(8_192).unwrap(); + pwm.set_duty_cycle(c.top / 4).unwrap(); Timer::after_secs(1).await; // 0% duty cycle, fully off. diff --git a/examples/rp23/src/bin/pwm.rs b/examples/rp23/src/bin/pwm.rs index 838eee625..5a4457158 100644 --- a/examples/rp23/src/bin/pwm.rs +++ b/examples/rp23/src/bin/pwm.rs @@ -50,8 +50,14 @@ async fn pwm_set_config(slice4: PWM_SLICE4, pin25: PIN_25) { /// Using GP4 in Slice2, make sure to use an appropriate resistor. #[embassy_executor::task] async fn pwm_set_dutycycle(slice2: PWM_SLICE2, pin4: PIN_4) { + // If we aim for a specific frequency, here is how we can calculate the top value. + // The top value sets the period of the PWM cycle, so a counter goes from 0 to top and then wraps around to 0. + // Every such wraparound is one PWM cycle. So here is how we get 25KHz: let mut c = Config::default(); - c.top = 32_768; + let pwm_freq = 25_000; // Hz, our desired frequency + let clock_freq = embassy_rp::clocks::clk_sys_freq(); + c.top = (clock_freq / pwm_freq) as u16 - 1; + let mut pwm = Pwm::new_output_a(slice2, pin4, c.clone()); loop { @@ -64,7 +70,7 @@ async fn pwm_set_dutycycle(slice2: PWM_SLICE2, pin4: PIN_4) { Timer::after_secs(1).await; // 25% duty cycle. Expressed as 32768/4 = 8192. - pwm.set_duty_cycle(8_192).unwrap(); + pwm.set_duty_cycle(c.top / 4).unwrap(); Timer::after_secs(1).await; // 0% duty cycle, fully off. diff --git a/examples/rp23/src/bin/pwm_tb6612fng_motor_driver.rs b/examples/rp23/src/bin/pwm_tb6612fng_motor_driver.rs index 6c3a8998c..263b551de 100644 --- a/examples/rp23/src/bin/pwm_tb6612fng_motor_driver.rs +++ b/examples/rp23/src/bin/pwm_tb6612fng_motor_driver.rs @@ -16,12 +16,6 @@ use embassy_time::{Duration, Timer}; use tb6612fng::{DriveCommand, Motor, Tb6612fng}; use {defmt_rtt as _, panic_probe as _}; -/// Maximum PWM value (fully on) -const PWM_MAX: u16 = 50000; - -/// Minimum PWM value (fully off) -const PWM_MIN: u16 = 0; - #[link_section = ".start_block"] #[used] pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); @@ -46,6 +40,11 @@ async fn main(_spawner: Spawner) { let s = split_resources!(p); let r = s.motor; + // we want a PWM frequency of 25KHz + let pwm_freq = 25_000; // Hz, our desired frequency + let clock_freq = embassy_rp::clocks::clk_sys_freq(); + let period = (clock_freq / pwm_freq) as u16 - 1; + // we need a standby output and two motors to construct a full TB6612FNG // standby pin @@ -55,8 +54,7 @@ async fn main(_spawner: Spawner) { let left_fwd = gpio::Output::new(r.left_forward_pin, gpio::Level::Low); let left_bckw = gpio::Output::new(r.left_backward_pin, gpio::Level::Low); let mut left_speed = pwm::Config::default(); - left_speed.top = PWM_MAX; - left_speed.compare_a = PWM_MIN; + left_speed.top = period; let left_pwm = pwm::Pwm::new_output_a(r.left_slice, r.left_pwm_pin, left_speed); let left_motor = Motor::new(left_fwd, left_bckw, left_pwm).unwrap(); @@ -64,8 +62,7 @@ async fn main(_spawner: Spawner) { let right_fwd = gpio::Output::new(r.right_forward_pin, gpio::Level::Low); let right_bckw = gpio::Output::new(r.right_backward_pin, gpio::Level::Low); let mut right_speed = pwm::Config::default(); - right_speed.top = PWM_MAX; - right_speed.compare_b = PWM_MIN; + right_speed.top = period; let right_pwm = pwm::Pwm::new_output_b(r.right_slice, r.right_pwm_pin, right_speed); let right_motor = Motor::new(right_fwd, right_bckw, right_pwm).unwrap(); From 82772e3a8f36b31052ca46af3947ba253458bef1 Mon Sep 17 00:00:00 2001 From: Lucas Martins Date: Mon, 21 Oct 2024 17:50:05 -0300 Subject: [PATCH 0259/1217] :memo: fix wrong comment --- embassy-stm32/src/usart/buffered.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs index edaf41be9..7ba209063 100644 --- a/embassy-stm32/src/usart/buffered.rs +++ b/embassy-stm32/src/usart/buffered.rs @@ -246,7 +246,7 @@ impl<'d> BufferedUart<'d> { ) } - /// Create a new bidirectional buffered UART driver with only RTS pin as the DE pin + /// Create a new bidirectional buffered UART driver with only the RTS pin as the DE pin pub fn new_with_rts_as_de( peri: impl Peripheral

+ 'd, _irq: impl interrupt::typelevel::Binding> + 'd, @@ -286,7 +286,7 @@ impl<'d> BufferedUart<'d> { new_pin!(rx, AfType::input(Pull::None)), new_pin!(tx, AfType::output(OutputType::PushPull, Speed::Medium)), new_pin!(rts, AfType::input(Pull::None)), - None, // no RTS + None, // no CTS None, // no DE tx_buffer, rx_buffer, From 548f11d5aef37d5ab1edac6970ceb7bee4300f4f Mon Sep 17 00:00:00 2001 From: rafael Date: Mon, 21 Oct 2024 23:19:45 +0200 Subject: [PATCH 0260/1217] cheaper motors need lower pwm frequency --- examples/rp23/src/bin/pwm_tb6612fng_motor_driver.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/rp23/src/bin/pwm_tb6612fng_motor_driver.rs b/examples/rp23/src/bin/pwm_tb6612fng_motor_driver.rs index 263b551de..3fad2928c 100644 --- a/examples/rp23/src/bin/pwm_tb6612fng_motor_driver.rs +++ b/examples/rp23/src/bin/pwm_tb6612fng_motor_driver.rs @@ -40,8 +40,8 @@ async fn main(_spawner: Spawner) { let s = split_resources!(p); let r = s.motor; - // we want a PWM frequency of 25KHz - let pwm_freq = 25_000; // Hz, our desired frequency + // we want a PWM frequency of 1KHz, especially cheaper motors do not respond well to higher frequencies + let pwm_freq = 1_000; // Hz, our desired frequency let clock_freq = embassy_rp::clocks::clk_sys_freq(); let period = (clock_freq / pwm_freq) as u16 - 1; @@ -77,8 +77,8 @@ async fn main(_spawner: Spawner) { // drive a straight line forward at 20% speed for 5s info!("drive straight"); - control.motor_a.drive(DriveCommand::Forward(20)).unwrap(); - control.motor_b.drive(DriveCommand::Forward(20)).unwrap(); + control.motor_a.drive(DriveCommand::Forward(80)).unwrap(); + control.motor_b.drive(DriveCommand::Forward(80)).unwrap(); Timer::after(Duration::from_secs(5)).await; // coast for 2s @@ -95,8 +95,8 @@ async fn main(_spawner: Spawner) { // slowly turn for 3s info!("turn"); - control.motor_a.drive(DriveCommand::Backward(10)).unwrap(); - control.motor_b.drive(DriveCommand::Forward(10)).unwrap(); + control.motor_a.drive(DriveCommand::Backward(50)).unwrap(); + control.motor_b.drive(DriveCommand::Forward(50)).unwrap(); Timer::after(Duration::from_secs(3)).await; // and put the driver in standby mode and wait for 5s From c94c5516d1e9681c7b8222b9ee30f416b4e84c7d Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 22 Oct 2024 03:34:18 +0200 Subject: [PATCH 0261/1217] net: automatically enable defmt/ip_in_core --- embassy-net/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-net/Cargo.toml b/embassy-net/Cargo.toml index 8a29aca79..1090892e0 100644 --- a/embassy-net/Cargo.toml +++ b/embassy-net/Cargo.toml @@ -27,7 +27,7 @@ default = [] std = [] ## Enable defmt -defmt = ["dep:defmt", "smoltcp/defmt", "embassy-net-driver/defmt", "heapless/defmt-03"] +defmt = ["dep:defmt", "smoltcp/defmt", "embassy-net-driver/defmt", "heapless/defmt-03", "defmt?/ip_in_core"] ## Trace all raw received and transmitted packets using defmt or log. packet-trace = [] @@ -65,7 +65,7 @@ multicast = ["smoltcp/multicast"] [dependencies] -defmt = { version = "0.3", optional = true } +defmt = { version = "0.3.8", optional = true } log = { version = "0.4.14", optional = true } smoltcp = { git="https://github.com/smoltcp-rs/smoltcp", rev="fe0b4d102253465850cd1cf39cd33d4721a4a8d5", default-features = false, features = [ From 3279c19eeeb942d15805c7780bf3bcad6159286e Mon Sep 17 00:00:00 2001 From: Dinu Blanovschi Date: Tue, 22 Oct 2024 12:30:37 +0200 Subject: [PATCH 0262/1217] feat(stm32): allow `bind_interrupts!` to accept conditional compilation attrs --- embassy-stm32/src/lib.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 451f595e0..3ff9dcb7e 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -165,7 +165,7 @@ pub use crate::_generated::interrupt; // developer note: this macro can't be in `embassy-hal-internal` due to the use of `$crate`. #[macro_export] macro_rules! bind_interrupts { - ($vis:vis struct $name:ident { $($irq:ident => $($handler:ty),*;)* }) => { + ($vis:vis struct $name:ident { $($(#[cfg($cond:meta)])? $irq:ident => $($handler:ty),*;)* }) => { #[derive(Copy, Clone)] $vis struct $name; @@ -174,11 +174,13 @@ macro_rules! bind_interrupts { #[no_mangle] unsafe extern "C" fn $irq() { $( + $(#[cfg($cond)])? <$handler as $crate::interrupt::typelevel::Handler<$crate::interrupt::typelevel::$irq>>::on_interrupt(); )* } $( + $(#[cfg($cond)])? unsafe impl $crate::interrupt::typelevel::Binding<$crate::interrupt::typelevel::$irq, $handler> for $name {} )* )* From 66822f1000f542cac767be77345cb527956ada04 Mon Sep 17 00:00:00 2001 From: Brad Gibson Date: Tue, 22 Oct 2024 05:29:11 -0700 Subject: [PATCH 0263/1217] update path to cyw43 firmware in `wifi_blinky.rs` comments --- examples/rp/src/bin/wifi_blinky.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/rp/src/bin/wifi_blinky.rs b/examples/rp/src/bin/wifi_blinky.rs index 04a61bbd5..0107a2326 100644 --- a/examples/rp/src/bin/wifi_blinky.rs +++ b/examples/rp/src/bin/wifi_blinky.rs @@ -33,8 +33,8 @@ async fn main(spawner: Spawner) { // To make flashing faster for development, you may want to flash the firmwares independently // at hardcoded addresses, instead of baking them into the program with `include_bytes!`: - // probe-rs download 43439A0.bin --binary-format bin --chip RP2040 --base-address 0x10100000 - // probe-rs download 43439A0_clm.bin --binary-format bin --chip RP2040 --base-address 0x10140000 + // probe-rs download ../../cyw43-firmware/43439A0.bin --binary-format bin --chip RP2040 --base-address 0x10100000 + // probe-rs download ../../cyw43-firmware/43439A0_clm.bin --binary-format bin --chip RP2040 --base-address 0x10140000 //let fw = unsafe { core::slice::from_raw_parts(0x10100000 as *const u8, 230321) }; //let clm = unsafe { core::slice::from_raw_parts(0x10140000 as *const u8, 4752) }; From ccd635f0dc5d9a21f7cec87e18368d70482b93ca Mon Sep 17 00:00:00 2001 From: Dinu Blanovschi Date: Tue, 22 Oct 2024 15:43:28 +0200 Subject: [PATCH 0264/1217] fix + allow both conditions on the irq and the handlers --- embassy-stm32/src/lib.rs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 3ff9dcb7e..2ce18c3c0 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -165,22 +165,31 @@ pub use crate::_generated::interrupt; // developer note: this macro can't be in `embassy-hal-internal` due to the use of `$crate`. #[macro_export] macro_rules! bind_interrupts { - ($vis:vis struct $name:ident { $($(#[cfg($cond:meta)])? $irq:ident => $($handler:ty),*;)* }) => { + ($vis:vis struct $name:ident { + $( + $(#[cfg($cond_irq:meta)])? + $irq:ident => $( + $(#[cfg($cond_handler:meta)])? + $handler:ty + ),*; + )* + }) => { #[derive(Copy, Clone)] $vis struct $name; $( #[allow(non_snake_case)] #[no_mangle] + $(#[cfg($cond_irq)])? unsafe extern "C" fn $irq() { $( - $(#[cfg($cond)])? + $(#[cfg($cond_handler)])? <$handler as $crate::interrupt::typelevel::Handler<$crate::interrupt::typelevel::$irq>>::on_interrupt(); )* } $( - $(#[cfg($cond)])? + $(#[cfg(all($cond_irq, $cond_handler))])? unsafe impl $crate::interrupt::typelevel::Binding<$crate::interrupt::typelevel::$irq, $handler> for $name {} )* )* From 82a438a0379b70b6df4bb72750267fa51ed787ab Mon Sep 17 00:00:00 2001 From: Dinu Blanovschi Date: Tue, 22 Oct 2024 15:51:05 +0200 Subject: [PATCH 0265/1217] fix --- embassy-stm32/src/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 2ce18c3c0..c59174988 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -189,7 +189,8 @@ macro_rules! bind_interrupts { } $( - $(#[cfg(all($cond_irq, $cond_handler))])? + $(#[cfg($cond_irq)])? + $(#[cfg($cond_handler)])? unsafe impl $crate::interrupt::typelevel::Binding<$crate::interrupt::typelevel::$irq, $handler> for $name {} )* )* From 5c23c789ee2776ea022957b82480dad6d0d0f660 Mon Sep 17 00:00:00 2001 From: Dinu Blanovschi Date: Tue, 22 Oct 2024 16:23:17 +0200 Subject: [PATCH 0266/1217] fix --- embassy-stm32/src/lib.rs | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index c59174988..de68c54dc 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -188,13 +188,30 @@ macro_rules! bind_interrupts { )* } - $( - $(#[cfg($cond_irq)])? + $crate::bind_interrupts!(@__generate_impls $name $(#[cfg($cond_irq)])? $irq => $( $(#[cfg($cond_handler)])? - unsafe impl $crate::interrupt::typelevel::Binding<$crate::interrupt::typelevel::$irq, $handler> for $name {} - )* + $handler; + )*); )* }; + + (@__generate_single_impl $name:ident $(#[cfg($cond_irq:meta)])? $irq:ident => $(#[cfg($cond_handler:meta)])? $handler:ty;) => { + #[cfg(all( + $($cond_irq,)? + $($cond_handler,)? + ))] + unsafe impl $crate::interrupt::typelevel::Binding<$crate::interrupt::typelevel::$irq, $handler> for $name {} + }; + + (@__generate_impls $name:ident $(#[cfg($cond_irq:meta)])? $irq:ident => $(#[cfg($cond_handler:meta)])? $handler:ty;) => { + $crate::bind_interrupts!(@__generate_single_impl $name $(#[cfg($cond_irq)])? $irq => $(#[cfg($cond_handler)])? $handler;); + }; + + (@__generate_impls $name:ident $(#[cfg($cond_irq:meta)])? $irq:ident => $(#[cfg($cond_handler:meta)])? $handler:ty; $(tail:tt)*) => { + $crate::bind_interrupts!(@__generate_single_impl $name $(#[cfg($cond_irq)])? $irq => $(#[cfg($cond_handler)])? $handler;); + + $crate::bind_interrupts!(@__generate_impls $name $(#[cfg($cond_irq)])? $irq => $(tail)*); + }; } // Reexports From e9f2e63796989c4e248418e341a442e0eff5946d Mon Sep 17 00:00:00 2001 From: Dinu Blanovschi Date: Tue, 22 Oct 2024 16:50:10 +0200 Subject: [PATCH 0267/1217] fix --- embassy-stm32/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index de68c54dc..4154a7275 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -207,10 +207,10 @@ macro_rules! bind_interrupts { $crate::bind_interrupts!(@__generate_single_impl $name $(#[cfg($cond_irq)])? $irq => $(#[cfg($cond_handler)])? $handler;); }; - (@__generate_impls $name:ident $(#[cfg($cond_irq:meta)])? $irq:ident => $(#[cfg($cond_handler:meta)])? $handler:ty; $(tail:tt)*) => { + (@__generate_impls $name:ident $(#[cfg($cond_irq:meta)])? $irq:ident => $(#[cfg($cond_handler:meta)])? $handler:ty; $($(#[cfg($cond_rest:meta)])? $handler_rest:ty;)+) => { $crate::bind_interrupts!(@__generate_single_impl $name $(#[cfg($cond_irq)])? $irq => $(#[cfg($cond_handler)])? $handler;); - $crate::bind_interrupts!(@__generate_impls $name $(#[cfg($cond_irq)])? $irq => $(tail)*); + $crate::bind_interrupts!(@__generate_impls $name $(#[cfg($cond_irq)])? $irq => $($(#[cfg($cond_rest)])? $handler_rest;)+); }; } From c79791552563746e9f62e3d2647d787d3947c249 Mon Sep 17 00:00:00 2001 From: Dinu Blanovschi Date: Tue, 22 Oct 2024 16:56:05 +0200 Subject: [PATCH 0268/1217] fix: review comments --- embassy-nrf/src/lib.rs | 19 ++++++++++++++----- embassy-rp/src/lib.rs | 19 ++++++++++++++----- embassy-stm32/src/lib.rs | 26 +++----------------------- 3 files changed, 31 insertions(+), 33 deletions(-) diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index 13623dd1c..bd53664a2 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs @@ -177,22 +177,31 @@ mod chip; // developer note: this macro can't be in `embassy-hal-internal` due to the use of `$crate`. #[macro_export] macro_rules! bind_interrupts { - ($vis:vis struct $name:ident { $($irq:ident => $($handler:ty),*;)* }) => { + ($vis:vis struct $name:ident { + $( + $(#[cfg($cond_irq:meta)])? + $irq:ident => $( + $(#[cfg($cond_handler:meta)])? + $handler:ty + ),*; + )* + }) => { #[derive(Copy, Clone)] $vis struct $name; $( #[allow(non_snake_case)] #[no_mangle] + $(#[cfg($cond_irq)])? unsafe extern "C" fn $irq() { $( + $(#[cfg($cond_handler)])? <$handler as $crate::interrupt::typelevel::Handler<$crate::interrupt::typelevel::$irq>>::on_interrupt(); + + $(#[cfg($cond_handler)])? + unsafe impl $crate::interrupt::typelevel::Binding<$crate::interrupt::typelevel::$irq, $handler> for $name {} )* } - - $( - unsafe impl $crate::interrupt::typelevel::Binding<$crate::interrupt::typelevel::$irq, $handler> for $name {} - )* )* }; } diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs index d402cf793..a72cebdd8 100644 --- a/embassy-rp/src/lib.rs +++ b/embassy-rp/src/lib.rs @@ -165,22 +165,31 @@ embassy_hal_internal::interrupt_mod!( // developer note: this macro can't be in `embassy-hal-internal` due to the use of `$crate`. #[macro_export] macro_rules! bind_interrupts { - ($vis:vis struct $name:ident { $($irq:ident => $($handler:ty),*;)* }) => { + ($vis:vis struct $name:ident { + $( + $(#[cfg($cond_irq:meta)])? + $irq:ident => $( + $(#[cfg($cond_handler:meta)])? + $handler:ty + ),*; + )* + }) => { #[derive(Copy, Clone)] $vis struct $name; $( #[allow(non_snake_case)] #[no_mangle] + $(#[cfg($cond_irq)])? unsafe extern "C" fn $irq() { $( + $(#[cfg($cond_handler)])? <$handler as $crate::interrupt::typelevel::Handler<$crate::interrupt::typelevel::$irq>>::on_interrupt(); + + $(#[cfg($cond_handler)])? + unsafe impl $crate::interrupt::typelevel::Binding<$crate::interrupt::typelevel::$irq, $handler> for $name {} )* } - - $( - unsafe impl $crate::interrupt::typelevel::Binding<$crate::interrupt::typelevel::$irq, $handler> for $name {} - )* )* }; } diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 4154a7275..65f02d62a 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -185,33 +185,13 @@ macro_rules! bind_interrupts { $( $(#[cfg($cond_handler)])? <$handler as $crate::interrupt::typelevel::Handler<$crate::interrupt::typelevel::$irq>>::on_interrupt(); + + $(#[cfg($cond_handler)])? + unsafe impl $crate::interrupt::typelevel::Binding<$crate::interrupt::typelevel::$irq, $handler> for $name {} )* } - - $crate::bind_interrupts!(@__generate_impls $name $(#[cfg($cond_irq)])? $irq => $( - $(#[cfg($cond_handler)])? - $handler; - )*); )* }; - - (@__generate_single_impl $name:ident $(#[cfg($cond_irq:meta)])? $irq:ident => $(#[cfg($cond_handler:meta)])? $handler:ty;) => { - #[cfg(all( - $($cond_irq,)? - $($cond_handler,)? - ))] - unsafe impl $crate::interrupt::typelevel::Binding<$crate::interrupt::typelevel::$irq, $handler> for $name {} - }; - - (@__generate_impls $name:ident $(#[cfg($cond_irq:meta)])? $irq:ident => $(#[cfg($cond_handler:meta)])? $handler:ty;) => { - $crate::bind_interrupts!(@__generate_single_impl $name $(#[cfg($cond_irq)])? $irq => $(#[cfg($cond_handler)])? $handler;); - }; - - (@__generate_impls $name:ident $(#[cfg($cond_irq:meta)])? $irq:ident => $(#[cfg($cond_handler:meta)])? $handler:ty; $($(#[cfg($cond_rest:meta)])? $handler_rest:ty;)+) => { - $crate::bind_interrupts!(@__generate_single_impl $name $(#[cfg($cond_irq)])? $irq => $(#[cfg($cond_handler)])? $handler;); - - $crate::bind_interrupts!(@__generate_impls $name $(#[cfg($cond_irq)])? $irq => $($(#[cfg($cond_rest)])? $handler_rest;)+); - }; } // Reexports From e5bc2666547d0320635fede91c76d936c56a1a90 Mon Sep 17 00:00:00 2001 From: Haobo Gu Date: Wed, 23 Oct 2024 12:54:50 +0800 Subject: [PATCH 0269/1217] feat: set ospi memory mapped mode Signed-off-by: Haobo Gu --- embassy-stm32/src/ospi/mod.rs | 37 +++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/embassy-stm32/src/ospi/mod.rs b/embassy-stm32/src/ospi/mod.rs index e4adc4b09..0574f7816 100644 --- a/embassy-stm32/src/ospi/mod.rs +++ b/embassy-stm32/src/ospi/mod.rs @@ -179,6 +179,43 @@ pub struct Ospi<'d, T: Instance, M: PeriMode> { } impl<'d, T: Instance, M: PeriMode> Ospi<'d, T, M> { + pub fn enable_memory_mapped_mode(&mut self) { + let reg = T::REGS; + while reg.sr().read().busy() { + info!("wait ospi busy"); + } + + reg.ccr().modify(|r| { + r.set_isize(crate::ospi::vals::SizeInBits::_8BIT); + r.set_adsize(crate::ospi::vals::SizeInBits::_24BIT); + r.set_admode(crate::ospi::vals::PhaseMode::ONELINE); + r.set_imode(crate::ospi::vals::PhaseMode::ONELINE); + r.set_dmode(crate::ospi::vals::PhaseMode::FOURLINES); + }); + + reg.cr().modify(|r| { + r.set_fmode(crate::ospi::vals::FunctionalMode::MEMORYMAPPED); + r.set_dmaen(false); + r.set_en(true); + }); + + // reg.tcr().modify(|r| { + // r.set_dcyc(6); + // }); + + } + pub fn disable_memory_mapped_mode(&mut self) { + let reg = T::REGS; + while reg.sr().read().busy() { + info!("wait ospi busy"); + } + reg.cr().modify(|r| { + r.set_fmode(crate::ospi::vals::FunctionalMode::INDIRECTWRITE); + r.set_dmaen(false); + r.set_en(true); + }); + } + fn new_inner( peri: impl Peripheral

+ 'd, d0: Option>, From be50b62677f04f0d30727a9168b435b90584f06c Mon Sep 17 00:00:00 2001 From: dvdsk Date: Wed, 23 Oct 2024 21:06:58 +0200 Subject: [PATCH 0270/1217] stm32/uart impl ReadReady for RingbufferdUart --- embassy-stm32/src/usart/mod.rs | 3 +++ embassy-stm32/src/usart/ringbuffered.rs | 11 +++++++++++ 2 files changed, 14 insertions(+) diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index 333e01e36..86c94789a 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -260,6 +260,8 @@ pub enum Error { Parity, /// Buffer too large for DMA BufferTooLong, + // TODO: ask what this is and document it (dvdsk) + DmaUnsynced, } enum ReadCompletionEvent { @@ -1689,6 +1691,7 @@ impl embedded_hal_nb::serial::Error for Error { Self::Overrun => embedded_hal_nb::serial::ErrorKind::Overrun, Self::Parity => embedded_hal_nb::serial::ErrorKind::Parity, Self::BufferTooLong => embedded_hal_nb::serial::ErrorKind::Other, + Self::DmaUnsynced => embedded_hal_nb::serial::ErrorKind::Other, } } } diff --git a/embassy-stm32/src/usart/ringbuffered.rs b/embassy-stm32/src/usart/ringbuffered.rs index eb2399d9c..f1914e1bf 100644 --- a/embassy-stm32/src/usart/ringbuffered.rs +++ b/embassy-stm32/src/usart/ringbuffered.rs @@ -5,6 +5,7 @@ use core::task::Poll; use embassy_embedded_hal::SetConfig; use embassy_hal_internal::PeripheralRef; +use embedded_io_async::ReadReady; use futures_util::future::{select, Either}; use super::{clear_interrupt_flags, rdr, reconfigure, sr, Config, ConfigError, Error, Info, State, UartRx}; @@ -262,3 +263,13 @@ impl embedded_io_async::Read for RingBufferedUartRx<'_> { self.read(buf).await } } + +impl ReadReady for RingBufferedUartRx<'_> { + fn read_ready(&mut self) -> Result { + let len = self.ring_buf.len().map_err(|e| match e { + crate::dma::ringbuffer::Error::Overrun => Self::Error::Overrun, + crate::dma::ringbuffer::Error::DmaUnsynced => Self::Error::DmaUnsynced, + })?; + Ok(len > 0) + } +} From 528a3e43550b5d2ce4a5f44d890feaa3e56c113a Mon Sep 17 00:00:00 2001 From: Alex Moon Date: Wed, 14 Aug 2024 17:07:57 -0400 Subject: [PATCH 0271/1217] Add support for transactions to Twim in embassy-nrf --- embassy-nrf/src/twim.rs | 653 ++++++++++++++++++++++++---------------- 1 file changed, 393 insertions(+), 260 deletions(-) diff --git a/embassy-nrf/src/twim.rs b/embassy-nrf/src/twim.rs index c64743ecc..d0518807c 100644 --- a/embassy-nrf/src/twim.rs +++ b/embassy-nrf/src/twim.rs @@ -4,6 +4,7 @@ use core::future::{poll_fn, Future}; use core::marker::PhantomData; +use core::mem::MaybeUninit; use core::sync::atomic::compiler_fence; use core::sync::atomic::Ordering::SeqCst; use core::task::Poll; @@ -13,11 +14,12 @@ use embassy_hal_internal::{into_ref, PeripheralRef}; use embassy_sync::waitqueue::AtomicWaker; #[cfg(feature = "time")] use embassy_time::{Duration, Instant}; +use embedded_hal_1::i2c::Operation; use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE}; use crate::gpio::Pin as GpioPin; use crate::interrupt::typelevel::Interrupt; -use crate::util::{slice_in_ram, slice_in_ram_or}; +use crate::util::slice_in_ram; use crate::{gpio, interrupt, pac, Peripheral}; /// TWI frequency @@ -103,6 +105,18 @@ impl interrupt::typelevel::Handler for InterruptHandl let r = T::regs(); let s = T::state(); + // Workaround for lack of LASTRX_SUSPEND short in some nRF chips + // Do this first to minimize latency + #[cfg(any(feature = "nrf52832", feature = "_nrf5340", feature = "_nrf9120"))] + if r.events_lastrx.read().bits() != 0 { + r.tasks_suspend.write(|w| unsafe { w.bits(1) }); + r.events_lastrx.reset(); + } + + if r.events_suspended.read().bits() != 0 { + s.end_waker.wake(); + r.intenclr.write(|w| w.suspended().clear()); + } if r.events_stopped.read().bits() != 0 { s.end_waker.wake(); r.intenclr.write(|w| w.stopped().clear()); @@ -182,8 +196,22 @@ impl<'d, T: Instance> Twim<'d, T> { } /// Set TX buffer, checking that it is in RAM and has suitable length. - unsafe fn set_tx_buffer(&mut self, buffer: &[u8]) -> Result<(), Error> { - slice_in_ram_or(buffer, Error::BufferNotInRAM)?; + unsafe fn set_tx_buffer( + &mut self, + buffer: &[u8], + ram_buffer: Option<&mut [MaybeUninit; FORCE_COPY_BUFFER_SIZE]>, + ) -> Result<(), Error> { + let buffer = if slice_in_ram(buffer) { + buffer + } else { + let ram_buffer = ram_buffer.ok_or(Error::BufferNotInRAM)?; + trace!("Copying TWIM tx buffer into RAM for DMA"); + let ram_buffer = &mut ram_buffer[..buffer.len()]; + // Inline implementation of the nightly API MaybeUninit::copy_from_slice(ram_buffer, buffer) + let uninit_src: &[MaybeUninit] = unsafe { core::mem::transmute(buffer) }; + ram_buffer.copy_from_slice(uninit_src); + unsafe { &*(ram_buffer as *const [MaybeUninit] as *const [u8]) } + }; if buffer.len() > EASY_DMA_SIZE { return Err(Error::TxBufferTooLong); @@ -290,7 +318,7 @@ impl<'d, T: Instance> Twim<'d, T> { fn blocking_wait(&mut self) { let r = T::regs(); loop { - if r.events_stopped.read().bits() != 0 { + if r.events_suspended.read().bits() != 0 || r.events_stopped.read().bits() != 0 { r.events_stopped.reset(); break; } @@ -307,7 +335,7 @@ impl<'d, T: Instance> Twim<'d, T> { let r = T::regs(); let deadline = Instant::now() + timeout; loop { - if r.events_stopped.read().bits() != 0 { + if r.events_suspended.read().bits() != 0 || r.events_stopped.read().bits() != 0 { r.events_stopped.reset(); break; } @@ -331,7 +359,7 @@ impl<'d, T: Instance> Twim<'d, T> { let s = T::state(); s.end_waker.register(cx.waker()); - if r.events_stopped.read().bits() != 0 { + if r.events_suspended.read().bits() != 0 || r.events_stopped.read().bits() != 0 { r.events_stopped.reset(); return Poll::Ready(()); @@ -347,75 +375,13 @@ impl<'d, T: Instance> Twim<'d, T> { }) } - fn setup_write_from_ram(&mut self, address: u8, buffer: &[u8], inten: bool) -> Result<(), Error> { - let r = T::regs(); - - compiler_fence(SeqCst); - - r.address.write(|w| unsafe { w.address().bits(address) }); - - // Set up the DMA write. - unsafe { self.set_tx_buffer(buffer)? }; - - // Clear events - r.events_stopped.reset(); - r.events_error.reset(); - r.events_lasttx.reset(); - self.clear_errorsrc(); - - if inten { - r.intenset.write(|w| w.stopped().set().error().set()); - } else { - r.intenclr.write(|w| w.stopped().clear().error().clear()); - } - - // Start write operation. - r.shorts.write(|w| w.lasttx_stop().enabled()); - r.tasks_starttx.write(|w| unsafe { w.bits(1) }); - if buffer.is_empty() { - // With a zero-length buffer, LASTTX doesn't fire (because there's no last byte!), so do the STOP ourselves. - r.tasks_stop.write(|w| unsafe { w.bits(1) }); - } - Ok(()) - } - - fn setup_read(&mut self, address: u8, buffer: &mut [u8], inten: bool) -> Result<(), Error> { - let r = T::regs(); - - compiler_fence(SeqCst); - - r.address.write(|w| unsafe { w.address().bits(address) }); - - // Set up the DMA read. - unsafe { self.set_rx_buffer(buffer)? }; - - // Clear events - r.events_stopped.reset(); - r.events_error.reset(); - self.clear_errorsrc(); - - if inten { - r.intenset.write(|w| w.stopped().set().error().set()); - } else { - r.intenclr.write(|w| w.stopped().clear().error().clear()); - } - - // Start read operation. - r.shorts.write(|w| w.lastrx_stop().enabled()); - r.tasks_startrx.write(|w| unsafe { w.bits(1) }); - if buffer.is_empty() { - // With a zero-length buffer, LASTRX doesn't fire (because there's no last byte!), so do the STOP ourselves. - r.tasks_stop.write(|w| unsafe { w.bits(1) }); - } - Ok(()) - } - - fn setup_write_read_from_ram( + fn setup_operations( &mut self, address: u8, - wr_buffer: &[u8], - rd_buffer: &mut [u8], + operations: &mut [Operation<'_>], + tx_ram_buffer: Option<&mut [MaybeUninit; FORCE_COPY_BUFFER_SIZE]>, inten: bool, + stop: bool, ) -> Result<(), Error> { let r = T::regs(); @@ -423,92 +389,343 @@ impl<'d, T: Instance> Twim<'d, T> { r.address.write(|w| unsafe { w.address().bits(address) }); - // Set up DMA buffers. - unsafe { - self.set_tx_buffer(wr_buffer)?; - self.set_rx_buffer(rd_buffer)?; - } - - // Clear events + let was_suspended = r.events_suspended.read().bits() != 0; + r.events_suspended.reset(); r.events_stopped.reset(); r.events_error.reset(); self.clear_errorsrc(); if inten { - r.intenset.write(|w| w.stopped().set().error().set()); + r.intenset.write(|w| w.suspended().set().stopped().set().error().set()); } else { - r.intenclr.write(|w| w.stopped().clear().error().clear()); + r.intenclr + .write(|w| w.suspended().clear().stopped().clear().error().clear()); } + #[cfg(any(feature = "nrf52832", feature = "_nrf5340", feature = "_nrf9120"))] + r.intenclr.write(|w| w.lastrx().clear()); - // Start write+read operation. - r.shorts.write(|w| { - w.lasttx_startrx().enabled(); - w.lastrx_stop().enabled(); - w - }); - r.tasks_starttx.write(|w| unsafe { w.bits(1) }); - if wr_buffer.is_empty() && rd_buffer.is_empty() { - // With a zero-length buffer, LASTRX/LASTTX doesn't fire (because there's no last byte!), so do the STOP ourselves. - // TODO handle when only one of the buffers is zero length - r.tasks_stop.write(|w| unsafe { w.bits(1) }); + match operations { + [Operation::Read(rd_buffer), Operation::Write(wr_buffer), rest @ ..] + if !rd_buffer.is_empty() && !wr_buffer.is_empty() => + { + let stop = stop && rest.is_empty(); + + // Set up DMA buffers. + unsafe { + self.set_tx_buffer(wr_buffer, tx_ram_buffer)?; + self.set_rx_buffer(rd_buffer)?; + } + + r.shorts.write(|w| { + w.lastrx_starttx().enabled(); + if stop { + w.lasttx_stop().enabled(); + } else { + w.lasttx_suspend().enabled(); + } + w + }); + + // Start read+write operation. + r.tasks_startrx.write(|w| unsafe { w.bits(1) }); + + if was_suspended { + r.tasks_resume.write(|w| unsafe { w.bits(1) }); + } + } + [Operation::Write(wr_buffer), Operation::Read(rd_buffer), rest @ ..] + if !wr_buffer.is_empty() && !rd_buffer.is_empty() => + { + let stop = stop && rest.is_empty(); + + // Set up DMA buffers. + unsafe { + self.set_tx_buffer(wr_buffer, tx_ram_buffer)?; + self.set_rx_buffer(rd_buffer)?; + } + + // Start write+read operation. + r.shorts.write(|w| { + w.lasttx_startrx().enabled(); + if stop { + w.lastrx_stop().enabled(); + } else { + #[cfg(not(any(feature = "nrf52832", feature = "_nrf5340", feature = "_nrf9120")))] + w.lastrx_suspend().enabled(); + } + w + }); + #[cfg(any(feature = "nrf52832", feature = "_nrf5340", feature = "_nrf9120"))] + if !stop { + r.intenset.write(|w| w.lastrx().set()); + } + + r.tasks_starttx.write(|w| unsafe { w.bits(1) }); + + if was_suspended { + r.tasks_resume.write(|w| unsafe { w.bits(1) }); + } + } + [Operation::Read(buffer), rest @ ..] => { + let stop = stop && rest.is_empty(); + + // Set up DMA buffers. + unsafe { + self.set_rx_buffer(buffer)?; + } + + // Start read operation. + r.shorts.write(|w| { + if stop { + w.lastrx_stop().enabled(); + } else { + #[cfg(not(any(feature = "nrf52832", feature = "_nrf5340", feature = "_nrf9120")))] + w.lastrx_suspend().enabled(); + } + w + }); + #[cfg(any(feature = "nrf52832", feature = "_nrf5340", feature = "_nrf9120"))] + if !stop { + r.intenset.write(|w| w.lastrx().set()); + } + + r.tasks_startrx.write(|w| unsafe { w.bits(1) }); + + if was_suspended { + r.tasks_resume.write(|w| unsafe { w.bits(1) }); + } + + if buffer.is_empty() { + // With a zero-length buffer, LASTRX doesn't fire (because there's no last byte!), so do the STOP/SUSPEND ourselves. + if stop { + r.tasks_stop.write(|w| unsafe { w.bits(1) }); + } else { + r.tasks_suspend.write(|w| unsafe { w.bits(1) }); + } + } + } + [Operation::Write(buffer), rest @ ..] => { + let stop = stop && rest.is_empty(); + + // Set up DMA buffers. + unsafe { + self.set_tx_buffer(buffer, tx_ram_buffer)?; + } + + // Start write operation. + r.shorts.write(|w| { + if stop { + w.lasttx_stop().enabled(); + } else { + w.lasttx_suspend().enabled(); + } + w + }); + + r.tasks_starttx.write(|w| unsafe { w.bits(1) }); + + if was_suspended { + r.tasks_resume.write(|w| unsafe { w.bits(1) }); + } + + if buffer.is_empty() { + // With a zero-length buffer, LASTTX doesn't fire (because there's no last byte!), so do the STOP/SUSPEND ourselves. + if stop { + r.tasks_stop.write(|w| unsafe { w.bits(1) }); + } else { + r.tasks_suspend.write(|w| unsafe { w.bits(1) }); + } + } + } + [] => { + if stop { + if was_suspended { + r.tasks_resume.write(|w| unsafe { w.bits(1) }); + } + + r.tasks_stop.write(|w| unsafe { w.bits(1) }); + } + } } Ok(()) } - fn setup_write_read( - &mut self, - address: u8, - wr_buffer: &[u8], - rd_buffer: &mut [u8], - inten: bool, - ) -> Result<(), Error> { - match self.setup_write_read_from_ram(address, wr_buffer, rd_buffer, inten) { - Ok(_) => Ok(()), - Err(Error::BufferNotInRAM) => { - trace!("Copying TWIM tx buffer into RAM for DMA"); - let tx_ram_buf = &mut [0; FORCE_COPY_BUFFER_SIZE][..wr_buffer.len()]; - tx_ram_buf.copy_from_slice(wr_buffer); - self.setup_write_read_from_ram(address, tx_ram_buf, rd_buffer, inten) + fn check_operations(&mut self, operations: &mut [Operation<'_>]) -> Result { + compiler_fence(SeqCst); + self.check_errorsrc()?; + + match operations { + [Operation::Read(rd_buffer), Operation::Write(wr_buffer), ..] + | [Operation::Write(wr_buffer), Operation::Read(rd_buffer), ..] + if !rd_buffer.is_empty() && !wr_buffer.is_empty() => + { + self.check_tx(wr_buffer.len())?; + self.check_rx(rd_buffer.len())?; + Ok(2) } - Err(error) => Err(error), + [Operation::Read(buffer), ..] => { + self.check_rx(buffer.len())?; + Ok(1) + } + [Operation::Write(buffer), ..] => { + self.check_tx(buffer.len())?; + Ok(1) + } + [] => Ok(0), } } - fn setup_write(&mut self, address: u8, wr_buffer: &[u8], inten: bool) -> Result<(), Error> { - match self.setup_write_from_ram(address, wr_buffer, inten) { - Ok(_) => Ok(()), - Err(Error::BufferNotInRAM) => { - trace!("Copying TWIM tx buffer into RAM for DMA"); - let tx_ram_buf = &mut [0; FORCE_COPY_BUFFER_SIZE][..wr_buffer.len()]; - tx_ram_buf.copy_from_slice(wr_buffer); - self.setup_write_from_ram(address, tx_ram_buf, inten) - } - Err(error) => Err(error), + // =========================================== + + /// Execute the provided operations on the I2C bus. + /// + /// Each buffer must have a length of at most 255 bytes on the nRF52832 + /// and at most 65535 bytes on the nRF52840. + /// + /// If `stop` is set, the transaction will be terminated with a STOP + /// condition and the Twim will be stopped. Otherwise, the bus will be + /// left busy via clock stretching and Twim will be suspended. + /// + /// The nrf52832, nrf5340, and nrf9120 do not have hardware support for + /// suspending following a read operation therefore it is emulated by the + /// interrupt handler. If the latency of servicing that interrupt is + /// longer than a byte worth of clocks on the bus, the SCL clock will + /// continue to run for one or more additional bytes. This applies to + /// consecutive read operations, certain write-read-write sequences, or + /// any sequence of operations ending in a read when `stop == false`. + pub fn blocking_transaction( + &mut self, + address: u8, + mut operations: &mut [Operation<'_>], + stop: bool, + ) -> Result<(), Error> { + let mut tx_ram_buffer = [MaybeUninit::uninit(); FORCE_COPY_BUFFER_SIZE]; + while !operations.is_empty() { + self.setup_operations(address, operations, Some(&mut tx_ram_buffer), false, stop)?; + self.blocking_wait(); + let consumed = self.check_operations(operations)?; + operations = &mut operations[consumed..]; } + Ok(()) } + /// Same as [`blocking_transaction`](Twim::blocking_transaction) but will fail instead of copying data into RAM. Consult the module level documentation to learn more. + pub fn blocking_transaction_from_ram( + &mut self, + address: u8, + mut operations: &mut [Operation<'_>], + stop: bool, + ) -> Result<(), Error> { + while !operations.is_empty() { + self.setup_operations(address, operations, None, false, stop)?; + self.blocking_wait(); + let consumed = self.check_operations(operations)?; + operations = &mut operations[consumed..]; + } + Ok(()) + } + + /// Execute the provided operations on the I2C bus with timeout. + /// + /// See [`blocking_transaction`]. + #[cfg(feature = "time")] + pub fn blocking_transaction_timeout( + &mut self, + address: u8, + mut operations: &mut [Operation<'_>], + stop: bool, + timeout: Duration, + ) -> Result<(), Error> { + let mut tx_ram_buffer = [MaybeUninit::uninit(); FORCE_COPY_BUFFER_SIZE]; + while !operations.is_empty() { + self.setup_operations(address, operations, Some(&mut tx_ram_buffer), false, stop)?; + self.blocking_wait_timeout(timeout)?; + let consumed = self.check_operations(operations)?; + operations = &mut operations[consumed..]; + } + Ok(()) + } + + /// Same as [`blocking_transaction_timeout`](Twim::blocking_transaction_timeout) but will fail instead of copying data into RAM. Consult the module level documentation to learn more. + #[cfg(feature = "time")] + pub fn blocking_transaction_from_ram_timeout( + &mut self, + address: u8, + mut operations: &mut [Operation<'_>], + stop: bool, + timeout: Duration, + ) -> Result<(), Error> { + while !operations.is_empty() { + self.setup_operations(address, operations, None, false, stop)?; + self.blocking_wait_timeout(timeout)?; + let consumed = self.check_operations(operations)?; + operations = &mut operations[consumed..]; + } + Ok(()) + } + + /// Execute the provided operations on the I2C bus. + /// + /// Each buffer must have a length of at most 255 bytes on the nRF52832 + /// and at most 65535 bytes on the nRF52840. + /// + /// If `stop` is set, the transaction will be terminated with a STOP + /// condition and the Twim will be stopped. Otherwise, the bus will be + /// left busy via clock stretching and Twim will be suspended. + /// + /// The nrf52832, nrf5340, and nrf9120 do not have hardware support for + /// suspending following a read operation therefore it is emulated by the + /// interrupt handler. If the latency of servicing that interrupt is + /// longer than a byte worth of clocks on the bus, the SCL clock will + /// continue to run for one or more additional bytes. This applies to + /// consecutive read operations, certain write-read-write sequences, or + /// any sequence of operations ending in a read when `stop == false`. + pub async fn transaction( + &mut self, + address: u8, + mut operations: &mut [Operation<'_>], + stop: bool, + ) -> Result<(), Error> { + let mut tx_ram_buffer = [MaybeUninit::uninit(); FORCE_COPY_BUFFER_SIZE]; + while !operations.is_empty() { + self.setup_operations(address, operations, Some(&mut tx_ram_buffer), true, stop)?; + self.async_wait().await; + let consumed = self.check_operations(operations)?; + operations = &mut operations[consumed..]; + } + Ok(()) + } + + /// Same as [`transaction`](Twim::transaction) but will fail instead of copying data into RAM. Consult the module level documentation to learn more. + pub async fn transaction_from_ram( + &mut self, + address: u8, + mut operations: &mut [Operation<'_>], + stop: bool, + ) -> Result<(), Error> { + while !operations.is_empty() { + self.setup_operations(address, operations, None, true, stop)?; + self.async_wait().await; + let consumed = self.check_operations(operations)?; + operations = &mut operations[consumed..]; + } + Ok(()) + } + + // =========================================== + /// Write to an I2C slave. /// /// The buffer must have a length of at most 255 bytes on the nRF52832 /// and at most 65535 bytes on the nRF52840. pub fn blocking_write(&mut self, address: u8, buffer: &[u8]) -> Result<(), Error> { - self.setup_write(address, buffer, false)?; - self.blocking_wait(); - compiler_fence(SeqCst); - self.check_errorsrc()?; - self.check_tx(buffer.len())?; - Ok(()) + self.blocking_transaction(address, &mut [Operation::Write(buffer)], true) } /// Same as [`blocking_write`](Twim::blocking_write) but will fail instead of copying data into RAM. Consult the module level documentation to learn more. pub fn blocking_write_from_ram(&mut self, address: u8, buffer: &[u8]) -> Result<(), Error> { - self.setup_write_from_ram(address, buffer, false)?; - self.blocking_wait(); - compiler_fence(SeqCst); - self.check_errorsrc()?; - self.check_tx(buffer.len())?; - Ok(()) + self.blocking_transaction_from_ram(address, &mut [Operation::Write(buffer)], true) } /// Read from an I2C slave. @@ -516,12 +733,7 @@ impl<'d, T: Instance> Twim<'d, T> { /// The buffer must have a length of at most 255 bytes on the nRF52832 /// and at most 65535 bytes on the nRF52840. pub fn blocking_read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> { - self.setup_read(address, buffer, false)?; - self.blocking_wait(); - compiler_fence(SeqCst); - self.check_errorsrc()?; - self.check_rx(buffer.len())?; - Ok(()) + self.blocking_transaction(address, &mut [Operation::Read(buffer)], true) } /// Write data to an I2C slave, then read data from the slave without @@ -530,13 +742,11 @@ impl<'d, T: Instance> Twim<'d, T> { /// The buffers must have a length of at most 255 bytes on the nRF52832 /// and at most 65535 bytes on the nRF52840. pub fn blocking_write_read(&mut self, address: u8, wr_buffer: &[u8], rd_buffer: &mut [u8]) -> Result<(), Error> { - self.setup_write_read(address, wr_buffer, rd_buffer, false)?; - self.blocking_wait(); - compiler_fence(SeqCst); - self.check_errorsrc()?; - self.check_tx(wr_buffer.len())?; - self.check_rx(rd_buffer.len())?; - Ok(()) + self.blocking_transaction( + address, + &mut [Operation::Write(wr_buffer), Operation::Read(rd_buffer)], + true, + ) } /// Same as [`blocking_write_read`](Twim::blocking_write_read) but will fail instead of copying data into RAM. Consult the module level documentation to learn more. @@ -546,13 +756,11 @@ impl<'d, T: Instance> Twim<'d, T> { wr_buffer: &[u8], rd_buffer: &mut [u8], ) -> Result<(), Error> { - self.setup_write_read_from_ram(address, wr_buffer, rd_buffer, false)?; - self.blocking_wait(); - compiler_fence(SeqCst); - self.check_errorsrc()?; - self.check_tx(wr_buffer.len())?; - self.check_rx(rd_buffer.len())?; - Ok(()) + self.blocking_transaction_from_ram( + address, + &mut [Operation::Write(wr_buffer), Operation::Read(rd_buffer)], + true, + ) } // =========================================== @@ -562,12 +770,7 @@ impl<'d, T: Instance> Twim<'d, T> { /// See [`blocking_write`]. #[cfg(feature = "time")] pub fn blocking_write_timeout(&mut self, address: u8, buffer: &[u8], timeout: Duration) -> Result<(), Error> { - self.setup_write(address, buffer, false)?; - self.blocking_wait_timeout(timeout)?; - compiler_fence(SeqCst); - self.check_errorsrc()?; - self.check_tx(buffer.len())?; - Ok(()) + self.blocking_transaction_timeout(address, &mut [Operation::Write(buffer)], true, timeout) } /// Same as [`blocking_write`](Twim::blocking_write) but will fail instead of copying data into RAM. Consult the module level documentation to learn more. @@ -578,12 +781,7 @@ impl<'d, T: Instance> Twim<'d, T> { buffer: &[u8], timeout: Duration, ) -> Result<(), Error> { - self.setup_write_from_ram(address, buffer, false)?; - self.blocking_wait_timeout(timeout)?; - compiler_fence(SeqCst); - self.check_errorsrc()?; - self.check_tx(buffer.len())?; - Ok(()) + self.blocking_transaction_from_ram_timeout(address, &mut [Operation::Write(buffer)], true, timeout) } /// Read from an I2C slave. @@ -592,12 +790,7 @@ impl<'d, T: Instance> Twim<'d, T> { /// and at most 65535 bytes on the nRF52840. #[cfg(feature = "time")] pub fn blocking_read_timeout(&mut self, address: u8, buffer: &mut [u8], timeout: Duration) -> Result<(), Error> { - self.setup_read(address, buffer, false)?; - self.blocking_wait_timeout(timeout)?; - compiler_fence(SeqCst); - self.check_errorsrc()?; - self.check_rx(buffer.len())?; - Ok(()) + self.blocking_transaction_timeout(address, &mut [Operation::Read(buffer)], true, timeout) } /// Write data to an I2C slave, then read data from the slave without @@ -613,13 +806,12 @@ impl<'d, T: Instance> Twim<'d, T> { rd_buffer: &mut [u8], timeout: Duration, ) -> Result<(), Error> { - self.setup_write_read(address, wr_buffer, rd_buffer, false)?; - self.blocking_wait_timeout(timeout)?; - compiler_fence(SeqCst); - self.check_errorsrc()?; - self.check_tx(wr_buffer.len())?; - self.check_rx(rd_buffer.len())?; - Ok(()) + self.blocking_transaction_timeout( + address, + &mut [Operation::Write(wr_buffer), Operation::Read(rd_buffer)], + true, + timeout, + ) } /// Same as [`blocking_write_read`](Twim::blocking_write_read) but will fail instead of copying data into RAM. Consult the module level documentation to learn more. @@ -631,13 +823,12 @@ impl<'d, T: Instance> Twim<'d, T> { rd_buffer: &mut [u8], timeout: Duration, ) -> Result<(), Error> { - self.setup_write_read_from_ram(address, wr_buffer, rd_buffer, false)?; - self.blocking_wait_timeout(timeout)?; - compiler_fence(SeqCst); - self.check_errorsrc()?; - self.check_tx(wr_buffer.len())?; - self.check_rx(rd_buffer.len())?; - Ok(()) + self.blocking_transaction_from_ram_timeout( + address, + &mut [Operation::Write(wr_buffer), Operation::Read(rd_buffer)], + true, + timeout, + ) } // =========================================== @@ -647,12 +838,7 @@ impl<'d, T: Instance> Twim<'d, T> { /// The buffer must have a length of at most 255 bytes on the nRF52832 /// and at most 65535 bytes on the nRF52840. pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> { - self.setup_read(address, buffer, true)?; - self.async_wait().await; - compiler_fence(SeqCst); - self.check_errorsrc()?; - self.check_rx(buffer.len())?; - Ok(()) + self.transaction(address, &mut [Operation::Read(buffer)], true).await } /// Write to an I2C slave. @@ -660,22 +846,13 @@ impl<'d, T: Instance> Twim<'d, T> { /// The buffer must have a length of at most 255 bytes on the nRF52832 /// and at most 65535 bytes on the nRF52840. pub async fn write(&mut self, address: u8, buffer: &[u8]) -> Result<(), Error> { - self.setup_write(address, buffer, true)?; - self.async_wait().await; - compiler_fence(SeqCst); - self.check_errorsrc()?; - self.check_tx(buffer.len())?; - Ok(()) + self.transaction(address, &mut [Operation::Write(buffer)], true).await } /// Same as [`write`](Twim::write) but will fail instead of copying data into RAM. Consult the module level documentation to learn more. pub async fn write_from_ram(&mut self, address: u8, buffer: &[u8]) -> Result<(), Error> { - self.setup_write_from_ram(address, buffer, true)?; - self.async_wait().await; - compiler_fence(SeqCst); - self.check_errorsrc()?; - self.check_tx(buffer.len())?; - Ok(()) + self.transaction_from_ram(address, &mut [Operation::Write(buffer)], true) + .await } /// Write data to an I2C slave, then read data from the slave without @@ -684,13 +861,12 @@ impl<'d, T: Instance> Twim<'d, T> { /// The buffers must have a length of at most 255 bytes on the nRF52832 /// and at most 65535 bytes on the nRF52840. pub async fn write_read(&mut self, address: u8, wr_buffer: &[u8], rd_buffer: &mut [u8]) -> Result<(), Error> { - self.setup_write_read(address, wr_buffer, rd_buffer, true)?; - self.async_wait().await; - compiler_fence(SeqCst); - self.check_errorsrc()?; - self.check_tx(wr_buffer.len())?; - self.check_rx(rd_buffer.len())?; - Ok(()) + self.transaction( + address, + &mut [Operation::Write(wr_buffer), Operation::Read(rd_buffer)], + true, + ) + .await } /// Same as [`write_read`](Twim::write_read) but will fail instead of copying data into RAM. Consult the module level documentation to learn more. @@ -700,13 +876,12 @@ impl<'d, T: Instance> Twim<'d, T> { wr_buffer: &[u8], rd_buffer: &mut [u8], ) -> Result<(), Error> { - self.setup_write_read_from_ram(address, wr_buffer, rd_buffer, true)?; - self.async_wait().await; - compiler_fence(SeqCst); - self.check_errorsrc()?; - self.check_tx(wr_buffer.len())?; - self.check_rx(rd_buffer.len())?; - Ok(()) + self.transaction_from_ram( + address, + &mut [Operation::Write(wr_buffer), Operation::Read(rd_buffer)], + true, + ) + .await } } @@ -777,16 +952,7 @@ mod eh02 { type Error = Error; fn write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Error> { - if slice_in_ram(bytes) { - self.blocking_write(addr, bytes) - } else { - let buf = &mut [0; FORCE_COPY_BUFFER_SIZE][..]; - for chunk in bytes.chunks(FORCE_COPY_BUFFER_SIZE) { - buf[..chunk.len()].copy_from_slice(chunk); - self.blocking_write(addr, &buf[..chunk.len()])?; - } - Ok(()) - } + self.blocking_write(addr, bytes) } } @@ -832,47 +998,14 @@ impl<'d, T: Instance> embedded_hal_1::i2c::ErrorType for Twim<'d, T> { } impl<'d, T: Instance> embedded_hal_1::i2c::I2c for Twim<'d, T> { - fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> { - self.blocking_read(address, buffer) - } - - fn write(&mut self, address: u8, buffer: &[u8]) -> Result<(), Self::Error> { - self.blocking_write(address, buffer) - } - - fn write_read(&mut self, address: u8, wr_buffer: &[u8], rd_buffer: &mut [u8]) -> Result<(), Self::Error> { - self.blocking_write_read(address, wr_buffer, rd_buffer) - } - - fn transaction( - &mut self, - _address: u8, - _operations: &mut [embedded_hal_1::i2c::Operation<'_>], - ) -> Result<(), Self::Error> { - todo!(); + fn transaction(&mut self, address: u8, operations: &mut [Operation<'_>]) -> Result<(), Self::Error> { + self.blocking_transaction(address, operations, true) } } impl<'d, T: Instance> embedded_hal_async::i2c::I2c for Twim<'d, T> { - async fn read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Self::Error> { - self.read(address, read).await - } - - async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Self::Error> { - self.write(address, write).await - } - async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> { - self.write_read(address, write, read).await - } - - async fn transaction( - &mut self, - address: u8, - operations: &mut [embedded_hal_1::i2c::Operation<'_>], - ) -> Result<(), Self::Error> { - let _ = address; - let _ = operations; - todo!() + async fn transaction(&mut self, address: u8, operations: &mut [Operation<'_>]) -> Result<(), Self::Error> { + self.transaction(address, operations, true).await } } From 110d87bbd2c4e5b60ed99c0a259b8366e5164d41 Mon Sep 17 00:00:00 2001 From: Alex Moon Date: Mon, 19 Aug 2024 16:35:13 -0400 Subject: [PATCH 0272/1217] Remove support for consecutive Read operations Due to Twim hardware limitations --- embassy-nrf/src/twim.rs | 189 ++++++++++++---------------------------- 1 file changed, 57 insertions(+), 132 deletions(-) diff --git a/embassy-nrf/src/twim.rs b/embassy-nrf/src/twim.rs index d0518807c..4a239e8b5 100644 --- a/embassy-nrf/src/twim.rs +++ b/embassy-nrf/src/twim.rs @@ -105,14 +105,6 @@ impl interrupt::typelevel::Handler for InterruptHandl let r = T::regs(); let s = T::state(); - // Workaround for lack of LASTRX_SUSPEND short in some nRF chips - // Do this first to minimize latency - #[cfg(any(feature = "nrf52832", feature = "_nrf5340", feature = "_nrf9120"))] - if r.events_lastrx.read().bits() != 0 { - r.tasks_suspend.write(|w| unsafe { w.bits(1) }); - r.events_lastrx.reset(); - } - if r.events_suspended.read().bits() != 0 { s.end_waker.wake(); r.intenclr.write(|w| w.suspended().clear()); @@ -381,7 +373,6 @@ impl<'d, T: Instance> Twim<'d, T> { operations: &mut [Operation<'_>], tx_ram_buffer: Option<&mut [MaybeUninit; FORCE_COPY_BUFFER_SIZE]>, inten: bool, - stop: bool, ) -> Result<(), Error> { let r = T::regs(); @@ -401,14 +392,12 @@ impl<'d, T: Instance> Twim<'d, T> { r.intenclr .write(|w| w.suspended().clear().stopped().clear().error().clear()); } - #[cfg(any(feature = "nrf52832", feature = "_nrf5340", feature = "_nrf9120"))] - r.intenclr.write(|w| w.lastrx().clear()); match operations { [Operation::Read(rd_buffer), Operation::Write(wr_buffer), rest @ ..] if !rd_buffer.is_empty() && !wr_buffer.is_empty() => { - let stop = stop && rest.is_empty(); + let stop = rest.is_empty(); // Set up DMA buffers. unsafe { @@ -433,11 +422,9 @@ impl<'d, T: Instance> Twim<'d, T> { r.tasks_resume.write(|w| unsafe { w.bits(1) }); } } - [Operation::Write(wr_buffer), Operation::Read(rd_buffer), rest @ ..] + [Operation::Write(wr_buffer), Operation::Read(rd_buffer)] if !wr_buffer.is_empty() && !rd_buffer.is_empty() => { - let stop = stop && rest.is_empty(); - // Set up DMA buffers. unsafe { self.set_tx_buffer(wr_buffer, tx_ram_buffer)?; @@ -447,18 +434,9 @@ impl<'d, T: Instance> Twim<'d, T> { // Start write+read operation. r.shorts.write(|w| { w.lasttx_startrx().enabled(); - if stop { - w.lastrx_stop().enabled(); - } else { - #[cfg(not(any(feature = "nrf52832", feature = "_nrf5340", feature = "_nrf9120")))] - w.lastrx_suspend().enabled(); - } + w.lastrx_stop().enabled(); w }); - #[cfg(any(feature = "nrf52832", feature = "_nrf5340", feature = "_nrf9120"))] - if !stop { - r.intenset.write(|w| w.lastrx().set()); - } r.tasks_starttx.write(|w| unsafe { w.bits(1) }); @@ -466,9 +444,7 @@ impl<'d, T: Instance> Twim<'d, T> { r.tasks_resume.write(|w| unsafe { w.bits(1) }); } } - [Operation::Read(buffer), rest @ ..] => { - let stop = stop && rest.is_empty(); - + [Operation::Read(buffer)] => { // Set up DMA buffers. unsafe { self.set_rx_buffer(buffer)?; @@ -476,18 +452,9 @@ impl<'d, T: Instance> Twim<'d, T> { // Start read operation. r.shorts.write(|w| { - if stop { - w.lastrx_stop().enabled(); - } else { - #[cfg(not(any(feature = "nrf52832", feature = "_nrf5340", feature = "_nrf9120")))] - w.lastrx_suspend().enabled(); - } + w.lastrx_stop().enabled(); w }); - #[cfg(any(feature = "nrf52832", feature = "_nrf5340", feature = "_nrf9120"))] - if !stop { - r.intenset.write(|w| w.lastrx().set()); - } r.tasks_startrx.write(|w| unsafe { w.bits(1) }); @@ -496,16 +463,15 @@ impl<'d, T: Instance> Twim<'d, T> { } if buffer.is_empty() { - // With a zero-length buffer, LASTRX doesn't fire (because there's no last byte!), so do the STOP/SUSPEND ourselves. - if stop { - r.tasks_stop.write(|w| unsafe { w.bits(1) }); - } else { - r.tasks_suspend.write(|w| unsafe { w.bits(1) }); - } + // With a zero-length buffer, LASTRX doesn't fire (because there's no last byte!), so do the STOP ourselves. + r.tasks_stop.write(|w| unsafe { w.bits(1) }); } } + [Operation::Read(_), ..] => { + panic!("Suspending after a read is not supported!"); + } [Operation::Write(buffer), rest @ ..] => { - let stop = stop && rest.is_empty(); + let stop = rest.is_empty(); // Set up DMA buffers. unsafe { @@ -538,13 +504,11 @@ impl<'d, T: Instance> Twim<'d, T> { } } [] => { - if stop { - if was_suspended { - r.tasks_resume.write(|w| unsafe { w.bits(1) }); - } - - r.tasks_stop.write(|w| unsafe { w.bits(1) }); + if was_suspended { + r.tasks_resume.write(|w| unsafe { w.bits(1) }); } + + r.tasks_stop.write(|w| unsafe { w.bits(1) }); } } @@ -557,17 +521,18 @@ impl<'d, T: Instance> Twim<'d, T> { match operations { [Operation::Read(rd_buffer), Operation::Write(wr_buffer), ..] - | [Operation::Write(wr_buffer), Operation::Read(rd_buffer), ..] + | [Operation::Write(wr_buffer), Operation::Read(rd_buffer)] if !rd_buffer.is_empty() && !wr_buffer.is_empty() => { self.check_tx(wr_buffer.len())?; self.check_rx(rd_buffer.len())?; Ok(2) } - [Operation::Read(buffer), ..] => { + [Operation::Read(buffer)] => { self.check_rx(buffer.len())?; Ok(1) } + [Operation::Read(_), ..] => unreachable!(), [Operation::Write(buffer), ..] => { self.check_tx(buffer.len())?; Ok(1) @@ -583,26 +548,17 @@ impl<'d, T: Instance> Twim<'d, T> { /// Each buffer must have a length of at most 255 bytes on the nRF52832 /// and at most 65535 bytes on the nRF52840. /// - /// If `stop` is set, the transaction will be terminated with a STOP - /// condition and the Twim will be stopped. Otherwise, the bus will be - /// left busy via clock stretching and Twim will be suspended. - /// - /// The nrf52832, nrf5340, and nrf9120 do not have hardware support for - /// suspending following a read operation therefore it is emulated by the - /// interrupt handler. If the latency of servicing that interrupt is - /// longer than a byte worth of clocks on the bus, the SCL clock will - /// continue to run for one or more additional bytes. This applies to - /// consecutive read operations, certain write-read-write sequences, or - /// any sequence of operations ending in a read when `stop == false`. - pub fn blocking_transaction( - &mut self, - address: u8, - mut operations: &mut [Operation<'_>], - stop: bool, - ) -> Result<(), Error> { + /// Consecutive `Read` operations are not supported because the Twim + /// hardware does not support suspending after a read operation. (Setting + /// the SUSPEND task in response to a LASTRX event causes the final byte of + /// the operation to be ACKed instead of NAKed. When the TWIM is resumed, + /// one more byte will be read before the new operation is started, leading + /// to an Overrun error if the RXD has not been updated, or an extraneous + /// byte read into the new buffer if the RXD has been updated.) + pub fn blocking_transaction(&mut self, address: u8, mut operations: &mut [Operation<'_>]) -> Result<(), Error> { let mut tx_ram_buffer = [MaybeUninit::uninit(); FORCE_COPY_BUFFER_SIZE]; while !operations.is_empty() { - self.setup_operations(address, operations, Some(&mut tx_ram_buffer), false, stop)?; + self.setup_operations(address, operations, Some(&mut tx_ram_buffer), false)?; self.blocking_wait(); let consumed = self.check_operations(operations)?; operations = &mut operations[consumed..]; @@ -615,10 +571,9 @@ impl<'d, T: Instance> Twim<'d, T> { &mut self, address: u8, mut operations: &mut [Operation<'_>], - stop: bool, ) -> Result<(), Error> { while !operations.is_empty() { - self.setup_operations(address, operations, None, false, stop)?; + self.setup_operations(address, operations, None, false)?; self.blocking_wait(); let consumed = self.check_operations(operations)?; operations = &mut operations[consumed..]; @@ -634,12 +589,11 @@ impl<'d, T: Instance> Twim<'d, T> { &mut self, address: u8, mut operations: &mut [Operation<'_>], - stop: bool, timeout: Duration, ) -> Result<(), Error> { let mut tx_ram_buffer = [MaybeUninit::uninit(); FORCE_COPY_BUFFER_SIZE]; while !operations.is_empty() { - self.setup_operations(address, operations, Some(&mut tx_ram_buffer), false, stop)?; + self.setup_operations(address, operations, Some(&mut tx_ram_buffer), false)?; self.blocking_wait_timeout(timeout)?; let consumed = self.check_operations(operations)?; operations = &mut operations[consumed..]; @@ -653,11 +607,10 @@ impl<'d, T: Instance> Twim<'d, T> { &mut self, address: u8, mut operations: &mut [Operation<'_>], - stop: bool, timeout: Duration, ) -> Result<(), Error> { while !operations.is_empty() { - self.setup_operations(address, operations, None, false, stop)?; + self.setup_operations(address, operations, None, false)?; self.blocking_wait_timeout(timeout)?; let consumed = self.check_operations(operations)?; operations = &mut operations[consumed..]; @@ -670,26 +623,17 @@ impl<'d, T: Instance> Twim<'d, T> { /// Each buffer must have a length of at most 255 bytes on the nRF52832 /// and at most 65535 bytes on the nRF52840. /// - /// If `stop` is set, the transaction will be terminated with a STOP - /// condition and the Twim will be stopped. Otherwise, the bus will be - /// left busy via clock stretching and Twim will be suspended. - /// - /// The nrf52832, nrf5340, and nrf9120 do not have hardware support for - /// suspending following a read operation therefore it is emulated by the - /// interrupt handler. If the latency of servicing that interrupt is - /// longer than a byte worth of clocks on the bus, the SCL clock will - /// continue to run for one or more additional bytes. This applies to - /// consecutive read operations, certain write-read-write sequences, or - /// any sequence of operations ending in a read when `stop == false`. - pub async fn transaction( - &mut self, - address: u8, - mut operations: &mut [Operation<'_>], - stop: bool, - ) -> Result<(), Error> { + /// Consecutive `Read` operations are not supported because the Twim + /// hardware does not support suspending after a read operation. (Setting + /// the SUSPEND task in response to a LASTRX event causes the final byte of + /// the operation to be ACKed instead of NAKed. When the TWIM is resumed, + /// one more byte will be read before the new operation is started, leading + /// to an Overrun error if the RXD has not been updated, or an extraneous + /// byte read into the new buffer if the RXD has been updated.) + pub async fn transaction(&mut self, address: u8, mut operations: &mut [Operation<'_>]) -> Result<(), Error> { let mut tx_ram_buffer = [MaybeUninit::uninit(); FORCE_COPY_BUFFER_SIZE]; while !operations.is_empty() { - self.setup_operations(address, operations, Some(&mut tx_ram_buffer), true, stop)?; + self.setup_operations(address, operations, Some(&mut tx_ram_buffer), true)?; self.async_wait().await; let consumed = self.check_operations(operations)?; operations = &mut operations[consumed..]; @@ -702,10 +646,9 @@ impl<'d, T: Instance> Twim<'d, T> { &mut self, address: u8, mut operations: &mut [Operation<'_>], - stop: bool, ) -> Result<(), Error> { while !operations.is_empty() { - self.setup_operations(address, operations, None, true, stop)?; + self.setup_operations(address, operations, None, true)?; self.async_wait().await; let consumed = self.check_operations(operations)?; operations = &mut operations[consumed..]; @@ -720,12 +663,12 @@ impl<'d, T: Instance> Twim<'d, T> { /// The buffer must have a length of at most 255 bytes on the nRF52832 /// and at most 65535 bytes on the nRF52840. pub fn blocking_write(&mut self, address: u8, buffer: &[u8]) -> Result<(), Error> { - self.blocking_transaction(address, &mut [Operation::Write(buffer)], true) + self.blocking_transaction(address, &mut [Operation::Write(buffer)]) } /// Same as [`blocking_write`](Twim::blocking_write) but will fail instead of copying data into RAM. Consult the module level documentation to learn more. pub fn blocking_write_from_ram(&mut self, address: u8, buffer: &[u8]) -> Result<(), Error> { - self.blocking_transaction_from_ram(address, &mut [Operation::Write(buffer)], true) + self.blocking_transaction_from_ram(address, &mut [Operation::Write(buffer)]) } /// Read from an I2C slave. @@ -733,7 +676,7 @@ impl<'d, T: Instance> Twim<'d, T> { /// The buffer must have a length of at most 255 bytes on the nRF52832 /// and at most 65535 bytes on the nRF52840. pub fn blocking_read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> { - self.blocking_transaction(address, &mut [Operation::Read(buffer)], true) + self.blocking_transaction(address, &mut [Operation::Read(buffer)]) } /// Write data to an I2C slave, then read data from the slave without @@ -742,11 +685,7 @@ impl<'d, T: Instance> Twim<'d, T> { /// The buffers must have a length of at most 255 bytes on the nRF52832 /// and at most 65535 bytes on the nRF52840. pub fn blocking_write_read(&mut self, address: u8, wr_buffer: &[u8], rd_buffer: &mut [u8]) -> Result<(), Error> { - self.blocking_transaction( - address, - &mut [Operation::Write(wr_buffer), Operation::Read(rd_buffer)], - true, - ) + self.blocking_transaction(address, &mut [Operation::Write(wr_buffer), Operation::Read(rd_buffer)]) } /// Same as [`blocking_write_read`](Twim::blocking_write_read) but will fail instead of copying data into RAM. Consult the module level documentation to learn more. @@ -756,11 +695,7 @@ impl<'d, T: Instance> Twim<'d, T> { wr_buffer: &[u8], rd_buffer: &mut [u8], ) -> Result<(), Error> { - self.blocking_transaction_from_ram( - address, - &mut [Operation::Write(wr_buffer), Operation::Read(rd_buffer)], - true, - ) + self.blocking_transaction_from_ram(address, &mut [Operation::Write(wr_buffer), Operation::Read(rd_buffer)]) } // =========================================== @@ -770,7 +705,7 @@ impl<'d, T: Instance> Twim<'d, T> { /// See [`blocking_write`]. #[cfg(feature = "time")] pub fn blocking_write_timeout(&mut self, address: u8, buffer: &[u8], timeout: Duration) -> Result<(), Error> { - self.blocking_transaction_timeout(address, &mut [Operation::Write(buffer)], true, timeout) + self.blocking_transaction_timeout(address, &mut [Operation::Write(buffer)], timeout) } /// Same as [`blocking_write`](Twim::blocking_write) but will fail instead of copying data into RAM. Consult the module level documentation to learn more. @@ -781,7 +716,7 @@ impl<'d, T: Instance> Twim<'d, T> { buffer: &[u8], timeout: Duration, ) -> Result<(), Error> { - self.blocking_transaction_from_ram_timeout(address, &mut [Operation::Write(buffer)], true, timeout) + self.blocking_transaction_from_ram_timeout(address, &mut [Operation::Write(buffer)], timeout) } /// Read from an I2C slave. @@ -790,7 +725,7 @@ impl<'d, T: Instance> Twim<'d, T> { /// and at most 65535 bytes on the nRF52840. #[cfg(feature = "time")] pub fn blocking_read_timeout(&mut self, address: u8, buffer: &mut [u8], timeout: Duration) -> Result<(), Error> { - self.blocking_transaction_timeout(address, &mut [Operation::Read(buffer)], true, timeout) + self.blocking_transaction_timeout(address, &mut [Operation::Read(buffer)], timeout) } /// Write data to an I2C slave, then read data from the slave without @@ -809,7 +744,6 @@ impl<'d, T: Instance> Twim<'d, T> { self.blocking_transaction_timeout( address, &mut [Operation::Write(wr_buffer), Operation::Read(rd_buffer)], - true, timeout, ) } @@ -826,7 +760,6 @@ impl<'d, T: Instance> Twim<'d, T> { self.blocking_transaction_from_ram_timeout( address, &mut [Operation::Write(wr_buffer), Operation::Read(rd_buffer)], - true, timeout, ) } @@ -838,7 +771,7 @@ impl<'d, T: Instance> Twim<'d, T> { /// The buffer must have a length of at most 255 bytes on the nRF52832 /// and at most 65535 bytes on the nRF52840. pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> { - self.transaction(address, &mut [Operation::Read(buffer)], true).await + self.transaction(address, &mut [Operation::Read(buffer)]).await } /// Write to an I2C slave. @@ -846,12 +779,12 @@ impl<'d, T: Instance> Twim<'d, T> { /// The buffer must have a length of at most 255 bytes on the nRF52832 /// and at most 65535 bytes on the nRF52840. pub async fn write(&mut self, address: u8, buffer: &[u8]) -> Result<(), Error> { - self.transaction(address, &mut [Operation::Write(buffer)], true).await + self.transaction(address, &mut [Operation::Write(buffer)]).await } /// Same as [`write`](Twim::write) but will fail instead of copying data into RAM. Consult the module level documentation to learn more. pub async fn write_from_ram(&mut self, address: u8, buffer: &[u8]) -> Result<(), Error> { - self.transaction_from_ram(address, &mut [Operation::Write(buffer)], true) + self.transaction_from_ram(address, &mut [Operation::Write(buffer)]) .await } @@ -861,12 +794,8 @@ impl<'d, T: Instance> Twim<'d, T> { /// The buffers must have a length of at most 255 bytes on the nRF52832 /// and at most 65535 bytes on the nRF52840. pub async fn write_read(&mut self, address: u8, wr_buffer: &[u8], rd_buffer: &mut [u8]) -> Result<(), Error> { - self.transaction( - address, - &mut [Operation::Write(wr_buffer), Operation::Read(rd_buffer)], - true, - ) - .await + self.transaction(address, &mut [Operation::Write(wr_buffer), Operation::Read(rd_buffer)]) + .await } /// Same as [`write_read`](Twim::write_read) but will fail instead of copying data into RAM. Consult the module level documentation to learn more. @@ -876,12 +805,8 @@ impl<'d, T: Instance> Twim<'d, T> { wr_buffer: &[u8], rd_buffer: &mut [u8], ) -> Result<(), Error> { - self.transaction_from_ram( - address, - &mut [Operation::Write(wr_buffer), Operation::Read(rd_buffer)], - true, - ) - .await + self.transaction_from_ram(address, &mut [Operation::Write(wr_buffer), Operation::Read(rd_buffer)]) + .await } } @@ -999,13 +924,13 @@ impl<'d, T: Instance> embedded_hal_1::i2c::ErrorType for Twim<'d, T> { impl<'d, T: Instance> embedded_hal_1::i2c::I2c for Twim<'d, T> { fn transaction(&mut self, address: u8, operations: &mut [Operation<'_>]) -> Result<(), Self::Error> { - self.blocking_transaction(address, operations, true) + self.blocking_transaction(address, operations) } } impl<'d, T: Instance> embedded_hal_async::i2c::I2c for Twim<'d, T> { async fn transaction(&mut self, address: u8, operations: &mut [Operation<'_>]) -> Result<(), Self::Error> { - self.transaction(address, operations, true).await + self.transaction(address, operations).await } } From 55805de05b4be39546c0b4c5e2ebc97cd3b1f75c Mon Sep 17 00:00:00 2001 From: Alex Moon Date: Wed, 21 Aug 2024 10:57:14 -0400 Subject: [PATCH 0273/1217] Refactoring and cleanup --- embassy-nrf/src/twim.rs | 183 +++++++++++++++++++++------------------- 1 file changed, 96 insertions(+), 87 deletions(-) diff --git a/embassy-nrf/src/twim.rs b/embassy-nrf/src/twim.rs index 4a239e8b5..187fce021 100644 --- a/embassy-nrf/src/twim.rs +++ b/embassy-nrf/src/twim.rs @@ -311,6 +311,7 @@ impl<'d, T: Instance> Twim<'d, T> { let r = T::regs(); loop { if r.events_suspended.read().bits() != 0 || r.events_stopped.read().bits() != 0 { + r.events_suspended.reset(); r.events_stopped.reset(); break; } @@ -372,15 +373,15 @@ impl<'d, T: Instance> Twim<'d, T> { address: u8, operations: &mut [Operation<'_>], tx_ram_buffer: Option<&mut [MaybeUninit; FORCE_COPY_BUFFER_SIZE]>, + last_op: Option<&Operation<'_>>, inten: bool, - ) -> Result<(), Error> { + ) -> Result { let r = T::regs(); compiler_fence(SeqCst); r.address.write(|w| unsafe { w.address().bits(address) }); - let was_suspended = r.events_suspended.read().bits() != 0; r.events_suspended.reset(); r.events_stopped.reset(); r.events_error.reset(); @@ -393,10 +394,12 @@ impl<'d, T: Instance> Twim<'d, T> { .write(|w| w.suspended().clear().stopped().clear().error().clear()); } + assert!(!operations.is_empty()); match operations { - [Operation::Read(rd_buffer), Operation::Write(wr_buffer), rest @ ..] - if !rd_buffer.is_empty() && !wr_buffer.is_empty() => - { + [Operation::Read(_), Operation::Read(_), ..] => { + panic!("Consecutive read operations are not supported!") + } + [Operation::Read(rd_buffer), Operation::Write(wr_buffer), rest @ ..] => { let stop = rest.is_empty(); // Set up DMA buffers. @@ -417,10 +420,38 @@ impl<'d, T: Instance> Twim<'d, T> { // Start read+write operation. r.tasks_startrx.write(|w| unsafe { w.bits(1) }); - - if was_suspended { + if last_op.is_some() { r.tasks_resume.write(|w| unsafe { w.bits(1) }); } + + // TODO: Handle empty write buffer + if rd_buffer.is_empty() { + // With a zero-length buffer, LASTRX doesn't fire (because there's no last byte!), so do the STARTTX ourselves. + r.tasks_starttx.write(|w| unsafe { w.bits(1) }); + } + + Ok(2) + } + [Operation::Read(buffer)] => { + // Set up DMA buffers. + unsafe { + self.set_rx_buffer(buffer)?; + } + + r.shorts.write(|w| w.lastrx_stop().enabled()); + + // Start read operation. + r.tasks_startrx.write(|w| unsafe { w.bits(1) }); + if last_op.is_some() { + r.tasks_resume.write(|w| unsafe { w.bits(1) }); + } + + if buffer.is_empty() { + // With a zero-length buffer, LASTRX doesn't fire (because there's no last byte!), so do the STOP ourselves. + r.tasks_stop.write(|w| unsafe { w.bits(1) }); + } + + Ok(1) } [Operation::Write(wr_buffer), Operation::Read(rd_buffer)] if !wr_buffer.is_empty() && !rd_buffer.is_empty() => @@ -439,36 +470,11 @@ impl<'d, T: Instance> Twim<'d, T> { }); r.tasks_starttx.write(|w| unsafe { w.bits(1) }); - - if was_suspended { - r.tasks_resume.write(|w| unsafe { w.bits(1) }); - } - } - [Operation::Read(buffer)] => { - // Set up DMA buffers. - unsafe { - self.set_rx_buffer(buffer)?; - } - - // Start read operation. - r.shorts.write(|w| { - w.lastrx_stop().enabled(); - w - }); - - r.tasks_startrx.write(|w| unsafe { w.bits(1) }); - - if was_suspended { + if last_op.is_some() { r.tasks_resume.write(|w| unsafe { w.bits(1) }); } - if buffer.is_empty() { - // With a zero-length buffer, LASTRX doesn't fire (because there's no last byte!), so do the STOP ourselves. - r.tasks_stop.write(|w| unsafe { w.bits(1) }); - } - } - [Operation::Read(_), ..] => { - panic!("Suspending after a read is not supported!"); + Ok(2) } [Operation::Write(buffer), rest @ ..] => { let stop = rest.is_empty(); @@ -489,8 +495,7 @@ impl<'d, T: Instance> Twim<'d, T> { }); r.tasks_starttx.write(|w| unsafe { w.bits(1) }); - - if was_suspended { + if last_op.is_some() { r.tasks_resume.write(|w| unsafe { w.bits(1) }); } @@ -502,43 +507,33 @@ impl<'d, T: Instance> Twim<'d, T> { r.tasks_suspend.write(|w| unsafe { w.bits(1) }); } } - } - [] => { - if was_suspended { - r.tasks_resume.write(|w| unsafe { w.bits(1) }); - } - r.tasks_stop.write(|w| unsafe { w.bits(1) }); + Ok(1) } + [] => unreachable!(), } - - Ok(()) } - fn check_operations(&mut self, operations: &mut [Operation<'_>]) -> Result { + fn check_operations(&mut self, operations: &[Operation<'_>]) -> Result<(), Error> { compiler_fence(SeqCst); self.check_errorsrc()?; + assert!(operations.len() == 1 || operations.len() == 2); match operations { - [Operation::Read(rd_buffer), Operation::Write(wr_buffer), ..] - | [Operation::Write(wr_buffer), Operation::Read(rd_buffer)] - if !rd_buffer.is_empty() && !wr_buffer.is_empty() => - { - self.check_tx(wr_buffer.len())?; + [Operation::Read(rd_buffer), Operation::Write(wr_buffer)] + | [Operation::Write(wr_buffer), Operation::Read(rd_buffer)] => { self.check_rx(rd_buffer.len())?; - Ok(2) + self.check_tx(wr_buffer.len())?; } [Operation::Read(buffer)] => { self.check_rx(buffer.len())?; - Ok(1) } - [Operation::Read(_), ..] => unreachable!(), [Operation::Write(buffer), ..] => { self.check_tx(buffer.len())?; - Ok(1) } - [] => Ok(0), + _ => unreachable!(), } + Ok(()) } // =========================================== @@ -548,20 +543,21 @@ impl<'d, T: Instance> Twim<'d, T> { /// Each buffer must have a length of at most 255 bytes on the nRF52832 /// and at most 65535 bytes on the nRF52840. /// - /// Consecutive `Read` operations are not supported because the Twim - /// hardware does not support suspending after a read operation. (Setting - /// the SUSPEND task in response to a LASTRX event causes the final byte of - /// the operation to be ACKed instead of NAKed. When the TWIM is resumed, - /// one more byte will be read before the new operation is started, leading - /// to an Overrun error if the RXD has not been updated, or an extraneous - /// byte read into the new buffer if the RXD has been updated.) + /// Consecutive `Operation::Read`s are not supported due to hardware + /// limitations. + /// + /// An `Operation::Write` following an `Operation::Read` must have a + /// non-empty buffer. pub fn blocking_transaction(&mut self, address: u8, mut operations: &mut [Operation<'_>]) -> Result<(), Error> { let mut tx_ram_buffer = [MaybeUninit::uninit(); FORCE_COPY_BUFFER_SIZE]; + let mut last_op = None; while !operations.is_empty() { - self.setup_operations(address, operations, Some(&mut tx_ram_buffer), false)?; + let ops = self.setup_operations(address, operations, Some(&mut tx_ram_buffer), last_op, false)?; + let (in_progress, rest) = operations.split_at_mut(ops); self.blocking_wait(); - let consumed = self.check_operations(operations)?; - operations = &mut operations[consumed..]; + self.check_operations(in_progress)?; + last_op = in_progress.last(); + operations = rest; } Ok(()) } @@ -572,11 +568,14 @@ impl<'d, T: Instance> Twim<'d, T> { address: u8, mut operations: &mut [Operation<'_>], ) -> Result<(), Error> { + let mut last_op = None; while !operations.is_empty() { - self.setup_operations(address, operations, None, false)?; + let ops = self.setup_operations(address, operations, None, last_op, false)?; + let (in_progress, rest) = operations.split_at_mut(ops); self.blocking_wait(); - let consumed = self.check_operations(operations)?; - operations = &mut operations[consumed..]; + self.check_operations(in_progress)?; + last_op = in_progress.last(); + operations = rest; } Ok(()) } @@ -592,11 +591,14 @@ impl<'d, T: Instance> Twim<'d, T> { timeout: Duration, ) -> Result<(), Error> { let mut tx_ram_buffer = [MaybeUninit::uninit(); FORCE_COPY_BUFFER_SIZE]; + let mut last_op = None; while !operations.is_empty() { - self.setup_operations(address, operations, Some(&mut tx_ram_buffer), false)?; + let ops = self.setup_operations(address, operations, Some(&mut tx_ram_buffer), last_op, false)?; + let (in_progress, rest) = operations.split_at_mut(ops); self.blocking_wait_timeout(timeout)?; - let consumed = self.check_operations(operations)?; - operations = &mut operations[consumed..]; + self.check_operations(in_progress)?; + last_op = in_progress.last(); + operations = rest; } Ok(()) } @@ -609,11 +611,14 @@ impl<'d, T: Instance> Twim<'d, T> { mut operations: &mut [Operation<'_>], timeout: Duration, ) -> Result<(), Error> { + let mut last_op = None; while !operations.is_empty() { - self.setup_operations(address, operations, None, false)?; + let ops = self.setup_operations(address, operations, None, last_op, false)?; + let (in_progress, rest) = operations.split_at_mut(ops); self.blocking_wait_timeout(timeout)?; - let consumed = self.check_operations(operations)?; - operations = &mut operations[consumed..]; + self.check_operations(in_progress)?; + last_op = in_progress.last(); + operations = rest; } Ok(()) } @@ -623,20 +628,21 @@ impl<'d, T: Instance> Twim<'d, T> { /// Each buffer must have a length of at most 255 bytes on the nRF52832 /// and at most 65535 bytes on the nRF52840. /// - /// Consecutive `Read` operations are not supported because the Twim - /// hardware does not support suspending after a read operation. (Setting - /// the SUSPEND task in response to a LASTRX event causes the final byte of - /// the operation to be ACKed instead of NAKed. When the TWIM is resumed, - /// one more byte will be read before the new operation is started, leading - /// to an Overrun error if the RXD has not been updated, or an extraneous - /// byte read into the new buffer if the RXD has been updated.) + /// Consecutive `Operation::Read`s are not supported due to hardware + /// limitations. + /// + /// An `Operation::Write` following an `Operation::Read` must have a + /// non-empty buffer. pub async fn transaction(&mut self, address: u8, mut operations: &mut [Operation<'_>]) -> Result<(), Error> { let mut tx_ram_buffer = [MaybeUninit::uninit(); FORCE_COPY_BUFFER_SIZE]; + let mut last_op = None; while !operations.is_empty() { - self.setup_operations(address, operations, Some(&mut tx_ram_buffer), true)?; + let ops = self.setup_operations(address, operations, Some(&mut tx_ram_buffer), last_op, true)?; + let (in_progress, rest) = operations.split_at_mut(ops); self.async_wait().await; - let consumed = self.check_operations(operations)?; - operations = &mut operations[consumed..]; + self.check_operations(in_progress)?; + last_op = in_progress.last(); + operations = rest; } Ok(()) } @@ -647,11 +653,14 @@ impl<'d, T: Instance> Twim<'d, T> { address: u8, mut operations: &mut [Operation<'_>], ) -> Result<(), Error> { + let mut last_op = None; while !operations.is_empty() { - self.setup_operations(address, operations, None, true)?; + let ops = self.setup_operations(address, operations, None, last_op, true)?; + let (in_progress, rest) = operations.split_at_mut(ops); self.async_wait().await; - let consumed = self.check_operations(operations)?; - operations = &mut operations[consumed..]; + self.check_operations(in_progress)?; + last_op = in_progress.last(); + operations = rest; } Ok(()) } From 1fed8ac5dbb239e53cdc51b10c27a0c58ea92aeb Mon Sep 17 00:00:00 2001 From: Vincenzo Marturano Date: Thu, 24 Oct 2024 15:12:04 +0200 Subject: [PATCH 0274/1217] Allow separate control of duty cycle for each channel in a pwm slice by splitting the Pwm driver. --- embassy-rp/src/pwm.rs | 52 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/embassy-rp/src/pwm.rs b/embassy-rp/src/pwm.rs index cfb99c569..4f11eb8f7 100644 --- a/embassy-rp/src/pwm.rs +++ b/embassy-rp/src/pwm.rs @@ -344,6 +344,58 @@ impl<'d> Pwm<'d> { fn bit(&self) -> u32 { 1 << self.slice as usize } + + #[inline] + /// Split Pwm driver to allow separate duty cycle control of each channel + pub fn split(&self) -> (PwmOutput,PwmOutput){ + (PwmOutput::new(PwmChannel::A,self.slice.clone()),PwmOutput::new(PwmChannel::B,self.slice.clone())) + } +} + +enum PwmChannel{ + A, + B +} + +/// Single channel of Pwm driver. +pub struct PwmOutput { + channel: PwmChannel, + slice: usize +} + +impl PwmOutput { + fn new(channel: PwmChannel,slice: usize) -> Self{ + Self { channel, slice } + } +} + +impl SetDutyCycle for PwmOutput { + fn max_duty_cycle(&self) -> u16 { + pac::PWM.ch(self.slice).top().read().top() + } + + fn set_duty_cycle(&mut self, duty: u16) -> Result<(), Self::Error> { + let max_duty = self.max_duty_cycle(); + if duty > max_duty { + return Err(PwmError::InvalidDutyCycle); + } + + let p = pac::PWM.ch(self.slice); + match self.channel { + PwmChannel::A => { + p.cc().modify(|w| { + w.set_a(duty); + }); + }, + PwmChannel::B => { + p.cc().modify(|w| { + w.set_b(duty); + }); + }, + } + + Ok(()) + } } /// Batch representation of PWM slices. From 2596de52bba32b0d1e755ab18909c10a9e663aad Mon Sep 17 00:00:00 2001 From: Vincenzo Marturano Date: Thu, 24 Oct 2024 15:39:22 +0200 Subject: [PATCH 0275/1217] Fixed missing trait implementation for PwmOutput. --- embassy-rp/src/pwm.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/embassy-rp/src/pwm.rs b/embassy-rp/src/pwm.rs index 4f11eb8f7..66f0dc7f2 100644 --- a/embassy-rp/src/pwm.rs +++ b/embassy-rp/src/pwm.rs @@ -369,6 +369,10 @@ impl PwmOutput { } } +impl ErrorType for PwmOutput { + type Error = PwmError; +} + impl SetDutyCycle for PwmOutput { fn max_duty_cycle(&self) -> u16 { pac::PWM.ch(self.slice).top().read().top() From 31662eaeef0762a7c7b9c95aee61a9066d7e447a Mon Sep 17 00:00:00 2001 From: Vincenzo Marturano Date: Thu, 24 Oct 2024 16:04:32 +0200 Subject: [PATCH 0276/1217] Add new() method to PwmBatch so it can be istantiated. --- embassy-rp/src/pwm.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/embassy-rp/src/pwm.rs b/embassy-rp/src/pwm.rs index 66f0dc7f2..4da5e5e28 100644 --- a/embassy-rp/src/pwm.rs +++ b/embassy-rp/src/pwm.rs @@ -406,6 +406,10 @@ impl SetDutyCycle for PwmOutput { pub struct PwmBatch(u32); impl PwmBatch { + #[inline] + pub fn new() -> Self{ + Self(0) + } #[inline] /// Enable a PWM slice in this batch. pub fn enable(&mut self, pwm: &Pwm<'_>) { From 052463212b6b6c1647f517ce38272dd4dd3d4353 Mon Sep 17 00:00:00 2001 From: Vincenzo Marturano Date: Thu, 24 Oct 2024 16:20:28 +0200 Subject: [PATCH 0277/1217] Revert "Add new() method to PwmBatch so it can be istantiated." This reverts commit 31662eaeef0762a7c7b9c95aee61a9066d7e447a. --- embassy-rp/src/pwm.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/embassy-rp/src/pwm.rs b/embassy-rp/src/pwm.rs index 4da5e5e28..66f0dc7f2 100644 --- a/embassy-rp/src/pwm.rs +++ b/embassy-rp/src/pwm.rs @@ -406,10 +406,6 @@ impl SetDutyCycle for PwmOutput { pub struct PwmBatch(u32); impl PwmBatch { - #[inline] - pub fn new() -> Self{ - Self(0) - } #[inline] /// Enable a PWM slice in this batch. pub fn enable(&mut self, pwm: &Pwm<'_>) { From 336ef01b05e87e6b2b3c9b98e9bdca0c7d78a6af Mon Sep 17 00:00:00 2001 From: Vincenzo Marturano Date: Thu, 24 Oct 2024 19:36:54 +0200 Subject: [PATCH 0278/1217] Implemented owned split. --- embassy-rp/src/pwm.rs | 47 ++++++++++++++++++++++++++----------------- 1 file changed, 29 insertions(+), 18 deletions(-) diff --git a/embassy-rp/src/pwm.rs b/embassy-rp/src/pwm.rs index 66f0dc7f2..5fea0901a 100644 --- a/embassy-rp/src/pwm.rs +++ b/embassy-rp/src/pwm.rs @@ -347,25 +347,36 @@ impl<'d> Pwm<'d> { #[inline] /// Split Pwm driver to allow separate duty cycle control of each channel - pub fn split(&self) -> (PwmOutput,PwmOutput){ - (PwmOutput::new(PwmChannel::A,self.slice.clone()),PwmOutput::new(PwmChannel::B,self.slice.clone())) + pub fn split(self) -> (Option, Option) { + + let pwm_output_a = if let Some(pin_a) = self.pin_a { + Some(PwmOutput::new(PwmChannelPin::A(pin_a), self.slice.clone())) + }; + + let pwm_output_b = if let Some(pin_b) = self.pin_b { + Some(PwmOutput::new(PwmChannelPin::B(pin_b), self.slice.clone())) + }; + + (pwm_output_a,pwm_output_b) } + } -enum PwmChannel{ - A, - B +enum PwmChannelPin<'d> { + A(PeripheralRef<'d, AnyPin>), + B(PeripheralRef<'d, AnyPin>) } /// Single channel of Pwm driver. -pub struct PwmOutput { - channel: PwmChannel, - slice: usize +pub struct PwmOutput<'d> { + //pin that can be ether ChannelAPin or ChannelBPin + channel_pin: PwmChannelPin<'d> , + slice: usize, } -impl PwmOutput { - fn new(channel: PwmChannel,slice: usize) -> Self{ - Self { channel, slice } +impl <'d> PwmOutput<'d> { + fn new(channel_pin: PwmChannelPin<'d>, slice: usize) -> Self { + Self { channel_pin ,slice } } } @@ -373,7 +384,7 @@ impl ErrorType for PwmOutput { type Error = PwmError; } -impl SetDutyCycle for PwmOutput { +impl<'d> SetDutyCycle for PwmOutput<'d> { fn max_duty_cycle(&self) -> u16 { pac::PWM.ch(self.slice).top().read().top() } @@ -385,19 +396,19 @@ impl SetDutyCycle for PwmOutput { } let p = pac::PWM.ch(self.slice); - match self.channel { - PwmChannel::A => { + match self.channel_pin { + PwmChannelPin::A => { p.cc().modify(|w| { w.set_a(duty); }); - }, - PwmChannel::B => { + } + PwmChannelPin::B => { p.cc().modify(|w| { w.set_b(duty); }); - }, + } } - + Ok(()) } } From 354ff3bac31a910598a6e350499262b3163d50ef Mon Sep 17 00:00:00 2001 From: Vincenzo Marturano Date: Thu, 24 Oct 2024 19:46:23 +0200 Subject: [PATCH 0279/1217] Fix missing lifetime --- embassy-rp/src/pwm.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-rp/src/pwm.rs b/embassy-rp/src/pwm.rs index 5fea0901a..2df2cfad3 100644 --- a/embassy-rp/src/pwm.rs +++ b/embassy-rp/src/pwm.rs @@ -347,7 +347,7 @@ impl<'d> Pwm<'d> { #[inline] /// Split Pwm driver to allow separate duty cycle control of each channel - pub fn split(self) -> (Option, Option) { + pub fn split(self) -> (Option>, Option>) { let pwm_output_a = if let Some(pin_a) = self.pin_a { Some(PwmOutput::new(PwmChannelPin::A(pin_a), self.slice.clone())) @@ -380,7 +380,7 @@ impl <'d> PwmOutput<'d> { } } -impl ErrorType for PwmOutput { +impl<'d> ErrorType for PwmOutput<'d> { type Error = PwmError; } From 874dbec5a4d11c57c3683a27ac09584e728694c2 Mon Sep 17 00:00:00 2001 From: Vincenzo Marturano Date: Thu, 24 Oct 2024 19:52:09 +0200 Subject: [PATCH 0280/1217] Fixed mistakes. --- embassy-rp/src/pwm.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/embassy-rp/src/pwm.rs b/embassy-rp/src/pwm.rs index 2df2cfad3..443308158 100644 --- a/embassy-rp/src/pwm.rs +++ b/embassy-rp/src/pwm.rs @@ -351,10 +351,14 @@ impl<'d> Pwm<'d> { let pwm_output_a = if let Some(pin_a) = self.pin_a { Some(PwmOutput::new(PwmChannelPin::A(pin_a), self.slice.clone())) + }else{ + None }; let pwm_output_b = if let Some(pin_b) = self.pin_b { Some(PwmOutput::new(PwmChannelPin::B(pin_b), self.slice.clone())) + }else { + None }; (pwm_output_a,pwm_output_b) @@ -397,12 +401,12 @@ impl<'d> SetDutyCycle for PwmOutput<'d> { let p = pac::PWM.ch(self.slice); match self.channel_pin { - PwmChannelPin::A => { + PwmChannelPin::A(_) => { p.cc().modify(|w| { w.set_a(duty); }); } - PwmChannelPin::B => { + PwmChannelPin::B(_) => { p.cc().modify(|w| { w.set_b(duty); }); From 7b62d70d184ca9e8e7c6864d6ed39b4e8f75f02f Mon Sep 17 00:00:00 2001 From: Haobo Gu Date: Fri, 25 Oct 2024 18:27:48 +0800 Subject: [PATCH 0281/1217] feat(ospi): add memory mapped mode Signed-off-by: Haobo Gu --- embassy-stm32/src/ospi/mod.rs | 63 ++++++++++++++++++++++++++--------- 1 file changed, 48 insertions(+), 15 deletions(-) diff --git a/embassy-stm32/src/ospi/mod.rs b/embassy-stm32/src/ospi/mod.rs index 0574f7816..7ccafe361 100644 --- a/embassy-stm32/src/ospi/mod.rs +++ b/embassy-stm32/src/ospi/mod.rs @@ -179,39 +179,72 @@ pub struct Ospi<'d, T: Instance, M: PeriMode> { } impl<'d, T: Instance, M: PeriMode> Ospi<'d, T, M> { - pub fn enable_memory_mapped_mode(&mut self) { + /// Enter memory mode. + /// The Input `TransferConfig` is used to configure the read operation in memory mode + pub fn enable_memory_mapped_mode( + &mut self, + read_config: TransferConfig, + write_config: TransferConfig, + ) -> Result<(), OspiError> { + // Use configure command to set read config + self.configure_command(&read_config, None)?; + let reg = T::REGS; while reg.sr().read().busy() { info!("wait ospi busy"); } - + reg.ccr().modify(|r| { - r.set_isize(crate::ospi::vals::SizeInBits::_8BIT); - r.set_adsize(crate::ospi::vals::SizeInBits::_24BIT); - r.set_admode(crate::ospi::vals::PhaseMode::ONELINE); - r.set_imode(crate::ospi::vals::PhaseMode::ONELINE); - r.set_dmode(crate::ospi::vals::PhaseMode::FOURLINES); + r.set_dqse(false); + r.set_sioo(true); }); - + + // Set wrting configurations, there are separate registers for write configurations in memory mapped mode + reg.wccr().modify(|w| { + w.set_imode(PhaseMode::from_bits(write_config.iwidth.into())); + w.set_idtr(write_config.idtr); + w.set_isize(SizeInBits::from_bits(write_config.isize.into())); + + w.set_admode(PhaseMode::from_bits(write_config.adwidth.into())); + w.set_addtr(write_config.idtr); + w.set_adsize(SizeInBits::from_bits(write_config.adsize.into())); + + w.set_dmode(PhaseMode::from_bits(write_config.dwidth.into())); + w.set_ddtr(write_config.ddtr); + + w.set_abmode(PhaseMode::from_bits(write_config.abwidth.into())); + w.set_dqse(true); + }); + + reg.wtcr().modify(|w| w.set_dcyc(write_config.dummy.into())); + + // Enable memory mapped mode reg.cr().modify(|r| { r.set_fmode(crate::ospi::vals::FunctionalMode::MEMORYMAPPED); - r.set_dmaen(false); - r.set_en(true); + r.set_tcen(false); }); - - // reg.tcr().modify(|r| { - // r.set_dcyc(6); - // }); - + Ok(()) } + + /// Quit from memory mapped mode pub fn disable_memory_mapped_mode(&mut self) { let reg = T::REGS; while reg.sr().read().busy() { info!("wait ospi busy"); } + reg.cr().modify(|r| { r.set_fmode(crate::ospi::vals::FunctionalMode::INDIRECTWRITE); + r.set_abort(true); r.set_dmaen(false); + r.set_en(false); + }); + + // Clear transfer complete flag + reg.fcr().write(|w| w.set_ctcf(true)); + + // Re-enable ospi + reg.cr().modify(|r| { r.set_en(true); }); } From 71fe8a7b90abc7b625d0f5b822508b350f3444d2 Mon Sep 17 00:00:00 2001 From: Vincenzo Marturano Date: Fri, 25 Oct 2024 12:54:06 +0200 Subject: [PATCH 0282/1217] Fixed owned split and implemented split_by_ref. --- embassy-rp/src/pwm.rs | 80 ++++++++++++++++++++++++++++++++----------- 1 file changed, 60 insertions(+), 20 deletions(-) diff --git a/embassy-rp/src/pwm.rs b/embassy-rp/src/pwm.rs index 443308158..18d476ed4 100644 --- a/embassy-rp/src/pwm.rs +++ b/embassy-rp/src/pwm.rs @@ -347,40 +347,80 @@ impl<'d> Pwm<'d> { #[inline] /// Split Pwm driver to allow separate duty cycle control of each channel - pub fn split(self) -> (Option>, Option>) { - - let pwm_output_a = if let Some(pin_a) = self.pin_a { - Some(PwmOutput::new(PwmChannelPin::A(pin_a), self.slice.clone())) - }else{ - None - }; - - let pwm_output_b = if let Some(pin_b) = self.pin_b { - Some(PwmOutput::new(PwmChannelPin::B(pin_b), self.slice.clone())) - }else { - None - }; - - (pwm_output_a,pwm_output_b) + pub fn split(mut self) -> (Option>, Option>) { + ( + self.pin_a + .take() + .map(|pin| PwmOutput::new(PwmChannelPin::A(pin), self.slice.clone(), true)), + self.pin_b + .take() + .map(|pin| PwmOutput::new(PwmChannelPin::B(pin), self.slice.clone(), true)), + ) } + pub fn split_by_ref(&mut self) -> (Option>, Option>) { + ( + self.pin_a + .as_mut() + .map(|pin| PwmOutput::new(PwmChannelPin::A(pin.reborrow()), self.slice.clone(), false)), + self.pin_b + .as_mut() + .map(|pin| PwmOutput::new(PwmChannelPin::B(pin.reborrow()), self.slice.clone(), false)), + ) + } } enum PwmChannelPin<'d> { A(PeripheralRef<'d, AnyPin>), - B(PeripheralRef<'d, AnyPin>) + B(PeripheralRef<'d, AnyPin>), } /// Single channel of Pwm driver. pub struct PwmOutput<'d> { //pin that can be ether ChannelAPin or ChannelBPin - channel_pin: PwmChannelPin<'d> , + channel_pin: PwmChannelPin<'d>, slice: usize, + is_owned: bool, } -impl <'d> PwmOutput<'d> { - fn new(channel_pin: PwmChannelPin<'d>, slice: usize) -> Self { - Self { channel_pin ,slice } +impl<'d> PwmOutput<'d> { + fn new(channel_pin: PwmChannelPin<'d>, slice: usize, is_owned: bool) -> Self { + Self { + channel_pin, + slice, + is_owned, + } + } +} + +impl<'d> Drop for PwmOutput<'d> { + fn drop(&mut self) { + if self.is_owned { + let p = pac::PWM.ch(self.slice); + match &self.channel_pin { + PwmChannelPin::A(pin) => { + p.cc().modify(|w| { + w.set_a(0); + }); + + pin.gpio().ctrl().write(|w| w.set_funcsel(31)); + ///Enable pin PULL-DOWN + pin.pad_ctrl().modify(|w| { + w.set_pde(true); + }); + } + PwmChannelPin::B(pin) => { + p.cc().modify(|w| { + w.set_b(0); + }); + pin.gpio().ctrl().write(|w| w.set_funcsel(31)); + ///Enable pin PULL-DOWN + pin.pad_ctrl().modify(|w| { + w.set_pde(true); + }); + } + } + } } } From 9690bed5a6f9a37bc926c1e86585bc28eb667ebf Mon Sep 17 00:00:00 2001 From: Vincenzo Marturano Date: Fri, 25 Oct 2024 13:12:24 +0200 Subject: [PATCH 0283/1217] Fix documentation. --- embassy-rp/src/pwm.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/embassy-rp/src/pwm.rs b/embassy-rp/src/pwm.rs index 18d476ed4..4fb8ade12 100644 --- a/embassy-rp/src/pwm.rs +++ b/embassy-rp/src/pwm.rs @@ -345,8 +345,8 @@ impl<'d> Pwm<'d> { 1 << self.slice as usize } + /// Splits the PWM driver into separate `PwmOutput` instances for channels A and B. #[inline] - /// Split Pwm driver to allow separate duty cycle control of each channel pub fn split(mut self) -> (Option>, Option>) { ( self.pin_a @@ -357,7 +357,9 @@ impl<'d> Pwm<'d> { .map(|pin| PwmOutput::new(PwmChannelPin::B(pin), self.slice.clone(), true)), ) } - + /// Splits the PWM driver by reference to allow for separate duty cycle control + /// of each channel (A and B) without taking ownership of the PWM instance. + #[inline] pub fn split_by_ref(&mut self) -> (Option>, Option>) { ( self.pin_a @@ -404,7 +406,7 @@ impl<'d> Drop for PwmOutput<'d> { }); pin.gpio().ctrl().write(|w| w.set_funcsel(31)); - ///Enable pin PULL-DOWN + //Enable pin PULL-DOWN pin.pad_ctrl().modify(|w| { w.set_pde(true); }); @@ -414,7 +416,7 @@ impl<'d> Drop for PwmOutput<'d> { w.set_b(0); }); pin.gpio().ctrl().write(|w| w.set_funcsel(31)); - ///Enable pin PULL-DOWN + //Enable pin PULL-DOWN pin.pad_ctrl().modify(|w| { w.set_pde(true); }); From 45e7a7a55aa6b5b8d41d81949b75b1b4a154f9bd Mon Sep 17 00:00:00 2001 From: William <174336620+williams-one@users.noreply.github.com> Date: Fri, 25 Oct 2024 15:03:26 +0200 Subject: [PATCH 0284/1217] Update CFBLR configuration As per section "43.7.23 LTDC layer x color frame buffer length register (LTDC_LxCFBLR)" of Reference manual for STM32U5 RM0456, CFBLL has to be set to the length of one pixel line plus 3 (instead of plus 7 as for H7) --- embassy-stm32/src/ltdc.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/embassy-stm32/src/ltdc.rs b/embassy-stm32/src/ltdc.rs index 4c5239971..e25c4f3fb 100644 --- a/embassy-stm32/src/ltdc.rs +++ b/embassy-stm32/src/ltdc.rs @@ -395,7 +395,10 @@ impl<'d, T: Instance> Ltdc<'d, T> { // framebuffer pitch and line length layer.cfblr().modify(|w| { w.set_cfbp(width * bytes_per_pixel); + #[cfg(not(stm32u5))] w.set_cfbll(width * bytes_per_pixel + 7); + #[cfg(stm32u5)] + w.set_cfbll(width * bytes_per_pixel + 3); }); // framebuffer line number From be5222421177b632cd120272e08156b64cc0b886 Mon Sep 17 00:00:00 2001 From: William <174336620+williams-one@users.noreply.github.com> Date: Fri, 25 Oct 2024 15:40:18 +0200 Subject: [PATCH 0285/1217] Add LTDC example for STM32U5G9J-DK2 demo board --- examples/stm32u5/Cargo.toml | 2 + examples/stm32u5/src/bin/ferris.bmp | Bin 0 -> 6794 bytes examples/stm32u5/src/bin/ltdc.rs | 462 ++++++++++++++++++++++++++++ 3 files changed, 464 insertions(+) create mode 100644 examples/stm32u5/src/bin/ferris.bmp create mode 100644 examples/stm32u5/src/bin/ltdc.rs diff --git a/examples/stm32u5/Cargo.toml b/examples/stm32u5/Cargo.toml index ad7db4c32..f594ad71a 100644 --- a/examples/stm32u5/Cargo.toml +++ b/examples/stm32u5/Cargo.toml @@ -21,6 +21,8 @@ cortex-m-rt = "0.7.0" embedded-hal = "0.2.6" panic-probe = { version = "0.3", features = ["print-defmt"] } heapless = { version = "0.8", default-features = false } +embedded-graphics = { version = "0.8.1" } +tinybmp = { version = "0.6.0" } micromath = "2.0.0" diff --git a/examples/stm32u5/src/bin/ferris.bmp b/examples/stm32u5/src/bin/ferris.bmp new file mode 100644 index 0000000000000000000000000000000000000000..7a222ab84ddd9f2707ca8dcebad84b1b39c21818 GIT binary patch literal 6794 zcmb`L33OD|8OQ(JNnU0$OJ>O|nIvR^V8})iwgjaFsH`H2vdNBYA}T_u7=r{^1}IQL zRKN`(6x0McMUzp1q-luKI(W`lj>IPOV3HPUtHrL?CG_66&B`R_wD+9%?zjHl_wKvz zzB@B!%1$SQwlfZ>qS6d{RM4Xj)bvc74X|j%gBqCw_y)L=0Aw&fZDYnyTPsSvKa;4T z@qpl<@ILJNN$8_Wgep#pIF%W3oDN*P1&Fr-oDF^AozTRmfFz_+Uk2jTX^2mtRVDNX z)LBT-WCDrVAetPg)VWY44nVwSAh^UlsI_@iFNQX85R4WR`sfM}r!9d_TMSL&FmSpO zBUmpCLzH%8FA+E(3tL``ZUB_CLqx~1qsO$pt4Mb)^ayA z<{99u_d;))OKY5tM9WMh*rq|3JPT^ed^!xXkwkk<@&Y;>55Qtx3blO>wAMv1Sr;PS z{vh=B#V}e|z+!m}oMQ>Jwv|w)EQQIw5<17j&^VXD>{tb>Z4LA(tDsF=frQk@piNna z{K5jL(^f<0e1hKN25_nCk(mBC^t897JdK33C!y`T23lt|3{=i5Do3(o8`SBQu%~W> zE^QMWY1JqmT!O@mDkS&a413xR7&5lNp1u>#)VEqjul+4{QWbMK5@-o;no`<&o4kTqi3rFS)u=RZvx~v08>bDmuSuaALeGta} z`{2wzfW(~VV9z`ZL%%~XQ8}6Rj;z;V&OU;qoR^S7`#VOBq`Vp!2fPAH|D#Buhdui( z=yHz1nNtJ(fM39r`x>mYH{5m{=A4sAp+{2g30MZa4JSQ}d2b>)_Y@oh-h(OsEg14n z!<_p*Y_w0IeNz5AunhbFPI@HgorSTm9;TuOSPRa`>c{k1GvFBdIgG>Fkvyam)}dXPJ@)~m4*3$c z;eUi>=vT0pU4x_iI+BOqfN{hZu$Fy|`HL1{!QzE@qH;afZD_!bT|2R&@^kEdb`O?3 zc>|mGe}&_3oSPBYs&^!;CwOp0 z|76MaR3My?J5mE$D0dt`F5tRH%H`#76;X+e#ylrED+2MVm%VmH3*j!~`H_l;NQ204 z)a8tvGH>n1?a!0Dn%xa`HT$+LpEg4Bx&tGjI?T5yS}=DJeaPtwcc5HupeHK>vLtzf z29DmtX*oTJ`v48~s$~aR9>L&AMWn4zNg(T}cao$AxT9H4b0BIX(?c5}p*quo9>@%) zOV3#0<_IsqB88jY$f80UA=^R?R2!&dkW%Js5QkXi8pQ-Q3{HB|9TxSF^P7ZNJ3=f> znZZEWMf4;xMhF*@x#BC(L~Wy7M)IS!h;*J8rg3?sqftXhU)TLKRq%O*kr2761~Ggc zAwyi1>cNr8Jl~=f3b|8y)q+BrHH34y#uFl}8~kAwCvxRyKa31@xqezG=6Kg#2qbs? zOrX+}smUKOi&8Tot6Z*`WTT+^*xMm+?~nq$oYUoUt@x0sZSx7?_O*2h&3obC{c~q6 zoV8%?y?0L-{*uSbtp3(5D)q}k>UuJsCf+_m~>XFZ`yzK6NPB5AI)^lknUuTSZ||* z^$++7^Rfx&dw~koRU7uda^jS`#dFzzO)Q+9uXSDaw7O3o+q1Q*n%-SK%ig78nOmi? zzre9^*e+rD76Dt=#q<7FS9SFfx5q0?YS|yw`+V(Zk5pHSFwcLBlS#i(g+ITp7(~I}<#~6%e7!cn9p(>H zmoO@AoOCPxc4;NdjeMc~a=Cm9usRGBqISI_Qt5fLnB=#~miY=LBt=l_0DI(h196@5 zHFVQCY%z#+_nv)Yi%Usk{4!9Sp;@un7NJ^84=Y?**{@ z@FOzmCqq~#$;!Yi3JvO<_>b=H?!PjwR-BNplYddm6>2br&onXB=QdKO$R%~5I7Rb+ z{2xmBJLBexciln0qn1BY!=usXLmdm2xWg1sxZwYmQodx7XGHGRhrXefFX*e$7#=I> zcLuof!X72^2BkbfBey8k{e@Zv5wch@gk^cyM_m|)+AvSBdg-fwe;RKpJRG20`ud-b ztI`idA6=IEhQw8etSZ4!LH2n&yuOervDSbNZ)A@9Lk;4bM~zx#s(K0%6;nASv`A%{lCl(;i}$X*|Ar* zsC?lQ<&~MN58;w!{Dsv{Zg$k%7{)uflqJo4&<-G+ON6y3Ck7&_E6N`yq4kP)67^?R zRG?%GY>Jejh{mmm#fav+O~ENbH10T-+Y#%dr@&tmUZipbrwGxw^sC=Aog=-Nbf<}G zD&2);DL6%l#wBA1Gr#;Fj#6Btu$jdTn=CwSCI(tmuIL^t?7teL?!vs{mTqzY6eh*s zrn0enm^dTLRzw_ literal 0 HcmV?d00001 diff --git a/examples/stm32u5/src/bin/ltdc.rs b/examples/stm32u5/src/bin/ltdc.rs new file mode 100644 index 000000000..5bf2cd67d --- /dev/null +++ b/examples/stm32u5/src/bin/ltdc.rs @@ -0,0 +1,462 @@ +#![no_std] +#![no_main] +#![macro_use] +#![allow(static_mut_refs)] + +/// This example was derived from examples\stm32h735\src\bin\ltdc.rs +/// It demonstrates the LTDC lcd display peripheral and was tested on an STM32U5G9J-DK2 demo board (embassy-stm32 feature "stm32u5g9zj" and probe-rs chip "STM32U5G9ZJTxQ") +/// +use bouncy_box::BouncyBox; +use defmt::{info, unwrap}; +use embassy_executor::Spawner; +use embassy_stm32::gpio::{Level, Output, Speed}; +use embassy_stm32::ltdc::{self, Ltdc, LtdcConfiguration, LtdcLayer, LtdcLayerConfig, PolarityActive, PolarityEdge}; +use embassy_stm32::{bind_interrupts, peripherals}; +use embassy_time::{Duration, Timer}; +use embedded_graphics::draw_target::DrawTarget; +use embedded_graphics::geometry::{OriginDimensions, Point, Size}; +use embedded_graphics::image::Image; +use embedded_graphics::pixelcolor::raw::RawU24; +use embedded_graphics::pixelcolor::Rgb888; +use embedded_graphics::prelude::*; +use embedded_graphics::primitives::Rectangle; +use embedded_graphics::Pixel; +use heapless::{Entry, FnvIndexMap}; +use tinybmp::Bmp; +use {defmt_rtt as _, panic_probe as _}; + +const DISPLAY_WIDTH: usize = 800; +const DISPLAY_HEIGHT: usize = 480; +const MY_TASK_POOL_SIZE: usize = 2; + +// the following two display buffers consume 261120 bytes that just about fits into axis ram found on the mcu +pub static mut FB1: [TargetPixelType; DISPLAY_WIDTH * DISPLAY_HEIGHT] = [0; DISPLAY_WIDTH * DISPLAY_HEIGHT]; +pub static mut FB2: [TargetPixelType; DISPLAY_WIDTH * DISPLAY_HEIGHT] = [0; DISPLAY_WIDTH * DISPLAY_HEIGHT]; + +bind_interrupts!(struct Irqs { + LTDC => ltdc::InterruptHandler; +}); + +const NUM_COLORS: usize = 256; + +#[embassy_executor::main] +async fn main(spawner: Spawner) { + let p = rcc_setup::stm32u5g9zj_init(); + + // enable ICACHE + embassy_stm32::pac::ICACHE.cr().write(|w| { + w.set_en(true); + }); + + // blink the led on another task + let led = Output::new(p.PD2, Level::High, Speed::Low); + unwrap!(spawner.spawn(led_task(led))); + + // numbers from STM32U5G9J-DK2.ioc + const RK050HR18H_HSYNC: u16 = 5; // Horizontal synchronization + const RK050HR18H_HBP: u16 = 8; // Horizontal back porch + const RK050HR18H_HFP: u16 = 8; // Horizontal front porch + const RK050HR18H_VSYNC: u16 = 5; // Vertical synchronization + const RK050HR18H_VBP: u16 = 8; // Vertical back porch + const RK050HR18H_VFP: u16 = 8; // Vertical front porch + + // NOTE: all polarities have to be reversed with respect to the STM32U5G9J-DK2 CubeMX parametrization + let ltdc_config = LtdcConfiguration { + active_width: DISPLAY_WIDTH as _, + active_height: DISPLAY_HEIGHT as _, + h_back_porch: RK050HR18H_HBP, + h_front_porch: RK050HR18H_HFP, + v_back_porch: RK050HR18H_VBP, + v_front_porch: RK050HR18H_VFP, + h_sync: RK050HR18H_HSYNC, + v_sync: RK050HR18H_VSYNC, + h_sync_polarity: PolarityActive::ActiveHigh, + v_sync_polarity: PolarityActive::ActiveHigh, + data_enable_polarity: PolarityActive::ActiveHigh, + pixel_clock_polarity: PolarityEdge::RisingEdge, + }; + + info!("init ltdc"); + let mut ltdc_de = Output::new(p.PD6, Level::Low, Speed::High); + let mut ltdc_disp_ctrl = Output::new(p.PE4, Level::Low, Speed::High); + let mut ltdc_bl_ctrl = Output::new(p.PE6, Level::Low, Speed::High); + let mut ltdc = Ltdc::new_with_pins( + p.LTDC, // PERIPHERAL + Irqs, // IRQS + p.PD3, // CLK + p.PE0, // HSYNC + p.PD13, // VSYNC + p.PB9, // B0 + p.PB2, // B1 + p.PD14, // B2 + p.PD15, // B3 + p.PD0, // B4 + p.PD1, // B5 + p.PE7, // B6 + p.PE8, // B7 + p.PC8, // G0 + p.PC9, // G1 + p.PE9, // G2 + p.PE10, // G3 + p.PE11, // G4 + p.PE12, // G5 + p.PE13, // G6 + p.PE14, // G7 + p.PC6, // R0 + p.PC7, // R1 + p.PE15, // R2 + p.PD8, // R3 + p.PD9, // R4 + p.PD10, // R5 + p.PD11, // R6 + p.PD12, // R7 + ); + ltdc.init(<dc_config); + ltdc_de.set_low(); + ltdc_bl_ctrl.set_high(); + ltdc_disp_ctrl.set_high(); + + // we only need to draw on one layer for this example (not to be confused with the double buffer) + info!("enable bottom layer"); + let layer_config = LtdcLayerConfig { + pixel_format: ltdc::PixelFormat::L8, // 1 byte per pixel + layer: LtdcLayer::Layer1, + window_x0: 0, + window_x1: DISPLAY_WIDTH as _, + window_y0: 0, + window_y1: DISPLAY_HEIGHT as _, + }; + + let ferris_bmp: Bmp = Bmp::from_slice(include_bytes!("./ferris.bmp")).unwrap(); + let color_map = build_color_lookup_map(&ferris_bmp); + let clut = build_clut(&color_map); + + // enable the bottom layer with a 256 color lookup table + ltdc.init_layer(&layer_config, Some(&clut)); + + // Safety: the DoubleBuffer controls access to the statically allocated frame buffers + // and it is the only thing that mutates their content + let mut double_buffer = DoubleBuffer::new( + unsafe { FB1.as_mut() }, + unsafe { FB2.as_mut() }, + layer_config, + color_map, + ); + + // this allows us to perform some simple animation for every frame + let mut bouncy_box = BouncyBox::new( + ferris_bmp.bounding_box(), + Rectangle::new(Point::zero(), Size::new(DISPLAY_WIDTH as u32, DISPLAY_HEIGHT as u32)), + 2, + ); + + loop { + // cpu intensive drawing to the buffer that is NOT currently being copied to the LCD screen + double_buffer.clear(); + let position = bouncy_box.next_point(); + let ferris = Image::new(&ferris_bmp, position); + unwrap!(ferris.draw(&mut double_buffer)); + + // perform async dma data transfer to the lcd screen + unwrap!(double_buffer.swap(&mut ltdc).await); + } +} + +/// builds the color look-up table from all unique colors found in the bitmap. This should be a 256 color indexed bitmap to work. +fn build_color_lookup_map(bmp: &Bmp) -> FnvIndexMap { + let mut color_map: FnvIndexMap = heapless::FnvIndexMap::new(); + let mut counter: u8 = 0; + + // add black to position 0 + color_map.insert(Rgb888::new(0, 0, 0).into_storage(), counter).unwrap(); + counter += 1; + + for Pixel(_point, color) in bmp.pixels() { + let raw = color.into_storage(); + if let Entry::Vacant(v) = color_map.entry(raw) { + v.insert(counter).expect("more than 256 colors detected"); + counter += 1; + } + } + color_map +} + +/// builds the color look-up table from the color map provided +fn build_clut(color_map: &FnvIndexMap) -> [ltdc::RgbColor; NUM_COLORS] { + let mut clut = [ltdc::RgbColor::default(); NUM_COLORS]; + for (color, index) in color_map.iter() { + let color = Rgb888::from(RawU24::new(*color)); + clut[*index as usize] = ltdc::RgbColor { + red: color.r(), + green: color.g(), + blue: color.b(), + }; + } + + clut +} + +#[embassy_executor::task(pool_size = MY_TASK_POOL_SIZE)] +async fn led_task(mut led: Output<'static>) { + let mut counter = 0; + loop { + info!("blink: {}", counter); + counter += 1; + + // on + led.set_low(); + Timer::after(Duration::from_millis(50)).await; + + // off + led.set_high(); + Timer::after(Duration::from_millis(450)).await; + } +} + +pub type TargetPixelType = u8; + +// A simple double buffer +pub struct DoubleBuffer { + buf0: &'static mut [TargetPixelType], + buf1: &'static mut [TargetPixelType], + is_buf0: bool, + layer_config: LtdcLayerConfig, + color_map: FnvIndexMap, +} + +impl DoubleBuffer { + pub fn new( + buf0: &'static mut [TargetPixelType], + buf1: &'static mut [TargetPixelType], + layer_config: LtdcLayerConfig, + color_map: FnvIndexMap, + ) -> Self { + Self { + buf0, + buf1, + is_buf0: true, + layer_config, + color_map, + } + } + + pub fn current(&mut self) -> (&FnvIndexMap, &mut [TargetPixelType]) { + if self.is_buf0 { + (&self.color_map, self.buf0) + } else { + (&self.color_map, self.buf1) + } + } + + pub async fn swap(&mut self, ltdc: &mut Ltdc<'_, T>) -> Result<(), ltdc::Error> { + let (_, buf) = self.current(); + let frame_buffer = buf.as_ptr(); + self.is_buf0 = !self.is_buf0; + ltdc.set_buffer(self.layer_config.layer, frame_buffer as *const _).await + } + + /// Clears the buffer + pub fn clear(&mut self) { + let (color_map, buf) = self.current(); + let black = Rgb888::new(0, 0, 0).into_storage(); + let color_index = color_map.get(&black).expect("no black found in the color map"); + + for a in buf.iter_mut() { + *a = *color_index; // solid black + } + } +} + +// Implement DrawTarget for +impl DrawTarget for DoubleBuffer { + type Color = Rgb888; + type Error = (); + + /// Draw a pixel + fn draw_iter(&mut self, pixels: I) -> Result<(), Self::Error> + where + I: IntoIterator>, + { + let size = self.size(); + let width = size.width as i32; + let height = size.height as i32; + let (color_map, buf) = self.current(); + + for pixel in pixels { + let Pixel(point, color) = pixel; + + if point.x >= 0 && point.y >= 0 && point.x < width && point.y < height { + let index = point.y * width + point.x; + let raw_color = color.into_storage(); + + match color_map.get(&raw_color) { + Some(x) => { + buf[index as usize] = *x; + } + None => panic!("color not found in color map: {}", raw_color), + }; + } else { + // Ignore invalid points + } + } + + Ok(()) + } +} + +impl OriginDimensions for DoubleBuffer { + /// Return the size of the display + fn size(&self) -> Size { + Size::new( + (self.layer_config.window_x1 - self.layer_config.window_x0) as _, + (self.layer_config.window_y1 - self.layer_config.window_y0) as _, + ) + } +} + +mod rcc_setup { + + use embassy_stm32::rcc; + use embassy_stm32::time::Hertz; + use embassy_stm32::{Config, Peripherals}; + + /// Sets up clocks for the stm32u5g9zj mcu + /// change this if you plan to use a different microcontroller + pub fn stm32u5g9zj_init() -> Peripherals { + // setup power and clocks for an STM32U5G9J-DK2 run from an external 16 Mhz external oscillator + let mut config = Config::default(); + config.rcc.hse = Some(rcc::Hse { + freq: Hertz(16_000_000), + mode: rcc::HseMode::Oscillator, + }); + config.rcc.pll1 = Some(rcc::Pll { + source: rcc::PllSource::HSE, + prediv: rcc::PllPreDiv::DIV1, + mul: rcc::PllMul::MUL10, + divp: None, + divq: None, + divr: Some(rcc::PllDiv::DIV1), + }); + config.rcc.sys = rcc::Sysclk::PLL1_R; // 160 Mhz + config.rcc.pll3 = Some(rcc::Pll { + source: rcc::PllSource::HSE, + prediv: rcc::PllPreDiv::DIV4, // PLL_M + mul: rcc::PllMul::MUL125, // PLL_N + divp: None, + divq: None, + divr: Some(rcc::PllDiv::DIV20), + }); + config.rcc.mux.ltdcsel = rcc::mux::Ltdcsel::PLL3_R; // 25 MHz + embassy_stm32::init(config) + } +} + +mod bouncy_box { + use embedded_graphics::geometry::Point; + use embedded_graphics::primitives::Rectangle; + + enum Direction { + DownLeft, + DownRight, + UpLeft, + UpRight, + } + + pub struct BouncyBox { + direction: Direction, + child_rect: Rectangle, + parent_rect: Rectangle, + current_point: Point, + move_by: usize, + } + + // This calculates the coordinates of a chile rectangle bounced around inside a parent bounded box + impl BouncyBox { + pub fn new(child_rect: Rectangle, parent_rect: Rectangle, move_by: usize) -> Self { + let center_box = parent_rect.center(); + let center_img = child_rect.center(); + let current_point = Point::new(center_box.x - center_img.x / 2, center_box.y - center_img.y / 2); + Self { + direction: Direction::DownRight, + child_rect, + parent_rect, + current_point, + move_by, + } + } + + pub fn next_point(&mut self) -> Point { + let direction = &self.direction; + let img_height = self.child_rect.size.height as i32; + let box_height = self.parent_rect.size.height as i32; + let img_width = self.child_rect.size.width as i32; + let box_width = self.parent_rect.size.width as i32; + let move_by = self.move_by as i32; + + match direction { + Direction::DownLeft => { + self.current_point.x -= move_by; + self.current_point.y += move_by; + + let x_out_of_bounds = self.current_point.x < 0; + let y_out_of_bounds = (self.current_point.y + img_height) > box_height; + + if x_out_of_bounds && y_out_of_bounds { + self.direction = Direction::UpRight + } else if x_out_of_bounds && !y_out_of_bounds { + self.direction = Direction::DownRight + } else if !x_out_of_bounds && y_out_of_bounds { + self.direction = Direction::UpLeft + } + } + Direction::DownRight => { + self.current_point.x += move_by; + self.current_point.y += move_by; + + let x_out_of_bounds = (self.current_point.x + img_width) > box_width; + let y_out_of_bounds = (self.current_point.y + img_height) > box_height; + + if x_out_of_bounds && y_out_of_bounds { + self.direction = Direction::UpLeft + } else if x_out_of_bounds && !y_out_of_bounds { + self.direction = Direction::DownLeft + } else if !x_out_of_bounds && y_out_of_bounds { + self.direction = Direction::UpRight + } + } + Direction::UpLeft => { + self.current_point.x -= move_by; + self.current_point.y -= move_by; + + let x_out_of_bounds = self.current_point.x < 0; + let y_out_of_bounds = self.current_point.y < 0; + + if x_out_of_bounds && y_out_of_bounds { + self.direction = Direction::DownRight + } else if x_out_of_bounds && !y_out_of_bounds { + self.direction = Direction::UpRight + } else if !x_out_of_bounds && y_out_of_bounds { + self.direction = Direction::DownLeft + } + } + Direction::UpRight => { + self.current_point.x += move_by; + self.current_point.y -= move_by; + + let x_out_of_bounds = (self.current_point.x + img_width) > box_width; + let y_out_of_bounds = self.current_point.y < 0; + + if x_out_of_bounds && y_out_of_bounds { + self.direction = Direction::DownLeft + } else if x_out_of_bounds && !y_out_of_bounds { + self.direction = Direction::UpLeft + } else if !x_out_of_bounds && y_out_of_bounds { + self.direction = Direction::DownRight + } + } + } + + self.current_point + } + } +} From d1db7d90434e7cf8d82361818427942c19923726 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Fri, 25 Oct 2024 18:53:59 +0200 Subject: [PATCH 0286/1217] Explain how to keep the executor awake --- docs/pages/faq.adoc | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/docs/pages/faq.adoc b/docs/pages/faq.adoc index 8eb947b5e..d4f49bfc1 100644 --- a/docs/pages/faq.adoc +++ b/docs/pages/faq.adoc @@ -372,3 +372,16 @@ Issues like these while implementing drivers often fall into one of the followin 3. Some kind of hardware errata, or some hardware misconfiguration like wrong clock speeds 4. Some issue with an interrupt handler, either enabling, disabling, or re-enabling of interrupts when necessary 5. Some kind of async issue, like not registering wakers fully before checking flags, or not registering or pending wakers at the right time + +== How can I prevent the thread-mode executor from going to sleep? == + +In some cases you might want to prevent the thread-mode executor from going to sleep, for example when doing so would result in current spikes that reduce analog performance. +As a workaround, you can spawn a task that yields in a loop, preventing the executor from going to sleep. Note that this may increase power consumption. + +[source,rust] +---- +#[embassy_executor::task] +async fn idle() { + loop { embassy_futures::yield_now().await; } +} +---- From 6545dfee6d370cd37701fbbbf85d46c1a8e34521 Mon Sep 17 00:00:00 2001 From: ckrenslehner Date: Fri, 25 Oct 2024 19:22:20 +0200 Subject: [PATCH 0287/1217] Update overview.adoc --- docs/pages/overview.adoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/pages/overview.adoc b/docs/pages/overview.adoc index 2ebc85f6d..8f97d937f 100644 --- a/docs/pages/overview.adoc +++ b/docs/pages/overview.adoc @@ -52,7 +52,7 @@ link:https://github.com/embassy-rs/embassy/tree/main/embassy-boot[embassy-boot] == What is DMA? -For most I/O in embedded devices, the peripheral doesn't directly support the transmission of multiple bits at once, with CAN being a notable exception. Instead, the MCU must write each byte, one at a time, and then wait until the peripheral is ready to send the next. For high I/O rates, this can pose a problem if the MCU must devote an increasing portion of its time handling each byte. The solution to this problem is to use the Direct Memory Access controller. +For most I/O in embedded devices, the peripheral doesn't directly support the transmission of multiple bytes at once, with CAN being a notable exception. Instead, the MCU must write each byte, one at a time, and then wait until the peripheral is ready to send the next. For high I/O rates, this can pose a problem if the MCU must devote an increasing portion of its time handling each byte. The solution to this problem is to use the Direct Memory Access controller. The Direct Memory Access controller (DMA) is a controller that is present in MCUs that Embassy supports, including stm32 and nrf. The DMA allows the MCU to set up a transfer, either send or receive, and then wait for the transfer to complete. With DMA, once started, no MCU intervention is required until the transfer is complete, meaning that the MCU can perform other computation, or set up other I/O while the transfer is in progress. For high I/O rates, DMA can cut the time that the MCU spends handling I/O by over half. However, because DMA is more complex to set-up, it is less widely used in the embedded community. Embassy aims to change that by making DMA the first choice rather than the last. Using Embassy, there's no additional tuning required once I/O rates increase because your application is already set-up to handle them. @@ -80,4 +80,4 @@ For more reading material on async Rust and Embassy: Videos: -* link:https://www.youtube.com/watch?v=wni5h5vIPhU[From Zero to Async in Embedded Rust] \ No newline at end of file +* link:https://www.youtube.com/watch?v=wni5h5vIPhU[From Zero to Async in Embedded Rust] From 2c05ac5262eb2beaa043818f02d82b656f272b4f Mon Sep 17 00:00:00 2001 From: ckrenslehner Date: Fri, 25 Oct 2024 20:36:46 +0200 Subject: [PATCH 0288/1217] Update embassy Cargo.toml section in new_project.adoc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Embassy is already published to crates.io 🾠--- docs/pages/new_project.adoc | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/docs/pages/new_project.adoc b/docs/pages/new_project.adoc index 821bcbd27..fa4c2e359 100644 --- a/docs/pages/new_project.adoc +++ b/docs/pages/new_project.adoc @@ -73,16 +73,28 @@ Now that cargo knows what target to compile for (and probe-rs knows what chip to Looking in `examples/stm32g4/Cargo.toml`, we can see that the examples require a number of embassy crates. For blinky, we’ll only need three of them: `embassy-stm32`, `embassy-executor` and `embassy-time`. -At the time of writing, the latest version of embassy isn‘t available on crates.io, so we need to install it straight from the git repository. The recommended way of doing so is as follows: + +At the time of writing, embassy is already published to crates.io. Therefore, dependencies can easily added via Cargo.toml. + +[source,toml] +---- +[dependencies] +embassy-stm32 = { version = "0.1.0", features = ["defmt", "time-driver-any", "stm32g474re", "memory-x", "unstable-pac", "exti"] } +embassy-executor = { version = "0.6.1", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-time = { version = "0.3.2", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +---- + +Prior embassy needed to be installed straight from the git repository. This can is still useful, if you want to checkout a specic revision of an embassy crate which is not yet published. +The recommended way of doing so is as follows: * Copy the required `embassy-*` lines from the example `Cargo.toml` * Make any necessary changes to `features`, e.g. requiring the `stm32g474re` feature of `embassy-stm32` * Remove the `path = ""` keys in the `embassy-*` entries * Create a `[patch.crates-io]` section, with entries for each embassy crate we need. These should all contain identical values: a link to the git repository, and a reference to the commit we’re checking out. Assuming you want the latest commit, you can find it by running `git ls-remote https://github.com/embassy-rs/embassy.git HEAD` -NOTE: When using this method, it’s necessary that the `version` keys in `[dependencies]` match up with the versions defined in each crate’s `Cargo.toml` in the specificed `rev` under `[patch.crates.io]`. This means that when updating, you have to a pick a new revision, change everything in `[patch.crates.io]` to match it, and then correct any versions under `[dependencies]` which have changed. Hopefully this will no longer be necessary once embassy is released on crates.io! +NOTE: When using this method, it’s necessary that the `version` keys in `[dependencies]` match up with the versions defined in each crate’s `Cargo.toml` in the specificed `rev` under `[patch.crates.io]`. This means that when updating, you have to a pick a new revision, change everything in `[patch.crates.io]` to match it, and then correct any versions under `[dependencies]` which have changed. -At the time of writing, this method produces the following results: +An example Cargo.toml file might look as follows: [source,toml] ---- From 3d0921ffc4afb49b5d28277a02cee55fcec08881 Mon Sep 17 00:00:00 2001 From: ckrenslehner Date: Fri, 25 Oct 2024 20:41:51 +0200 Subject: [PATCH 0289/1217] fix spelling --- docs/pages/new_project.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/pages/new_project.adoc b/docs/pages/new_project.adoc index fa4c2e359..38cea044b 100644 --- a/docs/pages/new_project.adoc +++ b/docs/pages/new_project.adoc @@ -84,7 +84,7 @@ embassy-executor = { version = "0.6.1", features = ["nightly", "arch-cortex-m", embassy-time = { version = "0.3.2", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } ---- -Prior embassy needed to be installed straight from the git repository. This can is still useful, if you want to checkout a specic revision of an embassy crate which is not yet published. +Prior, embassy needed to be installed straight from the git repository. Installing from git is still useful, if you want to checkout a specic revision of an embassy crate which is not yet published. The recommended way of doing so is as follows: * Copy the required `embassy-*` lines from the example `Cargo.toml` From edac7cc6304c724c9626f73a35a22b074588c012 Mon Sep 17 00:00:00 2001 From: dvdsk Date: Sat, 26 Oct 2024 12:38:10 +0200 Subject: [PATCH 0290/1217] stm32/uart remove DmaUnsynced from public api Its an internal error which should never be exposed. It should only occur with wrong driver implementations. We log to the user and return an Overrun error since handling DmaUnsynced as an Overrun will resolve it. --- embassy-stm32/src/dma/ringbuffer/mod.rs | 4 ++++ embassy-stm32/src/usart/mod.rs | 2 -- embassy-stm32/src/usart/ringbuffered.rs | 9 ++++++++- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/embassy-stm32/src/dma/ringbuffer/mod.rs b/embassy-stm32/src/dma/ringbuffer/mod.rs index 12d418414..0da8c374f 100644 --- a/embassy-stm32/src/dma/ringbuffer/mod.rs +++ b/embassy-stm32/src/dma/ringbuffer/mod.rs @@ -21,6 +21,10 @@ pub trait DmaCtrl { #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum Error { Overrun, + /// the newly read DMA positions don't make sense compared to the previous + /// ones. This can usually only occur due to wrong Driver implementation, if + /// the driver author (or the user using raw metapac code) directly resets + /// the channel for instance. DmaUnsynced, } diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index 86c94789a..aaf7b41e6 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -260,8 +260,6 @@ pub enum Error { Parity, /// Buffer too large for DMA BufferTooLong, - // TODO: ask what this is and document it (dvdsk) - DmaUnsynced, } enum ReadCompletionEvent { diff --git a/embassy-stm32/src/usart/ringbuffered.rs b/embassy-stm32/src/usart/ringbuffered.rs index f1914e1bf..a791ac2a9 100644 --- a/embassy-stm32/src/usart/ringbuffered.rs +++ b/embassy-stm32/src/usart/ringbuffered.rs @@ -268,7 +268,14 @@ impl ReadReady for RingBufferedUartRx<'_> { fn read_ready(&mut self) -> Result { let len = self.ring_buf.len().map_err(|e| match e { crate::dma::ringbuffer::Error::Overrun => Self::Error::Overrun, - crate::dma::ringbuffer::Error::DmaUnsynced => Self::Error::DmaUnsynced, + crate::dma::ringbuffer::Error::DmaUnsynced => { + error!( + "Ringbuffer error: DmaUNsynced, driver implementation is + probably bugged please open an issue" + ); + // we report this as overrun since its recoverable in the same way + Self::Error::Overrun + } })?; Ok(len > 0) } From ca6bcb4250fc294c2294265fbc83bf00398e089c Mon Sep 17 00:00:00 2001 From: Haobo Gu Date: Sat, 26 Oct 2024 23:41:30 +0800 Subject: [PATCH 0291/1217] feat(ospi): add ospi example Signed-off-by: Haobo Gu --- embassy-stm32/src/ospi/mod.rs | 9 +- .../stm32h7/src/bin/ospi_memory_mapped.rs | 435 ++++++++++++++++++ 2 files changed, 437 insertions(+), 7 deletions(-) create mode 100644 examples/stm32h7/src/bin/ospi_memory_mapped.rs diff --git a/embassy-stm32/src/ospi/mod.rs b/embassy-stm32/src/ospi/mod.rs index 7ccafe361..f8ef66216 100644 --- a/embassy-stm32/src/ospi/mod.rs +++ b/embassy-stm32/src/ospi/mod.rs @@ -180,7 +180,7 @@ pub struct Ospi<'d, T: Instance, M: PeriMode> { impl<'d, T: Instance, M: PeriMode> Ospi<'d, T, M> { /// Enter memory mode. - /// The Input `TransferConfig` is used to configure the read operation in memory mode + /// The Input `read_config` is used to configure the read operation in memory mode pub fn enable_memory_mapped_mode( &mut self, read_config: TransferConfig, @@ -190,9 +190,7 @@ impl<'d, T: Instance, M: PeriMode> Ospi<'d, T, M> { self.configure_command(&read_config, None)?; let reg = T::REGS; - while reg.sr().read().busy() { - info!("wait ospi busy"); - } + while reg.sr().read().busy() {} reg.ccr().modify(|r| { r.set_dqse(false); @@ -229,9 +227,6 @@ impl<'d, T: Instance, M: PeriMode> Ospi<'d, T, M> { /// Quit from memory mapped mode pub fn disable_memory_mapped_mode(&mut self) { let reg = T::REGS; - while reg.sr().read().busy() { - info!("wait ospi busy"); - } reg.cr().modify(|r| { r.set_fmode(crate::ospi::vals::FunctionalMode::INDIRECTWRITE); diff --git a/examples/stm32h7/src/bin/ospi_memory_mapped.rs b/examples/stm32h7/src/bin/ospi_memory_mapped.rs new file mode 100644 index 000000000..40f39f751 --- /dev/null +++ b/examples/stm32h7/src/bin/ospi_memory_mapped.rs @@ -0,0 +1,435 @@ +#![no_main] +#![no_std] + +// Tested on weact stm32h7b0 board + w25q64 spi flash + +use defmt::info; +use defmt_rtt as _; +use embassy_executor::Spawner; +use embassy_stm32::{ + gpio::{Level, Output, Speed}, + mode::Blocking, + ospi::{AddressSize, DummyCycles, Instance, Ospi, OspiWidth, TransferConfig}, + ospi::{ChipSelectHighTime, FIFOThresholdLevel, MemorySize, MemoryType, WrapSize}, + time::Hertz, + Config, +}; +use embassy_time::Timer; +use panic_probe as _; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + // RCC config + let mut config = Config::default(); + info!("START"); + { + use embassy_stm32::rcc::*; + config.rcc.hsi = Some(HSIPrescaler::DIV1); + config.rcc.csi = true; + // Needed for USB + config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); + // External oscillator 25MHZ + config.rcc.hse = Some(Hse { + freq: Hertz(25_000_000), + mode: HseMode::Oscillator, + }); + config.rcc.pll1 = Some(Pll { + source: PllSource::HSE, + prediv: PllPreDiv::DIV5, + mul: PllMul::MUL112, + divp: Some(PllDiv::DIV2), + divq: Some(PllDiv::DIV2), + divr: Some(PllDiv::DIV2), + }); + config.rcc.sys = Sysclk::PLL1_P; + config.rcc.ahb_pre = AHBPrescaler::DIV2; + config.rcc.apb1_pre = APBPrescaler::DIV2; + config.rcc.apb2_pre = APBPrescaler::DIV2; + config.rcc.apb3_pre = APBPrescaler::DIV2; + config.rcc.apb4_pre = APBPrescaler::DIV2; + config.rcc.voltage_scale = VoltageScale::Scale0; + } + + // Initialize peripherals + let p = embassy_stm32::init(config); + + let qspi_config = embassy_stm32::ospi::Config { + fifo_threshold: FIFOThresholdLevel::_16Bytes, + memory_type: MemoryType::Micron, + device_size: MemorySize::_8MiB, + chip_select_high_time: ChipSelectHighTime::_1Cycle, + free_running_clock: false, + clock_mode: false, + wrap_size: WrapSize::None, + clock_prescaler: 2, + sample_shifting: true, + delay_hold_quarter_cycle: false, + chip_select_boundary: 0, + delay_block_bypass: true, + max_transfer: 0, + refresh: 0, + }; + let ospi = embassy_stm32::ospi::Ospi::new_blocking_quadspi( + p.OCTOSPI1, + p.PB2, + p.PD11, + p.PD12, + p.PE2, + p.PD13, + p.PB6, + qspi_config, + ); + + let mut flash = FlashMemory::new(ospi).await; + + let flash_id = flash.read_id(); + info!("FLASH ID: {=[u8]:x}", flash_id); + let mut wr_buf = [0u8; 8]; + for i in 0..8 { + wr_buf[i] = i as u8; + } + let mut rd_buf = [0u8; 8]; + flash.erase_sector(0).await; + flash.write_memory(0, &wr_buf, true).await; + flash.read_memory(0, &mut rd_buf, true); + info!("WRITE BUF: {=[u8]:#X}", wr_buf); + info!("READ BUF: {=[u8]:#X}", rd_buf); + info!("Enabling memory mapped mode"); + flash.enable_mm().await; + + let first_u32 = unsafe { *(0x90000000 as *const u32) }; + assert_eq!(first_u32, 0x03020100); + + let second_u32 = unsafe { *(0x90000004 as *const u32) }; + assert_eq!(second_u32, 0x07060504); + flash.disable_mm().await; + + info!("DONE"); + // Output pin PE3 + let mut led = Output::new(p.PE3, Level::Low, Speed::Low); + + loop { + led.toggle(); + Timer::after_millis(1000).await; + } +} + +const MEMORY_PAGE_SIZE: usize = 8; + +const CMD_QUAD_READ: u8 = 0x6B; + +const CMD_QUAD_WRITE_PG: u8 = 0x32; + +const CMD_READ_ID: u8 = 0x9F; +const CMD_READ_UUID: u8 = 0x4B; + +const CMD_ENABLE_RESET: u8 = 0x66; +const CMD_RESET: u8 = 0x99; + +const CMD_WRITE_ENABLE: u8 = 0x06; + +const CMD_CHIP_ERASE: u8 = 0xC7; +const CMD_SECTOR_ERASE: u8 = 0x20; +const CMD_BLOCK_ERASE_32K: u8 = 0x52; +const CMD_BLOCK_ERASE_64K: u8 = 0xD8; + +const CMD_READ_SR: u8 = 0x05; +const CMD_READ_CR: u8 = 0x35; + +const CMD_WRITE_SR: u8 = 0x01; +const CMD_WRITE_CR: u8 = 0x31; + +/// Implementation of access to flash chip. +/// Chip commands are hardcoded as it depends on used chip. +/// This implementation is using chip GD25Q64C from Giga Device +pub struct FlashMemory { + ospi: Ospi<'static, I, Blocking>, +} + +impl FlashMemory { + pub async fn new(ospi: Ospi<'static, I, Blocking>) -> Self { + let mut memory = Self { ospi }; + + memory.reset_memory().await; + memory.enable_quad(); + memory + } + + async fn qpi_mode(&mut self) { + // Enter qpi mode + self.exec_command(0x38).await; + + // Set read param + let transaction = TransferConfig { + iwidth: OspiWidth::QUAD, + dwidth: OspiWidth::QUAD, + instruction: Some(0xC0), + ..Default::default() + }; + self.enable_write().await; + self.ospi.blocking_write(&[0x30_u8], transaction).unwrap(); + self.wait_write_finish(); + } + + pub async fn disable_mm(&mut self) { + self.ospi.disable_memory_mapped_mode(); + } + + pub async fn enable_mm(&mut self) { + self.qpi_mode().await; + + let read_config = TransferConfig { + iwidth: OspiWidth::QUAD, + isize: AddressSize::_8Bit, + adwidth: OspiWidth::QUAD, + adsize: AddressSize::_24bit, + dwidth: OspiWidth::QUAD, + instruction: Some(0x0B), // Fast read in QPI mode + dummy: DummyCycles::_8, + ..Default::default() + }; + + let write_config = TransferConfig { + iwidth: OspiWidth::SING, + isize: AddressSize::_8Bit, + adwidth: OspiWidth::SING, + adsize: AddressSize::_24bit, + dwidth: OspiWidth::QUAD, + instruction: Some(0x32), // Write config + dummy: DummyCycles::_0, + ..Default::default() + }; + self.ospi.enable_memory_mapped_mode(read_config, write_config).unwrap(); + } + + fn enable_quad(&mut self) { + let cr = self.read_cr(); + // info!("Read cr: {:x}", cr); + self.write_cr(cr | 0x02); + // info!("Read cr after writing: {:x}", cr); + } + + pub fn disable_quad(&mut self) { + let cr = self.read_cr(); + self.write_cr(cr & (!(0x02))); + } + + async fn exec_command_4(&mut self, cmd: u8) { + let transaction = TransferConfig { + iwidth: OspiWidth::QUAD, + adwidth: OspiWidth::NONE, + // adsize: AddressSize::_24bit, + dwidth: OspiWidth::NONE, + instruction: Some(cmd as u32), + address: None, + dummy: DummyCycles::_0, + ..Default::default() + }; + self.ospi.command(&transaction).await.unwrap(); + } + + async fn exec_command(&mut self, cmd: u8) { + let transaction = TransferConfig { + iwidth: OspiWidth::SING, + adwidth: OspiWidth::NONE, + // adsize: AddressSize::_24bit, + dwidth: OspiWidth::NONE, + instruction: Some(cmd as u32), + address: None, + dummy: DummyCycles::_0, + ..Default::default() + }; + // info!("Excuting command: {:x}", transaction.instruction); + self.ospi.command(&transaction).await.unwrap(); + } + + pub async fn reset_memory(&mut self) { + self.exec_command_4(CMD_ENABLE_RESET).await; + self.exec_command_4(CMD_RESET).await; + self.exec_command(CMD_ENABLE_RESET).await; + self.exec_command(CMD_RESET).await; + self.wait_write_finish(); + } + + pub async fn enable_write(&mut self) { + self.exec_command(CMD_WRITE_ENABLE).await; + } + + pub fn read_id(&mut self) -> [u8; 3] { + let mut buffer = [0; 3]; + let transaction: TransferConfig = TransferConfig { + iwidth: OspiWidth::SING, + isize: AddressSize::_8Bit, + adwidth: OspiWidth::NONE, + // adsize: AddressSize::_24bit, + dwidth: OspiWidth::SING, + instruction: Some(CMD_READ_ID as u32), + ..Default::default() + }; + // info!("Reading id: 0x{:X}", transaction.instruction); + self.ospi.blocking_read(&mut buffer, transaction).unwrap(); + buffer + } + + pub fn read_id_4(&mut self) -> [u8; 3] { + let mut buffer = [0; 3]; + let transaction: TransferConfig = TransferConfig { + iwidth: OspiWidth::SING, + isize: AddressSize::_8Bit, + adwidth: OspiWidth::NONE, + dwidth: OspiWidth::QUAD, + instruction: Some(CMD_READ_ID as u32), + ..Default::default() + }; + info!("Reading id: 0x{:X}", transaction.instruction); + self.ospi.blocking_read(&mut buffer, transaction).unwrap(); + buffer + } + + pub fn read_memory(&mut self, addr: u32, buffer: &mut [u8], use_dma: bool) { + let transaction = TransferConfig { + iwidth: OspiWidth::SING, + adwidth: OspiWidth::SING, + adsize: AddressSize::_24bit, + dwidth: OspiWidth::QUAD, + instruction: Some(CMD_QUAD_READ as u32), + address: Some(addr), + dummy: DummyCycles::_8, + ..Default::default() + }; + if use_dma { + self.ospi.blocking_read(buffer, transaction).unwrap(); + } else { + self.ospi.blocking_read(buffer, transaction).unwrap(); + } + } + + fn wait_write_finish(&mut self) { + while (self.read_sr() & 0x01) != 0 {} + } + + async fn perform_erase(&mut self, addr: u32, cmd: u8) { + let transaction = TransferConfig { + iwidth: OspiWidth::SING, + adwidth: OspiWidth::SING, + adsize: AddressSize::_24bit, + dwidth: OspiWidth::NONE, + instruction: Some(cmd as u32), + address: Some(addr), + dummy: DummyCycles::_0, + ..Default::default() + }; + self.enable_write().await; + self.ospi.command(&transaction).await.unwrap(); + self.wait_write_finish(); + } + + pub async fn erase_sector(&mut self, addr: u32) { + self.perform_erase(addr, CMD_SECTOR_ERASE).await; + } + + pub async fn erase_block_32k(&mut self, addr: u32) { + self.perform_erase(addr, CMD_BLOCK_ERASE_32K).await; + } + + pub async fn erase_block_64k(&mut self, addr: u32) { + self.perform_erase(addr, CMD_BLOCK_ERASE_64K).await; + } + + pub async fn erase_chip(&mut self) { + self.exec_command(CMD_CHIP_ERASE).await; + } + + async fn write_page(&mut self, addr: u32, buffer: &[u8], len: usize, use_dma: bool) { + assert!( + (len as u32 + (addr & 0x000000ff)) <= MEMORY_PAGE_SIZE as u32, + "write_page(): page write length exceeds page boundary (len = {}, addr = {:X}", + len, + addr + ); + + let transaction = TransferConfig { + iwidth: OspiWidth::SING, + adsize: AddressSize::_24bit, + adwidth: OspiWidth::SING, + dwidth: OspiWidth::QUAD, + instruction: Some(CMD_QUAD_WRITE_PG as u32), + address: Some(addr), + dummy: DummyCycles::_0, + ..Default::default() + }; + self.enable_write().await; + if use_dma { + self.ospi.blocking_write(buffer, transaction).unwrap(); + } else { + self.ospi.blocking_write(buffer, transaction).unwrap(); + } + self.wait_write_finish(); + } + + pub async fn write_memory(&mut self, addr: u32, buffer: &[u8], use_dma: bool) { + let mut left = buffer.len(); + let mut place = addr; + let mut chunk_start = 0; + + while left > 0 { + let max_chunk_size = MEMORY_PAGE_SIZE - (place & 0x000000ff) as usize; + let chunk_size = if left >= max_chunk_size { max_chunk_size } else { left }; + let chunk = &buffer[chunk_start..(chunk_start + chunk_size)]; + self.write_page(place, chunk, chunk_size, use_dma).await; + place += chunk_size as u32; + left -= chunk_size; + chunk_start += chunk_size; + } + } + + fn read_register(&mut self, cmd: u8) -> u8 { + let mut buffer = [0; 1]; + let transaction: TransferConfig = TransferConfig { + iwidth: OspiWidth::SING, + isize: AddressSize::_8Bit, + adwidth: OspiWidth::NONE, + adsize: AddressSize::_24bit, + dwidth: OspiWidth::SING, + instruction: Some(cmd as u32), + address: None, + dummy: DummyCycles::_0, + ..Default::default() + }; + self.ospi.blocking_read(&mut buffer, transaction).unwrap(); + // info!("Read w25q64 register: 0x{:x}", buffer[0]); + buffer[0] + } + + fn write_register(&mut self, cmd: u8, value: u8) { + let buffer = [value; 1]; + let transaction: TransferConfig = TransferConfig { + iwidth: OspiWidth::SING, + isize: AddressSize::_8Bit, + instruction: Some(cmd as u32), + adsize: AddressSize::_24bit, + adwidth: OspiWidth::NONE, + dwidth: OspiWidth::SING, + address: None, + dummy: DummyCycles::_0, + ..Default::default() + }; + self.ospi.blocking_write(&buffer, transaction).unwrap(); + } + + pub fn read_sr(&mut self) -> u8 { + self.read_register(CMD_READ_SR) + } + + pub fn read_cr(&mut self) -> u8 { + self.read_register(CMD_READ_CR) + } + + pub fn write_sr(&mut self, value: u8) { + self.write_register(CMD_WRITE_SR, value); + } + + pub fn write_cr(&mut self, value: u8) { + self.write_register(CMD_WRITE_CR, value); + } +} From 04c9130d326990dc92577f2ed4b2dc927efe2c13 Mon Sep 17 00:00:00 2001 From: Haobo Gu Date: Sat, 26 Oct 2024 23:50:16 +0800 Subject: [PATCH 0292/1217] feat(example): move ospi memory mapped example for stm32h7b0 to separate folder Signed-off-by: Haobo Gu --- examples/stm32h7b0/.cargo/config.toml | 8 ++ examples/stm32h7b0/Cargo.toml | 74 +++++++++++++++++++ examples/stm32h7b0/build.rs | 35 +++++++++ examples/stm32h7b0/memory.x | 5 ++ .../src/bin/ospi_memory_mapped.rs | 5 +- 5 files changed, 124 insertions(+), 3 deletions(-) create mode 100644 examples/stm32h7b0/.cargo/config.toml create mode 100644 examples/stm32h7b0/Cargo.toml create mode 100644 examples/stm32h7b0/build.rs create mode 100644 examples/stm32h7b0/memory.x rename examples/{stm32h7 => stm32h7b0}/src/bin/ospi_memory_mapped.rs (99%) diff --git a/examples/stm32h7b0/.cargo/config.toml b/examples/stm32h7b0/.cargo/config.toml new file mode 100644 index 000000000..870849a27 --- /dev/null +++ b/examples/stm32h7b0/.cargo/config.toml @@ -0,0 +1,8 @@ +[target.thumbv7em-none-eabihf] +runner = 'probe-rs run --chip STM32H7B0VBTx' + +[build] +target = "thumbv7em-none-eabihf" # Cortex-M4F and Cortex-M7F (with FPU) + +[env] +DEFMT_LOG = "trace" diff --git a/examples/stm32h7b0/Cargo.toml b/examples/stm32h7b0/Cargo.toml new file mode 100644 index 000000000..02c620443 --- /dev/null +++ b/examples/stm32h7b0/Cargo.toml @@ -0,0 +1,74 @@ +[package] +edition = "2021" +name = "embassy-stm32h7b0-examples" +version = "0.1.0" +license = "MIT OR Apache-2.0" + +[dependencies] +embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h7b0vb", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } +embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } +embassy-executor = { version = "0.6.1", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } +embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } +embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } + +defmt = "0.3" +defmt-rtt = "0.4" + +cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } +cortex-m-rt = "0.7.0" +embedded-hal = "0.2.6" +embedded-hal-1 = { package = "embedded-hal", version = "1.0" } +embedded-hal-async = { version = "1.0" } +embedded-nal-async = "0.8.0" +embedded-io-async = { version = "0.6.1" } +panic-probe = { version = "0.3", features = ["print-defmt"] } +heapless = { version = "0.8", default-features = false } +rand_core = "0.6.3" +critical-section = "1.1" +micromath = "2.0.0" +stm32-fmc = "0.3.0" +embedded-storage = "0.3.1" +static_cell = "2" +chrono = { version = "^0.4", default-features = false } +grounded = "0.2.0" + +# cargo build/run +[profile.dev] +codegen-units = 1 +debug = 2 +debug-assertions = true # <- +incremental = false +opt-level = 3 # <- +overflow-checks = true # <- + +# cargo test +[profile.test] +codegen-units = 1 +debug = 2 +debug-assertions = true # <- +incremental = false +opt-level = 3 # <- +overflow-checks = true # <- + +# cargo build/run --release +[profile.release] +codegen-units = 1 +debug = 2 +debug-assertions = false # <- +incremental = false +lto = 'fat' +opt-level = 3 # <- +overflow-checks = false # <- + +# cargo test --release +[profile.bench] +codegen-units = 1 +debug = 2 +debug-assertions = false # <- +incremental = false +lto = 'fat' +opt-level = 3 # <- +overflow-checks = false # <- diff --git a/examples/stm32h7b0/build.rs b/examples/stm32h7b0/build.rs new file mode 100644 index 000000000..30691aa97 --- /dev/null +++ b/examples/stm32h7b0/build.rs @@ -0,0 +1,35 @@ +//! This build script copies the `memory.x` file from the crate root into +//! a directory where the linker can always find it at build time. +//! For many projects this is optional, as the linker always searches the +//! project root directory -- wherever `Cargo.toml` is. However, if you +//! are using a workspace or have a more complicated build setup, this +//! build script becomes required. Additionally, by requesting that +//! Cargo re-run the build script whenever `memory.x` is changed, +//! updating `memory.x` ensures a rebuild of the application with the +//! new memory settings. + +use std::env; +use std::fs::File; +use std::io::Write; +use std::path::PathBuf; + +fn main() { + // Put `memory.x` in our output directory and ensure it's + // on the linker search path. + let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); + File::create(out.join("memory.x")) + .unwrap() + .write_all(include_bytes!("memory.x")) + .unwrap(); + println!("cargo:rustc-link-search={}", out.display()); + + // By default, Cargo will re-run a build script whenever + // any file in the project changes. By specifying `memory.x` + // here, we ensure the build script is only re-run when + // `memory.x` is changed. + println!("cargo:rerun-if-changed=memory.x"); + + println!("cargo:rustc-link-arg-bins=--nmagic"); + println!("cargo:rustc-link-arg-bins=-Tlink.x"); + println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); +} diff --git a/examples/stm32h7b0/memory.x b/examples/stm32h7b0/memory.x new file mode 100644 index 000000000..6eb1bb7c1 --- /dev/null +++ b/examples/stm32h7b0/memory.x @@ -0,0 +1,5 @@ +MEMORY +{ + FLASH : ORIGIN = 0x08000000, LENGTH = 128K /* BANK_1 */ + RAM : ORIGIN = 0x24000000, LENGTH = 512K /* SRAM */ +} \ No newline at end of file diff --git a/examples/stm32h7/src/bin/ospi_memory_mapped.rs b/examples/stm32h7b0/src/bin/ospi_memory_mapped.rs similarity index 99% rename from examples/stm32h7/src/bin/ospi_memory_mapped.rs rename to examples/stm32h7b0/src/bin/ospi_memory_mapped.rs index 40f39f751..e32a22e41 100644 --- a/examples/stm32h7/src/bin/ospi_memory_mapped.rs +++ b/examples/stm32h7b0/src/bin/ospi_memory_mapped.rs @@ -61,7 +61,7 @@ async fn main(_spawner: Spawner) { free_running_clock: false, clock_mode: false, wrap_size: WrapSize::None, - clock_prescaler: 2, + clock_prescaler: 4, sample_shifting: true, delay_hold_quarter_cycle: false, chip_select_boundary: 0, @@ -94,8 +94,8 @@ async fn main(_spawner: Spawner) { flash.read_memory(0, &mut rd_buf, true); info!("WRITE BUF: {=[u8]:#X}", wr_buf); info!("READ BUF: {=[u8]:#X}", rd_buf); - info!("Enabling memory mapped mode"); flash.enable_mm().await; + info!("Enabled memory mapped mode"); let first_u32 = unsafe { *(0x90000000 as *const u32) }; assert_eq!(first_u32, 0x03020100); @@ -121,7 +121,6 @@ const CMD_QUAD_READ: u8 = 0x6B; const CMD_QUAD_WRITE_PG: u8 = 0x32; const CMD_READ_ID: u8 = 0x9F; -const CMD_READ_UUID: u8 = 0x4B; const CMD_ENABLE_RESET: u8 = 0x66; const CMD_RESET: u8 = 0x99; From 3b5284d99d7054ac42e5d3e065fc1d27527f823a Mon Sep 17 00:00:00 2001 From: Haobo Gu Date: Sat, 26 Oct 2024 23:51:38 +0800 Subject: [PATCH 0293/1217] fix: fmt code Signed-off-by: Haobo Gu --- .../stm32h7b0/src/bin/ospi_memory_mapped.rs | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/examples/stm32h7b0/src/bin/ospi_memory_mapped.rs b/examples/stm32h7b0/src/bin/ospi_memory_mapped.rs index e32a22e41..9c397e507 100644 --- a/examples/stm32h7b0/src/bin/ospi_memory_mapped.rs +++ b/examples/stm32h7b0/src/bin/ospi_memory_mapped.rs @@ -4,18 +4,17 @@ // Tested on weact stm32h7b0 board + w25q64 spi flash use defmt::info; -use defmt_rtt as _; use embassy_executor::Spawner; -use embassy_stm32::{ - gpio::{Level, Output, Speed}, - mode::Blocking, - ospi::{AddressSize, DummyCycles, Instance, Ospi, OspiWidth, TransferConfig}, - ospi::{ChipSelectHighTime, FIFOThresholdLevel, MemorySize, MemoryType, WrapSize}, - time::Hertz, - Config, +use embassy_stm32::gpio::{Level, Output, Speed}; +use embassy_stm32::mode::Blocking; +use embassy_stm32::ospi::{ + AddressSize, ChipSelectHighTime, DummyCycles, FIFOThresholdLevel, Instance, MemorySize, MemoryType, Ospi, + OspiWidth, TransferConfig, WrapSize, }; +use embassy_stm32::time::Hertz; +use embassy_stm32::Config; use embassy_time::Timer; -use panic_probe as _; +use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] async fn main(_spawner: Spawner) { From 66205fdd859b4c8607d0b6be9e4fcb27e8096493 Mon Sep 17 00:00:00 2001 From: Georges Palauqui Date: Sun, 27 Oct 2024 09:50:57 +0100 Subject: [PATCH 0294/1217] update spi_display example for rp --- examples/rp/Cargo.toml | 8 +- examples/rp/src/bin/spi_display.rs | 163 +++-------------------------- 2 files changed, 18 insertions(+), 153 deletions(-) diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index 6a2c99716..b55b20c63 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml @@ -37,10 +37,10 @@ cortex-m = { version = "0.7.6", features = ["inline-asm"] } cortex-m-rt = "0.7.0" critical-section = "1.1" panic-probe = { version = "0.3", features = ["print-defmt"] } -display-interface-spi = "0.4.1" -embedded-graphics = "0.7.1" -st7789 = "0.6.1" -display-interface = "0.4.1" +display-interface-spi = "0.5.0" +embedded-graphics = "0.8.1" +mipidsi = "0.8.0" +display-interface = "0.5.0" byte-slice-cast = { version = "1.2.0", default-features = false } smart-leds = "0.4.0" heapless = "0.8" diff --git a/examples/rp/src/bin/spi_display.rs b/examples/rp/src/bin/spi_display.rs index e937b9d0a..dd114a4ae 100644 --- a/examples/rp/src/bin/spi_display.rs +++ b/examples/rp/src/bin/spi_display.rs @@ -9,11 +9,12 @@ use core::cell::RefCell; use defmt::*; +use display_interface_spi::SPIInterface; use embassy_embedded_hal::shared_bus::blocking::spi::SpiDeviceWithConfig; use embassy_executor::Spawner; use embassy_rp::gpio::{Level, Output}; use embassy_rp::spi; -use embassy_rp::spi::{Blocking, Spi}; +use embassy_rp::spi::Spi; use embassy_sync::blocking_mutex::raw::NoopRawMutex; use embassy_sync::blocking_mutex::Mutex; use embassy_time::Delay; @@ -24,10 +25,11 @@ use embedded_graphics::pixelcolor::Rgb565; use embedded_graphics::prelude::*; use embedded_graphics::primitives::{PrimitiveStyleBuilder, Rectangle}; use embedded_graphics::text::Text; -use st7789::{Orientation, ST7789}; +use mipidsi::models::ST7789; +use mipidsi::options::{Orientation, Rotation}; +use mipidsi::Builder; use {defmt_rtt as _, panic_probe as _}; -use crate::my_display_interface::SPIDeviceInterface; use crate::touch::Touch; const DISPLAY_FREQ: u32 = 64_000_000; @@ -58,7 +60,7 @@ async fn main(_spawner: Spawner) { touch_config.phase = spi::Phase::CaptureOnSecondTransition; touch_config.polarity = spi::Polarity::IdleHigh; - let spi: Spi<'_, _, Blocking> = Spi::new_blocking(p.SPI1, clk, mosi, miso, touch_config.clone()); + let spi = Spi::new_blocking(p.SPI1, clk, mosi, miso, touch_config.clone()); let spi_bus: Mutex = Mutex::new(RefCell::new(spi)); let display_spi = SpiDeviceWithConfig::new(&spi_bus, Output::new(display_cs, Level::High), display_config); @@ -74,17 +76,15 @@ async fn main(_spawner: Spawner) { let _bl = Output::new(bl, Level::High); // display interface abstraction from SPI and DC - let di = SPIDeviceInterface::new(display_spi, dcx); - - // create driver - let mut display = ST7789::new(di, rst, 240, 320); - - // initialize - display.init(&mut Delay).unwrap(); - - // set default orientation - display.set_orientation(Orientation::Landscape).unwrap(); + let di = SPIInterface::new(display_spi, dcx); + // Define the display from the display interface and initialize it + let mut display = Builder::new(ST7789, di) + .display_size(240, 320) + .reset_pin(rst) + .orientation(Orientation::new().rotate(Rotation::Deg90)) + .init(&mut Delay) + .unwrap(); display.clear(Rgb565::BLACK).unwrap(); let raw_image_data = ImageRawLE::new(include_bytes!("../../assets/ferris.raw"), 86); @@ -175,138 +175,3 @@ mod touch { } } } - -mod my_display_interface { - use display_interface::{DataFormat, DisplayError, WriteOnlyDataCommand}; - use embedded_hal_1::digital::OutputPin; - use embedded_hal_1::spi::SpiDevice; - - /// SPI display interface. - /// - /// This combines the SPI peripheral and a data/command pin - pub struct SPIDeviceInterface { - spi: SPI, - dc: DC, - } - - impl SPIDeviceInterface - where - SPI: SpiDevice, - DC: OutputPin, - { - /// Create new SPI interface for communciation with a display driver - pub fn new(spi: SPI, dc: DC) -> Self { - Self { spi, dc } - } - } - - impl WriteOnlyDataCommand for SPIDeviceInterface - where - SPI: SpiDevice, - DC: OutputPin, - { - fn send_commands(&mut self, cmds: DataFormat<'_>) -> Result<(), DisplayError> { - // 1 = data, 0 = command - self.dc.set_low().map_err(|_| DisplayError::DCError)?; - - send_u8(&mut self.spi, cmds).map_err(|_| DisplayError::BusWriteError)?; - Ok(()) - } - - fn send_data(&mut self, buf: DataFormat<'_>) -> Result<(), DisplayError> { - // 1 = data, 0 = command - self.dc.set_high().map_err(|_| DisplayError::DCError)?; - - send_u8(&mut self.spi, buf).map_err(|_| DisplayError::BusWriteError)?; - Ok(()) - } - } - - fn send_u8(spi: &mut T, words: DataFormat<'_>) -> Result<(), T::Error> { - match words { - DataFormat::U8(slice) => spi.write(slice), - DataFormat::U16(slice) => { - use byte_slice_cast::*; - spi.write(slice.as_byte_slice()) - } - DataFormat::U16LE(slice) => { - use byte_slice_cast::*; - for v in slice.as_mut() { - *v = v.to_le(); - } - spi.write(slice.as_byte_slice()) - } - DataFormat::U16BE(slice) => { - use byte_slice_cast::*; - for v in slice.as_mut() { - *v = v.to_be(); - } - spi.write(slice.as_byte_slice()) - } - DataFormat::U8Iter(iter) => { - let mut buf = [0; 32]; - let mut i = 0; - - for v in iter.into_iter() { - buf[i] = v; - i += 1; - - if i == buf.len() { - spi.write(&buf)?; - i = 0; - } - } - - if i > 0 { - spi.write(&buf[..i])?; - } - - Ok(()) - } - DataFormat::U16LEIter(iter) => { - use byte_slice_cast::*; - let mut buf = [0; 32]; - let mut i = 0; - - for v in iter.map(u16::to_le) { - buf[i] = v; - i += 1; - - if i == buf.len() { - spi.write(&buf.as_byte_slice())?; - i = 0; - } - } - - if i > 0 { - spi.write(&buf[..i].as_byte_slice())?; - } - - Ok(()) - } - DataFormat::U16BEIter(iter) => { - use byte_slice_cast::*; - let mut buf = [0; 64]; - let mut i = 0; - let len = buf.len(); - - for v in iter.map(u16::to_be) { - buf[i] = v; - i += 1; - - if i == len { - spi.write(&buf.as_byte_slice())?; - i = 0; - } - } - - if i > 0 { - spi.write(&buf[..i].as_byte_slice())?; - } - - Ok(()) - } - _ => unimplemented!(), - } - } -} From 7733b99e0960d41d7b7d88f4d94adb6b21eb17b4 Mon Sep 17 00:00:00 2001 From: Georges Palauqui Date: Sun, 27 Oct 2024 09:53:00 +0100 Subject: [PATCH 0295/1217] update spi_display example for rp23 --- examples/rp23/Cargo.toml | 8 +- examples/rp23/src/bin/spi_display.rs | 161 +++------------------------ 2 files changed, 17 insertions(+), 152 deletions(-) diff --git a/examples/rp23/Cargo.toml b/examples/rp23/Cargo.toml index 5527a1e0a..eec12a9ab 100644 --- a/examples/rp23/Cargo.toml +++ b/examples/rp23/Cargo.toml @@ -38,10 +38,10 @@ cortex-m = { version = "0.7.6", features = ["inline-asm"] } cortex-m-rt = "0.7.0" critical-section = "1.1" panic-probe = { version = "0.3", features = ["print-defmt"] } -display-interface-spi = "0.4.1" -embedded-graphics = "0.7.1" -st7789 = "0.6.1" -display-interface = "0.4.1" +display-interface-spi = "0.5.0" +embedded-graphics = "0.8.1" +mipidsi = "0.8.0" +display-interface = "0.5.0" byte-slice-cast = { version = "1.2.0", default-features = false } smart-leds = "0.3.0" heapless = "0.8" diff --git a/examples/rp23/src/bin/spi_display.rs b/examples/rp23/src/bin/spi_display.rs index 195db5a97..6b7c0781f 100644 --- a/examples/rp23/src/bin/spi_display.rs +++ b/examples/rp23/src/bin/spi_display.rs @@ -1,4 +1,4 @@ -//! This example shows how to use SPI (Serial Peripheral Interface) in the RP2040 chip. +//! This example shows how to use SPI (Serial Peripheral Interface) in the RP2350 chip. //! //! Example written for a display using the ST7789 chip. Possibly the Waveshare Pico-ResTouch //! (https://www.waveshare.com/wiki/Pico-ResTouch-LCD-2.8) @@ -9,6 +9,7 @@ use core::cell::RefCell; use defmt::*; +use display_interface_spi::SPIInterface; use embassy_embedded_hal::shared_bus::blocking::spi::SpiDeviceWithConfig; use embassy_executor::Spawner; use embassy_rp::block::ImageDef; @@ -25,14 +26,15 @@ use embedded_graphics::pixelcolor::Rgb565; use embedded_graphics::prelude::*; use embedded_graphics::primitives::{PrimitiveStyleBuilder, Rectangle}; use embedded_graphics::text::Text; -use st7789::{Orientation, ST7789}; +use mipidsi::models::ST7789; +use mipidsi::options::{Orientation, Rotation}; +use mipidsi::Builder; use {defmt_rtt as _, panic_probe as _}; #[link_section = ".start_block"] #[used] pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); -use crate::my_display_interface::SPIDeviceInterface; use crate::touch::Touch; const DISPLAY_FREQ: u32 = 64_000_000; @@ -79,17 +81,15 @@ async fn main(_spawner: Spawner) { let _bl = Output::new(bl, Level::High); // display interface abstraction from SPI and DC - let di = SPIDeviceInterface::new(display_spi, dcx); - - // create driver - let mut display = ST7789::new(di, rst, 240, 320); - - // initialize - display.init(&mut Delay).unwrap(); - - // set default orientation - display.set_orientation(Orientation::Landscape).unwrap(); + let di = SPIInterface::new(display_spi, dcx); + // Define the display from the display interface and initialize it + let mut display = Builder::new(ST7789, di) + .display_size(240, 320) + .reset_pin(rst) + .orientation(Orientation::new().rotate(Rotation::Deg90)) + .init(&mut Delay) + .unwrap(); display.clear(Rgb565::BLACK).unwrap(); let raw_image_data = ImageRawLE::new(include_bytes!("../../assets/ferris.raw"), 86); @@ -180,138 +180,3 @@ mod touch { } } } - -mod my_display_interface { - use display_interface::{DataFormat, DisplayError, WriteOnlyDataCommand}; - use embedded_hal_1::digital::OutputPin; - use embedded_hal_1::spi::SpiDevice; - - /// SPI display interface. - /// - /// This combines the SPI peripheral and a data/command pin - pub struct SPIDeviceInterface { - spi: SPI, - dc: DC, - } - - impl SPIDeviceInterface - where - SPI: SpiDevice, - DC: OutputPin, - { - /// Create new SPI interface for communciation with a display driver - pub fn new(spi: SPI, dc: DC) -> Self { - Self { spi, dc } - } - } - - impl WriteOnlyDataCommand for SPIDeviceInterface - where - SPI: SpiDevice, - DC: OutputPin, - { - fn send_commands(&mut self, cmds: DataFormat<'_>) -> Result<(), DisplayError> { - // 1 = data, 0 = command - self.dc.set_low().map_err(|_| DisplayError::DCError)?; - - send_u8(&mut self.spi, cmds).map_err(|_| DisplayError::BusWriteError)?; - Ok(()) - } - - fn send_data(&mut self, buf: DataFormat<'_>) -> Result<(), DisplayError> { - // 1 = data, 0 = command - self.dc.set_high().map_err(|_| DisplayError::DCError)?; - - send_u8(&mut self.spi, buf).map_err(|_| DisplayError::BusWriteError)?; - Ok(()) - } - } - - fn send_u8(spi: &mut T, words: DataFormat<'_>) -> Result<(), T::Error> { - match words { - DataFormat::U8(slice) => spi.write(slice), - DataFormat::U16(slice) => { - use byte_slice_cast::*; - spi.write(slice.as_byte_slice()) - } - DataFormat::U16LE(slice) => { - use byte_slice_cast::*; - for v in slice.as_mut() { - *v = v.to_le(); - } - spi.write(slice.as_byte_slice()) - } - DataFormat::U16BE(slice) => { - use byte_slice_cast::*; - for v in slice.as_mut() { - *v = v.to_be(); - } - spi.write(slice.as_byte_slice()) - } - DataFormat::U8Iter(iter) => { - let mut buf = [0; 32]; - let mut i = 0; - - for v in iter.into_iter() { - buf[i] = v; - i += 1; - - if i == buf.len() { - spi.write(&buf)?; - i = 0; - } - } - - if i > 0 { - spi.write(&buf[..i])?; - } - - Ok(()) - } - DataFormat::U16LEIter(iter) => { - use byte_slice_cast::*; - let mut buf = [0; 32]; - let mut i = 0; - - for v in iter.map(u16::to_le) { - buf[i] = v; - i += 1; - - if i == buf.len() { - spi.write(&buf.as_byte_slice())?; - i = 0; - } - } - - if i > 0 { - spi.write(&buf[..i].as_byte_slice())?; - } - - Ok(()) - } - DataFormat::U16BEIter(iter) => { - use byte_slice_cast::*; - let mut buf = [0; 64]; - let mut i = 0; - let len = buf.len(); - - for v in iter.map(u16::to_be) { - buf[i] = v; - i += 1; - - if i == len { - spi.write(&buf.as_byte_slice())?; - i = 0; - } - } - - if i > 0 { - spi.write(&buf[..i].as_byte_slice())?; - } - - Ok(()) - } - _ => unimplemented!(), - } - } -} From 917f1d1f4de6f7e25f483561001a9b5b36cbce7e Mon Sep 17 00:00:00 2001 From: Emil Fresk Date: Sun, 27 Oct 2024 09:55:00 +0100 Subject: [PATCH 0296/1217] This fixes 2 issues where STM32 BXCAN would hang 1. If one received frames under an `interrupt_free` section, in my case `init` in RTIC, the RX IRQ will fire and clear it's enable bit after `interrupt_free` is complete. There is no frame to read so RX is now unconditionally disabled forever. 2. On clearing of RX IRQ, TX stops silently. This happens due to the use of `write` instead of `modify` when modifying IRQ enable bits. Solution 1: Enable RX IRQs on every call to `try_read` that return no data. This solution also solves the issue of very delayed handling of the RX IRQ which would cause the same issue. Solution 2: Use `modify` instead of `write`. --- embassy-stm32/src/can/bxcan/mod.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/embassy-stm32/src/can/bxcan/mod.rs b/embassy-stm32/src/can/bxcan/mod.rs index baa4bee79..19f1cea29 100644 --- a/embassy-stm32/src/can/bxcan/mod.rs +++ b/embassy-stm32/src/can/bxcan/mod.rs @@ -893,7 +893,7 @@ impl RxMode { RxFifo::Fifo0 => 0usize, RxFifo::Fifo1 => 1usize, }; - T::regs().ier().write(|w| { + T::regs().ier().modify(|w| { w.set_fmpie(fifo_idx, false); }); waker.wake(); @@ -936,18 +936,22 @@ impl RxMode { Self::NonBuffered(_) => { let registers = &info.regs; if let Some(msg) = registers.receive_fifo(RxFifo::Fifo0) { - registers.0.ier().write(|w| { + registers.0.ier().modify(|w| { w.set_fmpie(0, true); }); Ok(msg) } else if let Some(msg) = registers.receive_fifo(RxFifo::Fifo1) { - registers.0.ier().write(|w| { + registers.0.ier().modify(|w| { w.set_fmpie(1, true); }); Ok(msg) } else if let Some(err) = registers.curr_error() { Err(TryReadError::BusError(err)) } else { + registers.0.ier().modify(|w| { + w.set_fmpie(0, true); + w.set_fmpie(1, true); + }); Err(TryReadError::Empty) } } From edd36382958f006667c32627c2afae24f1861892 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sun, 27 Oct 2024 19:21:38 +0100 Subject: [PATCH 0297/1217] Add examples/stm32h7b0 to CI --- ci.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/ci.sh b/ci.sh index b04a4b288..9f7a7a037 100755 --- a/ci.sh +++ b/ci.sh @@ -216,6 +216,7 @@ cargo batch \ --- build --release --manifest-path examples/stm32g4/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32g4 \ --- build --release --manifest-path examples/stm32h5/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/stm32h5 \ --- build --release --manifest-path examples/stm32h7/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32h7 \ + --- build --release --manifest-path examples/stm32h7b0/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32h7b0 \ --- build --release --manifest-path examples/stm32h735/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32h735 \ --- build --release --manifest-path examples/stm32h755cm4/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32h755cm4 \ --- build --release --manifest-path examples/stm32h755cm7/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32h755cm7 \ From ca8e885dbb65541a380e66c678ae148c24782e8e Mon Sep 17 00:00:00 2001 From: Connor <10554880+meigs2@users.noreply.github.com> Date: Sun, 27 Oct 2024 17:41:15 -0500 Subject: [PATCH 0298/1217] Add tx_dma to async spi --- embassy-rp/src/spi.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/embassy-rp/src/spi.rs b/embassy-rp/src/spi.rs index b89df74a2..a8f4e72c7 100644 --- a/embassy-rp/src/spi.rs +++ b/embassy-rp/src/spi.rs @@ -359,17 +359,18 @@ impl<'d, T: Instance> Spi<'d, T, Async> { inner: impl Peripheral

+ 'd, clk: impl Peripheral

+ 'd> + 'd, miso: impl Peripheral

+ 'd> + 'd, + tx_dma: impl Peripheral

+ 'd, rx_dma: impl Peripheral

+ 'd, config: Config, ) -> Self { - into_ref!(rx_dma, clk, miso); + into_ref!(tx_dma, rx_dma, clk, miso); Self::new_inner( inner, Some(clk.map_into()), None, Some(miso.map_into()), None, - None, + Some(tx_dma.map_into()), Some(rx_dma.map_into()), config, ) From bfff50a3619be3a9fbc052a70b2e43c95cc5dc42 Mon Sep 17 00:00:00 2001 From: William <174336620+williams-one@users.noreply.github.com> Date: Mon, 28 Oct 2024 08:40:38 +0100 Subject: [PATCH 0299/1217] Fix format --- examples/stm32u5/src/bin/ltdc.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/examples/stm32u5/src/bin/ltdc.rs b/examples/stm32u5/src/bin/ltdc.rs index 5bf2cd67d..bd59a9148 100644 --- a/examples/stm32u5/src/bin/ltdc.rs +++ b/examples/stm32u5/src/bin/ltdc.rs @@ -316,9 +316,8 @@ impl OriginDimensions for DoubleBuffer { mod rcc_setup { - use embassy_stm32::rcc; use embassy_stm32::time::Hertz; - use embassy_stm32::{Config, Peripherals}; + use embassy_stm32::{rcc, Config, Peripherals}; /// Sets up clocks for the stm32u5g9zj mcu /// change this if you plan to use a different microcontroller From 76606b6fe040d0735ab8a0e9ac99894de06264c4 Mon Sep 17 00:00:00 2001 From: William <174336620+williams-one@users.noreply.github.com> Date: Mon, 28 Oct 2024 08:46:07 +0100 Subject: [PATCH 0300/1217] Update chip from stm32u585ai to stm32u5g9zj and fix pinout --- examples/stm32u5/.cargo/config.toml | 4 ++-- examples/stm32u5/Cargo.toml | 4 ++-- examples/stm32u5/src/bin/i2c.rs | 2 +- examples/stm32u5/src/bin/usb_serial.rs | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/examples/stm32u5/.cargo/config.toml b/examples/stm32u5/.cargo/config.toml index 36c5b63a6..bdbd86354 100644 --- a/examples/stm32u5/.cargo/config.toml +++ b/examples/stm32u5/.cargo/config.toml @@ -1,6 +1,6 @@ [target.'cfg(all(target_arch = "arm", target_os = "none"))'] -# replace STM32U585AIIx with your chip as listed in `probe-rs chip list` -runner = "probe-rs run --chip STM32U585AIIx" +# replace STM32U5G9ZJTxQ with your chip as listed in `probe-rs chip list` +runner = "probe-rs run --chip STM32U5G9ZJTxQ" [build] target = "thumbv8m.main-none-eabihf" diff --git a/examples/stm32u5/Cargo.toml b/examples/stm32u5/Cargo.toml index f594ad71a..8b576425c 100644 --- a/examples/stm32u5/Cargo.toml +++ b/examples/stm32u5/Cargo.toml @@ -5,8 +5,8 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -# Change stm32u585ai to your chip name, if necessary. -embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "unstable-pac", "stm32u585ai", "time-driver-any", "memory-x" ] } +# Change stm32u5g9zj to your chip name, if necessary. +embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "unstable-pac", "stm32u5g9zj", "time-driver-any", "memory-x" ] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.6.1", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } diff --git a/examples/stm32u5/src/bin/i2c.rs b/examples/stm32u5/src/bin/i2c.rs index 19a78eac9..d5f5d6f60 100644 --- a/examples/stm32u5/src/bin/i2c.rs +++ b/examples/stm32u5/src/bin/i2c.rs @@ -13,7 +13,7 @@ const WHOAMI: u8 = 0x0F; #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_stm32::init(Default::default()); - let mut i2c = I2c::new_blocking(p.I2C2, p.PH4, p.PH5, Hertz(100_000), Default::default()); + let mut i2c = I2c::new_blocking(p.I2C2, p.PF1, p.PF0, Hertz(100_000), Default::default()); let mut data = [0u8; 1]; unwrap!(i2c.blocking_write_read(HTS221_ADDRESS, &[WHOAMI], &mut data)); diff --git a/examples/stm32u5/src/bin/usb_serial.rs b/examples/stm32u5/src/bin/usb_serial.rs index 4d56395da..4bb1a6079 100644 --- a/examples/stm32u5/src/bin/usb_serial.rs +++ b/examples/stm32u5/src/bin/usb_serial.rs @@ -13,7 +13,7 @@ use embassy_usb::Builder; use panic_probe as _; bind_interrupts!(struct Irqs { - OTG_FS => usb::InterruptHandler; + OTG_HS => usb::InterruptHandler; }); #[embassy_executor::main] @@ -48,7 +48,7 @@ async fn main(_spawner: Spawner) { // to enable vbus_detection to comply with the USB spec. If you enable it, the board // has to support it or USB won't work at all. See docs on `vbus_detection` for details. config.vbus_detection = false; - let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); + let driver = Driver::new_hs(p.USB_OTG_HS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); // Create embassy-usb Config let mut config = embassy_usb::Config::new(0xc0de, 0xcafe); From 5db6b4874def68a5cd1fe25e75327cf0abdbaa59 Mon Sep 17 00:00:00 2001 From: Dion Dokter Date: Tue, 29 Oct 2024 17:13:09 +0100 Subject: [PATCH 0301/1217] Expose async functions for QSPI --- embassy-stm32/src/qspi/mod.rs | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/embassy-stm32/src/qspi/mod.rs b/embassy-stm32/src/qspi/mod.rs index 308947e99..715c260e9 100644 --- a/embassy-stm32/src/qspi/mod.rs +++ b/embassy-stm32/src/qspi/mod.rs @@ -353,6 +353,21 @@ impl<'d, T: Instance> Qspi<'d, T, Async> { /// Blocking read data, using DMA. pub fn blocking_read_dma(&mut self, buf: &mut [u8], transaction: TransferConfig) { + let transfer = self.start_read_transfer(transaction, buf); + transfer.blocking_wait(); + } + + /// Blocking read data, using DMA. + pub async fn read_dma(&mut self, buf: &mut [u8], transaction: TransferConfig) { + let transfer = self.start_read_transfer(transaction, buf); + transfer.await; + } + + fn start_read_transfer<'a>( + &'a mut self, + transaction: TransferConfig, + buf: &'a mut [u8], + ) -> crate::dma::Transfer<'a> { self.setup_transaction(QspiMode::IndirectWrite, &transaction, Some(buf.len())); T::REGS.ccr().modify(|v| { @@ -373,12 +388,22 @@ impl<'d, T: Instance> Qspi<'d, T, Async> { // STM32H7 does not have dmaen #[cfg(not(stm32h7))] T::REGS.cr().modify(|v| v.set_dmaen(true)); - - transfer.blocking_wait(); + transfer } /// Blocking write data, using DMA. pub fn blocking_write_dma(&mut self, buf: &[u8], transaction: TransferConfig) { + let transfer = self.start_write_transfer(transaction, buf); + transfer.blocking_wait(); + } + + /// Async write data, using DMA. + pub async fn write_dma(&mut self, buf: &[u8], transaction: TransferConfig) { + let transfer = self.start_write_transfer(transaction, buf); + transfer.await; + } + + fn start_write_transfer<'a>(&'a mut self, transaction: TransferConfig, buf: &'a [u8]) -> crate::dma::Transfer<'a> { self.setup_transaction(QspiMode::IndirectWrite, &transaction, Some(buf.len())); T::REGS.ccr().modify(|v| { @@ -395,8 +420,7 @@ impl<'d, T: Instance> Qspi<'d, T, Async> { // STM32H7 does not have dmaen #[cfg(not(stm32h7))] T::REGS.cr().modify(|v| v.set_dmaen(true)); - - transfer.blocking_wait(); + transfer } } From 2d899a17e727a9b68ce01090b412c8211f055293 Mon Sep 17 00:00:00 2001 From: Dion Dokter Date: Tue, 29 Oct 2024 17:26:35 +0100 Subject: [PATCH 0302/1217] Add some sanity checks --- embassy-stm32/src/qspi/mod.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/embassy-stm32/src/qspi/mod.rs b/embassy-stm32/src/qspi/mod.rs index 715c260e9..6530b75b1 100644 --- a/embassy-stm32/src/qspi/mod.rs +++ b/embassy-stm32/src/qspi/mod.rs @@ -202,6 +202,18 @@ impl<'d, T: Instance, M: PeriMode> Qspi<'d, T, M> { } fn setup_transaction(&mut self, fmode: QspiMode, transaction: &TransferConfig, data_len: Option) { + if let (Some(_), QspiWidth::NONE) = (transaction.address, transaction.awidth) { + panic!("QSPI address can't be sent with an address width of NONE"); + } + + if let (Some(_), QspiWidth::NONE) = (data_len, transaction.dwidth) { + panic!("QSPI data can't be sent with a data width of NONE"); + } + + if let Some(0) = data_len { + panic!("QSPI data must be at least one byte"); + } + T::REGS.fcr().modify(|v| { v.set_csmf(true); v.set_ctcf(true); From 9fdfe5e99bfd28c18af287e6351d556ff5458025 Mon Sep 17 00:00:00 2001 From: Dion Dokter Date: Tue, 29 Oct 2024 17:50:46 +0100 Subject: [PATCH 0303/1217] Fix typo --- embassy-stm32/src/qspi/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/src/qspi/mod.rs b/embassy-stm32/src/qspi/mod.rs index 6530b75b1..40c064d57 100644 --- a/embassy-stm32/src/qspi/mod.rs +++ b/embassy-stm32/src/qspi/mod.rs @@ -369,7 +369,7 @@ impl<'d, T: Instance> Qspi<'d, T, Async> { transfer.blocking_wait(); } - /// Blocking read data, using DMA. + /// Async read data, using DMA. pub async fn read_dma(&mut self, buf: &mut [u8], transaction: TransferConfig) { let transfer = self.start_read_transfer(transaction, buf); transfer.await; From 28b1e0a98baaaacb72fc44255a9fdad7af35763b Mon Sep 17 00:00:00 2001 From: Frostie314159 Date: Tue, 29 Oct 2024 23:05:50 +0100 Subject: [PATCH 0304/1217] Reexported some smoltcp types for raw socket. --- embassy-net/src/raw.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-net/src/raw.rs b/embassy-net/src/raw.rs index ace325a46..0169606d5 100644 --- a/embassy-net/src/raw.rs +++ b/embassy-net/src/raw.rs @@ -5,10 +5,10 @@ use core::mem; use core::task::{Context, Poll}; use embassy_net_driver::Driver; -use smoltcp::iface::{Interface, SocketHandle}; +pub use smoltcp::iface::{Interface, SocketHandle}; use smoltcp::socket::raw; pub use smoltcp::socket::raw::PacketMetadata; -use smoltcp::wire::{IpProtocol, IpVersion}; +pub use smoltcp::wire::{IpProtocol, IpVersion}; use crate::Stack; From a3bbb3b43abd61ce86d6cd7b949a115f243e5dba Mon Sep 17 00:00:00 2001 From: Dion Dokter Date: Tue, 29 Oct 2024 23:35:28 +0100 Subject: [PATCH 0305/1217] Add check for the flipside of the coin too --- embassy-stm32/src/qspi/mod.rs | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/embassy-stm32/src/qspi/mod.rs b/embassy-stm32/src/qspi/mod.rs index 40c064d57..10b1cbc70 100644 --- a/embassy-stm32/src/qspi/mod.rs +++ b/embassy-stm32/src/qspi/mod.rs @@ -202,16 +202,19 @@ impl<'d, T: Instance, M: PeriMode> Qspi<'d, T, M> { } fn setup_transaction(&mut self, fmode: QspiMode, transaction: &TransferConfig, data_len: Option) { - if let (Some(_), QspiWidth::NONE) = (transaction.address, transaction.awidth) { - panic!("QSPI address can't be sent with an address width of NONE"); + match (transaction.address, transaction.awidth) { + (Some(_), QspiWidth::NONE) => panic!("QSPI address can't be sent with an address width of NONE"), + (Some(_), _) => {} + (None, QspiWidth::NONE) => {} + (None, _) => panic!("QSPI address is not set, so the address width should be NONE"), } - if let (Some(_), QspiWidth::NONE) = (data_len, transaction.dwidth) { - panic!("QSPI data can't be sent with a data width of NONE"); - } - - if let Some(0) = data_len { - panic!("QSPI data must be at least one byte"); + match (data_len, transaction.dwidth) { + (Some(0), _) => panic!("QSPI data must be at least one byte"), + (Some(_), QspiWidth::NONE) => panic!("QSPI data can't be sent with a data width of NONE"), + (Some(_), _) => {} + (None, QspiWidth::NONE) => {} + (None, _) => panic!("QSPI data is empty, so the data width should be NONE"), } T::REGS.fcr().modify(|v| { From 117d091ea1dd7aac410e6d26492866f9d20d3ec6 Mon Sep 17 00:00:00 2001 From: Frostie314159 Date: Wed, 30 Oct 2024 12:30:48 +0100 Subject: [PATCH 0306/1217] Made import private again. --- embassy-net/src/raw.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-net/src/raw.rs b/embassy-net/src/raw.rs index 0169606d5..1f725d00b 100644 --- a/embassy-net/src/raw.rs +++ b/embassy-net/src/raw.rs @@ -5,7 +5,7 @@ use core::mem; use core::task::{Context, Poll}; use embassy_net_driver::Driver; -pub use smoltcp::iface::{Interface, SocketHandle}; +use smoltcp::iface::{Interface, SocketHandle}; use smoltcp::socket::raw; pub use smoltcp::socket::raw::PacketMetadata; pub use smoltcp::wire::{IpProtocol, IpVersion}; From 93dd21042ceadea114b01c40a250d33402672569 Mon Sep 17 00:00:00 2001 From: flippette Date: Thu, 31 Oct 2024 22:14:11 +0200 Subject: [PATCH 0307/1217] Implement `embedded_io::Write` for `Uart<'d, T: Instance, Blocking>` (#3483) * Implement `embedded_io::{Read,Write}` for `Uart<'d, T: Instance, Blocking>` * Unimplement `embedded_io::Read` for `Uart<'d, T: Instance, Blocking>` * Revert "Unimplement `embedded_io::Read` for `Uart<'d, T: Instance, Blocking>`" * Unimplement `embedded_io::Read` for `Uart<'d, T: Instance, Blocking>` (take 2) --- embassy-rp/src/uart/mod.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/embassy-rp/src/uart/mod.rs b/embassy-rp/src/uart/mod.rs index c94e5e185..ad98a46c7 100644 --- a/embassy-rp/src/uart/mod.rs +++ b/embassy-rp/src/uart/mod.rs @@ -1264,6 +1264,20 @@ impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::Write for Uart<'d, T, M> } } +impl<'d, T: Instance> embedded_io::ErrorType for Uart<'d, T, Blocking> { + type Error = Error; +} + +impl<'d, T: Instance> embedded_io::Write for Uart<'d, T, Blocking> { + fn write(&mut self, buf: &[u8]) -> Result { + self.blocking_write(buf).map(|_| buf.len()) + } + + fn flush(&mut self) -> Result<(), Self::Error> { + self.blocking_flush() + } +} + trait SealedMode {} trait SealedInstance { From 3225848bd2e1ffd7fdc7df08d8262f5e6164409f Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 31 Oct 2024 21:26:40 +0100 Subject: [PATCH 0308/1217] rp/pio: ensure PADS IE=1 which is not the default in rp235x. Fixes #3476 --- embassy-rp/src/pio/mod.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/embassy-rp/src/pio/mod.rs b/embassy-rp/src/pio/mod.rs index 72aa8f104..98f4f8943 100644 --- a/embassy-rp/src/pio/mod.rs +++ b/embassy-rp/src/pio/mod.rs @@ -1054,9 +1054,17 @@ impl<'d, PIO: Instance> Common<'d, PIO> { pub fn make_pio_pin(&mut self, pin: impl Peripheral

+ 'd) -> Pin<'d, PIO> { into_ref!(pin); pin.gpio().ctrl().write(|w| w.set_funcsel(PIO::FUNCSEL as _)); - #[cfg(feature = "_rp235x")] - pin.pad_ctrl().modify(|w| { + pin.pad_ctrl().write(|w| { + #[cfg(feature = "_rp235x")] w.set_iso(false); + w.set_schmitt(true); + w.set_slewfast(false); + // TODO rp235x errata E9 recommends to not enable IE if we're not + // going to use input. Maybe add an API for the user to enable/disable this? + w.set_ie(true); + w.set_od(false); + w.set_pue(false); + w.set_pde(false); }); // we can be relaxed about this because we're &mut here and nothing is cached PIO::state().used_pins.fetch_or(1 << pin.pin_bank(), Ordering::Relaxed); From 70214fc2c23aded1f5a1b8a62425ac3aa581102f Mon Sep 17 00:00:00 2001 From: Anthony Grondin <104731965+AnthonyGrondin@users.noreply.github.com> Date: Thu, 31 Oct 2024 16:20:01 -0400 Subject: [PATCH 0309/1217] feat(embassy-net): Implement `TcpReader::wait_read_ready()` + `TcpWriter::wait_send_ready()` --- embassy-net/src/tcp.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/embassy-net/src/tcp.rs b/embassy-net/src/tcp.rs index a00ced8f4..150b4b36b 100644 --- a/embassy-net/src/tcp.rs +++ b/embassy-net/src/tcp.rs @@ -73,6 +73,16 @@ pub struct TcpWriter<'a> { } impl<'a> TcpReader<'a> { + /// Wait until the socket becomes readable. + /// + /// A socket becomes readable when the receive half of the full-duplex connection is open + /// (see [`may_recv()`](TcpSocket::may_recv)), and there is some pending data in the receive buffer. + /// + /// This is the equivalent of [read](#method.read), without buffering any data. + pub async fn wait_read_ready(&self) { + poll_fn(move |cx| self.io.poll_read_ready(cx)).await + } + /// Read data from the socket. /// /// Returns how many bytes were read, or an error. If no data is available, it waits @@ -115,6 +125,16 @@ impl<'a> TcpReader<'a> { } impl<'a> TcpWriter<'a> { + /// Wait until the socket becomes writable. + /// + /// A socket becomes writable when the transmit half of the full-duplex connection is open + /// (see [`may_send()`](TcpSocket::may_send)), and the transmit buffer is not full. + /// + /// This is the equivalent of [write](#method.write), without sending any data. + pub async fn wait_write_ready(&self) { + poll_fn(move |cx| self.io.poll_write_ready(cx)).await + } + /// Write data to the socket. /// /// Returns how many bytes were written, or an error. If the socket is not ready to From acaba50704b27abe6160539e6e764f5df0d58120 Mon Sep 17 00:00:00 2001 From: Anthony Grondin <104731965+AnthonyGrondin@users.noreply.github.com> Date: Thu, 31 Oct 2024 22:19:49 -0400 Subject: [PATCH 0310/1217] feat(embassy-net): Implement `wait_send_ready()` + `wait_recv_ready()` for Raw sockets. --- embassy-net/src/raw.rs | 53 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/embassy-net/src/raw.rs b/embassy-net/src/raw.rs index 1f725d00b..a88bcc458 100644 --- a/embassy-net/src/raw.rs +++ b/embassy-net/src/raw.rs @@ -62,6 +62,14 @@ impl<'a> RawSocket<'a> { }) } + /// Wait until the socket becomes readable. + /// + /// A socket is readable when a packet has been received, or when there are queued packets in + /// the buffer. + pub async fn wait_recv_ready(&self) { + poll_fn(move |cx| self.poll_recv_ready(cx)).await + } + /// Receive a datagram. /// /// This method will wait until a datagram is received. @@ -69,6 +77,24 @@ impl<'a> RawSocket<'a> { poll_fn(move |cx| self.poll_recv(buf, cx)).await } + /// Wait until a datagram can be read. + /// + /// When no datagram is readable, this method will return `Poll::Pending` and + /// register the current task to be notified when a datagram is received. + /// + /// When a datagram is received, this method will return `Poll::Ready`. + pub fn poll_recv_ready(&self, cx: &mut Context<'_>) -> Poll<()> { + self.with_mut(|s, _| { + if s.can_recv() { + Poll::Ready(()) + } else { + // socket buffer is empty wait until at least one byte has arrived + s.register_recv_waker(cx.waker()); + Poll::Pending + } + }) + } + /// Receive a datagram. /// /// When no datagram is available, this method will return `Poll::Pending` and @@ -85,6 +111,33 @@ impl<'a> RawSocket<'a> { }) } + /// Wait until the socket becomes writable. + /// + /// A socket becomes writable when there is space in the buffer, from initial memory or after + /// dispatching datagrams on a full buffer. + pub async fn wait_send_ready(&self) { + poll_fn(move |cx| self.poll_send_ready(cx)).await + } + + /// Wait until a datagram can be sent. + /// + /// When no datagram can be sent (i.e. the buffer is full), this method will return + /// `Poll::Pending` and register the current task to be notified when + /// space is freed in the buffer after a datagram has been dispatched. + /// + /// When a datagram can be sent, this method will return `Poll::Ready`. + pub fn poll_send_ready(&self, cx: &mut Context<'_>) -> Poll<()> { + self.with_mut(|s, _| { + if s.can_send() { + Poll::Ready(()) + } else { + // socket buffer is full wait until a datagram has been dispatched + s.register_send_waker(cx.waker()); + Poll::Pending + } + }) + } + /// Send a datagram. /// /// This method will wait until the datagram has been sent.` From 333d8584812c0ea3e1f9262922befbd3fe709775 Mon Sep 17 00:00:00 2001 From: Bjorn <75190918+BjornTheProgrammer@users.noreply.github.com> Date: Thu, 31 Oct 2024 22:51:03 -0700 Subject: [PATCH 0311/1217] Added ReceiverHandler to logger --- embassy-usb-logger/src/lib.rs | 92 ++++++++++++++++--- .../rp/src/bin/usb_serial_with_handler.rs | 64 +++++++++++++ 2 files changed, 143 insertions(+), 13 deletions(-) create mode 100644 examples/rp/src/bin/usb_serial_with_handler.rs diff --git a/embassy-usb-logger/src/lib.rs b/embassy-usb-logger/src/lib.rs index 11188b4ef..29c102f10 100644 --- a/embassy-usb-logger/src/lib.rs +++ b/embassy-usb-logger/src/lib.rs @@ -3,6 +3,7 @@ #![warn(missing_docs)] use core::fmt::Write as _; +use core::future::Future; use embassy_futures::join::join; use embassy_sync::pipe::Pipe; @@ -13,6 +14,25 @@ use log::{Metadata, Record}; type CS = embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; +/// A trait that can be implemented and then passed to the +pub trait ReceiverHandler { + /// Data comes in from the serial port with each command and runs this function + fn handle_data(&self, data: &[u8]) -> impl Future + Send; + + /// Create a new instance of the Handler + fn new() -> Self; +} + +/// Use this Handler if you don't wish to use any handler +pub struct DummyHandler; + +impl ReceiverHandler for DummyHandler { + async fn handle_data(&self, _data: &[u8]) {} + fn new() -> Self { + Self {} + } +} + /// The logger state containing buffers that must live as long as the USB peripheral. pub struct LoggerState<'d> { state: State<'d>, @@ -39,17 +59,19 @@ impl<'d> LoggerState<'d> { pub const MAX_PACKET_SIZE: u8 = 64; /// The logger handle, which contains a pipe with configurable size for buffering log messages. -pub struct UsbLogger { +pub struct UsbLogger { buffer: Pipe, custom_style: Option) -> ()>, + recieve_handler: Option, } -impl UsbLogger { +impl UsbLogger { /// Create a new logger instance. pub const fn new() -> Self { Self { buffer: Pipe::new(), custom_style: None, + recieve_handler: None, } } @@ -58,9 +80,15 @@ impl UsbLogger { Self { buffer: Pipe::new(), custom_style: Some(custom_style), + recieve_handler: None, } } + /// Add a command handler to the logger + pub fn with_handler(&mut self, handler: T) { + self.recieve_handler = Some(handler); + } + /// Run the USB logger using the state and USB driver. Never returns. pub async fn run<'d, D>(&'d self, state: &'d mut LoggerState<'d>, driver: D) -> ! where @@ -118,15 +146,22 @@ impl UsbLogger { } } }; - let discard_fut = async { - let mut discard_buf: [u8; MAX_PACKET_SIZE as usize] = [0; MAX_PACKET_SIZE as usize]; + let reciever_fut = async { + let mut reciever_buf: [u8; MAX_PACKET_SIZE as usize] = [0; MAX_PACKET_SIZE as usize]; receiver.wait_connection().await; loop { - let _ = receiver.read_packet(&mut discard_buf).await; + let n = receiver.read_packet(&mut reciever_buf).await.unwrap(); + match &self.recieve_handler { + Some(handler) => { + let data = &reciever_buf[..n]; + handler.handle_data(data).await; + } + None => (), + } } }; - join(log_fut, discard_fut).await; + join(log_fut, reciever_fut).await; } /// Creates the futures needed for the logger from a given class @@ -142,7 +177,7 @@ impl UsbLogger { } } -impl log::Log for UsbLogger { +impl log::Log for UsbLogger { fn enabled(&self, _metadata: &Metadata) -> bool { true } @@ -182,7 +217,7 @@ impl<'d, const N: usize> core::fmt::Write for Writer<'d, N> { /// Initialize and run the USB serial logger, never returns. /// -/// Arguments specify the buffer size, log level and the USB driver, respectively. +/// Arguments specify the buffer size, log level and the USB driver, respectively. You can optionally add a RecieverHandler. /// /// # Usage /// @@ -196,17 +231,27 @@ impl<'d, const N: usize> core::fmt::Write for Writer<'d, N> { #[macro_export] macro_rules! run { ( $x:expr, $l:expr, $p:ident ) => { - static LOGGER: ::embassy_usb_logger::UsbLogger<$x> = ::embassy_usb_logger::UsbLogger::new(); + static LOGGER: ::embassy_usb_logger::UsbLogger<$x, ::embassy_usb_logger::DummyHandler> = + ::embassy_usb_logger::UsbLogger::new(); unsafe { let _ = ::log::set_logger_racy(&LOGGER).map(|()| log::set_max_level_racy($l)); } let _ = LOGGER.run(&mut ::embassy_usb_logger::LoggerState::new(), $p).await; }; + + ( $x:expr, $l:expr, $p:ident, $h:ty ) => { + unsafe { + static mut LOGGER: ::embassy_usb_logger::UsbLogger<$x, $h> = ::embassy_usb_logger::UsbLogger::new(); + LOGGER.with_handler(<$h>::new()); + let _ = ::log::set_logger_racy(&LOGGER).map(|()| log::set_max_level_racy($l)); + let _ = LOGGER.run(&mut ::embassy_usb_logger::LoggerState::new(), $p).await; + } + }; } /// Initialize the USB serial logger from a serial class and return the future to run it. /// -/// Arguments specify the buffer size, log level and the serial class, respectively. +/// Arguments specify the buffer size, log level and the serial class, respectively. You can optionally add a RecieverHandler. /// /// # Usage /// @@ -220,19 +265,29 @@ macro_rules! run { #[macro_export] macro_rules! with_class { ( $x:expr, $l:expr, $p:ident ) => {{ - static LOGGER: ::embassy_usb_logger::UsbLogger<$x> = ::embassy_usb_logger::UsbLogger::new(); + static LOGGER: ::embassy_usb_logger::UsbLogger<$x, ::embassy_usb_logger::DummyHandler> = + ::embassy_usb_logger::UsbLogger::new(); unsafe { let _ = ::log::set_logger_racy(&LOGGER).map(|()| log::set_max_level_racy($l)); } LOGGER.create_future_from_class($p) }}; + + ( $x:expr, $l:expr, $p:ident, $h:ty ) => {{ + unsafe { + static mut LOGGER: ::embassy_usb_logger::UsbLogger<$x, $h> = ::embassy_usb_logger::UsbLogger::new(); + LOGGER.with_handler(<$h>::new()); + let _ = ::log::set_logger_racy(&LOGGER).map(|()| log::set_max_level_racy($l)); + LOGGER.create_future_from_class($p) + } + }}; } /// Initialize the USB serial logger from a serial class and return the future to run it. /// This version of the macro allows for a custom style function to be passed in. /// The custom style function will be called for each log record and is responsible for writing the log message to the buffer. /// -/// Arguments specify the buffer size, log level, the serial class and the custom style function, respectively. +/// Arguments specify the buffer size, log level, the serial class and the custom style function, respectively. You can optionally add a RecieverHandler. /// /// # Usage /// @@ -250,10 +305,21 @@ macro_rules! with_class { #[macro_export] macro_rules! with_custom_style { ( $x:expr, $l:expr, $p:ident, $s:expr ) => {{ - static LOGGER: ::embassy_usb_logger::UsbLogger<$x> = ::embassy_usb_logger::UsbLogger::with_custom_style($s); + static LOGGER: ::embassy_usb_logger::UsbLogger<$x, ::embassy_usb_logger::DummyHandler> = + ::embassy_usb_logger::UsbLogger::with_custom_style($s); unsafe { let _ = ::log::set_logger_racy(&LOGGER).map(|()| log::set_max_level_racy($l)); } LOGGER.create_future_from_class($p) }}; + + ( $x:expr, $l:expr, $p:ident, $s:expr, $h:ty ) => {{ + unsafe { + static mut LOGGER: ::embassy_usb_logger::UsbLogger<$x, $h> = + ::embassy_usb_logger::UsbLogger::with_custom_style($s); + LOGGER.with_handler(<$h>::new()); + let _ = ::log::set_logger_racy(&LOGGER).map(|()| log::set_max_level_racy($l)); + LOGGER.create_future_from_class($p) + } + }}; } diff --git a/examples/rp/src/bin/usb_serial_with_handler.rs b/examples/rp/src/bin/usb_serial_with_handler.rs new file mode 100644 index 000000000..a9e65be70 --- /dev/null +++ b/examples/rp/src/bin/usb_serial_with_handler.rs @@ -0,0 +1,64 @@ +//! This example shows how to use USB (Universal Serial Bus) in the RP2040 chip. +//! +//! This creates the possibility to send log::info/warn/error/debug! to USB serial port. + +#![no_std] +#![no_main] + +use core::str; + +use embassy_executor::Spawner; +use embassy_rp::bind_interrupts; +use embassy_rp::peripherals::USB; +use embassy_rp::rom_data::reset_to_usb_boot; +use embassy_rp::usb::{Driver, InterruptHandler}; +use embassy_time::Timer; +use embassy_usb_logger::ReceiverHandler; +use {defmt_rtt as _, panic_probe as _}; + +bind_interrupts!(struct Irqs { + USBCTRL_IRQ => InterruptHandler; +}); + +struct Handler; + +impl ReceiverHandler for Handler { + async fn handle_data(&self, data: &[u8]) { + if let Ok(data) = str::from_utf8(data) { + let data = data.trim(); + + // If you are using elf2uf2-term with the '-t' flag, then when closing the serial monitor, + // this will automatically put the pico into boot mode + if data == "q" || data == "elf2uf2-term" { + reset_to_usb_boot(0, 0); // Restart the chip + } else if data.eq_ignore_ascii_case("hello") { + log::info!("World!"); + } else { + log::info!("Recieved: {:?}", data); + } + } + } + + fn new() -> Self { + Self + } +} + +#[embassy_executor::task] +async fn logger_task(driver: Driver<'static, USB>) { + embassy_usb_logger::run!(1024, log::LevelFilter::Info, driver, Handler); +} + +#[embassy_executor::main] +async fn main(spawner: Spawner) { + let p = embassy_rp::init(Default::default()); + let driver = Driver::new(p.USB, Irqs); + spawner.spawn(logger_task(driver)).unwrap(); + + let mut counter = 0; + loop { + counter += 1; + log::info!("Tick {}", counter); + Timer::after_secs(1).await; + } +} From e93ac532aca2c699f19c43a080f2d8243e562a9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Kr=C3=B3lczyk?= Date: Fri, 1 Nov 2024 11:51:11 +0100 Subject: [PATCH 0312/1217] feat/stm32: disable multicast filtering on eth v2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Initially, this was feature-gated, but has been requested to be changed to be unconditional, see PR 3488 for reasons. When filtering is enabled, it intercepts and drops silently ipv6 packets, possibly somewhere around smoltcp::iface::interface::ipv6 lines 36, 44 in current head sha e9b66eadaeacef758ebc4a12378f8d2162144cf4 With filtering disabled (this patch), packets are received and communication over ipv6 is possible, neighbor discovery works. related: #2496 Signed-off-by: Krzysztof Królczyk --- embassy-stm32/src/eth/v2/mod.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/embassy-stm32/src/eth/v2/mod.rs b/embassy-stm32/src/eth/v2/mod.rs index b26f08cd9..9dd7f7d95 100644 --- a/embassy-stm32/src/eth/v2/mod.rs +++ b/embassy-stm32/src/eth/v2/mod.rs @@ -192,6 +192,9 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> { // TODO: Carrier sense ? ECRSFD }); + // Disable multicast filter + mac.macpfr().modify(|w| w.set_pm(true)); + // Note: Writing to LR triggers synchronisation of both LR and HR into the MAC core, // so the LR write must happen after the HR write. mac.maca0hr() From af694d233cf1d19f1aec9b522e8ef286b82424a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Kr=C3=B3lczyk?= Date: Fri, 1 Nov 2024 15:37:47 +0100 Subject: [PATCH 0313/1217] chore: improve some log msgs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Krzysztof Królczyk --- embassy-net/src/driver_util.rs | 4 ++-- embassy-net/src/lib.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/embassy-net/src/driver_util.rs b/embassy-net/src/driver_util.rs index f51641425..536f4c3d9 100644 --- a/embassy-net/src/driver_util.rs +++ b/embassy-net/src/driver_util.rs @@ -84,7 +84,7 @@ where { self.0.consume(|buf| { #[cfg(feature = "packet-trace")] - trace!("rx: {:?}", buf); + trace!("embassy device rx: {:02x}", buf); f(buf) }) } @@ -105,7 +105,7 @@ where self.0.consume(len, |buf| { let r = f(buf); #[cfg(feature = "packet-trace")] - trace!("tx: {:?}", buf); + trace!("embassy device tx: {:02x}", buf); r }) } diff --git a/embassy-net/src/lib.rs b/embassy-net/src/lib.rs index a7b7efa87..22e7358ac 100644 --- a/embassy-net/src/lib.rs +++ b/embassy-net/src/lib.rs @@ -391,12 +391,12 @@ impl<'d> Stack<'d> { self.with(|i| i.hardware_address) } - /// Get whether the link is up. + /// Check whether the link is up. pub fn is_link_up(&self) -> bool { self.with(|i| i.link_up) } - /// Get whether the network stack has a valid IP configuration. + /// Check whether the network stack has a valid IP configuration. /// This is true if the network stack has a static IP configuration or if DHCP has completed pub fn is_config_up(&self) -> bool { let v4_up; From 9634dfd6c119b054e232a886058d015ede5aec00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Kr=C3=B3lczyk?= Date: Fri, 1 Nov 2024 16:15:15 +0100 Subject: [PATCH 0314/1217] chore: address some clippy issues MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Krzysztof Królczyk --- embassy-net/src/lib.rs | 36 +++++++++++++++++------------------- embassy-net/src/tcp.rs | 4 ++-- 2 files changed, 19 insertions(+), 21 deletions(-) diff --git a/embassy-net/src/lib.rs b/embassy-net/src/lib.rs index 22e7358ac..ec7f10fdd 100644 --- a/embassy-net/src/lib.rs +++ b/embassy-net/src/lib.rs @@ -33,14 +33,14 @@ pub use embassy_net_driver as driver; use embassy_net_driver::{Driver, LinkState}; use embassy_sync::waitqueue::WakerRegistration; use embassy_time::{Instant, Timer}; -#[allow(unused_imports)] use heapless::Vec; #[cfg(feature = "dns")] pub use smoltcp::config::DNS_MAX_SERVER_COUNT; #[cfg(feature = "multicast")] pub use smoltcp::iface::MulticastError; -#[allow(unused_imports)] -use smoltcp::iface::{Interface, SocketHandle, SocketSet, SocketStorage}; +#[cfg(any(feature = "dns", feature = "dhcpv4"))] +use smoltcp::iface::SocketHandle; +use smoltcp::iface::{Interface, SocketSet, SocketStorage}; use smoltcp::phy::Medium; #[cfg(feature = "dhcpv4")] use smoltcp::socket::dhcpv4::{self, RetryConfig}; @@ -379,11 +379,11 @@ fn to_smoltcp_hardware_address(addr: driver::HardwareAddress) -> (HardwareAddres impl<'d> Stack<'d> { fn with(&self, f: impl FnOnce(&Inner) -> R) -> R { - f(&*self.inner.borrow()) + f(&self.inner.borrow()) } fn with_mut(&self, f: impl FnOnce(&mut Inner) -> R) -> R { - f(&mut *self.inner.borrow_mut()) + f(&mut self.inner.borrow_mut()) } /// Get the hardware address of the network interface. @@ -642,7 +642,7 @@ impl<'d> Stack<'d> { } impl Inner { - #[allow(clippy::absurd_extreme_comparisons, dead_code)] + #[allow(clippy::absurd_extreme_comparisons)] pub fn get_local_port(&mut self) -> u16 { let res = self.next_local_port; self.next_local_port = if res >= LOCAL_PORT_MAX { LOCAL_PORT_MIN } else { res + 1 }; @@ -732,7 +732,7 @@ impl Inner { debug!(" Default gateway: {:?}", config.gateway); unwrap!(addrs.push(IpCidr::Ipv4(config.address)).ok()); - gateway_v4 = config.gateway.into(); + gateway_v4 = config.gateway; #[cfg(feature = "dns")] for s in &config.dns_servers { debug!(" DNS server: {:?}", s); @@ -831,22 +831,19 @@ impl Inner { self.state_waker.wake(); } - #[allow(unused_mut)] - let mut apply_config = false; - #[cfg(feature = "dhcpv4")] if let Some(dhcp_handle) = self.dhcp_socket { let socket = self.sockets.get_mut::(dhcp_handle); - if self.link_up { + let configure = if self.link_up { if old_link_up != self.link_up { socket.reset(); } match socket.poll() { - None => {} + None => false, Some(dhcpv4::Event::Deconfigured) => { self.static_v4 = None; - apply_config = true; + true } Some(dhcpv4::Event::Configured(config)) => { self.static_v4 = Some(StaticConfigV4 { @@ -854,20 +851,21 @@ impl Inner { gateway: config.router, dns_servers: config.dns_servers, }); - apply_config = true; + true } } } else if old_link_up { socket.reset(); self.static_v4 = None; - apply_config = true; + true + } else { + false + }; + if configure { + self.apply_static_config() } } - if apply_config { - self.apply_static_config(); - } - if let Some(poll_at) = self.iface.poll_at(timestamp, &mut self.sockets) { let t = pin!(Timer::at(instant_from_smoltcp(poll_at))); if t.poll(cx).is_ready() { diff --git a/embassy-net/src/tcp.rs b/embassy-net/src/tcp.rs index 150b4b36b..32d374064 100644 --- a/embassy-net/src/tcp.rs +++ b/embassy-net/src/tcp.rs @@ -186,7 +186,7 @@ impl<'a> TcpSocket<'a> { }); Self { - io: TcpIo { stack: stack, handle }, + io: TcpIo { stack, handle }, } } @@ -806,7 +806,7 @@ pub mod client { }; let remote_endpoint = (addr, remote.port()); let mut socket = TcpConnection::new(self.stack, self.state)?; - socket.socket.set_timeout(self.socket_timeout.clone()); + socket.socket.set_timeout(self.socket_timeout); socket .socket .connect(remote_endpoint) From 84def1608fdd098676d957ed5c67ac4baf586963 Mon Sep 17 00:00:00 2001 From: flippette Date: Fri, 1 Nov 2024 23:44:37 +0200 Subject: [PATCH 0315/1217] Also implement `embedded_io::Write` for `UartTx<'d, T: Instance, Blocking>` --- embassy-rp/src/uart/mod.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/embassy-rp/src/uart/mod.rs b/embassy-rp/src/uart/mod.rs index ad98a46c7..08f20924c 100644 --- a/embassy-rp/src/uart/mod.rs +++ b/embassy-rp/src/uart/mod.rs @@ -1248,6 +1248,20 @@ impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::Write for UartTx<'d, T, } } +impl<'d, T: Instance> embedded_io::ErrorType for UartTx<'d, T, Blocking> { + type Error = Error; +} + +impl<'d, T: Instance> embedded_io::Write for UartTx<'d, T, Blocking> { + fn write(&mut self, buf: &[u8]) -> Result { + self.blocking_write(buf).map(|_| buf.len()) + } + + fn flush(&mut self) -> Result<(), Self::Error> { + self.blocking_flush() + } +} + impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::Read for Uart<'d, T, M> { fn read(&mut self) -> Result> { embedded_hal_02::serial::Read::read(&mut self.rx) From 43ff5a9b286c8864d7c623362322a6027980b24d Mon Sep 17 00:00:00 2001 From: dvdsk Date: Sat, 2 Nov 2024 14:00:27 +0100 Subject: [PATCH 0316/1217] stm32/uart fix leftover DmaUnsynced public api --- embassy-stm32/src/usart/mod.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index aaf7b41e6..333e01e36 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -1689,7 +1689,6 @@ impl embedded_hal_nb::serial::Error for Error { Self::Overrun => embedded_hal_nb::serial::ErrorKind::Overrun, Self::Parity => embedded_hal_nb::serial::ErrorKind::Parity, Self::BufferTooLong => embedded_hal_nb::serial::ErrorKind::Other, - Self::DmaUnsynced => embedded_hal_nb::serial::ErrorKind::Other, } } } From 1434d2f97a48f29cbe480a4d306ecf8716b1b2d4 Mon Sep 17 00:00:00 2001 From: Charles Edward Gagnon <76854355+carloskiki@users.noreply.github.com> Date: Sat, 2 Nov 2024 16:03:17 -0400 Subject: [PATCH 0317/1217] enhanced docs for time driver --- embassy-time-driver/src/lib.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/embassy-time-driver/src/lib.rs b/embassy-time-driver/src/lib.rs index 8000a9dcb..75f7037e3 100644 --- a/embassy-time-driver/src/lib.rs +++ b/embassy-time-driver/src/lib.rs @@ -109,12 +109,20 @@ pub trait Driver: Send + Sync + 'static { /// Try allocating an alarm handle. Returns None if no alarms left. /// Initially the alarm has no callback set, and a null `ctx` pointer. /// + /// The allocated alarm is a reusable resource and can be used multiple times. + /// Once the alarm has fired, it remains allocated and can be set again without needing + /// to be reallocated. + /// /// # Safety /// It is UB to make the alarm fire before setting a callback. unsafe fn allocate_alarm(&self) -> Option; /// Set the callback function to be called when the alarm triggers. /// The callback may be called from any context (interrupt or thread mode). + /// + /// The callback is maintained after the alarm has fired. Callers do not need + /// to set a callback again before setting another alarm, unless they want to + /// change the callback function or context. fn set_alarm_callback(&self, alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()); /// Set an alarm at the given timestamp. From 5c1f9cf99cc0b6d0215357bb4041ce5b936e9095 Mon Sep 17 00:00:00 2001 From: Charles Edward Gagnon Date: Sat, 2 Nov 2024 16:11:53 -0400 Subject: [PATCH 0318/1217] rustfmt --- embassy-time-driver/src/lib.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/embassy-time-driver/src/lib.rs b/embassy-time-driver/src/lib.rs index 75f7037e3..12f40b9b9 100644 --- a/embassy-time-driver/src/lib.rs +++ b/embassy-time-driver/src/lib.rs @@ -109,8 +109,8 @@ pub trait Driver: Send + Sync + 'static { /// Try allocating an alarm handle. Returns None if no alarms left. /// Initially the alarm has no callback set, and a null `ctx` pointer. /// - /// The allocated alarm is a reusable resource and can be used multiple times. - /// Once the alarm has fired, it remains allocated and can be set again without needing + /// The allocated alarm is a reusable resource and can be used multiple times. + /// Once the alarm has fired, it remains allocated and can be set again without needing /// to be reallocated. /// /// # Safety @@ -120,8 +120,8 @@ pub trait Driver: Send + Sync + 'static { /// Set the callback function to be called when the alarm triggers. /// The callback may be called from any context (interrupt or thread mode). /// - /// The callback is maintained after the alarm has fired. Callers do not need - /// to set a callback again before setting another alarm, unless they want to + /// The callback is maintained after the alarm has fired. Callers do not need + /// to set a callback again before setting another alarm, unless they want to /// change the callback function or context. fn set_alarm_callback(&self, alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()); From 926ae1a1d5eeff34649c0c20804323b32403807f Mon Sep 17 00:00:00 2001 From: Christian Enderle Date: Sun, 3 Nov 2024 10:56:40 +0100 Subject: [PATCH 0319/1217] low-power: add support for stm32u5 --- embassy-stm32/src/low_power.rs | 6 +++--- embassy-stm32/src/rtc/low_power.rs | 19 ++++++++++++++----- embassy-stm32/src/rtc/mod.rs | 1 + embassy-stm32/src/rtc/v3.rs | 2 ++ 4 files changed, 20 insertions(+), 8 deletions(-) diff --git a/embassy-stm32/src/low_power.rs b/embassy-stm32/src/low_power.rs index 2be1a42b7..a779b8a09 100644 --- a/embassy-stm32/src/low_power.rs +++ b/embassy-stm32/src/low_power.rs @@ -112,10 +112,10 @@ pub enum StopMode { Stop2, } -#[cfg(any(stm32l4, stm32l5))] +#[cfg(any(stm32l4, stm32l5, stm32u5))] use stm32_metapac::pwr::vals::Lpms; -#[cfg(any(stm32l4, stm32l5))] +#[cfg(any(stm32l4, stm32l5, stm32u5))] impl Into for StopMode { fn into(self) -> Lpms { match self { @@ -184,7 +184,7 @@ impl Executor { #[allow(unused_variables)] fn configure_stop(&mut self, stop_mode: StopMode) { - #[cfg(any(stm32l4, stm32l5))] + #[cfg(any(stm32l4, stm32l5, stm32u5))] crate::pac::PWR.cr1().modify(|m| m.set_lpms(stop_mode.into())); #[cfg(stm32h5)] crate::pac::PWR.pmcr().modify(|v| { diff --git a/embassy-stm32/src/rtc/low_power.rs b/embassy-stm32/src/rtc/low_power.rs index 875eaa639..bba359f31 100644 --- a/embassy-stm32/src/rtc/low_power.rs +++ b/embassy-stm32/src/rtc/low_power.rs @@ -65,7 +65,7 @@ pub(crate) enum WakeupPrescaler { Div16 = 16, } -#[cfg(any(stm32f4, stm32l0, stm32g4, stm32l4, stm32l5, stm32wb, stm32h5, stm32g0))] +#[cfg(any(stm32f4, stm32l0, stm32g4, stm32l4, stm32l5, stm32wb, stm32h5, stm32g0, stm32u5))] impl From for crate::pac::rtc::vals::Wucksel { fn from(val: WakeupPrescaler) -> Self { use crate::pac::rtc::vals::Wucksel; @@ -79,7 +79,7 @@ impl From for crate::pac::rtc::vals::Wucksel { } } -#[cfg(any(stm32f4, stm32l0, stm32g4, stm32l4, stm32l5, stm32wb, stm32h5, stm32g0))] +#[cfg(any(stm32f4, stm32l0, stm32g4, stm32l4, stm32l5, stm32wb, stm32h5, stm32g0, stm32u5))] impl From for WakeupPrescaler { fn from(val: crate::pac::rtc::vals::Wucksel) -> Self { use crate::pac::rtc::vals::Wucksel; @@ -219,12 +219,21 @@ impl Rtc { pub(crate) fn enable_wakeup_line(&self) { use crate::interrupt::typelevel::Interrupt; - use crate::pac::EXTI; ::WakeupInterrupt::unpend(); unsafe { ::WakeupInterrupt::enable() }; - EXTI.rtsr(0).modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true)); - EXTI.imr(0).modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true)); + #[cfg(not(stm32u5))] + { + use crate::pac::EXTI; + EXTI.rtsr(0).modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true)); + EXTI.imr(0).modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true)); + } + #[cfg(stm32u5)] + { + use crate::pac::RCC; + RCC.srdamr().modify(|w| w.set_rtcapbamen(true)); + RCC.apb3smenr().modify(|w| w.set_rtcapbsmen(true)); + } } } diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs index fe57cfe66..3722d11ab 100644 --- a/embassy-stm32/src/rtc/mod.rs +++ b/embassy-stm32/src/rtc/mod.rs @@ -285,6 +285,7 @@ trait SealedInstance { const BACKUP_REGISTER_COUNT: usize; #[cfg(feature = "low-power")] + #[cfg(not(stm32u5))] const EXTI_WAKEUP_LINE: usize; #[cfg(feature = "low-power")] diff --git a/embassy-stm32/src/rtc/v3.rs b/embassy-stm32/src/rtc/v3.rs index 02fd5272e..12cb10bc7 100644 --- a/embassy-stm32/src/rtc/v3.rs +++ b/embassy-stm32/src/rtc/v3.rs @@ -140,6 +140,8 @@ impl SealedInstance for crate::peripherals::RTC { } else if #[cfg(any(stm32l5, stm32h5))] { const EXTI_WAKEUP_LINE: usize = 17; type WakeupInterrupt = crate::interrupt::typelevel::RTC; + } else if #[cfg(stm32u5)] { + type WakeupInterrupt = crate::interrupt::typelevel::RTC; } ); From 51f6b813e1a4311ffb4adf2e66ed3effb990d246 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 24 Oct 2024 13:31:53 +0200 Subject: [PATCH 0320/1217] nrf: port to chiptool-based `nrf-pac`. --- embassy-net-nrf91/Cargo.toml | 3 +- embassy-net-nrf91/src/lib.rs | 78 ++-- embassy-nrf/Cargo.toml | 55 +-- embassy-nrf/src/buffered_uarte.rs | 157 ++++---- embassy-nrf/src/chips/nrf51.rs | 2 +- embassy-nrf/src/chips/nrf52805.rs | 2 +- embassy-nrf/src/chips/nrf52810.rs | 2 +- embassy-nrf/src/chips/nrf52811.rs | 2 +- embassy-nrf/src/chips/nrf52820.rs | 2 +- embassy-nrf/src/chips/nrf52832.rs | 2 +- embassy-nrf/src/chips/nrf52833.rs | 2 +- embassy-nrf/src/chips/nrf52840.rs | 2 +- embassy-nrf/src/chips/nrf5340_app.rs | 43 ++- embassy-nrf/src/chips/nrf5340_net.rs | 40 +- embassy-nrf/src/chips/nrf9120.rs | 36 +- embassy-nrf/src/chips/nrf9160.rs | 34 +- embassy-nrf/src/egu.rs | 20 +- embassy-nrf/src/gpio.rs | 133 ++++--- embassy-nrf/src/gpiote.rs | 145 +++---- embassy-nrf/src/i2s.rs | 166 ++++---- embassy-nrf/src/lib.rs | 120 +++--- embassy-nrf/src/nvmc.rs | 23 +- embassy-nrf/src/pdm.rs | 183 ++++----- embassy-nrf/src/ppi/dppi.rs | 8 +- embassy-nrf/src/ppi/mod.rs | 37 +- embassy-nrf/src/ppi/ppi.rs | 32 +- embassy-nrf/src/pwm.rs | 263 ++++++------- embassy-nrf/src/qdec.rs | 83 ++-- embassy-nrf/src/qspi.rs | 164 ++++---- embassy-nrf/src/radio/ble.rs | 188 +++++---- embassy-nrf/src/radio/ieee802154.rs | 223 ++++++----- embassy-nrf/src/radio/mod.rs | 19 +- embassy-nrf/src/rng.rs | 28 +- embassy-nrf/src/saadc.rs | 247 ++++++------ embassy-nrf/src/spim.rs | 130 +++---- embassy-nrf/src/spis.rs | 145 +++---- embassy-nrf/src/temp.rs | 22 +- embassy-nrf/src/time_driver.rs | 45 ++- embassy-nrf/src/timer.rs | 80 ++-- embassy-nrf/src/twim.rs | 238 ++++++------ embassy-nrf/src/twis.rs | 362 +++++++++--------- embassy-nrf/src/uarte.rs | 356 ++++++++--------- embassy-nrf/src/usb/mod.rs | 281 ++++++-------- embassy-nrf/src/usb/vbus_detect.rs | 35 +- embassy-nrf/src/wdt.rs | 80 ++-- examples/boot/bootloader/nrf/src/main.rs | 6 +- examples/nrf52840/src/bin/usb_ethernet.rs | 7 +- examples/nrf52840/src/bin/usb_hid_keyboard.rs | 6 +- examples/nrf52840/src/bin/usb_hid_mouse.rs | 7 +- examples/nrf52840/src/bin/usb_serial.rs | 7 +- .../nrf52840/src/bin/usb_serial_multitask.rs | 7 +- .../nrf52840/src/bin/usb_serial_winusb.rs | 7 +- examples/nrf52840/src/bin/wdt.rs | 4 +- tests/nrf/Cargo.toml | 5 + tests/nrf/src/bin/buffered_uart_spam.rs | 12 +- tests/nrf/src/bin/gpio.rs | 2 + tests/nrf/src/bin/spim.rs | 42 ++ tests/nrf/src/common.rs | 15 + 58 files changed, 2154 insertions(+), 2291 deletions(-) create mode 100644 tests/nrf/src/bin/spim.rs diff --git a/embassy-net-nrf91/Cargo.toml b/embassy-net-nrf91/Cargo.toml index 07a0c8886..98356c1ba 100644 --- a/embassy-net-nrf91/Cargo.toml +++ b/embassy-net-nrf91/Cargo.toml @@ -17,7 +17,8 @@ log = [ "dep:log" ] defmt = { version = "0.3", optional = true } log = { version = "0.4.14", optional = true } -nrf9160-pac = { version = "0.12.0" } +nrf-pac = { git = "https://github.com/embassy-rs/nrf-pac", rev = "875a29629cc1c87aae00cfea647a956b3807d8be" } +cortex-m = "0.7.7" embassy-time = { version = "0.3.1", path = "../embassy-time" } embassy-sync = { version = "0.6.0", path = "../embassy-sync"} diff --git a/embassy-net-nrf91/src/lib.rs b/embassy-net-nrf91/src/lib.rs index 60cdc38c6..80d08f7f5 100644 --- a/embassy-net-nrf91/src/lib.rs +++ b/embassy-net-nrf91/src/lib.rs @@ -17,12 +17,12 @@ use core::slice; use core::sync::atomic::{compiler_fence, fence, Ordering}; use core::task::{Poll, Waker}; +use cortex_m::peripheral::NVIC; use embassy_sync::blocking_mutex::raw::NoopRawMutex; use embassy_sync::pipe; use embassy_sync::waitqueue::{AtomicWaker, WakerRegistration}; use heapless::Vec; -use pac::NVIC; -use {embassy_net_driver_channel as ch, nrf9160_pac as pac}; +use {embassy_net_driver_channel as ch, nrf_pac as pac}; const RX_SIZE: usize = 8 * 1024; const TRACE_SIZE: usize = 16 * 1024; @@ -38,11 +38,9 @@ static WAKER: AtomicWaker = AtomicWaker::new(); /// Call this function on IPC IRQ pub fn on_ipc_irq() { - let ipc = unsafe { &*pac::IPC_NS::ptr() }; - trace!("irq"); - ipc.inten.write(|w| w); + pac::IPC_NS.inten().write(|_| ()); WAKER.wake(); } @@ -135,22 +133,21 @@ async fn new_internal<'a>( "shmem must be in the lower 128kb of RAM" ); - let spu = unsafe { &*pac::SPU_S::ptr() }; + let spu = pac::SPU_S; debug!("Setting IPC RAM as nonsecure..."); let region_start = (shmem_ptr as usize - 0x2000_0000) / SPU_REGION_SIZE; let region_end = region_start + shmem_len / SPU_REGION_SIZE; for i in region_start..region_end { - spu.ramregion[i].perm.write(|w| { - w.execute().set_bit(); - w.write().set_bit(); - w.read().set_bit(); - w.secattr().clear_bit(); - w.lock().clear_bit(); - w + spu.ramregion(i).perm().write(|w| { + w.set_execute(true); + w.set_write(true); + w.set_read(true); + w.set_secattr(false); + w.set_lock(false); }) } - spu.periphid[42].perm.write(|w| w.secattr().non_secure()); + spu.periphid(42).perm().write(|w| w.set_secattr(false)); let mut alloc = Allocator { start: shmem_ptr, @@ -158,8 +155,8 @@ async fn new_internal<'a>( _phantom: PhantomData, }; - let ipc = unsafe { &*pac::IPC_NS::ptr() }; - let power = unsafe { &*pac::POWER_S::ptr() }; + let ipc = pac::IPC_NS; + let power = pac::POWER_S; let cb: &mut ControlBlock = alloc.alloc().write(unsafe { mem::zeroed() }); let rx = alloc.alloc_bytes(RX_SIZE); @@ -177,20 +174,20 @@ async fn new_internal<'a>( cb.trace.base = trace.as_mut_ptr() as _; cb.trace.size = TRACE_SIZE; - ipc.gpmem[0].write(|w| unsafe { w.bits(cb as *mut _ as u32) }); - ipc.gpmem[1].write(|w| unsafe { w.bits(0) }); + ipc.gpmem(0).write_value(cb as *mut _ as u32); + ipc.gpmem(1).write_value(0); // connect task/event i to channel i for i in 0..8 { - ipc.send_cnf[i].write(|w| unsafe { w.bits(1 << i) }); - ipc.receive_cnf[i].write(|w| unsafe { w.bits(1 << i) }); + ipc.send_cnf(i).write(|w| w.0 = 1 << i); + ipc.receive_cnf(i).write(|w| w.0 = 1 << i); } compiler_fence(Ordering::SeqCst); // POWER.LTEMODEM.STARTN = 0 // The reg is missing in the PAC?? - let startn = unsafe { (power as *const _ as *mut u32).add(0x610 / 4) }; + let startn = unsafe { (power.as_ptr() as *mut u32).add(0x610 / 4) }; unsafe { startn.write_volatile(0) } unsafe { NVIC::unmask(pac::Interrupt::IPC) }; @@ -322,15 +319,15 @@ struct StateInner { impl StateInner { fn poll(&mut self, trace_writer: &mut Option>, ch: &mut ch::Runner) { trace!("poll!"); - let ipc = unsafe { &*pac::IPC_NS::ptr() }; + let ipc = pac::IPC_NS; - if ipc.events_receive[0].read().bits() != 0 { - ipc.events_receive[0].reset(); + if ipc.events_receive(0).read() != 0 { + ipc.events_receive(0).write_value(0); trace!("ipc 0"); } - if ipc.events_receive[2].read().bits() != 0 { - ipc.events_receive[2].reset(); + if ipc.events_receive(2).read() != 0 { + ipc.events_receive(2).write_value(0); trace!("ipc 2"); if !self.init { @@ -353,8 +350,8 @@ impl StateInner { } } - if ipc.events_receive[4].read().bits() != 0 { - ipc.events_receive[4].reset(); + if ipc.events_receive(4).read() != 0 { + ipc.events_receive(4).write_value(0); trace!("ipc 4"); loop { @@ -368,13 +365,13 @@ impl StateInner { } } - if ipc.events_receive[6].read().bits() != 0 { - ipc.events_receive[6].reset(); + if ipc.events_receive(6).read() != 0 { + ipc.events_receive(6).write_value(0); trace!("ipc 6"); } - if ipc.events_receive[7].read().bits() != 0 { - ipc.events_receive[7].reset(); + if ipc.events_receive(7).read() != 0 { + ipc.events_receive(7).write_value(0); trace!("ipc 7: trace"); let msg = unsafe { addr_of!((*self.cb).trace.rx_state).read_volatile() }; @@ -437,13 +434,12 @@ impl StateInner { } } - ipc.intenset.write(|w| { - w.receive0().set_bit(); - w.receive2().set_bit(); - w.receive4().set_bit(); - w.receive6().set_bit(); - w.receive7().set_bit(); - w + ipc.intenset().write(|w| { + w.set_receive0(true); + w.set_receive2(true); + w.set_receive4(true); + w.set_receive6(true); + w.set_receive7(true); }); } @@ -546,8 +542,8 @@ impl StateInner { unsafe { addr_of_mut!((*list_item).state).write_volatile((self.tx_seq_no as u32) << 16 | 0x01) } self.tx_seq_no = self.tx_seq_no.wrapping_add(1); - let ipc = unsafe { &*pac::IPC_NS::ptr() }; - ipc.tasks_send[ipc_ch].write(|w| unsafe { w.bits(1) }); + let ipc = pac::IPC_NS; + ipc.tasks_send(ipc_ch).write_value(1); Ok(()) } diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml index 3e66d6886..90fa7a16c 100644 --- a/embassy-nrf/Cargo.toml +++ b/embassy-nrf/Cargo.toml @@ -15,7 +15,7 @@ src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-nrf/s features = ["time", "defmt", "unstable-pac", "gpiote", "time-driver-rtc1"] flavors = [ - { regex_feature = "nrf51", target = "thumbv6m-none-eabi" }, + { regex_feature = "_nrf51", target = "thumbv6m-none-eabi" }, { regex_feature = "nrf52.*", target = "thumbv7em-none-eabihf" }, { regex_feature = "nrf53.*", target = "thumbv8m.main-none-eabihf" }, { regex_feature = "nrf91.*", target = "thumbv8m.main-none-eabihf" }, @@ -28,20 +28,7 @@ rustdoc-args = ["--cfg", "docsrs"] [features] default = ["rt"] ## Cortex-M runtime (enabled by default) -rt = [ - "nrf51-pac?/rt", - "nrf52805-pac?/rt", - "nrf52810-pac?/rt", - "nrf52811-pac?/rt", - "nrf52820-pac?/rt", - "nrf52832-pac?/rt", - "nrf52833-pac?/rt", - "nrf52840-pac?/rt", - "nrf5340-app-pac?/rt", - "nrf5340-net-pac?/rt", - "nrf9160-pac?/rt", - "nrf9120-pac?/rt", -] +rt = ["nrf-pac/rt"] ## Enable features requiring `embassy-time` time = ["dep:embassy-time"] @@ -75,21 +62,21 @@ qspi-multiwrite-flash = [] #! ### Chip selection features ## nRF51 -nrf51 = ["nrf51-pac", "_nrf51"] +nrf51 = ["nrf-pac/nrf51", "_nrf51"] ## nRF52805 -nrf52805 = ["nrf52805-pac", "_nrf52"] +nrf52805 = ["nrf-pac/nrf52805", "_nrf52"] ## nRF52810 -nrf52810 = ["nrf52810-pac", "_nrf52"] +nrf52810 = ["nrf-pac/nrf52810", "_nrf52"] ## nRF52811 -nrf52811 = ["nrf52811-pac", "_nrf52"] +nrf52811 = ["nrf-pac/nrf52811", "_nrf52"] ## nRF52820 -nrf52820 = ["nrf52820-pac", "_nrf52"] +nrf52820 = ["nrf-pac/nrf52820", "_nrf52"] ## nRF52832 -nrf52832 = ["nrf52832-pac", "_nrf52", "_nrf52832_anomaly_109"] +nrf52832 = ["nrf-pac/nrf52832", "_nrf52", "_nrf52832_anomaly_109"] ## nRF52833 -nrf52833 = ["nrf52833-pac", "_nrf52", "_gpio-p1"] +nrf52833 = ["nrf-pac/nrf52833", "_nrf52", "_gpio-p1"] ## nRF52840 -nrf52840 = ["nrf52840-pac", "_nrf52", "_gpio-p1"] +nrf52840 = ["nrf-pac/nrf52840", "_nrf52", "_gpio-p1"] ## nRF5340 application core in Secure mode nrf5340-app-s = ["_nrf5340-app", "_s"] ## nRF5340 application core in Non-Secure mode @@ -113,11 +100,11 @@ nrf9161-ns = ["nrf9120-ns"] # Features starting with `_` are for internal use only. They're not intended # to be enabled by other crates, and are not covered by semver guarantees. -_nrf5340-app = ["_nrf5340", "nrf5340-app-pac"] -_nrf5340-net = ["_nrf5340", "nrf5340-net-pac"] +_nrf5340-app = ["_nrf5340", "nrf-pac/nrf5340-app"] +_nrf5340-net = ["_nrf5340", "nrf-pac/nrf5340-net"] _nrf5340 = ["_gpio-p1", "_dppi"] -_nrf9160 = ["nrf9160-pac", "_dppi"] -_nrf9120 = ["nrf9120-pac", "_dppi"] +_nrf9160 = ["nrf-pac/nrf9160", "_dppi"] +_nrf9120 = ["nrf-pac/nrf9120", "_dppi"] _nrf52 = ["_ppi"] _nrf51 = ["_ppi"] _nrf91 = [] @@ -149,6 +136,8 @@ embedded-hal-async = { version = "1.0" } embedded-io = { version = "0.6.0" } embedded-io-async = { version = "0.6.1" } +nrf-pac = { git = "https://github.com/embassy-rs/nrf-pac", rev = "875a29629cc1c87aae00cfea647a956b3807d8be" } + defmt = { version = "0.3", optional = true } bitflags = "2.4.2" log = { version = "0.4.14", optional = true } @@ -162,15 +151,3 @@ embedded-storage-async = "0.4.1" cfg-if = "1.0.0" document-features = "0.2.7" -nrf51-pac = { version = "0.12.0", optional = true } -nrf52805-pac = { version = "0.12.0", optional = true } -nrf52810-pac = { version = "0.12.0", optional = true } -nrf52811-pac = { version = "0.12.0", optional = true } -nrf52820-pac = { version = "0.12.0", optional = true } -nrf52832-pac = { version = "0.12.0", optional = true } -nrf52833-pac = { version = "0.12.0", optional = true } -nrf52840-pac = { version = "0.12.0", optional = true } -nrf5340-app-pac = { version = "0.12.0", optional = true } -nrf5340-net-pac = { version = "0.12.0", optional = true } -nrf9160-pac = { version = "0.12.0", optional = true } -nrf9120-pac = { version = "0.12.0", optional = true } diff --git a/embassy-nrf/src/buffered_uarte.rs b/embassy-nrf/src/buffered_uarte.rs index 6d39597c6..b55e70a36 100644 --- a/embassy-nrf/src/buffered_uarte.rs +++ b/embassy-nrf/src/buffered_uarte.rs @@ -17,16 +17,17 @@ use core::task::Poll; use embassy_hal_internal::atomic_ring_buffer::RingBuffer; use embassy_hal_internal::{into_ref, PeripheralRef}; +use pac::uarte::vals; // Re-export SVD variants to allow user to directly set values -pub use pac::uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Parity}; +pub use pac::uarte::vals::{Baudrate, ConfigParity as Parity}; -use crate::gpio::{AnyPin, Pin as GpioPin, PselBits, SealedPin}; +use crate::gpio::{AnyPin, Pin as GpioPin}; use crate::interrupt::typelevel::Interrupt; use crate::ppi::{ self, AnyConfigurableChannel, AnyGroup, Channel, ConfigurableChannel, Event, Group, Ppi, PpiGroup, Task, }; use crate::timer::{Instance as TimerInstance, Timer}; -use crate::uarte::{configure, drop_tx_rx, Config, Instance as UarteInstance}; +use crate::uarte::{configure, configure_rx_pins, configure_tx_pins, drop_tx_rx, Config, Instance as UarteInstance}; use crate::{interrupt, pac, Peripheral, EASY_DMA_SIZE}; pub(crate) struct State { @@ -79,57 +80,57 @@ impl interrupt::typelevel::Handler for Interrupt let buf_len = s.rx_buf.len(); let half_len = buf_len / 2; - if r.events_error.read().bits() != 0 { - r.events_error.reset(); - let errs = r.errorsrc.read(); - r.errorsrc.write(|w| unsafe { w.bits(errs.bits()) }); + if r.events_error().read() != 0 { + r.events_error().write_value(0); + let errs = r.errorsrc().read(); + r.errorsrc().write_value(errs); - if errs.overrun().bit() { + if errs.overrun() { panic!("BufferedUarte overrun"); } } // Received some bytes, wake task. - if r.inten.read().rxdrdy().bit_is_set() && r.events_rxdrdy.read().bits() != 0 { - r.intenclr.write(|w| w.rxdrdy().clear()); - r.events_rxdrdy.reset(); + if r.inten().read().rxdrdy() && r.events_rxdrdy().read() != 0 { + r.intenclr().write(|w| w.set_rxdrdy(true)); + r.events_rxdrdy().write_value(0); ss.rx_waker.wake(); } - if r.events_endrx.read().bits() != 0 { + if r.events_endrx().read() != 0 { //trace!(" irq_rx: endrx"); - r.events_endrx.reset(); + r.events_endrx().write_value(0); let val = s.rx_ended_count.load(Ordering::Relaxed); s.rx_ended_count.store(val.wrapping_add(1), Ordering::Relaxed); } - if r.events_rxstarted.read().bits() != 0 || !s.rx_started.load(Ordering::Relaxed) { + if r.events_rxstarted().read() != 0 || !s.rx_started.load(Ordering::Relaxed) { //trace!(" irq_rx: rxstarted"); let (ptr, len) = rx.push_buf(); if len >= half_len { - r.events_rxstarted.reset(); + r.events_rxstarted().write_value(0); //trace!(" irq_rx: starting second {:?}", half_len); // Set up the DMA read - r.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) }); - r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(half_len as _) }); + r.rxd().ptr().write_value(ptr as u32); + r.rxd().maxcnt().write(|w| w.set_maxcnt(half_len as _)); let chn = s.rx_ppi_ch.load(Ordering::Relaxed); // Enable endrx -> startrx PPI channel. // From this point on, if endrx happens, startrx is automatically fired. - ppi::regs().chenset.write(|w| unsafe { w.bits(1 << chn) }); + ppi::regs().chenset().write(|w| w.0 = 1 << chn); // It is possible that endrx happened BEFORE enabling the PPI. In this case // the PPI channel doesn't trigger, and we'd hang. We have to detect this // and manually start. // check again in case endrx has happened between the last check and now. - if r.events_endrx.read().bits() != 0 { + if r.events_endrx().read() != 0 { //trace!(" irq_rx: endrx"); - r.events_endrx.reset(); + r.events_endrx().write_value(0); let val = s.rx_ended_count.load(Ordering::Relaxed); s.rx_ended_count.store(val.wrapping_add(1), Ordering::Relaxed); @@ -144,7 +145,7 @@ impl interrupt::typelevel::Handler for Interrupt // Check if the PPI channel is still enabled. The PPI channel disables itself // when it fires, so if it's still enabled it hasn't fired. - let ppi_ch_enabled = ppi::regs().chen.read().bits() & (1 << chn) != 0; + let ppi_ch_enabled = ppi::regs().chen().read().ch(chn as _); // if rxend happened, and the ppi channel hasn't fired yet, the rxend got missed. // this condition also naturally matches if `!started`, needed to kickstart the DMA. @@ -152,10 +153,10 @@ impl interrupt::typelevel::Handler for Interrupt //trace!("manually starting."); // disable the ppi ch, it's of no use anymore. - ppi::regs().chenclr.write(|w| unsafe { w.bits(1 << chn) }); + ppi::regs().chenclr().write(|w| w.set_ch(chn as _, true)); // manually start - r.tasks_startrx.write(|w| unsafe { w.bits(1) }); + r.tasks_startrx().write_value(1); } rx.push_done(half_len); @@ -164,7 +165,7 @@ impl interrupt::typelevel::Handler for Interrupt s.rx_started.store(true, Ordering::Relaxed); } else { //trace!(" irq_rx: rxstarted no buf"); - r.intenclr.write(|w| w.rxstarted().clear()); + r.intenclr().write(|w| w.set_rxstarted(true)); } } } @@ -173,8 +174,8 @@ impl interrupt::typelevel::Handler for Interrupt if let Some(mut tx) = unsafe { s.tx_buf.try_reader() } { // TX end - if r.events_endtx.read().bits() != 0 { - r.events_endtx.reset(); + if r.events_endtx().read() != 0 { + r.events_endtx().write_value(0); let n = s.tx_count.load(Ordering::Relaxed); //trace!(" irq_tx: endtx {:?}", n); @@ -192,11 +193,11 @@ impl interrupt::typelevel::Handler for Interrupt s.tx_count.store(len, Ordering::Relaxed); // Set up the DMA write - r.txd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) }); - r.txd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) }); + r.txd().ptr().write_value(ptr as u32); + r.txd().maxcnt().write(|w| w.set_maxcnt(len as _)); // Start UARTE Transmit transaction - r.tasks_starttx.write(|w| unsafe { w.bits(1) }); + r.tasks_starttx().write_value(1); } } } @@ -308,7 +309,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> { let tx = BufferedUarteTx::new_innerer(unsafe { peri.clone_unchecked() }, txd, cts, tx_buffer); let rx = BufferedUarteRx::new_innerer(peri, timer, ppi_ch1, ppi_ch2, ppi_group, rxd, rts, rx_buffer); - U::regs().enable.write(|w| w.enable().enabled()); + U::regs().enable().write(|w| w.set_enable(vals::Enable::ENABLED)); U::Interrupt::pend(); unsafe { U::Interrupt::enable() }; @@ -320,7 +321,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> { /// Adjust the baud rate to the provided value. pub fn set_baudrate(&mut self, baudrate: Baudrate) { let r = U::regs(); - r.baudrate.write(|w| w.baudrate().variant(baudrate)); + r.baudrate().write(|w| w.set_baudrate(baudrate)); } /// Split the UART in reader and writer parts. @@ -415,7 +416,7 @@ impl<'d, U: UarteInstance> BufferedUarteTx<'d, U> { let this = Self::new_innerer(peri, txd, cts, tx_buffer); - U::regs().enable.write(|w| w.enable().enabled()); + U::regs().enable().write(|w| w.set_enable(vals::Enable::ENABLED)); U::Interrupt::pend(); unsafe { U::Interrupt::enable() }; @@ -432,14 +433,7 @@ impl<'d, U: UarteInstance> BufferedUarteTx<'d, U> { ) -> Self { let r = U::regs(); - txd.set_high(); - txd.conf().write(|w| w.dir().output().drive().h0h1()); - r.psel.txd.write(|w| unsafe { w.bits(txd.psel_bits()) }); - - if let Some(pin) = &cts { - pin.conf().write(|w| w.input().connect().drive().h0h1()); - } - r.psel.cts.write(|w| unsafe { w.bits(cts.psel_bits()) }); + configure_tx_pins(r, txd, cts); // Initialize state let s = U::buffered_state(); @@ -447,12 +441,11 @@ impl<'d, U: UarteInstance> BufferedUarteTx<'d, U> { let len = tx_buffer.len(); unsafe { s.tx_buf.init(tx_buffer.as_mut_ptr(), len) }; - r.events_txstarted.reset(); + r.events_txstarted().write_value(0); // Enable interrupts - r.intenset.write(|w| { - w.endtx().set(); - w + r.intenset().write(|w| { + w.set_endtx(true); }); Self { _peri: peri } @@ -532,15 +525,14 @@ impl<'a, U: UarteInstance> Drop for BufferedUarteTx<'a, U> { fn drop(&mut self) { let r = U::regs(); - r.intenclr.write(|w| { - w.txdrdy().set_bit(); - w.txstarted().set_bit(); - w.txstopped().set_bit(); - w + r.intenclr().write(|w| { + w.set_txdrdy(true); + w.set_txstarted(true); + w.set_txstopped(true); }); - r.events_txstopped.reset(); - r.tasks_stoptx.write(|w| unsafe { w.bits(1) }); - while r.events_txstopped.read().bits() == 0 {} + r.events_txstopped().write_value(0); + r.tasks_stoptx().write_value(1); + while r.events_txstopped().read() == 0 {} let s = U::buffered_state(); unsafe { s.tx_buf.deinit() } @@ -639,7 +631,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarteRx<'d, U, T> { let this = Self::new_innerer(peri, timer, ppi_ch1, ppi_ch2, ppi_group, rxd, rts, rx_buffer); - U::regs().enable.write(|w| w.enable().enabled()); + U::regs().enable().write(|w| w.set_enable(vals::Enable::ENABLED)); U::Interrupt::pend(); unsafe { U::Interrupt::enable() }; @@ -663,14 +655,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarteRx<'d, U, T> { let r = U::regs(); - rxd.conf().write(|w| w.input().connect().drive().h0h1()); - r.psel.rxd.write(|w| unsafe { w.bits(rxd.psel_bits()) }); - - if let Some(pin) = &rts { - pin.set_high(); - pin.conf().write(|w| w.dir().output().drive().h0h1()); - } - r.psel.rts.write(|w| unsafe { w.bits(rts.psel_bits()) }); + configure_rx_pins(r, rxd, rts); // Initialize state let s = U::buffered_state(); @@ -681,20 +666,19 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarteRx<'d, U, T> { unsafe { s.rx_buf.init(rx_buffer.as_mut_ptr(), rx_len) }; // clear errors - let errors = r.errorsrc.read().bits(); - r.errorsrc.write(|w| unsafe { w.bits(errors) }); + let errors = r.errorsrc().read(); + r.errorsrc().write_value(errors); - r.events_rxstarted.reset(); - r.events_error.reset(); - r.events_endrx.reset(); + r.events_rxstarted().write_value(0); + r.events_error().write_value(0); + r.events_endrx().write_value(0); // Enable interrupts - r.intenset.write(|w| { - w.endtx().set(); - w.rxstarted().set(); - w.error().set(); - w.endrx().set(); - w + r.intenset().write(|w| { + w.set_endtx(true); + w.set_rxstarted(true); + w.set_error(true); + w.set_endrx(true); }); // Configure byte counter. @@ -704,15 +688,15 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarteRx<'d, U, T> { timer.clear(); timer.start(); - let mut ppi_ch1 = Ppi::new_one_to_one(ppi_ch1, Event::from_reg(&r.events_rxdrdy), timer.task_count()); + let mut ppi_ch1 = Ppi::new_one_to_one(ppi_ch1, Event::from_reg(r.events_rxdrdy()), timer.task_count()); ppi_ch1.enable(); s.rx_ppi_ch.store(ppi_ch2.number() as u8, Ordering::Relaxed); let mut ppi_group = PpiGroup::new(ppi_group); let mut ppi_ch2 = Ppi::new_one_to_two( ppi_ch2, - Event::from_reg(&r.events_endrx), - Task::from_reg(&r.tasks_startrx), + Event::from_reg(r.events_endrx()), + Task::from_reg(r.tasks_startrx()), ppi_group.task_disable_all(), ); ppi_ch2.disable(); @@ -747,8 +731,8 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarteRx<'d, U, T> { let ss = U::state(); // Read the RXDRDY counter. - T::regs().tasks_capture[0].write(|w| unsafe { w.bits(1) }); - let mut end = T::regs().cc[0].read().bits() as usize; + T::regs().tasks_capture(0).write_value(1); + let mut end = T::regs().cc(0).read() as usize; //trace!(" rxdrdy count = {:?}", end); // We've set a compare channel that resets the counter to 0 when it reaches `len*2`. @@ -769,7 +753,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarteRx<'d, U, T> { if start == end { //trace!(" empty"); ss.rx_waker.register(cx.waker()); - r.intenset.write(|w| w.rxdrdy().set_bit()); + r.intenset().write(|w| w.set_rxdrdy(true)); return Poll::Pending; } @@ -799,7 +783,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarteRx<'d, U, T> { let s = U::buffered_state(); let mut rx = unsafe { s.rx_buf.reader() }; rx.pop_done(amt); - U::regs().intenset.write(|w| w.rxstarted().set()); + U::regs().intenset().write(|w| w.set_rxstarted(true)); } /// we are ready to read if there is data in the buffer @@ -817,15 +801,14 @@ impl<'a, U: UarteInstance, T: TimerInstance> Drop for BufferedUarteRx<'a, U, T> self.timer.stop(); - r.intenclr.write(|w| { - w.rxdrdy().set_bit(); - w.rxstarted().set_bit(); - w.rxto().set_bit(); - w + r.intenclr().write(|w| { + w.set_rxdrdy(true); + w.set_rxstarted(true); + w.set_rxto(true); }); - r.events_rxto.reset(); - r.tasks_stoprx.write(|w| unsafe { w.bits(1) }); - while r.events_rxto.read().bits() == 0 {} + r.events_rxto().write_value(0); + r.tasks_stoprx().write_value(1); + while r.events_rxto().read() == 0 {} let s = U::buffered_state(); unsafe { s.rx_buf.deinit() } diff --git a/embassy-nrf/src/chips/nrf51.rs b/embassy-nrf/src/chips/nrf51.rs index cc1cbc8a0..95fa926c3 100644 --- a/embassy-nrf/src/chips/nrf51.rs +++ b/embassy-nrf/src/chips/nrf51.rs @@ -1,4 +1,4 @@ -pub use nrf51_pac as pac; +pub use nrf_pac as pac; /// The maximum buffer size that the EasyDMA can send/recv in one operation. pub const EASY_DMA_SIZE: usize = (1 << 14) - 1; diff --git a/embassy-nrf/src/chips/nrf52805.rs b/embassy-nrf/src/chips/nrf52805.rs index b51b0c93e..fc8db856c 100644 --- a/embassy-nrf/src/chips/nrf52805.rs +++ b/embassy-nrf/src/chips/nrf52805.rs @@ -1,4 +1,4 @@ -pub use nrf52805_pac as pac; +pub use nrf_pac as pac; /// The maximum buffer size that the EasyDMA can send/recv in one operation. pub const EASY_DMA_SIZE: usize = (1 << 14) - 1; diff --git a/embassy-nrf/src/chips/nrf52810.rs b/embassy-nrf/src/chips/nrf52810.rs index 273098d9b..11a8b4dde 100644 --- a/embassy-nrf/src/chips/nrf52810.rs +++ b/embassy-nrf/src/chips/nrf52810.rs @@ -1,4 +1,4 @@ -pub use nrf52810_pac as pac; +pub use nrf_pac as pac; /// The maximum buffer size that the EasyDMA can send/recv in one operation. pub const EASY_DMA_SIZE: usize = (1 << 10) - 1; diff --git a/embassy-nrf/src/chips/nrf52811.rs b/embassy-nrf/src/chips/nrf52811.rs index 9bce38636..077a36e31 100644 --- a/embassy-nrf/src/chips/nrf52811.rs +++ b/embassy-nrf/src/chips/nrf52811.rs @@ -1,4 +1,4 @@ -pub use nrf52811_pac as pac; +pub use nrf_pac as pac; /// The maximum buffer size that the EasyDMA can send/recv in one operation. pub const EASY_DMA_SIZE: usize = (1 << 14) - 1; diff --git a/embassy-nrf/src/chips/nrf52820.rs b/embassy-nrf/src/chips/nrf52820.rs index 2acae2c8f..6ee16706d 100644 --- a/embassy-nrf/src/chips/nrf52820.rs +++ b/embassy-nrf/src/chips/nrf52820.rs @@ -1,4 +1,4 @@ -pub use nrf52820_pac as pac; +pub use nrf_pac as pac; /// The maximum buffer size that the EasyDMA can send/recv in one operation. pub const EASY_DMA_SIZE: usize = (1 << 15) - 1; diff --git a/embassy-nrf/src/chips/nrf52832.rs b/embassy-nrf/src/chips/nrf52832.rs index 94b373ab3..4a7a29229 100644 --- a/embassy-nrf/src/chips/nrf52832.rs +++ b/embassy-nrf/src/chips/nrf52832.rs @@ -1,4 +1,4 @@ -pub use nrf52832_pac as pac; +pub use nrf_pac as pac; /// The maximum buffer size that the EasyDMA can send/recv in one operation. pub const EASY_DMA_SIZE: usize = (1 << 8) - 1; diff --git a/embassy-nrf/src/chips/nrf52833.rs b/embassy-nrf/src/chips/nrf52833.rs index 09cde1ac1..6d70b763f 100644 --- a/embassy-nrf/src/chips/nrf52833.rs +++ b/embassy-nrf/src/chips/nrf52833.rs @@ -1,4 +1,4 @@ -pub use nrf52833_pac as pac; +pub use nrf_pac as pac; /// The maximum buffer size that the EasyDMA can send/recv in one operation. pub const EASY_DMA_SIZE: usize = (1 << 16) - 1; diff --git a/embassy-nrf/src/chips/nrf52840.rs b/embassy-nrf/src/chips/nrf52840.rs index 0f3d1b250..b6afbf213 100644 --- a/embassy-nrf/src/chips/nrf52840.rs +++ b/embassy-nrf/src/chips/nrf52840.rs @@ -1,4 +1,4 @@ -pub use nrf52840_pac as pac; +pub use nrf_pac as pac; /// The maximum buffer size that the EasyDMA can send/recv in one operation. pub const EASY_DMA_SIZE: usize = (1 << 16) - 1; diff --git a/embassy-nrf/src/chips/nrf5340_app.rs b/embassy-nrf/src/chips/nrf5340_app.rs index 584f6e43c..43588eef3 100644 --- a/embassy-nrf/src/chips/nrf5340_app.rs +++ b/embassy-nrf/src/chips/nrf5340_app.rs @@ -5,16 +5,17 @@ pub mod pac { // The nRF5340 has a secure and non-secure (NS) mode. // To avoid cfg spam, we remove _ns or _s suffixes here. - pub use nrf5340_app_pac::NVIC_PRIO_BITS; + #[cfg(feature="rt")] + pub use nrf_pac::NVIC_PRIO_BITS; + pub use nrf_pac::{common, shared}; #[cfg(feature="rt")] #[doc(no_inline)] - pub use nrf5340_app_pac::interrupt; + pub use nrf_pac::interrupt; #[doc(no_inline)] - pub use nrf5340_app_pac::{ + pub use nrf_pac::{ Interrupt, - Peripherals, cache_s as cache, cachedata_s as cachedata, @@ -26,11 +27,11 @@ pub mod pac { ctrlap_ns as ctrlap, dcnf_ns as dcnf, dppic_ns as dppic, - egu0_ns as egu0, + egu_ns as egu, ficr_s as ficr, fpu_ns as fpu, - gpiote0_s as gpiote, - i2s0_ns as i2s0, + gpiote_s as gpiote, + i2s_ns as i2s, ipc_ns as ipc, kmu_ns as kmu, lpcomp_ns as lpcomp, @@ -38,36 +39,36 @@ pub mod pac { nfct_ns as nfct, nvmc_ns as nvmc, oscillators_ns as oscillators, - p0_ns as p0, - pdm0_ns as pdm, + gpio_ns as gpio, + pdm_ns as pdm, power_ns as power, - pwm0_ns as pwm0, - qdec0_ns as qdec, + pwm_ns as pwm, + qdec_ns as qdec, qspi_ns as qspi, regulators_ns as regulators, reset_ns as reset, - rtc0_ns as rtc0, + rtc_ns as rtc, saadc_ns as saadc, - spim0_ns as spim0, - spis0_ns as spis0, + spim_ns as spim, + spis_ns as spis, spu_s as spu, tad_s as tad, - timer0_ns as timer0, - twim0_ns as twim0, - twis0_ns as twis0, - uarte0_ns as uarte0, + timer_ns as timer, + twim_ns as twim, + twis_ns as twis, + uarte_ns as uarte, uicr_s as uicr, usbd_ns as usbd, usbregulator_ns as usbregulator, vmc_ns as vmc, - wdt0_ns as wdt0, + wdt_ns as wdt, }; /// Non-Secure mode (NS) peripherals pub mod ns { #[cfg(feature = "nrf5340-app-ns")] #[doc(no_inline)] - pub use nrf5340_app_pac::{ + pub use nrf_pac::{ CLOCK_NS as CLOCK, COMP_NS as COMP, CTRLAP_NS as CTRLAP, @@ -141,7 +142,7 @@ pub mod pac { pub mod s { #[cfg(feature = "nrf5340-app-s")] #[doc(no_inline)] - pub use nrf5340_app_pac::{ + pub use nrf_pac::{ CACHEDATA_S as CACHEDATA, CACHEINFO_S as CACHEINFO, CACHE_S as CACHE, diff --git a/embassy-nrf/src/chips/nrf5340_net.rs b/embassy-nrf/src/chips/nrf5340_net.rs index d772c9a49..00ff5fea6 100644 --- a/embassy-nrf/src/chips/nrf5340_net.rs +++ b/embassy-nrf/src/chips/nrf5340_net.rs @@ -5,16 +5,17 @@ pub mod pac { // The nRF5340 has a secure and non-secure (NS) mode. // To avoid cfg spam, we remove _ns or _s suffixes here. - pub use nrf5340_net_pac::NVIC_PRIO_BITS; + #[cfg(feature="rt")] + pub use nrf_pac::NVIC_PRIO_BITS; + pub use nrf_pac::{common, shared}; #[cfg(feature="rt")] #[doc(no_inline)] - pub use nrf5340_net_pac::interrupt; + pub use nrf_pac::interrupt; #[doc(no_inline)] - pub use nrf5340_net_pac::{ + pub use nrf_pac::{ Interrupt, - Peripherals, aar_ns as aar, acl_ns as acl, @@ -26,25 +27,25 @@ pub mod pac { dcnf_ns as dcnf, dppic_ns as dppic, ecb_ns as ecb, - egu0_ns as egu0, + egu_ns as egu, ficr_ns as ficr, gpiote_ns as gpiote, ipc_ns as ipc, nvmc_ns as nvmc, - p0_ns as p0, + gpio_ns as gpio, power_ns as power, radio_ns as radio, reset_ns as reset, rng_ns as rng, - rtc0_ns as rtc0, - spim0_ns as spim0, - spis0_ns as spis0, - swi0_ns as swi0, + rtc_ns as rtc, + spim_ns as spim, + spis_ns as spis, + swi_ns as swi, temp_ns as temp, - timer0_ns as timer0, - twim0_ns as twim0, - twis0_ns as twis0, - uarte0_ns as uarte0, + timer_ns as timer, + twim_ns as twim, + twis_ns as twis, + uarte_ns as uarte, uicr_ns as uicr, vmc_ns as vmc, vreqctrl_ns as vreqctrl, @@ -54,25 +55,17 @@ pub mod pac { ACL_NS as ACL, APPMUTEX_NS as APPMUTEX, APPMUTEX_S as APPMUTEX_S, - CBP as CBP, CCM_NS as CCM, CLOCK_NS as CLOCK, - CPUID as CPUID, CTI_NS as CTI, CTRLAP_NS as CTRLAP, - DCB as DCB, DCNF_NS as DCNF, DPPIC_NS as DPPIC, - DWT as DWT, ECB_NS as ECB, EGU0_NS as EGU0, FICR_NS as FICR, - FPB as FPB, GPIOTE_NS as GPIOTE, IPC_NS as IPC, - ITM as ITM, - MPU as MPU, - NVIC as NVIC, NVMC_NS as NVMC, P0_NS as P0, P1_NS as P1, @@ -82,19 +75,16 @@ pub mod pac { RNG_NS as RNG, RTC0_NS as RTC0, RTC1_NS as RTC1, - SCB as SCB, SPIM0_NS as SPIM0, SPIS0_NS as SPIS0, SWI0_NS as SWI0, SWI1_NS as SWI1, SWI2_NS as SWI2, SWI3_NS as SWI3, - SYST as SYST, TEMP_NS as TEMP, TIMER0_NS as TIMER0, TIMER1_NS as TIMER1, TIMER2_NS as TIMER2, - TPIU as TPIU, TWIM0_NS as TWIM0, TWIS0_NS as TWIS0, UARTE0_NS as UARTE0, diff --git a/embassy-nrf/src/chips/nrf9120.rs b/embassy-nrf/src/chips/nrf9120.rs index b53510118..b89570dcd 100644 --- a/embassy-nrf/src/chips/nrf9120.rs +++ b/embassy-nrf/src/chips/nrf9120.rs @@ -5,14 +5,16 @@ pub mod pac { // The nRF9120 has a secure and non-secure (NS) mode. // To avoid cfg spam, we remove _ns or _s suffixes here. - pub use nrf9120_pac::NVIC_PRIO_BITS; + #[cfg(feature="rt")] + pub use nrf_pac::NVIC_PRIO_BITS; + pub use nrf_pac::{common, shared}; #[cfg(feature="rt")] #[doc(no_inline)] - pub use nrf9120_pac::interrupt; + pub use nrf_pac::interrupt; #[doc(no_inline)] - pub use nrf9120_pac::{ + pub use nrf_pac::{ Interrupt, cc_host_rgf_s as cc_host_rgf, @@ -20,29 +22,29 @@ pub mod pac { cryptocell_s as cryptocell, ctrl_ap_peri_s as ctrl_ap_peri, dppic_ns as dppic, - egu0_ns as egu0, + egu_ns as egu, ficr_s as ficr, fpu_ns as fpu, - gpiote0_s as gpiote, + gpiote_s as gpiote, i2s_ns as i2s, ipc_ns as ipc, kmu_ns as kmu, nvmc_ns as nvmc, - p0_ns as p0, + gpio_ns as gpio, pdm_ns as pdm, power_ns as power, - pwm0_ns as pwm0, + pwm_ns as pwm, regulators_ns as regulators, - rtc0_ns as rtc0, + rtc_ns as rtc, saadc_ns as saadc, - spim0_ns as spim0, - spis0_ns as spis0, + spim_ns as spim, + spis_ns as spis, spu_s as spu, tad_s as tad, - timer0_ns as timer0, - twim0_ns as twim0, - twis0_ns as twis0, - uarte0_ns as uarte0, + timer_ns as timer, + twim_ns as twim, + twis_ns as twis, + uarte_ns as uarte, uicr_s as uicr, vmc_ns as vmc, wdt_ns as wdt, @@ -51,7 +53,7 @@ pub mod pac { /// Non-Secure mode (NS) peripherals pub mod ns { #[doc(no_inline)] - pub use nrf9120_pac::{ + pub use nrf_pac::{ CLOCK_NS as CLOCK, DPPIC_NS as DPPIC, EGU0_NS as EGU0, @@ -108,7 +110,7 @@ pub mod pac { /// Secure mode (S) peripherals pub mod s { #[doc(no_inline)] - pub use nrf9120_pac::{ + pub use nrf_pac::{ CC_HOST_RGF_S as CC_HOST_RGF, CLOCK_S as CLOCK, CRYPTOCELL_S as CRYPTOCELL, @@ -121,7 +123,7 @@ pub mod pac { EGU4_S as EGU4, EGU5_S as EGU5, FICR_S as FICR, - FPU as FPU, + FPU_NS as FPU, GPIOTE0_S as GPIOTE0, I2S_S as I2S, IPC_S as IPC, diff --git a/embassy-nrf/src/chips/nrf9160.rs b/embassy-nrf/src/chips/nrf9160.rs index 8107ca175..dba3d1ef5 100644 --- a/embassy-nrf/src/chips/nrf9160.rs +++ b/embassy-nrf/src/chips/nrf9160.rs @@ -5,14 +5,16 @@ pub mod pac { // The nRF9160 has a secure and non-secure (NS) mode. // To avoid cfg spam, we remove _ns or _s suffixes here. - pub use nrf9160_pac::NVIC_PRIO_BITS; + #[cfg(feature="rt")] + pub use nrf_pac::NVIC_PRIO_BITS; + pub use nrf_pac::{common, shared}; #[cfg(feature="rt")] #[doc(no_inline)] - pub use nrf9160_pac::interrupt; + pub use nrf_pac::interrupt; #[doc(no_inline)] - pub use nrf9160_pac::{ + pub use nrf_pac::{ Interrupt, cc_host_rgf_s as cc_host_rgf, @@ -20,29 +22,29 @@ pub mod pac { cryptocell_s as cryptocell, ctrl_ap_peri_s as ctrl_ap_peri, dppic_ns as dppic, - egu0_ns as egu0, + egu_ns as egu, ficr_s as ficr, fpu_ns as fpu, - gpiote0_s as gpiote, + gpiote_s as gpiote, i2s_ns as i2s, ipc_ns as ipc, kmu_ns as kmu, nvmc_ns as nvmc, - p0_ns as p0, + gpio_ns as gpio, pdm_ns as pdm, power_ns as power, - pwm0_ns as pwm0, + pwm_ns as pwm, regulators_ns as regulators, - rtc0_ns as rtc0, + rtc_ns as rtc, saadc_ns as saadc, - spim0_ns as spim0, - spis0_ns as spis0, + spim_ns as spim, + spis_ns as spis, spu_s as spu, tad_s as tad, - timer0_ns as timer0, - twim0_ns as twim0, - twis0_ns as twis0, - uarte0_ns as uarte0, + timer_ns as timer, + twim_ns as twim, + twis_ns as twis, + uarte_ns as uarte, uicr_s as uicr, vmc_ns as vmc, wdt_ns as wdt, @@ -51,7 +53,7 @@ pub mod pac { /// Non-Secure mode (NS) peripherals pub mod ns { #[doc(no_inline)] - pub use nrf9160_pac::{ + pub use nrf_pac::{ CLOCK_NS as CLOCK, DPPIC_NS as DPPIC, EGU0_NS as EGU0, @@ -108,7 +110,7 @@ pub mod pac { /// Secure mode (S) peripherals pub mod s { #[doc(no_inline)] - pub use nrf9160_pac::{ + pub use nrf_pac::{ CC_HOST_RGF_S as CC_HOST_RGF, CLOCK_S as CLOCK, CRYPTOCELL_S as CRYPTOCELL, diff --git a/embassy-nrf/src/egu.rs b/embassy-nrf/src/egu.rs index 204446d29..7f9abdac4 100644 --- a/embassy-nrf/src/egu.rs +++ b/embassy-nrf/src/egu.rs @@ -34,7 +34,7 @@ impl<'d, T: Instance> Egu<'d, T> { } pub(crate) trait SealedInstance { - fn regs() -> &'static pac::egu0::RegisterBlock; + fn regs() -> pac::egu::Egu; } /// Basic Egu instance. @@ -47,8 +47,8 @@ pub trait Instance: Peripheral

+ SealedInstance + 'static + Send { macro_rules! impl_egu { ($type:ident, $pac_type:ident, $irq:ident) => { impl crate::egu::SealedInstance for peripherals::$type { - fn regs() -> &'static pac::egu0::RegisterBlock { - unsafe { &*pac::$pac_type::ptr() } + fn regs() -> pac::egu::Egu { + pac::$pac_type } } impl crate::egu::Instance for peripherals::$type { @@ -68,32 +68,26 @@ impl<'d, T: Instance> Trigger<'d, T> { pub fn task(&self) -> Task<'d> { let nr = self.number as usize; let regs = T::regs(); - Task::from_reg(®s.tasks_trigger[nr]) + Task::from_reg(regs.tasks_trigger(nr)) } /// Get event for this trigger to use with PPI. pub fn event(&self) -> Event<'d> { let nr = self.number as usize; let regs = T::regs(); - Event::from_reg(®s.events_triggered[nr]) + Event::from_reg(regs.events_triggered(nr)) } /// Enable interrupts for this trigger pub fn enable_interrupt(&mut self) { let regs = T::regs(); - unsafe { - regs.intenset - .modify(|r, w| w.bits(r.bits() | (1 << self.number as usize))) - }; + regs.intenset().modify(|w| w.set_triggered(self.number as usize, true)); } /// Enable interrupts for this trigger pub fn disable_interrupt(&mut self) { let regs = T::regs(); - unsafe { - regs.intenclr - .modify(|r, w| w.bits(r.bits() | (1 << self.number as usize))) - }; + regs.intenset().modify(|w| w.set_triggered(self.number as usize, false)); } } diff --git a/embassy-nrf/src/gpio.rs b/embassy-nrf/src/gpio.rs index dbc26ea3f..35b0f2e7b 100644 --- a/embassy-nrf/src/gpio.rs +++ b/embassy-nrf/src/gpio.rs @@ -7,14 +7,11 @@ use core::hint::unreachable_unchecked; use cfg_if::cfg_if; use embassy_hal_internal::{impl_peripheral, into_ref, PeripheralRef}; -#[cfg(feature = "nrf51")] +use crate::pac::common::{Reg, RW}; use crate::pac::gpio; -#[cfg(feature = "nrf51")] -use crate::pac::gpio::pin_cnf::{DRIVE_A, PULL_A}; -#[cfg(not(feature = "nrf51"))] -use crate::pac::p0 as gpio; -#[cfg(not(feature = "nrf51"))] -use crate::pac::p0::pin_cnf::{DRIVE_A, PULL_A}; +use crate::pac::gpio::vals; +#[cfg(not(feature = "_nrf51"))] +use crate::pac::shared::{regs::Psel, vals::Connect}; use crate::{pac, Peripheral}; /// A GPIO port with up to 32 pins. @@ -103,7 +100,7 @@ impl From for bool { } /// Drive strength settings for an output pin. -// These numbers match DRIVE_A exactly so hopefully the compiler will unify them. +// These numbers match vals::Drive exactly so hopefully the compiler will unify them. #[derive(Clone, Copy, Debug, PartialEq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[repr(u8)] @@ -188,24 +185,24 @@ impl<'d> Output<'d> { } } -pub(crate) fn convert_drive(drive: OutputDrive) -> DRIVE_A { +pub(crate) fn convert_drive(drive: OutputDrive) -> vals::Drive { match drive { - OutputDrive::Standard => DRIVE_A::S0S1, - OutputDrive::HighDrive0Standard1 => DRIVE_A::H0S1, - OutputDrive::Standard0HighDrive1 => DRIVE_A::S0H1, - OutputDrive::HighDrive => DRIVE_A::H0H1, - OutputDrive::Disconnect0Standard1 => DRIVE_A::D0S1, - OutputDrive::Disconnect0HighDrive1 => DRIVE_A::D0H1, - OutputDrive::Standard0Disconnect1 => DRIVE_A::S0D1, - OutputDrive::HighDrive0Disconnect1 => DRIVE_A::H0D1, + OutputDrive::Standard => vals::Drive::S0S1, + OutputDrive::HighDrive0Standard1 => vals::Drive::H0S1, + OutputDrive::Standard0HighDrive1 => vals::Drive::S0H1, + OutputDrive::HighDrive => vals::Drive::H0H1, + OutputDrive::Disconnect0Standard1 => vals::Drive::D0S1, + OutputDrive::Disconnect0HighDrive1 => vals::Drive::D0H1, + OutputDrive::Standard0Disconnect1 => vals::Drive::S0D1, + OutputDrive::HighDrive0Disconnect1 => vals::Drive::H0D1, } } -fn convert_pull(pull: Pull) -> PULL_A { +fn convert_pull(pull: Pull) -> vals::Pull { match pull { - Pull::None => PULL_A::DISABLED, - Pull::Up => PULL_A::PULLUP, - Pull::Down => PULL_A::PULLDOWN, + Pull::None => vals::Pull::DISABLED, + Pull::Up => vals::Pull::PULLUP, + Pull::Down => vals::Pull::PULLDOWN, } } @@ -234,12 +231,11 @@ impl<'d> Flex<'d> { #[inline] pub fn set_as_input(&mut self, pull: Pull) { self.pin.conf().write(|w| { - w.dir().input(); - w.input().connect(); - w.pull().variant(convert_pull(pull)); - w.drive().s0s1(); - w.sense().disabled(); - w + w.set_dir(vals::Dir::INPUT); + w.set_input(vals::Input::CONNECT); + w.set_pull(convert_pull(pull)); + w.set_drive(vals::Drive::S0S1); + w.set_sense(vals::Sense::DISABLED); }); } @@ -250,12 +246,11 @@ impl<'d> Flex<'d> { #[inline] pub fn set_as_output(&mut self, drive: OutputDrive) { self.pin.conf().write(|w| { - w.dir().output(); - w.input().disconnect(); - w.pull().disabled(); - w.drive().variant(convert_drive(drive)); - w.sense().disabled(); - w + w.set_dir(vals::Dir::OUTPUT); + w.set_input(vals::Input::DISCONNECT); + w.set_pull(vals::Pull::DISABLED); + w.set_drive(convert_drive(drive)); + w.set_sense(vals::Sense::DISABLED); }); } @@ -271,31 +266,30 @@ impl<'d> Flex<'d> { #[inline] pub fn set_as_input_output(&mut self, pull: Pull, drive: OutputDrive) { self.pin.conf().write(|w| { - w.dir().output(); - w.input().connect(); - w.pull().variant(convert_pull(pull)); - w.drive().variant(convert_drive(drive)); - w.sense().disabled(); - w + w.set_dir(vals::Dir::OUTPUT); + w.set_input(vals::Input::CONNECT); + w.set_pull(convert_pull(pull)); + w.set_drive(convert_drive(drive)); + w.set_sense(vals::Sense::DISABLED); }); } /// Put the pin into disconnected mode. #[inline] pub fn set_as_disconnected(&mut self) { - self.pin.conf().reset(); + self.pin.conf().write(|_| ()); } /// Get whether the pin input level is high. #[inline] pub fn is_high(&self) -> bool { - !self.is_low() + self.pin.block().in_().read().pin(self.pin.pin() as _) } /// Get whether the pin input level is low. #[inline] pub fn is_low(&self) -> bool { - self.pin.block().in_.read().bits() & (1 << self.pin.pin()) == 0 + !self.is_high() } /// Get the pin input level. @@ -338,13 +332,13 @@ impl<'d> Flex<'d> { /// Get whether the output level is set to high. #[inline] pub fn is_set_high(&self) -> bool { - !self.is_set_low() + self.pin.block().out().read().pin(self.pin.pin() as _) } /// Get whether the output level is set to low. #[inline] pub fn is_set_low(&self) -> bool { - self.pin.block().out.read().bits() & (1 << self.pin.pin()) == 0 + !self.is_set_high() } /// Get the current output level. @@ -356,7 +350,7 @@ impl<'d> Flex<'d> { impl<'d> Drop for Flex<'d> { fn drop(&mut self) { - self.pin.conf().reset(); + self.pin.conf().write(|_| ()) } } @@ -375,35 +369,33 @@ pub(crate) trait SealedPin { } #[inline] - fn block(&self) -> &gpio::RegisterBlock { - unsafe { - match self.pin_port() / 32 { - #[cfg(feature = "nrf51")] - 0 => &*pac::GPIO::ptr(), - #[cfg(not(feature = "nrf51"))] - 0 => &*pac::P0::ptr(), - #[cfg(feature = "_gpio-p1")] - 1 => &*pac::P1::ptr(), - _ => unreachable_unchecked(), - } + fn block(&self) -> gpio::Gpio { + match self.pin_port() / 32 { + #[cfg(feature = "_nrf51")] + 0 => pac::GPIO, + #[cfg(not(feature = "_nrf51"))] + 0 => pac::P0, + #[cfg(feature = "_gpio-p1")] + 1 => pac::P1, + _ => unsafe { unreachable_unchecked() }, } } #[inline] - fn conf(&self) -> &gpio::PIN_CNF { - &self.block().pin_cnf[self._pin() as usize] + fn conf(&self) -> Reg { + self.block().pin_cnf(self._pin() as usize) } /// Set the output as high. #[inline] fn set_high(&self) { - unsafe { self.block().outset.write(|w| w.bits(1u32 << self._pin())) } + self.block().outset().write(|w| w.set_pin(self._pin() as _, true)) } /// Set the output as low. #[inline] fn set_low(&self) { - unsafe { self.block().outclr.write(|w| w.bits(1u32 << self._pin())) } + self.block().outclr().write(|w| w.set_pin(self._pin() as _, true)) } } @@ -429,8 +421,9 @@ pub trait Pin: Peripheral

+ Into + SealedPin + Sized + 'static /// Peripheral port register value #[inline] - fn psel_bits(&self) -> u32 { - self.pin_port() as u32 + #[cfg(not(feature = "_nrf51"))] + fn psel_bits(&self) -> pac::shared::regs::Psel { + pac::shared::regs::Psel(self.pin_port() as u32) } /// Convert from concrete pin type PX_XX to type erased `AnyPin`. @@ -471,26 +464,30 @@ impl SealedPin for AnyPin { #[cfg(not(feature = "_nrf51"))] pub(crate) trait PselBits { - fn psel_bits(&self) -> u32; + fn psel_bits(&self) -> pac::shared::regs::Psel; } #[cfg(not(feature = "_nrf51"))] impl<'a, P: Pin> PselBits for Option> { #[inline] - fn psel_bits(&self) -> u32 { + fn psel_bits(&self) -> pac::shared::regs::Psel { match self { Some(pin) => pin.psel_bits(), - None => 1u32 << 31, + None => DISCONNECTED, } } } +#[cfg(not(feature = "_nrf51"))] +pub(crate) const DISCONNECTED: Psel = Psel(1 << 31); + +#[cfg(not(feature = "_nrf51"))] #[allow(dead_code)] -pub(crate) fn deconfigure_pin(psel_bits: u32) { - if psel_bits & 0x8000_0000 != 0 { +pub(crate) fn deconfigure_pin(psel: Psel) { + if psel.connect() == Connect::DISCONNECTED { return; } - unsafe { AnyPin::steal(psel_bits as _).conf().reset() } + unsafe { AnyPin::steal(psel.0 as _).conf().write(|_| ()) } } // ==================== diff --git a/embassy-nrf/src/gpiote.rs b/embassy-nrf/src/gpiote.rs index 9d97c7be9..87bb405f4 100644 --- a/embassy-nrf/src/gpiote.rs +++ b/embassy-nrf/src/gpiote.rs @@ -9,10 +9,14 @@ use embassy_sync::waitqueue::AtomicWaker; use crate::gpio::{AnyPin, Flex, Input, Output, Pin as GpioPin, SealedPin as _}; use crate::interrupt::InterruptExt; +#[cfg(not(feature = "_nrf51"))] +use crate::pac::gpio::vals::Detectmode; +use crate::pac::gpio::vals::Sense; +use crate::pac::gpiote::vals::{Mode, Outinit, Polarity}; use crate::ppi::{Event, Task}; use crate::{interrupt, pac, peripherals}; -#[cfg(feature = "nrf51")] +#[cfg(feature = "_nrf51")] /// Amount of GPIOTE channels in the chip. const CHANNEL_COUNT: usize = 4; #[cfg(not(feature = "_nrf51"))] @@ -51,14 +55,14 @@ pub enum OutputChannelPolarity { Toggle, } -fn regs() -> &'static pac::gpiote::RegisterBlock { +fn regs() -> pac::gpiote::Gpiote { cfg_if::cfg_if! { if #[cfg(any(feature="nrf5340-app-s", feature="nrf9160-s", feature="nrf9120-s"))] { - unsafe { &*pac::GPIOTE0::ptr() } + pac::GPIOTE0 } else if #[cfg(any(feature="nrf5340-app-ns", feature="nrf9160-ns", feature="nrf9120-ns"))] { - unsafe { &*pac::GPIOTE1::ptr() } + pac::GPIOTE1 } else { - unsafe { &*pac::GPIOTE::ptr() } + pac::GPIOTE } } } @@ -68,15 +72,15 @@ pub(crate) fn init(irq_prio: crate::interrupt::Priority) { #[cfg(not(feature = "_nrf51"))] { #[cfg(any(feature = "nrf52833", feature = "nrf52840", feature = "_nrf5340"))] - let ports = unsafe { &[&*pac::P0::ptr(), &*pac::P1::ptr()] }; + let ports = &[pac::P0, pac::P1]; #[cfg(not(any(feature = "_nrf51", feature = "nrf52833", feature = "nrf52840", feature = "_nrf5340")))] - let ports = unsafe { &[&*pac::P0::ptr()] }; + let ports = &[pac::P0]; for &p in ports { // Enable latched detection - p.detectmode.write(|w| w.detectmode().ldetect()); + p.detectmode().write(|w| w.set_detectmode(Detectmode::LDETECT)); // Clear latch - p.latch.write(|w| unsafe { w.bits(0xFFFFFFFF) }) + p.latch().write(|w| w.0 = 0xFFFFFFFF) } } @@ -93,7 +97,7 @@ pub(crate) fn init(irq_prio: crate::interrupt::Priority) { unsafe { irq.enable() }; let g = regs(); - g.intenset.write(|w| w.port().set()); + g.intenset().write(|w| w.set_port(true)); } #[cfg(any(feature = "nrf5340-app-s", feature = "nrf9160-s", feature = "nrf9120-s"))] @@ -121,47 +125,47 @@ unsafe fn handle_gpiote_interrupt() { let g = regs(); for i in 0..CHANNEL_COUNT { - if g.events_in[i].read().bits() != 0 { - g.intenclr.write(|w| w.bits(1 << i)); + if g.events_in(i).read() != 0 { + g.intenclr().write(|w| w.0 = 1 << i); CHANNEL_WAKERS[i].wake(); } } - if g.events_port.read().bits() != 0 { - g.events_port.write(|w| w); + if g.events_port().read() != 0 { + g.events_port().write_value(0); #[cfg(any(feature = "nrf52833", feature = "nrf52840", feature = "_nrf5340"))] - let ports = &[&*pac::P0::ptr(), &*pac::P1::ptr()]; + let ports = &[pac::P0, pac::P1]; #[cfg(not(any(feature = "_nrf51", feature = "nrf52833", feature = "nrf52840", feature = "_nrf5340")))] - let ports = &[&*pac::P0::ptr()]; + let ports = &[pac::P0]; #[cfg(feature = "_nrf51")] - let ports = unsafe { &[&*pac::GPIO::ptr()] }; + let ports = &[pac::GPIO]; #[cfg(feature = "_nrf51")] for (port, &p) in ports.iter().enumerate() { - let inp = p.in_.read().bits(); + let inp = p.in_().read(); for pin in 0..32 { - let fired = match p.pin_cnf[pin as usize].read().sense().variant() { - Some(pac::gpio::pin_cnf::SENSE_A::HIGH) => inp & (1 << pin) != 0, - Some(pac::gpio::pin_cnf::SENSE_A::LOW) => inp & (1 << pin) == 0, + let fired = match p.pin_cnf(pin as usize).read().sense() { + Sense::HIGH => inp.pin(pin), + Sense::LOW => !inp.pin(pin), _ => false, }; if fired { PORT_WAKERS[port * 32 + pin as usize].wake(); - p.pin_cnf[pin as usize].modify(|_, w| w.sense().disabled()); + p.pin_cnf(pin as usize).modify(|w| w.set_sense(Sense::DISABLED)); } } } #[cfg(not(feature = "_nrf51"))] for (port, &p) in ports.iter().enumerate() { - let bits = p.latch.read().bits(); + let bits = p.latch().read().0; for pin in BitIter(bits) { - p.pin_cnf[pin as usize].modify(|_, w| w.sense().disabled()); + p.pin_cnf(pin as usize).modify(|w| w.set_sense(Sense::DISABLED)); PORT_WAKERS[port * 32 + pin as usize].wake(); } - p.latch.write(|w| w.bits(bits)); + p.latch().write(|w| w.0 = bits); } } } @@ -194,8 +198,8 @@ impl<'d> Drop for InputChannel<'d> { fn drop(&mut self) { let g = regs(); let num = self.ch.number(); - g.config[num].write(|w| w.mode().disabled()); - g.intenclr.write(|w| unsafe { w.bits(1 << num) }); + g.config(num).write(|w| w.set_mode(Mode::DISABLED)); + g.intenclr().write(|w| w.0 = 1 << num); } } @@ -207,22 +211,23 @@ impl<'d> InputChannel<'d> { let g = regs(); let num = ch.number(); - g.config[num].write(|w| { + g.config(num).write(|w| { + w.set_mode(Mode::EVENT); match polarity { - InputChannelPolarity::HiToLo => w.mode().event().polarity().hi_to_lo(), - InputChannelPolarity::LoToHi => w.mode().event().polarity().lo_to_hi(), - InputChannelPolarity::None => w.mode().event().polarity().none(), - InputChannelPolarity::Toggle => w.mode().event().polarity().toggle(), + InputChannelPolarity::HiToLo => w.set_polarity(Polarity::HI_TO_LO), + InputChannelPolarity::LoToHi => w.set_polarity(Polarity::LO_TO_HI), + InputChannelPolarity::None => w.set_polarity(Polarity::NONE), + InputChannelPolarity::Toggle => w.set_polarity(Polarity::TOGGLE), }; #[cfg(any(feature = "nrf52833", feature = "nrf52840", feature = "_nrf5340"))] - w.port().bit(match pin.pin.pin.port() { + w.set_port(match pin.pin.pin.port() { crate::gpio::Port::Port0 => false, crate::gpio::Port::Port1 => true, }); - unsafe { w.psel().bits(pin.pin.pin.pin()) } + w.set_psel(pin.pin.pin.pin()); }); - g.events_in[num].reset(); + g.events_in(num).write_value(0); InputChannel { ch: ch.map_into(), pin } } @@ -233,13 +238,13 @@ impl<'d> InputChannel<'d> { let num = self.ch.number(); // Enable interrupt - g.events_in[num].reset(); - g.intenset.write(|w| unsafe { w.bits(1 << num) }); + g.events_in(num).write_value(0); + g.intenset().write(|w| w.0 = 1 << num); poll_fn(|cx| { CHANNEL_WAKERS[num].register(cx.waker()); - if g.events_in[num].read().bits() != 0 { + if g.events_in(num).read() != 0 { Poll::Ready(()) } else { Poll::Pending @@ -251,7 +256,7 @@ impl<'d> InputChannel<'d> { /// Returns the IN event, for use with PPI. pub fn event_in(&self) -> Event<'d> { let g = regs(); - Event::from_reg(&g.events_in[self.ch.number()]) + Event::from_reg(g.events_in(self.ch.number())) } } @@ -265,8 +270,8 @@ impl<'d> Drop for OutputChannel<'d> { fn drop(&mut self) { let g = regs(); let num = self.ch.number(); - g.config[num].write(|w| w.mode().disabled()); - g.intenclr.write(|w| unsafe { w.bits(1 << num) }); + g.config(num).write(|w| w.set_mode(Mode::DISABLED)); + g.intenclr().write(|w| w.0 = 1 << num); } } @@ -277,23 +282,23 @@ impl<'d> OutputChannel<'d> { let g = regs(); let num = ch.number(); - g.config[num].write(|w| { - w.mode().task(); + g.config(num).write(|w| { + w.set_mode(Mode::TASK); match pin.is_set_high() { - true => w.outinit().high(), - false => w.outinit().low(), + true => w.set_outinit(Outinit::HIGH), + false => w.set_outinit(Outinit::LOW), }; match polarity { - OutputChannelPolarity::Set => w.polarity().lo_to_hi(), - OutputChannelPolarity::Clear => w.polarity().hi_to_lo(), - OutputChannelPolarity::Toggle => w.polarity().toggle(), + OutputChannelPolarity::Set => w.set_polarity(Polarity::HI_TO_LO), + OutputChannelPolarity::Clear => w.set_polarity(Polarity::LO_TO_HI), + OutputChannelPolarity::Toggle => w.set_polarity(Polarity::TOGGLE), }; #[cfg(any(feature = "nrf52833", feature = "nrf52840", feature = "_nrf5340"))] - w.port().bit(match pin.pin.pin.port() { + w.set_port(match pin.pin.pin.port() { crate::gpio::Port::Port0 => false, crate::gpio::Port::Port1 => true, }); - unsafe { w.psel().bits(pin.pin.pin.pin()) } + w.set_psel(pin.pin.pin.pin()); }); OutputChannel { @@ -305,41 +310,41 @@ impl<'d> OutputChannel<'d> { /// Triggers the OUT task (does the action as configured with task_out_polarity, defaults to Toggle). pub fn out(&self) { let g = regs(); - g.tasks_out[self.ch.number()].write(|w| unsafe { w.bits(1) }); + g.tasks_out(self.ch.number()).write_value(1); } /// Triggers the SET task (set associated pin high). - #[cfg(not(feature = "nrf51"))] + #[cfg(not(feature = "_nrf51"))] pub fn set(&self) { let g = regs(); - g.tasks_set[self.ch.number()].write(|w| unsafe { w.bits(1) }); + g.tasks_set(self.ch.number()).write_value(1); } /// Triggers the CLEAR task (set associated pin low). - #[cfg(not(feature = "nrf51"))] + #[cfg(not(feature = "_nrf51"))] pub fn clear(&self) { let g = regs(); - g.tasks_clr[self.ch.number()].write(|w| unsafe { w.bits(1) }); + g.tasks_clr(self.ch.number()).write_value(1); } /// Returns the OUT task, for use with PPI. pub fn task_out(&self) -> Task<'d> { let g = regs(); - Task::from_reg(&g.tasks_out[self.ch.number()]) + Task::from_reg(g.tasks_out(self.ch.number())) } /// Returns the CLR task, for use with PPI. - #[cfg(not(feature = "nrf51"))] + #[cfg(not(feature = "_nrf51"))] pub fn task_clr(&self) -> Task<'d> { let g = regs(); - Task::from_reg(&g.tasks_clr[self.ch.number()]) + Task::from_reg(g.tasks_clr(self.ch.number())) } /// Returns the SET task, for use with PPI. - #[cfg(not(feature = "nrf51"))] + #[cfg(not(feature = "_nrf51"))] pub fn task_set(&self) -> Task<'d> { let g = regs(); - Task::from_reg(&g.tasks_set[self.ch.number()]) + Task::from_reg(g.tasks_set(self.ch.number())) } } @@ -362,7 +367,7 @@ impl<'a> Unpin for PortInputFuture<'a> {} impl<'a> Drop for PortInputFuture<'a> { fn drop(&mut self) { - self.pin.conf().modify(|_, w| w.sense().disabled()); + self.pin.conf().modify(|w| w.set_sense(Sense::DISABLED)); } } @@ -372,7 +377,7 @@ impl<'a> Future for PortInputFuture<'a> { fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { PORT_WAKERS[self.pin.pin_port() as usize].register(cx.waker()); - if self.pin.conf().read().sense().is_disabled() { + if self.pin.conf().read().sense() == Sense::DISABLED { Poll::Ready(()) } else { Poll::Pending @@ -410,13 +415,13 @@ impl<'d> Input<'d> { impl<'d> Flex<'d> { /// Wait until the pin is high. If it is already high, return immediately. pub async fn wait_for_high(&mut self) { - self.pin.conf().modify(|_, w| w.sense().high()); + self.pin.conf().modify(|w| w.set_sense(Sense::HIGH)); PortInputFuture::new(&mut self.pin).await } /// Wait until the pin is low. If it is already low, return immediately. pub async fn wait_for_low(&mut self) { - self.pin.conf().modify(|_, w| w.sense().low()); + self.pin.conf().modify(|w| w.set_sense(Sense::LOW)); PortInputFuture::new(&mut self.pin).await } @@ -435,9 +440,9 @@ impl<'d> Flex<'d> { /// Wait for the pin to undergo any transition, i.e low to high OR high to low. pub async fn wait_for_any_edge(&mut self) { if self.is_high() { - self.pin.conf().modify(|_, w| w.sense().low()); + self.pin.conf().modify(|w| w.set_sense(Sense::LOW)); } else { - self.pin.conf().modify(|_, w| w.sense().high()); + self.pin.conf().modify(|w| w.set_sense(Sense::HIGH)); } PortInputFuture::new(&mut self.pin).await } @@ -504,13 +509,13 @@ impl_channel!(GPIOTE_CH0, 0); impl_channel!(GPIOTE_CH1, 1); impl_channel!(GPIOTE_CH2, 2); impl_channel!(GPIOTE_CH3, 3); -#[cfg(not(feature = "nrf51"))] +#[cfg(not(feature = "_nrf51"))] impl_channel!(GPIOTE_CH4, 4); -#[cfg(not(feature = "nrf51"))] +#[cfg(not(feature = "_nrf51"))] impl_channel!(GPIOTE_CH5, 5); -#[cfg(not(feature = "nrf51"))] +#[cfg(not(feature = "_nrf51"))] impl_channel!(GPIOTE_CH6, 6); -#[cfg(not(feature = "nrf51"))] +#[cfg(not(feature = "_nrf51"))] impl_channel!(GPIOTE_CH7, 7); // ==================== diff --git a/embassy-nrf/src/i2s.rs b/embassy-nrf/src/i2s.rs index 5f565a9b7..384a1637b 100644 --- a/embassy-nrf/src/i2s.rs +++ b/embassy-nrf/src/i2s.rs @@ -13,11 +13,11 @@ use embassy_hal_internal::drop::OnDrop; use embassy_hal_internal::{into_ref, PeripheralRef}; use embassy_sync::waitqueue::AtomicWaker; -use crate::gpio::{AnyPin, Pin as GpioPin}; +use crate::gpio::{AnyPin, Pin as GpioPin, PselBits}; use crate::interrupt::typelevel::Interrupt; -use crate::pac::i2s::RegisterBlock; +use crate::pac::i2s::vals; use crate::util::slice_in_ram_or; -use crate::{interrupt, Peripheral, EASY_DMA_SIZE}; +use crate::{interrupt, pac, Peripheral, EASY_DMA_SIZE}; /// Type alias for `MultiBuffering` with 2 buffers. pub type DoubleBuffering = MultiBuffering; @@ -117,9 +117,20 @@ pub enum MckFreq { } impl MckFreq { - const REGISTER_VALUES: &'static [u32] = &[ - 0x20000000, 0x18000000, 0x16000000, 0x11000000, 0x10000000, 0x0C000000, 0x0B000000, 0x08800000, 0x08400000, - 0x08000000, 0x06000000, 0x04100000, 0x020C0000, + const REGISTER_VALUES: &'static [vals::Mckfreq] = &[ + vals::Mckfreq::_32MDIV8, + vals::Mckfreq::_32MDIV10, + vals::Mckfreq::_32MDIV11, + vals::Mckfreq::_32MDIV15, + vals::Mckfreq::_32MDIV16, + vals::Mckfreq::_32MDIV21, + vals::Mckfreq::_32MDIV23, + vals::Mckfreq::_32MDIV30, + vals::Mckfreq::_32MDIV31, + vals::Mckfreq::_32MDIV32, + vals::Mckfreq::_32MDIV42, + vals::Mckfreq::_32MDIV63, + vals::Mckfreq::_32MDIV125, ]; const FREQUENCIES: &'static [u32] = &[ @@ -128,7 +139,7 @@ impl MckFreq { ]; /// Return the value that needs to be written to the register. - pub fn to_register_value(&self) -> u32 { + pub fn to_register_value(&self) -> vals::Mckfreq { Self::REGISTER_VALUES[usize::from(*self)] } @@ -174,8 +185,8 @@ impl Ratio { const RATIOS: &'static [u32] = &[32, 48, 64, 96, 128, 192, 256, 384, 512]; /// Return the value that needs to be written to the register. - pub fn to_register_value(&self) -> u8 { - usize::from(*self) as u8 + pub fn to_register_value(&self) -> vals::Ratio { + vals::Ratio::from_bits(*self as u8) } /// Return the divisor for this ratio @@ -304,9 +315,9 @@ pub enum SampleWidth { _24bit, } -impl From for u8 { +impl From for vals::Swidth { fn from(variant: SampleWidth) -> Self { - variant as _ + vals::Swidth::from_bits(variant as u8) } } @@ -319,11 +330,11 @@ pub enum Align { Right, } -impl From for bool { +impl From for vals::Align { fn from(variant: Align) -> Self { match variant { - Align::Left => false, - Align::Right => true, + Align::Left => vals::Align::LEFT, + Align::Right => vals::Align::RIGHT, } } } @@ -337,11 +348,11 @@ pub enum Format { Aligned, } -impl From for bool { +impl From for vals::Format { fn from(variant: Format) -> Self { match variant { - Format::I2S => false, - Format::Aligned => true, + Format::I2S => vals::Format::I2S, + Format::Aligned => vals::Format::ALIGNED, } } } @@ -357,9 +368,9 @@ pub enum Channels { MonoRight, } -impl From for u8 { +impl From for vals::Channels { fn from(variant: Channels) -> Self { - variant as _ + vals::Channels::from_bits(variant as u8) } } @@ -506,61 +517,32 @@ impl<'d, T: Instance> I2S<'d, T> { } fn apply_config(&self) { - let c = &T::regs().config; + let c = T::regs().config(); match &self.master_clock { Some(MasterClock { freq, ratio }) => { - c.mode.write(|w| w.mode().master()); - c.mcken.write(|w| w.mcken().enabled()); - c.mckfreq - .write(|w| unsafe { w.mckfreq().bits(freq.to_register_value()) }); - c.ratio.write(|w| unsafe { w.ratio().bits(ratio.to_register_value()) }); + c.mode().write(|w| w.set_mode(vals::Mode::MASTER)); + c.mcken().write(|w| w.set_mcken(true)); + c.mckfreq().write(|w| w.set_mckfreq(freq.to_register_value())); + c.ratio().write(|w| w.set_ratio(ratio.to_register_value())); } None => { - c.mode.write(|w| w.mode().slave()); + c.mode().write(|w| w.set_mode(vals::Mode::SLAVE)); } }; - c.swidth - .write(|w| unsafe { w.swidth().bits(self.config.sample_width.into()) }); - c.align.write(|w| w.align().bit(self.config.align.into())); - c.format.write(|w| w.format().bit(self.config.format.into())); - c.channels - .write(|w| unsafe { w.channels().bits(self.config.channels.into()) }); + c.swidth().write(|w| w.set_swidth(self.config.sample_width.into())); + c.align().write(|w| w.set_align(self.config.align.into())); + c.format().write(|w| w.set_format(self.config.format.into())); + c.channels().write(|w| w.set_channels(self.config.channels.into())); } fn select_pins(&self) { - let psel = &T::regs().psel; - - if let Some(mck) = &self.mck { - psel.mck.write(|w| { - unsafe { w.bits(mck.psel_bits()) }; - w.connect().connected() - }); - } - - psel.sck.write(|w| { - unsafe { w.bits(self.sck.psel_bits()) }; - w.connect().connected() - }); - - psel.lrck.write(|w| { - unsafe { w.bits(self.lrck.psel_bits()) }; - w.connect().connected() - }); - - if let Some(sdin) = &self.sdin { - psel.sdin.write(|w| { - unsafe { w.bits(sdin.psel_bits()) }; - w.connect().connected() - }); - } - - if let Some(sdout) = &self.sdout { - psel.sdout.write(|w| { - unsafe { w.bits(sdout.psel_bits()) }; - w.connect().connected() - }); - } + let psel = T::regs().psel(); + psel.mck().write_value(self.mck.psel_bits()); + psel.sck().write_value(self.sck.psel_bits()); + psel.lrck().write_value(self.lrck.psel_bits()); + psel.sdin().write_value(self.sdin.psel_bits()); + psel.sdout().write_value(self.sdout.psel_bits()); } fn setup_interrupt(&self) { @@ -888,7 +870,7 @@ impl<'d, T: Instance, S: Sample, const NB: usize, const NS: usize> FullDuplexStr } /// Helper encapsulating common I2S device operations. -struct Device(&'static RegisterBlock, PhantomData); +struct Device(pac::i2s::I2s, PhantomData); impl Device { fn new() -> Self { @@ -898,132 +880,132 @@ impl Device { #[inline(always)] pub fn enable(&self) { trace!("ENABLED"); - self.0.enable.write(|w| w.enable().enabled()); + self.0.enable().write(|w| w.set_enable(true)); } #[inline(always)] pub fn disable(&self) { trace!("DISABLED"); - self.0.enable.write(|w| w.enable().disabled()); + self.0.enable().write(|w| w.set_enable(false)); } #[inline(always)] fn enable_tx(&self) { trace!("TX ENABLED"); - self.0.config.txen.write(|w| w.txen().enabled()); + self.0.config().txen().write(|w| w.set_txen(true)); } #[inline(always)] fn disable_tx(&self) { trace!("TX DISABLED"); - self.0.config.txen.write(|w| w.txen().disabled()); + self.0.config().txen().write(|w| w.set_txen(false)); } #[inline(always)] fn enable_rx(&self) { trace!("RX ENABLED"); - self.0.config.rxen.write(|w| w.rxen().enabled()); + self.0.config().rxen().write(|w| w.set_rxen(true)); } #[inline(always)] fn disable_rx(&self) { trace!("RX DISABLED"); - self.0.config.rxen.write(|w| w.rxen().disabled()); + self.0.config().rxen().write(|w| w.set_rxen(false)); } #[inline(always)] fn start(&self) { trace!("START"); - self.0.tasks_start.write(|w| unsafe { w.bits(1) }); + self.0.tasks_start().write_value(1); } #[inline(always)] fn stop(&self) { - self.0.tasks_stop.write(|w| unsafe { w.bits(1) }); + self.0.tasks_stop().write_value(1); } #[inline(always)] fn is_stopped(&self) -> bool { - self.0.events_stopped.read().bits() != 0 + self.0.events_stopped().read() != 0 } #[inline(always)] fn reset_stopped_event(&self) { trace!("STOPPED EVENT: Reset"); - self.0.events_stopped.reset(); + self.0.events_stopped().write_value(0); } #[inline(always)] fn disable_stopped_interrupt(&self) { trace!("STOPPED INTERRUPT: Disabled"); - self.0.intenclr.write(|w| w.stopped().clear()); + self.0.intenclr().write(|w| w.set_stopped(true)); } #[inline(always)] fn enable_stopped_interrupt(&self) { trace!("STOPPED INTERRUPT: Enabled"); - self.0.intenset.write(|w| w.stopped().set()); + self.0.intenset().write(|w| w.set_stopped(true)); } #[inline(always)] fn reset_tx_ptr_event(&self) { trace!("TX PTR EVENT: Reset"); - self.0.events_txptrupd.reset(); + self.0.events_txptrupd().write_value(0); } #[inline(always)] fn reset_rx_ptr_event(&self) { trace!("RX PTR EVENT: Reset"); - self.0.events_rxptrupd.reset(); + self.0.events_rxptrupd().write_value(0); } #[inline(always)] fn disable_tx_ptr_interrupt(&self) { trace!("TX PTR INTERRUPT: Disabled"); - self.0.intenclr.write(|w| w.txptrupd().clear()); + self.0.intenclr().write(|w| w.set_txptrupd(true)); } #[inline(always)] fn disable_rx_ptr_interrupt(&self) { trace!("RX PTR INTERRUPT: Disabled"); - self.0.intenclr.write(|w| w.rxptrupd().clear()); + self.0.intenclr().write(|w| w.set_rxptrupd(true)); } #[inline(always)] fn enable_tx_ptr_interrupt(&self) { trace!("TX PTR INTERRUPT: Enabled"); - self.0.intenset.write(|w| w.txptrupd().set()); + self.0.intenset().write(|w| w.set_txptrupd(true)); } #[inline(always)] fn enable_rx_ptr_interrupt(&self) { trace!("RX PTR INTERRUPT: Enabled"); - self.0.intenset.write(|w| w.rxptrupd().set()); + self.0.intenset().write(|w| w.set_rxptrupd(true)); } #[inline(always)] fn is_tx_ptr_updated(&self) -> bool { - self.0.events_txptrupd.read().bits() != 0 + self.0.events_txptrupd().read() != 0 } #[inline(always)] fn is_rx_ptr_updated(&self) -> bool { - self.0.events_rxptrupd.read().bits() != 0 + self.0.events_rxptrupd().read() != 0 } #[inline] fn update_tx(&self, buffer_ptr: *const [S]) -> Result<(), Error> { let (ptr, maxcnt) = Self::validated_dma_parts(buffer_ptr)?; - self.0.rxtxd.maxcnt.write(|w| unsafe { w.bits(maxcnt) }); - self.0.txd.ptr.write(|w| unsafe { w.ptr().bits(ptr) }); + self.0.rxtxd().maxcnt().write(|w| w.0 = maxcnt); + self.0.txd().ptr().write_value(ptr); Ok(()) } #[inline] fn update_rx(&self, buffer_ptr: *const [S]) -> Result<(), Error> { let (ptr, maxcnt) = Self::validated_dma_parts(buffer_ptr)?; - self.0.rxtxd.maxcnt.write(|w| unsafe { w.bits(maxcnt) }); - self.0.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr) }); + self.0.rxtxd().maxcnt().write(|w| w.0 = maxcnt); + self.0.rxd().ptr().write_value(ptr); Ok(()) } @@ -1160,7 +1142,7 @@ impl State { } pub(crate) trait SealedInstance { - fn regs() -> &'static crate::pac::i2s::RegisterBlock; + fn regs() -> pac::i2s::I2s; fn state() -> &'static State; } @@ -1174,8 +1156,8 @@ pub trait Instance: Peripheral

+ SealedInstance + 'static + Send { macro_rules! impl_i2s { ($type:ident, $pac_type:ident, $irq:ident) => { impl crate::i2s::SealedInstance for peripherals::$type { - fn regs() -> &'static crate::pac::i2s::RegisterBlock { - unsafe { &*pac::$pac_type::ptr() } + fn regs() -> pac::i2s::I2s { + pac::$pac_type } fn state() -> &'static crate::i2s::State { static STATE: crate::i2s::State = crate::i2s::State::new(); diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index bd53664a2..03d3ca5f7 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs @@ -11,7 +11,7 @@ #![doc = document_features::document_features!(feature_label = r#"{feature}"#)] #[cfg(not(any( - feature = "nrf51", + feature = "_nrf51", feature = "nrf52805", feature = "nrf52810", feature = "nrf52811", @@ -68,7 +68,7 @@ pub(crate) mod util; #[cfg(feature = "_time-driver")] mod time_driver; -#[cfg(not(feature = "nrf51"))] +#[cfg(not(feature = "_nrf51"))] pub mod buffered_uarte; pub mod gpio; #[cfg(feature = "gpiote")] @@ -78,7 +78,7 @@ pub mod gpiote; #[cfg(not(any(feature = "_nrf91", feature = "_nrf5340-app")))] pub mod radio; -#[cfg(not(feature = "nrf51"))] +#[cfg(not(feature = "_nrf51"))] pub mod egu; #[cfg(any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840"))] pub mod i2s; @@ -95,32 +95,32 @@ pub mod nvmc; pub mod pdm; pub mod ppi; #[cfg(not(any( - feature = "nrf51", + feature = "_nrf51", feature = "nrf52805", feature = "nrf52820", feature = "_nrf5340-net" )))] pub mod pwm; -#[cfg(not(any(feature = "nrf51", feature = "_nrf91", feature = "_nrf5340-net")))] +#[cfg(not(any(feature = "_nrf51", feature = "_nrf91", feature = "_nrf5340-net")))] pub mod qdec; #[cfg(any(feature = "nrf52840", feature = "_nrf5340-app"))] pub mod qspi; #[cfg(not(any(feature = "_nrf5340-app", feature = "_nrf91")))] pub mod rng; -#[cfg(not(any(feature = "nrf51", feature = "nrf52820", feature = "_nrf5340-net")))] +#[cfg(not(any(feature = "_nrf51", feature = "nrf52820", feature = "_nrf5340-net")))] pub mod saadc; -#[cfg(not(feature = "nrf51"))] +#[cfg(not(feature = "_nrf51"))] pub mod spim; -#[cfg(not(feature = "nrf51"))] +#[cfg(not(feature = "_nrf51"))] pub mod spis; #[cfg(not(any(feature = "_nrf5340", feature = "_nrf91")))] pub mod temp; pub mod timer; -#[cfg(not(feature = "nrf51"))] +#[cfg(not(feature = "_nrf51"))] pub mod twim; -#[cfg(not(feature = "nrf51"))] +#[cfg(not(feature = "_nrf51"))] pub mod twis; -#[cfg(not(feature = "nrf51"))] +#[cfg(not(feature = "_nrf51"))] pub mod uarte; #[cfg(any( feature = "_nrf5340-app", @@ -133,7 +133,7 @@ pub mod usb; pub mod wdt; // This mod MUST go last, so that it sees all the `impl_foo!` macros -#[cfg_attr(feature = "nrf51", path = "chips/nrf51.rs")] +#[cfg_attr(feature = "_nrf51", path = "chips/nrf51.rs")] #[cfg_attr(feature = "nrf52805", path = "chips/nrf52805.rs")] #[cfg_attr(feature = "nrf52810", path = "chips/nrf52810.rs")] #[cfg_attr(feature = "nrf52811", path = "chips/nrf52811.rs")] @@ -216,6 +216,7 @@ pub use chip::{peripherals, Peripherals, EASY_DMA_SIZE}; pub use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; pub use crate::chip::interrupt; +#[cfg(feature = "rt")] pub use crate::pac::NVIC_PRIO_BITS; pub mod config { @@ -405,7 +406,7 @@ mod consts { pub const APPROTECT_DISABLED: u32 = 0x0000_005a; } -#[cfg(not(feature = "nrf51"))] +#[cfg(not(feature = "_nrf51"))] #[derive(Debug, Copy, Clone, Eq, PartialEq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] enum WriteResult { @@ -417,12 +418,12 @@ enum WriteResult { Failed, } -#[cfg(not(feature = "nrf51"))] +#[cfg(not(feature = "_nrf51"))] unsafe fn uicr_write(address: *mut u32, value: u32) -> WriteResult { uicr_write_masked(address, value, 0xFFFF_FFFF) } -#[cfg(not(feature = "nrf51"))] +#[cfg(not(feature = "_nrf51"))] unsafe fn uicr_write_masked(address: *mut u32, value: u32, mask: u32) -> WriteResult { let curr_val = address.read_volatile(); if curr_val & mask == value & mask { @@ -434,13 +435,13 @@ unsafe fn uicr_write_masked(address: *mut u32, value: u32, mask: u32) -> WriteRe return WriteResult::Failed; } - let nvmc = &*pac::NVMC::ptr(); - nvmc.config.write(|w| w.wen().wen()); - while nvmc.ready.read().ready().is_busy() {} + let nvmc = pac::NVMC; + nvmc.config().write(|w| w.set_wen(pac::nvmc::vals::Wen::WEN)); + while !nvmc.ready().read().ready() {} address.write_volatile(value | !mask); - while nvmc.ready.read().ready().is_busy() {} - nvmc.config.reset(); - while nvmc.ready.read().ready().is_busy() {} + while !nvmc.ready().read().ready() {} + nvmc.config().write(|_| {}); + while !nvmc.ready().read().ready() {} WriteResult::Written } @@ -459,7 +460,7 @@ pub fn init(config: config::Config) -> Peripherals { let mut needs_reset = false; // Setup debug protection. - #[cfg(not(feature = "nrf51"))] + #[cfg(not(feature = "_nrf51"))] match config.debug { config::Debug::Allowed => { #[cfg(feature = "_nrf52")] @@ -486,17 +487,17 @@ pub fn init(config: config::Config) -> Peripherals { #[cfg(feature = "_nrf5340")] unsafe { - let p = &*pac::CTRLAP::ptr(); + let p = pac::CTRLAP; let res = uicr_write(consts::UICR_APPROTECT, consts::APPROTECT_DISABLED); needs_reset |= res == WriteResult::Written; - p.approtect.disable.write(|w| w.bits(consts::APPROTECT_DISABLED)); + p.approtect().disable().write_value(consts::APPROTECT_DISABLED); #[cfg(feature = "_nrf5340-app")] { let res = uicr_write(consts::UICR_SECUREAPPROTECT, consts::APPROTECT_DISABLED); needs_reset |= res == WriteResult::Written; - p.secureapprotect.disable.write(|w| w.bits(consts::APPROTECT_DISABLED)); + p.secureapprotect().disable().write_value(consts::APPROTECT_DISABLED); } } @@ -576,85 +577,79 @@ pub fn init(config: config::Config) -> Peripherals { cortex_m::peripheral::SCB::sys_reset(); } - let r = unsafe { &*pac::CLOCK::ptr() }; + let r = pac::CLOCK; // Start HFCLK. match config.hfclk_source { config::HfclkSource::Internal => {} config::HfclkSource::ExternalXtal => { // Datasheet says this is likely to take 0.36ms - r.events_hfclkstarted.write(|w| unsafe { w.bits(0) }); - r.tasks_hfclkstart.write(|w| unsafe { w.bits(1) }); - while r.events_hfclkstarted.read().bits() == 0 {} + r.events_hfclkstarted().write_value(0); + r.tasks_hfclkstart().write_value(1); + while r.events_hfclkstarted().read() == 0 {} } } // Configure LFCLK. - #[cfg(not(any(feature = "nrf51", feature = "_nrf5340", feature = "_nrf91")))] + #[cfg(not(any(feature = "_nrf51", feature = "_nrf5340", feature = "_nrf91")))] match config.lfclk_source { - config::LfclkSource::InternalRC => r.lfclksrc.write(|w| w.src().rc()), - config::LfclkSource::Synthesized => r.lfclksrc.write(|w| w.src().synth()), - - config::LfclkSource::ExternalXtal => r.lfclksrc.write(|w| w.src().xtal()), - - config::LfclkSource::ExternalLowSwing => r.lfclksrc.write(|w| { - w.src().xtal(); - w.external().enabled(); - w.bypass().disabled(); - w + config::LfclkSource::InternalRC => r.lfclksrc().write(|w| w.set_src(pac::clock::vals::Lfclksrc::RC)), + config::LfclkSource::Synthesized => r.lfclksrc().write(|w| w.set_src(pac::clock::vals::Lfclksrc::SYNTH)), + config::LfclkSource::ExternalXtal => r.lfclksrc().write(|w| w.set_src(pac::clock::vals::Lfclksrc::XTAL)), + config::LfclkSource::ExternalLowSwing => r.lfclksrc().write(|w| { + w.set_src(pac::clock::vals::Lfclksrc::XTAL); + w.set_external(true); + w.set_bypass(false); }), - config::LfclkSource::ExternalFullSwing => r.lfclksrc.write(|w| { - w.src().xtal(); - w.external().enabled(); - w.bypass().enabled(); - w + config::LfclkSource::ExternalFullSwing => r.lfclksrc().write(|w| { + w.set_src(pac::clock::vals::Lfclksrc::XTAL); + w.set_external(true); + w.set_bypass(true); }), } #[cfg(feature = "_nrf91")] match config.lfclk_source { - config::LfclkSource::InternalRC => r.lfclksrc.write(|w| w.src().lfrc()), - config::LfclkSource::ExternalXtal => r.lfclksrc.write(|w| w.src().lfxo()), + config::LfclkSource::InternalRC => r.lfclksrc().write(|w| w.set_src(pac::clock::vals::Lfclksrc::LFRC)), + config::LfclkSource::ExternalXtal => r.lfclksrc().write(|w| w.set_src(pac::clock::vals::Lfclksrc::LFXO)), } // Start LFCLK. // Datasheet says this could take 100us from synth source // 600us from rc source, 0.25s from an external source. - r.events_lfclkstarted.write(|w| unsafe { w.bits(0) }); - r.tasks_lfclkstart.write(|w| unsafe { w.bits(1) }); - while r.events_lfclkstarted.read().bits() == 0 {} + r.events_lfclkstarted().write_value(0); + r.tasks_lfclkstart().write_value(1); + while r.events_lfclkstarted().read() == 0 {} #[cfg(not(any(feature = "_nrf5340", feature = "_nrf91")))] { // Setup DCDCs. - let pwr = unsafe { &*pac::POWER::ptr() }; #[cfg(feature = "nrf52840")] if config.dcdc.reg0 { - pwr.dcdcen0.write(|w| w.dcdcen().set_bit()); + pac::POWER.dcdcen0().write(|w| w.set_dcdcen(true)); } if config.dcdc.reg1 { - pwr.dcdcen.write(|w| w.dcdcen().set_bit()); + pac::POWER.dcdcen().write(|w| w.set_dcdcen(true)); } } #[cfg(feature = "_nrf91")] { // Setup DCDC. - let reg = unsafe { &*pac::REGULATORS::ptr() }; if config.dcdc.regmain { - reg.dcdcen.write(|w| w.dcdcen().set_bit()); + pac::REGULATORS.dcdcen().write(|w| w.set_dcdcen(true)); } } #[cfg(feature = "_nrf5340-app")] { // Setup DCDC. - let reg = unsafe { &*pac::REGULATORS::ptr() }; + let reg = pac::REGULATORS; if config.dcdc.regh { - reg.vregh.dcdcen.write(|w| w.dcdcen().set_bit()); + reg.vregh().dcdcen().write(|w| w.set_dcdcen(true)); } if config.dcdc.regmain { - reg.vregmain.dcdcen.write(|w| w.dcdcen().set_bit()); + reg.vregmain().dcdcen().write(|w| w.set_dcdcen(true)); } if config.dcdc.regradio { - reg.vregradio.dcdcen.write(|w| w.dcdcen().set_bit()); + reg.vregradio().dcdcen().write(|w| w.set_dcdcen(true)); } } @@ -668,9 +663,10 @@ pub fn init(config: config::Config) -> Peripherals { // Disable UARTE (enabled by default for some reason) #[cfg(feature = "_nrf91")] - unsafe { - (*pac::UARTE0::ptr()).enable.write(|w| w.enable().disabled()); - (*pac::UARTE1::ptr()).enable.write(|w| w.enable().disabled()); + { + use pac::uarte::vals::Enable; + pac::UARTE0.enable().write(|w| w.set_enable(Enable::DISABLED)); + pac::UARTE1.enable().write(|w| w.set_enable(Enable::DISABLED)); } peripherals diff --git a/embassy-nrf/src/nvmc.rs b/embassy-nrf/src/nvmc.rs index 9b17e7da0..6973b4847 100644 --- a/embassy-nrf/src/nvmc.rs +++ b/embassy-nrf/src/nvmc.rs @@ -7,6 +7,7 @@ use embedded_storage::nor_flash::{ ErrorType, MultiwriteNorFlash, NorFlash, NorFlashError, NorFlashErrorKind, ReadNorFlash, }; +use crate::pac::nvmc::vals; use crate::peripherals::NVMC; use crate::{pac, Peripheral}; @@ -51,13 +52,13 @@ impl<'d> Nvmc<'d> { Self { _p } } - fn regs() -> &'static pac::nvmc::RegisterBlock { - unsafe { &*pac::NVMC::ptr() } + fn regs() -> pac::nvmc::Nvmc { + pac::NVMC } fn wait_ready(&mut self) { let p = Self::regs(); - while p.ready.read().ready().is_busy() {} + while !p.ready().read().ready() {} } #[cfg(not(any(feature = "_nrf91", feature = "_nrf5340")))] @@ -68,12 +69,12 @@ impl<'d> Nvmc<'d> { #[cfg(any(feature = "_nrf91", feature = "_nrf5340"))] fn wait_ready_write(&mut self) { let p = Self::regs(); - while p.readynext.read().readynext().is_busy() {} + while !p.readynext().read().readynext() {} } #[cfg(not(any(feature = "_nrf91", feature = "_nrf5340")))] fn erase_page(&mut self, page_addr: u32) { - Self::regs().erasepage().write(|w| unsafe { w.bits(page_addr) }); + Self::regs().erasepage().write_value(page_addr); } #[cfg(any(feature = "_nrf91", feature = "_nrf5340"))] @@ -86,23 +87,23 @@ impl<'d> Nvmc<'d> { fn enable_erase(&self) { #[cfg(not(feature = "_ns"))] - Self::regs().config.write(|w| w.wen().een()); + Self::regs().config().write(|w| w.set_wen(vals::Wen::EEN)); #[cfg(feature = "_ns")] - Self::regs().configns.write(|w| w.wen().een()); + Self::regs().configns().write(|w| w.set_wen(vals::ConfignsWen::EEN)); } fn enable_read(&self) { #[cfg(not(feature = "_ns"))] - Self::regs().config.write(|w| w.wen().ren()); + Self::regs().config().write(|w| w.set_wen(vals::Wen::REN)); #[cfg(feature = "_ns")] - Self::regs().configns.write(|w| w.wen().ren()); + Self::regs().configns().write(|w| w.set_wen(vals::ConfignsWen::REN)); } fn enable_write(&self) { #[cfg(not(feature = "_ns"))] - Self::regs().config.write(|w| w.wen().wen()); + Self::regs().config().write(|w| w.set_wen(vals::Wen::WEN)); #[cfg(feature = "_ns")] - Self::regs().configns.write(|w| w.wen().wen()); + Self::regs().configns().write(|w| w.set_wen(vals::ConfignsWen::WEN)); } } diff --git a/embassy-nrf/src/pdm.rs b/embassy-nrf/src/pdm.rs index 5160fe3c4..483d1a644 100644 --- a/embassy-nrf/src/pdm.rs +++ b/embassy-nrf/src/pdm.rs @@ -13,18 +13,19 @@ use embassy_sync::waitqueue::AtomicWaker; use fixed::types::I7F1; use crate::chip::EASY_DMA_SIZE; -use crate::gpio::{AnyPin, Pin as GpioPin, SealedPin}; +use crate::gpio::{AnyPin, Pin as GpioPin, SealedPin, DISCONNECTED}; use crate::interrupt::typelevel::Interrupt; -use crate::pac::pdm::mode::{EDGE_A, OPERATION_A}; -pub use crate::pac::pdm::pdmclkctrl::FREQ_A as Frequency; +use crate::pac::gpio::vals as gpiovals; +use crate::pac::pdm::vals; +pub use crate::pac::pdm::vals::Freq as Frequency; #[cfg(any( feature = "nrf52840", feature = "nrf52833", feature = "_nrf5340-app", feature = "_nrf91", ))] -pub use crate::pac::pdm::ratio::RATIO_A as Ratio; -use crate::{interrupt, Peripheral}; +pub use crate::pac::pdm::vals::Ratio; +use crate::{interrupt, pac, Peripheral}; /// Interrupt handler pub struct InterruptHandler { @@ -35,16 +36,16 @@ impl interrupt::typelevel::Handler for InterruptHandl unsafe fn on_interrupt() { let r = T::regs(); - if r.events_end.read().bits() != 0 { - r.intenclr.write(|w| w.end().clear()); + if r.events_end().read() != 0 { + r.intenclr().write(|w| w.set_end(true)); } - if r.events_started.read().bits() != 0 { - r.intenclr.write(|w| w.started().clear()); + if r.events_started().read() != 0 { + r.intenclr().write(|w| w.set_started(true)); } - if r.events_stopped.read().bits() != 0 { - r.intenclr.write(|w| w.stopped().clear()); + if r.events_stopped().read() != 0 { + r.intenclr().write(|w| w.set_stopped(true)); } T::state().waker.wake(); @@ -109,50 +110,47 @@ impl<'d, T: Instance> Pdm<'d, T> { let r = T::regs(); // setup gpio pins - din.conf().write(|w| w.input().set_bit()); - r.psel.din.write(|w| unsafe { w.bits(din.psel_bits()) }); + din.conf().write(|w| w.set_input(gpiovals::Input::CONNECT)); + r.psel().din().write_value(din.psel_bits()); clk.set_low(); - clk.conf().write(|w| w.dir().output()); - r.psel.clk.write(|w| unsafe { w.bits(clk.psel_bits()) }); + clk.conf().write(|w| w.set_dir(gpiovals::Dir::OUTPUT)); + r.psel().clk().write_value(clk.psel_bits()); // configure - r.pdmclkctrl.write(|w| w.freq().variant(config.frequency)); + r.pdmclkctrl().write(|w| w.set_freq(config.frequency)); #[cfg(any( feature = "nrf52840", feature = "nrf52833", feature = "_nrf5340-app", feature = "_nrf91", ))] - r.ratio.write(|w| w.ratio().variant(config.ratio)); - r.mode.write(|w| { - w.operation().variant(config.operation_mode.into()); - w.edge().variant(config.edge.into()); - w + r.ratio().write(|w| w.set_ratio(config.ratio)); + r.mode().write(|w| { + w.set_operation(config.operation_mode.into()); + w.set_edge(config.edge.into()); }); Self::_set_gain(r, config.gain_left, config.gain_right); // Disable all events interrupts - r.intenclr.write(|w| unsafe { w.bits(0x003F_FFFF) }); + r.intenclr().write(|w| w.0 = 0x003F_FFFF); // IRQ T::Interrupt::unpend(); unsafe { T::Interrupt::enable() }; - r.enable.write(|w| w.enable().set_bit()); + r.enable().write(|w| w.set_enable(true)); Self { _peri: pdm } } - fn _set_gain(r: &crate::pac::pdm::RegisterBlock, gain_left: I7F1, gain_right: I7F1) { - let gain_to_bits = |gain: I7F1| -> u8 { - let gain = gain.saturating_add(I7F1::from_bits(0x28)).to_bits().clamp(0, 0x50); - unsafe { core::mem::transmute(gain) } + fn _set_gain(r: pac::pdm::Pdm, gain_left: I7F1, gain_right: I7F1) { + let gain_to_bits = |gain: I7F1| -> vals::Gain { + let gain: i8 = gain.saturating_add(I7F1::from_bits(0x28)).to_bits().clamp(0, 0x50); + vals::Gain::from_bits(gain as u8) }; - let gain_left = gain_to_bits(gain_left); - let gain_right = gain_to_bits(gain_right); - r.gainl.write(|w| unsafe { w.gainl().bits(gain_left) }); - r.gainr.write(|w| unsafe { w.gainr().bits(gain_right) }); + r.gainl().write(|w| w.set_gainl(gain_to_bits(gain_left))); + r.gainr().write(|w| w.set_gainr(gain_to_bits(gain_right))); } /// Adjust the gain of the PDM microphone on the fly @@ -166,21 +164,17 @@ impl<'d, T: Instance> Pdm<'d, T> { let r = T::regs(); // start dummy sampling because microphone needs some setup time - r.sample - .ptr - .write(|w| unsafe { w.sampleptr().bits(DUMMY_BUFFER.as_ptr() as u32) }); - r.sample - .maxcnt - .write(|w| unsafe { w.buffsize().bits(DUMMY_BUFFER.len() as _) }); + r.sample().ptr().write_value(DUMMY_BUFFER.as_ptr() as u32); + r.sample().maxcnt().write(|w| w.set_buffsize(DUMMY_BUFFER.len() as _)); - r.tasks_start.write(|w| unsafe { w.bits(1) }); + r.tasks_start().write_value(1); } /// Stop sampling microphone data inta a dummy buffer pub async fn stop(&mut self) { let r = T::regs(); - r.tasks_stop.write(|w| unsafe { w.bits(1) }); - r.events_started.reset(); + r.tasks_stop().write_value(1); + r.events_started().write_value(0); } /// Sample data into the given buffer @@ -194,41 +188,33 @@ impl<'d, T: Instance> Pdm<'d, T> { let r = T::regs(); - if r.events_started.read().bits() == 0 { + if r.events_started().read() == 0 { return Err(Error::NotRunning); } let drop = OnDrop::new(move || { - r.intenclr.write(|w| w.end().clear()); - r.events_stopped.reset(); + r.intenclr().write(|w| w.set_end(true)); + r.events_stopped().write_value(0); // reset to dummy buffer - r.sample - .ptr - .write(|w| unsafe { w.sampleptr().bits(DUMMY_BUFFER.as_ptr() as u32) }); - r.sample - .maxcnt - .write(|w| unsafe { w.buffsize().bits(DUMMY_BUFFER.len() as _) }); + r.sample().ptr().write_value(DUMMY_BUFFER.as_ptr() as u32); + r.sample().maxcnt().write(|w| w.set_buffsize(DUMMY_BUFFER.len() as _)); - while r.events_stopped.read().bits() == 0 {} + while r.events_stopped().read() == 0 {} }); // setup user buffer let ptr = buffer.as_ptr(); let len = buffer.len(); - r.sample.ptr.write(|w| unsafe { w.sampleptr().bits(ptr as u32) }); - r.sample.maxcnt.write(|w| unsafe { w.buffsize().bits(len as _) }); + r.sample().ptr().write_value(ptr as u32); + r.sample().maxcnt().write(|w| w.set_buffsize(len as _)); // wait till the current sample is finished and the user buffer sample is started Self::wait_for_sample().await; // reset the buffer back to the dummy buffer - r.sample - .ptr - .write(|w| unsafe { w.sampleptr().bits(DUMMY_BUFFER.as_ptr() as u32) }); - r.sample - .maxcnt - .write(|w| unsafe { w.buffsize().bits(DUMMY_BUFFER.len() as _) }); + r.sample().ptr().write_value(DUMMY_BUFFER.as_ptr() as u32); + r.sample().maxcnt().write(|w| w.set_buffsize(DUMMY_BUFFER.len() as _)); // wait till the user buffer is sampled Self::wait_for_sample().await; @@ -241,14 +227,14 @@ impl<'d, T: Instance> Pdm<'d, T> { async fn wait_for_sample() { let r = T::regs(); - r.events_end.reset(); - r.intenset.write(|w| w.end().set()); + r.events_end().write_value(0); + r.intenset().write(|w| w.set_end(true)); compiler_fence(Ordering::SeqCst); poll_fn(|cx| { T::state().waker.register(cx.waker()); - if r.events_end.read().bits() != 0 { + if r.events_end().read() != 0 { return Poll::Ready(()); } Poll::Pending @@ -279,40 +265,37 @@ impl<'d, T: Instance> Pdm<'d, T> { { let r = T::regs(); - if r.events_started.read().bits() != 0 { + if r.events_started().read() != 0 { return Err(Error::AlreadyRunning); } - r.sample - .ptr - .write(|w| unsafe { w.sampleptr().bits(bufs[0].as_mut_ptr() as u32) }); - r.sample.maxcnt.write(|w| unsafe { w.buffsize().bits(N as _) }); + r.sample().ptr().write_value(bufs[0].as_mut_ptr() as u32); + r.sample().maxcnt().write(|w| w.set_buffsize(N as _)); // Reset and enable the events - r.events_end.reset(); - r.events_started.reset(); - r.events_stopped.reset(); - r.intenset.write(|w| { - w.end().set(); - w.started().set(); - w.stopped().set(); - w + r.events_end().write_value(0); + r.events_started().write_value(0); + r.events_stopped().write_value(0); + r.intenset().write(|w| { + w.set_end(true); + w.set_started(true); + w.set_stopped(true); }); // Don't reorder the start event before the previous writes. Hopefully self // wouldn't happen anyway compiler_fence(Ordering::SeqCst); - r.tasks_start.write(|w| unsafe { w.bits(1) }); + r.tasks_start().write_value(1); let mut current_buffer = 0; let mut done = false; let drop = OnDrop::new(|| { - r.tasks_stop.write(|w| unsafe { w.bits(1) }); + r.tasks_stop().write_value(1); // N.B. It would be better if this were async, but Drop only support sync code - while r.events_stopped.read().bits() != 0 {} + while r.events_stopped().read() != 0 {} }); // Wait for events and complete when the sampler indicates it has had enough @@ -321,11 +304,11 @@ impl<'d, T: Instance> Pdm<'d, T> { T::state().waker.register(cx.waker()); - if r.events_end.read().bits() != 0 { + if r.events_end().read() != 0 { compiler_fence(Ordering::SeqCst); - r.events_end.reset(); - r.intenset.write(|w| w.end().set()); + r.events_end().write_value(0); + r.intenset().write(|w| w.set_end(true)); if !done { // Discard the last buffer after the user requested a stop @@ -333,23 +316,21 @@ impl<'d, T: Instance> Pdm<'d, T> { let next_buffer = 1 - current_buffer; current_buffer = next_buffer; } else { - r.tasks_stop.write(|w| unsafe { w.bits(1) }); + r.tasks_stop().write_value(1); done = true; }; }; } - if r.events_started.read().bits() != 0 { - r.events_started.reset(); - r.intenset.write(|w| w.started().set()); + if r.events_started().read() != 0 { + r.events_started().write_value(0); + r.intenset().write(|w| w.set_started(true)); let next_buffer = 1 - current_buffer; - r.sample - .ptr - .write(|w| unsafe { w.sampleptr().bits(bufs[next_buffer].as_mut_ptr() as u32) }); + r.sample().ptr().write_value(bufs[next_buffer].as_mut_ptr() as u32); } - if r.events_stopped.read().bits() != 0 { + if r.events_stopped().read() != 0 { return Poll::Ready(()); } @@ -411,11 +392,11 @@ pub enum OperationMode { Stereo, } -impl From for OPERATION_A { +impl From for vals::Operation { fn from(mode: OperationMode) -> Self { match mode { - OperationMode::Mono => OPERATION_A::MONO, - OperationMode::Stereo => OPERATION_A::STEREO, + OperationMode::Mono => vals::Operation::MONO, + OperationMode::Stereo => vals::Operation::STEREO, } } } @@ -429,11 +410,11 @@ pub enum Edge { LeftFalling, } -impl From for EDGE_A { +impl From for vals::Edge { fn from(edge: Edge) -> Self { match edge { - Edge::LeftRising => EDGE_A::LEFT_RISING, - Edge::LeftFalling => EDGE_A::LEFT_FALLING, + Edge::LeftRising => vals::Edge::LEFT_RISING, + Edge::LeftFalling => vals::Edge::LEFT_FALLING, } } } @@ -442,12 +423,12 @@ impl<'d, T: Instance> Drop for Pdm<'d, T> { fn drop(&mut self) { let r = T::regs(); - r.tasks_stop.write(|w| unsafe { w.bits(1) }); + r.tasks_stop().write_value(1); - r.enable.write(|w| w.enable().disabled()); + r.enable().write(|w| w.set_enable(false)); - r.psel.din.reset(); - r.psel.clk.reset(); + r.psel().din().write_value(DISCONNECTED); + r.psel().clk().write_value(DISCONNECTED); } } @@ -465,7 +446,7 @@ impl State { } pub(crate) trait SealedInstance { - fn regs() -> &'static crate::pac::pdm::RegisterBlock; + fn regs() -> crate::pac::pdm::Pdm; fn state() -> &'static State; } @@ -479,8 +460,8 @@ pub trait Instance: Peripheral

+ SealedInstance + 'static + Send { macro_rules! impl_pdm { ($type:ident, $pac_type:ident, $irq:ident) => { impl crate::pdm::SealedInstance for peripherals::$type { - fn regs() -> &'static crate::pac::pdm::RegisterBlock { - unsafe { &*pac::$pac_type::ptr() } + fn regs() -> crate::pac::pdm::Pdm { + pac::$pac_type } fn state() -> &'static crate::pdm::State { static STATE: crate::pdm::State = crate::pdm::State::new(); diff --git a/embassy-nrf/src/ppi/dppi.rs b/embassy-nrf/src/ppi/dppi.rs index 0bc7f821e..3c7b96df7 100644 --- a/embassy-nrf/src/ppi/dppi.rs +++ b/embassy-nrf/src/ppi/dppi.rs @@ -6,8 +6,8 @@ use crate::{pac, Peripheral}; const DPPI_ENABLE_BIT: u32 = 0x8000_0000; const DPPI_CHANNEL_MASK: u32 = 0x0000_00FF; -pub(crate) fn regs() -> &'static pac::dppic::RegisterBlock { - unsafe { &*pac::DPPIC::ptr() } +pub(crate) fn regs() -> pac::dppic::Dppic { + pac::DPPIC } impl<'d, C: ConfigurableChannel> Ppi<'d, C, 1, 1> { @@ -57,13 +57,13 @@ impl<'d, C: Channel, const EVENT_COUNT: usize, const TASK_COUNT: usize> Ppi<'d, /// Enables the channel. pub fn enable(&mut self) { let n = self.ch.number(); - regs().chenset.write(|w| unsafe { w.bits(1 << n) }); + regs().chenset().write(|w| w.0 = 1 << n); } /// Disables the channel. pub fn disable(&mut self) { let n = self.ch.number(); - regs().chenclr.write(|w| unsafe { w.bits(1 << n) }); + regs().chenclr().write(|w| w.0 = 1 << n); } } diff --git a/embassy-nrf/src/ppi/mod.rs b/embassy-nrf/src/ppi/mod.rs index 13f7dcc83..325e4ce00 100644 --- a/embassy-nrf/src/ppi/mod.rs +++ b/embassy-nrf/src/ppi/mod.rs @@ -20,6 +20,7 @@ use core::ptr::NonNull; use embassy_hal_internal::{impl_peripheral, into_ref, PeripheralRef}; +use crate::pac::common::{Reg, RW, W}; use crate::{peripherals, Peripheral}; #[cfg_attr(feature = "_dppi", path = "dppi.rs")] @@ -50,7 +51,7 @@ impl<'d, G: Group> PpiGroup<'d, G> { let r = regs(); let n = g.number(); - r.chg[n].write(|w| unsafe { w.bits(0) }); + r.chg(n).write(|_| ()); Self { g } } @@ -65,7 +66,7 @@ impl<'d, G: Group> PpiGroup<'d, G> { let r = regs(); let ng = self.g.number(); let nc = ch.ch.number(); - r.chg[ng].modify(|r, w| unsafe { w.bits(r.bits() | 1 << nc) }); + r.chg(ng).modify(|w| w.set_ch(nc, true)); } /// Remove a PPI channel from this group. @@ -78,19 +79,19 @@ impl<'d, G: Group> PpiGroup<'d, G> { let r = regs(); let ng = self.g.number(); let nc = ch.ch.number(); - r.chg[ng].modify(|r, w| unsafe { w.bits(r.bits() & !(1 << nc)) }); + r.chg(ng).modify(|w| w.set_ch(nc, false)); } /// Enable all the channels in this group. pub fn enable_all(&mut self) { let n = self.g.number(); - regs().tasks_chg[n].en.write(|w| unsafe { w.bits(1) }); + regs().tasks_chg(n).en().write_value(1); } /// Disable all the channels in this group. pub fn disable_all(&mut self) { let n = self.g.number(); - regs().tasks_chg[n].dis.write(|w| unsafe { w.bits(1) }); + regs().tasks_chg(n).dis().write_value(1); } /// Get a reference to the "enable all" task. @@ -98,7 +99,7 @@ impl<'d, G: Group> PpiGroup<'d, G> { /// When triggered, it will enable all the channels in this group. pub fn task_enable_all(&self) -> Task<'d> { let n = self.g.number(); - Task::from_reg(®s().tasks_chg[n].en) + Task::from_reg(regs().tasks_chg(n).en()) } /// Get a reference to the "disable all" task. @@ -106,7 +107,7 @@ impl<'d, G: Group> PpiGroup<'d, G> { /// When triggered, it will disable all the channels in this group. pub fn task_disable_all(&self) -> Task<'d> { let n = self.g.number(); - Task::from_reg(®s().tasks_chg[n].dis) + Task::from_reg(regs().tasks_chg(n).dis()) } } @@ -114,7 +115,7 @@ impl<'d, G: Group> Drop for PpiGroup<'d, G> { fn drop(&mut self) { let r = regs(); let n = self.g.number(); - r.chg[n].write(|w| unsafe { w.bits(0) }); + r.chg(n).write(|_| ()); } } @@ -143,11 +144,8 @@ impl<'d> Task<'d> { unsafe { self.0.as_ptr().write_volatile(1) }; } - pub(crate) fn from_reg(reg: &T) -> Self { - Self( - unsafe { NonNull::new_unchecked(reg as *const _ as *mut _) }, - PhantomData, - ) + pub(crate) fn from_reg(reg: Reg) -> Self { + Self(unsafe { NonNull::new_unchecked(reg.as_ptr()) }, PhantomData) } /// Address of subscription register for this task. @@ -178,11 +176,8 @@ impl<'d> Event<'d> { Self(ptr, PhantomData) } - pub(crate) fn from_reg(reg: &'d T) -> Self { - Self( - unsafe { NonNull::new_unchecked(reg as *const _ as *mut _) }, - PhantomData, - ) + pub(crate) fn from_reg(reg: Reg) -> Self { + Self(unsafe { NonNull::new_unchecked(reg.as_ptr()) }, PhantomData) } /// Describes whether this Event is currently in a triggered state. @@ -284,7 +279,7 @@ impl ConfigurableChannel for AnyConfigurableChannel { } } -#[cfg(not(feature = "nrf51"))] +#[cfg(not(feature = "_nrf51"))] macro_rules! impl_ppi_channel { ($type:ident, $number:expr) => { impl crate::ppi::SealedChannel for peripherals::$type {} @@ -366,7 +361,7 @@ impl_group!(PPI_GROUP0, 0); impl_group!(PPI_GROUP1, 1); impl_group!(PPI_GROUP2, 2); impl_group!(PPI_GROUP3, 3); -#[cfg(not(feature = "nrf51"))] +#[cfg(not(feature = "_nrf51"))] impl_group!(PPI_GROUP4, 4); -#[cfg(not(feature = "nrf51"))] +#[cfg(not(feature = "_nrf51"))] impl_group!(PPI_GROUP5, 5); diff --git a/embassy-nrf/src/ppi/ppi.rs b/embassy-nrf/src/ppi/ppi.rs index 8ff52ece3..a1beb9dcd 100644 --- a/embassy-nrf/src/ppi/ppi.rs +++ b/embassy-nrf/src/ppi/ppi.rs @@ -14,11 +14,11 @@ impl<'d> Event<'d> { } } -pub(crate) fn regs() -> &'static pac::ppi::RegisterBlock { - unsafe { &*pac::PPI::ptr() } +pub(crate) fn regs() -> pac::ppi::Ppi { + pac::PPI } -#[cfg(not(feature = "nrf51"))] // Not for nrf51 because of the fork task +#[cfg(not(feature = "_nrf51"))] // Not for nrf51 because of the fork task impl<'d, C: super::StaticChannel> Ppi<'d, C, 0, 1> { /// Configure PPI channel to trigger `task`. pub fn new_zero_to_one(ch: impl Peripheral

+ 'd, task: Task) -> Self { @@ -26,7 +26,7 @@ impl<'d, C: super::StaticChannel> Ppi<'d, C, 0, 1> { let r = regs(); let n = ch.number(); - r.fork[n].tep.write(|w| unsafe { w.bits(task.reg_val()) }); + r.fork(n).tep().write_value(task.reg_val()); Self { ch } } @@ -39,14 +39,14 @@ impl<'d, C: ConfigurableChannel> Ppi<'d, C, 1, 1> { let r = regs(); let n = ch.number(); - r.ch[n].eep.write(|w| unsafe { w.bits(event.reg_val()) }); - r.ch[n].tep.write(|w| unsafe { w.bits(task.reg_val()) }); + r.ch(n).eep().write_value(event.reg_val()); + r.ch(n).tep().write_value(task.reg_val()); Self { ch } } } -#[cfg(not(feature = "nrf51"))] // Not for nrf51 because of the fork task +#[cfg(not(feature = "_nrf51"))] // Not for nrf51 because of the fork task impl<'d, C: ConfigurableChannel> Ppi<'d, C, 1, 2> { /// Configure PPI channel to trigger both `task1` and `task2` on `event`. pub fn new_one_to_two(ch: impl Peripheral

+ 'd, event: Event<'d>, task1: Task<'d>, task2: Task<'d>) -> Self { @@ -54,9 +54,9 @@ impl<'d, C: ConfigurableChannel> Ppi<'d, C, 1, 2> { let r = regs(); let n = ch.number(); - r.ch[n].eep.write(|w| unsafe { w.bits(event.reg_val()) }); - r.ch[n].tep.write(|w| unsafe { w.bits(task1.reg_val()) }); - r.fork[n].tep.write(|w| unsafe { w.bits(task2.reg_val()) }); + r.ch(n).eep().write_value(event.reg_val()); + r.ch(n).tep().write_value(task1.reg_val()); + r.fork(n).tep().write_value(task2.reg_val()); Self { ch } } @@ -66,13 +66,13 @@ impl<'d, C: Channel, const EVENT_COUNT: usize, const TASK_COUNT: usize> Ppi<'d, /// Enables the channel. pub fn enable(&mut self) { let n = self.ch.number(); - regs().chenset.write(|w| unsafe { w.bits(1 << n) }); + regs().chenset().write(|w| w.set_ch(n, true)); } /// Disables the channel. pub fn disable(&mut self) { let n = self.ch.number(); - regs().chenclr.write(|w| unsafe { w.bits(1 << n) }); + regs().chenclr().write(|w| w.set_ch(n, true)); } } @@ -82,9 +82,9 @@ impl<'d, C: Channel, const EVENT_COUNT: usize, const TASK_COUNT: usize> Drop for let r = regs(); let n = self.ch.number(); - r.ch[n].eep.write(|w| unsafe { w.bits(0) }); - r.ch[n].tep.write(|w| unsafe { w.bits(0) }); - #[cfg(not(feature = "nrf51"))] - r.fork[n].tep.write(|w| unsafe { w.bits(0) }); + r.ch(n).eep().write_value(0); + r.ch(n).tep().write_value(0); + #[cfg(not(feature = "_nrf51"))] + r.fork(n).tep().write_value(0); } } diff --git a/embassy-nrf/src/pwm.rs b/embassy-nrf/src/pwm.rs index 8e8f166d7..c8f1e0b09 100644 --- a/embassy-nrf/src/pwm.rs +++ b/embassy-nrf/src/pwm.rs @@ -6,7 +6,9 @@ use core::sync::atomic::{compiler_fence, Ordering}; use embassy_hal_internal::{into_ref, PeripheralRef}; -use crate::gpio::{convert_drive, AnyPin, OutputDrive, Pin as GpioPin, PselBits, SealedPin as _}; +use crate::gpio::{convert_drive, AnyPin, OutputDrive, Pin as GpioPin, PselBits, SealedPin as _, DISCONNECTED}; +use crate::pac::gpio::vals as gpiovals; +use crate::pac::pwm::vals; use crate::ppi::{Event, Task}; use crate::util::slice_in_ram_or; use crate::{interrupt, pac, Peripheral}; @@ -128,52 +130,61 @@ impl<'d, T: Instance> SequencePwm<'d, T> { if let Some(pin) = &ch0 { pin.set_low(); - pin.conf() - .write(|w| w.dir().output().drive().variant(convert_drive(config.ch0_drive))); + pin.conf().write(|w| { + w.set_dir(gpiovals::Dir::OUTPUT); + w.set_drive(convert_drive(config.ch0_drive)); + }); } if let Some(pin) = &ch1 { pin.set_low(); - pin.conf() - .write(|w| w.dir().output().drive().variant(convert_drive(config.ch1_drive))); + pin.conf().write(|w| { + w.set_dir(gpiovals::Dir::OUTPUT); + w.set_drive(convert_drive(config.ch1_drive)); + }); } if let Some(pin) = &ch2 { pin.set_low(); - pin.conf() - .write(|w| w.dir().output().drive().variant(convert_drive(config.ch2_drive))); + pin.conf().write(|w| { + w.set_dir(gpiovals::Dir::OUTPUT); + w.set_drive(convert_drive(config.ch2_drive)); + }); } if let Some(pin) = &ch3 { pin.set_low(); - pin.conf() - .write(|w| w.dir().output().drive().variant(convert_drive(config.ch3_drive))); + pin.conf().write(|w| { + w.set_dir(gpiovals::Dir::OUTPUT); + w.set_drive(convert_drive(config.ch3_drive)); + }); } - r.psel.out[0].write(|w| unsafe { w.bits(ch0.psel_bits()) }); - r.psel.out[1].write(|w| unsafe { w.bits(ch1.psel_bits()) }); - r.psel.out[2].write(|w| unsafe { w.bits(ch2.psel_bits()) }); - r.psel.out[3].write(|w| unsafe { w.bits(ch3.psel_bits()) }); + r.psel().out(0).write_value(ch0.psel_bits()); + r.psel().out(1).write_value(ch1.psel_bits()); + r.psel().out(2).write_value(ch2.psel_bits()); + r.psel().out(3).write_value(ch3.psel_bits()); // Disable all interrupts - r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) }); - r.shorts.reset(); - r.events_stopped.reset(); - r.events_loopsdone.reset(); - r.events_seqend[0].reset(); - r.events_seqend[1].reset(); - r.events_pwmperiodend.reset(); - r.events_seqstarted[0].reset(); - r.events_seqstarted[1].reset(); + r.intenclr().write(|w| w.0 = 0xFFFF_FFFF); + r.shorts().write(|_| ()); + r.events_stopped().write_value(0); + r.events_loopsdone().write_value(0); + r.events_seqend(0).write_value(0); + r.events_seqend(1).write_value(0); + r.events_pwmperiodend().write_value(0); + r.events_seqstarted(0).write_value(0); + r.events_seqstarted(1).write_value(0); - r.decoder.write(|w| { - w.load().bits(config.sequence_load as u8); - w.mode().refresh_count() + r.decoder().write(|w| { + w.set_load(vals::Load::from_bits(config.sequence_load as u8)); + w.set_mode(vals::Mode::REFRESH_COUNT); }); - r.mode.write(|w| match config.counter_mode { - CounterMode::UpAndDown => w.updown().up_and_down(), - CounterMode::Up => w.updown().up(), + r.mode().write(|w| match config.counter_mode { + CounterMode::UpAndDown => w.set_updown(vals::Updown::UP_AND_DOWN), + CounterMode::Up => w.set_updown(vals::Updown::UP), }); - r.prescaler.write(|w| w.prescaler().bits(config.prescaler as u8)); - r.countertop.write(|w| unsafe { w.countertop().bits(config.max_duty) }); + r.prescaler() + .write(|w| w.set_prescaler(vals::Prescaler::from_bits(config.prescaler as u8))); + r.countertop().write(|w| w.set_countertop(config.max_duty)); Ok(Self { _peri: _pwm, @@ -189,7 +200,7 @@ impl<'d, T: Instance> SequencePwm<'d, T> { pub fn event_stopped(&self) -> Event<'d> { let r = T::regs(); - Event::from_reg(&r.events_stopped) + Event::from_reg(r.events_stopped()) } /// Returns reference to `LoopsDone` event endpoint for PPI. @@ -197,7 +208,7 @@ impl<'d, T: Instance> SequencePwm<'d, T> { pub fn event_loops_done(&self) -> Event<'d> { let r = T::regs(); - Event::from_reg(&r.events_loopsdone) + Event::from_reg(r.events_loopsdone()) } /// Returns reference to `PwmPeriodEnd` event endpoint for PPI. @@ -205,7 +216,7 @@ impl<'d, T: Instance> SequencePwm<'d, T> { pub fn event_pwm_period_end(&self) -> Event<'d> { let r = T::regs(); - Event::from_reg(&r.events_pwmperiodend) + Event::from_reg(r.events_pwmperiodend()) } /// Returns reference to `Seq0 End` event endpoint for PPI. @@ -213,7 +224,7 @@ impl<'d, T: Instance> SequencePwm<'d, T> { pub fn event_seq_end(&self) -> Event<'d> { let r = T::regs(); - Event::from_reg(&r.events_seqend[0]) + Event::from_reg(r.events_seqend(0)) } /// Returns reference to `Seq1 End` event endpoint for PPI. @@ -221,7 +232,7 @@ impl<'d, T: Instance> SequencePwm<'d, T> { pub fn event_seq1_end(&self) -> Event<'d> { let r = T::regs(); - Event::from_reg(&r.events_seqend[1]) + Event::from_reg(r.events_seqend(1)) } /// Returns reference to `Seq0 Started` event endpoint for PPI. @@ -229,7 +240,7 @@ impl<'d, T: Instance> SequencePwm<'d, T> { pub fn event_seq0_started(&self) -> Event<'d> { let r = T::regs(); - Event::from_reg(&r.events_seqstarted[0]) + Event::from_reg(r.events_seqstarted(0)) } /// Returns reference to `Seq1 Started` event endpoint for PPI. @@ -237,7 +248,7 @@ impl<'d, T: Instance> SequencePwm<'d, T> { pub fn event_seq1_started(&self) -> Event<'d> { let r = T::regs(); - Event::from_reg(&r.events_seqstarted[1]) + Event::from_reg(r.events_seqstarted(1)) } /// Returns reference to `Seq0 Start` task endpoint for PPI. @@ -248,7 +259,7 @@ impl<'d, T: Instance> SequencePwm<'d, T> { pub unsafe fn task_start_seq0(&self) -> Task<'d> { let r = T::regs(); - Task::from_reg(&r.tasks_seqstart[0]) + Task::from_reg(r.tasks_seqstart(0)) } /// Returns reference to `Seq1 Started` task endpoint for PPI. @@ -259,7 +270,7 @@ impl<'d, T: Instance> SequencePwm<'d, T> { pub unsafe fn task_start_seq1(&self) -> Task<'d> { let r = T::regs(); - Task::from_reg(&r.tasks_seqstart[1]) + Task::from_reg(r.tasks_seqstart(1)) } /// Returns reference to `NextStep` task endpoint for PPI. @@ -270,7 +281,7 @@ impl<'d, T: Instance> SequencePwm<'d, T> { pub unsafe fn task_next_step(&self) -> Task<'d> { let r = T::regs(); - Task::from_reg(&r.tasks_nextstep) + Task::from_reg(r.tasks_nextstep()) } /// Returns reference to `Stop` task endpoint for PPI. @@ -281,7 +292,7 @@ impl<'d, T: Instance> SequencePwm<'d, T> { pub unsafe fn task_stop(&self) -> Task<'d> { let r = T::regs(); - Task::from_reg(&r.tasks_stop) + Task::from_reg(r.tasks_stop()) } } @@ -291,23 +302,23 @@ impl<'a, T: Instance> Drop for SequencePwm<'a, T> { if let Some(pin) = &self.ch0 { pin.set_low(); - pin.conf().reset(); - r.psel.out[0].reset(); + pin.conf().write(|_| ()); + r.psel().out(0).write_value(DISCONNECTED); } if let Some(pin) = &self.ch1 { pin.set_low(); - pin.conf().reset(); - r.psel.out[1].reset(); + pin.conf().write(|_| ()); + r.psel().out(1).write_value(DISCONNECTED); } if let Some(pin) = &self.ch2 { pin.set_low(); - pin.conf().reset(); - r.psel.out[2].reset(); + pin.conf().write(|_| ()); + r.psel().out(2).write_value(DISCONNECTED); } if let Some(pin) = &self.ch3 { pin.set_low(); - pin.conf().reset(); - r.psel.out[3].reset(); + pin.conf().write(|_| ()); + r.psel().out(3).write_value(DISCONNECTED); } } } @@ -463,21 +474,17 @@ impl<'d, 's, T: Instance> Sequencer<'d, 's, T> { let r = T::regs(); - r.seq0.refresh.write(|w| unsafe { w.bits(sequence0.config.refresh) }); - r.seq0.enddelay.write(|w| unsafe { w.bits(sequence0.config.end_delay) }); - r.seq0.ptr.write(|w| unsafe { w.bits(sequence0.words.as_ptr() as u32) }); - r.seq0.cnt.write(|w| unsafe { w.bits(sequence0.words.len() as u32) }); + r.seq(0).refresh().write(|w| w.0 = sequence0.config.refresh); + r.seq(0).enddelay().write(|w| w.0 = sequence0.config.end_delay); + r.seq(0).ptr().write_value(sequence0.words.as_ptr() as u32); + r.seq(0).cnt().write(|w| w.0 = sequence0.words.len() as u32); - r.seq1.refresh.write(|w| unsafe { w.bits(alt_sequence.config.refresh) }); - r.seq1 - .enddelay - .write(|w| unsafe { w.bits(alt_sequence.config.end_delay) }); - r.seq1 - .ptr - .write(|w| unsafe { w.bits(alt_sequence.words.as_ptr() as u32) }); - r.seq1.cnt.write(|w| unsafe { w.bits(alt_sequence.words.len() as u32) }); + r.seq(1).refresh().write(|w| w.0 = alt_sequence.config.refresh); + r.seq(1).enddelay().write(|w| w.0 = alt_sequence.config.end_delay); + r.seq(1).ptr().write_value(alt_sequence.words.as_ptr() as u32); + r.seq(1).cnt().write(|w| w.0 = alt_sequence.words.len() as u32); - r.enable.write(|w| w.enable().enabled()); + r.enable().write(|w| w.set_enable(true)); // defensive before seqstart compiler_fence(Ordering::SeqCst); @@ -486,18 +493,17 @@ impl<'d, 's, T: Instance> Sequencer<'d, 's, T> { match times { // just the one time, no loop count - SequenceMode::Loop(n) => { - r.loop_.write(|w| unsafe { w.cnt().bits(n) }); + SequenceMode::Loop(_) => { + r.loop_().write(|w| w.set_cnt(vals::LoopCnt::DISABLED)); } // to play infinitely, repeat the sequence one time, then have loops done self trigger seq0 again SequenceMode::Infinite => { - r.loop_.write(|w| unsafe { w.cnt().bits(0x1) }); - r.shorts.write(|w| w.loopsdone_seqstart0().enabled()); + r.loop_().write(|w| w.set_cnt(vals::LoopCnt::from_bits(1))); + r.shorts().write(|w| w.set_loopsdone_seqstart0(true)); } } - // tasks_seqstart() doesn't exist in all svds so write its bit instead - r.tasks_seqstart[seqstart_index].write(|w| unsafe { w.bits(0x01) }); + r.tasks_seqstart(seqstart_index).write_value(1); Ok(()) } @@ -509,14 +515,12 @@ impl<'d, 's, T: Instance> Sequencer<'d, 's, T> { pub fn stop(&self) { let r = T::regs(); - r.shorts.reset(); + r.shorts().write(|_| ()); compiler_fence(Ordering::SeqCst); - // tasks_stop() doesn't exist in all svds so write its bit instead - r.tasks_stop.write(|w| unsafe { w.bits(0x01) }); - - r.enable.write(|w| w.enable().disabled()); + r.tasks_stop().write_value(1); + r.enable().write(|w| w.set_enable(false)); } } @@ -672,29 +676,13 @@ impl<'d, T: Instance> SimplePwm<'d, T> { let r = T::regs(); - if let Some(pin) = &ch0 { - pin.set_low(); - pin.conf().write(|w| w.dir().output()); + for (i, ch) in [&ch0, &ch1, &ch2, &ch3].into_iter().enumerate() { + if let Some(pin) = ch { + pin.set_low(); + pin.conf().write(|w| w.set_dir(gpiovals::Dir::OUTPUT)); + } + r.psel().out(i).write_value(ch0.psel_bits()); } - if let Some(pin) = &ch1 { - pin.set_low(); - pin.conf().write(|w| w.dir().output()); - } - if let Some(pin) = &ch2 { - pin.set_low(); - pin.conf().write(|w| w.dir().output()); - } - if let Some(pin) = &ch3 { - pin.set_low(); - pin.conf().write(|w| w.dir().output()); - } - - // if NoPin provided writes disconnected (top bit 1) 0x80000000 else - // writes pin number ex 13 (0x0D) which is connected (top bit 0) - r.psel.out[0].write(|w| unsafe { w.bits(ch0.psel_bits()) }); - r.psel.out[1].write(|w| unsafe { w.bits(ch1.psel_bits()) }); - r.psel.out[2].write(|w| unsafe { w.bits(ch2.psel_bits()) }); - r.psel.out[3].write(|w| unsafe { w.bits(ch3.psel_bits()) }); let pwm = Self { _peri: _pwm, @@ -706,26 +694,25 @@ impl<'d, T: Instance> SimplePwm<'d, T> { }; // Disable all interrupts - r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) }); - r.shorts.reset(); + r.intenclr().write(|w| w.0 = 0xFFFF_FFFF); + r.shorts().write(|_| ()); // Enable - r.enable.write(|w| w.enable().enabled()); + r.enable().write(|w| w.set_enable(true)); - r.seq0.ptr.write(|w| unsafe { w.bits((pwm.duty).as_ptr() as u32) }); + r.seq(0).ptr().write_value((pwm.duty).as_ptr() as u32); + r.seq(0).cnt().write(|w| w.0 = 4); + r.seq(0).refresh().write(|w| w.0 = 0); + r.seq(0).enddelay().write(|w| w.0 = 0); - r.seq0.cnt.write(|w| unsafe { w.bits(4) }); - r.seq0.refresh.write(|w| unsafe { w.bits(0) }); - r.seq0.enddelay.write(|w| unsafe { w.bits(0) }); - - r.decoder.write(|w| { - w.load().individual(); - w.mode().refresh_count() + r.decoder().write(|w| { + w.set_load(vals::Load::INDIVIDUAL); + w.set_mode(vals::Mode::REFRESH_COUNT); }); - r.mode.write(|w| w.updown().up()); - r.prescaler.write(|w| w.prescaler().div_16()); - r.countertop.write(|w| unsafe { w.countertop().bits(1000) }); - r.loop_.write(|w| w.cnt().disabled()); + r.mode().write(|w| w.set_updown(vals::Updown::UP)); + r.prescaler().write(|w| w.set_prescaler(vals::Prescaler::DIV_16)); + r.countertop().write(|w| w.set_countertop(1000)); + r.loop_().write(|w| w.set_cnt(vals::LoopCnt::DISABLED)); pwm } @@ -734,21 +721,21 @@ impl<'d, T: Instance> SimplePwm<'d, T> { #[inline(always)] pub fn is_enabled(&self) -> bool { let r = T::regs(); - r.enable.read().enable().bit_is_set() + r.enable().read().enable() } /// Enables the PWM generator. #[inline(always)] pub fn enable(&self) { let r = T::regs(); - r.enable.write(|w| w.enable().enabled()); + r.enable().write(|w| w.set_enable(true)); } /// Disables the PWM generator. Does NOT clear the last duty cycle from the pin. #[inline(always)] pub fn disable(&self) { let r = T::regs(); - r.enable.write(|w| w.enable().disabled()); + r.enable().write(|w| w.set_enable(false)); } /// Returns the current duty of the channel @@ -763,33 +750,35 @@ impl<'d, T: Instance> SimplePwm<'d, T> { self.duty[channel] = duty & 0x7FFF; // reload ptr in case self was moved - r.seq0.ptr.write(|w| unsafe { w.bits((self.duty).as_ptr() as u32) }); + r.seq(0).ptr().write_value((self.duty).as_ptr() as u32); // defensive before seqstart compiler_fence(Ordering::SeqCst); - r.events_seqend[0].reset(); + r.events_seqend(0).write_value(0); // tasks_seqstart() doesn't exist in all svds so write its bit instead - r.tasks_seqstart[0].write(|w| unsafe { w.bits(1) }); + r.tasks_seqstart(0).write_value(1); // defensive wait until waveform is loaded after seqstart so set_duty // can't be called again while dma is still reading if self.is_enabled() { - while r.events_seqend[0].read().bits() == 0 {} + while r.events_seqend(0).read() == 0 {} } } /// Sets the PWM clock prescaler. #[inline(always)] pub fn set_prescaler(&self, div: Prescaler) { - T::regs().prescaler.write(|w| w.prescaler().bits(div as u8)); + T::regs() + .prescaler() + .write(|w| w.set_prescaler(vals::Prescaler::from_bits(div as u8))); } /// Gets the PWM clock prescaler. #[inline(always)] pub fn prescaler(&self) -> Prescaler { - match T::regs().prescaler.read().prescaler().bits() { + match T::regs().prescaler().read().prescaler().to_bits() { 0 => Prescaler::Div1, 1 => Prescaler::Div2, 2 => Prescaler::Div4, @@ -805,15 +794,13 @@ impl<'d, T: Instance> SimplePwm<'d, T> { /// Sets the maximum duty cycle value. #[inline(always)] pub fn set_max_duty(&self, duty: u16) { - T::regs() - .countertop - .write(|w| unsafe { w.countertop().bits(duty.min(32767u16)) }); + T::regs().countertop().write(|w| w.set_countertop(duty.min(32767u16))); } /// Returns the maximum duty cycle value. #[inline(always)] pub fn max_duty(&self) -> u16 { - T::regs().countertop.read().countertop().bits() + T::regs().countertop().read().countertop() } /// Sets the PWM output frequency. @@ -836,7 +823,7 @@ impl<'d, T: Instance> SimplePwm<'d, T> { #[inline(always)] pub fn set_ch0_drive(&self, drive: OutputDrive) { if let Some(pin) = &self.ch0 { - pin.conf().modify(|_, w| w.drive().variant(convert_drive(drive))); + pin.conf().modify(|w| w.set_drive(convert_drive(drive))); } } @@ -844,7 +831,7 @@ impl<'d, T: Instance> SimplePwm<'d, T> { #[inline(always)] pub fn set_ch1_drive(&self, drive: OutputDrive) { if let Some(pin) = &self.ch1 { - pin.conf().modify(|_, w| w.drive().variant(convert_drive(drive))); + pin.conf().modify(|w| w.set_drive(convert_drive(drive))); } } @@ -852,7 +839,7 @@ impl<'d, T: Instance> SimplePwm<'d, T> { #[inline(always)] pub fn set_ch2_drive(&self, drive: OutputDrive) { if let Some(pin) = &self.ch2 { - pin.conf().modify(|_, w| w.drive().variant(convert_drive(drive))); + pin.conf().modify(|w| w.set_drive(convert_drive(drive))); } } @@ -860,7 +847,7 @@ impl<'d, T: Instance> SimplePwm<'d, T> { #[inline(always)] pub fn set_ch3_drive(&self, drive: OutputDrive) { if let Some(pin) = &self.ch3 { - pin.conf().modify(|_, w| w.drive().variant(convert_drive(drive))); + pin.conf().modify(|w| w.set_drive(convert_drive(drive))); } } } @@ -873,29 +860,29 @@ impl<'a, T: Instance> Drop for SimplePwm<'a, T> { if let Some(pin) = &self.ch0 { pin.set_low(); - pin.conf().reset(); - r.psel.out[0].reset(); + pin.conf().write(|_| ()); + r.psel().out(0).write_value(DISCONNECTED); } if let Some(pin) = &self.ch1 { pin.set_low(); - pin.conf().reset(); - r.psel.out[1].reset(); + pin.conf().write(|_| ()); + r.psel().out(1).write_value(DISCONNECTED); } if let Some(pin) = &self.ch2 { pin.set_low(); - pin.conf().reset(); - r.psel.out[2].reset(); + pin.conf().write(|_| ()); + r.psel().out(2).write_value(DISCONNECTED); } if let Some(pin) = &self.ch3 { pin.set_low(); - pin.conf().reset(); - r.psel.out[3].reset(); + pin.conf().write(|_| ()); + r.psel().out(3).write_value(DISCONNECTED); } } } pub(crate) trait SealedInstance { - fn regs() -> &'static pac::pwm0::RegisterBlock; + fn regs() -> pac::pwm::Pwm; } /// PWM peripheral instance. @@ -908,8 +895,8 @@ pub trait Instance: Peripheral

+ SealedInstance + 'static { macro_rules! impl_pwm { ($type:ident, $pac_type:ident, $irq:ident) => { impl crate::pwm::SealedInstance for peripherals::$type { - fn regs() -> &'static pac::pwm0::RegisterBlock { - unsafe { &*pac::$pac_type::ptr() } + fn regs() -> pac::pwm::Pwm { + pac::$pac_type } } impl crate::pwm::Instance for peripherals::$type { diff --git a/embassy-nrf/src/qdec.rs b/embassy-nrf/src/qdec.rs index 7409c9b1e..efd2a134c 100644 --- a/embassy-nrf/src/qdec.rs +++ b/embassy-nrf/src/qdec.rs @@ -11,7 +11,9 @@ use embassy_sync::waitqueue::AtomicWaker; use crate::gpio::{AnyPin, Pin as GpioPin, SealedPin as _}; use crate::interrupt::typelevel::Interrupt; -use crate::{interrupt, Peripheral}; +use crate::pac::gpio::vals as gpiovals; +use crate::pac::qdec::vals; +use crate::{interrupt, pac, Peripheral}; /// Quadrature decoder driver. pub struct Qdec<'d, T: Instance> { @@ -52,7 +54,7 @@ pub struct InterruptHandler { impl interrupt::typelevel::Handler for InterruptHandler { unsafe fn on_interrupt() { - T::regs().intenclr.write(|w| w.reportrdy().clear()); + T::regs().intenclr().write(|w| w.set_reportrdy(true)); T::state().waker.wake(); } } @@ -93,54 +95,59 @@ impl<'d, T: Instance> Qdec<'d, T> { let r = T::regs(); // Select pins. - a.conf().write(|w| w.input().connect().pull().pullup()); - b.conf().write(|w| w.input().connect().pull().pullup()); - r.psel.a.write(|w| unsafe { w.bits(a.psel_bits()) }); - r.psel.b.write(|w| unsafe { w.bits(b.psel_bits()) }); + a.conf().write(|w| { + w.set_input(gpiovals::Input::CONNECT); + w.set_pull(gpiovals::Pull::PULLUP); + }); + b.conf().write(|w| { + w.set_input(gpiovals::Input::CONNECT); + w.set_pull(gpiovals::Pull::PULLUP); + }); + r.psel().a().write_value(a.psel_bits()); + r.psel().b().write_value(b.psel_bits()); if let Some(led_pin) = &led { - led_pin.conf().write(|w| w.dir().output()); - r.psel.led.write(|w| unsafe { w.bits(led_pin.psel_bits()) }); + led_pin.conf().write(|w| w.set_dir(gpiovals::Dir::OUTPUT)); + r.psel().led().write_value(led_pin.psel_bits()); } // Enables/disable input debounce filters - r.dbfen.write(|w| match config.debounce { - true => w.dbfen().enabled(), - false => w.dbfen().disabled(), + r.dbfen().write(|w| match config.debounce { + true => w.set_dbfen(true), + false => w.set_dbfen(false), }); // Set LED output pin polarity - r.ledpol.write(|w| match config.led_polarity { - LedPolarity::ActiveHigh => w.ledpol().active_high(), - LedPolarity::ActiveLow => w.ledpol().active_low(), + r.ledpol().write(|w| match config.led_polarity { + LedPolarity::ActiveHigh => w.set_ledpol(vals::Ledpol::ACTIVE_HIGH), + LedPolarity::ActiveLow => w.set_ledpol(vals::Ledpol::ACTIVE_LOW), }); // Set time period the LED is switched ON prior to sampling (0..511 us). - r.ledpre - .write(|w| unsafe { w.ledpre().bits(config.led_pre_usecs.min(511)) }); + r.ledpre().write(|w| w.set_ledpre(config.led_pre_usecs.min(511))); // Set sample period - r.sampleper.write(|w| match config.period { - SamplePeriod::_128us => w.sampleper()._128us(), - SamplePeriod::_256us => w.sampleper()._256us(), - SamplePeriod::_512us => w.sampleper()._512us(), - SamplePeriod::_1024us => w.sampleper()._1024us(), - SamplePeriod::_2048us => w.sampleper()._2048us(), - SamplePeriod::_4096us => w.sampleper()._4096us(), - SamplePeriod::_8192us => w.sampleper()._8192us(), - SamplePeriod::_16384us => w.sampleper()._16384us(), - SamplePeriod::_32ms => w.sampleper()._32ms(), - SamplePeriod::_65ms => w.sampleper()._65ms(), - SamplePeriod::_131ms => w.sampleper()._131ms(), + r.sampleper().write(|w| match config.period { + SamplePeriod::_128us => w.set_sampleper(vals::Sampleper::_128US), + SamplePeriod::_256us => w.set_sampleper(vals::Sampleper::_256US), + SamplePeriod::_512us => w.set_sampleper(vals::Sampleper::_512US), + SamplePeriod::_1024us => w.set_sampleper(vals::Sampleper::_1024US), + SamplePeriod::_2048us => w.set_sampleper(vals::Sampleper::_2048US), + SamplePeriod::_4096us => w.set_sampleper(vals::Sampleper::_4096US), + SamplePeriod::_8192us => w.set_sampleper(vals::Sampleper::_8192US), + SamplePeriod::_16384us => w.set_sampleper(vals::Sampleper::_16384US), + SamplePeriod::_32ms => w.set_sampleper(vals::Sampleper::_32MS), + SamplePeriod::_65ms => w.set_sampleper(vals::Sampleper::_65MS), + SamplePeriod::_131ms => w.set_sampleper(vals::Sampleper::_131MS), }); T::Interrupt::unpend(); unsafe { T::Interrupt::enable() }; // Enable peripheral - r.enable.write(|w| w.enable().set_bit()); + r.enable().write(|w| w.set_enable(true)); // Start sampling - unsafe { r.tasks_start.write(|w| w.bits(1)) }; + r.tasks_start().write_value(1); Self { _p: p } } @@ -169,16 +176,16 @@ impl<'d, T: Instance> Qdec<'d, T> { /// ``` pub async fn read(&mut self) -> i16 { let t = T::regs(); - t.intenset.write(|w| w.reportrdy().set()); - unsafe { t.tasks_readclracc.write(|w| w.bits(1)) }; + t.intenset().write(|w| w.set_reportrdy(true)); + t.tasks_readclracc().write_value(1); poll_fn(|cx| { T::state().waker.register(cx.waker()); - if t.events_reportrdy.read().bits() == 0 { + if t.events_reportrdy().read() == 0 { Poll::Pending } else { - t.events_reportrdy.reset(); - let acc = t.accread.read().bits(); + t.events_reportrdy().write_value(0); + let acc = t.accread().read(); Poll::Ready(acc as i16) } }) @@ -259,7 +266,7 @@ impl State { } pub(crate) trait SealedInstance { - fn regs() -> &'static crate::pac::qdec::RegisterBlock; + fn regs() -> pac::qdec::Qdec; fn state() -> &'static State; } @@ -273,8 +280,8 @@ pub trait Instance: Peripheral

+ SealedInstance + 'static + Send { macro_rules! impl_qdec { ($type:ident, $pac_type:ident, $irq:ident) => { impl crate::qdec::SealedInstance for peripherals::$type { - fn regs() -> &'static crate::pac::qdec::RegisterBlock { - unsafe { &*pac::$pac_type::ptr() } + fn regs() -> pac::qdec::Qdec { + pac::$pac_type } fn state() -> &'static crate::qdec::State { static STATE: crate::qdec::State = crate::qdec::State::new(); diff --git a/embassy-nrf/src/qspi.rs b/embassy-nrf/src/qspi.rs index d40096edc..de9c268c1 100755 --- a/embassy-nrf/src/qspi.rs +++ b/embassy-nrf/src/qspi.rs @@ -14,11 +14,12 @@ use embedded_storage::nor_flash::{ErrorType, NorFlash, NorFlashError, NorFlashEr use crate::gpio::{self, Pin as GpioPin}; use crate::interrupt::typelevel::Interrupt; -pub use crate::pac::qspi::ifconfig0::{ - ADDRMODE_A as AddressMode, PPSIZE_A as WritePageSize, READOC_A as ReadOpcode, WRITEOC_A as WriteOpcode, +use crate::pac::gpio::vals as gpiovals; +use crate::pac::qspi::vals; +pub use crate::pac::qspi::vals::{ + Addrmode as AddressMode, Ppsize as WritePageSize, Readoc as ReadOpcode, Spimode as SpiMode, Writeoc as WriteOpcode, }; -pub use crate::pac::qspi::ifconfig1::SPIMODE_A as SpiMode; -use crate::{interrupt, Peripheral}; +use crate::{interrupt, pac, Peripheral}; /// Deep power-down config. pub struct DeepPowerDownConfig { @@ -129,9 +130,9 @@ impl interrupt::typelevel::Handler for InterruptHandl let r = T::regs(); let s = T::state(); - if r.events_ready.read().bits() != 0 { + if r.events_ready().read() != 0 { s.waker.wake(); - r.intenclr.write(|w| w.ready().clear()); + r.intenclr().write(|w| w.set_ready(true)); } } } @@ -164,13 +165,12 @@ impl<'d, T: Instance> Qspi<'d, T> { ($pin:ident) => { $pin.set_high(); $pin.conf().write(|w| { - w.dir().output(); - w.drive().h0h1(); + w.set_dir(gpiovals::Dir::OUTPUT); + w.set_drive(gpiovals::Drive::H0H1); #[cfg(all(feature = "_nrf5340", feature = "_s"))] - w.mcusel().peripheral(); - w + w.set_mcusel(gpiovals::Mcusel::PERIPHERAL); }); - r.psel.$pin.write(|w| unsafe { w.bits($pin.psel_bits()) }); + r.psel().$pin().write_value($pin.psel_bits()); }; } @@ -181,46 +181,39 @@ impl<'d, T: Instance> Qspi<'d, T> { config_pin!(io2); config_pin!(io3); - r.ifconfig0.write(|w| { - w.addrmode().variant(config.address_mode); - w.dpmenable().bit(config.deep_power_down.is_some()); - w.ppsize().variant(config.write_page_size); - w.readoc().variant(config.read_opcode); - w.writeoc().variant(config.write_opcode); - w + r.ifconfig0().write(|w| { + w.set_addrmode(config.address_mode); + w.set_dpmenable(config.deep_power_down.is_some()); + w.set_ppsize(config.write_page_size); + w.set_readoc(config.read_opcode); + w.set_writeoc(config.write_opcode); }); if let Some(dpd) = &config.deep_power_down { - r.dpmdur.write(|w| unsafe { - w.enter().bits(dpd.enter_time); - w.exit().bits(dpd.exit_time); - w + r.dpmdur().write(|w| { + w.set_enter(dpd.enter_time); + w.set_exit(dpd.exit_time); }) } - r.ifconfig1.write(|w| unsafe { - w.sckdelay().bits(config.sck_delay); - w.dpmen().exit(); - w.spimode().variant(config.spi_mode); - w.sckfreq().bits(config.frequency as u8); - w + r.ifconfig1().write(|w| { + w.set_sckdelay(config.sck_delay); + w.set_dpmen(false); + w.set_spimode(config.spi_mode); + w.set_sckfreq(config.frequency as u8); }); - r.iftiming.write(|w| unsafe { - w.rxdelay().bits(config.rx_delay & 0b111); - w + r.iftiming().write(|w| { + w.set_rxdelay(config.rx_delay & 0b111); }); - r.xipoffset.write(|w| unsafe { - w.xipoffset().bits(config.xip_offset); - w - }); + r.xipoffset().write_value(config.xip_offset); T::Interrupt::unpend(); unsafe { T::Interrupt::enable() }; // Enable it - r.enable.write(|w| w.enable().enabled()); + r.enable().write(|w| w.set_enable(true)); let res = Self { _peri: qspi, @@ -228,10 +221,10 @@ impl<'d, T: Instance> Qspi<'d, T> { capacity: config.capacity, }; - r.events_ready.reset(); - r.intenset.write(|w| w.ready().set()); + r.events_ready().write_value(0); + r.intenset().write(|w| w.set_ready(true)); - r.tasks_activate.write(|w| w.tasks_activate().bit(true)); + r.tasks_activate().write_value(1); Self::blocking_wait_ready(); @@ -284,22 +277,21 @@ impl<'d, T: Instance> Qspi<'d, T> { } let r = T::regs(); - r.cinstrdat0.write(|w| unsafe { w.bits(dat0) }); - r.cinstrdat1.write(|w| unsafe { w.bits(dat1) }); + r.cinstrdat0().write(|w| w.0 = dat0); + r.cinstrdat1().write(|w| w.0 = dat1); - r.events_ready.reset(); - r.intenset.write(|w| w.ready().set()); + r.events_ready().write_value(0); + r.intenset().write(|w| w.set_ready(true)); - r.cinstrconf.write(|w| { - let w = unsafe { w.opcode().bits(opcode) }; - let w = unsafe { w.length().bits(len + 1) }; - let w = w.lio2().bit(true); - let w = w.lio3().bit(true); - let w = w.wipwait().bit(true); - let w = w.wren().bit(true); - let w = w.lfen().bit(false); - let w = w.lfstop().bit(false); - w + r.cinstrconf().write(|w| { + w.set_opcode(opcode); + w.set_length(vals::Length::from_bits(len + 1)); + w.set_lio2(true); + w.set_lio3(true); + w.set_wipwait(true); + w.set_wren(true); + w.set_lfen(false); + w.set_lfstop(false); }); Ok(()) } @@ -307,8 +299,8 @@ impl<'d, T: Instance> Qspi<'d, T> { fn custom_instruction_finish(&mut self, resp: &mut [u8]) -> Result<(), Error> { let r = T::regs(); - let dat0 = r.cinstrdat0.read().bits(); - let dat1 = r.cinstrdat1.read().bits(); + let dat0 = r.cinstrdat0().read().0; + let dat1 = r.cinstrdat1().read().0; for i in 0..4 { if i < resp.len() { resp[i] = (dat0 >> (i * 8)) as u8; @@ -327,7 +319,7 @@ impl<'d, T: Instance> Qspi<'d, T> { let r = T::regs(); let s = T::state(); s.waker.register(cx.waker()); - if r.events_ready.read().bits() != 0 { + if r.events_ready().read() != 0 { return Poll::Ready(()); } Poll::Pending @@ -338,7 +330,7 @@ impl<'d, T: Instance> Qspi<'d, T> { fn blocking_wait_ready() { loop { let r = T::regs(); - if r.events_ready.read().bits() != 0 { + if r.events_ready().read() != 0 { break; } } @@ -352,13 +344,13 @@ impl<'d, T: Instance> Qspi<'d, T> { let r = T::regs(); - r.read.src.write(|w| unsafe { w.src().bits(address) }); - r.read.dst.write(|w| unsafe { w.dst().bits(data.as_ptr() as u32) }); - r.read.cnt.write(|w| unsafe { w.cnt().bits(data.len() as u32) }); + r.read().src().write_value(address); + r.read().dst().write_value(data.as_ptr() as u32); + r.read().cnt().write(|w| w.set_cnt(data.len() as u32)); - r.events_ready.reset(); - r.intenset.write(|w| w.ready().set()); - r.tasks_readstart.write(|w| w.tasks_readstart().bit(true)); + r.events_ready().write_value(0); + r.intenset().write(|w| w.set_ready(true)); + r.tasks_readstart().write_value(1); Ok(()) } @@ -370,13 +362,13 @@ impl<'d, T: Instance> Qspi<'d, T> { assert_eq!(address % 4, 0); let r = T::regs(); - r.write.src.write(|w| unsafe { w.src().bits(data.as_ptr() as u32) }); - r.write.dst.write(|w| unsafe { w.dst().bits(address) }); - r.write.cnt.write(|w| unsafe { w.cnt().bits(data.len() as u32) }); + r.write().src().write_value(data.as_ptr() as u32); + r.write().dst().write_value(address); + r.write().cnt().write(|w| w.set_cnt(data.len() as u32)); - r.events_ready.reset(); - r.intenset.write(|w| w.ready().set()); - r.tasks_writestart.write(|w| w.tasks_writestart().bit(true)); + r.events_ready().write_value(0); + r.intenset().write(|w| w.set_ready(true)); + r.tasks_writestart().write_value(1); Ok(()) } @@ -386,12 +378,12 @@ impl<'d, T: Instance> Qspi<'d, T> { assert_eq!(address % 4096, 0); let r = T::regs(); - r.erase.ptr.write(|w| unsafe { w.ptr().bits(address) }); - r.erase.len.write(|w| w.len()._4kb()); + r.erase().ptr().write_value(address); + r.erase().len().write(|w| w.set_len(vals::Len::_4KB)); - r.events_ready.reset(); - r.intenset.write(|w| w.ready().set()); - r.tasks_erasestart.write(|w| w.tasks_erasestart().bit(true)); + r.events_ready().write_value(0); + r.intenset().write(|w| w.set_ready(true)); + r.tasks_erasestart().write_value(1); Ok(()) } @@ -538,12 +530,12 @@ impl<'d, T: Instance> Drop for Qspi<'d, T> { if self.dpm_enabled { trace!("qspi: doing deep powerdown..."); - r.ifconfig1.modify(|_, w| w.dpmen().enter()); + r.ifconfig1().modify(|w| w.set_dpmen(true)); // Wait for DPM enter. // Unfortunately we must spin. There's no way to do this interrupt-driven. // The READY event does NOT fire on DPM enter (but it does fire on DPM exit :shrug:) - while r.status.read().dpm().is_disabled() {} + while !r.status().read().dpm() {} // Wait MORE for DPM enter. // I have absolutely no idea why, but the wait above is not enough :'( @@ -552,23 +544,23 @@ impl<'d, T: Instance> Drop for Qspi<'d, T> { } // it seems events_ready is not generated in response to deactivate. nrfx doesn't wait for it. - r.tasks_deactivate.write(|w| w.tasks_deactivate().set_bit()); + r.tasks_deactivate().write_value(1); // Workaround https://infocenter.nordicsemi.com/topic/errata_nRF52840_Rev1/ERR/nRF52840/Rev1/latest/anomaly_840_122.html?cp=4_0_1_2_1_7 // Note that the doc has 2 register writes, but the first one is really the write to tasks_deactivate, // so we only do the second one here. unsafe { ptr::write_volatile(0x40029054 as *mut u32, 1) } - r.enable.write(|w| w.enable().disabled()); + r.enable().write(|w| w.set_enable(false)); // Note: we do NOT deconfigure CSN here. If DPM is in use and we disconnect CSN, // leaving it floating, the flash chip might read it as zero which would cause it to // spuriously exit DPM. - gpio::deconfigure_pin(r.psel.sck.read().bits()); - gpio::deconfigure_pin(r.psel.io0.read().bits()); - gpio::deconfigure_pin(r.psel.io1.read().bits()); - gpio::deconfigure_pin(r.psel.io2.read().bits()); - gpio::deconfigure_pin(r.psel.io3.read().bits()); + gpio::deconfigure_pin(r.psel().sck().read()); + gpio::deconfigure_pin(r.psel().io0().read()); + gpio::deconfigure_pin(r.psel().io1().read()); + gpio::deconfigure_pin(r.psel().io2().read()); + gpio::deconfigure_pin(r.psel().io3().read()); trace!("qspi: dropped"); } @@ -667,7 +659,7 @@ impl State { } pub(crate) trait SealedInstance { - fn regs() -> &'static crate::pac::qspi::RegisterBlock; + fn regs() -> pac::qspi::Qspi; fn state() -> &'static State; } @@ -681,8 +673,8 @@ pub trait Instance: Peripheral

+ SealedInstance + 'static + Send { macro_rules! impl_qspi { ($type:ident, $pac_type:ident, $irq:ident) => { impl crate::qspi::SealedInstance for peripherals::$type { - fn regs() -> &'static crate::pac::qspi::RegisterBlock { - unsafe { &*pac::$pac_type::ptr() } + fn regs() -> pac::qspi::Qspi { + pac::$pac_type } fn state() -> &'static crate::qspi::State { static STATE: crate::qspi::State = crate::qspi::State::new(); diff --git a/embassy-nrf/src/radio/ble.rs b/embassy-nrf/src/radio/ble.rs index 4f0b0641f..682ca1c79 100644 --- a/embassy-nrf/src/radio/ble.rs +++ b/embassy-nrf/src/radio/ble.rs @@ -6,11 +6,12 @@ use core::task::Poll; use embassy_hal_internal::drop::OnDrop; use embassy_hal_internal::{into_ref, PeripheralRef}; -pub use pac::radio::mode::MODE_A as Mode; -#[cfg(not(feature = "nrf51"))] -use pac::radio::pcnf0::PLEN_A as PreambleLength; +pub use pac::radio::vals::Mode; +#[cfg(not(feature = "_nrf51"))] +use pac::radio::vals::Plen as PreambleLength; use crate::interrupt::typelevel::Interrupt; +use crate::pac::radio::vals; use crate::radio::*; pub use crate::radio::{Error, TxPower}; use crate::util::slice_in_ram_or; @@ -30,69 +31,63 @@ impl<'d, T: Instance> Radio<'d, T> { let r = T::regs(); - r.pcnf1.write(|w| unsafe { + r.pcnf1().write(|w| { // It is 0 bytes long in a standard BLE packet - w.statlen() - .bits(0) - // MaxLen configures the maximum packet payload plus add-on size in - // number of bytes that can be transmitted or received by the RADIO. This feature can be used to ensure - // that the RADIO does not overwrite, or read beyond, the RAM assigned to the packet payload. This means - // that if the packet payload length defined by PCNF1.STATLEN and the LENGTH field in the packet specifies a - // packet larger than MAXLEN, the payload will be truncated at MAXLEN - // - // To simplify the implementation, It is setted as the maximum value - // and the length of the packet is controlled only by the LENGTH field in the packet - .maxlen() - .bits(255) - // Configure the length of the address field in the packet - // The prefix after the address fields is always appended, so is always 1 byte less than the size of the address - // The base address is truncated from the least significant byte if the BALEN is less than 4 - // - // BLE address is always 4 bytes long - .balen() - .bits(3) // 3 bytes base address (+ 1 prefix); - // Configure the endianess - // For BLE is always little endian (LSB first) - .endian() - .little() - // Data whitening is used to avoid long sequences of zeros or - // ones, e.g., 0b0000000 or 0b1111111, in the data bit stream. - // The whitener and de-whitener are defined the same way, - // using a 7-bit linear feedback shift register with the - // polynomial x7 + x4 + 1. - // - // In BLE Whitening shall be applied on the PDU and CRC of all - // Link Layer packets and is performed after the CRC generation - // in the transmitter. No other parts of the packets are whitened. - // De-whitening is performed before the CRC checking in the receiver - // Before whitening or de-whitening, the shift register should be - // initialized based on the channel index. - .whiteen() - .set_bit() + w.set_statlen(0); + // MaxLen configures the maximum packet payload plus add-on size in + // number of bytes that can be transmitted or received by the RADIO. This feature can be used to ensure + // that the RADIO does not overwrite, or read beyond, the RAM assigned to the packet payload. This means + // that if the packet payload length defined by PCNF1.STATLEN and the LENGTH field in the packet specifies a + // packet larger than MAXLEN, the payload will be truncated at MAXLEN + // + // To simplify the implementation, It is setted as the maximum value + // and the length of the packet is controlled only by the LENGTH field in the packet + w.set_maxlen(255); + // Configure the length of the address field in the packet + // The prefix after the address fields is always appended, so is always 1 byte less than the size of the address + // The base address is truncated from the least significant byte if the BALEN is less than 4 + // + // BLE address is always 4 bytes long + w.set_balen(3); // 3 bytes base address (+ 1 prefix); + // Configure the endianess + // For BLE is always little endian (LSB first) + w.set_endian(vals::Endian::LITTLE); + // Data whitening is used to avoid long sequences of zeros or + // ones, e.g., 0b0000000 or 0b1111111, in the data bit stream. + // The whitener and de-whitener are defined the same way, + // using a 7-bit linear feedback shift register with the + // polynomial x7 + x4 + 1. + // + // In BLE Whitening shall be applied on the PDU and CRC of all + // Link Layer packets and is performed after the CRC generation + // in the transmitter. No other parts of the packets are whitened. + // De-whitening is performed before the CRC checking in the receiver + // Before whitening or de-whitening, the shift register should be + // initialized based on the channel index. + w.set_whiteen(true); }); // Configure CRC - r.crccnf.write(|w| { + r.crccnf().write(|w| { // In BLE the CRC shall be calculated on the PDU of all Link Layer // packets (even if the packet is encrypted). // It skips the address field - w.skipaddr() - .skip() - // In BLE 24-bit CRC = 3 bytes - .len() - .three() + w.set_skipaddr(vals::Skipaddr::SKIP); + // In BLE 24-bit CRC = 3 bytes + w.set_len(vals::Len::THREE); }); // Ch map between 2400 MHZ .. 2500 MHz // All modes use this range - #[cfg(not(feature = "nrf51"))] - r.frequency.write(|w| w.map().default()); + #[cfg(not(feature = "_nrf51"))] + r.frequency().write(|w| w.set_map(vals::Map::DEFAULT)); // Configure shortcuts to simplify and speed up sending and receiving packets. - r.shorts.write(|w| { + r.shorts().write(|w| { // start transmission/recv immediately after ramp-up // disable radio when transmission/recv is done - w.ready_start().enabled().end_disable().enabled() + w.set_ready_start(true); + w.set_end_disable(true); }); // Enable NVIC interrupt @@ -113,11 +108,11 @@ impl<'d, T: Instance> Radio<'d, T> { assert!(self.state() == RadioState::DISABLED); let r = T::regs(); - r.mode.write(|w| w.mode().variant(mode)); + r.mode().write(|w| w.set_mode(mode)); - #[cfg(not(feature = "nrf51"))] - r.pcnf0.write(|w| { - w.plen().variant(match mode { + #[cfg(not(feature = "_nrf51"))] + r.pcnf0().write(|w| { + w.set_plen(match mode { Mode::BLE_1MBIT => PreambleLength::_8BIT, Mode::BLE_2MBIT => PreambleLength::_16BIT, #[cfg(any( @@ -147,18 +142,14 @@ impl<'d, T: Instance> Radio<'d, T> { true => 8, }; - r.pcnf0.write(|w| unsafe { - w - // Configure S0 to 1 byte length, this will represent the Data/Adv header flags - .s0len() - .set_bit() - // Configure the length (in bits) field to 1 byte length, this will represent the length of the payload - // and also be used to know how many bytes to read/write from/to the buffer - .lflen() - .bits(8) - // Configure the lengh (in bits) of bits in the S1 field. It could be used to represent the CTEInfo for data packages in BLE. - .s1len() - .bits(s1len) + r.pcnf0().write(|w| { + // Configure S0 to 1 byte length, this will represent the Data/Adv header flags + w.set_s0len(true); + // Configure the length (in bits) field to 1 byte length, this will represent the length of the payload + // and also be used to know how many bytes to read/write from/to the buffer + w.set_lflen(0); + // Configure the lengh (in bits) of bits in the S1 field. It could be used to represent the CTEInfo for data packages in BLE. + w.set_s1len(s1len); }); } @@ -172,7 +163,7 @@ impl<'d, T: Instance> Radio<'d, T> { let r = T::regs(); - r.datawhiteiv.write(|w| unsafe { w.datawhiteiv().bits(whitening_init) }); + r.datawhiteiv().write(|w| w.set_datawhiteiv(whitening_init)); } /// Set the central frequency to be used @@ -185,8 +176,7 @@ impl<'d, T: Instance> Radio<'d, T> { let r = T::regs(); - r.frequency - .write(|w| unsafe { w.frequency().bits((frequency - 2400) as u8) }); + r.frequency().write(|w| w.set_frequency((frequency - 2400) as u8)); } /// Set the acess address @@ -204,31 +194,25 @@ impl<'d, T: Instance> Radio<'d, T> { // The byte ordering on air is always least significant byte first for the address // So for the address 0xAA_BB_CC_DD, the address on air will be DD CC BB AA // The package order is BASE, PREFIX so BASE=0xBB_CC_DD and PREFIX=0xAA - r.prefix0 - .write(|w| unsafe { w.ap0().bits((access_address >> 24) as u8) }); + r.prefix0().write(|w| w.set_ap0((access_address >> 24) as u8)); // The base address is truncated from the least significant byte (because the BALEN is less than 4) // So it shifts the address to the right - r.base0.write(|w| unsafe { w.bits(access_address << 8) }); + r.base0().write_value(access_address << 8); // Don't match tx address - r.txaddress.write(|w| unsafe { w.txaddress().bits(0) }); + r.txaddress().write(|w| w.set_txaddress(0)); // Match on logical address // This config only filter the packets by the address, // so only packages send to the previous address // will finish the reception (TODO: check the explanation) - r.rxaddresses.write(|w| { - w.addr0() - .enabled() - .addr1() - .enabled() - .addr2() - .enabled() - .addr3() - .enabled() - .addr4() - .enabled() + r.rxaddresses().write(|w| { + w.set_addr0(true); + w.set_addr1(true); + w.set_addr2(true); + w.set_addr3(true); + w.set_addr4(true); }); } @@ -241,7 +225,7 @@ impl<'d, T: Instance> Radio<'d, T> { let r = T::regs(); - r.crcpoly.write(|w| unsafe { + r.crcpoly().write(|w| { // Configure the CRC polynomial // Each term in the CRC polynomial is mapped to a bit in this // register which index corresponds to the term's exponent. @@ -249,7 +233,7 @@ impl<'d, T: Instance> Radio<'d, T> { // 1, and bit number 0 of the register content is ignored by // the hardware. The following example is for an 8 bit CRC // polynomial: x8 + x7 + x3 + x2 + 1 = 1 1000 1101 . - w.crcpoly().bits(crc_poly & 0xFFFFFF) + w.set_crcpoly(crc_poly & 0xFFFFFF) }); } @@ -263,7 +247,7 @@ impl<'d, T: Instance> Radio<'d, T> { let r = T::regs(); - r.crcinit.write(|w| unsafe { w.crcinit().bits(crc_init & 0xFFFFFF) }); + r.crcinit().write(|w| w.set_crcinit(crc_init & 0xFFFFFF)); } /// Set the radio tx power @@ -274,7 +258,7 @@ impl<'d, T: Instance> Radio<'d, T> { let r = T::regs(); - r.txpower.write(|w| w.txpower().variant(tx_power)); + r.txpower().write(|w| w.set_txpower(tx_power)); } /// Set buffer to read/write @@ -294,7 +278,7 @@ impl<'d, T: Instance> Radio<'d, T> { let ptr = buffer.as_ptr(); // Configure the payload - r.packetptr.write(|w| unsafe { w.bits(ptr as u32) }); + r.packetptr().write_value(ptr as u32); Ok(()) } @@ -310,7 +294,7 @@ impl<'d, T: Instance> Radio<'d, T> { // Initialize the transmission // trace!("txen"); - r.tasks_txen.write(|w| unsafe { w.bits(1) }); + r.tasks_txen().write_value(1); }) .await; @@ -327,7 +311,7 @@ impl<'d, T: Instance> Radio<'d, T> { self.trigger_and_wait_end(move || { // Initialize the transmission // trace!("rxen"); - r.tasks_rxen.write(|w| unsafe { w.bits(1) }); + r.tasks_rxen().write_value(1); }) .await; @@ -344,21 +328,21 @@ impl<'d, T: Instance> Radio<'d, T> { let drop = OnDrop::new(|| { trace!("radio drop: stopping"); - r.intenclr.write(|w| w.end().clear()); + r.intenclr().write(|w| w.set_end(true)); - r.tasks_stop.write(|w| unsafe { w.bits(1) }); + r.tasks_stop().write_value(1); - r.events_end.reset(); + r.events_end().write_value(0); trace!("radio drop: stopped"); }); // trace!("radio:enable interrupt"); // Clear some remnant side-effects (TODO: check if this is necessary) - r.events_end.reset(); + r.events_end().write_value(0); // Enable interrupt - r.intenset.write(|w| w.end().set()); + r.intenset().write(|w| w.set_end(true)); compiler_fence(Ordering::SeqCst); @@ -368,7 +352,7 @@ impl<'d, T: Instance> Radio<'d, T> { // On poll check if interrupt happen poll_fn(|cx| { s.event_waker.register(cx.waker()); - if r.events_end.read().bits() == 1 { + if r.events_end().read() == 1 { // trace!("radio:end"); return core::task::Poll::Ready(()); } @@ -377,7 +361,7 @@ impl<'d, T: Instance> Radio<'d, T> { .await; compiler_fence(Ordering::SeqCst); - r.events_end.reset(); // ACK + r.events_end().write_value(0); // ACK // Everthing ends fine, so it disable the drop drop.defuse(); @@ -392,15 +376,15 @@ impl<'d, T: Instance> Radio<'d, T> { if self.state() != RadioState::DISABLED { trace!("radio:disable"); // Trigger the disable task - r.tasks_disable.write(|w| unsafe { w.bits(1) }); + r.tasks_disable().write_value(1); // Wait until the radio is disabled - while r.events_disabled.read().bits() == 0 {} + while r.events_disabled().read() == 0 {} compiler_fence(Ordering::SeqCst); // Acknowledge it - r.events_disabled.reset(); + r.events_disabled().write_value(0); } } } diff --git a/embassy-nrf/src/radio/ieee802154.rs b/embassy-nrf/src/radio/ieee802154.rs index 298f8a574..083842f4a 100644 --- a/embassy-nrf/src/radio/ieee802154.rs +++ b/embassy-nrf/src/radio/ieee802154.rs @@ -9,6 +9,7 @@ use embassy_hal_internal::{into_ref, PeripheralRef}; use super::{state, Error, Instance, InterruptHandler, RadioState, TxPower}; use crate::interrupt::typelevel::Interrupt; use crate::interrupt::{self}; +use crate::pac::radio::vals; use crate::Peripheral; /// Default (IEEE compliant) Start of Frame Delimiter @@ -47,58 +48,47 @@ impl<'d, T: Instance> Radio<'d, T> { let r = T::regs(); // Disable and enable to reset peripheral - r.power.write(|w| w.power().disabled()); - r.power.write(|w| w.power().enabled()); + r.power().write(|w| w.set_power(false)); + r.power().write(|w| w.set_power(true)); // Enable 802.15.4 mode - r.mode.write(|w| w.mode().ieee802154_250kbit()); + r.mode().write(|w| w.set_mode(vals::Mode::IEEE802154_250KBIT)); // Configure CRC skip address - r.crccnf.write(|w| w.len().two().skipaddr().ieee802154()); - unsafe { - // Configure CRC polynomial and init - r.crcpoly.write(|w| w.crcpoly().bits(0x0001_1021)); - r.crcinit.write(|w| w.crcinit().bits(0)); - r.pcnf0.write(|w| { - // 8-bit on air length - w.lflen() - .bits(8) - // Zero bytes S0 field length - .s0len() - .clear_bit() - // Zero bytes S1 field length - .s1len() - .bits(0) - // Do not include S1 field in RAM if S1 length > 0 - .s1incl() - .clear_bit() - // Zero code Indicator length - .cilen() - .bits(0) - // 32-bit zero preamble - .plen() - ._32bit_zero() - // Include CRC in length - .crcinc() - .include() - }); - r.pcnf1.write(|w| { - // Maximum packet length - w.maxlen() - .bits(Packet::MAX_PSDU_LEN) - // Zero static length - .statlen() - .bits(0) - // Zero base address length - .balen() - .bits(0) - // Little-endian - .endian() - .clear_bit() - // Disable packet whitening - .whiteen() - .clear_bit() - }); - } + r.crccnf().write(|w| { + w.set_len(vals::Len::TWO); + w.set_skipaddr(vals::Skipaddr::IEEE802154); + }); + // Configure CRC polynomial and init + r.crcpoly().write(|w| w.set_crcpoly(0x0001_1021)); + r.crcinit().write(|w| w.set_crcinit(0)); + r.pcnf0().write(|w| { + // 8-bit on air length + w.set_lflen(8); + // Zero bytes S0 field length + w.set_s0len(false); + // Zero bytes S1 field length + w.set_s1len(0); + // Do not include S1 field in RAM if S1 length > 0 + w.set_s1incl(vals::S1incl::AUTOMATIC); + // Zero code Indicator length + w.set_cilen(0); + // 32-bit zero preamble + w.set_plen(vals::Plen::_32BIT_ZERO); + // Include CRC in length + w.set_crcinc(vals::Crcinc::INCLUDE); + }); + r.pcnf1().write(|w| { + // Maximum packet length + w.set_maxlen(Packet::MAX_PSDU_LEN); + // Zero static length + w.set_statlen(0); + // Zero base address length + w.set_balen(0); + // Little-endian + w.set_endian(vals::Endian::LITTLE); + // Disable packet whitening + w.set_whiteen(false); + }); // Enable NVIC interrupt T::Interrupt::unpend(); @@ -125,8 +115,10 @@ impl<'d, T: Instance> Radio<'d, T> { } let frequency_offset = (channel - 10) * 5; self.needs_enable = true; - r.frequency - .write(|w| unsafe { w.frequency().bits(frequency_offset).map().default() }); + r.frequency().write(|w| { + w.set_frequency(frequency_offset); + w.set_map(vals::Map::DEFAULT); + }); } /// Changes the Clear Channel Assessment method @@ -134,12 +126,14 @@ impl<'d, T: Instance> Radio<'d, T> { let r = T::regs(); self.needs_enable = true; match cca { - Cca::CarrierSense => r.ccactrl.write(|w| w.ccamode().carrier_mode()), + Cca::CarrierSense => r.ccactrl().write(|w| w.set_ccamode(vals::Ccamode::CARRIER_MODE)), Cca::EnergyDetection { ed_threshold } => { // "[ED] is enabled by first configuring the field CCAMODE=EdMode in CCACTRL // and writing the CCAEDTHRES field to a chosen value." - r.ccactrl - .write(|w| unsafe { w.ccamode().ed_mode().ccaedthres().bits(ed_threshold) }); + r.ccactrl().write(|w| { + w.set_ccamode(vals::Ccamode::ED_MODE); + w.set_ccaedthres(ed_threshold); + }); } } } @@ -147,13 +141,13 @@ impl<'d, T: Instance> Radio<'d, T> { /// Changes the Start of Frame Delimiter (SFD) pub fn set_sfd(&mut self, sfd: u8) { let r = T::regs(); - r.sfd.write(|w| unsafe { w.sfd().bits(sfd) }); + r.sfd().write(|w| w.set_sfd(sfd)); } /// Clear interrupts pub fn clear_all_interrupts(&mut self) { let r = T::regs(); - r.intenclr.write(|w| unsafe { w.bits(0xffff_ffff) }); + r.intenclr().write(|w| w.0 = 0xffff_ffff); } /// Changes the radio transmission power @@ -163,43 +157,43 @@ impl<'d, T: Instance> Radio<'d, T> { let tx_power: TxPower = match power { #[cfg(not(any(feature = "nrf52811", feature = "_nrf5340-net")))] - 8 => TxPower::POS8D_BM, + 8 => TxPower::POS8_DBM, #[cfg(not(any(feature = "nrf52811", feature = "_nrf5340-net")))] - 7 => TxPower::POS7D_BM, + 7 => TxPower::POS7_DBM, #[cfg(not(any(feature = "nrf52811", feature = "_nrf5340-net")))] - 6 => TxPower::POS6D_BM, + 6 => TxPower::POS6_DBM, #[cfg(not(any(feature = "nrf52811", feature = "_nrf5340-net")))] - 5 => TxPower::POS5D_BM, + 5 => TxPower::POS5_DBM, #[cfg(not(feature = "_nrf5340-net"))] - 4 => TxPower::POS4D_BM, + 4 => TxPower::POS4_DBM, #[cfg(not(feature = "_nrf5340-net"))] - 3 => TxPower::POS3D_BM, + 3 => TxPower::POS3_DBM, #[cfg(not(any(feature = "nrf52811", feature = "_nrf5340-net")))] - 2 => TxPower::POS2D_BM, - 0 => TxPower::_0D_BM, + 2 => TxPower::POS2_DBM, + 0 => TxPower::_0_DBM, #[cfg(feature = "_nrf5340-net")] - -1 => TxPower::NEG1D_BM, + -1 => TxPower::NEG1_DBM, #[cfg(feature = "_nrf5340-net")] - -2 => TxPower::NEG2D_BM, + -2 => TxPower::NEG2_DBM, #[cfg(feature = "_nrf5340-net")] - -3 => TxPower::NEG3D_BM, - -4 => TxPower::NEG4D_BM, + -3 => TxPower::NEG3_DBM, + -4 => TxPower::NEG4_DBM, #[cfg(feature = "_nrf5340-net")] - -5 => TxPower::NEG5D_BM, + -5 => TxPower::NEG5_DBM, #[cfg(feature = "_nrf5340-net")] - -6 => TxPower::NEG6D_BM, + -6 => TxPower::NEG6_DBM, #[cfg(feature = "_nrf5340-net")] - -7 => TxPower::NEG7D_BM, - -8 => TxPower::NEG8D_BM, - -12 => TxPower::NEG12D_BM, - -16 => TxPower::NEG16D_BM, - -20 => TxPower::NEG20D_BM, - -30 => TxPower::NEG30D_BM, - -40 => TxPower::NEG40D_BM, + -7 => TxPower::NEG7_DBM, + -8 => TxPower::NEG8_DBM, + -12 => TxPower::NEG12_DBM, + -16 => TxPower::NEG16_DBM, + -20 => TxPower::NEG20_DBM, + -30 => TxPower::NEG30_DBM, + -40 => TxPower::NEG40_DBM, _ => panic!("Invalid transmission power value"), }; - r.txpower.write(|w| w.txpower().variant(tx_power)); + r.txpower().write(|w| w.set_txpower(tx_power)); } /// Waits until the radio state matches the given `state` @@ -221,7 +215,7 @@ impl<'d, T: Instance> Radio<'d, T> { RadioState::DISABLED => return, // idle or ramping up RadioState::RX_RU | RadioState::RX_IDLE | RadioState::TX_RU | RadioState::TX_IDLE => { - r.tasks_disable.write(|w| w.tasks_disable().set_bit()); + r.tasks_disable().write_value(1); self.wait_for_radio_state(RadioState::DISABLED); return; } @@ -232,29 +226,30 @@ impl<'d, T: Instance> Radio<'d, T> { } // cancel ongoing transfer or ongoing CCA RadioState::RX => { - r.tasks_ccastop.write(|w| w.tasks_ccastop().set_bit()); - r.tasks_stop.write(|w| w.tasks_stop().set_bit()); + r.tasks_ccastop().write_value(1); + r.tasks_stop().write_value(1); self.wait_for_radio_state(RadioState::RX_IDLE); } RadioState::TX => { - r.tasks_stop.write(|w| w.tasks_stop().set_bit()); + r.tasks_stop().write_value(1); self.wait_for_radio_state(RadioState::TX_IDLE); } + _ => unreachable!(), } } } fn set_buffer(&mut self, buffer: &[u8]) { let r = T::regs(); - r.packetptr.write(|w| unsafe { w.bits(buffer.as_ptr() as u32) }); + r.packetptr().write_value(buffer.as_ptr() as u32); } /// Moves the radio to the RXIDLE state fn receive_prepare(&mut self) { // clear related events - T::regs().events_ccabusy.reset(); - T::regs().events_phyend.reset(); - // NOTE to avoid errata 204 (see rev1 v1.4) we do TX_IDLE -> DISABLED -> RX_IDLE + T::regs().events_ccabusy().write_value(0); + T::regs().events_phyend().write_value(0); + // NOTE to avoid errata 204 (see rev1 v1.4) we do TX_IDLE -> DISABLED -> RXIDLE let disable = match self.state() { RadioState::DISABLED => false, RadioState::RX_IDLE => self.needs_enable, @@ -279,7 +274,7 @@ impl<'d, T: Instance> Radio<'d, T> { // The radio goes through following states when receiving a 802.15.4 packet // // enable RX → ramp up RX → RX idle → Receive → end (PHYEND) - r.shorts.write(|w| w.rxready_start().enabled()); + r.shorts().write(|w| w.set_rxready_start(true)); // set up RX buffer self.set_buffer(packet.buffer.as_mut()); @@ -289,17 +284,17 @@ impl<'d, T: Instance> Radio<'d, T> { match self.state() { // Re-start receiver - RadioState::RX_IDLE => r.tasks_start.write(|w| w.tasks_start().set_bit()), + RadioState::RX_IDLE => r.tasks_start().write_value(1), // Enable receiver - _ => r.tasks_rxen.write(|w| w.tasks_rxen().set_bit()), + _ => r.tasks_rxen().write_value(1), } } /// Cancel receiving packet fn receive_cancel() { let r = T::regs(); - r.shorts.reset(); - r.tasks_stop.write(|w| w.tasks_stop().set_bit()); + r.shorts().write(|_| {}); + r.tasks_stop().write_value(1); loop { match state(r) { RadioState::DISABLED | RadioState::RX_IDLE => break, @@ -329,12 +324,12 @@ impl<'d, T: Instance> Radio<'d, T> { core::future::poll_fn(|cx| { s.event_waker.register(cx.waker()); - if r.events_phyend.read().events_phyend().bit_is_set() { - r.events_phyend.reset(); + if r.events_phyend().read() != 0 { + r.events_phyend().write_value(0); trace!("RX done poll"); return Poll::Ready(()); } else { - r.intenset.write(|w| w.phyend().set()); + r.intenset().write(|w| w.set_phyend(true)); }; Poll::Pending @@ -344,8 +339,8 @@ impl<'d, T: Instance> Radio<'d, T> { dma_end_fence(); dropper.defuse(); - let crc = r.rxcrc.read().rxcrc().bits() as u16; - if r.crcstatus.read().crcstatus().bit_is_set() { + let crc = r.rxcrc().read().rxcrc() as u16; + if r.crcstatus().read().crcstatus() == vals::Crcstatus::CRCOK { Ok(()) } else { Err(Error::CrcFailed(crc)) @@ -387,17 +382,12 @@ impl<'d, T: Instance> Radio<'d, T> { // CCA idle → enable TX → start TX → TX → end (PHYEND) → disabled // // CCA might end up in the event CCABUSY in which there will be no transmission - r.shorts.write(|w| { - w.rxready_ccastart() - .enabled() - .ccaidle_txen() - .enabled() - .txready_start() - .enabled() - .ccabusy_disable() - .enabled() - .phyend_disable() - .enabled() + r.shorts().write(|w| { + w.set_rxready_ccastart(true); + w.set_ccaidle_txen(true); + w.set_txready_start(true); + w.set_ccabusy_disable(true); + w.set_phyend_disable(true); }); // Set transmission buffer @@ -410,27 +400,30 @@ impl<'d, T: Instance> Radio<'d, T> { match self.state() { // Re-start receiver - RadioState::RX_IDLE => r.tasks_ccastart.write(|w| w.tasks_ccastart().set_bit()), + RadioState::RX_IDLE => r.tasks_ccastart().write_value(1), // Enable receiver - _ => r.tasks_rxen.write(|w| w.tasks_rxen().set_bit()), + _ => r.tasks_rxen().write_value(1), } self.clear_all_interrupts(); let result = core::future::poll_fn(|cx| { s.event_waker.register(cx.waker()); - if r.events_phyend.read().events_phyend().bit_is_set() { - r.events_phyend.reset(); - r.events_ccabusy.reset(); + if r.events_phyend().read() != 0 { + r.events_phyend().write_value(0); + r.events_ccabusy().write_value(0); trace!("TX done poll"); return Poll::Ready(TransmitResult::Success); - } else if r.events_ccabusy.read().events_ccabusy().bit_is_set() { - r.events_ccabusy.reset(); + } else if r.events_ccabusy().read() != 0 { + r.events_ccabusy().write_value(0); trace!("TX no CCA"); return Poll::Ready(TransmitResult::ChannelInUse); } - r.intenset.write(|w| w.phyend().set().ccabusy().set()); + r.intenset().write(|w| { + w.set_phyend(true); + w.set_ccabusy(true); + }); Poll::Pending }) diff --git a/embassy-nrf/src/radio/mod.rs b/embassy-nrf/src/radio/mod.rs index 8edca1df2..251f37d3d 100644 --- a/embassy-nrf/src/radio/mod.rs +++ b/embassy-nrf/src/radio/mod.rs @@ -20,8 +20,8 @@ pub mod ieee802154; use core::marker::PhantomData; use embassy_sync::waitqueue::AtomicWaker; -use pac::radio::state::STATE_A as RadioState; -pub use pac::radio::txpower::TXPOWER_A as TxPower; +use pac::radio::vals::State as RadioState; +pub use pac::radio::vals::Txpower as TxPower; use crate::{interrupt, pac, Peripheral}; @@ -52,7 +52,7 @@ impl interrupt::typelevel::Handler for InterruptHandl let r = T::regs(); let s = T::state(); // clear all interrupts - r.intenclr.write(|w| w.bits(0xffff_ffff)); + r.intenclr().write(|w| w.0 = 0xffff_ffff); s.event_waker.wake(); } } @@ -70,15 +70,15 @@ impl State { } pub(crate) trait SealedInstance { - fn regs() -> &'static crate::pac::radio::RegisterBlock; + fn regs() -> crate::pac::radio::Radio; fn state() -> &'static State; } macro_rules! impl_radio { ($type:ident, $pac_type:ident, $irq:ident) => { impl crate::radio::SealedInstance for peripherals::$type { - fn regs() -> &'static pac::radio::RegisterBlock { - unsafe { &*pac::$pac_type::ptr() } + fn regs() -> crate::pac::radio::Radio { + pac::$pac_type } fn state() -> &'static crate::radio::State { @@ -100,9 +100,6 @@ pub trait Instance: Peripheral

+ SealedInstance + 'static + Send { } /// Get the state of the radio -pub(crate) fn state(radio: &pac::radio::RegisterBlock) -> RadioState { - match radio.state.read().state().variant() { - Some(state) => state, - None => unreachable!(), - } +pub(crate) fn state(radio: pac::radio::Radio) -> RadioState { + radio.state().read().state() } diff --git a/embassy-nrf/src/rng.rs b/embassy-nrf/src/rng.rs index ff61e08f3..7a98ab2fb 100644 --- a/embassy-nrf/src/rng.rs +++ b/embassy-nrf/src/rng.rs @@ -14,7 +14,7 @@ use embassy_hal_internal::{into_ref, PeripheralRef}; use embassy_sync::waitqueue::WakerRegistration; use crate::interrupt::typelevel::Interrupt; -use crate::{interrupt, Peripheral}; +use crate::{interrupt, pac, Peripheral}; /// Interrupt handler. pub struct InterruptHandler { @@ -26,7 +26,7 @@ impl interrupt::typelevel::Handler for InterruptHandl let r = T::regs(); // Clear the event. - r.events_valrdy.reset(); + r.events_valrdy().write_value(0); // Mutate the slice within a critical section, // so that the future isn't dropped in between us loading the pointer and actually dereferencing it. @@ -40,7 +40,7 @@ impl interrupt::typelevel::Handler for InterruptHandl // The safety contract of `Rng::new` means that the future can't have been dropped // without calling its destructor. unsafe { - *state.ptr = r.value.read().value().bits(); + *state.ptr = r.value().read().value(); state.ptr = state.ptr.add(1); } @@ -84,19 +84,19 @@ impl<'d, T: Instance> Rng<'d, T> { } fn stop(&self) { - T::regs().tasks_stop.write(|w| unsafe { w.bits(1) }) + T::regs().tasks_stop().write_value(1) } fn start(&self) { - T::regs().tasks_start.write(|w| unsafe { w.bits(1) }) + T::regs().tasks_start().write_value(1) } fn enable_irq(&self) { - T::regs().intenset.write(|w| w.valrdy().set()); + T::regs().intenset().write(|w| w.set_valrdy(true)); } fn disable_irq(&self) { - T::regs().intenclr.write(|w| w.valrdy().clear()); + T::regs().intenclr().write(|w| w.set_valrdy(true)); } /// Enable or disable the RNG's bias correction. @@ -106,7 +106,7 @@ impl<'d, T: Instance> Rng<'d, T> { /// /// Defaults to disabled. pub fn set_bias_correction(&self, enable: bool) { - T::regs().config.write(|w| w.dercen().bit(enable)) + T::regs().config().write(|w| w.set_dercen(enable)) } /// Fill the buffer with random bytes. @@ -162,9 +162,9 @@ impl<'d, T: Instance> Rng<'d, T> { for byte in dest.iter_mut() { let regs = T::regs(); - while regs.events_valrdy.read().bits() == 0 {} - regs.events_valrdy.reset(); - *byte = regs.value.read().value().bits(); + while regs.events_valrdy().read() == 0 {} + regs.events_valrdy().write_value(0); + *byte = regs.value().read().value(); } self.stop(); @@ -244,7 +244,7 @@ impl InnerState { } pub(crate) trait SealedInstance { - fn regs() -> &'static crate::pac::rng::RegisterBlock; + fn regs() -> pac::rng::Rng; fn state() -> &'static State; } @@ -258,8 +258,8 @@ pub trait Instance: Peripheral

+ SealedInstance + 'static + Send { macro_rules! impl_rng { ($type:ident, $pac_type:ident, $irq:ident) => { impl crate::rng::SealedInstance for peripherals::$type { - fn regs() -> &'static crate::pac::rng::RegisterBlock { - unsafe { &*pac::$pac_type::ptr() } + fn regs() -> crate::pac::rng::Rng { + pac::$pac_type } fn state() -> &'static crate::rng::State { static STATE: crate::rng::State = crate::rng::State::new(); diff --git a/embassy-nrf/src/saadc.rs b/embassy-nrf/src/saadc.rs index bbfa9b3b9..70bda9f70 100644 --- a/embassy-nrf/src/saadc.rs +++ b/embassy-nrf/src/saadc.rs @@ -9,14 +9,10 @@ use core::task::Poll; use embassy_hal_internal::drop::OnDrop; use embassy_hal_internal::{impl_peripheral, into_ref, PeripheralRef}; use embassy_sync::waitqueue::AtomicWaker; -use pac::{saadc, SAADC}; -use saadc::ch::config::{GAIN_A, REFSEL_A, RESP_A, TACQ_A}; -// We treat the positive and negative channels with the same enum values to keep our type tidy and given they are the same -pub(crate) use saadc::ch::pselp::PSELP_A as InputChannel; -use saadc::oversample::OVERSAMPLE_A; -use saadc::resolution::VAL_A; +pub(crate) use vals::Psel as InputChannel; use crate::interrupt::InterruptExt; +use crate::pac::saadc::vals; use crate::ppi::{ConfigurableChannel, Event, Ppi, Task}; use crate::timer::{Frequency, Instance as TimerInstance, Timer}; use crate::{interrupt, pac, peripherals, Peripheral}; @@ -34,20 +30,20 @@ pub struct InterruptHandler { impl interrupt::typelevel::Handler for InterruptHandler { unsafe fn on_interrupt() { - let r = unsafe { &*SAADC::ptr() }; + let r = pac::SAADC; - if r.events_calibratedone.read().bits() != 0 { - r.intenclr.write(|w| w.calibratedone().clear()); + if r.events_calibratedone().read() != 0 { + r.intenclr().write(|w| w.set_calibratedone(true)); WAKER.wake(); } - if r.events_end.read().bits() != 0 { - r.intenclr.write(|w| w.end().clear()); + if r.events_end().read() != 0 { + r.intenclr().write(|w| w.set_end(true)); WAKER.wake(); } - if r.events_started.read().bits() != 0 { - r.intenclr.write(|w| w.started().clear()); + if r.events_started().read() != 0 { + r.intenclr().write(|w| w.set_started(true)); WAKER.wake(); } } @@ -150,44 +146,36 @@ impl<'d, const N: usize> Saadc<'d, N> { ) -> Self { into_ref!(saadc); - let r = unsafe { &*SAADC::ptr() }; + let r = pac::SAADC; let Config { resolution, oversample } = config; // Configure channels - r.enable.write(|w| w.enable().enabled()); - r.resolution.write(|w| w.val().variant(resolution.into())); - r.oversample.write(|w| w.oversample().variant(oversample.into())); + r.enable().write(|w| w.set_enable(true)); + r.resolution().write(|w| w.set_val(resolution.into())); + r.oversample().write(|w| w.set_oversample(oversample.into())); for (i, cc) in channel_configs.iter().enumerate() { - r.ch[i].pselp.write(|w| w.pselp().variant(cc.p_channel.channel())); + r.ch(i).pselp().write(|w| w.set_pselp(cc.p_channel.channel())); if let Some(n_channel) = &cc.n_channel { - r.ch[i] - .pseln - .write(|w| unsafe { w.pseln().bits(n_channel.channel() as u8) }); + r.ch(i).pseln().write(|w| w.set_pseln(n_channel.channel())); } - r.ch[i].config.write(|w| { - w.refsel().variant(cc.reference.into()); - w.gain().variant(cc.gain.into()); - w.tacq().variant(cc.time.into()); - if cc.n_channel.is_none() { - w.mode().se(); - } else { - w.mode().diff(); - } - w.resp().variant(cc.resistor.into()); - w.resn().bypass(); - if !matches!(oversample, Oversample::BYPASS) { - w.burst().enabled(); - } else { - w.burst().disabled(); - } - w + r.ch(i).config().write(|w| { + w.set_refsel(cc.reference.into()); + w.set_gain(cc.gain.into()); + w.set_tacq(cc.time.into()); + w.set_mode(match cc.n_channel { + None => vals::ConfigMode::SE, + Some(_) => vals::ConfigMode::DIFF, + }); + w.set_resp(cc.resistor.into()); + w.set_resn(vals::Resn::BYPASS); + w.set_burst(!matches!(oversample, Oversample::BYPASS)); }); } // Disable all events interrupts - r.intenclr.write(|w| unsafe { w.bits(0x003F_FFFF) }); + r.intenclr().write(|w| w.0 = 0x003F_FFFF); interrupt::SAADC.unpend(); unsafe { interrupt::SAADC.enable() }; @@ -195,8 +183,8 @@ impl<'d, const N: usize> Saadc<'d, N> { Self { _p: saadc } } - fn regs() -> &'static saadc::RegisterBlock { - unsafe { &*SAADC::ptr() } + fn regs() -> pac::saadc::Saadc { + pac::SAADC } /// Perform SAADC calibration. Completes when done. @@ -204,13 +192,13 @@ impl<'d, const N: usize> Saadc<'d, N> { let r = Self::regs(); // Reset and enable the end event - r.events_calibratedone.reset(); - r.intenset.write(|w| w.calibratedone().set()); + r.events_calibratedone().write_value(0); + r.intenset().write(|w| w.set_calibratedone(true)); // Order is important compiler_fence(Ordering::SeqCst); - r.tasks_calibrateoffset.write(|w| unsafe { w.bits(1) }); + r.tasks_calibrateoffset().write_value(1); // Wait for 'calibratedone' event. poll_fn(|cx| { @@ -218,8 +206,8 @@ impl<'d, const N: usize> Saadc<'d, N> { WAKER.register(cx.waker()); - if r.events_calibratedone.read().bits() != 0 { - r.events_calibratedone.reset(); + if r.events_calibratedone().read() != 0 { + r.events_calibratedone().write_value(0); return Poll::Ready(()); } @@ -239,19 +227,19 @@ impl<'d, const N: usize> Saadc<'d, N> { let r = Self::regs(); // Set up the DMA - r.result.ptr.write(|w| unsafe { w.ptr().bits(buf.as_mut_ptr() as u32) }); - r.result.maxcnt.write(|w| unsafe { w.maxcnt().bits(N as _) }); + r.result().ptr().write_value(buf.as_mut_ptr() as u32); + r.result().maxcnt().write(|w| w.set_maxcnt(N as _)); // Reset and enable the end event - r.events_end.reset(); - r.intenset.write(|w| w.end().set()); + r.events_end().write_value(0); + r.intenset().write(|w| w.set_end(true)); // Don't reorder the ADC start event before the previous writes. Hopefully self // wouldn't happen anyway. compiler_fence(Ordering::SeqCst); - r.tasks_start.write(|w| unsafe { w.bits(1) }); - r.tasks_sample.write(|w| unsafe { w.bits(1) }); + r.tasks_start().write_value(1); + r.tasks_sample().write_value(1); // Wait for 'end' event. poll_fn(|cx| { @@ -259,8 +247,8 @@ impl<'d, const N: usize> Saadc<'d, N> { WAKER.register(cx.waker()); - if r.events_end.read().bits() != 0 { - r.events_end.reset(); + if r.events_end().read() != 0 { + r.events_end().write_value(0); return Poll::Ready(()); } @@ -311,8 +299,11 @@ impl<'d, const N: usize> Saadc<'d, N> { // We want the task start to effectively short with the last one ending so // we don't miss any samples. It'd be great for the SAADC to offer a SHORTS // register instead, but it doesn't, so we must use PPI. - let mut start_ppi = - Ppi::new_one_to_one(ppi_ch1, Event::from_reg(&r.events_end), Task::from_reg(&r.tasks_start)); + let mut start_ppi = Ppi::new_one_to_one( + ppi_ch1, + Event::from_reg(r.events_end()), + Task::from_reg(r.tasks_start()), + ); start_ppi.enable(); let timer = Timer::new(timer); @@ -322,7 +313,7 @@ impl<'d, const N: usize> Saadc<'d, N> { let timer_cc = timer.cc(0); - let mut sample_ppi = Ppi::new_one_to_one(ppi_ch2, timer_cc.event_compare(), Task::from_reg(&r.tasks_sample)); + let mut sample_ppi = Ppi::new_one_to_one(ppi_ch2, timer_cc.event_compare(), Task::from_reg(r.tasks_sample())); timer.start(); @@ -355,43 +346,37 @@ impl<'d, const N: usize> Saadc<'d, N> { // Establish mode and sample rate match sample_rate_divisor { Some(sr) => { - r.samplerate.write(|w| unsafe { - w.cc().bits(sr); - w.mode().timers(); - w + r.samplerate().write(|w| { + w.set_cc(sr); + w.set_mode(vals::SamplerateMode::TIMERS); }); - r.tasks_sample.write(|w| unsafe { w.bits(1) }); // Need to kick-start the internal timer + r.tasks_sample().write_value(1); // Need to kick-start the internal timer } - None => r.samplerate.write(|w| unsafe { - w.cc().bits(0); - w.mode().task(); - w + None => r.samplerate().write(|w| { + w.set_cc(0); + w.set_mode(vals::SamplerateMode::TASK); }), } // Set up the initial DMA - r.result - .ptr - .write(|w| unsafe { w.ptr().bits(bufs[0].as_mut_ptr() as u32) }); - r.result.maxcnt.write(|w| unsafe { w.maxcnt().bits((N0 * N) as _) }); + r.result().ptr().write_value(bufs[0].as_mut_ptr() as u32); + r.result().maxcnt().write(|w| w.set_maxcnt((N0 * N) as _)); // Reset and enable the events - r.events_end.reset(); - r.events_started.reset(); - r.intenset.write(|w| { - w.end().set(); - w.started().set(); - w + r.events_end().write_value(0); + r.events_started().write_value(0); + r.intenset().write(|w| { + w.set_end(true); + w.set_started(true); }); // Don't reorder the ADC start event before the previous writes. Hopefully self // wouldn't happen anyway. compiler_fence(Ordering::SeqCst); - r.tasks_start.write(|w| unsafe { w.bits(1) }); + r.tasks_start().write_value(1); let mut inited = false; - let mut current_buffer = 0; // Wait for events and complete when the sampler indicates it has had enough. @@ -400,11 +385,11 @@ impl<'d, const N: usize> Saadc<'d, N> { WAKER.register(cx.waker()); - if r.events_end.read().bits() != 0 { + if r.events_end().read() != 0 { compiler_fence(Ordering::SeqCst); - r.events_end.reset(); - r.intenset.write(|w| w.end().set()); + r.events_end().write_value(0); + r.intenset().write(|w| w.set_end(true)); match callback(&bufs[current_buffer]) { CallbackResult::Continue => { @@ -417,9 +402,9 @@ impl<'d, const N: usize> Saadc<'d, N> { } } - if r.events_started.read().bits() != 0 { - r.events_started.reset(); - r.intenset.write(|w| w.started().set()); + if r.events_started().read() != 0 { + r.events_started().write_value(0); + r.intenset().write(|w| w.set_started(true)); if !inited { init(); @@ -427,9 +412,7 @@ impl<'d, const N: usize> Saadc<'d, N> { } let next_buffer = 1 - current_buffer; - r.result - .ptr - .write(|w| unsafe { w.ptr().bits(bufs[next_buffer].as_mut_ptr() as u32) }); + r.result().ptr().write_value(bufs[next_buffer].as_mut_ptr() as u32); } Poll::Pending @@ -447,11 +430,11 @@ impl<'d, const N: usize> Saadc<'d, N> { compiler_fence(Ordering::SeqCst); - r.events_stopped.reset(); - r.tasks_stop.write(|w| unsafe { w.bits(1) }); + r.events_stopped().write_value(0); + r.tasks_stop().write_value(1); - while r.events_stopped.read().bits() == 0 {} - r.events_stopped.reset(); + while r.events_stopped().read() == 0 {} + r.events_stopped().write_value(0); } } @@ -481,21 +464,21 @@ impl<'d> Saadc<'d, 1> { impl<'d, const N: usize> Drop for Saadc<'d, N> { fn drop(&mut self) { let r = Self::regs(); - r.enable.write(|w| w.enable().disabled()); + r.enable().write(|w| w.set_enable(false)); } } -impl From for GAIN_A { +impl From for vals::Gain { fn from(gain: Gain) -> Self { match gain { - Gain::GAIN1_6 => GAIN_A::GAIN1_6, - Gain::GAIN1_5 => GAIN_A::GAIN1_5, - Gain::GAIN1_4 => GAIN_A::GAIN1_4, - Gain::GAIN1_3 => GAIN_A::GAIN1_3, - Gain::GAIN1_2 => GAIN_A::GAIN1_2, - Gain::GAIN1 => GAIN_A::GAIN1, - Gain::GAIN2 => GAIN_A::GAIN2, - Gain::GAIN4 => GAIN_A::GAIN4, + Gain::GAIN1_6 => vals::Gain::GAIN1_6, + Gain::GAIN1_5 => vals::Gain::GAIN1_5, + Gain::GAIN1_4 => vals::Gain::GAIN1_4, + Gain::GAIN1_3 => vals::Gain::GAIN1_3, + Gain::GAIN1_2 => vals::Gain::GAIN1_2, + Gain::GAIN1 => vals::Gain::GAIN1, + Gain::GAIN2 => vals::Gain::GAIN2, + Gain::GAIN4 => vals::Gain::GAIN4, } } } @@ -522,11 +505,11 @@ pub enum Gain { GAIN4 = 7, } -impl From for REFSEL_A { +impl From for vals::Refsel { fn from(reference: Reference) -> Self { match reference { - Reference::INTERNAL => REFSEL_A::INTERNAL, - Reference::VDD1_4 => REFSEL_A::VDD1_4, + Reference::INTERNAL => vals::Refsel::INTERNAL, + Reference::VDD1_4 => vals::Refsel::VDD1_4, } } } @@ -541,13 +524,13 @@ pub enum Reference { VDD1_4 = 1, } -impl From for RESP_A { +impl From for vals::Resp { fn from(resistor: Resistor) -> Self { match resistor { - Resistor::BYPASS => RESP_A::BYPASS, - Resistor::PULLDOWN => RESP_A::PULLDOWN, - Resistor::PULLUP => RESP_A::PULLUP, - Resistor::VDD1_2 => RESP_A::VDD1_2, + Resistor::BYPASS => vals::Resp::BYPASS, + Resistor::PULLDOWN => vals::Resp::PULLDOWN, + Resistor::PULLUP => vals::Resp::PULLUP, + Resistor::VDD1_2 => vals::Resp::VDD1_2, } } } @@ -566,15 +549,15 @@ pub enum Resistor { VDD1_2 = 3, } -impl From

+ SealedInstance + 'static { macro_rules! impl_spim { ($type:ident, $pac_type:ident, $irq:ident) => { impl crate::spim::SealedInstance for peripherals::$type { - fn regs() -> &'static pac::spim0::RegisterBlock { - unsafe { &*pac::$pac_type::ptr() } + fn regs() -> pac::spim::Spim { + pac::$pac_type } fn state() -> &'static crate::spim::State { static STATE: crate::spim::State = crate::spim::State::new(); @@ -621,40 +618,35 @@ impl<'d, T: Instance> SetConfig for Spim<'d, T> { let r = T::regs(); // Configure mode. let mode = config.mode; - r.config.write(|w| { + r.config().write(|w| { + w.set_order(config.bit_order); match mode { MODE_0 => { - w.order().variant(config.bit_order); - w.cpol().active_high(); - w.cpha().leading(); + w.set_cpol(vals::Cpol::ACTIVE_HIGH); + w.set_cpha(vals::Cpha::LEADING); } MODE_1 => { - w.order().variant(config.bit_order); - w.cpol().active_high(); - w.cpha().trailing(); + w.set_cpol(vals::Cpol::ACTIVE_HIGH); + w.set_cpha(vals::Cpha::TRAILING); } MODE_2 => { - w.order().variant(config.bit_order); - w.cpol().active_low(); - w.cpha().leading(); + w.set_cpol(vals::Cpol::ACTIVE_LOW); + w.set_cpha(vals::Cpha::LEADING); } MODE_3 => { - w.order().variant(config.bit_order); - w.cpol().active_low(); - w.cpha().trailing(); + w.set_cpol(vals::Cpol::ACTIVE_LOW); + w.set_cpha(vals::Cpha::TRAILING); } } - - w }); // Configure frequency. let frequency = config.frequency; - r.frequency.write(|w| w.frequency().variant(frequency)); + r.frequency().write(|w| w.set_frequency(frequency)); // Set over-read character let orc = config.orc; - r.orc.write(|w| unsafe { w.orc().bits(orc) }); + r.orc().write(|w| w.set_orc(orc)); Ok(()) } diff --git a/embassy-nrf/src/spis.rs b/embassy-nrf/src/spis.rs index e98b34369..a363e5909 100644 --- a/embassy-nrf/src/spis.rs +++ b/embassy-nrf/src/spis.rs @@ -10,11 +10,13 @@ use embassy_embedded_hal::SetConfig; use embassy_hal_internal::{into_ref, PeripheralRef}; use embassy_sync::waitqueue::AtomicWaker; pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; -pub use pac::spis0::config::ORDER_A as BitOrder; +pub use pac::spis::vals::Order as BitOrder; use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE}; -use crate::gpio::{self, AnyPin, Pin as GpioPin, SealedPin as _}; +use crate::gpio::{self, convert_drive, AnyPin, OutputDrive, Pin as GpioPin, SealedPin as _}; use crate::interrupt::typelevel::Interrupt; +use crate::pac::gpio::vals as gpiovals; +use crate::pac::spis::vals; use crate::util::slice_in_ram_or; use crate::{interrupt, pac, Peripheral}; @@ -54,6 +56,9 @@ pub struct Config { /// Automatically make the firmware side acquire the semaphore on transfer end. pub auto_acquire: bool, + + /// Drive strength for the MISO line. + pub miso_drive: OutputDrive, } impl Default for Config { @@ -64,6 +69,7 @@ impl Default for Config { orc: 0x00, def: 0x00, auto_acquire: true, + miso_drive: OutputDrive::HighDrive, } } } @@ -78,14 +84,14 @@ impl interrupt::typelevel::Handler for InterruptHandl let r = T::regs(); let s = T::state(); - if r.events_end.read().bits() != 0 { + if r.events_end().read() != 0 { s.waker.wake(); - r.intenclr.write(|w| w.end().clear()); + r.intenclr().write(|w| w.set_end(true)); } - if r.events_acquired.read().bits() != 0 { + if r.events_acquired().read() != 0 { s.waker.wake(); - r.intenclr.write(|w| w.acquired().clear()); + r.intenclr().write(|w| w.set_acquired(true)); } } } @@ -184,23 +190,26 @@ impl<'d, T: Instance> Spis<'d, T> { let r = T::regs(); // Configure pins. - cs.conf().write(|w| w.input().connect().drive().h0h1()); - r.psel.csn.write(|w| unsafe { w.bits(cs.psel_bits()) }); + cs.conf().write(|w| w.set_input(gpiovals::Input::CONNECT)); + r.psel().csn().write_value(cs.psel_bits()); if let Some(sck) = &sck { - sck.conf().write(|w| w.input().connect().drive().h0h1()); - r.psel.sck.write(|w| unsafe { w.bits(sck.psel_bits()) }); + sck.conf().write(|w| w.set_input(gpiovals::Input::CONNECT)); + r.psel().sck().write_value(sck.psel_bits()); } if let Some(mosi) = &mosi { - mosi.conf().write(|w| w.input().connect().drive().h0h1()); - r.psel.mosi.write(|w| unsafe { w.bits(mosi.psel_bits()) }); + mosi.conf().write(|w| w.set_input(gpiovals::Input::CONNECT)); + r.psel().mosi().write_value(mosi.psel_bits()); } if let Some(miso) = &miso { - miso.conf().write(|w| w.dir().output().drive().h0h1()); - r.psel.miso.write(|w| unsafe { w.bits(miso.psel_bits()) }); + miso.conf().write(|w| { + w.set_dir(gpiovals::Dir::OUTPUT); + w.set_drive(convert_drive(config.miso_drive)) + }); + r.psel().miso().write_value(miso.psel_bits()); } // Enable SPIS instance. - r.enable.write(|w| w.enable().enabled()); + r.enable().write(|w| w.set_enable(vals::Enable::ENABLED)); let mut spis = Self { _p: spis }; @@ -208,7 +217,7 @@ impl<'d, T: Instance> Spis<'d, T> { Self::set_config(&mut spis, &config).unwrap(); // Disable all events interrupts. - r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) }); + r.intenclr().write(|w| w.0 = 0xFFFF_FFFF); T::Interrupt::unpend(); unsafe { T::Interrupt::enable() }; @@ -229,21 +238,21 @@ impl<'d, T: Instance> Spis<'d, T> { if tx.len() > EASY_DMA_SIZE { return Err(Error::TxBufferTooLong); } - r.txd.ptr.write(|w| unsafe { w.ptr().bits(tx as *const u8 as _) }); - r.txd.maxcnt.write(|w| unsafe { w.maxcnt().bits(tx.len() as _) }); + r.txd().ptr().write_value(tx as *const u8 as _); + r.txd().maxcnt().write(|w| w.set_maxcnt(tx.len() as _)); // Set up the DMA read. if rx.len() > EASY_DMA_SIZE { return Err(Error::RxBufferTooLong); } - r.rxd.ptr.write(|w| unsafe { w.ptr().bits(rx as *mut u8 as _) }); - r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(rx.len() as _) }); + r.rxd().ptr().write_value(rx as *mut u8 as _); + r.rxd().maxcnt().write(|w| w.set_maxcnt(rx.len() as _)); // Reset end event. - r.events_end.reset(); + r.events_end().write_value(0); // Release the semaphore. - r.tasks_release.write(|w| unsafe { w.bits(1) }); + r.tasks_release().write_value(1); Ok(()) } @@ -253,20 +262,20 @@ impl<'d, T: Instance> Spis<'d, T> { let r = T::regs(); // Acquire semaphore. - if r.semstat.read().bits() != 1 { - r.events_acquired.reset(); - r.tasks_acquire.write(|w| unsafe { w.bits(1) }); + if r.semstat().read().0 != 1 { + r.events_acquired().write_value(0); + r.tasks_acquire().write_value(1); // Wait until CPU has acquired the semaphore. - while r.semstat.read().bits() != 1 {} + while r.semstat().read().0 != 1 {} } self.prepare(rx, tx)?; // Wait for 'end' event. - while r.events_end.read().bits() == 0 {} + while r.events_end().read() == 0 {} - let n_rx = r.rxd.amount.read().bits() as usize; - let n_tx = r.txd.amount.read().bits() as usize; + let n_rx = r.rxd().amount().read().0 as usize; + let n_tx = r.txd().amount().read().0 as usize; compiler_fence(Ordering::SeqCst); @@ -291,22 +300,25 @@ impl<'d, T: Instance> Spis<'d, T> { let s = T::state(); // Clear status register. - r.status.write(|w| w.overflow().clear().overread().clear()); + r.status().write(|w| { + w.set_overflow(true); + w.set_overread(true); + }); // Acquire semaphore. - if r.semstat.read().bits() != 1 { + if r.semstat().read().0 != 1 { // Reset and enable the acquire event. - r.events_acquired.reset(); - r.intenset.write(|w| w.acquired().set()); + r.events_acquired().write_value(0); + r.intenset().write(|w| w.set_acquired(true)); // Request acquiring the SPIS semaphore. - r.tasks_acquire.write(|w| unsafe { w.bits(1) }); + r.tasks_acquire().write_value(1); // Wait until CPU has acquired the semaphore. poll_fn(|cx| { s.waker.register(cx.waker()); - if r.events_acquired.read().bits() == 1 { - r.events_acquired.reset(); + if r.events_acquired().read() == 1 { + r.events_acquired().write_value(0); return Poll::Ready(()); } Poll::Pending @@ -317,19 +329,19 @@ impl<'d, T: Instance> Spis<'d, T> { self.prepare(rx, tx)?; // Wait for 'end' event. - r.intenset.write(|w| w.end().set()); + r.intenset().write(|w| w.set_end(true)); poll_fn(|cx| { s.waker.register(cx.waker()); - if r.events_end.read().bits() != 0 { - r.events_end.reset(); + if r.events_end().read() != 0 { + r.events_end().write_value(0); return Poll::Ready(()); } Poll::Pending }) .await; - let n_rx = r.rxd.amount.read().bits() as usize; - let n_tx = r.txd.amount.read().bits() as usize; + let n_rx = r.rxd().amount().read().0 as usize; + let n_tx = r.txd().amount().read().0 as usize; compiler_fence(Ordering::SeqCst); @@ -428,12 +440,12 @@ impl<'d, T: Instance> Spis<'d, T> { /// Checks if last transaction overread. pub fn is_overread(&mut self) -> bool { - T::regs().status.read().overread().is_present() + T::regs().status().read().overread() } /// Checks if last transaction overflowed. pub fn is_overflow(&mut self) -> bool { - T::regs().status.read().overflow().is_present() + T::regs().status().read().overflow() } } @@ -443,12 +455,12 @@ impl<'d, T: Instance> Drop for Spis<'d, T> { // Disable let r = T::regs(); - r.enable.write(|w| w.enable().disabled()); + r.enable().write(|w| w.set_enable(vals::Enable::DISABLED)); - gpio::deconfigure_pin(r.psel.sck.read().bits()); - gpio::deconfigure_pin(r.psel.csn.read().bits()); - gpio::deconfigure_pin(r.psel.miso.read().bits()); - gpio::deconfigure_pin(r.psel.mosi.read().bits()); + gpio::deconfigure_pin(r.psel().sck().read()); + gpio::deconfigure_pin(r.psel().csn().read()); + gpio::deconfigure_pin(r.psel().miso().read()); + gpio::deconfigure_pin(r.psel().mosi().read()); trace!("spis drop: done"); } @@ -467,7 +479,7 @@ impl State { } pub(crate) trait SealedInstance { - fn regs() -> &'static pac::spis0::RegisterBlock; + fn regs() -> pac::spis::Spis; fn state() -> &'static State; } @@ -481,8 +493,8 @@ pub trait Instance: Peripheral

+ SealedInstance + 'static { macro_rules! impl_spis { ($type:ident, $pac_type:ident, $irq:ident) => { impl crate::spis::SealedInstance for peripherals::$type { - fn regs() -> &'static pac::spis0::RegisterBlock { - unsafe { &*pac::$pac_type::ptr() } + fn regs() -> pac::spis::Spis { + pac::$pac_type } fn state() -> &'static crate::spis::State { static STATE: crate::spis::State = crate::spis::State::new(); @@ -504,44 +516,39 @@ impl<'d, T: Instance> SetConfig for Spis<'d, T> { let r = T::regs(); // Configure mode. let mode = config.mode; - r.config.write(|w| { + r.config().write(|w| { + w.set_order(config.bit_order); match mode { MODE_0 => { - w.order().variant(config.bit_order); - w.cpol().active_high(); - w.cpha().leading(); + w.set_cpol(vals::Cpol::ACTIVE_HIGH); + w.set_cpha(vals::Cpha::LEADING); } MODE_1 => { - w.order().variant(config.bit_order); - w.cpol().active_high(); - w.cpha().trailing(); + w.set_cpol(vals::Cpol::ACTIVE_HIGH); + w.set_cpha(vals::Cpha::TRAILING); } MODE_2 => { - w.order().variant(config.bit_order); - w.cpol().active_low(); - w.cpha().leading(); + w.set_cpol(vals::Cpol::ACTIVE_LOW); + w.set_cpha(vals::Cpha::LEADING); } MODE_3 => { - w.order().variant(config.bit_order); - w.cpol().active_low(); - w.cpha().trailing(); + w.set_cpol(vals::Cpol::ACTIVE_LOW); + w.set_cpha(vals::Cpha::TRAILING); } } - - w }); // Set over-read character. let orc = config.orc; - r.orc.write(|w| unsafe { w.orc().bits(orc) }); + r.orc().write(|w| w.set_orc(orc)); // Set default character. let def = config.def; - r.def.write(|w| unsafe { w.def().bits(def) }); + r.def().write(|w| w.set_def(def)); // Configure auto-acquire on 'transfer end' event. let auto_acquire = config.auto_acquire; - r.shorts.write(|w| w.end_acquire().bit(auto_acquire)); + r.shorts().write(|w| w.set_end_acquire(auto_acquire)); Ok(()) } diff --git a/embassy-nrf/src/temp.rs b/embassy-nrf/src/temp.rs index ed4a47713..1488c5c24 100644 --- a/embassy-nrf/src/temp.rs +++ b/embassy-nrf/src/temp.rs @@ -19,8 +19,8 @@ pub struct InterruptHandler { impl interrupt::typelevel::Handler for InterruptHandler { unsafe fn on_interrupt() { - let r = unsafe { &*pac::TEMP::PTR }; - r.intenclr.write(|w| w.datardy().clear()); + let r = pac::TEMP; + r.intenclr().write(|w| w.set_datardy(true)); WAKER.wake(); } } @@ -72,21 +72,21 @@ impl<'d> Temp<'d> { // In case the future is dropped, stop the task and reset events. let on_drop = OnDrop::new(|| { let t = Self::regs(); - t.tasks_stop.write(|w| unsafe { w.bits(1) }); - t.events_datardy.reset(); + t.tasks_stop().write_value(1); + t.events_datardy().write_value(0); }); let t = Self::regs(); - t.intenset.write(|w| w.datardy().set()); - unsafe { t.tasks_start.write(|w| w.bits(1)) }; + t.intenset().write(|w| w.set_datardy(true)); + t.tasks_start().write_value(1); let value = poll_fn(|cx| { WAKER.register(cx.waker()); - if t.events_datardy.read().bits() == 0 { + if t.events_datardy().read() == 0 { Poll::Pending } else { - t.events_datardy.reset(); - let raw = t.temp.read().bits(); + t.events_datardy().write_value(0); + let raw = t.temp().read(); Poll::Ready(I30F2::from_bits(raw as i32)) } }) @@ -95,7 +95,7 @@ impl<'d> Temp<'d> { value } - fn regs() -> &'static pac::temp::RegisterBlock { - unsafe { &*pac::TEMP::ptr() } + fn regs() -> pac::temp::Temp { + pac::TEMP } } diff --git a/embassy-nrf/src/time_driver.rs b/embassy-nrf/src/time_driver.rs index 3407c9504..e39c4ed52 100644 --- a/embassy-nrf/src/time_driver.rs +++ b/embassy-nrf/src/time_driver.rs @@ -10,8 +10,8 @@ use embassy_time_driver::{AlarmHandle, Driver}; use crate::interrupt::InterruptExt; use crate::{interrupt, pac}; -fn rtc() -> &'static pac::rtc0::RegisterBlock { - unsafe { &*pac::RTC1::ptr() } +fn rtc() -> pac::rtc::Rtc { + pac::RTC1 } /// Calculate the timestamp from the period count and the tick count. @@ -128,19 +128,18 @@ embassy_time_driver::time_driver_impl!(static DRIVER: RtcDriver = RtcDriver { impl RtcDriver { fn init(&'static self, irq_prio: crate::interrupt::Priority) { let r = rtc(); - r.cc[3].write(|w| unsafe { w.bits(0x800000) }); + r.cc(3).write(|w| w.set_compare(0x800000)); - r.intenset.write(|w| { - let w = w.ovrflw().set(); - let w = w.compare3().set(); - w + r.intenset().write(|w| { + w.set_ovrflw(true); + w.set_compare3(true); }); - r.tasks_clear.write(|w| unsafe { w.bits(1) }); - r.tasks_start.write(|w| unsafe { w.bits(1) }); + r.tasks_clear().write_value(1); + r.tasks_start().write_value(1); // Wait for clear - while r.counter.read().bits() != 0 {} + while r.counter().read().0 != 0 {} interrupt::RTC1.set_priority(irq_prio); unsafe { interrupt::RTC1.enable() }; @@ -148,19 +147,19 @@ impl RtcDriver { fn on_interrupt(&self) { let r = rtc(); - if r.events_ovrflw.read().bits() == 1 { - r.events_ovrflw.write(|w| w); + if r.events_ovrflw().read() == 1 { + r.events_ovrflw().write_value(0); self.next_period(); } - if r.events_compare[3].read().bits() == 1 { - r.events_compare[3].write(|w| w); + if r.events_compare(3).read() == 1 { + r.events_compare(3).write_value(0); self.next_period(); } for n in 0..ALARM_COUNT { - if r.events_compare[n].read().bits() == 1 { - r.events_compare[n].write(|w| w); + if r.events_compare(n).read() == 1 { + r.events_compare(n).write_value(0); critical_section::with(|cs| { self.trigger_alarm(n, cs); }) @@ -181,7 +180,7 @@ impl RtcDriver { if at < t + 0xc00000 { // just enable it. `set_alarm` has already set the correct CC val. - r.intenset.write(|w| unsafe { w.bits(compare_n(n)) }); + r.intenset().write(|w| w.0 = compare_n(n)); } } }) @@ -195,7 +194,7 @@ impl RtcDriver { fn trigger_alarm(&self, n: usize, cs: CriticalSection) { let r = rtc(); - r.intenclr.write(|w| unsafe { w.bits(compare_n(n)) }); + r.intenclr().write(|w| w.0 = compare_n(n)); let alarm = &self.alarms.borrow(cs)[n]; alarm.timestamp.set(u64::MAX); @@ -215,7 +214,7 @@ impl Driver for RtcDriver { // `period` MUST be read before `counter`, see comment at the top for details. let period = self.period.load(Ordering::Relaxed); compiler_fence(Ordering::Acquire); - let counter = rtc().counter.read().bits(); + let counter = rtc().counter().read().0; calc_now(period, counter) } @@ -252,7 +251,7 @@ impl Driver for RtcDriver { if timestamp <= t { // If alarm timestamp has passed the alarm will not fire. // Disarm the alarm and return `false` to indicate that. - r.intenclr.write(|w| unsafe { w.bits(compare_n(n)) }); + r.intenclr().write(|w| w.0 = compare_n(n)); alarm.timestamp.set(u64::MAX); @@ -277,15 +276,15 @@ impl Driver for RtcDriver { // by the Alarm trait contract. What's not allowed is triggering alarms *before* their scheduled time, // and we don't do that here. let safe_timestamp = timestamp.max(t + 3); - r.cc[n].write(|w| unsafe { w.bits(safe_timestamp as u32 & 0xFFFFFF) }); + r.cc(n).write(|w| w.set_compare(safe_timestamp as u32 & 0xFFFFFF)); let diff = timestamp - t; if diff < 0xc00000 { - r.intenset.write(|w| unsafe { w.bits(compare_n(n)) }); + r.intenset().write(|w| w.0 = compare_n(n)); } else { // If it's too far in the future, don't setup the compare channel yet. // It will be setup later by `next_period`. - r.intenclr.write(|w| unsafe { w.bits(compare_n(n)) }); + r.intenclr().write(|w| w.0 = compare_n(n)); } true diff --git a/embassy-nrf/src/timer.rs b/embassy-nrf/src/timer.rs index ac5328ded..a9aeb40fa 100644 --- a/embassy-nrf/src/timer.rs +++ b/embassy-nrf/src/timer.rs @@ -8,13 +8,14 @@ use embassy_hal_internal::{into_ref, PeripheralRef}; +use crate::pac::timer::vals; use crate::ppi::{Event, Task}; use crate::{pac, Peripheral}; pub(crate) trait SealedInstance { /// The number of CC registers this instance has. const CCS: usize; - fn regs() -> &'static pac::timer0::RegisterBlock; + fn regs() -> pac::timer::Timer; } /// Basic Timer instance. @@ -31,8 +32,8 @@ macro_rules! impl_timer { ($type:ident, $pac_type:ident, $irq:ident, $ccs:literal) => { impl crate::timer::SealedInstance for peripherals::$type { const CCS: usize = $ccs; - fn regs() -> &'static pac::timer0::RegisterBlock { - unsafe { &*(pac::$pac_type::ptr() as *const pac::timer0::RegisterBlock) } + fn regs() -> pac::timer::Timer { + unsafe { pac::timer::Timer::from_ptr(pac::$pac_type.as_ptr()) } } } impl crate::timer::Instance for peripherals::$type { @@ -114,19 +115,19 @@ impl<'d, T: Instance> Timer<'d, T> { // since changing BITMODE while running can cause 'unpredictable behaviour' according to the specification. this.stop(); - #[cfg(not(feature = "nrf51"))] - if _is_counter { - regs.mode.write(|w| w.mode().low_power_counter()); - } else { - regs.mode.write(|w| w.mode().timer()); - } - - #[cfg(feature = "nrf51")] - regs.mode.write(|w| w.mode().timer()); + regs.mode().write(|w| { + w.set_mode(match _is_counter { + #[cfg(not(feature = "_nrf51"))] + true => vals::Mode::LOW_POWER_COUNTER, + #[cfg(feature = "_nrf51")] + true => vals::Mode::COUNTER, + false => vals::Mode::TIMER, + }) + }); // Make the counter's max value as high as possible. // TODO: is there a reason someone would want to set this lower? - regs.bitmode.write(|w| w.bitmode()._32bit()); + regs.bitmode().write(|w| w.set_bitmode(vals::Bitmode::_32BIT)); // Initialize the counter at 0. this.clear(); @@ -148,38 +149,38 @@ impl<'d, T: Instance> Timer<'d, T> { /// Starts the timer. pub fn start(&self) { - T::regs().tasks_start.write(|w| unsafe { w.bits(1) }) + T::regs().tasks_start().write_value(1) } /// Stops the timer. pub fn stop(&self) { - T::regs().tasks_stop.write(|w| unsafe { w.bits(1) }) + T::regs().tasks_stop().write_value(1) } /// Reset the timer's counter to 0. pub fn clear(&self) { - T::regs().tasks_clear.write(|w| unsafe { w.bits(1) }) + T::regs().tasks_clear().write_value(1) } /// Returns the START task, for use with PPI. /// /// When triggered, this task starts the timer. pub fn task_start(&self) -> Task<'d> { - Task::from_reg(&T::regs().tasks_start) + Task::from_reg(T::regs().tasks_start()) } /// Returns the STOP task, for use with PPI. /// /// When triggered, this task stops the timer. pub fn task_stop(&self) -> Task<'d> { - Task::from_reg(&T::regs().tasks_stop) + Task::from_reg(T::regs().tasks_stop()) } /// Returns the CLEAR task, for use with PPI. /// /// When triggered, this task resets the timer's counter to 0. pub fn task_clear(&self) -> Task<'d> { - Task::from_reg(&T::regs().tasks_clear) + Task::from_reg(T::regs().tasks_clear()) } /// Returns the COUNT task, for use with PPI. @@ -187,7 +188,7 @@ impl<'d, T: Instance> Timer<'d, T> { /// When triggered, this task increments the timer's counter by 1. /// Only works in counter mode. pub fn task_count(&self) -> Task<'d> { - Task::from_reg(&T::regs().tasks_count) + Task::from_reg(T::regs().tasks_count()) } /// Change the timer's frequency. @@ -198,10 +199,10 @@ impl<'d, T: Instance> Timer<'d, T> { self.stop(); T::regs() - .prescaler + .prescaler() // SAFETY: `frequency` is a variant of `Frequency`, // whose values are all in the range of 0-9 (the valid range of `prescaler`). - .write(|w| unsafe { w.prescaler().bits(frequency as u8) }) + .write(|w| w.set_prescaler(frequency as u8)) } /// Returns this timer's `n`th CC register. @@ -234,28 +235,19 @@ pub struct Cc<'d, T: Instance> { impl<'d, T: Instance> Cc<'d, T> { /// Get the current value stored in the register. pub fn read(&self) -> u32 { - #[cfg(not(feature = "nrf51"))] - return T::regs().cc[self.n].read().cc().bits(); - - #[cfg(feature = "nrf51")] - return T::regs().cc[self.n].read().bits(); + return T::regs().cc(self.n).read(); } /// Set the value stored in the register. /// /// `event_compare` will fire when the timer's counter reaches this value. pub fn write(&self, value: u32) { - // SAFETY: there are no invalid values for the CC register. - #[cfg(not(feature = "nrf51"))] - T::regs().cc[self.n].write(|w| unsafe { w.cc().bits(value) }); - - #[cfg(feature = "nrf51")] - T::regs().cc[self.n].write(|w| unsafe { w.bits(value) }); + T::regs().cc(self.n).write_value(value); } /// Capture the current value of the timer's counter in this register, and return it. pub fn capture(&self) -> u32 { - T::regs().tasks_capture[self.n].write(|w| unsafe { w.bits(1) }); + T::regs().tasks_capture(self.n).write_value(1); self.read() } @@ -263,14 +255,14 @@ impl<'d, T: Instance> Cc<'d, T> { /// /// When triggered, this task will capture the current value of the timer's counter in this register. pub fn task_capture(&self) -> Task<'d> { - Task::from_reg(&T::regs().tasks_capture) + Task::from_reg(T::regs().tasks_capture(self.n)) } /// Returns this CC register's COMPARE event, for use with PPI. /// /// This event will fire when the timer's counter reaches the value in this CC register. pub fn event_compare(&self) -> Event<'d> { - Event::from_reg(&T::regs().events_compare[self.n]) + Event::from_reg(T::regs().events_compare(self.n)) } /// Enable the shortcut between this CC register's COMPARE event and the timer's CLEAR task. @@ -279,16 +271,12 @@ impl<'d, T: Instance> Cc<'d, T> { /// /// So, when the timer's counter reaches the value stored in this register, the timer's counter will be reset to 0. pub fn short_compare_clear(&self) { - T::regs() - .shorts - .modify(|r, w| unsafe { w.bits(r.bits() | (1 << self.n)) }) + T::regs().shorts().modify(|w| w.set_compare_clear(self.n, true)) } /// Disable the shortcut between this CC register's COMPARE event and the timer's CLEAR task. pub fn unshort_compare_clear(&self) { - T::regs() - .shorts - .modify(|r, w| unsafe { w.bits(r.bits() & !(1 << self.n)) }) + T::regs().shorts().modify(|w| w.set_compare_clear(self.n, false)) } /// Enable the shortcut between this CC register's COMPARE event and the timer's STOP task. @@ -297,15 +285,11 @@ impl<'d, T: Instance> Cc<'d, T> { /// /// So, when the timer's counter reaches the value stored in this register, the timer will stop counting up. pub fn short_compare_stop(&self) { - T::regs() - .shorts - .modify(|r, w| unsafe { w.bits(r.bits() | (1 << (8 + self.n))) }) + T::regs().shorts().modify(|w| w.set_compare_stop(self.n, true)) } /// Disable the shortcut between this CC register's COMPARE event and the timer's STOP task. pub fn unshort_compare_stop(&self) { - T::regs() - .shorts - .modify(|r, w| unsafe { w.bits(r.bits() & !(1 << (8 + self.n))) }) + T::regs().shorts().modify(|w| w.set_compare_stop(self.n, false)) } } diff --git a/embassy-nrf/src/twim.rs b/embassy-nrf/src/twim.rs index 187fce021..ebad39df2 100644 --- a/embassy-nrf/src/twim.rs +++ b/embassy-nrf/src/twim.rs @@ -15,24 +15,16 @@ use embassy_sync::waitqueue::AtomicWaker; #[cfg(feature = "time")] use embassy_time::{Duration, Instant}; use embedded_hal_1::i2c::Operation; +pub use pac::twim::vals::Frequency; use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE}; use crate::gpio::Pin as GpioPin; use crate::interrupt::typelevel::Interrupt; +use crate::pac::gpio::vals as gpiovals; +use crate::pac::twim::vals; use crate::util::slice_in_ram; use crate::{gpio, interrupt, pac, Peripheral}; -/// TWI frequency -#[derive(Clone, Copy)] -pub enum Frequency { - /// 100 kbps - K100 = 26738688, - /// 250 kbps - K250 = 67108864, - /// 400 kbps - K400 = 104857600, -} - /// TWIM config. #[non_exhaustive] pub struct Config { @@ -105,17 +97,17 @@ impl interrupt::typelevel::Handler for InterruptHandl let r = T::regs(); let s = T::state(); - if r.events_suspended.read().bits() != 0 { + if r.events_suspended().read() != 0 { s.end_waker.wake(); - r.intenclr.write(|w| w.suspended().clear()); + r.intenclr().write(|w| w.set_suspended(true)); } - if r.events_stopped.read().bits() != 0 { + if r.events_stopped().read() != 0 { s.end_waker.wake(); - r.intenclr.write(|w| w.stopped().clear()); + r.intenclr().write(|w| w.set_stopped(true)); } - if r.events_error.read().bits() != 0 { + if r.events_error().read() != 0 { s.end_waker.wake(); - r.intenclr.write(|w| w.error().clear()); + r.intenclr().write(|w| w.set_error(true)); } } } @@ -140,38 +132,34 @@ impl<'d, T: Instance> Twim<'d, T> { // Configure pins sda.conf().write(|w| { - w.dir().input(); - w.input().connect(); - if config.sda_high_drive { - w.drive().h0d1(); - } else { - w.drive().s0d1(); - } + w.set_dir(gpiovals::Dir::OUTPUT); + w.set_input(gpiovals::Input::CONNECT); + w.set_drive(match config.sda_high_drive { + true => gpiovals::Drive::H0D1, + false => gpiovals::Drive::S0D1, + }); if config.sda_pullup { - w.pull().pullup(); + w.set_pull(gpiovals::Pull::PULLUP); } - w }); scl.conf().write(|w| { - w.dir().input(); - w.input().connect(); - if config.scl_high_drive { - w.drive().h0d1(); - } else { - w.drive().s0d1(); + w.set_dir(gpiovals::Dir::OUTPUT); + w.set_input(gpiovals::Input::CONNECT); + w.set_drive(match config.scl_high_drive { + true => gpiovals::Drive::H0D1, + false => gpiovals::Drive::S0D1, + }); + if config.sda_pullup { + w.set_pull(gpiovals::Pull::PULLUP); } - if config.scl_pullup { - w.pull().pullup(); - } - w }); // Select pins. - r.psel.sda.write(|w| unsafe { w.bits(sda.psel_bits()) }); - r.psel.scl.write(|w| unsafe { w.bits(scl.psel_bits()) }); + r.psel().sda().write_value(sda.psel_bits()); + r.psel().scl().write_value(scl.psel_bits()); // Enable TWIM instance. - r.enable.write(|w| w.enable().enabled()); + r.enable().write(|w| w.set_enable(vals::Enable::ENABLED)); let mut twim = Self { _p: twim }; @@ -179,7 +167,7 @@ impl<'d, T: Instance> Twim<'d, T> { Self::set_config(&mut twim, &config).unwrap(); // Disable all events interrupts - r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) }); + r.intenclr().write(|w| w.0 = 0xFFFF_FFFF); T::Interrupt::unpend(); unsafe { T::Interrupt::enable() }; @@ -211,22 +199,18 @@ impl<'d, T: Instance> Twim<'d, T> { let r = T::regs(); - r.txd.ptr.write(|w| - // We're giving the register a pointer to the stack. Since we're - // waiting for the I2C transaction to end before this stack pointer - // becomes invalid, there's nothing wrong here. - // - // The PTR field is a full 32 bits wide and accepts the full range - // of values. - w.ptr().bits(buffer.as_ptr() as u32)); - r.txd.maxcnt.write(|w| + // We're giving the register a pointer to the stack. Since we're + // waiting for the I2C transaction to end before this stack pointer + // becomes invalid, there's nothing wrong here. + r.txd().ptr().write_value(buffer.as_ptr() as u32); + r.txd().maxcnt().write(|w| // We're giving it the length of the buffer, so no danger of // accessing invalid memory. We have verified that the length of the // buffer fits in an `u8`, so the cast to `u8` is also fine. // // The MAXCNT field is 8 bits wide and accepts the full range of // values. - w.maxcnt().bits(buffer.len() as _)); + w.set_maxcnt(buffer.len() as _)); Ok(()) } @@ -242,15 +226,11 @@ impl<'d, T: Instance> Twim<'d, T> { let r = T::regs(); - r.rxd.ptr.write(|w| - // We're giving the register a pointer to the stack. Since we're - // waiting for the I2C transaction to end before this stack pointer - // becomes invalid, there's nothing wrong here. - // - // The PTR field is a full 32 bits wide and accepts the full range - // of values. - w.ptr().bits(buffer.as_mut_ptr() as u32)); - r.rxd.maxcnt.write(|w| + // We're giving the register a pointer to the stack. Since we're + // waiting for the I2C transaction to end before this stack pointer + // becomes invalid, there's nothing wrong here. + r.rxd().ptr().write_value(buffer.as_mut_ptr() as u32); + r.rxd().maxcnt().write(|w| // We're giving it the length of the buffer, so no danger of // accessing invalid memory. We have verified that the length of the // buffer fits in an `u8`, so the cast to the type of maxcnt @@ -260,29 +240,32 @@ impl<'d, T: Instance> Twim<'d, T> { // type than a u8, so we use a `_` cast rather than a `u8` cast. // The MAXCNT field is thus at least 8 bits wide and accepts the // full range of values that fit in a `u8`. - w.maxcnt().bits(buffer.len() as _)); + w.set_maxcnt(buffer.len() as _)); Ok(()) } fn clear_errorsrc(&mut self) { let r = T::regs(); - r.errorsrc - .write(|w| w.anack().bit(true).dnack().bit(true).overrun().bit(true)); + r.errorsrc().write(|w| { + w.set_anack(true); + w.set_dnack(true); + w.set_overrun(true); + }); } /// Get Error instance, if any occurred. fn check_errorsrc(&self) -> Result<(), Error> { let r = T::regs(); - let err = r.errorsrc.read(); - if err.anack().is_received() { + let err = r.errorsrc().read(); + if err.anack() { return Err(Error::AddressNack); } - if err.dnack().is_received() { + if err.dnack() { return Err(Error::DataNack); } - if err.overrun().is_received() { + if err.overrun() { return Err(Error::Overrun); } Ok(()) @@ -290,7 +273,7 @@ impl<'d, T: Instance> Twim<'d, T> { fn check_rx(&self, len: usize) -> Result<(), Error> { let r = T::regs(); - if r.rxd.amount.read().bits() != len as u32 { + if r.rxd().amount().read().0 != len as u32 { Err(Error::Receive) } else { Ok(()) @@ -299,7 +282,7 @@ impl<'d, T: Instance> Twim<'d, T> { fn check_tx(&self, len: usize) -> Result<(), Error> { let r = T::regs(); - if r.txd.amount.read().bits() != len as u32 { + if r.txd().amount().read().0 != len as u32 { Err(Error::Transmit) } else { Ok(()) @@ -310,14 +293,14 @@ impl<'d, T: Instance> Twim<'d, T> { fn blocking_wait(&mut self) { let r = T::regs(); loop { - if r.events_suspended.read().bits() != 0 || r.events_stopped.read().bits() != 0 { - r.events_suspended.reset(); - r.events_stopped.reset(); + if r.events_suspended().read() != 0 || r.events_stopped().read() != 0 { + r.events_suspended().write_value(0); + r.events_stopped().write_value(0); break; } - if r.events_error.read().bits() != 0 { - r.events_error.reset(); - r.tasks_stop.write(|w| unsafe { w.bits(1) }); + if r.events_error().read() != 0 { + r.events_error().write_value(0); + r.tasks_stop().write_value(1); } } } @@ -328,16 +311,16 @@ impl<'d, T: Instance> Twim<'d, T> { let r = T::regs(); let deadline = Instant::now() + timeout; loop { - if r.events_suspended.read().bits() != 0 || r.events_stopped.read().bits() != 0 { - r.events_stopped.reset(); + if r.events_suspended().read() != 0 || r.events_stopped().read() != 0 { + r.events_stopped().write_value(0); break; } - if r.events_error.read().bits() != 0 { - r.events_error.reset(); - r.tasks_stop.write(|w| unsafe { w.bits(1) }); + if r.events_error().read() != 0 { + r.events_error().write_value(0); + r.tasks_stop().write_value(1); } if Instant::now() > deadline { - r.tasks_stop.write(|w| unsafe { w.bits(1) }); + r.tasks_stop().write_value(1); return Err(Error::Timeout); } } @@ -352,16 +335,16 @@ impl<'d, T: Instance> Twim<'d, T> { let s = T::state(); s.end_waker.register(cx.waker()); - if r.events_suspended.read().bits() != 0 || r.events_stopped.read().bits() != 0 { - r.events_stopped.reset(); + if r.events_suspended().read() != 0 || r.events_stopped().read() != 0 { + r.events_stopped().write_value(0); return Poll::Ready(()); } // stop if an error occurred - if r.events_error.read().bits() != 0 { - r.events_error.reset(); - r.tasks_stop.write(|w| unsafe { w.bits(1) }); + if r.events_error().read() != 0 { + r.events_error().write_value(0); + r.tasks_stop().write_value(1); } Poll::Pending @@ -380,18 +363,25 @@ impl<'d, T: Instance> Twim<'d, T> { compiler_fence(SeqCst); - r.address.write(|w| unsafe { w.address().bits(address) }); + r.address().write(|w| w.set_address(address)); - r.events_suspended.reset(); - r.events_stopped.reset(); - r.events_error.reset(); + r.events_suspended().write_value(0); + r.events_stopped().write_value(0); + r.events_error().write_value(0); self.clear_errorsrc(); if inten { - r.intenset.write(|w| w.suspended().set().stopped().set().error().set()); + r.intenset().write(|w| { + w.set_suspended(true); + w.set_stopped(true); + w.set_error(true); + }); } else { - r.intenclr - .write(|w| w.suspended().clear().stopped().clear().error().clear()); + r.intenclr().write(|w| { + w.set_suspended(true); + w.set_stopped(true); + w.set_error(true); + }); } assert!(!operations.is_empty()); @@ -408,26 +398,25 @@ impl<'d, T: Instance> Twim<'d, T> { self.set_rx_buffer(rd_buffer)?; } - r.shorts.write(|w| { - w.lastrx_starttx().enabled(); + r.shorts().write(|w| { + w.set_lastrx_starttx(true); if stop { - w.lasttx_stop().enabled(); + w.set_lasttx_stop(true); } else { - w.lasttx_suspend().enabled(); + w.set_lasttx_suspend(true); } - w }); // Start read+write operation. - r.tasks_startrx.write(|w| unsafe { w.bits(1) }); + r.tasks_startrx().write_value(1); if last_op.is_some() { - r.tasks_resume.write(|w| unsafe { w.bits(1) }); + r.tasks_resume().write_value(1); } // TODO: Handle empty write buffer if rd_buffer.is_empty() { // With a zero-length buffer, LASTRX doesn't fire (because there's no last byte!), so do the STARTTX ourselves. - r.tasks_starttx.write(|w| unsafe { w.bits(1) }); + r.tasks_starttx().write_value(1); } Ok(2) @@ -438,17 +427,17 @@ impl<'d, T: Instance> Twim<'d, T> { self.set_rx_buffer(buffer)?; } - r.shorts.write(|w| w.lastrx_stop().enabled()); + r.shorts().write(|w| w.set_lastrx_stop(true)); // Start read operation. - r.tasks_startrx.write(|w| unsafe { w.bits(1) }); + r.tasks_startrx().write_value(1); if last_op.is_some() { - r.tasks_resume.write(|w| unsafe { w.bits(1) }); + r.tasks_resume().write_value(1); } if buffer.is_empty() { // With a zero-length buffer, LASTRX doesn't fire (because there's no last byte!), so do the STOP ourselves. - r.tasks_stop.write(|w| unsafe { w.bits(1) }); + r.tasks_stop().write_value(1); } Ok(1) @@ -463,15 +452,14 @@ impl<'d, T: Instance> Twim<'d, T> { } // Start write+read operation. - r.shorts.write(|w| { - w.lasttx_startrx().enabled(); - w.lastrx_stop().enabled(); - w + r.shorts().write(|w| { + w.set_lasttx_startrx(true); + w.set_lastrx_stop(true); }); - r.tasks_starttx.write(|w| unsafe { w.bits(1) }); + r.tasks_starttx().write_value(1); if last_op.is_some() { - r.tasks_resume.write(|w| unsafe { w.bits(1) }); + r.tasks_resume().write_value(1); } Ok(2) @@ -485,26 +473,25 @@ impl<'d, T: Instance> Twim<'d, T> { } // Start write operation. - r.shorts.write(|w| { + r.shorts().write(|w| { if stop { - w.lasttx_stop().enabled(); + w.set_lasttx_stop(true); } else { - w.lasttx_suspend().enabled(); + w.set_lasttx_suspend(true); } - w }); - r.tasks_starttx.write(|w| unsafe { w.bits(1) }); + r.tasks_starttx().write_value(1); if last_op.is_some() { - r.tasks_resume.write(|w| unsafe { w.bits(1) }); + r.tasks_resume().write_value(1); } if buffer.is_empty() { // With a zero-length buffer, LASTTX doesn't fire (because there's no last byte!), so do the STOP/SUSPEND ourselves. if stop { - r.tasks_stop.write(|w| unsafe { w.bits(1) }); + r.tasks_stop().write_value(1); } else { - r.tasks_suspend.write(|w| unsafe { w.bits(1) }); + r.tasks_suspend().write_value(1); } } @@ -827,10 +814,10 @@ impl<'a, T: Instance> Drop for Twim<'a, T> { // disable! let r = T::regs(); - r.enable.write(|w| w.enable().disabled()); + r.enable().write(|w| w.set_enable(vals::Enable::DISABLED)); - gpio::deconfigure_pin(r.psel.sda.read().bits()); - gpio::deconfigure_pin(r.psel.scl.read().bits()); + gpio::deconfigure_pin(r.psel().sda().read()); + gpio::deconfigure_pin(r.psel().scl().read()); trace!("twim drop: done"); } @@ -849,7 +836,7 @@ impl State { } pub(crate) trait SealedInstance { - fn regs() -> &'static pac::twim0::RegisterBlock; + fn regs() -> pac::twim::Twim; fn state() -> &'static State; } @@ -863,8 +850,8 @@ pub trait Instance: Peripheral

+ SealedInstance + 'static { macro_rules! impl_twim { ($type:ident, $pac_type:ident, $irq:ident) => { impl crate::twim::SealedInstance for peripherals::$type { - fn regs() -> &'static pac::twim0::RegisterBlock { - unsafe { &*pac::$pac_type::ptr() } + fn regs() -> pac::twim::Twim { + pac::$pac_type } fn state() -> &'static crate::twim::State { static STATE: crate::twim::State = crate::twim::State::new(); @@ -948,8 +935,7 @@ impl<'d, T: Instance> SetConfig for Twim<'d, T> { type ConfigError = (); fn set_config(&mut self, config: &Self::Config) -> Result<(), Self::ConfigError> { let r = T::regs(); - r.frequency - .write(|w| unsafe { w.frequency().bits(config.frequency as u32) }); + r.frequency().write(|w| w.set_frequency(config.frequency)); Ok(()) } diff --git a/embassy-nrf/src/twis.rs b/embassy-nrf/src/twis.rs index f3eab008f..60de2ed9d 100644 --- a/embassy-nrf/src/twis.rs +++ b/embassy-nrf/src/twis.rs @@ -16,6 +16,8 @@ use embassy_time::{Duration, Instant}; use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE}; use crate::gpio::Pin as GpioPin; use crate::interrupt::typelevel::Interrupt; +use crate::pac::gpio::vals as gpiovals; +use crate::pac::twis::vals; use crate::util::slice_in_ram_or; use crate::{gpio, interrupt, pac, Peripheral}; @@ -119,17 +121,20 @@ impl interrupt::typelevel::Handler for InterruptHandl let r = T::regs(); let s = T::state(); - if r.events_read.read().bits() != 0 || r.events_write.read().bits() != 0 { + if r.events_read().read() != 0 || r.events_write().read() != 0 { s.waker.wake(); - r.intenclr.modify(|_r, w| w.read().clear().write().clear()); + r.intenclr().write(|w| { + w.set_read(true); + w.set_write(true); + }); } - if r.events_stopped.read().bits() != 0 { + if r.events_stopped().read() != 0 { s.waker.wake(); - r.intenclr.modify(|_r, w| w.stopped().clear()); + r.intenclr().write(|w| w.set_stopped(true)); } - if r.events_error.read().bits() != 0 { + if r.events_error().read() != 0 { s.waker.wake(); - r.intenclr.modify(|_r, w| w.error().clear()); + r.intenclr().write(|w| w.set_error(true)); } } } @@ -154,55 +159,51 @@ impl<'d, T: Instance> Twis<'d, T> { // Configure pins sda.conf().write(|w| { - w.dir().input(); - w.input().connect(); - if config.sda_high_drive { - w.drive().h0d1(); - } else { - w.drive().s0d1(); - } + w.set_dir(gpiovals::Dir::INPUT); + w.set_input(gpiovals::Input::CONNECT); + w.set_drive(match config.sda_high_drive { + true => gpiovals::Drive::H0D1, + false => gpiovals::Drive::S0D1, + }); if config.sda_pullup { - w.pull().pullup(); + w.set_pull(gpiovals::Pull::PULLUP); } - w }); scl.conf().write(|w| { - w.dir().input(); - w.input().connect(); - if config.scl_high_drive { - w.drive().h0d1(); - } else { - w.drive().s0d1(); + w.set_dir(gpiovals::Dir::INPUT); + w.set_input(gpiovals::Input::CONNECT); + w.set_drive(match config.scl_high_drive { + true => gpiovals::Drive::H0D1, + false => gpiovals::Drive::S0D1, + }); + if config.sda_pullup { + w.set_pull(gpiovals::Pull::PULLUP); } - if config.scl_pullup { - w.pull().pullup(); - } - w }); // Select pins. - r.psel.sda.write(|w| unsafe { w.bits(sda.psel_bits()) }); - r.psel.scl.write(|w| unsafe { w.bits(scl.psel_bits()) }); + r.psel().sda().write_value(sda.psel_bits()); + r.psel().scl().write_value(scl.psel_bits()); // Enable TWIS instance. - r.enable.write(|w| w.enable().enabled()); + r.enable().write(|w| w.set_enable(vals::Enable::ENABLED)); // Disable all events interrupts - r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) }); + r.intenclr().write(|w| w.0 = 0xFFFF_FFFF); // Set address - r.address[0].write(|w| unsafe { w.address().bits(config.address0) }); - r.config.write(|w| w.address0().enabled()); + r.address(0).write(|w| w.set_address(config.address0)); + r.config().write(|w| w.set_address0(true)); if let Some(address1) = config.address1 { - r.address[1].write(|w| unsafe { w.address().bits(address1) }); - r.config.modify(|_r, w| w.address1().enabled()); + r.address(1).write(|w| w.set_address(address1)); + r.config().modify(|w| w.set_address1(true)); } // Set over-read character - r.orc.write(|w| unsafe { w.orc().bits(config.orc) }); + r.orc().write(|w| w.set_orc(config.orc)); // Generate suspend on read event - r.shorts.write(|w| w.read_suspend().enabled()); + r.shorts().write(|w| w.set_read_suspend(true)); T::Interrupt::unpend(); unsafe { T::Interrupt::enable() }; @@ -220,22 +221,18 @@ impl<'d, T: Instance> Twis<'d, T> { let r = T::regs(); - r.txd.ptr.write(|w| - // We're giving the register a pointer to the stack. Since we're - // waiting for the I2C transaction to end before this stack pointer - // becomes invalid, there's nothing wrong here. - // - // The PTR field is a full 32 bits wide and accepts the full range - // of values. - w.ptr().bits(buffer.as_ptr() as u32)); - r.txd.maxcnt.write(|w| + // We're giving the register a pointer to the stack. Since we're + // waiting for the I2C transaction to end before this stack pointer + // becomes invalid, there's nothing wrong here. + r.txd().ptr().write_value(buffer.as_ptr() as u32); + r.txd().maxcnt().write(|w| // We're giving it the length of the buffer, so no danger of // accessing invalid memory. We have verified that the length of the // buffer fits in an `u8`, so the cast to `u8` is also fine. // // The MAXCNT field is 8 bits wide and accepts the full range of // values. - w.maxcnt().bits(buffer.len() as _)); + w.set_maxcnt(buffer.len() as _)); Ok(()) } @@ -251,15 +248,11 @@ impl<'d, T: Instance> Twis<'d, T> { let r = T::regs(); - r.rxd.ptr.write(|w| - // We're giving the register a pointer to the stack. Since we're - // waiting for the I2C transaction to end before this stack pointer - // becomes invalid, there's nothing wrong here. - // - // The PTR field is a full 32 bits wide and accepts the full range - // of values. - w.ptr().bits(buffer.as_mut_ptr() as u32)); - r.rxd.maxcnt.write(|w| + // We're giving the register a pointer to the stack. Since we're + // waiting for the I2C transaction to end before this stack pointer + // becomes invalid, there's nothing wrong here. + r.rxd().ptr().write_value(buffer.as_mut_ptr() as u32); + r.rxd().maxcnt().write(|w| // We're giving it the length of the buffer, so no danger of // accessing invalid memory. We have verified that the length of the // buffer fits in an `u8`, so the cast to the type of maxcnt @@ -269,48 +262,51 @@ impl<'d, T: Instance> Twis<'d, T> { // type than a u8, so we use a `_` cast rather than a `u8` cast. // The MAXCNT field is thus at least 8 bits wide and accepts the // full range of values that fit in a `u8`. - w.maxcnt().bits(buffer.len() as _)); + w.set_maxcnt(buffer.len() as _)); Ok(()) } fn clear_errorsrc(&mut self) { let r = T::regs(); - r.errorsrc - .write(|w| w.overflow().bit(true).overread().bit(true).dnack().bit(true)); + r.errorsrc().write(|w| { + w.set_overflow(true); + w.set_overread(true); + w.set_dnack(true); + }); } /// Returns matched address for latest command. pub fn address_match(&self) -> u8 { let r = T::regs(); - r.address[r.match_.read().bits() as usize].read().address().bits() + r.address(r.match_().read().0 as usize).read().address() } /// Returns the index of the address matched in the latest command. pub fn address_match_index(&self) -> usize { - T::regs().match_.read().bits() as _ + T::regs().match_().read().0 as _ } /// Wait for read, write, stop or error fn blocking_listen_wait(&mut self) -> Result { let r = T::regs(); loop { - if r.events_error.read().bits() != 0 { - r.events_error.reset(); - r.tasks_stop.write(|w| unsafe { w.bits(1) }); - while r.events_stopped.read().bits() == 0 {} + if r.events_error().read() != 0 { + r.events_error().write_value(0); + r.tasks_stop().write_value(1); + while r.events_stopped().read() == 0 {} return Err(Error::Overflow); } - if r.events_stopped.read().bits() != 0 { - r.events_stopped.reset(); + if r.events_stopped().read() != 0 { + r.events_stopped().write_value(0); return Err(Error::Bus); } - if r.events_read.read().bits() != 0 { - r.events_read.reset(); + if r.events_read().read() != 0 { + r.events_read().write_value(0); return Ok(Status::Read); } - if r.events_write.read().bits() != 0 { - r.events_write.reset(); + if r.events_write().read() != 0 { + r.events_write().write_value(0); return Ok(Status::Write); } } @@ -321,22 +317,22 @@ impl<'d, T: Instance> Twis<'d, T> { let r = T::regs(); loop { // stop if an error occurred - if r.events_error.read().bits() != 0 { - r.events_error.reset(); - r.tasks_stop.write(|w| unsafe { w.bits(1) }); + if r.events_error().read() != 0 { + r.events_error().write_value(0); + r.tasks_stop().write_value(1); return Err(Error::Overflow); - } else if r.events_stopped.read().bits() != 0 { - r.events_stopped.reset(); + } else if r.events_stopped().read() != 0 { + r.events_stopped().write_value(0); return match status { Status::Read => Ok(Command::Read), Status::Write => { - let n = r.rxd.amount.read().bits() as usize; + let n = r.rxd().amount().read().0 as usize; Ok(Command::Write(n)) } }; - } else if r.events_read.read().bits() != 0 { - r.events_read.reset(); - let n = r.rxd.amount.read().bits() as usize; + } else if r.events_read().read() != 0 { + r.events_read().write_value(0); + let n = r.rxd().amount().read().0 as usize; return Ok(Command::WriteRead(n)); } } @@ -347,20 +343,20 @@ impl<'d, T: Instance> Twis<'d, T> { let r = T::regs(); loop { // stop if an error occurred - if r.events_error.read().bits() != 0 { - r.events_error.reset(); - r.tasks_stop.write(|w| unsafe { w.bits(1) }); - let errorsrc = r.errorsrc.read(); - if errorsrc.overread().is_detected() { + if r.events_error().read() != 0 { + r.events_error().write_value(0); + r.tasks_stop().write_value(1); + let errorsrc = r.errorsrc().read(); + if errorsrc.overread() { return Err(Error::OverRead); - } else if errorsrc.dnack().is_received() { + } else if errorsrc.dnack() { return Err(Error::DataNack); } else { return Err(Error::Bus); } - } else if r.events_stopped.read().bits() != 0 { - r.events_stopped.reset(); - let n = r.txd.amount.read().bits() as usize; + } else if r.events_stopped().read() != 0 { + r.events_stopped().write_value(0); + let n = r.txd().amount().read().0 as usize; return Ok(n); } } @@ -373,23 +369,23 @@ impl<'d, T: Instance> Twis<'d, T> { let deadline = Instant::now() + timeout; loop { // stop if an error occurred - if r.events_error.read().bits() != 0 { - r.events_error.reset(); - r.tasks_stop.write(|w| unsafe { w.bits(1) }); - let errorsrc = r.errorsrc.read(); - if errorsrc.overread().is_detected() { + if r.events_error().read() != 0 { + r.events_error().write_value(0); + r.tasks_stop().write_value(1); + let errorsrc = r.errorsrc().read(); + if errorsrc.overread() { return Err(Error::OverRead); - } else if errorsrc.dnack().is_received() { + } else if errorsrc.dnack() { return Err(Error::DataNack); } else { return Err(Error::Bus); } - } else if r.events_stopped.read().bits() != 0 { - r.events_stopped.reset(); - let n = r.txd.amount.read().bits() as usize; + } else if r.events_stopped().read() != 0 { + r.events_stopped().write_value(0); + let n = r.txd().amount().read().0 as usize; return Ok(n); } else if Instant::now() > deadline { - r.tasks_stop.write(|w| unsafe { w.bits(1) }); + r.tasks_stop().write_value(1); return Err(Error::Timeout); } } @@ -401,26 +397,26 @@ impl<'d, T: Instance> Twis<'d, T> { let r = T::regs(); let deadline = Instant::now() + timeout; loop { - if r.events_error.read().bits() != 0 { - r.events_error.reset(); - r.tasks_stop.write(|w| unsafe { w.bits(1) }); - while r.events_stopped.read().bits() == 0 {} + if r.events_error().read() != 0 { + r.events_error().write_value(0); + r.tasks_stop().write_value(1); + while r.events_stopped().read() == 0 {} return Err(Error::Overflow); } - if r.events_stopped.read().bits() != 0 { - r.events_stopped.reset(); + if r.events_stopped().read() != 0 { + r.events_stopped().write_value(0); return Err(Error::Bus); } - if r.events_read.read().bits() != 0 { - r.events_read.reset(); + if r.events_read().read() != 0 { + r.events_read().write_value(0); return Ok(Status::Read); } - if r.events_write.read().bits() != 0 { - r.events_write.reset(); + if r.events_write().read() != 0 { + r.events_write().write_value(0); return Ok(Status::Write); } if Instant::now() > deadline { - r.tasks_stop.write(|w| unsafe { w.bits(1) }); + r.tasks_stop().write_value(1); return Err(Error::Timeout); } } @@ -433,25 +429,25 @@ impl<'d, T: Instance> Twis<'d, T> { let deadline = Instant::now() + timeout; loop { // stop if an error occurred - if r.events_error.read().bits() != 0 { - r.events_error.reset(); - r.tasks_stop.write(|w| unsafe { w.bits(1) }); + if r.events_error().read() != 0 { + r.events_error().write_value(0); + r.tasks_stop().write_value(1); return Err(Error::Overflow); - } else if r.events_stopped.read().bits() != 0 { - r.events_stopped.reset(); + } else if r.events_stopped().read() != 0 { + r.events_stopped().write_value(0); return match status { Status::Read => Ok(Command::Read), Status::Write => { - let n = r.rxd.amount.read().bits() as usize; + let n = r.rxd().amount().read().0 as usize; Ok(Command::Write(n)) } }; - } else if r.events_read.read().bits() != 0 { - r.events_read.reset(); - let n = r.rxd.amount.read().bits() as usize; + } else if r.events_read().read() != 0 { + r.events_read().write_value(0); + let n = r.rxd().amount().read().0 as usize; return Ok(Command::WriteRead(n)); } else if Instant::now() > deadline { - r.tasks_stop.write(|w| unsafe { w.bits(1) }); + r.tasks_stop().write_value(1); return Err(Error::Timeout); } } @@ -466,20 +462,20 @@ impl<'d, T: Instance> Twis<'d, T> { s.waker.register(cx.waker()); // stop if an error occurred - if r.events_error.read().bits() != 0 { - r.events_error.reset(); - r.tasks_stop.write(|w| unsafe { w.bits(1) }); - let errorsrc = r.errorsrc.read(); - if errorsrc.overread().is_detected() { + if r.events_error().read() != 0 { + r.events_error().write_value(0); + r.tasks_stop().write_value(1); + let errorsrc = r.errorsrc().read(); + if errorsrc.overread() { return Poll::Ready(Err(Error::OverRead)); - } else if errorsrc.dnack().is_received() { + } else if errorsrc.dnack() { return Poll::Ready(Err(Error::DataNack)); } else { return Poll::Ready(Err(Error::Bus)); } - } else if r.events_stopped.read().bits() != 0 { - r.events_stopped.reset(); - let n = r.txd.amount.read().bits() as usize; + } else if r.events_stopped().read() != 0 { + r.events_stopped().write_value(0); + let n = r.txd().amount().read().0 as usize; return Poll::Ready(Ok(n)); } @@ -496,18 +492,18 @@ impl<'d, T: Instance> Twis<'d, T> { s.waker.register(cx.waker()); // stop if an error occurred - if r.events_error.read().bits() != 0 { - r.events_error.reset(); - r.tasks_stop.write(|w| unsafe { w.bits(1) }); + if r.events_error().read() != 0 { + r.events_error().write_value(0); + r.tasks_stop().write_value(1); return Poll::Ready(Err(Error::Overflow)); - } else if r.events_read.read().bits() != 0 { - r.events_read.reset(); + } else if r.events_read().read() != 0 { + r.events_read().write_value(0); return Poll::Ready(Ok(Status::Read)); - } else if r.events_write.read().bits() != 0 { - r.events_write.reset(); + } else if r.events_write().read() != 0 { + r.events_write().write_value(0); return Poll::Ready(Ok(Status::Write)); - } else if r.events_stopped.read().bits() != 0 { - r.events_stopped.reset(); + } else if r.events_stopped().read() != 0 { + r.events_stopped().write_value(0); return Poll::Ready(Err(Error::Bus)); } Poll::Pending @@ -523,22 +519,22 @@ impl<'d, T: Instance> Twis<'d, T> { s.waker.register(cx.waker()); // stop if an error occurred - if r.events_error.read().bits() != 0 { - r.events_error.reset(); - r.tasks_stop.write(|w| unsafe { w.bits(1) }); + if r.events_error().read() != 0 { + r.events_error().write_value(0); + r.tasks_stop().write_value(1); return Poll::Ready(Err(Error::Overflow)); - } else if r.events_stopped.read().bits() != 0 { - r.events_stopped.reset(); + } else if r.events_stopped().read() != 0 { + r.events_stopped().write_value(0); return match status { Status::Read => Poll::Ready(Ok(Command::Read)), Status::Write => { - let n = r.rxd.amount.read().bits() as usize; + let n = r.rxd().amount().read().0 as usize; Poll::Ready(Ok(Command::Write(n))) } }; - } else if r.events_read.read().bits() != 0 { - r.events_read.reset(); - let n = r.rxd.amount.read().bits() as usize; + } else if r.events_read().read() != 0 { + r.events_read().write_value(0); + let n = r.rxd().amount().read().0 as usize; return Poll::Ready(Ok(Command::WriteRead(n))); } Poll::Pending @@ -554,19 +550,25 @@ impl<'d, T: Instance> Twis<'d, T> { unsafe { self.set_tx_buffer(buffer)? }; // Clear events - r.events_stopped.reset(); - r.events_error.reset(); + r.events_stopped().write_value(0); + r.events_error().write_value(0); self.clear_errorsrc(); if inten { - r.intenset.write(|w| w.stopped().set().error().set()); + r.intenset().write(|w| { + w.set_stopped(true); + w.set_error(true); + }); } else { - r.intenclr.write(|w| w.stopped().clear().error().clear()); + r.intenclr().write(|w| { + w.set_stopped(true); + w.set_error(true); + }); } // Start write operation. - r.tasks_preparetx.write(|w| unsafe { w.bits(1) }); - r.tasks_resume.write(|w| unsafe { w.bits(1) }); + r.tasks_preparetx().write_value(1); + r.tasks_resume().write_value(1); Ok(()) } @@ -591,22 +593,30 @@ impl<'d, T: Instance> Twis<'d, T> { unsafe { self.set_rx_buffer(buffer)? }; // Clear events - r.events_read.reset(); - r.events_write.reset(); - r.events_stopped.reset(); - r.events_error.reset(); + r.events_read().write_value(0); + r.events_write().write_value(0); + r.events_stopped().write_value(0); + r.events_error().write_value(0); self.clear_errorsrc(); if inten { - r.intenset - .write(|w| w.stopped().set().error().set().read().set().write().set()); + r.intenset().write(|w| { + w.set_stopped(true); + w.set_error(true); + w.set_read(true); + w.set_write(true); + }); } else { - r.intenclr - .write(|w| w.stopped().clear().error().clear().read().clear().write().clear()); + r.intenclr().write(|w| { + w.set_stopped(true); + w.set_error(true); + w.set_read(true); + w.set_write(true); + }); } // Start read operation. - r.tasks_preparerx.write(|w| unsafe { w.bits(1) }); + r.tasks_preparerx().write_value(1); Ok(()) } @@ -616,16 +626,24 @@ impl<'d, T: Instance> Twis<'d, T> { compiler_fence(SeqCst); // Clear events - r.events_read.reset(); - r.events_write.reset(); - r.events_stopped.reset(); - r.events_error.reset(); + r.events_read().write_value(0); + r.events_write().write_value(0); + r.events_stopped().write_value(0); + r.events_error().write_value(0); self.clear_errorsrc(); if inten { - r.intenset.write(|w| w.stopped().set().error().set().read().set()); + r.intenset().write(|w| { + w.set_stopped(true); + w.set_error(true); + w.set_read(true); + }); } else { - r.intenclr.write(|w| w.stopped().clear().error().clear().read().clear()); + r.intenclr().write(|w| { + w.set_stopped(true); + w.set_error(true); + w.set_read(true); + }); } Ok(()) @@ -745,10 +763,10 @@ impl<'a, T: Instance> Drop for Twis<'a, T> { // disable! let r = T::regs(); - r.enable.write(|w| w.enable().disabled()); + r.enable().write(|w| w.set_enable(vals::Enable::DISABLED)); - gpio::deconfigure_pin(r.psel.sda.read().bits()); - gpio::deconfigure_pin(r.psel.scl.read().bits()); + gpio::deconfigure_pin(r.psel().sda().read()); + gpio::deconfigure_pin(r.psel().scl().read()); trace!("twis drop: done"); } @@ -767,7 +785,7 @@ impl State { } pub(crate) trait SealedInstance { - fn regs() -> &'static pac::twis0::RegisterBlock; + fn regs() -> pac::twis::Twis; fn state() -> &'static State; } @@ -781,8 +799,8 @@ pub trait Instance: Peripheral

+ SealedInstance + 'static { macro_rules! impl_twis { ($type:ident, $pac_type:ident, $irq:ident) => { impl crate::twis::SealedInstance for peripherals::$type { - fn regs() -> &'static pac::twis0::RegisterBlock { - unsafe { &*pac::$pac_type::ptr() } + fn regs() -> pac::twis::Twis { + pac::$pac_type } fn state() -> &'static crate::twis::State { static STATE: crate::twis::State = crate::twis::State::new(); diff --git a/embassy-nrf/src/uarte.rs b/embassy-nrf/src/uarte.rs index 4cf193617..2a59d029d 100644 --- a/embassy-nrf/src/uarte.rs +++ b/embassy-nrf/src/uarte.rs @@ -21,13 +21,14 @@ use core::task::Poll; use embassy_hal_internal::drop::OnDrop; use embassy_hal_internal::{into_ref, PeripheralRef}; use embassy_sync::waitqueue::AtomicWaker; -use pac::uarte0::RegisterBlock; // Re-export SVD variants to allow user to directly set values. -pub use pac::uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Parity}; +pub use pac::uarte::vals::{Baudrate, ConfigParity as Parity}; use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE}; -use crate::gpio::{self, AnyPin, Pin as GpioPin, PselBits, SealedPin as _}; +use crate::gpio::{self, AnyPin, Pin as GpioPin, PselBits, SealedPin as _, DISCONNECTED}; use crate::interrupt::typelevel::Interrupt; +use crate::pac::gpio::vals as gpiovals; +use crate::pac::uarte::vals; use crate::ppi::{AnyConfigurableChannel, ConfigurableChannel, Event, Ppi, Task}; use crate::timer::{Frequency, Instance as TimerInstance, Timer}; use crate::util::slice_in_ram_or; @@ -54,7 +55,7 @@ impl Default for Config { bitflags::bitflags! { /// Error source flags - pub struct ErrorSource: u32 { + pub(crate) struct ErrorSource: u32 { /// Buffer overrun const OVERRUN = 0x01; /// Parity error @@ -112,20 +113,20 @@ impl interrupt::typelevel::Handler for InterruptHandl let r = T::regs(); let s = T::state(); - let endrx = r.events_endrx.read().bits(); - let error = r.events_error.read().bits(); + let endrx = r.events_endrx().read(); + let error = r.events_error().read(); if endrx != 0 || error != 0 { s.rx_waker.wake(); if endrx != 0 { - r.intenclr.write(|w| w.endrx().clear()); + r.intenclr().write(|w| w.set_endrx(true)); } if error != 0 { - r.intenclr.write(|w| w.error().clear()); + r.intenclr().write(|w| w.set_error(true)); } } - if r.events_endtx.read().bits() != 0 { + if r.events_endtx().read() != 0 { s.tx_waker.wake(); - r.intenclr.write(|w| w.endtx().clear()); + r.intenclr().write(|w| w.set_endtx(true)); } } } @@ -200,28 +201,12 @@ impl<'d, T: Instance> Uarte<'d, T> { _ => panic!("RTS and CTS pins must be either both set or none set."), }; configure(r, config, hardware_flow_control); - - rxd.conf().write(|w| w.input().connect().drive().h0h1()); - r.psel.rxd.write(|w| unsafe { w.bits(rxd.psel_bits()) }); - - txd.set_high(); - txd.conf().write(|w| w.dir().output().drive().h0h1()); - r.psel.txd.write(|w| unsafe { w.bits(txd.psel_bits()) }); - - if let Some(pin) = &cts { - pin.conf().write(|w| w.input().connect().drive().h0h1()); - } - r.psel.cts.write(|w| unsafe { w.bits(cts.psel_bits()) }); - - if let Some(pin) = &rts { - pin.set_high(); - pin.conf().write(|w| w.dir().output().drive().h0h1()); - } - r.psel.rts.write(|w| unsafe { w.bits(rts.psel_bits()) }); + configure_rx_pins(r, rxd, rts); + configure_tx_pins(r, txd, cts); T::Interrupt::unpend(); unsafe { T::Interrupt::enable() }; - r.enable.write(|w| w.enable().enabled()); + r.enable().write(|w| w.set_enable(vals::Enable::ENABLED)); let s = T::state(); s.tx_rx_refcount.store(2, Ordering::Relaxed); @@ -264,7 +249,7 @@ impl<'d, T: Instance> Uarte<'d, T> { /// Return the endtx event for use with PPI pub fn event_endtx(&self) -> Event { let r = T::regs(); - Event::from_reg(&r.events_endtx) + Event::from_reg(r.events_endtx()) } /// Read bytes until the buffer is filled. @@ -298,27 +283,72 @@ impl<'d, T: Instance> Uarte<'d, T> { } } -pub(crate) fn configure(r: &RegisterBlock, config: Config, hardware_flow_control: bool) { - r.config.write(|w| { - w.hwfc().bit(hardware_flow_control); - w.parity().variant(config.parity); - w +pub(crate) fn configure_tx_pins( + r: pac::uarte::Uarte, + txd: PeripheralRef<'_, AnyPin>, + cts: Option>, +) { + txd.set_high(); + txd.conf().write(|w| { + w.set_dir(gpiovals::Dir::OUTPUT); + w.set_input(gpiovals::Input::DISCONNECT); + w.set_drive(gpiovals::Drive::H0H1); }); - r.baudrate.write(|w| w.baudrate().variant(config.baudrate)); + r.psel().txd().write_value(txd.psel_bits()); + + if let Some(pin) = &cts { + pin.conf().write(|w| { + w.set_dir(gpiovals::Dir::INPUT); + w.set_input(gpiovals::Input::CONNECT); + w.set_drive(gpiovals::Drive::H0H1); + }); + } + r.psel().cts().write_value(cts.psel_bits()); +} + +pub(crate) fn configure_rx_pins( + r: pac::uarte::Uarte, + rxd: PeripheralRef<'_, AnyPin>, + rts: Option>, +) { + rxd.conf().write(|w| { + w.set_dir(gpiovals::Dir::INPUT); + w.set_input(gpiovals::Input::CONNECT); + w.set_drive(gpiovals::Drive::H0H1); + }); + r.psel().rxd().write_value(rxd.psel_bits()); + + if let Some(pin) = &rts { + pin.set_high(); + pin.conf().write(|w| { + w.set_dir(gpiovals::Dir::OUTPUT); + w.set_input(gpiovals::Input::DISCONNECT); + w.set_drive(gpiovals::Drive::H0H1); + }); + } + r.psel().rts().write_value(rts.psel_bits()); +} + +pub(crate) fn configure(r: pac::uarte::Uarte, config: Config, hardware_flow_control: bool) { + r.config().write(|w| { + w.set_hwfc(hardware_flow_control); + w.set_parity(config.parity); + }); + r.baudrate().write(|w| w.set_baudrate(config.baudrate)); // Disable all interrupts - r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) }); + r.intenclr().write(|w| w.0 = 0xFFFF_FFFF); // Reset rxstarted, txstarted. These are used by drop to know whether a transfer was // stopped midway or not. - r.events_rxstarted.reset(); - r.events_txstarted.reset(); + r.events_rxstarted().write_value(0); + r.events_txstarted().write_value(0); // reset all pins - r.psel.txd.write(|w| w.connect().disconnected()); - r.psel.rxd.write(|w| w.connect().disconnected()); - r.psel.cts.write(|w| w.connect().disconnected()); - r.psel.rts.write(|w| w.connect().disconnected()); + r.psel().txd().write_value(DISCONNECTED); + r.psel().rxd().write_value(DISCONNECTED); + r.psel().cts().write_value(DISCONNECTED); + r.psel().rts().write_value(DISCONNECTED); apply_workaround_for_enable_anomaly(r); } @@ -356,19 +386,11 @@ impl<'d, T: Instance> UarteTx<'d, T> { let r = T::regs(); configure(r, config, cts.is_some()); - - txd.set_high(); - txd.conf().write(|w| w.dir().output().drive().s0s1()); - r.psel.txd.write(|w| unsafe { w.bits(txd.psel_bits()) }); - - if let Some(pin) = &cts { - pin.conf().write(|w| w.input().connect().drive().h0h1()); - } - r.psel.cts.write(|w| unsafe { w.bits(cts.psel_bits()) }); + configure_tx_pins(r, txd, cts); T::Interrupt::unpend(); unsafe { T::Interrupt::enable() }; - r.enable.write(|w| w.enable().enabled()); + r.enable().write(|w| w.set_enable(vals::Enable::ENABLED)); let s = T::state(); s.tx_rx_refcount.store(1, Ordering::Relaxed); @@ -410,29 +432,29 @@ impl<'d, T: Instance> UarteTx<'d, T> { let drop = OnDrop::new(move || { trace!("write drop: stopping"); - r.intenclr.write(|w| w.endtx().clear()); - r.events_txstopped.reset(); - r.tasks_stoptx.write(|w| unsafe { w.bits(1) }); + r.intenclr().write(|w| w.set_endtx(true)); + r.events_txstopped().write_value(0); + r.tasks_stoptx().write_value(1); // TX is stopped almost instantly, spinning is fine. - while r.events_endtx.read().bits() == 0 {} + while r.events_endtx().read() == 0 {} trace!("write drop: stopped"); }); - r.txd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) }); - r.txd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) }); + r.txd().ptr().write_value(ptr as u32); + r.txd().maxcnt().write(|w| w.set_maxcnt(len as _)); - r.events_endtx.reset(); - r.intenset.write(|w| w.endtx().set()); + r.events_endtx().write_value(0); + r.intenset().write(|w| w.set_endtx(true)); compiler_fence(Ordering::SeqCst); trace!("starttx"); - r.tasks_starttx.write(|w| unsafe { w.bits(1) }); + r.tasks_starttx().write_value(1); poll_fn(|cx| { s.tx_waker.register(cx.waker()); - if r.events_endtx.read().bits() != 0 { + if r.events_endtx().read() != 0 { return Poll::Ready(()); } Poll::Pending @@ -440,7 +462,7 @@ impl<'d, T: Instance> UarteTx<'d, T> { .await; compiler_fence(Ordering::SeqCst); - r.events_txstarted.reset(); + r.events_txstarted().write_value(0); drop.defuse(); Ok(()) @@ -476,21 +498,21 @@ impl<'d, T: Instance> UarteTx<'d, T> { let r = T::regs(); - r.txd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) }); - r.txd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) }); + r.txd().ptr().write_value(ptr as u32); + r.txd().maxcnt().write(|w| w.set_maxcnt(len as _)); - r.events_endtx.reset(); - r.intenclr.write(|w| w.endtx().clear()); + r.events_endtx().write_value(0); + r.intenclr().write(|w| w.set_endtx(true)); compiler_fence(Ordering::SeqCst); trace!("starttx"); - r.tasks_starttx.write(|w| unsafe { w.bits(1) }); + r.tasks_starttx().write_value(1); - while r.events_endtx.read().bits() == 0 {} + while r.events_endtx().read() == 0 {} compiler_fence(Ordering::SeqCst); - r.events_txstarted.reset(); + r.events_txstarted().write_value(0); Ok(()) } @@ -502,11 +524,11 @@ impl<'a, T: Instance> Drop for UarteTx<'a, T> { let r = T::regs(); - let did_stoptx = r.events_txstarted.read().bits() != 0; + let did_stoptx = r.events_txstarted().read() != 0; trace!("did_stoptx {}", did_stoptx); // Wait for txstopped, if needed. - while did_stoptx && r.events_txstopped.read().bits() == 0 {} + while did_stoptx && r.events_txstopped().read() == 0 {} let s = T::state(); @@ -541,9 +563,9 @@ impl<'d, T: Instance> UarteRx<'d, T> { /// Check for errors and clear the error register if an error occured. fn check_and_clear_errors(&mut self) -> Result<(), Error> { let r = T::regs(); - let err_bits = r.errorsrc.read().bits(); - r.errorsrc.write(|w| unsafe { w.bits(err_bits) }); - ErrorSource::from_bits_truncate(err_bits).check() + let err_bits = r.errorsrc().read(); + r.errorsrc().write_value(err_bits); + ErrorSource::from_bits_truncate(err_bits.0).check() } fn new_inner( @@ -555,19 +577,11 @@ impl<'d, T: Instance> UarteRx<'d, T> { let r = T::regs(); configure(r, config, rts.is_some()); - - rxd.conf().write(|w| w.input().connect().drive().h0h1()); - r.psel.rxd.write(|w| unsafe { w.bits(rxd.psel_bits()) }); - - if let Some(pin) = &rts { - pin.set_high(); - pin.conf().write(|w| w.dir().output().drive().h0h1()); - } - r.psel.rts.write(|w| unsafe { w.bits(rts.psel_bits()) }); + configure_rx_pins(r, rxd, rts); T::Interrupt::unpend(); unsafe { T::Interrupt::enable() }; - r.enable.write(|w| w.enable().enabled()); + r.enable().write(|w| w.set_enable(vals::Enable::ENABLED)); let s = T::state(); s.tx_rx_refcount.store(1, Ordering::Relaxed); @@ -594,8 +608,8 @@ impl<'d, T: Instance> UarteRx<'d, T> { // We want to stop RX if line is idle for 2 bytes worth of time // That is 20 bits (each byte is 1 start bit + 8 data bits + 1 stop bit) // This gives us the amount of 16M ticks for 20 bits. - let baudrate = r.baudrate.read().baudrate().variant().unwrap(); - let timeout = 0x8000_0000 / (baudrate as u32 / 40); + let baudrate = r.baudrate().read().baudrate(); + let timeout = 0x8000_0000 / (baudrate.to_bits() / 40); timer.set_frequency(Frequency::F16MHz); timer.cc(0).write(timeout); @@ -604,7 +618,7 @@ impl<'d, T: Instance> UarteRx<'d, T> { let mut ppi_ch1 = Ppi::new_one_to_two( ppi_ch1.map_into(), - Event::from_reg(&r.events_rxdrdy), + Event::from_reg(r.events_rxdrdy()), timer.task_clear(), timer.task_start(), ); @@ -613,7 +627,7 @@ impl<'d, T: Instance> UarteRx<'d, T> { let mut ppi_ch2 = Ppi::new_one_to_one( ppi_ch2.map_into(), timer.cc(0).event_compare(), - Task::from_reg(&r.tasks_stoprx), + Task::from_reg(r.tasks_stoprx()), ); ppi_ch2.enable(); @@ -643,43 +657,42 @@ impl<'d, T: Instance> UarteRx<'d, T> { let drop = OnDrop::new(move || { trace!("read drop: stopping"); - r.intenclr.write(|w| { - w.endrx().clear(); - w.error().clear() + r.intenclr().write(|w| { + w.set_endrx(true); + w.set_error(true); }); - r.events_rxto.reset(); - r.events_error.reset(); - r.errorsrc.reset(); - r.tasks_stoprx.write(|w| unsafe { w.bits(1) }); + r.events_rxto().write_value(0); + r.events_error().write_value(0); + r.tasks_stoprx().write_value(1); - while r.events_endrx.read().bits() == 0 {} + while r.events_endrx().read() == 0 {} trace!("read drop: stopped"); }); - r.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) }); - r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) }); + r.rxd().ptr().write_value(ptr as u32); + r.rxd().maxcnt().write(|w| w.set_maxcnt(len as _)); - r.events_endrx.reset(); - r.events_error.reset(); - r.intenset.write(|w| { - w.endrx().set(); - w.error().set() + r.events_endrx().write_value(0); + r.events_error().write_value(0); + r.intenset().write(|w| { + w.set_endrx(true); + w.set_error(true); }); compiler_fence(Ordering::SeqCst); trace!("startrx"); - r.tasks_startrx.write(|w| unsafe { w.bits(1) }); + r.tasks_startrx().write_value(1); let result = poll_fn(|cx| { s.rx_waker.register(cx.waker()); if let Err(e) = self.check_and_clear_errors() { - r.tasks_stoprx.write(|w| unsafe { w.bits(1) }); + r.tasks_stoprx().write_value(1); return Poll::Ready(Err(e)); } - if r.events_endrx.read().bits() != 0 { + if r.events_endrx().read() != 0 { return Poll::Ready(Ok(())); } Poll::Pending @@ -687,7 +700,7 @@ impl<'d, T: Instance> UarteRx<'d, T> { .await; compiler_fence(Ordering::SeqCst); - r.events_rxstarted.reset(); + r.events_rxstarted().write_value(0); drop.defuse(); result @@ -707,25 +720,25 @@ impl<'d, T: Instance> UarteRx<'d, T> { let r = T::regs(); - r.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) }); - r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) }); + r.rxd().ptr().write_value(ptr as u32); + r.rxd().maxcnt().write(|w| w.set_maxcnt(len as _)); - r.events_endrx.reset(); - r.events_error.reset(); - r.intenclr.write(|w| { - w.endrx().clear(); - w.error().clear() + r.events_endrx().write_value(0); + r.events_error().write_value(0); + r.intenclr().write(|w| { + w.set_endrx(true); + w.set_error(true); }); compiler_fence(Ordering::SeqCst); trace!("startrx"); - r.tasks_startrx.write(|w| unsafe { w.bits(1) }); + r.tasks_startrx().write_value(1); - while r.events_endrx.read().bits() == 0 && r.events_error.read().bits() == 0 {} + while r.events_endrx().read() == 0 && r.events_error().read() == 0 {} compiler_fence(Ordering::SeqCst); - r.events_rxstarted.reset(); + r.events_rxstarted().write_value(0); self.check_and_clear_errors() } @@ -737,11 +750,11 @@ impl<'a, T: Instance> Drop for UarteRx<'a, T> { let r = T::regs(); - let did_stoprx = r.events_rxstarted.read().bits() != 0; + let did_stoprx = r.events_rxstarted().read() != 0; trace!("did_stoprx {}", did_stoprx); // Wait for rxto, if needed. - while did_stoprx && r.events_rxto.read().bits() == 0 {} + while did_stoprx && r.events_rxto().read() == 0 {} let s = T::state(); @@ -794,39 +807,39 @@ impl<'d, T: Instance, U: TimerInstance> UarteRxWithIdle<'d, T, U> { let drop = OnDrop::new(|| { self.timer.stop(); - r.intenclr.write(|w| { - w.endrx().clear(); - w.error().clear() + r.intenclr().write(|w| { + w.set_endrx(true); + w.set_error(true); }); - r.events_rxto.reset(); - r.events_error.reset(); - r.tasks_stoprx.write(|w| unsafe { w.bits(1) }); + r.events_rxto().write_value(0); + r.events_error().write_value(0); + r.tasks_stoprx().write_value(1); - while r.events_endrx.read().bits() == 0 {} + while r.events_endrx().read() == 0 {} }); - r.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) }); - r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) }); + r.rxd().ptr().write_value(ptr as u32); + r.rxd().maxcnt().write(|w| w.set_maxcnt(len as _)); - r.events_endrx.reset(); - r.events_error.reset(); - r.intenset.write(|w| { - w.endrx().set(); - w.error().set() + r.events_endrx().write_value(0); + r.events_error().write_value(0); + r.intenset().write(|w| { + w.set_endrx(true); + w.set_error(true); }); compiler_fence(Ordering::SeqCst); - r.tasks_startrx.write(|w| unsafe { w.bits(1) }); + r.tasks_startrx().write_value(1); let result = poll_fn(|cx| { s.rx_waker.register(cx.waker()); if let Err(e) = self.rx.check_and_clear_errors() { - r.tasks_stoprx.write(|w| unsafe { w.bits(1) }); + r.tasks_stoprx().write_value(1); return Poll::Ready(Err(e)); } - if r.events_endrx.read().bits() != 0 { + if r.events_endrx().read() != 0 { return Poll::Ready(Ok(())); } @@ -835,10 +848,10 @@ impl<'d, T: Instance, U: TimerInstance> UarteRxWithIdle<'d, T, U> { .await; compiler_fence(Ordering::SeqCst); - let n = r.rxd.amount.read().amount().bits() as usize; + let n = r.rxd().amount().read().0 as usize; self.timer.stop(); - r.events_rxstarted.reset(); + r.events_rxstarted().write_value(0); drop.defuse(); @@ -863,56 +876,57 @@ impl<'d, T: Instance, U: TimerInstance> UarteRxWithIdle<'d, T, U> { self.ppi_ch1.enable(); - r.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) }); - r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(len as _) }); + r.rxd().ptr().write_value(ptr as u32); + r.rxd().maxcnt().write(|w| w.set_maxcnt(len as _)); - r.events_endrx.reset(); - r.events_error.reset(); - r.intenclr.write(|w| { - w.endrx().clear(); - w.error().clear() + r.events_endrx().write_value(0); + r.events_error().write_value(0); + r.intenclr().write(|w| { + w.set_endrx(true); + w.set_error(true); }); compiler_fence(Ordering::SeqCst); - r.tasks_startrx.write(|w| unsafe { w.bits(1) }); + r.tasks_startrx().write_value(1); - while r.events_endrx.read().bits() == 0 && r.events_error.read().bits() == 0 {} + while r.events_endrx().read() == 0 && r.events_error().read() == 0 {} compiler_fence(Ordering::SeqCst); - let n = r.rxd.amount.read().amount().bits() as usize; + let n = r.rxd().amount().read().0 as usize; self.timer.stop(); - r.events_rxstarted.reset(); + r.events_rxstarted().write_value(0); self.rx.check_and_clear_errors().map(|_| n) } } #[cfg(not(any(feature = "_nrf9160", feature = "_nrf5340")))] -pub(crate) fn apply_workaround_for_enable_anomaly(_r: &crate::pac::uarte0::RegisterBlock) { +pub(crate) fn apply_workaround_for_enable_anomaly(_r: pac::uarte::Uarte) { // Do nothing } #[cfg(any(feature = "_nrf9160", feature = "_nrf5340"))] -pub(crate) fn apply_workaround_for_enable_anomaly(r: &crate::pac::uarte0::RegisterBlock) { +pub(crate) fn apply_workaround_for_enable_anomaly(r: pac::uarte::Uarte) { // Apply workaround for anomalies: // - nRF9160 - anomaly 23 // - nRF5340 - anomaly 44 - let rxenable_reg: *const u32 = ((r as *const _ as usize) + 0x564) as *const u32; - let txenable_reg: *const u32 = ((r as *const _ as usize) + 0x568) as *const u32; + let rp = r.as_ptr() as *mut u32; + let rxenable_reg = unsafe { rp.add(0x564 / 4) }; + let txenable_reg = unsafe { rp.add(0x568 / 4) }; // NB Safety: This is taken from Nordic's driver - // https://github.com/NordicSemiconductor/nrfx/blob/master/drivers/src/nrfx_uarte.c#L197 if unsafe { core::ptr::read_volatile(txenable_reg) } == 1 { - r.tasks_stoptx.write(|w| unsafe { w.bits(1) }); + r.tasks_stoptx().write_value(1); } // NB Safety: This is taken from Nordic's driver - // https://github.com/NordicSemiconductor/nrfx/blob/master/drivers/src/nrfx_uarte.c#L197 if unsafe { core::ptr::read_volatile(rxenable_reg) } == 1 { - r.enable.write(|w| w.enable().enabled()); - r.tasks_stoprx.write(|w| unsafe { w.bits(1) }); + r.enable().write(|w| w.set_enable(vals::Enable::ENABLED)); + r.tasks_stoprx().write_value(1); let mut workaround_succeded = false; // The UARTE is able to receive up to four bytes after the STOPRX task has been triggered. @@ -933,23 +947,23 @@ pub(crate) fn apply_workaround_for_enable_anomaly(r: &crate::pac::uarte0::Regist panic!("Failed to apply workaround for UART"); } - let errors = r.errorsrc.read().bits(); - // NB Safety: safe to write back the bits we just read to clear them - r.errorsrc.write(|w| unsafe { w.bits(errors) }); - r.enable.write(|w| w.enable().disabled()); + // write back the bits we just read to clear them + let errors = r.errorsrc().read(); + r.errorsrc().write_value(errors); + r.enable().write(|w| w.set_enable(vals::Enable::DISABLED)); } } -pub(crate) fn drop_tx_rx(r: &pac::uarte0::RegisterBlock, s: &State) { +pub(crate) fn drop_tx_rx(r: pac::uarte::Uarte, s: &State) { if s.tx_rx_refcount.fetch_sub(1, Ordering::Relaxed) == 1 { // Finally we can disable, and we do so for the peripheral // i.e. not just rx concerns. - r.enable.write(|w| w.enable().disabled()); + r.enable().write(|w| w.set_enable(vals::Enable::DISABLED)); - gpio::deconfigure_pin(r.psel.rxd.read().bits()); - gpio::deconfigure_pin(r.psel.txd.read().bits()); - gpio::deconfigure_pin(r.psel.rts.read().bits()); - gpio::deconfigure_pin(r.psel.cts.read().bits()); + gpio::deconfigure_pin(r.psel().rxd().read()); + gpio::deconfigure_pin(r.psel().txd().read()); + gpio::deconfigure_pin(r.psel().rts().read()); + gpio::deconfigure_pin(r.psel().cts().read()); trace!("uarte tx and rx drop: done"); } @@ -971,7 +985,7 @@ impl State { } pub(crate) trait SealedInstance { - fn regs() -> &'static pac::uarte0::RegisterBlock; + fn regs() -> pac::uarte::Uarte; fn state() -> &'static State; fn buffered_state() -> &'static crate::buffered_uarte::State; } @@ -986,8 +1000,8 @@ pub trait Instance: Peripheral

+ SealedInstance + 'static + Send { macro_rules! impl_uarte { ($type:ident, $pac_type:ident, $irq:ident) => { impl crate::uarte::SealedInstance for peripherals::$type { - fn regs() -> &'static pac::uarte0::RegisterBlock { - unsafe { &*pac::$pac_type::ptr() } + fn regs() -> pac::uarte::Uarte { + pac::$pac_type } fn state() -> &'static crate::uarte::State { static STATE: crate::uarte::State = crate::uarte::State::new(); diff --git a/embassy-nrf/src/usb/mod.rs b/embassy-nrf/src/usb/mod.rs index 8cbb1a350..52c9c532b 100644 --- a/embassy-nrf/src/usb/mod.rs +++ b/embassy-nrf/src/usb/mod.rs @@ -15,10 +15,10 @@ use embassy_hal_internal::{into_ref, PeripheralRef}; use embassy_sync::waitqueue::AtomicWaker; use embassy_usb_driver as driver; use embassy_usb_driver::{Direction, EndpointAddress, EndpointError, EndpointInfo, EndpointType, Event, Unsupported}; -use pac::usbd::RegisterBlock; use self::vbus_detect::VbusDetect; use crate::interrupt::typelevel::Interrupt; +use crate::pac::usbd::vals; use crate::util::slice_in_ram; use crate::{interrupt, pac, Peripheral}; @@ -38,19 +38,19 @@ impl interrupt::typelevel::Handler for InterruptHandl unsafe fn on_interrupt() { let regs = T::regs(); - if regs.events_usbreset.read().bits() != 0 { - regs.intenclr.write(|w| w.usbreset().clear()); + if regs.events_usbreset().read() != 0 { + regs.intenclr().write(|w| w.set_usbreset(true)); BUS_WAKER.wake(); EP0_WAKER.wake(); } - if regs.events_ep0setup.read().bits() != 0 { - regs.intenclr.write(|w| w.ep0setup().clear()); + if regs.events_ep0setup().read() != 0 { + regs.intenclr().write(|w| w.set_ep0setup(true)); EP0_WAKER.wake(); } - if regs.events_ep0datadone.read().bits() != 0 { - regs.intenclr.write(|w| w.ep0datadone().clear()); + if regs.events_ep0datadone().read() != 0 { + regs.intenclr().write(|w| w.set_ep0datadone(true)); EP0_WAKER.wake(); } @@ -63,22 +63,22 @@ impl interrupt::typelevel::Handler for InterruptHandl // Therefore, it's fine to clear just the event, and let main thread // check the individual bits in EVENTCAUSE and EPDATASTATUS. It // doesn't cause an infinite irq loop. - if regs.events_usbevent.read().bits() != 0 { - regs.events_usbevent.reset(); + if regs.events_usbevent().read() != 0 { + regs.events_usbevent().write_value(0); BUS_WAKER.wake(); } - if regs.events_epdata.read().bits() != 0 { - regs.events_epdata.reset(); + if regs.events_epdata().read() != 0 { + regs.events_epdata().write_value(0); - let r = regs.epdatastatus.read().bits(); - regs.epdatastatus.write(|w| unsafe { w.bits(r) }); - READY_ENDPOINTS.fetch_or(r, Ordering::AcqRel); + let r = regs.epdatastatus().read(); + regs.epdatastatus().write_value(r); + READY_ENDPOINTS.fetch_or(r.0, Ordering::AcqRel); for i in 1..=7 { - if r & In::mask(i) != 0 { + if r.0 & In::mask(i) != 0 { In::waker(i).wake(); } - if r & Out::mask(i) != 0 { + if r.0 & Out::mask(i) != 0 { Out::waker(i).wake(); } } @@ -181,35 +181,34 @@ impl<'d, T: Instance, V: VbusDetect> driver::Bus for Bus<'d, T, V> { errata::pre_enable(); - regs.enable.write(|w| w.enable().enabled()); + regs.enable().write(|w| w.set_enable(true)); // Wait until the peripheral is ready. - regs.intenset.write(|w| w.usbevent().set_bit()); + regs.intenset().write(|w| w.set_usbevent(true)); poll_fn(|cx| { BUS_WAKER.register(cx.waker()); - if regs.eventcause.read().ready().is_ready() { + if regs.eventcause().read().ready() { Poll::Ready(()) } else { Poll::Pending } }) .await; - regs.eventcause.write(|w| w.ready().clear_bit_by_one()); + regs.eventcause().write(|w| w.set_ready(true)); errata::post_enable(); unsafe { NVIC::unmask(pac::Interrupt::USBD) }; - regs.intenset.write(|w| { - w.usbreset().set_bit(); - w.usbevent().set_bit(); - w.epdata().set_bit(); - w + regs.intenset().write(|w| { + w.set_usbreset(true); + w.set_usbevent(true); + w.set_epdata(true); }); if self.vbus_detect.wait_power_ready().await.is_ok() { // Enable the USB pullup, allowing enumeration. - regs.usbpullup.write(|w| w.connect().enabled()); + regs.usbpullup().write(|w| w.set_connect(true)); trace!("enabled"); } else { trace!("usb power not ready due to usb removal"); @@ -218,7 +217,7 @@ impl<'d, T: Instance, V: VbusDetect> driver::Bus for Bus<'d, T, V> { async fn disable(&mut self) { let regs = T::regs(); - regs.enable.write(|x| x.enable().disabled()); + regs.enable().write(|x| x.set_enable(false)); } async fn poll(&mut self) -> Event { @@ -226,13 +225,13 @@ impl<'d, T: Instance, V: VbusDetect> driver::Bus for Bus<'d, T, V> { BUS_WAKER.register(cx.waker()); let regs = T::regs(); - if regs.events_usbreset.read().bits() != 0 { - regs.events_usbreset.reset(); - regs.intenset.write(|w| w.usbreset().set()); + if regs.events_usbreset().read() != 0 { + regs.events_usbreset().write_value(0); + regs.intenset().write(|w| w.set_usbreset(true)); // Disable all endpoints except EP0 - regs.epinen.write(|w| unsafe { w.bits(0x01) }); - regs.epouten.write(|w| unsafe { w.bits(0x01) }); + regs.epinen().write(|w| w.0 = 0x01); + regs.epouten().write(|w| w.0 = 0x01); READY_ENDPOINTS.store(In::mask(0), Ordering::Release); for i in 1..=7 { In::waker(i).wake(); @@ -242,27 +241,27 @@ impl<'d, T: Instance, V: VbusDetect> driver::Bus for Bus<'d, T, V> { return Poll::Ready(Event::Reset); } - let r = regs.eventcause.read(); + let r = regs.eventcause().read(); - if r.isooutcrc().bit() { - regs.eventcause.write(|w| w.isooutcrc().detected()); + if r.isooutcrc() { + regs.eventcause().write(|w| w.set_isooutcrc(true)); trace!("USB event: isooutcrc"); } - if r.usbwuallowed().bit() { - regs.eventcause.write(|w| w.usbwuallowed().allowed()); + if r.usbwuallowed() { + regs.eventcause().write(|w| w.set_usbwuallowed(true)); trace!("USB event: usbwuallowed"); } - if r.suspend().bit() { - regs.eventcause.write(|w| w.suspend().detected()); - regs.lowpower.write(|w| w.lowpower().low_power()); + if r.suspend() { + regs.eventcause().write(|w| w.set_suspend(true)); + regs.lowpower().write(|w| w.set_lowpower(vals::Lowpower::LOW_POWER)); return Poll::Ready(Event::Suspend); } - if r.resume().bit() { - regs.eventcause.write(|w| w.resume().detected()); + if r.resume() { + regs.eventcause().write(|w| w.set_resume(true)); return Poll::Ready(Event::Resume); } - if r.ready().bit() { - regs.eventcause.write(|w| w.ready().ready()); + if r.ready() { + regs.eventcause().write(|w| w.set_ready(true)); trace!("USB event: ready"); } @@ -284,16 +283,19 @@ impl<'d, T: Instance, V: VbusDetect> driver::Bus for Bus<'d, T, V> { fn endpoint_set_stalled(&mut self, ep_addr: EndpointAddress, stalled: bool) { let regs = T::regs(); - unsafe { - if ep_addr.index() == 0 { - regs.tasks_ep0stall.write(|w| w.tasks_ep0stall().bit(stalled)); - } else { - regs.epstall.write(|w| { - w.ep().bits(ep_addr.index() as u8 & 0b111); - w.io().bit(ep_addr.is_in()); - w.stall().bit(stalled) - }); + if ep_addr.index() == 0 { + if stalled { + regs.tasks_ep0stall().write_value(1); } + } else { + regs.epstall().write(|w| { + w.set_ep(ep_addr.index() as u8 & 0b111); + w.set_io(match ep_addr.direction() { + Direction::In => vals::Io::IN, + Direction::Out => vals::Io::OUT, + }); + w.set_stall(stalled); + }); } } @@ -301,8 +303,8 @@ impl<'d, T: Instance, V: VbusDetect> driver::Bus for Bus<'d, T, V> { let regs = T::regs(); let i = ep_addr.index(); match ep_addr.direction() { - Direction::Out => regs.halted.epout[i].read().getstatus().is_halted(), - Direction::In => regs.halted.epin[i].read().getstatus().is_halted(), + Direction::Out => regs.halted().epout(i).read().getstatus() == vals::Getstatus::HALTED, + Direction::In => regs.halted().epin(i).read().getstatus() == vals::Getstatus::HALTED, } } @@ -317,15 +319,13 @@ impl<'d, T: Instance, V: VbusDetect> driver::Bus for Bus<'d, T, V> { match ep_addr.direction() { Direction::In => { let mut was_enabled = false; - regs.epinen.modify(|r, w| { - let mut bits = r.bits(); - was_enabled = (bits & mask) != 0; + regs.epinen().modify(|w| { + was_enabled = (w.0 & mask) != 0; if enabled { - bits |= mask + w.0 |= mask } else { - bits &= !mask + w.0 &= !mask } - unsafe { w.bits(bits) } }); let ready_mask = In::mask(i); @@ -340,15 +340,8 @@ impl<'d, T: Instance, V: VbusDetect> driver::Bus for Bus<'d, T, V> { In::waker(i).wake(); } Direction::Out => { - regs.epouten.modify(|r, w| { - let mut bits = r.bits(); - if enabled { - bits |= mask - } else { - bits &= !mask - } - unsafe { w.bits(bits) } - }); + regs.epouten() + .modify(|w| if enabled { w.0 |= mask } else { w.0 &= !mask }); let ready_mask = Out::mask(i); if enabled { @@ -356,7 +349,7 @@ impl<'d, T: Instance, V: VbusDetect> driver::Bus for Bus<'d, T, V> { // peripheral will NAK all incoming packets) until we write a zero to the SIZE // register (see figure 203 of the 52840 manual). To avoid that we write a 0 to the // SIZE register - regs.size.epout[i].reset(); + regs.size().epout(i).write(|_| ()); } else { READY_ENDPOINTS.fetch_and(!ready_mask, Ordering::AcqRel); } @@ -370,25 +363,24 @@ impl<'d, T: Instance, V: VbusDetect> driver::Bus for Bus<'d, T, V> { async fn remote_wakeup(&mut self) -> Result<(), Unsupported> { let regs = T::regs(); - if regs.lowpower.read().lowpower().is_low_power() { + if regs.lowpower().read().lowpower() == vals::Lowpower::LOW_POWER { errata::pre_wakeup(); - regs.lowpower.write(|w| w.lowpower().force_normal()); + regs.lowpower().write(|w| w.set_lowpower(vals::Lowpower::FORCE_NORMAL)); poll_fn(|cx| { BUS_WAKER.register(cx.waker()); let regs = T::regs(); - let r = regs.eventcause.read(); + let r = regs.eventcause().read(); - if regs.events_usbreset.read().bits() != 0 { + if regs.events_usbreset().read() != 0 { Poll::Ready(()) - } else if r.resume().bit() { + } else if r.resume() { Poll::Ready(()) - } else if r.usbwuallowed().bit() { - regs.eventcause.write(|w| w.usbwuallowed().allowed()); - - regs.dpdmvalue.write(|w| w.state().resume()); - regs.tasks_dpdmdrive.write(|w| w.tasks_dpdmdrive().set_bit()); + } else if r.usbwuallowed() { + regs.eventcause().write(|w| w.set_usbwuallowed(true)); + regs.dpdmvalue().write(|w| w.set_state(vals::State::RESUME)); + regs.tasks_dpdmdrive().write_value(1); Poll::Ready(()) } else { @@ -413,7 +405,7 @@ pub enum In {} trait EndpointDir { fn waker(i: usize) -> &'static AtomicWaker; fn mask(i: usize) -> u32; - fn is_enabled(regs: &RegisterBlock, i: usize) -> bool; + fn is_enabled(regs: pac::usbd::Usbd, i: usize) -> bool; } impl EndpointDir for In { @@ -428,8 +420,8 @@ impl EndpointDir for In { } #[inline] - fn is_enabled(regs: &RegisterBlock, i: usize) -> bool { - (regs.epinen.read().bits() & (1 << i)) != 0 + fn is_enabled(regs: pac::usbd::Usbd, i: usize) -> bool { + regs.epinen().read().in_(i) } } @@ -445,8 +437,8 @@ impl EndpointDir for Out { } #[inline] - fn is_enabled(regs: &RegisterBlock, i: usize) -> bool { - (regs.epouten.read().bits() & (1 << i)) != 0 + fn is_enabled(regs: pac::usbd::Usbd, i: usize) -> bool { + regs.epouten().read().out(i) } } @@ -529,33 +521,23 @@ unsafe fn read_dma(i: usize, buf: &mut [u8]) -> Result buf.len() { return Err(EndpointError::BufferOverflow); } - let epout = [ - ®s.epout0, - ®s.epout1, - ®s.epout2, - ®s.epout3, - ®s.epout4, - ®s.epout5, - ®s.epout6, - ®s.epout7, - ]; - epout[i].ptr.write(|w| w.bits(buf.as_ptr() as u32)); + regs.epout(i).ptr().write_value(buf.as_ptr() as u32); // MAXCNT must match SIZE - epout[i].maxcnt.write(|w| w.bits(size as u32)); + regs.epout(i).maxcnt().write(|w| w.set_maxcnt(size as _)); dma_start(); - regs.events_endepout[i].reset(); - regs.tasks_startepout[i].write(|w| w.tasks_startepout().set_bit()); - while regs.events_endepout[i].read().events_endepout().bit_is_clear() {} - regs.events_endepout[i].reset(); + regs.events_endepout(i).write_value(0); + regs.tasks_startepout(i).write_value(1); + while regs.events_endepout(i).read() == 0 {} + regs.events_endepout(i).write_value(0); dma_end(); - regs.size.epout[i].reset(); + regs.size().epout(i).write(|_| ()); Ok(size) } @@ -574,27 +556,16 @@ unsafe fn write_dma(i: usize, buf: &[u8]) { buf.as_ptr() }; - let epin = [ - ®s.epin0, - ®s.epin1, - ®s.epin2, - ®s.epin3, - ®s.epin4, - ®s.epin5, - ®s.epin6, - ®s.epin7, - ]; - // Set the buffer length so the right number of bytes are transmitted. // Safety: `buf.len()` has been checked to be <= the max buffer length. - epin[i].ptr.write(|w| w.bits(ptr as u32)); - epin[i].maxcnt.write(|w| w.maxcnt().bits(buf.len() as u8)); + regs.epin(i).ptr().write_value(ptr as u32); + regs.epin(i).maxcnt().write(|w| w.set_maxcnt(buf.len() as u8)); - regs.events_endepin[i].reset(); + regs.events_endepin(i).write_value(0); dma_start(); - regs.tasks_startepin[i].write(|w| w.bits(1)); - while regs.events_endepin[i].read().bits() == 0 {} + regs.tasks_startepin(i).write_value(1); + while regs.events_endepin(i).read() == 0 {} dma_end(); } @@ -637,14 +608,14 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> { let regs = T::regs(); // Reset shorts - regs.shorts.write(|w| w); + regs.shorts().write(|_| ()); // Wait for SETUP packet - regs.intenset.write(|w| w.ep0setup().set()); + regs.intenset().write(|w| w.set_ep0setup(true)); poll_fn(|cx| { EP0_WAKER.register(cx.waker()); let regs = T::regs(); - if regs.events_ep0setup.read().bits() != 0 { + if regs.events_ep0setup().read() != 0 { Poll::Ready(()) } else { Poll::Pending @@ -652,17 +623,17 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> { }) .await; - regs.events_ep0setup.reset(); + regs.events_ep0setup().write_value(0); let mut buf = [0; 8]; - buf[0] = regs.bmrequesttype.read().bits() as u8; - buf[1] = regs.brequest.read().brequest().bits(); - buf[2] = regs.wvaluel.read().wvaluel().bits(); - buf[3] = regs.wvalueh.read().wvalueh().bits(); - buf[4] = regs.windexl.read().windexl().bits(); - buf[5] = regs.windexh.read().windexh().bits(); - buf[6] = regs.wlengthl.read().wlengthl().bits(); - buf[7] = regs.wlengthh.read().wlengthh().bits(); + buf[0] = regs.bmrequesttype().read().0 as u8; + buf[1] = regs.brequest().read().0 as u8; + buf[2] = regs.wvaluel().read().0 as u8; + buf[3] = regs.wvalueh().read().0 as u8; + buf[4] = regs.windexl().read().0 as u8; + buf[5] = regs.windexh().read().0 as u8; + buf[6] = regs.wlengthl().read().0 as u8; + buf[7] = regs.wlengthh().read().0 as u8; buf } @@ -670,26 +641,26 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> { async fn data_out(&mut self, buf: &mut [u8], _first: bool, _last: bool) -> Result { let regs = T::regs(); - regs.events_ep0datadone.reset(); + regs.events_ep0datadone().write_value(0); // This starts a RX on EP0. events_ep0datadone notifies when done. - regs.tasks_ep0rcvout.write(|w| w.tasks_ep0rcvout().set_bit()); + regs.tasks_ep0rcvout().write_value(1); // Wait until ready - regs.intenset.write(|w| { - w.usbreset().set(); - w.ep0setup().set(); - w.ep0datadone().set() + regs.intenset().write(|w| { + w.set_usbreset(true); + w.set_ep0setup(true); + w.set_ep0datadone(true); }); poll_fn(|cx| { EP0_WAKER.register(cx.waker()); let regs = T::regs(); - if regs.events_ep0datadone.read().bits() != 0 { + if regs.events_ep0datadone().read() != 0 { Poll::Ready(Ok(())) - } else if regs.events_usbreset.read().bits() != 0 { + } else if regs.events_usbreset().read() != 0 { trace!("aborted control data_out: usb reset"); Poll::Ready(Err(EndpointError::Disabled)) - } else if regs.events_ep0setup.read().bits() != 0 { + } else if regs.events_ep0setup().read() != 0 { trace!("aborted control data_out: received another SETUP"); Poll::Ready(Err(EndpointError::Disabled)) } else { @@ -703,29 +674,29 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> { async fn data_in(&mut self, buf: &[u8], _first: bool, last: bool) -> Result<(), EndpointError> { let regs = T::regs(); - regs.events_ep0datadone.reset(); + regs.events_ep0datadone().write_value(0); - regs.shorts.write(|w| w.ep0datadone_ep0status().bit(last)); + regs.shorts().write(|w| w.set_ep0datadone_ep0status(last)); // This starts a TX on EP0. events_ep0datadone notifies when done. unsafe { write_dma::(0, buf) } - regs.intenset.write(|w| { - w.usbreset().set(); - w.ep0setup().set(); - w.ep0datadone().set() + regs.intenset().write(|w| { + w.set_usbreset(true); + w.set_ep0setup(true); + w.set_ep0datadone(true); }); poll_fn(|cx| { cx.waker().wake_by_ref(); EP0_WAKER.register(cx.waker()); let regs = T::regs(); - if regs.events_ep0datadone.read().bits() != 0 { + if regs.events_ep0datadone().read() != 0 { Poll::Ready(Ok(())) - } else if regs.events_usbreset.read().bits() != 0 { + } else if regs.events_usbreset().read() != 0 { trace!("aborted control data_in: usb reset"); Poll::Ready(Err(EndpointError::Disabled)) - } else if regs.events_ep0setup.read().bits() != 0 { + } else if regs.events_ep0setup().read() != 0 { trace!("aborted control data_in: received another SETUP"); Poll::Ready(Err(EndpointError::Disabled)) } else { @@ -737,12 +708,12 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> { async fn accept(&mut self) { let regs = T::regs(); - regs.tasks_ep0status.write(|w| w.tasks_ep0status().bit(true)); + regs.tasks_ep0status().write_value(1); } async fn reject(&mut self) { let regs = T::regs(); - regs.tasks_ep0stall.write(|w| w.tasks_ep0stall().bit(true)); + regs.tasks_ep0stall().write_value(1); } async fn accept_set_address(&mut self, _addr: u8) { @@ -806,7 +777,7 @@ impl Allocator { } pub(crate) trait SealedInstance { - fn regs() -> &'static pac::usbd::RegisterBlock; + fn regs() -> pac::usbd::Usbd; } /// USB peripheral instance. @@ -819,8 +790,8 @@ pub trait Instance: Peripheral

+ SealedInstance + 'static + Send { macro_rules! impl_usb { ($type:ident, $pac_type:ident, $irq:ident) => { impl crate::usb::SealedInstance for peripherals::$type { - fn regs() -> &'static pac::usbd::RegisterBlock { - unsafe { &*pac::$pac_type::ptr() } + fn regs() -> pac::usbd::Usbd { + pac::$pac_type } } impl crate::usb::Instance for peripherals::$type { diff --git a/embassy-nrf/src/usb/vbus_detect.rs b/embassy-nrf/src/usb/vbus_detect.rs index a05e5aa52..7f816a5ad 100644 --- a/embassy-nrf/src/usb/vbus_detect.rs +++ b/embassy-nrf/src/usb/vbus_detect.rs @@ -34,9 +34,9 @@ type UsbRegIrq = interrupt::typelevel::POWER_CLOCK; type UsbRegIrq = interrupt::typelevel::USBREGULATOR; #[cfg(not(feature = "_nrf5340"))] -type UsbRegPeri = pac::POWER; +const USB_REG_PERI: pac::power::Power = pac::POWER; #[cfg(feature = "_nrf5340")] -type UsbRegPeri = pac::USBREGULATOR; +const USB_REG_PERI: pac::usbregulator::Usbregulator = pac::USBREGULATOR; /// Interrupt handler. pub struct InterruptHandler { @@ -45,21 +45,21 @@ pub struct InterruptHandler { impl interrupt::typelevel::Handler for InterruptHandler { unsafe fn on_interrupt() { - let regs = unsafe { &*UsbRegPeri::ptr() }; + let regs = USB_REG_PERI; - if regs.events_usbdetected.read().bits() != 0 { - regs.events_usbdetected.reset(); + if regs.events_usbdetected().read() != 0 { + regs.events_usbdetected().write_value(0); BUS_WAKER.wake(); } - if regs.events_usbremoved.read().bits() != 0 { - regs.events_usbremoved.reset(); + if regs.events_usbremoved().read() != 0 { + regs.events_usbremoved().write_value(0); BUS_WAKER.wake(); POWER_WAKER.wake(); } - if regs.events_usbpwrrdy.read().bits() != 0 { - regs.events_usbpwrrdy.reset(); + if regs.events_usbpwrrdy().read() != 0 { + regs.events_usbpwrrdy().write_value(0); POWER_WAKER.wake(); } } @@ -78,13 +78,16 @@ static POWER_WAKER: AtomicWaker = AtomicWaker::new(); impl HardwareVbusDetect { /// Create a new `VbusDetectNative`. pub fn new(_irq: impl interrupt::typelevel::Binding + 'static) -> Self { - let regs = unsafe { &*UsbRegPeri::ptr() }; + let regs = USB_REG_PERI; UsbRegIrq::unpend(); unsafe { UsbRegIrq::enable() }; - regs.intenset - .write(|w| w.usbdetected().set().usbremoved().set().usbpwrrdy().set()); + regs.intenset().write(|w| { + w.set_usbdetected(true); + w.set_usbremoved(true); + w.set_usbpwrrdy(true); + }); Self { _private: () } } @@ -92,16 +95,16 @@ impl HardwareVbusDetect { impl VbusDetect for HardwareVbusDetect { fn is_usb_detected(&self) -> bool { - let regs = unsafe { &*UsbRegPeri::ptr() }; - regs.usbregstatus.read().vbusdetect().is_vbus_present() + let regs = USB_REG_PERI; + regs.usbregstatus().read().vbusdetect() } async fn wait_power_ready(&mut self) -> Result<(), ()> { poll_fn(move |cx| { POWER_WAKER.register(cx.waker()); - let regs = unsafe { &*UsbRegPeri::ptr() }; + let regs = USB_REG_PERI; - if regs.usbregstatus.read().outputrdy().is_ready() { + if regs.usbregstatus().read().outputrdy() { Poll::Ready(Ok(())) } else if !self.is_usb_detected() { Poll::Ready(Err(())) diff --git a/embassy-nrf/src/wdt.rs b/embassy-nrf/src/wdt.rs index e4cfa3344..dfe6cbec3 100644 --- a/embassy-nrf/src/wdt.rs +++ b/embassy-nrf/src/wdt.rs @@ -3,7 +3,8 @@ //! This HAL implements a basic watchdog timer with 1..=8 handles. //! Once the watchdog has been started, it cannot be stopped. -use crate::pac::WDT; +use crate::pac::wdt::vals; +pub use crate::pac::wdt::vals::{Halt as HaltConfig, Sleep as SleepConfig}; use crate::peripherals; const MIN_TICKS: u32 = 15; @@ -18,29 +19,29 @@ pub struct Config { pub timeout_ticks: u32, /// Should the watchdog continue to count during sleep modes? - pub run_during_sleep: bool, + pub action_during_sleep: SleepConfig, /// Should the watchdog continue to count when the CPU is halted for debug? - pub run_during_debug_halt: bool, + pub action_during_debug_halt: HaltConfig, } impl Config { /// Create a config structure from the current configuration of the WDT /// peripheral. pub fn try_new(_wdt: &peripherals::WDT) -> Option { - let r = unsafe { &*WDT::ptr() }; + let r = crate::pac::WDT; #[cfg(not(feature = "_nrf91"))] - let runstatus = r.runstatus.read().runstatus().bit(); + let runstatus = r.runstatus().read().runstatus(); #[cfg(feature = "_nrf91")] - let runstatus = r.runstatus.read().runstatuswdt().bit(); + let runstatus = r.runstatus().read().runstatuswdt(); if runstatus { - let config = r.config.read(); + let config = r.config().read(); Some(Self { - timeout_ticks: r.crv.read().bits(), - run_during_sleep: config.sleep().bit(), - run_during_debug_halt: config.halt().bit(), + timeout_ticks: r.crv().read(), + action_during_sleep: config.sleep(), + action_during_debug_halt: config.halt(), }) } else { None @@ -52,8 +53,8 @@ impl Default for Config { fn default() -> Self { Self { timeout_ticks: 32768, // 1 second - run_during_debug_halt: true, - run_during_sleep: true, + action_during_debug_halt: HaltConfig::RUN, + action_during_sleep: SleepConfig::RUN, } } } @@ -78,36 +79,35 @@ impl Watchdog { ) -> Result<(Self, [WatchdogHandle; N]), peripherals::WDT> { assert!(N >= 1 && N <= 8); - let r = unsafe { &*WDT::ptr() }; + let r = crate::pac::WDT; let crv = config.timeout_ticks.max(MIN_TICKS); - let rren = (1u32 << N) - 1; + let rren = crate::pac::wdt::regs::Rren((1u32 << N) - 1); #[cfg(not(feature = "_nrf91"))] - let runstatus = r.runstatus.read().runstatus().bit(); + let runstatus = r.runstatus().read().runstatus(); #[cfg(feature = "_nrf91")] - let runstatus = r.runstatus.read().runstatuswdt().bit(); + let runstatus = r.runstatus().read().runstatuswdt(); if runstatus { - let curr_config = r.config.read(); - if curr_config.halt().bit() != config.run_during_debug_halt - || curr_config.sleep().bit() != config.run_during_sleep - || r.crv.read().bits() != crv - || r.rren.read().bits() != rren + let curr_config = r.config().read(); + if curr_config.halt() != config.action_during_debug_halt + || curr_config.sleep() != config.action_during_sleep + || r.crv().read() != crv + || r.rren().read() != rren { return Err(wdt); } } else { - r.config.write(|w| { - w.sleep().bit(config.run_during_sleep); - w.halt().bit(config.run_during_debug_halt); - w + r.config().write(|w| { + w.set_sleep(config.action_during_sleep); + w.set_halt(config.action_during_debug_halt); }); - r.intenset.write(|w| w.timeout().set_bit()); + r.intenset().write(|w| w.set_timeout(true)); - r.crv.write(|w| unsafe { w.bits(crv) }); - r.rren.write(|w| unsafe { w.bits(rren) }); - r.tasks_start.write(|w| unsafe { w.bits(1) }); + r.crv().write_value(crv); + r.rren().write_value(rren); + r.tasks_start().write_value(1); } let this = Self { _private: () }; @@ -130,8 +130,7 @@ impl Watchdog { /// interrupt has been enabled. #[inline(always)] pub fn enable_interrupt(&mut self) { - let r = unsafe { &*WDT::ptr() }; - r.intenset.write(|w| w.timeout().set_bit()); + crate::pac::WDT.intenset().write(|w| w.set_timeout(true)); } /// Disable the watchdog interrupt. @@ -139,8 +138,7 @@ impl Watchdog { /// NOTE: This has no effect on the reset caused by the Watchdog. #[inline(always)] pub fn disable_interrupt(&mut self) { - let r = unsafe { &*WDT::ptr() }; - r.intenclr.write(|w| w.timeout().set_bit()); + crate::pac::WDT.intenclr().write(|w| w.set_timeout(true)); } /// Is the watchdog still awaiting pets from any handle? @@ -149,9 +147,9 @@ impl Watchdog { /// handles to prevent a reset this time period. #[inline(always)] pub fn awaiting_pets(&self) -> bool { - let r = unsafe { &*WDT::ptr() }; - let enabled = r.rren.read().bits(); - let status = r.reqstatus.read().bits(); + let r = crate::pac::WDT; + let enabled = r.rren().read().0; + let status = r.reqstatus().read().0; (status & enabled) == 0 } } @@ -170,16 +168,14 @@ impl WatchdogHandle { /// prevent a reset from occurring. #[inline] pub fn pet(&mut self) { - let r = unsafe { &*WDT::ptr() }; - r.rr[self.index as usize].write(|w| w.rr().reload()); + let r = crate::pac::WDT; + r.rr(self.index as usize).write(|w| w.set_rr(vals::Rr::RELOAD)); } /// Has this handle been pet within the current window? pub fn is_pet(&self) -> bool { - let r = unsafe { &*WDT::ptr() }; - let rd = r.reqstatus.read().bits(); - let idx = self.index as usize; - ((rd >> idx) & 0x1) == 0 + let r = crate::pac::WDT; + !r.reqstatus().read().rr(self.index as usize) } /// Steal a watchdog handle by index. diff --git a/examples/boot/bootloader/nrf/src/main.rs b/examples/boot/bootloader/nrf/src/main.rs index 67c700437..b849a0df3 100644 --- a/examples/boot/bootloader/nrf/src/main.rs +++ b/examples/boot/bootloader/nrf/src/main.rs @@ -8,7 +8,7 @@ use cortex_m_rt::{entry, exception}; use defmt_rtt as _; use embassy_boot_nrf::*; use embassy_nrf::nvmc::Nvmc; -use embassy_nrf::wdt; +use embassy_nrf::wdt::{self, HaltConfig, SleepConfig}; use embassy_sync::blocking_mutex::Mutex; #[entry] @@ -25,8 +25,8 @@ fn main() -> ! { let mut wdt_config = wdt::Config::default(); wdt_config.timeout_ticks = 32768 * 5; // timeout seconds - wdt_config.run_during_sleep = true; - wdt_config.run_during_debug_halt = false; + wdt_config.action_during_sleep = SleepConfig::RUN; + wdt_config.action_during_debug_halt = HaltConfig::PAUSE; let flash = WatchdogFlash::start(Nvmc::new(p.NVMC), p.WDT, wdt_config); let flash = Mutex::new(RefCell::new(flash)); diff --git a/examples/nrf52840/src/bin/usb_ethernet.rs b/examples/nrf52840/src/bin/usb_ethernet.rs index b07adac1f..82364ded8 100644 --- a/examples/nrf52840/src/bin/usb_ethernet.rs +++ b/examples/nrf52840/src/bin/usb_ethernet.rs @@ -1,8 +1,6 @@ #![no_std] #![no_main] -use core::mem; - use defmt::*; use embassy_executor::Spawner; use embassy_net::tcp::TcpSocket; @@ -46,11 +44,10 @@ async fn net_task(mut runner: embassy_net::Runner<'static, Device<'static, MTU>> #[embassy_executor::main] async fn main(spawner: Spawner) { let p = embassy_nrf::init(Default::default()); - let clock: pac::CLOCK = unsafe { mem::transmute(()) }; info!("Enabling ext hfosc..."); - clock.tasks_hfclkstart.write(|w| unsafe { w.bits(1) }); - while clock.events_hfclkstarted.read().bits() != 1 {} + pac::CLOCK.tasks_hfclkstart().write_value(1); + while pac::CLOCK.events_hfclkstarted().read() != 1 {} // Create the driver, from the HAL. let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs)); diff --git a/examples/nrf52840/src/bin/usb_hid_keyboard.rs b/examples/nrf52840/src/bin/usb_hid_keyboard.rs index e33ee5866..3b752fd16 100644 --- a/examples/nrf52840/src/bin/usb_hid_keyboard.rs +++ b/examples/nrf52840/src/bin/usb_hid_keyboard.rs @@ -1,7 +1,6 @@ #![no_std] #![no_main] -use core::mem; use core::sync::atomic::{AtomicBool, Ordering}; use defmt::*; @@ -30,11 +29,10 @@ static SUSPENDED: AtomicBool = AtomicBool::new(false); #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_nrf::init(Default::default()); - let clock: pac::CLOCK = unsafe { mem::transmute(()) }; info!("Enabling ext hfosc..."); - clock.tasks_hfclkstart.write(|w| unsafe { w.bits(1) }); - while clock.events_hfclkstarted.read().bits() != 1 {} + pac::CLOCK.tasks_hfclkstart().write_value(1); + while pac::CLOCK.events_hfclkstarted().read() != 1 {} // Create the driver, from the HAL. let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs)); diff --git a/examples/nrf52840/src/bin/usb_hid_mouse.rs b/examples/nrf52840/src/bin/usb_hid_mouse.rs index 8076ac283..3f13a014e 100644 --- a/examples/nrf52840/src/bin/usb_hid_mouse.rs +++ b/examples/nrf52840/src/bin/usb_hid_mouse.rs @@ -1,8 +1,6 @@ #![no_std] #![no_main] -use core::mem; - use defmt::*; use embassy_executor::Spawner; use embassy_futures::join::join; @@ -24,11 +22,10 @@ bind_interrupts!(struct Irqs { #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_nrf::init(Default::default()); - let clock: pac::CLOCK = unsafe { mem::transmute(()) }; info!("Enabling ext hfosc..."); - clock.tasks_hfclkstart.write(|w| unsafe { w.bits(1) }); - while clock.events_hfclkstarted.read().bits() != 1 {} + pac::CLOCK.tasks_hfclkstart().write_value(1); + while pac::CLOCK.events_hfclkstarted().read() != 1 {} // Create the driver, from the HAL. let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs)); diff --git a/examples/nrf52840/src/bin/usb_serial.rs b/examples/nrf52840/src/bin/usb_serial.rs index 02048e692..30fe103ad 100644 --- a/examples/nrf52840/src/bin/usb_serial.rs +++ b/examples/nrf52840/src/bin/usb_serial.rs @@ -1,8 +1,6 @@ #![no_std] #![no_main] -use core::mem; - use defmt::{info, panic}; use embassy_executor::Spawner; use embassy_futures::join::join; @@ -22,11 +20,10 @@ bind_interrupts!(struct Irqs { #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_nrf::init(Default::default()); - let clock: pac::CLOCK = unsafe { mem::transmute(()) }; info!("Enabling ext hfosc..."); - clock.tasks_hfclkstart.write(|w| unsafe { w.bits(1) }); - while clock.events_hfclkstarted.read().bits() != 1 {} + pac::CLOCK.tasks_hfclkstart().write_value(1); + while pac::CLOCK.events_hfclkstarted().read() != 1 {} // Create the driver, from the HAL. let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs)); diff --git a/examples/nrf52840/src/bin/usb_serial_multitask.rs b/examples/nrf52840/src/bin/usb_serial_multitask.rs index 895cca8b9..05b5f0ec9 100644 --- a/examples/nrf52840/src/bin/usb_serial_multitask.rs +++ b/examples/nrf52840/src/bin/usb_serial_multitask.rs @@ -1,8 +1,6 @@ #![no_std] #![no_main] -use core::mem; - use defmt::{info, panic, unwrap}; use embassy_executor::Spawner; use embassy_nrf::usb::vbus_detect::HardwareVbusDetect; @@ -39,11 +37,10 @@ async fn echo_task(mut class: CdcAcmClass<'static, MyDriver>) { #[embassy_executor::main] async fn main(spawner: Spawner) { let p = embassy_nrf::init(Default::default()); - let clock: pac::CLOCK = unsafe { mem::transmute(()) }; info!("Enabling ext hfosc..."); - clock.tasks_hfclkstart.write(|w| unsafe { w.bits(1) }); - while clock.events_hfclkstarted.read().bits() != 1 {} + pac::CLOCK.tasks_hfclkstart().write_value(1); + while pac::CLOCK.events_hfclkstarted().read() != 1 {} // Create the driver, from the HAL. let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs)); diff --git a/examples/nrf52840/src/bin/usb_serial_winusb.rs b/examples/nrf52840/src/bin/usb_serial_winusb.rs index c6675a3d3..7c07158e0 100644 --- a/examples/nrf52840/src/bin/usb_serial_winusb.rs +++ b/examples/nrf52840/src/bin/usb_serial_winusb.rs @@ -1,8 +1,6 @@ #![no_std] #![no_main] -use core::mem; - use defmt::{info, panic}; use embassy_executor::Spawner; use embassy_futures::join::join; @@ -27,11 +25,10 @@ const DEVICE_INTERFACE_GUIDS: &[&str] = &["{EAA9A5DC-30BA-44BC-9232-606CDC875321 #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_nrf::init(Default::default()); - let clock: pac::CLOCK = unsafe { mem::transmute(()) }; info!("Enabling ext hfosc..."); - clock.tasks_hfclkstart.write(|w| unsafe { w.bits(1) }); - while clock.events_hfclkstarted.read().bits() != 1 {} + pac::CLOCK.tasks_hfclkstart().write_value(1); + while pac::CLOCK.events_hfclkstarted().read() != 1 {} // Create the driver, from the HAL. let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs)); diff --git a/examples/nrf52840/src/bin/wdt.rs b/examples/nrf52840/src/bin/wdt.rs index ede88cc26..0d9ee3cf8 100644 --- a/examples/nrf52840/src/bin/wdt.rs +++ b/examples/nrf52840/src/bin/wdt.rs @@ -4,7 +4,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_nrf::gpio::{Input, Pull}; -use embassy_nrf::wdt::{Config, Watchdog}; +use embassy_nrf::wdt::{Config, HaltConfig, Watchdog}; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] @@ -17,7 +17,7 @@ async fn main(_spawner: Spawner) { // This is needed for `probe-rs run` to be able to catch the panic message // in the WDT interrupt. The core resets 2 ticks after firing the interrupt. - config.run_during_debug_halt = false; + config.action_during_debug_halt = HaltConfig::PAUSE; let (_wdt, [mut handle]) = match Watchdog::try_new(p.WDT, config) { Ok(x) => x, diff --git a/tests/nrf/Cargo.toml b/tests/nrf/Cargo.toml index d36ab9c67..6a710f29d 100644 --- a/tests/nrf/Cargo.toml +++ b/tests/nrf/Cargo.toml @@ -86,6 +86,11 @@ name = "gpiote" path = "src/bin/gpiote.rs" required-features = [] +[[bin]] +name = "spim" +path = "src/bin/spim.rs" +required-features = [ "easydma",] + [[bin]] name = "timer" path = "src/bin/timer.rs" diff --git a/tests/nrf/src/bin/buffered_uart_spam.rs b/tests/nrf/src/bin/buffered_uart_spam.rs index 45daaae0c..cf9ca50d2 100644 --- a/tests/nrf/src/bin/buffered_uart_spam.rs +++ b/tests/nrf/src/bin/buffered_uart_spam.rs @@ -50,15 +50,15 @@ async fn main(_spawner: Spawner) { const NSPAM: usize = 17; static mut TX_BUF: [u8; NSPAM] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; let _spam = UarteTx::new(peri!(p, UART1), irqs!(UART1), peri!(p, PIN_A), config.clone()); - let spam_peri: pac::UARTE1 = unsafe { mem::transmute(()) }; - let event = unsafe { Event::new_unchecked(NonNull::new_unchecked(&spam_peri.events_endtx as *const _ as _)) }; - let task = unsafe { Task::new_unchecked(NonNull::new_unchecked(&spam_peri.tasks_starttx as *const _ as _)) }; + let spam_peri = pac::UARTE1; + let event = unsafe { Event::new_unchecked(NonNull::new_unchecked(spam_peri.events_endtx().as_ptr())) }; + let task = unsafe { Task::new_unchecked(NonNull::new_unchecked(spam_peri.tasks_starttx().as_ptr())) }; let mut spam_ppi = Ppi::new_one_to_one(p.PPI_CH2, event, task); spam_ppi.enable(); let p = (&raw mut TX_BUF) as *mut u8; - spam_peri.txd.ptr.write(|w| unsafe { w.ptr().bits(p as u32) }); - spam_peri.txd.maxcnt.write(|w| unsafe { w.maxcnt().bits(NSPAM as _) }); - spam_peri.tasks_starttx.write(|w| unsafe { w.bits(1) }); + spam_peri.txd().ptr().write_value(p as u32); + spam_peri.txd().maxcnt().write(|w| w.set_maxcnt(NSPAM as _)); + spam_peri.tasks_starttx().write_value(1); let mut i = 0; let mut total = 0; diff --git a/tests/nrf/src/bin/gpio.rs b/tests/nrf/src/bin/gpio.rs index 9e809a694..4995d244c 100644 --- a/tests/nrf/src/bin/gpio.rs +++ b/tests/nrf/src/bin/gpio.rs @@ -17,10 +17,12 @@ async fn main(_spawner: Spawner) { let mut output = Output::new(peri!(p, PIN_B), Level::Low, OutputDrive::Standard); output.set_low(); + assert!(output.is_set_low()); Timer::after_millis(10).await; assert!(input.is_low()); output.set_high(); + assert!(output.is_set_high()); Timer::after_millis(10).await; assert!(input.is_high()); diff --git a/tests/nrf/src/bin/spim.rs b/tests/nrf/src/bin/spim.rs new file mode 100644 index 000000000..c2ec90b88 --- /dev/null +++ b/tests/nrf/src/bin/spim.rs @@ -0,0 +1,42 @@ +// required-features: easydma +#![no_std] +#![no_main] + +#[path = "../common.rs"] +mod common; + +use defmt::{assert_eq, *}; +use embassy_executor::Spawner; +use embassy_nrf::spim::Spim; +use embassy_nrf::{peripherals, spim}; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let mut p = embassy_nrf::init(Default::default()); + let mut config = spim::Config::default(); + config.frequency = spim::Frequency::M1; + let mut spim = Spim::new( + &mut peri!(p, SPIM0), + irqs!(SPIM0), + &mut peri!(p, PIN_X), + &mut peri!(p, PIN_A), // MISO + &mut peri!(p, PIN_B), // MOSI + config.clone(), + ); + let data = [ + 0x42, 0x43, 0x44, 0x45, 0x66, 0x12, 0x23, 0x34, 0x45, 0x19, 0x91, 0xaa, 0xff, 0xa5, 0x5a, 0x77, + ]; + let mut buf = [0u8; 16]; + + buf.fill(0); + spim.blocking_transfer(&mut buf, &data).unwrap(); + assert_eq!(data, buf); + + buf.fill(0); + spim.transfer(&mut buf, &data).await.unwrap(); + assert_eq!(data, buf); + + info!("Test OK"); + cortex_m::asm::bkpt(); +} diff --git a/tests/nrf/src/common.rs b/tests/nrf/src/common.rs index ff5299b0f..c588dabf5 100644 --- a/tests/nrf/src/common.rs +++ b/tests/nrf/src/common.rs @@ -52,51 +52,66 @@ define_peris!(PIN_A = P0_13, PIN_B = P0_14,); #[cfg(feature = "nrf52832")] define_peris!( PIN_A = P0_11, PIN_B = P0_12, + PIN_X = P0_13, UART0 = UARTE0, + SPIM0 = TWISPI0, @irq UART0 = {UARTE0_UART0 => uarte::InterruptHandler;}, @irq UART0_BUFFERED = {UARTE0_UART0 => buffered_uarte::InterruptHandler;}, + @irq SPIM0 = {SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0 => spim::InterruptHandler;}, ); #[cfg(feature = "nrf52833")] define_peris!( PIN_A = P1_01, PIN_B = P1_02, + PIN_X = P1_03, UART0 = UARTE0, UART1 = UARTE1, + SPIM0 = TWISPI0, @irq UART0 = {UARTE0_UART0 => uarte::InterruptHandler;}, @irq UART1 = {UARTE1 => uarte::InterruptHandler;}, @irq UART0_BUFFERED = {UARTE0_UART0 => buffered_uarte::InterruptHandler;}, @irq UART1_BUFFERED = {UARTE1 => buffered_uarte::InterruptHandler;}, + @irq SPIM0 = {SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0 => spim::InterruptHandler;}, ); #[cfg(feature = "nrf52840")] define_peris!( PIN_A = P1_02, PIN_B = P1_03, + PIN_X = P1_04, UART0 = UARTE0, UART1 = UARTE1, + SPIM0 = TWISPI0, @irq UART0 = {UARTE0_UART0 => uarte::InterruptHandler;}, @irq UART1 = {UARTE1 => uarte::InterruptHandler;}, @irq UART0_BUFFERED = {UARTE0_UART0 => buffered_uarte::InterruptHandler;}, @irq UART1_BUFFERED = {UARTE1 => buffered_uarte::InterruptHandler;}, + @irq SPIM0 = {SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0 => spim::InterruptHandler;}, ); #[cfg(feature = "nrf5340")] define_peris!( PIN_A = P1_08, PIN_B = P1_09, + PIN_X = P1_10, UART0 = SERIAL0, UART1 = SERIAL1, + SPIM0 = SERIAL0, @irq UART0 = {SERIAL0 => uarte::InterruptHandler;}, @irq UART1 = {SERIAL1 => uarte::InterruptHandler;}, @irq UART0_BUFFERED = {SERIAL0 => buffered_uarte::InterruptHandler;}, @irq UART1_BUFFERED = {SERIAL1 => buffered_uarte::InterruptHandler;}, + @irq SPIM0 = {SERIAL0 => spim::InterruptHandler;}, ); #[cfg(feature = "nrf9160")] define_peris!( PIN_A = P0_00, PIN_B = P0_01, + PIN_X = P0_02, UART0 = SERIAL0, UART1 = SERIAL1, + SPIM0 = SERIAL0, @irq UART0 = {UARTE0_SPIM0_SPIS0_TWIM0_TWIS0 => uarte::InterruptHandler;}, @irq UART1 = {UARTE1_SPIM1_SPIS1_TWIM1_TWIS1 => uarte::InterruptHandler;}, @irq UART0_BUFFERED = {UARTE0_SPIM0_SPIS0_TWIM0_TWIS0 => buffered_uarte::InterruptHandler;}, @irq UART1_BUFFERED = {UARTE1_SPIM1_SPIS1_TWIM1_TWIS1 => buffered_uarte::InterruptHandler;}, + @irq SPIM0 = {UARTE0_SPIM0_SPIS0_TWIM0_TWIS0 => spim::InterruptHandler;}, ); From aa453caa79a0f612698e0bcb3bfff635a172eb5f Mon Sep 17 00:00:00 2001 From: Kenneth Knudsen Date: Mon, 4 Nov 2024 15:08:57 +0100 Subject: [PATCH 0321/1217] add split_ref for stm32 uart --- embassy-stm32/src/usart/buffered.rs | 7 +++++++ embassy-stm32/src/usart/mod.rs | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs index 7ba209063..d7ac33d07 100644 --- a/embassy-stm32/src/usart/buffered.rs +++ b/embassy-stm32/src/usart/buffered.rs @@ -396,6 +396,13 @@ impl<'d> BufferedUart<'d> { (self.tx, self.rx) } + /// Split the Uart into a transmitter and receiver by mutable reference, + /// which is particularly useful when having two tasks correlating to + /// transmitting and receiving. + pub fn split_ref(&mut self) -> (&mut BufferedUartTx<'d>, &mut BufferedUartRx<'d>) { + (&mut self.tx, &mut self.rx) + } + /// Reconfigure the driver pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { reconfigure(self.rx.info, self.rx.kernel_clock, config)?; diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index 333e01e36..8152fc560 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -1440,6 +1440,13 @@ impl<'d, M: Mode> Uart<'d, M> { (self.tx, self.rx) } + /// Split the Uart into a transmitter and receiver by mutable reference, + /// which is particularly useful when having two tasks correlating to + /// transmitting and receiving. + pub fn split_ref(&mut self) -> (&mut UartTx<'d, M>, &mut UartRx<'d, M>) { + (&mut self.tx, &mut self.rx) + } + /// Send break character pub fn send_break(&self) { self.tx.send_break(); From bffe7cf8a6b9c59475c0d8d2f2f8f9e88ad22087 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 4 Nov 2024 16:06:54 +0100 Subject: [PATCH 0322/1217] nrf: fix docs build. --- embassy-nrf/Cargo.toml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml index 90fa7a16c..24a3db91d 100644 --- a/embassy-nrf/Cargo.toml +++ b/embassy-nrf/Cargo.toml @@ -15,7 +15,7 @@ src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-nrf/s features = ["time", "defmt", "unstable-pac", "gpiote", "time-driver-rtc1"] flavors = [ - { regex_feature = "_nrf51", target = "thumbv6m-none-eabi" }, + { regex_feature = "nrf51", target = "thumbv6m-none-eabi" }, { regex_feature = "nrf52.*", target = "thumbv7em-none-eabihf" }, { regex_feature = "nrf53.*", target = "thumbv8m.main-none-eabihf" }, { regex_feature = "nrf91.*", target = "thumbv8m.main-none-eabihf" }, @@ -150,4 +150,3 @@ embedded-storage = "0.3.1" embedded-storage-async = "0.4.1" cfg-if = "1.0.0" document-features = "0.2.7" - From 6dffb2213c295b57de13f4377a5f99878cb506e7 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 4 Nov 2024 17:46:26 +0100 Subject: [PATCH 0323/1217] Update Nightly. --- rust-toolchain-nightly.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain-nightly.toml b/rust-toolchain-nightly.toml index acab9d615..d0c92e655 100644 --- a/rust-toolchain-nightly.toml +++ b/rust-toolchain-nightly.toml @@ -1,5 +1,5 @@ [toolchain] -channel = "nightly-2024-10-13" +channel = "nightly-2024-11-04" components = [ "rust-src", "rustfmt", "llvm-tools", "miri" ] targets = [ "thumbv7em-none-eabi", From fff304b3de85d63c1df404ab3abc17a2ac42844a Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 4 Nov 2024 18:41:31 +0100 Subject: [PATCH 0324/1217] nrf/pwm: fix bad pin assignment. --- embassy-nrf/src/pwm.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-nrf/src/pwm.rs b/embassy-nrf/src/pwm.rs index c8f1e0b09..ad88029b0 100644 --- a/embassy-nrf/src/pwm.rs +++ b/embassy-nrf/src/pwm.rs @@ -681,7 +681,7 @@ impl<'d, T: Instance> SimplePwm<'d, T> { pin.set_low(); pin.conf().write(|w| w.set_dir(gpiovals::Dir::OUTPUT)); } - r.psel().out(i).write_value(ch0.psel_bits()); + r.psel().out(i).write_value(ch.psel_bits()); } let pwm = Self { From f51ee98aef323b6d88e04ec4b3521a04d97485f9 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 4 Nov 2024 18:41:58 +0100 Subject: [PATCH 0325/1217] nrf/pwm: disconnect input. --- embassy-nrf/src/pwm.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/embassy-nrf/src/pwm.rs b/embassy-nrf/src/pwm.rs index ad88029b0..7f1f568f4 100644 --- a/embassy-nrf/src/pwm.rs +++ b/embassy-nrf/src/pwm.rs @@ -132,6 +132,7 @@ impl<'d, T: Instance> SequencePwm<'d, T> { pin.set_low(); pin.conf().write(|w| { w.set_dir(gpiovals::Dir::OUTPUT); + w.set_input(gpiovals::Input::DISCONNECT); w.set_drive(convert_drive(config.ch0_drive)); }); } @@ -139,6 +140,7 @@ impl<'d, T: Instance> SequencePwm<'d, T> { pin.set_low(); pin.conf().write(|w| { w.set_dir(gpiovals::Dir::OUTPUT); + w.set_input(gpiovals::Input::DISCONNECT); w.set_drive(convert_drive(config.ch1_drive)); }); } @@ -146,6 +148,7 @@ impl<'d, T: Instance> SequencePwm<'d, T> { pin.set_low(); pin.conf().write(|w| { w.set_dir(gpiovals::Dir::OUTPUT); + w.set_input(gpiovals::Input::DISCONNECT); w.set_drive(convert_drive(config.ch2_drive)); }); } @@ -153,6 +156,7 @@ impl<'d, T: Instance> SequencePwm<'d, T> { pin.set_low(); pin.conf().write(|w| { w.set_dir(gpiovals::Dir::OUTPUT); + w.set_input(gpiovals::Input::DISCONNECT); w.set_drive(convert_drive(config.ch3_drive)); }); } @@ -679,7 +683,12 @@ impl<'d, T: Instance> SimplePwm<'d, T> { for (i, ch) in [&ch0, &ch1, &ch2, &ch3].into_iter().enumerate() { if let Some(pin) = ch { pin.set_low(); - pin.conf().write(|w| w.set_dir(gpiovals::Dir::OUTPUT)); + + pin.conf().write(|w| { + w.set_dir(gpiovals::Dir::OUTPUT); + w.set_input(gpiovals::Input::DISCONNECT); + w.set_drive(gpiovals::Drive::S0S1); + }); } r.psel().out(i).write_value(ch.psel_bits()); } From 03adeeddc2abd1c02a659f428f114848cf83e5ac Mon Sep 17 00:00:00 2001 From: Kaspar Schleiser Date: Mon, 4 Nov 2024 23:02:30 +0100 Subject: [PATCH 0326/1217] executor: allow overriding `embassy_executor` path in `task` macro --- embassy-executor-macros/src/macros/task.rs | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/embassy-executor-macros/src/macros/task.rs b/embassy-executor-macros/src/macros/task.rs index 2f2aeda76..e8134c6a9 100644 --- a/embassy-executor-macros/src/macros/task.rs +++ b/embassy-executor-macros/src/macros/task.rs @@ -1,3 +1,5 @@ +use std::str::FromStr; + use darling::export::NestedMeta; use darling::FromMeta; use proc_macro2::{Span, TokenStream}; @@ -11,6 +13,9 @@ use crate::util::*; struct Args { #[darling(default)] pool_size: Option, + /// Use this to override the `embassy_executor` crate path. Defaults to `::embassy_executor`. + #[darling(default)] + embassy_executor: Option, } pub fn run(args: TokenStream, item: TokenStream) -> TokenStream { @@ -42,6 +47,10 @@ pub fn run(args: TokenStream, item: TokenStream) -> TokenStream { lit: Lit::Int(LitInt::new("1", Span::call_site())), })); + let embassy_executor = args + .embassy_executor + .unwrap_or(Expr::Verbatim(TokenStream::from_str("::embassy_executor").unwrap())); + if f.sig.asyncness.is_none() { error(&mut errors, &f.sig, "task functions must be async"); } @@ -131,13 +140,13 @@ pub fn run(args: TokenStream, item: TokenStream) -> TokenStream { } const POOL_SIZE: usize = #pool_size; - static POOL: ::embassy_executor::raw::TaskPool<<() as _EmbassyInternalTaskTrait>::Fut, POOL_SIZE> = ::embassy_executor::raw::TaskPool::new(); + static POOL: #embassy_executor::raw::TaskPool<<() as _EmbassyInternalTaskTrait>::Fut, POOL_SIZE> = #embassy_executor::raw::TaskPool::new(); unsafe { POOL._spawn_async_fn(move || <() as _EmbassyInternalTaskTrait>::construct(#(#full_args,)*)) } }; #[cfg(not(feature = "nightly"))] let mut task_outer_body = quote! { const POOL_SIZE: usize = #pool_size; - static POOL: ::embassy_executor::_export::TaskPoolRef = ::embassy_executor::_export::TaskPoolRef::new(); + static POOL: #embassy_executor::_export::TaskPoolRef = #embassy_executor::_export::TaskPoolRef::new(); unsafe { POOL.get::<_, POOL_SIZE>()._spawn_async_fn(move || #task_inner_ident(#(#full_args,)*)) } }; @@ -146,7 +155,7 @@ pub fn run(args: TokenStream, item: TokenStream) -> TokenStream { if !errors.is_empty() { task_outer_body = quote! { #![allow(unused_variables, unreachable_code)] - let _x: ::embassy_executor::SpawnToken<()> = ::core::todo!(); + let _x: #embassy_executor::SpawnToken<()> = ::core::todo!(); _x }; } @@ -164,7 +173,7 @@ pub fn run(args: TokenStream, item: TokenStream) -> TokenStream { #task_inner #(#task_outer_attrs)* - #visibility fn #task_ident #generics (#fargs) -> ::embassy_executor::SpawnToken #where_clause{ + #visibility fn #task_ident #generics (#fargs) -> #embassy_executor::SpawnToken #where_clause{ #task_outer_body } From fb004fb6e2bd1fe23c50bf0faccd9d4a8061e986 Mon Sep 17 00:00:00 2001 From: Georges Palauqui Date: Sun, 27 Oct 2024 10:23:18 +0100 Subject: [PATCH 0327/1217] add second example fo SPI display on RP --- examples/rp/Cargo.toml | 1 + examples/rp/src/bin/spi_gc9a01.rs | 126 ++++++++++++++++++++++++++++++ 2 files changed, 127 insertions(+) create mode 100644 examples/rp/src/bin/spi_gc9a01.rs diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index b55b20c63..901355aeb 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml @@ -45,6 +45,7 @@ byte-slice-cast = { version = "1.2.0", default-features = false } smart-leds = "0.4.0" heapless = "0.8" usbd-hid = "0.8.1" +rand_core = "0.6.4" embedded-hal-1 = { package = "embedded-hal", version = "1.0" } embedded-hal-async = "1.0" diff --git a/examples/rp/src/bin/spi_gc9a01.rs b/examples/rp/src/bin/spi_gc9a01.rs new file mode 100644 index 000000000..d1cf23e16 --- /dev/null +++ b/examples/rp/src/bin/spi_gc9a01.rs @@ -0,0 +1,126 @@ +//! This example shows how to use SPI (Serial Peripheral Interface) in the RP2040 chip. +//! +//! Example written for a display using the GC9A01 chip. Possibly the Waveshare RP2040-LCD-1.28 +//! (https://www.waveshare.com/wiki/RP2040-LCD-1.28) + +#![no_std] +#![no_main] + +use core::cell::RefCell; + +use defmt::*; +use display_interface_spi::SPIInterface; +use embassy_embedded_hal::shared_bus::blocking::spi::SpiDeviceWithConfig; +use embassy_executor::Spawner; +use embassy_rp::clocks::RoscRng; +use embassy_rp::gpio::{Level, Output}; +use embassy_rp::spi; +use embassy_rp::spi::{Blocking, Spi}; +use embassy_sync::blocking_mutex::raw::NoopRawMutex; +use embassy_sync::blocking_mutex::Mutex; +use embassy_time::{Delay, Duration, Timer}; +use embedded_graphics::image::{Image, ImageRawLE}; +use embedded_graphics::pixelcolor::Rgb565; +use embedded_graphics::prelude::*; +use embedded_graphics::primitives::{PrimitiveStyleBuilder, Rectangle}; +use mipidsi::models::GC9A01; +use mipidsi::options::{ColorOrder, ColorInversion}; +use mipidsi::Builder; +use rand_core::RngCore; +use {defmt_rtt as _, panic_probe as _}; + +const DISPLAY_FREQ: u32 = 64_000_000; +const LCD_X_RES: i32 = 240; +const LCD_Y_RES: i32 = 240; +const FERRIS_WIDTH: u32 = 86; +const FERRIS_HEIGHT: u32 = 64; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_rp::init(Default::default()); + let mut rng = RoscRng; + + info!("Hello World!"); + + let bl = p.PIN_25; + let rst = p.PIN_12; + let display_cs = p.PIN_9; + let dcx = p.PIN_8; + let mosi = p.PIN_11; + let clk = p.PIN_10; + + // create SPI + let mut display_config = spi::Config::default(); + display_config.frequency = DISPLAY_FREQ; + display_config.phase = spi::Phase::CaptureOnSecondTransition; + display_config.polarity = spi::Polarity::IdleHigh; + + let spi: Spi<'_, _, Blocking> = Spi::new_blocking_txonly(p.SPI1, clk, mosi, display_config.clone()); + let spi_bus: Mutex = Mutex::new(RefCell::new(spi)); + + let display_spi = SpiDeviceWithConfig::new(&spi_bus, Output::new(display_cs, Level::High), display_config); + let dcx = Output::new(dcx, Level::Low); + let rst = Output::new(rst, Level::Low); + // dcx: 0 = command, 1 = data + + // Enable LCD backlight + let _bl = Output::new(bl, Level::High); + + // display interface abstraction from SPI and DC + let di = SPIInterface::new(display_spi, dcx); + + // Define the display from the display interface and initialize it + let mut display = Builder::new(GC9A01, di) + .display_size(240, 240) + .reset_pin(rst) + .color_order(ColorOrder::Bgr) + .invert_colors(ColorInversion::Inverted) + .init(&mut Delay) + .unwrap(); + display.clear(Rgb565::BLACK).unwrap(); + + let raw_image_data = ImageRawLE::new(include_bytes!("../../assets/ferris.raw"), FERRIS_WIDTH); + let mut ferris = Image::new(&raw_image_data, Point::zero()); + + let r = rng.next_u32(); + let mut delta = Point { + x: ((r % 10) + 5) as i32, + y: (((r >> 8) % 10) + 5) as i32, + }; + loop { + // Move Ferris + let bb = ferris.bounding_box(); + let tl = bb.top_left; + let br = bb.bottom_right().unwrap(); + if tl.x < 0 || br.x > LCD_X_RES { + delta.x = -delta.x; + } + if tl.y < 0 || br.y > LCD_Y_RES { + delta.y = -delta.y; + } + + // Erase ghosting + let style = PrimitiveStyleBuilder::new().fill_color(Rgb565::BLACK).build(); + let mut off = Point { x: 0, y: 0 }; + if delta.x < 0 { + off.x = FERRIS_WIDTH as i32; + } + Rectangle::new(tl + off, Size::new(delta.x as u32, FERRIS_HEIGHT)) + .into_styled(style) + .draw(&mut display) + .unwrap(); + off = Point { x: 0, y: 0 }; + if delta.y < 0 { + off.y = FERRIS_HEIGHT as i32; + } + Rectangle::new(tl + off, Size::new(FERRIS_WIDTH, delta.y as u32)) + .into_styled(style) + .draw(&mut display) + .unwrap(); + // Translate Ferris + ferris.translate_mut(delta); + // Display the image + ferris.draw(&mut display).unwrap(); + Timer::after(Duration::from_millis(50)).await; + } +} From 9d21e3a1ae2bc22b5577032423aa3dac1ee09a3a Mon Sep 17 00:00:00 2001 From: Georges Palauqui Date: Tue, 5 Nov 2024 19:40:49 +0100 Subject: [PATCH 0328/1217] fix fmt --- examples/rp/src/bin/spi_gc9a01.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/rp/src/bin/spi_gc9a01.rs b/examples/rp/src/bin/spi_gc9a01.rs index d1cf23e16..30afc253d 100644 --- a/examples/rp/src/bin/spi_gc9a01.rs +++ b/examples/rp/src/bin/spi_gc9a01.rs @@ -24,7 +24,7 @@ use embedded_graphics::pixelcolor::Rgb565; use embedded_graphics::prelude::*; use embedded_graphics::primitives::{PrimitiveStyleBuilder, Rectangle}; use mipidsi::models::GC9A01; -use mipidsi::options::{ColorOrder, ColorInversion}; +use mipidsi::options::{ColorInversion, ColorOrder}; use mipidsi::Builder; use rand_core::RngCore; use {defmt_rtt as _, panic_probe as _}; From 682504eb0ea4e3b076c98885a1027c2ca47bdc53 Mon Sep 17 00:00:00 2001 From: Mathias Date: Wed, 6 Nov 2024 09:17:29 +0100 Subject: [PATCH 0329/1217] Fix get_state in cases where WRITE_SIZE != 1 --- embassy-boot/src/firmware_updater/asynch.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-boot/src/firmware_updater/asynch.rs b/embassy-boot/src/firmware_updater/asynch.rs index d9d15b004..0dc09e18d 100644 --- a/embassy-boot/src/firmware_updater/asynch.rs +++ b/embassy-boot/src/firmware_updater/asynch.rs @@ -304,7 +304,7 @@ impl<'d, STATE: NorFlash> FirmwareState<'d, STATE> { /// `mark_booted`. pub async fn get_state(&mut self) -> Result { self.state.read(0, &mut self.aligned).await?; - Ok(State::from(&self.aligned)) + Ok(State::from(&self.aligned[..STATE::WRITE_SIZE])) } /// Mark to trigger firmware swap on next boot. From 1e850ae79149e737c1ba39a383596eabcb0bb940 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Wed, 6 Nov 2024 10:44:01 +0100 Subject: [PATCH 0330/1217] Detect and allow older nightlies --- embassy-executor/Cargo.toml | 3 ++ embassy-executor/build.rs | 11 +++++++ embassy-executor/build_common.rs | 51 +++++++++++++++++++++++++++++++ embassy-executor/src/lib.rs | 1 + embassy-executor/src/raw/waker.rs | 11 ++++++- 5 files changed, 76 insertions(+), 1 deletion(-) diff --git a/embassy-executor/Cargo.toml b/embassy-executor/Cargo.toml index 22a176621..6011d8663 100644 --- a/embassy-executor/Cargo.toml +++ b/embassy-executor/Cargo.toml @@ -57,6 +57,9 @@ avr-device = { version = "0.5.3", optional = true } critical-section = { version = "1.1", features = ["std"] } trybuild = "1.0" +[build-dependencies] +rustc_version = "0.4.1" + [features] ## Enable nightly-only features diff --git a/embassy-executor/build.rs b/embassy-executor/build.rs index 8a41d7503..c4c86e1e2 100644 --- a/embassy-executor/build.rs +++ b/embassy-executor/build.rs @@ -96,4 +96,15 @@ fn main() { let mut rustc_cfgs = common::CfgSet::new(); common::set_target_cfgs(&mut rustc_cfgs); + + // Waker API changed on 2024-09-06 + rustc_cfgs.declare("at_least_2024_09_06"); + let Some(compiler) = common::compiler_info() else { + return; + }; + if compiler.channel == rustc_version::Channel::Nightly + && compiler.commit_date.map(|d| d >= "2024-09-06").unwrap_or(false) + { + rustc_cfgs.enable("at_least_2024_09_06"); + } } diff --git a/embassy-executor/build_common.rs b/embassy-executor/build_common.rs index 4f24e6d37..af6bb0618 100644 --- a/embassy-executor/build_common.rs +++ b/embassy-executor/build_common.rs @@ -92,3 +92,54 @@ pub fn set_target_cfgs(cfgs: &mut CfgSet) { cfgs.set("has_fpu", target.ends_with("-eabihf")); } + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +pub struct CompilerDate { + year: u16, + month: u8, + day: u8, +} + +impl CompilerDate { + fn parse(date: &str) -> Option { + let mut parts = date.split('-'); + let year = parts.next()?.parse().ok()?; + let month = parts.next()?.parse().ok()?; + let day = parts.next()?.parse().ok()?; + Some(Self { year, month, day }) + } +} + +impl PartialEq<&str> for CompilerDate { + fn eq(&self, other: &&str) -> bool { + let Some(other) = Self::parse(other) else { + return false; + }; + self.eq(&other) + } +} + +impl PartialOrd<&str> for CompilerDate { + fn partial_cmp(&self, other: &&str) -> Option { + Self::parse(other).map(|other| self.cmp(&other)) + } +} + +pub struct CompilerInfo { + #[allow(unused)] + pub version: rustc_version::Version, + pub channel: rustc_version::Channel, + pub commit_date: Option, +} + +pub fn compiler_info() -> Option { + let Ok(meta) = rustc_version::version_meta() else { + return None; + }; + + Some(CompilerInfo { + version: meta.semver, + channel: meta.channel, + commit_date: meta.commit_date.as_deref().and_then(CompilerDate::parse), + }) +} diff --git a/embassy-executor/src/lib.rs b/embassy-executor/src/lib.rs index d816539ac..8e07a8b18 100644 --- a/embassy-executor/src/lib.rs +++ b/embassy-executor/src/lib.rs @@ -1,4 +1,5 @@ #![cfg_attr(not(any(feature = "arch-std", feature = "arch-wasm")), no_std)] +#![cfg_attr(all(feature = "nightly", not(at_least_2024_09_06)), feature(waker_getters))] #![allow(clippy::new_without_default)] #![doc = include_str!("../README.md")] #![warn(missing_docs)] diff --git a/embassy-executor/src/raw/waker.rs b/embassy-executor/src/raw/waker.rs index 8bb2cfd05..30b8cdd4c 100644 --- a/embassy-executor/src/raw/waker.rs +++ b/embassy-executor/src/raw/waker.rs @@ -50,7 +50,16 @@ pub fn task_from_waker(waker: &Waker) -> TaskRef { #[cfg(feature = "nightly")] { - (waker.vtable(), waker.data()) + #[cfg(not(at_least_2024_09_06))] + { + let raw_waker = waker.as_raw(); + (raw_waker.vtable(), raw_waker.data()) + } + + #[cfg(at_least_2024_09_06)] + { + (waker.vtable(), waker.data()) + } } }; From 72109a7bda5cf1568b1ff2b1b4b7de06f73d3342 Mon Sep 17 00:00:00 2001 From: Kenneth Knudsen Date: Wed, 6 Nov 2024 10:52:03 +0100 Subject: [PATCH 0331/1217] Split_ref with shortened lifetime. When borrowed skip drop on rx and tx --- embassy-stm32/src/usart/buffered.rs | 78 +++++++++++++++++++---------- 1 file changed, 52 insertions(+), 26 deletions(-) diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs index d7ac33d07..f7b2bf4b4 100644 --- a/embassy-stm32/src/usart/buffered.rs +++ b/embassy-stm32/src/usart/buffered.rs @@ -157,6 +157,7 @@ pub struct BufferedUartTx<'d> { tx: Option>, cts: Option>, de: Option>, + is_borrowed: bool, } /// Rx-only buffered UART @@ -168,6 +169,7 @@ pub struct BufferedUartRx<'d> { kernel_clock: Hertz, rx: Option>, rts: Option>, + is_borrowed: bool, } impl<'d> SetConfig for BufferedUart<'d> { @@ -341,6 +343,7 @@ impl<'d> BufferedUart<'d> { kernel_clock, rx, rts, + is_borrowed: false, }, tx: BufferedUartTx { info, @@ -349,6 +352,7 @@ impl<'d> BufferedUart<'d> { tx, cts, de, + is_borrowed: false, }, }; this.enable_and_configure(tx_buffer, rx_buffer, &config)?; @@ -396,11 +400,29 @@ impl<'d> BufferedUart<'d> { (self.tx, self.rx) } - /// Split the Uart into a transmitter and receiver by mutable reference, + /// Split the Uart into a transmitter and receiver, /// which is particularly useful when having two tasks correlating to /// transmitting and receiving. - pub fn split_ref(&mut self) -> (&mut BufferedUartTx<'d>, &mut BufferedUartRx<'d>) { - (&mut self.tx, &mut self.rx) + pub fn split_ref(&mut self) -> (BufferedUartTx<'_>, BufferedUartRx<'_>) { + ( + BufferedUartTx { + info: self.tx.info, + state: self.tx.state, + kernel_clock: self.tx.kernel_clock, + tx: self.tx.tx.as_mut().map(PeripheralRef::reborrow), + cts: self.tx.cts.as_mut().map(PeripheralRef::reborrow), + de: self.tx.de.as_mut().map(PeripheralRef::reborrow), + is_borrowed: true, + }, + BufferedUartRx { + info: self.rx.info, + state: self.rx.state, + kernel_clock: self.rx.kernel_clock, + rx: self.rx.rx.as_mut().map(PeripheralRef::reborrow), + rts: self.rx.rts.as_mut().map(PeripheralRef::reborrow), + is_borrowed: true, + }, + ) } /// Reconfigure the driver @@ -607,40 +629,44 @@ impl<'d> BufferedUartTx<'d> { impl<'d> Drop for BufferedUartRx<'d> { fn drop(&mut self) { - let state = self.state; - unsafe { - state.rx_buf.deinit(); + if !self.is_borrowed { + let state = self.state; + unsafe { + state.rx_buf.deinit(); - // TX is inactive if the the buffer is not available. - // We can now unregister the interrupt handler - if state.tx_buf.len() == 0 { - self.info.interrupt.disable(); + // TX is inactive if the the buffer is not available. + // We can now unregister the interrupt handler + if state.tx_buf.len() == 0 { + self.info.interrupt.disable(); + } } - } - self.rx.as_ref().map(|x| x.set_as_disconnected()); - self.rts.as_ref().map(|x| x.set_as_disconnected()); - drop_tx_rx(self.info, state); + self.rx.as_ref().map(|x| x.set_as_disconnected()); + self.rts.as_ref().map(|x| x.set_as_disconnected()); + drop_tx_rx(self.info, state); + } } } impl<'d> Drop for BufferedUartTx<'d> { fn drop(&mut self) { - let state = self.state; - unsafe { - state.tx_buf.deinit(); + if !self.is_borrowed { + let state = self.state; + unsafe { + state.tx_buf.deinit(); - // RX is inactive if the the buffer is not available. - // We can now unregister the interrupt handler - if state.rx_buf.len() == 0 { - self.info.interrupt.disable(); + // RX is inactive if the the buffer is not available. + // We can now unregister the interrupt handler + if state.rx_buf.len() == 0 { + self.info.interrupt.disable(); + } } - } - self.tx.as_ref().map(|x| x.set_as_disconnected()); - self.cts.as_ref().map(|x| x.set_as_disconnected()); - self.de.as_ref().map(|x| x.set_as_disconnected()); - drop_tx_rx(self.info, state); + self.tx.as_ref().map(|x| x.set_as_disconnected()); + self.cts.as_ref().map(|x| x.set_as_disconnected()); + self.de.as_ref().map(|x| x.set_as_disconnected()); + drop_tx_rx(self.info, state); + } } } From 94659325ab7e61381b31a156e7fc61ac912c794c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Wed, 6 Nov 2024 13:56:55 +0100 Subject: [PATCH 0332/1217] Prep executor 0.6.2 --- embassy-executor/CHANGELOG.md | 8 ++++++-- embassy-executor/Cargo.toml | 2 +- embassy-rp/Cargo.toml | 2 +- embassy-stm32/Cargo.toml | 2 +- embassy-time/Cargo.toml | 2 +- examples/boot/application/nrf/Cargo.toml | 2 +- examples/boot/application/rp/Cargo.toml | 2 +- examples/boot/application/stm32f3/Cargo.toml | 2 +- examples/boot/application/stm32f7/Cargo.toml | 2 +- examples/boot/application/stm32h7/Cargo.toml | 2 +- examples/boot/application/stm32l0/Cargo.toml | 2 +- examples/boot/application/stm32l1/Cargo.toml | 2 +- examples/boot/application/stm32l4/Cargo.toml | 2 +- examples/boot/application/stm32wb-dfu/Cargo.toml | 2 +- examples/boot/application/stm32wl/Cargo.toml | 2 +- examples/lpc55s69/Cargo.toml | 2 +- examples/nrf-rtos-trace/Cargo.toml | 2 +- examples/nrf51/Cargo.toml | 2 +- examples/nrf52810/Cargo.toml | 2 +- examples/nrf52840/Cargo.toml | 2 +- examples/nrf5340/Cargo.toml | 2 +- examples/nrf9151/ns/Cargo.toml | 2 +- examples/nrf9151/s/Cargo.toml | 2 +- examples/nrf9160/Cargo.toml | 2 +- examples/rp/Cargo.toml | 2 +- examples/rp23/Cargo.toml | 2 +- examples/std/Cargo.toml | 2 +- examples/stm32c0/Cargo.toml | 2 +- examples/stm32f0/Cargo.toml | 2 +- examples/stm32f1/Cargo.toml | 2 +- examples/stm32f2/Cargo.toml | 2 +- examples/stm32f3/Cargo.toml | 2 +- examples/stm32f334/Cargo.toml | 2 +- examples/stm32f4/Cargo.toml | 2 +- examples/stm32f469/Cargo.toml | 2 +- examples/stm32f7/Cargo.toml | 2 +- examples/stm32g0/Cargo.toml | 2 +- examples/stm32g4/Cargo.toml | 2 +- examples/stm32h5/Cargo.toml | 2 +- examples/stm32h7/Cargo.toml | 2 +- examples/stm32h735/Cargo.toml | 2 +- examples/stm32h755cm4/Cargo.toml | 2 +- examples/stm32h755cm7/Cargo.toml | 2 +- examples/stm32h7b0/Cargo.toml | 2 +- examples/stm32h7rs/Cargo.toml | 2 +- examples/stm32l0/Cargo.toml | 2 +- examples/stm32l1/Cargo.toml | 2 +- examples/stm32l4/Cargo.toml | 2 +- examples/stm32l5/Cargo.toml | 2 +- examples/stm32u0/Cargo.toml | 2 +- examples/stm32u5/Cargo.toml | 2 +- examples/stm32wb/Cargo.toml | 2 +- examples/stm32wba/Cargo.toml | 2 +- examples/stm32wl/Cargo.toml | 2 +- examples/wasm/Cargo.toml | 2 +- tests/nrf/Cargo.toml | 2 +- tests/riscv32/Cargo.toml | 2 +- tests/rp/Cargo.toml | 2 +- tests/stm32/Cargo.toml | 2 +- 59 files changed, 64 insertions(+), 60 deletions(-) diff --git a/embassy-executor/CHANGELOG.md b/embassy-executor/CHANGELOG.md index 3d8c48676..b342ccc32 100644 --- a/embassy-executor/CHANGELOG.md +++ b/embassy-executor/CHANGELOG.md @@ -7,20 +7,24 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +## 0.6.2 - 2024-11-06 + +- The `nightly` feature no longer requires `nightly-2024-09-06` or newer. + ## 0.6.1 - 2024-10-21 - Soundness fix: Deny using `impl Trait` in task arguments. This was previously accidentally allowed when not using the `nightly` feature, and could cause out of bounds memory accesses if spawning the same task mulitple times with different underlying types for the `impl Trait`. Affected versions are 0.4.x, 0.5.0 and 0.6.0, which have been yanked. - Add an architecture-agnostic executor that spins waiting for tasks to run, enabled with the `arch-spin` feature. -- Update for breaking change in the nightly waker_getters API. The `nightly` feature now requires`nightly-2024-09-06` or newer. +- Update for breaking change in the nightly waker_getters API. The `nightly` feature now requires `nightly-2024-09-06` or newer. - Improve macro error messages. ## 0.6.0 - 2024-08-05 - Add collapse_debuginfo to fmt.rs macros. - initial support for AVR -- use nightly waker_getters APIs +- use nightly waker_getters APIs ## 0.5.1 - 2024-10-21 diff --git a/embassy-executor/Cargo.toml b/embassy-executor/Cargo.toml index 6011d8663..6b16a6343 100644 --- a/embassy-executor/Cargo.toml +++ b/embassy-executor/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "embassy-executor" -version = "0.6.1" +version = "0.6.2" edition = "2021" license = "MIT OR Apache-2.0" description = "async/await executor designed for embedded usage" diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index 3e61641ff..4616116aa 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml @@ -147,5 +147,5 @@ rp-binary-info = { version = "0.1.0", optional = true } smart-leds = "0.4.0" [dev-dependencies] -embassy-executor = { version = "0.6.1", path = "../embassy-executor", features = ["arch-std", "executor-thread"] } +embassy-executor = { version = "0.6.2", path = "../embassy-executor", features = ["arch-std", "executor-thread"] } static_cell = { version = "2" } diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 9fdc799d8..6ab6e162e 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -51,7 +51,7 @@ embassy-embedded-hal = {version = "0.2.0", path = "../embassy-embedded-hal", def embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver" } embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver" } embassy-usb-synopsys-otg = {version = "0.1.0", path = "../embassy-usb-synopsys-otg" } -embassy-executor = { version = "0.6.1", path = "../embassy-executor", optional = true } +embassy-executor = { version = "0.6.2", path = "../embassy-executor", optional = true } embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } embedded-hal-1 = { package = "embedded-hal", version = "1.0" } diff --git a/embassy-time/Cargo.toml b/embassy-time/Cargo.toml index dc3561145..0e61434f1 100644 --- a/embassy-time/Cargo.toml +++ b/embassy-time/Cargo.toml @@ -431,4 +431,4 @@ wasm-timer = { version = "0.2.5", optional = true } [dev-dependencies] serial_test = "0.9" critical-section = { version = "1.1", features = ["std"] } -embassy-executor = { version = "0.6.1", path = "../embassy-executor" } +embassy-executor = { version = "0.6.2", path = "../embassy-executor" } diff --git a/examples/boot/application/nrf/Cargo.toml b/examples/boot/application/nrf/Cargo.toml index 3815ac196..e2ae240ae 100644 --- a/examples/boot/application/nrf/Cargo.toml +++ b/examples/boot/application/nrf/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.6.1", path = "../../../../embassy-executor", features = ["task-arena-size-16384", "arch-cortex-m", "executor-thread", "integrated-timers", "arch-cortex-m", "executor-thread"] } +embassy-executor = { version = "0.6.2", path = "../../../../embassy-executor", features = ["task-arena-size-16384", "arch-cortex-m", "executor-thread", "integrated-timers", "arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [] } embassy-nrf = { version = "0.2.0", path = "../../../../embassy-nrf", features = ["time-driver-rtc1", "gpiote", ] } embassy-boot = { version = "0.3.0", path = "../../../../embassy-boot", features = [] } diff --git a/examples/boot/application/rp/Cargo.toml b/examples/boot/application/rp/Cargo.toml index 86ea9fc2a..f61ac3fd9 100644 --- a/examples/boot/application/rp/Cargo.toml +++ b/examples/boot/application/rp/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.6.1", path = "../../../../embassy-executor", features = ["task-arena-size-16384", "arch-cortex-m", "executor-thread", "integrated-timers", "arch-cortex-m", "executor-thread"] } +embassy-executor = { version = "0.6.2", path = "../../../../embassy-executor", features = ["task-arena-size-16384", "arch-cortex-m", "executor-thread", "integrated-timers", "arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [] } embassy-rp = { version = "0.2.0", path = "../../../../embassy-rp", features = ["time-driver", "rp2040"] } embassy-boot-rp = { version = "0.3.0", path = "../../../../embassy-boot-rp", features = [] } diff --git a/examples/boot/application/stm32f3/Cargo.toml b/examples/boot/application/stm32f3/Cargo.toml index 29049e58c..dd20d2e0d 100644 --- a/examples/boot/application/stm32f3/Cargo.toml +++ b/examples/boot/application/stm32f3/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.6.1", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } +embassy-executor = { version = "0.6.2", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32f303re", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32" } diff --git a/examples/boot/application/stm32f7/Cargo.toml b/examples/boot/application/stm32f7/Cargo.toml index ed102b073..ce38e9ab9 100644 --- a/examples/boot/application/stm32f7/Cargo.toml +++ b/examples/boot/application/stm32f7/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.6.1", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } +embassy-executor = { version = "0.6.2", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32f767zi", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } diff --git a/examples/boot/application/stm32h7/Cargo.toml b/examples/boot/application/stm32h7/Cargo.toml index cc705b1d6..841075627 100644 --- a/examples/boot/application/stm32h7/Cargo.toml +++ b/examples/boot/application/stm32h7/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.6.1", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } +embassy-executor = { version = "0.6.2", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32h743zi", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } diff --git a/examples/boot/application/stm32l0/Cargo.toml b/examples/boot/application/stm32l0/Cargo.toml index 17fc1d7d0..1a92517db 100644 --- a/examples/boot/application/stm32l0/Cargo.toml +++ b/examples/boot/application/stm32l0/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.6.1", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } +embassy-executor = { version = "0.6.2", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l072cz", "time-driver-any", "exti", "memory-x"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } diff --git a/examples/boot/application/stm32l1/Cargo.toml b/examples/boot/application/stm32l1/Cargo.toml index fd2c19f99..57eeb07a1 100644 --- a/examples/boot/application/stm32l1/Cargo.toml +++ b/examples/boot/application/stm32l1/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.6.1", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } +embassy-executor = { version = "0.6.2", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l151cb-a", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } diff --git a/examples/boot/application/stm32l4/Cargo.toml b/examples/boot/application/stm32l4/Cargo.toml index 3852261ac..f51ca29e1 100644 --- a/examples/boot/application/stm32l4/Cargo.toml +++ b/examples/boot/application/stm32l4/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.6.1", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } +embassy-executor = { version = "0.6.2", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l475vg", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } diff --git a/examples/boot/application/stm32wb-dfu/Cargo.toml b/examples/boot/application/stm32wb-dfu/Cargo.toml index 2d89f6d42..112de92f1 100644 --- a/examples/boot/application/stm32wb-dfu/Cargo.toml +++ b/examples/boot/application/stm32wb-dfu/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.6.1", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } +embassy-executor = { version = "0.6.2", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32wb55rg", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } diff --git a/examples/boot/application/stm32wl/Cargo.toml b/examples/boot/application/stm32wl/Cargo.toml index e07d97d86..e2c42ce20 100644 --- a/examples/boot/application/stm32wl/Cargo.toml +++ b/examples/boot/application/stm32wl/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.6.1", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } +embassy-executor = { version = "0.6.2", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32wl55jc-cm4", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } diff --git a/examples/lpc55s69/Cargo.toml b/examples/lpc55s69/Cargo.toml index a69007a2c..a18b29f2e 100644 --- a/examples/lpc55s69/Cargo.toml +++ b/examples/lpc55s69/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-nxp = { version = "0.1.0", path = "../../embassy-nxp", features = ["rt"] } -embassy-executor = { version = "0.6.1", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt"] } +embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt"] } panic-halt = "0.2.0" diff --git a/examples/nrf-rtos-trace/Cargo.toml b/examples/nrf-rtos-trace/Cargo.toml index 2358ced56..fbdd2744c 100644 --- a/examples/nrf-rtos-trace/Cargo.toml +++ b/examples/nrf-rtos-trace/Cargo.toml @@ -16,7 +16,7 @@ log = [ [dependencies] embassy-sync = { version = "0.6.0", path = "../../embassy-sync" } -embassy-executor = { version = "0.6.1", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "rtos-trace", "integrated-timers"] } +embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "rtos-trace", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time" } embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] } diff --git a/examples/nrf51/Cargo.toml b/examples/nrf51/Cargo.toml index f94026158..3799a87cc 100644 --- a/examples/nrf51/Cargo.toml +++ b/examples/nrf51/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-executor = { version = "0.6.1", path = "../../embassy-executor", features = ["task-arena-size-4096", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["task-arena-size-4096", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf51", "gpiote", "time-driver-rtc1", "unstable-pac", "time", "rt"] } diff --git a/examples/nrf52810/Cargo.toml b/examples/nrf52810/Cargo.toml index 867ead6d8..e3045bdba 100644 --- a/examples/nrf52810/Cargo.toml +++ b/examples/nrf52810/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.1", path = "../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf52810", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } diff --git a/examples/nrf52840/Cargo.toml b/examples/nrf52840/Cargo.toml index cb05b7204..e0a27c628 100644 --- a/examples/nrf52840/Cargo.toml +++ b/examples/nrf52840/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.1", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } diff --git a/examples/nrf5340/Cargo.toml b/examples/nrf5340/Cargo.toml index 2387eaa58..2a4e78b7c 100644 --- a/examples/nrf5340/Cargo.toml +++ b/examples/nrf5340/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.1", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf5340-app-s", "time-driver-rtc1", "gpiote", "unstable-pac"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } diff --git a/examples/nrf9151/ns/Cargo.toml b/examples/nrf9151/ns/Cargo.toml index 78260dae3..679331716 100644 --- a/examples/nrf9151/ns/Cargo.toml +++ b/examples/nrf9151/ns/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-executor = { version = "0.6.1", path = "../../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.2", path = "../../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.2.0", path = "../../../embassy-nrf", features = ["defmt", "nrf9120-ns", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } diff --git a/examples/nrf9151/s/Cargo.toml b/examples/nrf9151/s/Cargo.toml index 17ead4ab4..63114478b 100644 --- a/examples/nrf9151/s/Cargo.toml +++ b/examples/nrf9151/s/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-executor = { version = "0.6.1", path = "../../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.2", path = "../../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.2.0", path = "../../../embassy-nrf", features = ["defmt", "nrf9120-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } diff --git a/examples/nrf9160/Cargo.toml b/examples/nrf9160/Cargo.toml index 2572f3353..d5b0f0a41 100644 --- a/examples/nrf9160/Cargo.toml +++ b/examples/nrf9160/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-executor = { version = "0.6.1", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf9160-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } embassy-net-nrf91 = { version = "0.1.0", path = "../../embassy-net-nrf91", features = ["defmt"] } diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index b55b20c63..b45f5040a 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal", features = ["defmt"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.1", path = "../../embassy-executor", features = ["task-arena-size-98304", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["task-arena-size-98304", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-rp = { version = "0.2.0", path = "../../embassy-rp", features = ["defmt", "unstable-pac", "time-driver", "critical-section-impl", "rp2040"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/rp23/Cargo.toml b/examples/rp23/Cargo.toml index eec12a9ab..99a75a67f 100644 --- a/examples/rp23/Cargo.toml +++ b/examples/rp23/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal", features = ["defmt"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.1", path = "../../embassy-executor", features = ["task-arena-size-98304", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["task-arena-size-98304", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-rp = { version = "0.2.0", path = "../../embassy-rp", features = ["defmt", "unstable-pac", "time-driver", "critical-section-impl", "rp235xa", "binary-info"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/std/Cargo.toml b/examples/std/Cargo.toml index 27d0062fb..fac180c0c 100644 --- a/examples/std/Cargo.toml +++ b/examples/std/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["log"] } -embassy-executor = { version = "0.6.1", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-std", "executor-thread", "log", "integrated-timers"] } +embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-std", "executor-thread", "log", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["log", "std", ] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features=[ "std", "log", "medium-ethernet", "medium-ip", "tcp", "udp", "dns", "dhcpv4", "proto-ipv6"] } embassy-net-tuntap = { version = "0.1.0", path = "../../embassy-net-tuntap" } diff --git a/examples/stm32c0/Cargo.toml b/examples/stm32c0/Cargo.toml index 46a25cc4d..f8a845095 100644 --- a/examples/stm32c0/Cargo.toml +++ b/examples/stm32c0/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32c031c6 to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32c031c6", "memory-x", "unstable-pac", "exti"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.1", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } defmt = "0.3" diff --git a/examples/stm32f0/Cargo.toml b/examples/stm32f0/Cargo.toml index 93d9ab7ce..6154fdc64 100644 --- a/examples/stm32f0/Cargo.toml +++ b/examples/stm32f0/Cargo.toml @@ -13,7 +13,7 @@ defmt = "0.3" defmt-rtt = "0.4" panic-probe = { version = "0.3", features = ["print-defmt"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.1", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } static_cell = "2" portable-atomic = { version = "1.5", features = ["unsafe-assume-single-core"] } diff --git a/examples/stm32f1/Cargo.toml b/examples/stm32f1/Cargo.toml index a75d0fe4c..c4836859e 100644 --- a/examples/stm32f1/Cargo.toml +++ b/examples/stm32f1/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32f103c8 to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f103c8", "unstable-pac", "memory-x", "time-driver-any" ] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.1", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32f2/Cargo.toml b/examples/stm32f2/Cargo.toml index 166729211..0e4827e5d 100644 --- a/examples/stm32f2/Cargo.toml +++ b/examples/stm32f2/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32f207zg to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f207zg", "unstable-pac", "memory-x", "time-driver-any", "exti"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.1", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } defmt = "0.3" diff --git a/examples/stm32f3/Cargo.toml b/examples/stm32f3/Cargo.toml index e60ea80c6..08a921634 100644 --- a/examples/stm32f3/Cargo.toml +++ b/examples/stm32f3/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32f303ze to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f303ze", "unstable-pac", "memory-x", "time-driver-any", "exti"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.1", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32f334/Cargo.toml b/examples/stm32f334/Cargo.toml index 4ba993009..cba83bf8c 100644 --- a/examples/stm32f334/Cargo.toml +++ b/examples/stm32f334/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.1", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f334r8", "unstable-pac", "memory-x", "time-driver-any", "exti"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/stm32f4/Cargo.toml b/examples/stm32f4/Cargo.toml index 975e47398..32fb845cb 100644 --- a/examples/stm32f4/Cargo.toml +++ b/examples/stm32f4/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32f429zi to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32f429zi", "unstable-pac", "memory-x", "time-driver-any", "exti", "chrono"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.1", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt" ] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", ] } diff --git a/examples/stm32f469/Cargo.toml b/examples/stm32f469/Cargo.toml index 4e1a778cd..139b4b937 100644 --- a/examples/stm32f469/Cargo.toml +++ b/examples/stm32f469/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Specific examples only for stm32f469 embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32f469ni", "unstable-pac", "memory-x", "time-driver-any", "exti", "chrono"] } -embassy-executor = { version = "0.6.1", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } defmt = "0.3" diff --git a/examples/stm32f7/Cargo.toml b/examples/stm32f7/Cargo.toml index 879b05d91..2c55da04c 100644 --- a/examples/stm32f7/Cargo.toml +++ b/examples/stm32f7/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32f777zi to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32f777zi", "memory-x", "unstable-pac", "time-driver-any", "exti"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.1", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } embedded-io-async = { version = "0.6.1" } diff --git a/examples/stm32g0/Cargo.toml b/examples/stm32g0/Cargo.toml index 77f70e57d..bf258a7fd 100644 --- a/examples/stm32g0/Cargo.toml +++ b/examples/stm32g0/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32g0b1re to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32g0b1re", "memory-x", "unstable-pac", "exti"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.1", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", default-features = false, features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32g4/Cargo.toml b/examples/stm32g4/Cargo.toml index 86d29f94e..cc3b44b57 100644 --- a/examples/stm32g4/Cargo.toml +++ b/examples/stm32g4/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32g491re to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32g491re", "memory-x", "unstable-pac", "exti"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.1", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32h5/Cargo.toml b/examples/stm32h5/Cargo.toml index 9ca8bc969..d1a865e4c 100644 --- a/examples/stm32h5/Cargo.toml +++ b/examples/stm32h5/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32h563zi to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h563zi", "memory-x", "time-driver-any", "exti", "unstable-pac", "low-power"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.1", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/stm32h7/Cargo.toml b/examples/stm32h7/Cargo.toml index f2f207395..1ba792f72 100644 --- a/examples/stm32h7/Cargo.toml +++ b/examples/stm32h7/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h743bi", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } -embassy-executor = { version = "0.6.1", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/stm32h735/Cargo.toml b/examples/stm32h735/Cargo.toml index bac76ddfb..6a74d83ab 100644 --- a/examples/stm32h735/Cargo.toml +++ b/examples/stm32h735/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h735ig", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } -embassy-executor = { version = "0.6.1", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32h755cm4/Cargo.toml b/examples/stm32h755cm4/Cargo.toml index 1fbceddde..ee96e64d6 100644 --- a/examples/stm32h755cm4/Cargo.toml +++ b/examples/stm32h755cm4/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h755zi-cm4", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } -embassy-executor = { version = "0.6.1", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/stm32h755cm7/Cargo.toml b/examples/stm32h755cm7/Cargo.toml index 8b864169b..61c425719 100644 --- a/examples/stm32h755cm7/Cargo.toml +++ b/examples/stm32h755cm7/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h755zi-cm7", "time-driver-tim3", "exti", "memory-x", "unstable-pac", "chrono"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } -embassy-executor = { version = "0.6.1", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/stm32h7b0/Cargo.toml b/examples/stm32h7b0/Cargo.toml index 02c620443..255ce933c 100644 --- a/examples/stm32h7b0/Cargo.toml +++ b/examples/stm32h7b0/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h7b0vb", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } -embassy-executor = { version = "0.6.1", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/stm32h7rs/Cargo.toml b/examples/stm32h7rs/Cargo.toml index 29881bf8b..055be6a91 100644 --- a/examples/stm32h7rs/Cargo.toml +++ b/examples/stm32h7rs/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32h743bi to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h7s3l8", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.1", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/stm32l0/Cargo.toml b/examples/stm32l0/Cargo.toml index 273cdce1d..4e2bb8b67 100644 --- a/examples/stm32l0/Cargo.toml +++ b/examples/stm32l0/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32l072cz to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32l072cz", "unstable-pac", "time-driver-any", "exti", "memory-x"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.1", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } defmt = "0.3" diff --git a/examples/stm32l1/Cargo.toml b/examples/stm32l1/Cargo.toml index af4775a74..865cad87f 100644 --- a/examples/stm32l1/Cargo.toml +++ b/examples/stm32l1/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.1", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32l151cb-a", "time-driver-any", "memory-x"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/stm32l4/Cargo.toml b/examples/stm32l4/Cargo.toml index 70c5c5e26..7f963fc53 100644 --- a/examples/stm32l4/Cargo.toml +++ b/examples/stm32l4/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32l4s5vi to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32l4s5qi", "memory-x", "time-driver-any", "exti", "chrono"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.1", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768", ] } embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/stm32l5/Cargo.toml b/examples/stm32l5/Cargo.toml index 78cb79eac..0604625f2 100644 --- a/examples/stm32l5/Cargo.toml +++ b/examples/stm32l5/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32l552ze to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32l552ze", "time-driver-any", "exti", "memory-x", "low-power"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.1", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } diff --git a/examples/stm32u0/Cargo.toml b/examples/stm32u0/Cargo.toml index 931409b51..97ef0b704 100644 --- a/examples/stm32u0/Cargo.toml +++ b/examples/stm32u0/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32u083rc to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32u083rc", "memory-x", "unstable-pac", "exti", "chrono"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.1", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", default-features = false, features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32u5/Cargo.toml b/examples/stm32u5/Cargo.toml index 8b576425c..f474e6db0 100644 --- a/examples/stm32u5/Cargo.toml +++ b/examples/stm32u5/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32u5g9zj to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "unstable-pac", "stm32u5g9zj", "time-driver-any", "memory-x" ] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.1", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32wb/Cargo.toml b/examples/stm32wb/Cargo.toml index 8cea2ace8..26de81122 100644 --- a/examples/stm32wb/Cargo.toml +++ b/examples/stm32wb/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32wb55rg", "time-driver-any", "memory-x", "exti"] } embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", features = ["defmt", "stm32wb55rg"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.1", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", ], optional=true } diff --git a/examples/stm32wba/Cargo.toml b/examples/stm32wba/Cargo.toml index 4261564dd..807f809e0 100644 --- a/examples/stm32wba/Cargo.toml +++ b/examples/stm32wba/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32wba52cg", "time-driver-any", "memory-x", "exti"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.1", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", ], optional=true } diff --git a/examples/stm32wl/Cargo.toml b/examples/stm32wl/Cargo.toml index f8d5afb86..3b4223977 100644 --- a/examples/stm32wl/Cargo.toml +++ b/examples/stm32wl/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32wl55jc-cm4 to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32wl55jc-cm4", "time-driver-any", "memory-x", "unstable-pac", "exti", "chrono"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.1", path = "../../embassy-executor", features = ["task-arena-size-4096", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["task-arena-size-4096", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } diff --git a/examples/wasm/Cargo.toml b/examples/wasm/Cargo.toml index f8db71233..ea66d9b99 100644 --- a/examples/wasm/Cargo.toml +++ b/examples/wasm/Cargo.toml @@ -9,7 +9,7 @@ crate-type = ["cdylib"] [dependencies] embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["log"] } -embassy-executor = { version = "0.6.1", path = "../../embassy-executor", features = ["arch-wasm", "executor-thread", "log", "integrated-timers"] } +embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["arch-wasm", "executor-thread", "log", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["log", "wasm", ] } wasm-logger = "0.2.0" diff --git a/tests/nrf/Cargo.toml b/tests/nrf/Cargo.toml index 6a710f29d..c1d386b93 100644 --- a/tests/nrf/Cargo.toml +++ b/tests/nrf/Cargo.toml @@ -9,7 +9,7 @@ teleprobe-meta = "1" embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt", ] } -embassy-executor = { version = "0.6.1", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "task-arena-size-16384", "integrated-timers"] } +embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "task-arena-size-16384", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "time-driver-rtc1", "gpiote", "unstable-pac"] } embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } diff --git a/tests/riscv32/Cargo.toml b/tests/riscv32/Cargo.toml index 0ee7f5a00..35dd283eb 100644 --- a/tests/riscv32/Cargo.toml +++ b/tests/riscv32/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] critical-section = { version = "1.1.1", features = ["restore-state-bool"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync" } -embassy-executor = { version = "0.6.1", path = "../../embassy-executor", features = ["arch-riscv32", "executor-thread"] } +embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["arch-riscv32", "executor-thread"] } embassy-time = { version = "0.3.2", path = "../../embassy-time" } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/tests/rp/Cargo.toml b/tests/rp/Cargo.toml index ce812af78..72f7ceb8f 100644 --- a/tests/rp/Cargo.toml +++ b/tests/rp/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" teleprobe-meta = "1.1" embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.1", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", ] } embassy-rp = { version = "0.2.0", path = "../../embassy-rp", features = [ "defmt", "unstable-pac", "time-driver", "critical-section-impl", "intrinsics", "rom-v2-intrinsics", "run-from-ram", "rp2040"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml index 468d2ed54..f30217fc0 100644 --- a/tests/stm32/Cargo.toml +++ b/tests/stm32/Cargo.toml @@ -60,7 +60,7 @@ cm0 = ["portable-atomic/unsafe-assume-single-core"] teleprobe-meta = "1" embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.1", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "tick-hz-131_072", "defmt-timestamp-uptime"] } embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "memory-x", "time-driver-any"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } From aeb85454e9e8f59f36a434ea25bdeef5d2f330ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Wed, 6 Nov 2024 14:09:41 +0100 Subject: [PATCH 0333/1217] Also bump macros --- embassy-executor-macros/Cargo.toml | 2 +- embassy-executor/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-executor-macros/Cargo.toml b/embassy-executor-macros/Cargo.toml index 306cf8352..5a38f2f06 100644 --- a/embassy-executor-macros/Cargo.toml +++ b/embassy-executor-macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "embassy-executor-macros" -version = "0.6.1" +version = "0.6.2" edition = "2021" license = "MIT OR Apache-2.0" description = "macros for creating the entry point and tasks for embassy-executor" diff --git a/embassy-executor/Cargo.toml b/embassy-executor/Cargo.toml index 6b16a6343..2450ae61b 100644 --- a/embassy-executor/Cargo.toml +++ b/embassy-executor/Cargo.toml @@ -33,7 +33,7 @@ defmt = { version = "0.3", optional = true } log = { version = "0.4.14", optional = true } rtos-trace = { version = "0.1.2", optional = true } -embassy-executor-macros = { version = "0.6.1", path = "../embassy-executor-macros" } +embassy-executor-macros = { version = "0.6.2", path = "../embassy-executor-macros" } embassy-time-driver = { version = "0.1.0", path = "../embassy-time-driver", optional = true } embassy-time-queue-driver = { version = "0.1.0", path = "../embassy-time-queue-driver", optional = true } critical-section = "1.1" From 555231aeb510ed17996c2446ad412aefd4258cb3 Mon Sep 17 00:00:00 2001 From: elagil Date: Wed, 6 Nov 2024 19:46:52 +0100 Subject: [PATCH 0334/1217] chore: update stm32 data source --- embassy-stm32/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 6ab6e162e..e2ba4fd60 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -72,7 +72,7 @@ rand_core = "0.6.3" sdio-host = "0.5.0" critical-section = "1.1" #stm32-metapac = { version = "15" } -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-9b7414490b10ffbd5beb1b0dcf14adb018cbe37f" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-7bb5f235587c3a6886a7be1c8f58fdf22c5257f3" } vcell = "0.1.3" nb = "1.0.0" @@ -101,7 +101,7 @@ proc-macro2 = "1.0.36" quote = "1.0.15" #stm32-metapac = { version = "15", default-features = false, features = ["metadata"]} -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-9b7414490b10ffbd5beb1b0dcf14adb018cbe37f", default-features = false, features = ["metadata"] } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-7bb5f235587c3a6886a7be1c8f58fdf22c5257f3", default-features = false, features = ["metadata"] } [features] default = ["rt"] From e69be0a23bc182a78f2647cc1a739910a1a8e985 Mon Sep 17 00:00:00 2001 From: elagil Date: Wed, 6 Nov 2024 19:46:55 +0100 Subject: [PATCH 0335/1217] fix: STM32U5 RCC fields --- embassy-stm32/src/rcc/u5.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/embassy-stm32/src/rcc/u5.rs b/embassy-stm32/src/rcc/u5.rs index 28545ca51..1e2bfe62d 100644 --- a/embassy-stm32/src/rcc/u5.rs +++ b/embassy-stm32/src/rcc/u5.rs @@ -279,8 +279,10 @@ pub(crate) unsafe fn init(config: Config) { hsi48: hsi48, rtc: rtc, hse: hse, + hse_div_2: hse.map(|clk| clk / 2u32), hsi: hsi, pll1_p: pll1.p, + pll1_p_div_2: pll1.p.map(|clk| clk / 2u32), pll1_q: pll1.q, pll1_r: pll1.r, pll2_p: pll2.p, From 7231032f977fe4a1a486dfd963f7105b01bf684d Mon Sep 17 00:00:00 2001 From: Christian Enderle Date: Thu, 7 Nov 2024 13:23:39 +0100 Subject: [PATCH 0336/1217] RCC: added msik for stm32u5 --- embassy-stm32/src/rcc/u5.rs | 42 +++++++++++++++++++++++++++++++------ 1 file changed, 36 insertions(+), 6 deletions(-) diff --git a/embassy-stm32/src/rcc/u5.rs b/embassy-stm32/src/rcc/u5.rs index 1e2bfe62d..bb3d5f320 100644 --- a/embassy-stm32/src/rcc/u5.rs +++ b/embassy-stm32/src/rcc/u5.rs @@ -62,7 +62,8 @@ pub struct Pll { #[derive(Clone, Copy)] pub struct Config { // base clock sources - pub msi: Option, + pub msis: Option, + pub msik: Option, pub hsi: bool, pub hse: Option, pub hsi48: Option, @@ -94,7 +95,8 @@ pub struct Config { impl Default for Config { fn default() -> Self { Self { - msi: Some(Msirange::RANGE_4MHZ), + msis: Some(Msirange::RANGE_4MHZ), + msik: Some(Msirange::RANGE_4MHZ), hse: None, hsi: false, hsi48: Some(Default::default()), @@ -118,7 +120,7 @@ pub(crate) unsafe fn init(config: Config) { PWR.vosr().modify(|w| w.set_vos(config.voltage_range)); while !PWR.vosr().read().vosrdy() {} - let msi = config.msi.map(|range| { + let msis = config.msis.map(|range| { // Check MSI output per RM0456 § 11.4.10 match config.voltage_range { VoltageScale::RANGE4 => { @@ -147,6 +149,34 @@ pub(crate) unsafe fn init(config: Config) { msirange_to_hertz(range) }); + let msik = config.msik.map(|range| { + // Check MSI output per RM0456 § 11.4.10 + match config.voltage_range { + VoltageScale::RANGE4 => { + assert!(msirange_to_hertz(range).0 <= 24_000_000); + } + _ => {} + } + + // RM0456 § 11.8.2: spin until MSIS is off or MSIS is ready before setting its range + loop { + let cr = RCC.cr().read(); + if cr.msikon() == false || cr.msikrdy() == true { + break; + } + } + + RCC.icscr1().modify(|w| { + w.set_msikrange(range); + w.set_msirgsel(Msirgsel::ICSCR1); + }); + RCC.cr().write(|w| { + w.set_msikon(true); + }); + while !RCC.cr().read().msikrdy() {} + msirange_to_hertz(range) + }); + let hsi = config.hsi.then(|| { RCC.cr().write(|w| w.set_hsion(true)); while !RCC.cr().read().hsirdy() {} @@ -181,7 +211,7 @@ pub(crate) unsafe fn init(config: Config) { let hsi48 = config.hsi48.map(super::init_hsi48); - let pll_input = PllInput { hse, hsi, msi }; + let pll_input = PllInput { hse, hsi, msi: msis }; let pll1 = init_pll(PllInstance::Pll1, config.pll1, &pll_input, config.voltage_range); let pll2 = init_pll(PllInstance::Pll2, config.pll2, &pll_input, config.voltage_range); let pll3 = init_pll(PllInstance::Pll3, config.pll3, &pll_input, config.voltage_range); @@ -189,7 +219,7 @@ pub(crate) unsafe fn init(config: Config) { let sys_clk = match config.sys { Sysclk::HSE => hse.unwrap(), Sysclk::HSI => hsi.unwrap(), - Sysclk::MSIS => msi.unwrap(), + Sysclk::MSIS => msis.unwrap(), Sysclk::PLL1_R => pll1.r.unwrap(), }; @@ -276,6 +306,7 @@ pub(crate) unsafe fn init(config: Config) { pclk3: Some(pclk3), pclk1_tim: Some(pclk1_tim), pclk2_tim: Some(pclk2_tim), + msik: msik, hsi48: hsi48, rtc: rtc, hse: hse, @@ -300,7 +331,6 @@ pub(crate) unsafe fn init(config: Config) { hsi48_div_2: None, lse: None, lsi: None, - msik: None, shsi: None, shsi_div_2: None, ); From cf2424f5c21416571ccd695ccea61b447094c9ef Mon Sep 17 00:00:00 2001 From: Christian Enderle Date: Thu, 7 Nov 2024 14:16:10 +0100 Subject: [PATCH 0337/1217] RCC: add lsi and lse clock frequency for STM32U5 --- embassy-stm32/src/rcc/u5.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/rcc/u5.rs b/embassy-stm32/src/rcc/u5.rs index bb3d5f320..af99c77bc 100644 --- a/embassy-stm32/src/rcc/u5.rs +++ b/embassy-stm32/src/rcc/u5.rs @@ -5,6 +5,7 @@ pub use crate::pac::rcc::vals::{ }; use crate::pac::rcc::vals::{Hseext, Msirgsel, Pllmboost, Pllrge}; use crate::pac::{FLASH, PWR, RCC}; +use crate::rcc::LSI_FREQ; use crate::time::Hertz; /// HSI speed @@ -294,6 +295,9 @@ pub(crate) unsafe fn init(config: Config) { let rtc = config.ls.init(); + let lse = config.ls.lse.map(|l| l.frequency); + let lsi = config.ls.lsi.then_some(LSI_FREQ); + config.mux.init(); set_clocks!( @@ -309,6 +313,8 @@ pub(crate) unsafe fn init(config: Config) { msik: msik, hsi48: hsi48, rtc: rtc, + lse: lse, + lsi: lsi, hse: hse, hse_div_2: hse.map(|clk| clk / 2u32), hsi: hsi, @@ -329,8 +335,6 @@ pub(crate) unsafe fn init(config: Config) { // TODO audioclk: None, hsi48_div_2: None, - lse: None, - lsi: None, shsi: None, shsi_div_2: None, ); From 0de204ccd7fea064f1b2ad5f0830a9b8ff0a09a9 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Fri, 8 Nov 2024 13:20:13 +0100 Subject: [PATCH 0338/1217] Fix "non-local impl definition" warning from recent nightlies. --- embassy-nrf/src/lib.rs | 59 +++++++++++++++++++++++----------------- embassy-rp/src/lib.rs | 15 ++++++++-- embassy-stm32/src/lib.rs | 11 +++++++- 3 files changed, 56 insertions(+), 29 deletions(-) diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index 03d3ca5f7..430b6fae7 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs @@ -177,34 +177,43 @@ mod chip; // developer note: this macro can't be in `embassy-hal-internal` due to the use of `$crate`. #[macro_export] macro_rules! bind_interrupts { - ($vis:vis struct $name:ident { - $( - $(#[cfg($cond_irq:meta)])? - $irq:ident => $( - $(#[cfg($cond_handler:meta)])? - $handler:ty - ),*; - )* - }) => { - #[derive(Copy, Clone)] - $vis struct $name; + ($vis:vis struct $name:ident { + $( + $(#[cfg($cond_irq:meta)])? + $irq:ident => $( + $(#[cfg($cond_handler:meta)])? + $handler:ty + ),*; + )* + }) => { + #[derive(Copy, Clone)] + $vis struct $name; - $( - #[allow(non_snake_case)] - #[no_mangle] - $(#[cfg($cond_irq)])? - unsafe extern "C" fn $irq() { - $( - $(#[cfg($cond_handler)])? - <$handler as $crate::interrupt::typelevel::Handler<$crate::interrupt::typelevel::$irq>>::on_interrupt(); + $( + #[allow(non_snake_case)] + #[no_mangle] + $(#[cfg($cond_irq)])? + unsafe extern "C" fn $irq() { + $( + $(#[cfg($cond_handler)])? + <$handler as $crate::interrupt::typelevel::Handler<$crate::interrupt::typelevel::$irq>>::on_interrupt(); - $(#[cfg($cond_handler)])? - unsafe impl $crate::interrupt::typelevel::Binding<$crate::interrupt::typelevel::$irq, $handler> for $name {} - )* - } - )* - }; + )* + } + + $(#[cfg($cond_irq)])? + $crate::bind_interrupts!(@inner + $( + $(#[cfg($cond_handler)])? + unsafe impl $crate::interrupt::typelevel::Binding<$crate::interrupt::typelevel::$irq, $handler> for $name {} + )* + ); + )* + }; + (@inner $($t:tt)*) => { + $($t)* } +} // Reexports diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs index 51f6ed7f8..f0893b5a0 100644 --- a/embassy-rp/src/lib.rs +++ b/embassy-rp/src/lib.rs @@ -175,8 +175,8 @@ macro_rules! bind_interrupts { ),*; )* }) => { - #[derive(Copy, Clone)] - $vis struct $name; + #[derive(Copy, Clone)] + $vis struct $name; $( #[allow(non_snake_case)] @@ -187,12 +187,21 @@ macro_rules! bind_interrupts { $(#[cfg($cond_handler)])? <$handler as $crate::interrupt::typelevel::Handler<$crate::interrupt::typelevel::$irq>>::on_interrupt(); + )* + } + + $(#[cfg($cond_irq)])? + $crate::bind_interrupts!(@inner + $( $(#[cfg($cond_handler)])? unsafe impl $crate::interrupt::typelevel::Binding<$crate::interrupt::typelevel::$irq, $handler> for $name {} )* - } + ); )* }; + (@inner $($t:tt)*) => { + $($t)* + } } #[cfg(feature = "rp2040")] diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 1e6185bc1..286a18da2 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -186,12 +186,21 @@ macro_rules! bind_interrupts { $(#[cfg($cond_handler)])? <$handler as $crate::interrupt::typelevel::Handler<$crate::interrupt::typelevel::$irq>>::on_interrupt(); + )* + } + + $(#[cfg($cond_irq)])? + $crate::bind_interrupts!(@inner + $( $(#[cfg($cond_handler)])? unsafe impl $crate::interrupt::typelevel::Binding<$crate::interrupt::typelevel::$irq, $handler> for $name {} )* - } + ); )* }; + (@inner $($t:tt)*) => { + $($t)* + } } // Reexports From af5e23ade0f0cb9ec945fded3005d11f8bc157d3 Mon Sep 17 00:00:00 2001 From: Giona Imperatori Date: Sat, 9 Nov 2024 21:50:20 +0100 Subject: [PATCH 0339/1217] fix(nrf5340-app): added SPIM4 peripheral --- embassy-nrf/src/chips/nrf5340_app.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/embassy-nrf/src/chips/nrf5340_app.rs b/embassy-nrf/src/chips/nrf5340_app.rs index 43588eef3..d7846b094 100644 --- a/embassy-nrf/src/chips/nrf5340_app.rs +++ b/embassy-nrf/src/chips/nrf5340_app.rs @@ -252,6 +252,7 @@ embassy_hal_internal::peripherals! { SERIAL1, SERIAL2, SERIAL3, + SPIM4, // SAADC SAADC, @@ -402,6 +403,7 @@ impl_spim!(SERIAL0, SPIM0, SERIAL0); impl_spim!(SERIAL1, SPIM1, SERIAL1); impl_spim!(SERIAL2, SPIM2, SERIAL2); impl_spim!(SERIAL3, SPIM3, SERIAL3); +impl_spim!(SPIM4, SPIM4, SPIM4); impl_spis!(SERIAL0, SPIS0, SERIAL0); impl_spis!(SERIAL1, SPIS1, SERIAL1); From f9a1511de4d3972da0fd4f7367043a65c673c593 Mon Sep 17 00:00:00 2001 From: Bronson Date: Sun, 10 Nov 2024 12:50:11 +1030 Subject: [PATCH 0340/1217] add default data to watch new() --- embassy-sync/src/watch.rs | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/embassy-sync/src/watch.rs b/embassy-sync/src/watch.rs index 59798d04f..e0f5e14f9 100644 --- a/embassy-sync/src/watch.rs +++ b/embassy-sync/src/watch.rs @@ -31,7 +31,7 @@ use crate::waitqueue::MultiWakerRegistration; /// /// let f = async { /// -/// static WATCH: Watch = Watch::new(); +/// static WATCH: Watch = Watch::new(None); /// /// // Obtain receivers and sender /// let mut rcv0 = WATCH.receiver().unwrap(); @@ -299,10 +299,10 @@ impl WatchBehavior for Watch impl Watch { /// Create a new `Watch` channel. - pub const fn new() -> Self { + pub const fn new(data: Option) -> Self { Self { mutex: Mutex::new(RefCell::new(WatchState { - data: None, + data, current_id: 0, wakers: MultiWakerRegistration::new(), receiver_count: 0, @@ -775,7 +775,7 @@ mod tests { #[test] fn multiple_sends() { let f = async { - static WATCH: Watch = Watch::new(); + static WATCH: Watch = Watch::new(None); // Obtain receiver and sender let mut rcv = WATCH.receiver().unwrap(); @@ -801,7 +801,7 @@ mod tests { #[test] fn all_try_get() { let f = async { - static WATCH: Watch = Watch::new(); + static WATCH: Watch = Watch::new(None); // Obtain receiver and sender let mut rcv = WATCH.receiver().unwrap(); @@ -835,7 +835,7 @@ mod tests { static CONFIG0: u8 = 10; static CONFIG1: u8 = 20; - static WATCH: Watch = Watch::new(); + static WATCH: Watch = Watch::new(None); // Obtain receiver and sender let mut rcv = WATCH.receiver().unwrap(); @@ -867,7 +867,7 @@ mod tests { #[test] fn sender_modify() { let f = async { - static WATCH: Watch = Watch::new(); + static WATCH: Watch = Watch::new(None); // Obtain receiver and sender let mut rcv = WATCH.receiver().unwrap(); @@ -894,7 +894,7 @@ mod tests { #[test] fn predicate_fn() { let f = async { - static WATCH: Watch = Watch::new(); + static WATCH: Watch = Watch::new(None); // Obtain receiver and sender let mut rcv = WATCH.receiver().unwrap(); @@ -923,7 +923,7 @@ mod tests { #[test] fn receive_after_create() { let f = async { - static WATCH: Watch = Watch::new(); + static WATCH: Watch = Watch::new(None); // Obtain sender and send value let snd = WATCH.sender(); @@ -939,7 +939,7 @@ mod tests { #[test] fn max_receivers_drop() { let f = async { - static WATCH: Watch = Watch::new(); + static WATCH: Watch = Watch::new(None); // Try to create 3 receivers (only 2 can exist at once) let rcv0 = WATCH.receiver(); @@ -964,7 +964,7 @@ mod tests { #[test] fn multiple_receivers() { let f = async { - static WATCH: Watch = Watch::new(); + static WATCH: Watch = Watch::new(None); // Obtain receivers and sender let mut rcv0 = WATCH.receiver().unwrap(); @@ -989,7 +989,7 @@ mod tests { fn clone_senders() { let f = async { // Obtain different ways to send - static WATCH: Watch = Watch::new(); + static WATCH: Watch = Watch::new(None); let snd0 = WATCH.sender(); let snd1 = snd0.clone(); @@ -1010,7 +1010,7 @@ mod tests { #[test] fn use_dynamics() { let f = async { - static WATCH: Watch = Watch::new(); + static WATCH: Watch = Watch::new(None); // Obtain receiver and sender let mut anon_rcv = WATCH.dyn_anon_receiver(); @@ -1031,7 +1031,7 @@ mod tests { #[test] fn convert_to_dyn() { let f = async { - static WATCH: Watch = Watch::new(); + static WATCH: Watch = Watch::new(None); // Obtain receiver and sender let anon_rcv = WATCH.anon_receiver(); @@ -1057,7 +1057,7 @@ mod tests { #[test] fn dynamic_receiver_count() { let f = async { - static WATCH: Watch = Watch::new(); + static WATCH: Watch = Watch::new(None); // Obtain receiver and sender let rcv0 = WATCH.receiver(); @@ -1087,7 +1087,7 @@ mod tests { #[test] fn contains_value() { let f = async { - static WATCH: Watch = Watch::new(); + static WATCH: Watch = Watch::new(None); // Obtain receiver and sender let rcv = WATCH.receiver().unwrap(); From 8d0882991ee88ce4af52d32bbaebecf40fa57914 Mon Sep 17 00:00:00 2001 From: Bronson Date: Sun, 10 Nov 2024 12:54:37 +1030 Subject: [PATCH 0341/1217] added watch new_with() --- embassy-sync/src/watch.rs | 42 +++++++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/embassy-sync/src/watch.rs b/embassy-sync/src/watch.rs index e0f5e14f9..90dcf97ef 100644 --- a/embassy-sync/src/watch.rs +++ b/embassy-sync/src/watch.rs @@ -31,7 +31,7 @@ use crate::waitqueue::MultiWakerRegistration; /// /// let f = async { /// -/// static WATCH: Watch = Watch::new(None); +/// static WATCH: Watch = Watch::new(); /// /// // Obtain receivers and sender /// let mut rcv0 = WATCH.receiver().unwrap(); @@ -299,7 +299,19 @@ impl WatchBehavior for Watch impl Watch { /// Create a new `Watch` channel. - pub const fn new(data: Option) -> Self { + pub const fn new() -> Self { + Self { + mutex: Mutex::new(RefCell::new(WatchState { + data: None, + current_id: 0, + wakers: MultiWakerRegistration::new(), + receiver_count: 0, + })), + } +} + + /// Create a new `Watch` channel. + pub const fn new_with(data: Option) -> Self { Self { mutex: Mutex::new(RefCell::new(WatchState { data, @@ -775,7 +787,7 @@ mod tests { #[test] fn multiple_sends() { let f = async { - static WATCH: Watch = Watch::new(None); + static WATCH: Watch = Watch::new(); // Obtain receiver and sender let mut rcv = WATCH.receiver().unwrap(); @@ -801,7 +813,7 @@ mod tests { #[test] fn all_try_get() { let f = async { - static WATCH: Watch = Watch::new(None); + static WATCH: Watch = Watch::new(); // Obtain receiver and sender let mut rcv = WATCH.receiver().unwrap(); @@ -835,7 +847,7 @@ mod tests { static CONFIG0: u8 = 10; static CONFIG1: u8 = 20; - static WATCH: Watch = Watch::new(None); + static WATCH: Watch = Watch::new(); // Obtain receiver and sender let mut rcv = WATCH.receiver().unwrap(); @@ -867,7 +879,7 @@ mod tests { #[test] fn sender_modify() { let f = async { - static WATCH: Watch = Watch::new(None); + static WATCH: Watch = Watch::new(); // Obtain receiver and sender let mut rcv = WATCH.receiver().unwrap(); @@ -894,7 +906,7 @@ mod tests { #[test] fn predicate_fn() { let f = async { - static WATCH: Watch = Watch::new(None); + static WATCH: Watch = Watch::new(); // Obtain receiver and sender let mut rcv = WATCH.receiver().unwrap(); @@ -923,7 +935,7 @@ mod tests { #[test] fn receive_after_create() { let f = async { - static WATCH: Watch = Watch::new(None); + static WATCH: Watch = Watch::new(); // Obtain sender and send value let snd = WATCH.sender(); @@ -939,7 +951,7 @@ mod tests { #[test] fn max_receivers_drop() { let f = async { - static WATCH: Watch = Watch::new(None); + static WATCH: Watch = Watch::new(); // Try to create 3 receivers (only 2 can exist at once) let rcv0 = WATCH.receiver(); @@ -964,7 +976,7 @@ mod tests { #[test] fn multiple_receivers() { let f = async { - static WATCH: Watch = Watch::new(None); + static WATCH: Watch = Watch::new(); // Obtain receivers and sender let mut rcv0 = WATCH.receiver().unwrap(); @@ -989,7 +1001,7 @@ mod tests { fn clone_senders() { let f = async { // Obtain different ways to send - static WATCH: Watch = Watch::new(None); + static WATCH: Watch = Watch::new(); let snd0 = WATCH.sender(); let snd1 = snd0.clone(); @@ -1010,7 +1022,7 @@ mod tests { #[test] fn use_dynamics() { let f = async { - static WATCH: Watch = Watch::new(None); + static WATCH: Watch = Watch::new(); // Obtain receiver and sender let mut anon_rcv = WATCH.dyn_anon_receiver(); @@ -1031,7 +1043,7 @@ mod tests { #[test] fn convert_to_dyn() { let f = async { - static WATCH: Watch = Watch::new(None); + static WATCH: Watch = Watch::new(); // Obtain receiver and sender let anon_rcv = WATCH.anon_receiver(); @@ -1057,7 +1069,7 @@ mod tests { #[test] fn dynamic_receiver_count() { let f = async { - static WATCH: Watch = Watch::new(None); + static WATCH: Watch = Watch::new(); // Obtain receiver and sender let rcv0 = WATCH.receiver(); @@ -1087,7 +1099,7 @@ mod tests { #[test] fn contains_value() { let f = async { - static WATCH: Watch = Watch::new(None); + static WATCH: Watch = Watch::new(); // Obtain receiver and sender let rcv = WATCH.receiver().unwrap(); From 32f0cde1cc6f277fb3f91d9fc0cc754c09267376 Mon Sep 17 00:00:00 2001 From: Bronson Date: Sun, 10 Nov 2024 13:15:41 +1030 Subject: [PATCH 0342/1217] fix formatting --- embassy-sync/src/watch.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-sync/src/watch.rs b/embassy-sync/src/watch.rs index 90dcf97ef..d645ffe17 100644 --- a/embassy-sync/src/watch.rs +++ b/embassy-sync/src/watch.rs @@ -308,7 +308,7 @@ impl Watch { receiver_count: 0, })), } -} + } /// Create a new `Watch` channel. pub const fn new_with(data: Option) -> Self { From 730dde9ba901d89040d3d943cf36b4217ac52bf9 Mon Sep 17 00:00:00 2001 From: Bronson Date: Sun, 10 Nov 2024 21:09:24 +1030 Subject: [PATCH 0343/1217] remove option --- embassy-sync/src/watch.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/embassy-sync/src/watch.rs b/embassy-sync/src/watch.rs index d645ffe17..404e31714 100644 --- a/embassy-sync/src/watch.rs +++ b/embassy-sync/src/watch.rs @@ -310,11 +310,11 @@ impl Watch { } } - /// Create a new `Watch` channel. - pub const fn new_with(data: Option) -> Self { + /// Create a new `Watch` channel with default data. + pub const fn new_with(data: T) -> Self { Self { mutex: Mutex::new(RefCell::new(WatchState { - data, + data: Some(data), current_id: 0, wakers: MultiWakerRegistration::new(), receiver_count: 0, From 32dcff39959bda11a7a3ef35fb3c77e172d46ae4 Mon Sep 17 00:00:00 2001 From: rafael Date: Sun, 10 Nov 2024 17:20:59 +0100 Subject: [PATCH 0344/1217] add simple-robot to Embassy in the wild --- docs/pages/embassy_in_the_wild.adoc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/pages/embassy_in_the_wild.adoc b/docs/pages/embassy_in_the_wild.adoc index bb457a869..620794c31 100644 --- a/docs/pages/embassy_in_the_wild.adoc +++ b/docs/pages/embassy_in_the_wild.adoc @@ -2,6 +2,8 @@ Here are known examples of real-world projects which make use of Embassy. Feel free to link:https://github.com/embassy-rs/embassy/blob/main/docs/pages/embassy_in_the_wild.adoc[add more]! +* link:https://github.com/1-rafael-1/simple-robot[A simple tracked robot based on Raspberry Pi Pico 2] +** A hobbyist project building a tracked robot with basic autonomous and manual drive mode. * link:https://github.com/1-rafael-1/pi-pico-alarmclock-rust[A Raspberry Pi Pico W Alarmclock] ** A hobbyist project building an alarm clock around a Pi Pico W complete with code, components list and enclosure design files. * link:https://github.com/haobogu/rmk/[RMK: A feature-rich Rust keyboard firmware] From 4d75c4ee51266bd40b2018004425a91954bf7721 Mon Sep 17 00:00:00 2001 From: Junfeng Liu Date: Tue, 12 Nov 2024 10:36:44 +0800 Subject: [PATCH 0345/1217] Fix wrong unit --- embassy-stm32/src/rcc/h.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/src/rcc/h.rs b/embassy-stm32/src/rcc/h.rs index 55fe8ca9d..df2929ba4 100644 --- a/embassy-stm32/src/rcc/h.rs +++ b/embassy-stm32/src/rcc/h.rs @@ -779,7 +779,7 @@ fn init_pll(num: usize, config: Option, input: &PllInput) -> PllOutput { ..=3_999_999 => Pllrge::RANGE2, ..=7_999_999 => Pllrge::RANGE4, ..=16_000_000 => Pllrge::RANGE8, - x => panic!("pll ref_clk out of range: {} mhz", x), + x => panic!("pll ref_clk out of range: {} hz", x), }; // The smaller range (150 to 420 MHz) must From baeb59b5b8d63ef9bb6ecada518ea8b911d2dc30 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 12 Nov 2024 16:28:26 +0100 Subject: [PATCH 0346/1217] executor: use WakerHack unconditionally even if `nightly` feature is enabled. (#3528) This ensures the executor compiles with all recent nightly versions, including the stable-but-with-nightly-features-enabled xtensa rustc. --- embassy-executor/Cargo.toml | 3 --- embassy-executor/build.rs | 11 -------- embassy-executor/build_common.rs | 19 -------------- embassy-executor/src/lib.rs | 1 - embassy-executor/src/raw/waker.rs | 42 ++++++++----------------------- 5 files changed, 11 insertions(+), 65 deletions(-) diff --git a/embassy-executor/Cargo.toml b/embassy-executor/Cargo.toml index 2450ae61b..7141fe0f9 100644 --- a/embassy-executor/Cargo.toml +++ b/embassy-executor/Cargo.toml @@ -57,9 +57,6 @@ avr-device = { version = "0.5.3", optional = true } critical-section = { version = "1.1", features = ["std"] } trybuild = "1.0" -[build-dependencies] -rustc_version = "0.4.1" - [features] ## Enable nightly-only features diff --git a/embassy-executor/build.rs b/embassy-executor/build.rs index c4c86e1e2..8a41d7503 100644 --- a/embassy-executor/build.rs +++ b/embassy-executor/build.rs @@ -96,15 +96,4 @@ fn main() { let mut rustc_cfgs = common::CfgSet::new(); common::set_target_cfgs(&mut rustc_cfgs); - - // Waker API changed on 2024-09-06 - rustc_cfgs.declare("at_least_2024_09_06"); - let Some(compiler) = common::compiler_info() else { - return; - }; - if compiler.channel == rustc_version::Channel::Nightly - && compiler.commit_date.map(|d| d >= "2024-09-06").unwrap_or(false) - { - rustc_cfgs.enable("at_least_2024_09_06"); - } } diff --git a/embassy-executor/build_common.rs b/embassy-executor/build_common.rs index af6bb0618..b15a8369f 100644 --- a/embassy-executor/build_common.rs +++ b/embassy-executor/build_common.rs @@ -124,22 +124,3 @@ impl PartialOrd<&str> for CompilerDate { Self::parse(other).map(|other| self.cmp(&other)) } } - -pub struct CompilerInfo { - #[allow(unused)] - pub version: rustc_version::Version, - pub channel: rustc_version::Channel, - pub commit_date: Option, -} - -pub fn compiler_info() -> Option { - let Ok(meta) = rustc_version::version_meta() else { - return None; - }; - - Some(CompilerInfo { - version: meta.semver, - channel: meta.channel, - commit_date: meta.commit_date.as_deref().and_then(CompilerDate::parse), - }) -} diff --git a/embassy-executor/src/lib.rs b/embassy-executor/src/lib.rs index 8e07a8b18..d816539ac 100644 --- a/embassy-executor/src/lib.rs +++ b/embassy-executor/src/lib.rs @@ -1,5 +1,4 @@ #![cfg_attr(not(any(feature = "arch-std", feature = "arch-wasm")), no_std)] -#![cfg_attr(all(feature = "nightly", not(at_least_2024_09_06)), feature(waker_getters))] #![allow(clippy::new_without_default)] #![doc = include_str!("../README.md")] #![warn(missing_docs)] diff --git a/embassy-executor/src/raw/waker.rs b/embassy-executor/src/raw/waker.rs index 30b8cdd4c..d2256adfa 100644 --- a/embassy-executor/src/raw/waker.rs +++ b/embassy-executor/src/raw/waker.rs @@ -32,40 +32,20 @@ pub(crate) unsafe fn from_task(p: TaskRef) -> Waker { /// /// Panics if the waker is not created by the Embassy executor. pub fn task_from_waker(waker: &Waker) -> TaskRef { - let (vtable, data) = { - #[cfg(not(feature = "nightly"))] - { - struct WakerHack { - data: *const (), - vtable: &'static RawWakerVTable, - } + struct WakerHack { + data: *const (), + vtable: &'static RawWakerVTable, + } - // safety: OK because WakerHack has the same layout as Waker. - // This is not really guaranteed because the structs are `repr(Rust)`, it is - // indeed the case in the current implementation. - // TODO use waker_getters when stable. https://github.com/rust-lang/rust/issues/96992 - let hack: &WakerHack = unsafe { core::mem::transmute(waker) }; - (hack.vtable, hack.data) - } + // safety: OK because WakerHack has the same layout as Waker. + // This is not really guaranteed because the structs are `repr(Rust)`, it is + // indeed the case in the current implementation. + // TODO use waker_getters when stable. https://github.com/rust-lang/rust/issues/96992 + let hack: &WakerHack = unsafe { core::mem::transmute(waker) }; - #[cfg(feature = "nightly")] - { - #[cfg(not(at_least_2024_09_06))] - { - let raw_waker = waker.as_raw(); - (raw_waker.vtable(), raw_waker.data()) - } - - #[cfg(at_least_2024_09_06)] - { - (waker.vtable(), waker.data()) - } - } - }; - - if vtable != &VTABLE { + if hack.vtable != &VTABLE { panic!("Found waker not created by the Embassy executor. `embassy_time::Timer` only works with the Embassy executor.") } // safety: our wakers are always created with `TaskRef::as_ptr` - unsafe { TaskRef::from_ptr(data as *const TaskHeader) } + unsafe { TaskRef::from_ptr(hack.data as *const TaskHeader) } } From 853c5c567add8134b8419cf0a6a2b6c8cb0b0aa6 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 12 Nov 2024 16:30:46 +0100 Subject: [PATCH 0347/1217] executor: compare vtable addr instead of contents. Saves a whopping 44 bytes of text, yay. --- embassy-executor/src/raw/waker.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/embassy-executor/src/raw/waker.rs b/embassy-executor/src/raw/waker.rs index d2256adfa..9c70f995a 100644 --- a/embassy-executor/src/raw/waker.rs +++ b/embassy-executor/src/raw/waker.rs @@ -43,7 +43,9 @@ pub fn task_from_waker(waker: &Waker) -> TaskRef { // TODO use waker_getters when stable. https://github.com/rust-lang/rust/issues/96992 let hack: &WakerHack = unsafe { core::mem::transmute(waker) }; - if hack.vtable != &VTABLE { + // make sure to compare vtable addresses. Doing `==` on the references + // will compare the contents, which is slower. + if hack.vtable as *const _ != &VTABLE as *const _ { panic!("Found waker not created by the Embassy executor. `embassy_time::Timer` only works with the Embassy executor.") } // safety: our wakers are always created with `TaskRef::as_ptr` From 95b84494bc2f6a137e7dfe349971b4386ec66411 Mon Sep 17 00:00:00 2001 From: Scott Mabin Date: Tue, 12 Nov 2024 14:09:24 +0000 Subject: [PATCH 0348/1217] basic xtensa CI --- .github/ci/build-xtensa.sh | 37 ++++++++++++++++++++++++++++++++++++ ci-xtensa.sh | 39 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+) create mode 100755 .github/ci/build-xtensa.sh create mode 100755 ci-xtensa.sh diff --git a/.github/ci/build-xtensa.sh b/.github/ci/build-xtensa.sh new file mode 100755 index 000000000..a13391c82 --- /dev/null +++ b/.github/ci/build-xtensa.sh @@ -0,0 +1,37 @@ +#!/bin/bash +## on push branch~=gh-readonly-queue/main/.* +## on pull_request + +set -euo pipefail + +export RUSTUP_HOME=/ci/cache/rustup +export CARGO_HOME=/ci/cache/cargo +export CARGO_TARGET_DIR=/ci/cache/target + +# needed for "dumb HTTP" transport support +# used when pointing stm32-metapac to a CI-built one. +export CARGO_NET_GIT_FETCH_WITH_CLI=true + +cargo install espup +/ci/cache/cargo/bin/espup install + +# Restore lockfiles +if [ -f /ci/cache/lockfiles.tar ]; then + echo Restoring lockfiles... + tar xf /ci/cache/lockfiles.tar +fi + +hashtime restore /ci/cache/filetime.json || true +hashtime save /ci/cache/filetime.json + +mkdir .cargo +cat > .cargo/config.toml<< EOF +[unstable] +build-std = ["alloc", "core"] +EOF + +./ci-xtensa.sh + +# Save lockfiles +echo Saving lockfiles... +find . -type f -name Cargo.lock -exec tar -cf /ci/cache/lockfiles.tar '{}' \+ diff --git a/ci-xtensa.sh b/ci-xtensa.sh new file mode 100755 index 000000000..32d362def --- /dev/null +++ b/ci-xtensa.sh @@ -0,0 +1,39 @@ +#!/bin/bash + +set -eo pipefail + +export RUSTFLAGS=-Dwarnings +export DEFMT_LOG=trace,embassy_hal_internal=debug,embassy_net_esp_hosted=debug,cyw43=info,cyw43_pio=info,smoltcp=info +export RUSTUP_TOOLCHAIN=esp +if [[ -z "${CARGO_TARGET_DIR}" ]]; then + export CARGO_TARGET_DIR=target_ci +fi + +cargo batch \ + --- build --release --manifest-path embassy-executor/Cargo.toml --target xtensa-esp32-none-elf \ + --- build --release --manifest-path embassy-executor/Cargo.toml --target xtensa-esp32-none-elf --features log \ + --- build --release --manifest-path embassy-executor/Cargo.toml --target xtensa-esp32-none-elf --features defmt \ + --- build --release --manifest-path embassy-executor/Cargo.toml --target xtensa-esp32s2-none-elf --features defmt \ + --- build --release --manifest-path embassy-executor/Cargo.toml --target xtensa-esp32-none-elf --features defmt,arch-spin,executor-thread,integrated-timers \ + --- build --release --manifest-path embassy-executor/Cargo.toml --target xtensa-esp32s2-none-elf --features defmt,arch-spin,executor-thread,integrated-timers \ + --- build --release --manifest-path embassy-executor/Cargo.toml --target xtensa-esp32s3-none-elf --features defmt,arch-spin,executor-thread,integrated-timers \ + --- build --release --manifest-path embassy-executor/Cargo.toml --target xtensa-esp32-none-elf --features arch-spin \ + --- build --release --manifest-path embassy-executor/Cargo.toml --target xtensa-esp32-none-elf --features arch-spin,integrated-timers \ + --- build --release --manifest-path embassy-executor/Cargo.toml --target xtensa-esp32-none-elf --features arch-spin,rtos-trace \ + --- build --release --manifest-path embassy-executor/Cargo.toml --target xtensa-esp32-none-elf --features arch-spin,integrated-timers,rtos-trace \ + --- build --release --manifest-path embassy-executor/Cargo.toml --target xtensa-esp32-none-elf --features arch-spin,executor-thread \ + --- build --release --manifest-path embassy-executor/Cargo.toml --target xtensa-esp32-none-elf --features arch-spin,executor-thread,integrated-timers \ + --- build --release --manifest-path embassy-sync/Cargo.toml --target xtensa-esp32s2-none-elf --features defmt \ + --- build --release --manifest-path embassy-time/Cargo.toml --target xtensa-esp32s2-none-elf --features defmt,defmt-timestamp-uptime,generic-queue-8,mock-driver \ + --- build --release --manifest-path embassy-net/Cargo.toml --target xtensa-esp32-none-elf --features defmt,tcp,udp,dns,proto-ipv4,medium-ethernet,packet-trace \ + --- build --release --manifest-path embassy-net/Cargo.toml --target xtensa-esp32-none-elf --features defmt,tcp,udp,dns,proto-ipv4,multicast,medium-ethernet \ + --- build --release --manifest-path embassy-net/Cargo.toml --target xtensa-esp32-none-elf --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet \ + --- build --release --manifest-path embassy-net/Cargo.toml --target xtensa-esp32-none-elf --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet,dhcpv4-hostname \ + --- build --release --manifest-path embassy-net/Cargo.toml --target xtensa-esp32-none-elf --features defmt,tcp,udp,dns,proto-ipv6,medium-ethernet \ + --- build --release --manifest-path embassy-net/Cargo.toml --target xtensa-esp32-none-elf --features defmt,tcp,udp,dns,proto-ipv6,medium-ieee802154 \ + --- build --release --manifest-path embassy-net/Cargo.toml --target xtensa-esp32-none-elf --features defmt,tcp,udp,dns,proto-ipv6,medium-ethernet,medium-ieee802154 \ + --- build --release --manifest-path embassy-net/Cargo.toml --target xtensa-esp32-none-elf --features defmt,tcp,udp,dns,proto-ipv6,medium-ethernet \ + --- build --release --manifest-path embassy-net/Cargo.toml --target xtensa-esp32-none-elf --features defmt,tcp,udp,dns,proto-ipv4,proto-ipv6,medium-ethernet \ + --- build --release --manifest-path embassy-net/Cargo.toml --target xtensa-esp32-none-elf --features defmt,tcp,udp,dns,proto-ipv4,proto-ipv6,medium-ip \ + --- build --release --manifest-path embassy-net/Cargo.toml --target xtensa-esp32-none-elf --features defmt,tcp,udp,dns,proto-ipv4,proto-ipv6,medium-ip,medium-ethernet \ + --- build --release --manifest-path embassy-net/Cargo.toml --target xtensa-esp32-none-elf --features defmt,tcp,udp,dns,proto-ipv4,proto-ipv6,medium-ip,medium-ethernet,medium-ieee802154 \ \ No newline at end of file From 796f6c034a148e1fedb3196a2c73a155f5d0545f Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 12 Nov 2024 17:48:36 +0100 Subject: [PATCH 0349/1217] Release embassy-executor 0.6.3. --- docs/examples/basic/Cargo.toml | 2 +- docs/examples/layer-by-layer/blinky-async/Cargo.toml | 2 +- docs/pages/new_project.adoc | 2 +- embassy-executor/CHANGELOG.md | 5 +++++ embassy-executor/Cargo.toml | 2 +- embassy-rp/Cargo.toml | 2 +- embassy-stm32/Cargo.toml | 2 +- embassy-time/Cargo.toml | 2 +- examples/boot/application/nrf/Cargo.toml | 2 +- examples/boot/application/rp/Cargo.toml | 2 +- examples/boot/application/stm32f3/Cargo.toml | 2 +- examples/boot/application/stm32f7/Cargo.toml | 2 +- examples/boot/application/stm32h7/Cargo.toml | 2 +- examples/boot/application/stm32l0/Cargo.toml | 2 +- examples/boot/application/stm32l1/Cargo.toml | 2 +- examples/boot/application/stm32l4/Cargo.toml | 2 +- examples/boot/application/stm32wb-dfu/Cargo.toml | 2 +- examples/boot/application/stm32wl/Cargo.toml | 2 +- examples/lpc55s69/Cargo.toml | 2 +- examples/nrf-rtos-trace/Cargo.toml | 2 +- examples/nrf51/Cargo.toml | 2 +- examples/nrf52810/Cargo.toml | 2 +- examples/nrf52840/Cargo.toml | 2 +- examples/nrf5340/Cargo.toml | 2 +- examples/nrf9151/ns/Cargo.toml | 2 +- examples/nrf9151/s/Cargo.toml | 2 +- examples/nrf9160/Cargo.toml | 2 +- examples/rp/Cargo.toml | 2 +- examples/rp23/Cargo.toml | 2 +- examples/std/Cargo.toml | 2 +- examples/stm32c0/Cargo.toml | 2 +- examples/stm32f0/Cargo.toml | 2 +- examples/stm32f1/Cargo.toml | 2 +- examples/stm32f2/Cargo.toml | 2 +- examples/stm32f3/Cargo.toml | 2 +- examples/stm32f334/Cargo.toml | 2 +- examples/stm32f4/Cargo.toml | 2 +- examples/stm32f469/Cargo.toml | 2 +- examples/stm32f7/Cargo.toml | 2 +- examples/stm32g0/Cargo.toml | 2 +- examples/stm32g4/Cargo.toml | 2 +- examples/stm32h5/Cargo.toml | 2 +- examples/stm32h7/Cargo.toml | 2 +- examples/stm32h735/Cargo.toml | 2 +- examples/stm32h755cm4/Cargo.toml | 2 +- examples/stm32h755cm7/Cargo.toml | 2 +- examples/stm32h7b0/Cargo.toml | 2 +- examples/stm32h7rs/Cargo.toml | 2 +- examples/stm32l0/Cargo.toml | 2 +- examples/stm32l1/Cargo.toml | 2 +- examples/stm32l4/Cargo.toml | 2 +- examples/stm32l5/Cargo.toml | 2 +- examples/stm32u0/Cargo.toml | 2 +- examples/stm32u5/Cargo.toml | 2 +- examples/stm32wb/Cargo.toml | 2 +- examples/stm32wba/Cargo.toml | 2 +- examples/stm32wl/Cargo.toml | 2 +- examples/wasm/Cargo.toml | 2 +- tests/nrf/Cargo.toml | 2 +- tests/riscv32/Cargo.toml | 2 +- tests/rp/Cargo.toml | 2 +- tests/stm32/Cargo.toml | 2 +- 62 files changed, 66 insertions(+), 61 deletions(-) diff --git a/docs/examples/basic/Cargo.toml b/docs/examples/basic/Cargo.toml index 5d391adf3..d46431b9a 100644 --- a/docs/examples/basic/Cargo.toml +++ b/docs/examples/basic/Cargo.toml @@ -6,7 +6,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-executor = { version = "0.6.0", path = "../../../embassy-executor", features = ["defmt", "integrated-timers", "arch-cortex-m", "executor-thread"] } +embassy-executor = { version = "0.6.3", path = "../../../embassy-executor", features = ["defmt", "integrated-timers", "arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.3.2", path = "../../../embassy-time", features = ["defmt"] } embassy-nrf = { version = "0.2.0", path = "../../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote"] } diff --git a/docs/examples/layer-by-layer/blinky-async/Cargo.toml b/docs/examples/layer-by-layer/blinky-async/Cargo.toml index 7f8d8af3e..f6d2e4fc7 100644 --- a/docs/examples/layer-by-layer/blinky-async/Cargo.toml +++ b/docs/examples/layer-by-layer/blinky-async/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" cortex-m = "0.7" cortex-m-rt = "0.7" embassy-stm32 = { version = "0.1.0", features = ["stm32l475vg", "memory-x", "exti"] } -embassy-executor = { version = "0.6.0", features = ["arch-cortex-m", "executor-thread"] } +embassy-executor = { version = "0.6.3", features = ["arch-cortex-m", "executor-thread"] } defmt = "0.3.0" defmt-rtt = "0.3.0" diff --git a/docs/pages/new_project.adoc b/docs/pages/new_project.adoc index 38cea044b..f8dd848be 100644 --- a/docs/pages/new_project.adoc +++ b/docs/pages/new_project.adoc @@ -80,7 +80,7 @@ At the time of writing, embassy is already published to crates.io. Therefore, de ---- [dependencies] embassy-stm32 = { version = "0.1.0", features = ["defmt", "time-driver-any", "stm32g474re", "memory-x", "unstable-pac", "exti"] } -embassy-executor = { version = "0.6.1", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.3", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } ---- diff --git a/embassy-executor/CHANGELOG.md b/embassy-executor/CHANGELOG.md index b342ccc32..e07e3924f 100644 --- a/embassy-executor/CHANGELOG.md +++ b/embassy-executor/CHANGELOG.md @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +## 0.6.3 - 2024-11-12 + +- Building with the `nightly` feature now works with the Xtensa Rust compiler 1.82. +- Compare vtable address instead of contents. Saves 44 bytes of flash on cortex-m. + ## 0.6.2 - 2024-11-06 - The `nightly` feature no longer requires `nightly-2024-09-06` or newer. diff --git a/embassy-executor/Cargo.toml b/embassy-executor/Cargo.toml index 7141fe0f9..7c930b658 100644 --- a/embassy-executor/Cargo.toml +++ b/embassy-executor/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "embassy-executor" -version = "0.6.2" +version = "0.6.3" edition = "2021" license = "MIT OR Apache-2.0" description = "async/await executor designed for embedded usage" diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index 4616116aa..401ecd215 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml @@ -147,5 +147,5 @@ rp-binary-info = { version = "0.1.0", optional = true } smart-leds = "0.4.0" [dev-dependencies] -embassy-executor = { version = "0.6.2", path = "../embassy-executor", features = ["arch-std", "executor-thread"] } +embassy-executor = { version = "0.6.3", path = "../embassy-executor", features = ["arch-std", "executor-thread"] } static_cell = { version = "2" } diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index e2ba4fd60..4fe4ff358 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -51,7 +51,7 @@ embassy-embedded-hal = {version = "0.2.0", path = "../embassy-embedded-hal", def embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver" } embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver" } embassy-usb-synopsys-otg = {version = "0.1.0", path = "../embassy-usb-synopsys-otg" } -embassy-executor = { version = "0.6.2", path = "../embassy-executor", optional = true } +embassy-executor = { version = "0.6.3", path = "../embassy-executor", optional = true } embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } embedded-hal-1 = { package = "embedded-hal", version = "1.0" } diff --git a/embassy-time/Cargo.toml b/embassy-time/Cargo.toml index 0e61434f1..8c7de9840 100644 --- a/embassy-time/Cargo.toml +++ b/embassy-time/Cargo.toml @@ -431,4 +431,4 @@ wasm-timer = { version = "0.2.5", optional = true } [dev-dependencies] serial_test = "0.9" critical-section = { version = "1.1", features = ["std"] } -embassy-executor = { version = "0.6.2", path = "../embassy-executor" } +embassy-executor = { version = "0.6.3", path = "../embassy-executor" } diff --git a/examples/boot/application/nrf/Cargo.toml b/examples/boot/application/nrf/Cargo.toml index e2ae240ae..3bf33d212 100644 --- a/examples/boot/application/nrf/Cargo.toml +++ b/examples/boot/application/nrf/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.6.2", path = "../../../../embassy-executor", features = ["task-arena-size-16384", "arch-cortex-m", "executor-thread", "integrated-timers", "arch-cortex-m", "executor-thread"] } +embassy-executor = { version = "0.6.3", path = "../../../../embassy-executor", features = ["task-arena-size-16384", "arch-cortex-m", "executor-thread", "integrated-timers", "arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [] } embassy-nrf = { version = "0.2.0", path = "../../../../embassy-nrf", features = ["time-driver-rtc1", "gpiote", ] } embassy-boot = { version = "0.3.0", path = "../../../../embassy-boot", features = [] } diff --git a/examples/boot/application/rp/Cargo.toml b/examples/boot/application/rp/Cargo.toml index f61ac3fd9..85515abc5 100644 --- a/examples/boot/application/rp/Cargo.toml +++ b/examples/boot/application/rp/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.6.2", path = "../../../../embassy-executor", features = ["task-arena-size-16384", "arch-cortex-m", "executor-thread", "integrated-timers", "arch-cortex-m", "executor-thread"] } +embassy-executor = { version = "0.6.3", path = "../../../../embassy-executor", features = ["task-arena-size-16384", "arch-cortex-m", "executor-thread", "integrated-timers", "arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [] } embassy-rp = { version = "0.2.0", path = "../../../../embassy-rp", features = ["time-driver", "rp2040"] } embassy-boot-rp = { version = "0.3.0", path = "../../../../embassy-boot-rp", features = [] } diff --git a/examples/boot/application/stm32f3/Cargo.toml b/examples/boot/application/stm32f3/Cargo.toml index dd20d2e0d..45394f1d5 100644 --- a/examples/boot/application/stm32f3/Cargo.toml +++ b/examples/boot/application/stm32f3/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.6.2", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32f303re", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32" } diff --git a/examples/boot/application/stm32f7/Cargo.toml b/examples/boot/application/stm32f7/Cargo.toml index ce38e9ab9..8bb6c5df3 100644 --- a/examples/boot/application/stm32f7/Cargo.toml +++ b/examples/boot/application/stm32f7/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.6.2", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32f767zi", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } diff --git a/examples/boot/application/stm32h7/Cargo.toml b/examples/boot/application/stm32h7/Cargo.toml index 841075627..85d3af65f 100644 --- a/examples/boot/application/stm32h7/Cargo.toml +++ b/examples/boot/application/stm32h7/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.6.2", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32h743zi", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } diff --git a/examples/boot/application/stm32l0/Cargo.toml b/examples/boot/application/stm32l0/Cargo.toml index 1a92517db..a8a6f0bab 100644 --- a/examples/boot/application/stm32l0/Cargo.toml +++ b/examples/boot/application/stm32l0/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.6.2", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l072cz", "time-driver-any", "exti", "memory-x"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } diff --git a/examples/boot/application/stm32l1/Cargo.toml b/examples/boot/application/stm32l1/Cargo.toml index 57eeb07a1..0a8447aa6 100644 --- a/examples/boot/application/stm32l1/Cargo.toml +++ b/examples/boot/application/stm32l1/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.6.2", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l151cb-a", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } diff --git a/examples/boot/application/stm32l4/Cargo.toml b/examples/boot/application/stm32l4/Cargo.toml index f51ca29e1..1b5d33f78 100644 --- a/examples/boot/application/stm32l4/Cargo.toml +++ b/examples/boot/application/stm32l4/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.6.2", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l475vg", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } diff --git a/examples/boot/application/stm32wb-dfu/Cargo.toml b/examples/boot/application/stm32wb-dfu/Cargo.toml index 112de92f1..cde4a3ae6 100644 --- a/examples/boot/application/stm32wb-dfu/Cargo.toml +++ b/examples/boot/application/stm32wb-dfu/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.6.2", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32wb55rg", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } diff --git a/examples/boot/application/stm32wl/Cargo.toml b/examples/boot/application/stm32wl/Cargo.toml index e2c42ce20..8e94051ce 100644 --- a/examples/boot/application/stm32wl/Cargo.toml +++ b/examples/boot/application/stm32wl/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.6.2", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32wl55jc-cm4", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } diff --git a/examples/lpc55s69/Cargo.toml b/examples/lpc55s69/Cargo.toml index a18b29f2e..ee0c09dd3 100644 --- a/examples/lpc55s69/Cargo.toml +++ b/examples/lpc55s69/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-nxp = { version = "0.1.0", path = "../../embassy-nxp", features = ["rt"] } -embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt"] } +embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt"] } panic-halt = "0.2.0" diff --git a/examples/nrf-rtos-trace/Cargo.toml b/examples/nrf-rtos-trace/Cargo.toml index fbdd2744c..ae8d62100 100644 --- a/examples/nrf-rtos-trace/Cargo.toml +++ b/examples/nrf-rtos-trace/Cargo.toml @@ -16,7 +16,7 @@ log = [ [dependencies] embassy-sync = { version = "0.6.0", path = "../../embassy-sync" } -embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "rtos-trace", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "rtos-trace", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time" } embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] } diff --git a/examples/nrf51/Cargo.toml b/examples/nrf51/Cargo.toml index 3799a87cc..05e702773 100644 --- a/examples/nrf51/Cargo.toml +++ b/examples/nrf51/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["task-arena-size-4096", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-4096", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf51", "gpiote", "time-driver-rtc1", "unstable-pac", "time", "rt"] } diff --git a/examples/nrf52810/Cargo.toml b/examples/nrf52810/Cargo.toml index e3045bdba..3cc88ed7e 100644 --- a/examples/nrf52810/Cargo.toml +++ b/examples/nrf52810/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf52810", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } diff --git a/examples/nrf52840/Cargo.toml b/examples/nrf52840/Cargo.toml index e0a27c628..9ac6e3594 100644 --- a/examples/nrf52840/Cargo.toml +++ b/examples/nrf52840/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } diff --git a/examples/nrf5340/Cargo.toml b/examples/nrf5340/Cargo.toml index 2a4e78b7c..9103db907 100644 --- a/examples/nrf5340/Cargo.toml +++ b/examples/nrf5340/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf5340-app-s", "time-driver-rtc1", "gpiote", "unstable-pac"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } diff --git a/examples/nrf9151/ns/Cargo.toml b/examples/nrf9151/ns/Cargo.toml index 679331716..96bf6700d 100644 --- a/examples/nrf9151/ns/Cargo.toml +++ b/examples/nrf9151/ns/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-executor = { version = "0.6.2", path = "../../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.2.0", path = "../../../embassy-nrf", features = ["defmt", "nrf9120-ns", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } diff --git a/examples/nrf9151/s/Cargo.toml b/examples/nrf9151/s/Cargo.toml index 63114478b..f7adf259d 100644 --- a/examples/nrf9151/s/Cargo.toml +++ b/examples/nrf9151/s/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-executor = { version = "0.6.2", path = "../../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.2.0", path = "../../../embassy-nrf", features = ["defmt", "nrf9120-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } diff --git a/examples/nrf9160/Cargo.toml b/examples/nrf9160/Cargo.toml index d5b0f0a41..47eba5552 100644 --- a/examples/nrf9160/Cargo.toml +++ b/examples/nrf9160/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf9160-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } embassy-net-nrf91 = { version = "0.1.0", path = "../../embassy-net-nrf91", features = ["defmt"] } diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index b45f5040a..6420ca32c 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal", features = ["defmt"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["task-arena-size-98304", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-98304", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-rp = { version = "0.2.0", path = "../../embassy-rp", features = ["defmt", "unstable-pac", "time-driver", "critical-section-impl", "rp2040"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/rp23/Cargo.toml b/examples/rp23/Cargo.toml index 99a75a67f..3ea92f208 100644 --- a/examples/rp23/Cargo.toml +++ b/examples/rp23/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal", features = ["defmt"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["task-arena-size-98304", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-98304", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-rp = { version = "0.2.0", path = "../../embassy-rp", features = ["defmt", "unstable-pac", "time-driver", "critical-section-impl", "rp235xa", "binary-info"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/std/Cargo.toml b/examples/std/Cargo.toml index fac180c0c..6e918366c 100644 --- a/examples/std/Cargo.toml +++ b/examples/std/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["log"] } -embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-std", "executor-thread", "log", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-std", "executor-thread", "log", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["log", "std", ] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features=[ "std", "log", "medium-ethernet", "medium-ip", "tcp", "udp", "dns", "dhcpv4", "proto-ipv6"] } embassy-net-tuntap = { version = "0.1.0", path = "../../embassy-net-tuntap" } diff --git a/examples/stm32c0/Cargo.toml b/examples/stm32c0/Cargo.toml index f8a845095..06f11ef00 100644 --- a/examples/stm32c0/Cargo.toml +++ b/examples/stm32c0/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32c031c6 to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32c031c6", "memory-x", "unstable-pac", "exti"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } defmt = "0.3" diff --git a/examples/stm32f0/Cargo.toml b/examples/stm32f0/Cargo.toml index 6154fdc64..f5f1147fe 100644 --- a/examples/stm32f0/Cargo.toml +++ b/examples/stm32f0/Cargo.toml @@ -13,7 +13,7 @@ defmt = "0.3" defmt-rtt = "0.4" panic-probe = { version = "0.3", features = ["print-defmt"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } static_cell = "2" portable-atomic = { version = "1.5", features = ["unsafe-assume-single-core"] } diff --git a/examples/stm32f1/Cargo.toml b/examples/stm32f1/Cargo.toml index c4836859e..846dcfd7c 100644 --- a/examples/stm32f1/Cargo.toml +++ b/examples/stm32f1/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32f103c8 to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f103c8", "unstable-pac", "memory-x", "time-driver-any" ] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32f2/Cargo.toml b/examples/stm32f2/Cargo.toml index 0e4827e5d..ad87c973b 100644 --- a/examples/stm32f2/Cargo.toml +++ b/examples/stm32f2/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32f207zg to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f207zg", "unstable-pac", "memory-x", "time-driver-any", "exti"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } defmt = "0.3" diff --git a/examples/stm32f3/Cargo.toml b/examples/stm32f3/Cargo.toml index 08a921634..f44d28473 100644 --- a/examples/stm32f3/Cargo.toml +++ b/examples/stm32f3/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32f303ze to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f303ze", "unstable-pac", "memory-x", "time-driver-any", "exti"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32f334/Cargo.toml b/examples/stm32f334/Cargo.toml index cba83bf8c..548ec1289 100644 --- a/examples/stm32f334/Cargo.toml +++ b/examples/stm32f334/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f334r8", "unstable-pac", "memory-x", "time-driver-any", "exti"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/stm32f4/Cargo.toml b/examples/stm32f4/Cargo.toml index 32fb845cb..368c5eb98 100644 --- a/examples/stm32f4/Cargo.toml +++ b/examples/stm32f4/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32f429zi to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32f429zi", "unstable-pac", "memory-x", "time-driver-any", "exti", "chrono"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt" ] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", ] } diff --git a/examples/stm32f469/Cargo.toml b/examples/stm32f469/Cargo.toml index 139b4b937..382f7e485 100644 --- a/examples/stm32f469/Cargo.toml +++ b/examples/stm32f469/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Specific examples only for stm32f469 embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32f469ni", "unstable-pac", "memory-x", "time-driver-any", "exti", "chrono"] } -embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } defmt = "0.3" diff --git a/examples/stm32f7/Cargo.toml b/examples/stm32f7/Cargo.toml index 2c55da04c..4f24d0eda 100644 --- a/examples/stm32f7/Cargo.toml +++ b/examples/stm32f7/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32f777zi to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32f777zi", "memory-x", "unstable-pac", "time-driver-any", "exti"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } embedded-io-async = { version = "0.6.1" } diff --git a/examples/stm32g0/Cargo.toml b/examples/stm32g0/Cargo.toml index bf258a7fd..ed74f1ba9 100644 --- a/examples/stm32g0/Cargo.toml +++ b/examples/stm32g0/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32g0b1re to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32g0b1re", "memory-x", "unstable-pac", "exti"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", default-features = false, features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32g4/Cargo.toml b/examples/stm32g4/Cargo.toml index cc3b44b57..3d5dd8069 100644 --- a/examples/stm32g4/Cargo.toml +++ b/examples/stm32g4/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32g491re to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32g491re", "memory-x", "unstable-pac", "exti"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32h5/Cargo.toml b/examples/stm32h5/Cargo.toml index d1a865e4c..c71ad2db0 100644 --- a/examples/stm32h5/Cargo.toml +++ b/examples/stm32h5/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32h563zi to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h563zi", "memory-x", "time-driver-any", "exti", "unstable-pac", "low-power"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/stm32h7/Cargo.toml b/examples/stm32h7/Cargo.toml index 1ba792f72..4a82d487f 100644 --- a/examples/stm32h7/Cargo.toml +++ b/examples/stm32h7/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h743bi", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } -embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/stm32h735/Cargo.toml b/examples/stm32h735/Cargo.toml index 6a74d83ab..e66e344d2 100644 --- a/examples/stm32h735/Cargo.toml +++ b/examples/stm32h735/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h735ig", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } -embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32h755cm4/Cargo.toml b/examples/stm32h755cm4/Cargo.toml index ee96e64d6..8b46c3952 100644 --- a/examples/stm32h755cm4/Cargo.toml +++ b/examples/stm32h755cm4/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h755zi-cm4", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } -embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/stm32h755cm7/Cargo.toml b/examples/stm32h755cm7/Cargo.toml index 61c425719..1db5143a4 100644 --- a/examples/stm32h755cm7/Cargo.toml +++ b/examples/stm32h755cm7/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h755zi-cm7", "time-driver-tim3", "exti", "memory-x", "unstable-pac", "chrono"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } -embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/stm32h7b0/Cargo.toml b/examples/stm32h7b0/Cargo.toml index 255ce933c..e22548bf0 100644 --- a/examples/stm32h7b0/Cargo.toml +++ b/examples/stm32h7b0/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h7b0vb", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } -embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/stm32h7rs/Cargo.toml b/examples/stm32h7rs/Cargo.toml index 055be6a91..07c69977d 100644 --- a/examples/stm32h7rs/Cargo.toml +++ b/examples/stm32h7rs/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32h743bi to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h7s3l8", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/stm32l0/Cargo.toml b/examples/stm32l0/Cargo.toml index 4e2bb8b67..f67fa6b00 100644 --- a/examples/stm32l0/Cargo.toml +++ b/examples/stm32l0/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32l072cz to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32l072cz", "unstable-pac", "time-driver-any", "exti", "memory-x"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } defmt = "0.3" diff --git a/examples/stm32l1/Cargo.toml b/examples/stm32l1/Cargo.toml index 865cad87f..4d382f16e 100644 --- a/examples/stm32l1/Cargo.toml +++ b/examples/stm32l1/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32l151cb-a", "time-driver-any", "memory-x"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/stm32l4/Cargo.toml b/examples/stm32l4/Cargo.toml index 7f963fc53..699358388 100644 --- a/examples/stm32l4/Cargo.toml +++ b/examples/stm32l4/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32l4s5vi to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32l4s5qi", "memory-x", "time-driver-any", "exti", "chrono"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768", ] } embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/stm32l5/Cargo.toml b/examples/stm32l5/Cargo.toml index 0604625f2..ce9c76441 100644 --- a/examples/stm32l5/Cargo.toml +++ b/examples/stm32l5/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32l552ze to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32l552ze", "time-driver-any", "exti", "memory-x", "low-power"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } diff --git a/examples/stm32u0/Cargo.toml b/examples/stm32u0/Cargo.toml index 97ef0b704..6dd9bc7fa 100644 --- a/examples/stm32u0/Cargo.toml +++ b/examples/stm32u0/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32u083rc to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32u083rc", "memory-x", "unstable-pac", "exti", "chrono"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", default-features = false, features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32u5/Cargo.toml b/examples/stm32u5/Cargo.toml index f474e6db0..9a2b1dccf 100644 --- a/examples/stm32u5/Cargo.toml +++ b/examples/stm32u5/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32u5g9zj to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "unstable-pac", "stm32u5g9zj", "time-driver-any", "memory-x" ] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32wb/Cargo.toml b/examples/stm32wb/Cargo.toml index 26de81122..9a050e31e 100644 --- a/examples/stm32wb/Cargo.toml +++ b/examples/stm32wb/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32wb55rg", "time-driver-any", "memory-x", "exti"] } embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", features = ["defmt", "stm32wb55rg"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", ], optional=true } diff --git a/examples/stm32wba/Cargo.toml b/examples/stm32wba/Cargo.toml index 807f809e0..1697ffa1c 100644 --- a/examples/stm32wba/Cargo.toml +++ b/examples/stm32wba/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32wba52cg", "time-driver-any", "memory-x", "exti"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", ], optional=true } diff --git a/examples/stm32wl/Cargo.toml b/examples/stm32wl/Cargo.toml index 3b4223977..eeb13608c 100644 --- a/examples/stm32wl/Cargo.toml +++ b/examples/stm32wl/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32wl55jc-cm4 to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32wl55jc-cm4", "time-driver-any", "memory-x", "unstable-pac", "exti", "chrono"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["task-arena-size-4096", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-4096", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } diff --git a/examples/wasm/Cargo.toml b/examples/wasm/Cargo.toml index ea66d9b99..8c1b8a4f6 100644 --- a/examples/wasm/Cargo.toml +++ b/examples/wasm/Cargo.toml @@ -9,7 +9,7 @@ crate-type = ["cdylib"] [dependencies] embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["log"] } -embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["arch-wasm", "executor-thread", "log", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-wasm", "executor-thread", "log", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["log", "wasm", ] } wasm-logger = "0.2.0" diff --git a/tests/nrf/Cargo.toml b/tests/nrf/Cargo.toml index c1d386b93..0e58487d2 100644 --- a/tests/nrf/Cargo.toml +++ b/tests/nrf/Cargo.toml @@ -9,7 +9,7 @@ teleprobe-meta = "1" embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt", ] } -embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "task-arena-size-16384", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "task-arena-size-16384", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "time-driver-rtc1", "gpiote", "unstable-pac"] } embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } diff --git a/tests/riscv32/Cargo.toml b/tests/riscv32/Cargo.toml index 35dd283eb..ae60dac10 100644 --- a/tests/riscv32/Cargo.toml +++ b/tests/riscv32/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] critical-section = { version = "1.1.1", features = ["restore-state-bool"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync" } -embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["arch-riscv32", "executor-thread"] } +embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-riscv32", "executor-thread"] } embassy-time = { version = "0.3.2", path = "../../embassy-time" } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/tests/rp/Cargo.toml b/tests/rp/Cargo.toml index 72f7ceb8f..359dae3bc 100644 --- a/tests/rp/Cargo.toml +++ b/tests/rp/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" teleprobe-meta = "1.1" embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", ] } embassy-rp = { version = "0.2.0", path = "../../embassy-rp", features = [ "defmt", "unstable-pac", "time-driver", "critical-section-impl", "intrinsics", "rom-v2-intrinsics", "run-from-ram", "rp2040"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml index f30217fc0..58da8c1b5 100644 --- a/tests/stm32/Cargo.toml +++ b/tests/stm32/Cargo.toml @@ -60,7 +60,7 @@ cm0 = ["portable-atomic/unsafe-assume-single-core"] teleprobe-meta = "1" embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "tick-hz-131_072", "defmt-timestamp-uptime"] } embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "memory-x", "time-driver-any"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } From 6801c6496c2f6e5dd94b1f2af8df03df0db61cc1 Mon Sep 17 00:00:00 2001 From: Cedric VINCENT Date: Wed, 13 Nov 2024 17:54:52 +0100 Subject: [PATCH 0350/1217] Fix multiprio examples for stm32 devices. Commit bbe1eebc has changed the order of TIM candidates when using the time-driver-any feature. For instance, in the case of STM32F3, it previously returned TIM2 but now returns TIM15. Consequently, the "multiprio" example no longer works as it requires three *free* CC register (for alarms), while TIM15 provides only one (CC1 is always reserved for regular time keeping). This commit was successfully tested on STM32F3. Additionally, I verified that all the examples using a timer for STM32F0 and STM32F4 still build correctly. Fixes #2749 --- examples/stm32f0/Cargo.toml | 2 +- examples/stm32f3/Cargo.toml | 2 +- examples/stm32f4/Cargo.toml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/stm32f0/Cargo.toml b/examples/stm32f0/Cargo.toml index f5f1147fe..d80a7503b 100644 --- a/examples/stm32f0/Cargo.toml +++ b/examples/stm32f0/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32f091rc to your chip name, if necessary. -embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "memory-x", "stm32f091rc", "time-driver-any", "exti", "unstable-pac"] } +embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "memory-x", "stm32f091rc", "time-driver-tim2", "exti", "unstable-pac"] } cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } cortex-m-rt = "0.7.0" defmt = "0.3" diff --git a/examples/stm32f3/Cargo.toml b/examples/stm32f3/Cargo.toml index f44d28473..9c97e32d3 100644 --- a/examples/stm32f3/Cargo.toml +++ b/examples/stm32f3/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32f303ze to your chip name, if necessary. -embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f303ze", "unstable-pac", "memory-x", "time-driver-any", "exti"] } +embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f303ze", "unstable-pac", "memory-x", "time-driver-tim2", "exti"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } diff --git a/examples/stm32f4/Cargo.toml b/examples/stm32f4/Cargo.toml index 368c5eb98..cb8392922 100644 --- a/examples/stm32f4/Cargo.toml +++ b/examples/stm32f4/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32f429zi to your chip name, if necessary. -embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32f429zi", "unstable-pac", "memory-x", "time-driver-any", "exti", "chrono"] } +embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32f429zi", "unstable-pac", "memory-x", "time-driver-tim4", "exti", "chrono"] } embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } From 19a06d6b8a00e3758d60246dbfed3b867fee35cb Mon Sep 17 00:00:00 2001 From: ibuki2003 Date: Thu, 14 Nov 2024 02:50:04 +0900 Subject: [PATCH 0351/1217] fix(rp): use uart dreq number defined in pac --- embassy-rp/src/uart/mod.rs | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/embassy-rp/src/uart/mod.rs b/embassy-rp/src/uart/mod.rs index 08f20924c..8d12aeef6 100644 --- a/embassy-rp/src/uart/mod.rs +++ b/embassy-rp/src/uart/mod.rs @@ -1295,8 +1295,8 @@ impl<'d, T: Instance> embedded_io::Write for Uart<'d, T, Blocking> { trait SealedMode {} trait SealedInstance { - const TX_DREQ: u8; - const RX_DREQ: u8; + const TX_DREQ: pac::dma::vals::TreqSel; + const RX_DREQ: pac::dma::vals::TreqSel; fn regs() -> pac::uart::Uart; @@ -1334,8 +1334,8 @@ pub trait Instance: SealedInstance { macro_rules! impl_instance { ($inst:ident, $irq:ident, $tx_dreq:expr, $rx_dreq:expr) => { impl SealedInstance for peripherals::$inst { - const TX_DREQ: u8 = $tx_dreq; - const RX_DREQ: u8 = $rx_dreq; + const TX_DREQ: pac::dma::vals::TreqSel = $tx_dreq; + const RX_DREQ: pac::dma::vals::TreqSel = $rx_dreq; fn regs() -> pac::uart::Uart { pac::$inst @@ -1360,8 +1360,18 @@ macro_rules! impl_instance { }; } -impl_instance!(UART0, UART0_IRQ, 20, 21); -impl_instance!(UART1, UART1_IRQ, 22, 23); +impl_instance!( + UART0, + UART0_IRQ, + pac::dma::vals::TreqSel::UART0_TX, + pac::dma::vals::TreqSel::UART0_RX +); +impl_instance!( + UART1, + UART1_IRQ, + pac::dma::vals::TreqSel::UART1_TX, + pac::dma::vals::TreqSel::UART1_RX +); /// Trait for TX pins. pub trait TxPin: crate::gpio::Pin {} From 4692f06c33ba18bc6ecd5522ac794aea954ec9f2 Mon Sep 17 00:00:00 2001 From: elagil Date: Fri, 15 Nov 2024 00:01:40 +0100 Subject: [PATCH 0352/1217] fix: flush SAI FIFO on disable --- embassy-stm32/src/sai/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/embassy-stm32/src/sai/mod.rs b/embassy-stm32/src/sai/mod.rs index 7d2f071de..1b26011db 100644 --- a/embassy-stm32/src/sai/mod.rs +++ b/embassy-stm32/src/sai/mod.rs @@ -1045,6 +1045,7 @@ impl<'d, T: Instance, W: word::Word> Drop for Sai<'d, T, W> { fn drop(&mut self) { let ch = T::REGS.ch(self.sub_block as usize); ch.cr1().modify(|w| w.set_saien(false)); + ch.cr2().modify(|w| w.set_fflush(true)); self.fs.as_ref().map(|x| x.set_as_disconnected()); self.sd.as_ref().map(|x| x.set_as_disconnected()); self.sck.as_ref().map(|x| x.set_as_disconnected()); From edb9b03deeddf306208c685b91d294a93d0ca54f Mon Sep 17 00:00:00 2001 From: elagil Date: Fri, 15 Nov 2024 00:07:23 +0100 Subject: [PATCH 0353/1217] fix: flush SAI FIFO on init --- embassy-stm32/src/sai/mod.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/sai/mod.rs b/embassy-stm32/src/sai/mod.rs index 1b26011db..62b44b77f 100644 --- a/embassy-stm32/src/sai/mod.rs +++ b/embassy-stm32/src/sai/mod.rs @@ -861,12 +861,15 @@ impl<'d, T: Instance, W: word::Word> Sai<'d, T, W> { ring_buffer: RingBuffer<'d, W>, config: Config, ) -> Self { + let ch = T::REGS.ch(sub_block as usize); + #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))] { - let ch = T::REGS.ch(sub_block as usize); ch.cr1().modify(|w| w.set_saien(false)); } + ch.cr2().modify(|w| w.set_fflush(true)); + #[cfg(any(sai_v4_2pdm, sai_v4_4pdm))] { if let SyncInput::External(i) = config.sync_input { @@ -888,7 +891,6 @@ impl<'d, T: Instance, W: word::Word> Sai<'d, T, W> { #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))] { - let ch = T::REGS.ch(sub_block as usize); ch.cr1().modify(|w| { w.set_mode(config.mode.mode(if Self::is_transmitter(&ring_buffer) { TxRx::Transmitter From 3f23fd5c98244921b97858912bbcdfd681b4f92e Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Fri, 15 Nov 2024 02:22:20 +0100 Subject: [PATCH 0354/1217] Update nrf-pac. --- embassy-net-nrf91/Cargo.toml | 2 +- embassy-nrf/Cargo.toml | 2 +- embassy-nrf/src/chips/nrf51.rs | 8 +- embassy-nrf/src/chips/nrf52805.rs | 28 +- embassy-nrf/src/chips/nrf52810.rs | 28 +- embassy-nrf/src/chips/nrf52811.rs | 36 +- embassy-nrf/src/chips/nrf52820.rs | 52 +-- embassy-nrf/src/chips/nrf52832.rs | 60 +-- embassy-nrf/src/chips/nrf52833.rs | 60 +-- embassy-nrf/src/chips/nrf52840.rs | 60 +-- embassy-nrf/src/chips/nrf5340_app.rs | 369 +++++++----------- embassy-nrf/src/chips/nrf5340_net.rs | 48 +-- embassy-nrf/src/chips/nrf9120.rs | 335 +++++++--------- embassy-nrf/src/chips/nrf9160.rs | 335 +++++++--------- embassy-nrf/src/lib.rs | 2 +- embassy-nrf/src/time_driver.rs | 2 +- embassy-nrf/src/usb/vbus_detect.rs | 4 +- examples/nrf52840-rtic/src/bin/blinky.rs | 2 +- examples/nrf52840/src/bin/buffered_uart.rs | 2 +- examples/nrf52840/src/bin/multiprio.rs | 16 +- examples/nrf52840/src/bin/spis.rs | 2 +- examples/nrf52840/src/bin/twim.rs | 2 +- examples/nrf52840/src/bin/twim_lowpower.rs | 2 +- examples/nrf52840/src/bin/twis.rs | 2 +- examples/nrf52840/src/bin/uart.rs | 2 +- examples/nrf52840/src/bin/uart_idle.rs | 2 +- examples/nrf52840/src/bin/uart_split.rs | 2 +- examples/nrf52840/src/bin/usb_ethernet.rs | 2 +- examples/nrf52840/src/bin/usb_hid_keyboard.rs | 2 +- examples/nrf52840/src/bin/usb_hid_mouse.rs | 2 +- examples/nrf52840/src/bin/usb_serial.rs | 2 +- .../nrf52840/src/bin/usb_serial_multitask.rs | 2 +- .../nrf52840/src/bin/usb_serial_winusb.rs | 2 +- examples/nrf9151/ns/src/bin/uart.rs | 2 +- examples/nrf9160/src/bin/modem_tcp_client.rs | 2 +- tests/nrf/src/common.rs | 28 +- 36 files changed, 641 insertions(+), 868 deletions(-) diff --git a/embassy-net-nrf91/Cargo.toml b/embassy-net-nrf91/Cargo.toml index 98356c1ba..77a1c4cb5 100644 --- a/embassy-net-nrf91/Cargo.toml +++ b/embassy-net-nrf91/Cargo.toml @@ -17,7 +17,7 @@ log = [ "dep:log" ] defmt = { version = "0.3", optional = true } log = { version = "0.4.14", optional = true } -nrf-pac = { git = "https://github.com/embassy-rs/nrf-pac", rev = "875a29629cc1c87aae00cfea647a956b3807d8be" } +nrf-pac = { git = "https://github.com/embassy-rs/nrf-pac", rev = "12e2461859acb0bfea9b2ef5cd73f1283c139ac0" } cortex-m = "0.7.7" embassy-time = { version = "0.3.1", path = "../embassy-time" } diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml index 24a3db91d..7b20d2643 100644 --- a/embassy-nrf/Cargo.toml +++ b/embassy-nrf/Cargo.toml @@ -136,7 +136,7 @@ embedded-hal-async = { version = "1.0" } embedded-io = { version = "0.6.0" } embedded-io-async = { version = "0.6.1" } -nrf-pac = { git = "https://github.com/embassy-rs/nrf-pac", rev = "875a29629cc1c87aae00cfea647a956b3807d8be" } +nrf-pac = { git = "https://github.com/embassy-rs/nrf-pac", rev = "12e2461859acb0bfea9b2ef5cd73f1283c139ac0" } defmt = { version = "0.3", optional = true } bitflags = "2.4.2" diff --git a/embassy-nrf/src/chips/nrf51.rs b/embassy-nrf/src/chips/nrf51.rs index 95fa926c3..a0365a6ee 100644 --- a/embassy-nrf/src/chips/nrf51.rs +++ b/embassy-nrf/src/chips/nrf51.rs @@ -146,11 +146,11 @@ impl_pin!(P0_31, 0, 31); impl_radio!(RADIO, RADIO, RADIO); embassy_hal_internal::interrupt_mod!( - POWER_CLOCK, + CLOCK_POWER, RADIO, UART0, - SPI0_TWI0, - SPI1_TWI1, + TWISPI0, + TWISPI1, GPIOTE, ADC, TIMER0, @@ -160,7 +160,7 @@ embassy_hal_internal::interrupt_mod!( TEMP, RNG, ECB, - CCM_AAR, + AAR_CCM, WDT, RTC1, QDEC, diff --git a/embassy-nrf/src/chips/nrf52805.rs b/embassy-nrf/src/chips/nrf52805.rs index fc8db856c..a9cbccec4 100644 --- a/embassy-nrf/src/chips/nrf52805.rs +++ b/embassy-nrf/src/chips/nrf52805.rs @@ -138,15 +138,15 @@ embassy_hal_internal::peripherals! { EGU1, } -impl_uarte!(UARTE0, UARTE0, UARTE0_UART0); +impl_uarte!(UARTE0, UARTE0, UARTE0); -impl_spim!(SPI0, SPIM0, SPIM0_SPIS0_SPI0); +impl_spim!(SPI0, SPIM0, SPI0); -impl_spis!(SPI0, SPIS0, SPIM0_SPIS0_SPI0); +impl_spis!(SPI0, SPIS0, SPI0); -impl_twim!(TWI0, TWIM0, TWIM0_TWIS0_TWI0); +impl_twim!(TWI0, TWIM0, TWI0); -impl_twis!(TWI0, TWIS0, TWIM0_TWIS0_TWI0); +impl_twis!(TWI0, TWIS0, TWI0); impl_qdec!(QDEC, QDEC, QDEC); @@ -218,15 +218,15 @@ impl_saadc_input!(P0_05, ANALOG_INPUT3); impl_radio!(RADIO, RADIO, RADIO); -impl_egu!(EGU0, EGU0, SWI0_EGU0); -impl_egu!(EGU1, EGU1, SWI1_EGU1); +impl_egu!(EGU0, EGU0, EGU0_SWI0); +impl_egu!(EGU1, EGU1, EGU1_SWI1); embassy_hal_internal::interrupt_mod!( - POWER_CLOCK, + CLOCK_POWER, RADIO, - UARTE0_UART0, - TWIM0_TWIS0_TWI0, - SPIM0_SPIS0_SPI0, + UARTE0, + TWI0, + SPI0, GPIOTE, SAADC, TIMER0, @@ -236,12 +236,12 @@ embassy_hal_internal::interrupt_mod!( TEMP, RNG, ECB, - CCM_AAR, + AAR_CCM, WDT, RTC1, QDEC, - SWI0_EGU0, - SWI1_EGU1, + EGU0_SWI0, + EGU1_SWI1, SWI2, SWI3, SWI4, diff --git a/embassy-nrf/src/chips/nrf52810.rs b/embassy-nrf/src/chips/nrf52810.rs index 11a8b4dde..ca31c35e1 100644 --- a/embassy-nrf/src/chips/nrf52810.rs +++ b/embassy-nrf/src/chips/nrf52810.rs @@ -144,15 +144,15 @@ embassy_hal_internal::peripherals! { EGU1, } -impl_uarte!(UARTE0, UARTE0, UARTE0_UART0); +impl_uarte!(UARTE0, UARTE0, UARTE0); -impl_spim!(SPI0, SPIM0, SPIM0_SPIS0_SPI0); +impl_spim!(SPI0, SPIM0, SPI0); -impl_spis!(SPI0, SPIS0, SPIM0_SPIS0_SPI0); +impl_spis!(SPI0, SPIS0, SPI0); -impl_twim!(TWI0, TWIM0, TWIM0_TWIS0_TWI0); +impl_twim!(TWI0, TWIM0, TWI0); -impl_twis!(TWI0, TWIS0, TWIM0_TWIS0_TWI0); +impl_twis!(TWI0, TWIS0, TWI0); impl_pwm!(PWM0, PWM0, PWM0); @@ -244,15 +244,15 @@ impl_saadc_input!(P0_31, ANALOG_INPUT7); impl_radio!(RADIO, RADIO, RADIO); -impl_egu!(EGU0, EGU0, SWI0_EGU0); -impl_egu!(EGU1, EGU1, SWI1_EGU1); +impl_egu!(EGU0, EGU0, EGU0_SWI0); +impl_egu!(EGU1, EGU1, EGU1_SWI1); embassy_hal_internal::interrupt_mod!( - POWER_CLOCK, + CLOCK_POWER, RADIO, - UARTE0_UART0, - TWIM0_TWIS0_TWI0, - SPIM0_SPIS0_SPI0, + UARTE0, + TWI0, + SPI0, GPIOTE, SAADC, TIMER0, @@ -262,13 +262,13 @@ embassy_hal_internal::interrupt_mod!( TEMP, RNG, ECB, - CCM_AAR, + AAR_CCM, WDT, RTC1, QDEC, COMP, - SWI0_EGU0, - SWI1_EGU1, + EGU0_SWI0, + EGU1_SWI1, SWI2, SWI3, SWI4, diff --git a/embassy-nrf/src/chips/nrf52811.rs b/embassy-nrf/src/chips/nrf52811.rs index 077a36e31..caf3fdcf8 100644 --- a/embassy-nrf/src/chips/nrf52811.rs +++ b/embassy-nrf/src/chips/nrf52811.rs @@ -27,8 +27,8 @@ embassy_hal_internal::peripherals! { UARTE0, // SPI/TWI - TWISPI0, - SPI1, + TWI0_SPI1, + SPI0, // SAADC SAADC, @@ -144,17 +144,17 @@ embassy_hal_internal::peripherals! { EGU1, } -impl_uarte!(UARTE0, UARTE0, UARTE0_UART0); +impl_uarte!(UARTE0, UARTE0, UARTE0); -impl_spim!(TWISPI0, SPIM0, TWIM0_TWIS0_TWI0_SPIM0_SPIS0_SPI0); -impl_spim!(SPI1, SPIM1, SPIM1_SPIS1_SPI1); +impl_spim!(SPI0, SPIM0, SPI0); +impl_spim!(TWI0_SPI1, SPIM1, TWI0_SPI1); -impl_spis!(TWISPI0, SPIS0, TWIM0_TWIS0_TWI0_SPIM0_SPIS0_SPI0); -impl_spis!(SPI1, SPIS1, SPIM1_SPIS1_SPI1); +impl_spis!(SPI0, SPIS0, SPI0); +impl_spis!(TWI0_SPI1, SPIS1, TWI0_SPI1); -impl_twim!(TWISPI0, TWIM0, TWIM0_TWIS0_TWI0_SPIM0_SPIS0_SPI0); +impl_twim!(TWI0_SPI1, TWIM0, TWI0_SPI1); -impl_twis!(TWISPI0, TWIS0, TWIM0_TWIS0_TWI0_SPIM0_SPIS0_SPI0); +impl_twis!(TWI0_SPI1, TWIS0, TWI0_SPI1); impl_pwm!(PWM0, PWM0, PWM0); @@ -246,15 +246,15 @@ impl_saadc_input!(P0_31, ANALOG_INPUT7); impl_radio!(RADIO, RADIO, RADIO); -impl_egu!(EGU0, EGU0, SWI0_EGU0); -impl_egu!(EGU1, EGU1, SWI1_EGU1); +impl_egu!(EGU0, EGU0, EGU0_SWI0); +impl_egu!(EGU1, EGU1, EGU1_SWI1); embassy_hal_internal::interrupt_mod!( - POWER_CLOCK, + CLOCK_POWER, RADIO, - UARTE0_UART0, - TWIM0_TWIS0_TWI0_SPIM0_SPIS0_SPI0, - SPIM1_SPIS1_SPI1, + UARTE0, + TWI0_SPI1, + SPI0, GPIOTE, SAADC, TIMER0, @@ -264,13 +264,13 @@ embassy_hal_internal::interrupt_mod!( TEMP, RNG, ECB, - CCM_AAR, + AAR_CCM, WDT, RTC1, QDEC, COMP, - SWI0_EGU0, - SWI1_EGU1, + EGU0_SWI0, + EGU1_SWI1, SWI2, SWI3, SWI4, diff --git a/embassy-nrf/src/chips/nrf52820.rs b/embassy-nrf/src/chips/nrf52820.rs index 6ee16706d..39573e4a5 100644 --- a/embassy-nrf/src/chips/nrf52820.rs +++ b/embassy-nrf/src/chips/nrf52820.rs @@ -145,19 +145,19 @@ embassy_hal_internal::peripherals! { impl_usb!(USBD, USBD, USBD); -impl_uarte!(UARTE0, UARTE0, UARTE0_UART0); +impl_uarte!(UARTE0, UARTE0, UARTE0); -impl_spim!(TWISPI0, SPIM0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); -impl_spim!(TWISPI1, SPIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); +impl_spim!(TWISPI0, SPIM0, TWISPI0); +impl_spim!(TWISPI1, SPIM1, TWISPI1); -impl_spis!(TWISPI0, SPIS0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); -impl_spis!(TWISPI1, SPIS1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); +impl_spis!(TWISPI0, SPIS0, TWISPI0); +impl_spis!(TWISPI1, SPIS1, TWISPI1); -impl_twim!(TWISPI0, TWIM0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); -impl_twim!(TWISPI1, TWIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); +impl_twim!(TWISPI0, TWIM0, TWISPI0); +impl_twim!(TWISPI1, TWIM1, TWISPI1); -impl_twis!(TWISPI0, TWIS0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); -impl_twis!(TWISPI1, TWIS1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); +impl_twis!(TWISPI0, TWIS0, TWISPI0); +impl_twis!(TWISPI1, TWIS1, TWISPI1); impl_timer!(TIMER0, TIMER0, TIMER0); impl_timer!(TIMER1, TIMER1, TIMER1); @@ -237,19 +237,19 @@ impl_ppi_channel!(PPI_CH31, 31 => static); impl_radio!(RADIO, RADIO, RADIO); -impl_egu!(EGU0, EGU0, SWI0_EGU0); -impl_egu!(EGU1, EGU1, SWI1_EGU1); -impl_egu!(EGU2, EGU2, SWI2_EGU2); -impl_egu!(EGU3, EGU3, SWI3_EGU3); -impl_egu!(EGU4, EGU4, SWI4_EGU4); -impl_egu!(EGU5, EGU5, SWI5_EGU5); +impl_egu!(EGU0, EGU0, EGU0_SWI0); +impl_egu!(EGU1, EGU1, EGU1_SWI1); +impl_egu!(EGU2, EGU2, EGU2_SWI2); +impl_egu!(EGU3, EGU3, EGU3_SWI3); +impl_egu!(EGU4, EGU4, EGU4_SWI4); +impl_egu!(EGU5, EGU5, EGU5_SWI5); embassy_hal_internal::interrupt_mod!( - POWER_CLOCK, + CLOCK_POWER, RADIO, - UARTE0_UART0, - SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0, - SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1, + UARTE0, + TWISPI0, + TWISPI1, GPIOTE, TIMER0, TIMER1, @@ -258,17 +258,17 @@ embassy_hal_internal::interrupt_mod!( TEMP, RNG, ECB, - CCM_AAR, + AAR_CCM, WDT, RTC1, QDEC, COMP, - SWI0_EGU0, - SWI1_EGU1, - SWI2_EGU2, - SWI3_EGU3, - SWI4_EGU4, - SWI5_EGU5, + EGU0_SWI0, + EGU1_SWI1, + EGU2_SWI2, + EGU3_SWI3, + EGU4_SWI4, + EGU5_SWI5, TIMER3, USBD, ); diff --git a/embassy-nrf/src/chips/nrf52832.rs b/embassy-nrf/src/chips/nrf52832.rs index 4a7a29229..7ff58d63e 100644 --- a/embassy-nrf/src/chips/nrf52832.rs +++ b/embassy-nrf/src/chips/nrf52832.rs @@ -163,21 +163,21 @@ embassy_hal_internal::peripherals! { EGU5, } -impl_uarte!(UARTE0, UARTE0, UARTE0_UART0); +impl_uarte!(UARTE0, UARTE0, UARTE0); -impl_spim!(TWISPI0, SPIM0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); -impl_spim!(TWISPI1, SPIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); -impl_spim!(SPI2, SPIM2, SPIM2_SPIS2_SPI2); +impl_spim!(TWISPI0, SPIM0, TWISPI0); +impl_spim!(TWISPI1, SPIM1, TWISPI1); +impl_spim!(SPI2, SPIM2, SPI2); -impl_spis!(TWISPI0, SPIS0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); -impl_spis!(TWISPI1, SPIS1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); -impl_spis!(SPI2, SPIS2, SPIM2_SPIS2_SPI2); +impl_spis!(TWISPI0, SPIS0, TWISPI0); +impl_spis!(TWISPI1, SPIS1, TWISPI1); +impl_spis!(SPI2, SPIS2, SPI2); -impl_twim!(TWISPI0, TWIM0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); -impl_twim!(TWISPI1, TWIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); +impl_twim!(TWISPI0, TWIM0, TWISPI0); +impl_twim!(TWISPI1, TWIM1, TWISPI1); -impl_twis!(TWISPI0, TWIS0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); -impl_twis!(TWISPI1, TWIS1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); +impl_twis!(TWISPI0, TWIS0, TWISPI0); +impl_twis!(TWISPI1, TWIS1, TWISPI1); impl_pwm!(PWM0, PWM0, PWM0); impl_pwm!(PWM1, PWM1, PWM1); @@ -277,19 +277,19 @@ impl_i2s!(I2S, I2S, I2S); impl_radio!(RADIO, RADIO, RADIO); -impl_egu!(EGU0, EGU0, SWI0_EGU0); -impl_egu!(EGU1, EGU1, SWI1_EGU1); -impl_egu!(EGU2, EGU2, SWI2_EGU2); -impl_egu!(EGU3, EGU3, SWI3_EGU3); -impl_egu!(EGU4, EGU4, SWI4_EGU4); -impl_egu!(EGU5, EGU5, SWI5_EGU5); +impl_egu!(EGU0, EGU0, EGU0_SWI0); +impl_egu!(EGU1, EGU1, EGU1_SWI1); +impl_egu!(EGU2, EGU2, EGU2_SWI2); +impl_egu!(EGU3, EGU3, EGU3_SWI3); +impl_egu!(EGU4, EGU4, EGU4_SWI4); +impl_egu!(EGU5, EGU5, EGU5_SWI5); embassy_hal_internal::interrupt_mod!( - POWER_CLOCK, + CLOCK_POWER, RADIO, - UARTE0_UART0, - SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0, - SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1, + UARTE0, + TWISPI0, + TWISPI1, NFCT, GPIOTE, SAADC, @@ -300,17 +300,17 @@ embassy_hal_internal::interrupt_mod!( TEMP, RNG, ECB, - CCM_AAR, + AAR_CCM, WDT, RTC1, QDEC, COMP_LPCOMP, - SWI0_EGU0, - SWI1_EGU1, - SWI2_EGU2, - SWI3_EGU3, - SWI4_EGU4, - SWI5_EGU5, + EGU0_SWI0, + EGU1_SWI1, + EGU2_SWI2, + EGU3_SWI3, + EGU4_SWI4, + EGU5_SWI5, TIMER3, TIMER4, PWM0, @@ -318,8 +318,8 @@ embassy_hal_internal::interrupt_mod!( MWU, PWM1, PWM2, - SPIM2_SPIS2_SPI2, + SPI2, RTC2, - FPU, I2S, + FPU, ); diff --git a/embassy-nrf/src/chips/nrf52833.rs b/embassy-nrf/src/chips/nrf52833.rs index 6d70b763f..a6273452a 100644 --- a/embassy-nrf/src/chips/nrf52833.rs +++ b/embassy-nrf/src/chips/nrf52833.rs @@ -185,23 +185,23 @@ embassy_hal_internal::peripherals! { impl_usb!(USBD, USBD, USBD); -impl_uarte!(UARTE0, UARTE0, UARTE0_UART0); +impl_uarte!(UARTE0, UARTE0, UARTE0); impl_uarte!(UARTE1, UARTE1, UARTE1); -impl_spim!(TWISPI0, SPIM0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); -impl_spim!(TWISPI1, SPIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); -impl_spim!(SPI2, SPIM2, SPIM2_SPIS2_SPI2); +impl_spim!(TWISPI0, SPIM0, TWISPI0); +impl_spim!(TWISPI1, SPIM1, TWISPI1); +impl_spim!(SPI2, SPIM2, SPI2); impl_spim!(SPI3, SPIM3, SPIM3); -impl_spis!(TWISPI0, SPIS0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); -impl_spis!(TWISPI1, SPIS1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); -impl_spis!(SPI2, SPIS2, SPIM2_SPIS2_SPI2); +impl_spis!(TWISPI0, SPIS0, TWISPI0); +impl_spis!(TWISPI1, SPIS1, TWISPI1); +impl_spis!(SPI2, SPIS2, SPI2); -impl_twim!(TWISPI0, TWIM0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); -impl_twim!(TWISPI1, TWIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); +impl_twim!(TWISPI0, TWIM0, TWISPI0); +impl_twim!(TWISPI1, TWIM1, TWISPI1); -impl_twis!(TWISPI0, TWIS0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); -impl_twis!(TWISPI1, TWIS1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); +impl_twis!(TWISPI0, TWIS0, TWISPI0); +impl_twis!(TWISPI1, TWIS1, TWISPI1); impl_pwm!(PWM0, PWM0, PWM0); impl_pwm!(PWM1, PWM1, PWM1); @@ -319,19 +319,19 @@ impl_i2s!(I2S, I2S, I2S); impl_radio!(RADIO, RADIO, RADIO); -impl_egu!(EGU0, EGU0, SWI0_EGU0); -impl_egu!(EGU1, EGU1, SWI1_EGU1); -impl_egu!(EGU2, EGU2, SWI2_EGU2); -impl_egu!(EGU3, EGU3, SWI3_EGU3); -impl_egu!(EGU4, EGU4, SWI4_EGU4); -impl_egu!(EGU5, EGU5, SWI5_EGU5); +impl_egu!(EGU0, EGU0, EGU0_SWI0); +impl_egu!(EGU1, EGU1, EGU1_SWI1); +impl_egu!(EGU2, EGU2, EGU2_SWI2); +impl_egu!(EGU3, EGU3, EGU3_SWI3); +impl_egu!(EGU4, EGU4, EGU4_SWI4); +impl_egu!(EGU5, EGU5, EGU5_SWI5); embassy_hal_internal::interrupt_mod!( - POWER_CLOCK, + CLOCK_POWER, RADIO, - UARTE0_UART0, - SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0, - SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1, + UARTE0, + TWISPI0, + TWISPI1, NFCT, GPIOTE, SAADC, @@ -342,17 +342,17 @@ embassy_hal_internal::interrupt_mod!( TEMP, RNG, ECB, - CCM_AAR, + AAR_CCM, WDT, RTC1, QDEC, COMP_LPCOMP, - SWI0_EGU0, - SWI1_EGU1, - SWI2_EGU2, - SWI3_EGU3, - SWI4_EGU4, - SWI5_EGU5, + EGU0_SWI0, + EGU1_SWI1, + EGU2_SWI2, + EGU3_SWI3, + EGU4_SWI4, + EGU5_SWI5, TIMER3, TIMER4, PWM0, @@ -360,12 +360,12 @@ embassy_hal_internal::interrupt_mod!( MWU, PWM1, PWM2, - SPIM2_SPIS2_SPI2, + SPI2, RTC2, + I2S, FPU, USBD, UARTE1, PWM3, SPIM3, - I2S, ); diff --git a/embassy-nrf/src/chips/nrf52840.rs b/embassy-nrf/src/chips/nrf52840.rs index b6afbf213..fb341afd5 100644 --- a/embassy-nrf/src/chips/nrf52840.rs +++ b/embassy-nrf/src/chips/nrf52840.rs @@ -188,23 +188,23 @@ embassy_hal_internal::peripherals! { impl_usb!(USBD, USBD, USBD); -impl_uarte!(UARTE0, UARTE0, UARTE0_UART0); +impl_uarte!(UARTE0, UARTE0, UARTE0); impl_uarte!(UARTE1, UARTE1, UARTE1); -impl_spim!(TWISPI0, SPIM0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); -impl_spim!(TWISPI1, SPIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); -impl_spim!(SPI2, SPIM2, SPIM2_SPIS2_SPI2); +impl_spim!(TWISPI0, SPIM0, TWISPI0); +impl_spim!(TWISPI1, SPIM1, TWISPI1); +impl_spim!(SPI2, SPIM2, SPI2); impl_spim!(SPI3, SPIM3, SPIM3); -impl_spis!(TWISPI0, SPIS0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); -impl_spis!(TWISPI1, SPIS1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); -impl_spis!(SPI2, SPIS2, SPIM2_SPIS2_SPI2); +impl_spis!(TWISPI0, SPIS0, TWISPI0); +impl_spis!(TWISPI1, SPIS1, TWISPI1); +impl_spis!(SPI2, SPIS2, SPI2); -impl_twim!(TWISPI0, TWIM0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); -impl_twim!(TWISPI1, TWIM1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); +impl_twim!(TWISPI0, TWIM0, TWISPI0); +impl_twim!(TWISPI1, TWIM1, TWISPI1); -impl_twis!(TWISPI0, TWIS0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); -impl_twis!(TWISPI1, TWIS1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1); +impl_twis!(TWISPI0, TWIS0, TWISPI0); +impl_twis!(TWISPI1, TWIS1, TWISPI1); impl_pwm!(PWM0, PWM0, PWM0); impl_pwm!(PWM1, PWM1, PWM1); @@ -324,19 +324,19 @@ impl_i2s!(I2S, I2S, I2S); impl_radio!(RADIO, RADIO, RADIO); -impl_egu!(EGU0, EGU0, SWI0_EGU0); -impl_egu!(EGU1, EGU1, SWI1_EGU1); -impl_egu!(EGU2, EGU2, SWI2_EGU2); -impl_egu!(EGU3, EGU3, SWI3_EGU3); -impl_egu!(EGU4, EGU4, SWI4_EGU4); -impl_egu!(EGU5, EGU5, SWI5_EGU5); +impl_egu!(EGU0, EGU0, EGU0_SWI0); +impl_egu!(EGU1, EGU1, EGU1_SWI1); +impl_egu!(EGU2, EGU2, EGU2_SWI2); +impl_egu!(EGU3, EGU3, EGU3_SWI3); +impl_egu!(EGU4, EGU4, EGU4_SWI4); +impl_egu!(EGU5, EGU5, EGU5_SWI5); embassy_hal_internal::interrupt_mod!( - POWER_CLOCK, + CLOCK_POWER, RADIO, - UARTE0_UART0, - SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0, - SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1, + UARTE0, + TWISPI0, + TWISPI1, NFCT, GPIOTE, SAADC, @@ -347,17 +347,17 @@ embassy_hal_internal::interrupt_mod!( TEMP, RNG, ECB, - CCM_AAR, + AAR_CCM, WDT, RTC1, QDEC, COMP_LPCOMP, - SWI0_EGU0, - SWI1_EGU1, - SWI2_EGU2, - SWI3_EGU3, - SWI4_EGU4, - SWI5_EGU5, + EGU0_SWI0, + EGU1_SWI1, + EGU2_SWI2, + EGU3_SWI3, + EGU4_SWI4, + EGU5_SWI5, TIMER3, TIMER4, PWM0, @@ -365,8 +365,9 @@ embassy_hal_internal::interrupt_mod!( MWU, PWM1, PWM2, - SPIM2_SPIS2_SPI2, + SPI2, RTC2, + I2S, FPU, USBD, UARTE1, @@ -374,5 +375,4 @@ embassy_hal_internal::interrupt_mod!( CRYPTOCELL, PWM3, SPIM3, - I2S, ); diff --git a/embassy-nrf/src/chips/nrf5340_app.rs b/embassy-nrf/src/chips/nrf5340_app.rs index d7846b094..6dc64fb4f 100644 --- a/embassy-nrf/src/chips/nrf5340_app.rs +++ b/embassy-nrf/src/chips/nrf5340_app.rs @@ -2,229 +2,158 @@ #[allow(unused_imports)] #[rustfmt::skip] pub mod pac { - // The nRF5340 has a secure and non-secure (NS) mode. - // To avoid cfg spam, we remove _ns or _s suffixes here. - - #[cfg(feature="rt")] - pub use nrf_pac::NVIC_PRIO_BITS; - pub use nrf_pac::{common, shared}; - - #[cfg(feature="rt")] - #[doc(no_inline)] - pub use nrf_pac::interrupt; - - #[doc(no_inline)] - pub use nrf_pac::{ - Interrupt, - - cache_s as cache, - cachedata_s as cachedata, - cacheinfo_s as cacheinfo, - clock_ns as clock, - comp_ns as comp, - cryptocell_s as cryptocell, - cti_s as cti, - ctrlap_ns as ctrlap, - dcnf_ns as dcnf, - dppic_ns as dppic, - egu_ns as egu, - ficr_s as ficr, - fpu_ns as fpu, - gpiote_s as gpiote, - i2s_ns as i2s, - ipc_ns as ipc, - kmu_ns as kmu, - lpcomp_ns as lpcomp, - mutex_ns as mutex, - nfct_ns as nfct, - nvmc_ns as nvmc, - oscillators_ns as oscillators, - gpio_ns as gpio, - pdm_ns as pdm, - power_ns as power, - pwm_ns as pwm, - qdec_ns as qdec, - qspi_ns as qspi, - regulators_ns as regulators, - reset_ns as reset, - rtc_ns as rtc, - saadc_ns as saadc, - spim_ns as spim, - spis_ns as spis, - spu_s as spu, - tad_s as tad, - timer_ns as timer, - twim_ns as twim, - twis_ns as twis, - uarte_ns as uarte, - uicr_s as uicr, - usbd_ns as usbd, - usbregulator_ns as usbregulator, - vmc_ns as vmc, - wdt_ns as wdt, - }; - - /// Non-Secure mode (NS) peripherals - pub mod ns { - #[cfg(feature = "nrf5340-app-ns")] - #[doc(no_inline)] - pub use nrf_pac::{ - CLOCK_NS as CLOCK, - COMP_NS as COMP, - CTRLAP_NS as CTRLAP, - DCNF_NS as DCNF, - DPPIC_NS as DPPIC, - EGU0_NS as EGU0, - EGU1_NS as EGU1, - EGU2_NS as EGU2, - EGU3_NS as EGU3, - EGU4_NS as EGU4, - EGU5_NS as EGU5, - FPU_NS as FPU, - GPIOTE1_NS as GPIOTE1, - I2S0_NS as I2S0, - IPC_NS as IPC, - KMU_NS as KMU, - LPCOMP_NS as LPCOMP, - MUTEX_NS as MUTEX, - NFCT_NS as NFCT, - NVMC_NS as NVMC, - OSCILLATORS_NS as OSCILLATORS, - P0_NS as P0, - P1_NS as P1, - PDM0_NS as PDM0, - POWER_NS as POWER, - PWM0_NS as PWM0, - PWM1_NS as PWM1, - PWM2_NS as PWM2, - PWM3_NS as PWM3, - QDEC0_NS as QDEC0, - QDEC1_NS as QDEC1, - QSPI_NS as QSPI, - REGULATORS_NS as REGULATORS, - RESET_NS as RESET, - RTC0_NS as RTC0, - RTC1_NS as RTC1, - SAADC_NS as SAADC, - SPIM0_NS as SPIM0, - SPIM1_NS as SPIM1, - SPIM2_NS as SPIM2, - SPIM3_NS as SPIM3, - SPIM4_NS as SPIM4, - SPIS0_NS as SPIS0, - SPIS1_NS as SPIS1, - SPIS2_NS as SPIS2, - SPIS3_NS as SPIS3, - TIMER0_NS as TIMER0, - TIMER1_NS as TIMER1, - TIMER2_NS as TIMER2, - TWIM0_NS as TWIM0, - TWIM1_NS as TWIM1, - TWIM2_NS as TWIM2, - TWIM3_NS as TWIM3, - TWIS0_NS as TWIS0, - TWIS1_NS as TWIS1, - TWIS2_NS as TWIS2, - TWIS3_NS as TWIS3, - UARTE0_NS as UARTE0, - UARTE1_NS as UARTE1, - UARTE2_NS as UARTE2, - UARTE3_NS as UARTE3, - USBD_NS as USBD, - USBREGULATOR_NS as USBREGULATOR, - VMC_NS as VMC, - WDT0_NS as WDT0, - WDT1_NS as WDT1, - }; - } - - /// Secure mode (S) peripherals - pub mod s { - #[cfg(feature = "nrf5340-app-s")] - #[doc(no_inline)] - pub use nrf_pac::{ - CACHEDATA_S as CACHEDATA, - CACHEINFO_S as CACHEINFO, - CACHE_S as CACHE, - CLOCK_S as CLOCK, - COMP_S as COMP, - CRYPTOCELL_S as CRYPTOCELL, - CTI_S as CTI, - CTRLAP_S as CTRLAP, - DCNF_S as DCNF, - DPPIC_S as DPPIC, - EGU0_S as EGU0, - EGU1_S as EGU1, - EGU2_S as EGU2, - EGU3_S as EGU3, - EGU4_S as EGU4, - EGU5_S as EGU5, - FICR_S as FICR, - FPU_S as FPU, - GPIOTE0_S as GPIOTE0, - I2S0_S as I2S0, - IPC_S as IPC, - KMU_S as KMU, - LPCOMP_S as LPCOMP, - MUTEX_S as MUTEX, - NFCT_S as NFCT, - NVMC_S as NVMC, - OSCILLATORS_S as OSCILLATORS, - P0_S as P0, - P1_S as P1, - PDM0_S as PDM0, - POWER_S as POWER, - PWM0_S as PWM0, - PWM1_S as PWM1, - PWM2_S as PWM2, - PWM3_S as PWM3, - QDEC0_S as QDEC0, - QDEC1_S as QDEC1, - QSPI_S as QSPI, - REGULATORS_S as REGULATORS, - RESET_S as RESET, - RTC0_S as RTC0, - RTC1_S as RTC1, - SAADC_S as SAADC, - SPIM0_S as SPIM0, - SPIM1_S as SPIM1, - SPIM2_S as SPIM2, - SPIM3_S as SPIM3, - SPIM4_S as SPIM4, - SPIS0_S as SPIS0, - SPIS1_S as SPIS1, - SPIS2_S as SPIS2, - SPIS3_S as SPIS3, - SPU_S as SPU, - TAD_S as TAD, - TIMER0_S as TIMER0, - TIMER1_S as TIMER1, - TIMER2_S as TIMER2, - TWIM0_S as TWIM0, - TWIM1_S as TWIM1, - TWIM2_S as TWIM2, - TWIM3_S as TWIM3, - TWIS0_S as TWIS0, - TWIS1_S as TWIS1, - TWIS2_S as TWIS2, - TWIS3_S as TWIS3, - UARTE0_S as UARTE0, - UARTE1_S as UARTE1, - UARTE2_S as UARTE2, - UARTE3_S as UARTE3, - UICR_S as UICR, - USBD_S as USBD, - USBREGULATOR_S as USBREGULATOR, - VMC_S as VMC, - WDT0_S as WDT0, - WDT1_S as WDT1, - }; - } + pub use nrf_pac::*; #[cfg(feature = "_ns")] - pub use ns::*; + #[doc(no_inline)] + pub use nrf_pac::{ + CLOCK_NS as CLOCK, + COMP_NS as COMP, + CTRLAP_NS as CTRLAP, + DCNF_NS as DCNF, + DPPIC_NS as DPPIC, + EGU0_NS as EGU0, + EGU1_NS as EGU1, + EGU2_NS as EGU2, + EGU3_NS as EGU3, + EGU4_NS as EGU4, + EGU5_NS as EGU5, + FPU_NS as FPU, + GPIOTE1_NS as GPIOTE1, + I2S0_NS as I2S0, + IPC_NS as IPC, + KMU_NS as KMU, + LPCOMP_NS as LPCOMP, + MUTEX_NS as MUTEX, + NFCT_NS as NFCT, + NVMC_NS as NVMC, + OSCILLATORS_NS as OSCILLATORS, + P0_NS as P0, + P1_NS as P1, + PDM0_NS as PDM0, + POWER_NS as POWER, + PWM0_NS as PWM0, + PWM1_NS as PWM1, + PWM2_NS as PWM2, + PWM3_NS as PWM3, + QDEC0_NS as QDEC0, + QDEC1_NS as QDEC1, + QSPI_NS as QSPI, + REGULATORS_NS as REGULATORS, + RESET_NS as RESET, + RTC0_NS as RTC0, + RTC1_NS as RTC1, + SAADC_NS as SAADC, + SPIM0_NS as SPIM0, + SPIM1_NS as SPIM1, + SPIM2_NS as SPIM2, + SPIM3_NS as SPIM3, + SPIM4_NS as SPIM4, + SPIS0_NS as SPIS0, + SPIS1_NS as SPIS1, + SPIS2_NS as SPIS2, + SPIS3_NS as SPIS3, + TIMER0_NS as TIMER0, + TIMER1_NS as TIMER1, + TIMER2_NS as TIMER2, + TWIM0_NS as TWIM0, + TWIM1_NS as TWIM1, + TWIM2_NS as TWIM2, + TWIM3_NS as TWIM3, + TWIS0_NS as TWIS0, + TWIS1_NS as TWIS1, + TWIS2_NS as TWIS2, + TWIS3_NS as TWIS3, + UARTE0_NS as UARTE0, + UARTE1_NS as UARTE1, + UARTE2_NS as UARTE2, + UARTE3_NS as UARTE3, + USBD_NS as USBD, + USBREGULATOR_NS as USBREGULATOR, + VMC_NS as VMC, + WDT0_NS as WDT0, + WDT1_NS as WDT1, + }; + #[cfg(feature = "_s")] - pub use s::*; + #[doc(no_inline)] + pub use nrf_pac::{ + CACHEDATA_S as CACHEDATA, + CACHEINFO_S as CACHEINFO, + CACHE_S as CACHE, + CLOCK_S as CLOCK, + COMP_S as COMP, + CRYPTOCELL_S as CRYPTOCELL, + CTI_S as CTI, + CTRLAP_S as CTRLAP, + DCNF_S as DCNF, + DPPIC_S as DPPIC, + EGU0_S as EGU0, + EGU1_S as EGU1, + EGU2_S as EGU2, + EGU3_S as EGU3, + EGU4_S as EGU4, + EGU5_S as EGU5, + FICR_S as FICR, + FPU_S as FPU, + GPIOTE0_S as GPIOTE0, + I2S0_S as I2S0, + IPC_S as IPC, + KMU_S as KMU, + LPCOMP_S as LPCOMP, + MUTEX_S as MUTEX, + NFCT_S as NFCT, + NVMC_S as NVMC, + OSCILLATORS_S as OSCILLATORS, + P0_S as P0, + P1_S as P1, + PDM0_S as PDM0, + POWER_S as POWER, + PWM0_S as PWM0, + PWM1_S as PWM1, + PWM2_S as PWM2, + PWM3_S as PWM3, + QDEC0_S as QDEC0, + QDEC1_S as QDEC1, + QSPI_S as QSPI, + REGULATORS_S as REGULATORS, + RESET_S as RESET, + RTC0_S as RTC0, + RTC1_S as RTC1, + SAADC_S as SAADC, + SPIM0_S as SPIM0, + SPIM1_S as SPIM1, + SPIM2_S as SPIM2, + SPIM3_S as SPIM3, + SPIM4_S as SPIM4, + SPIS0_S as SPIS0, + SPIS1_S as SPIS1, + SPIS2_S as SPIS2, + SPIS3_S as SPIS3, + SPU_S as SPU, + TAD_S as TAD, + TIMER0_S as TIMER0, + TIMER1_S as TIMER1, + TIMER2_S as TIMER2, + TWIM0_S as TWIM0, + TWIM1_S as TWIM1, + TWIM2_S as TWIM2, + TWIM3_S as TWIM3, + TWIS0_S as TWIS0, + TWIS1_S as TWIS1, + TWIS2_S as TWIS2, + TWIS3_S as TWIS3, + UARTE0_S as UARTE0, + UARTE1_S as UARTE1, + UARTE2_S as UARTE2, + UARTE3_S as UARTE3, + UICR_S as UICR, + USBD_S as USBD, + USBREGULATOR_S as USBREGULATOR, + VMC_S as VMC, + WDT0_S as WDT0, + WDT1_S as WDT1, + }; } /// The maximum buffer size that the EasyDMA can send/recv in one operation. diff --git a/embassy-nrf/src/chips/nrf5340_net.rs b/embassy-nrf/src/chips/nrf5340_net.rs index 00ff5fea6..6c6ac3fbb 100644 --- a/embassy-nrf/src/chips/nrf5340_net.rs +++ b/embassy-nrf/src/chips/nrf5340_net.rs @@ -2,55 +2,10 @@ #[allow(unused_imports)] #[rustfmt::skip] pub mod pac { - // The nRF5340 has a secure and non-secure (NS) mode. - // To avoid cfg spam, we remove _ns or _s suffixes here. - - #[cfg(feature="rt")] - pub use nrf_pac::NVIC_PRIO_BITS; - pub use nrf_pac::{common, shared}; - - #[cfg(feature="rt")] - #[doc(no_inline)] - pub use nrf_pac::interrupt; + pub use nrf_pac::*; #[doc(no_inline)] pub use nrf_pac::{ - Interrupt, - - aar_ns as aar, - acl_ns as acl, - appmutex_ns as appmutex, - ccm_ns as ccm, - clock_ns as clock, - cti_ns as cti, - ctrlap_ns as ctrlap, - dcnf_ns as dcnf, - dppic_ns as dppic, - ecb_ns as ecb, - egu_ns as egu, - ficr_ns as ficr, - gpiote_ns as gpiote, - ipc_ns as ipc, - nvmc_ns as nvmc, - gpio_ns as gpio, - power_ns as power, - radio_ns as radio, - reset_ns as reset, - rng_ns as rng, - rtc_ns as rtc, - spim_ns as spim, - spis_ns as spis, - swi_ns as swi, - temp_ns as temp, - timer_ns as timer, - twim_ns as twim, - twis_ns as twis, - uarte_ns as uarte, - uicr_ns as uicr, - vmc_ns as vmc, - vreqctrl_ns as vreqctrl, - wdt_ns as wdt, - AAR_NS as AAR, ACL_NS as ACL, APPMUTEX_NS as APPMUTEX, @@ -93,7 +48,6 @@ pub mod pac { VREQCTRL_NS as VREQCTRL, WDT_NS as WDT, }; - } /// The maximum buffer size that the EasyDMA can send/recv in one operation. diff --git a/embassy-nrf/src/chips/nrf9120.rs b/embassy-nrf/src/chips/nrf9120.rs index b89570dcd..b02b8c6d8 100644 --- a/embassy-nrf/src/chips/nrf9120.rs +++ b/embassy-nrf/src/chips/nrf9120.rs @@ -2,179 +2,124 @@ #[allow(unused_imports)] #[rustfmt::skip] pub mod pac { - // The nRF9120 has a secure and non-secure (NS) mode. - // To avoid cfg spam, we remove _ns or _s suffixes here. - - #[cfg(feature="rt")] - pub use nrf_pac::NVIC_PRIO_BITS; - pub use nrf_pac::{common, shared}; - - #[cfg(feature="rt")] - #[doc(no_inline)] - pub use nrf_pac::interrupt; - - #[doc(no_inline)] - pub use nrf_pac::{ - Interrupt, - - cc_host_rgf_s as cc_host_rgf, - clock_ns as clock, - cryptocell_s as cryptocell, - ctrl_ap_peri_s as ctrl_ap_peri, - dppic_ns as dppic, - egu_ns as egu, - ficr_s as ficr, - fpu_ns as fpu, - gpiote_s as gpiote, - i2s_ns as i2s, - ipc_ns as ipc, - kmu_ns as kmu, - nvmc_ns as nvmc, - gpio_ns as gpio, - pdm_ns as pdm, - power_ns as power, - pwm_ns as pwm, - regulators_ns as regulators, - rtc_ns as rtc, - saadc_ns as saadc, - spim_ns as spim, - spis_ns as spis, - spu_s as spu, - tad_s as tad, - timer_ns as timer, - twim_ns as twim, - twis_ns as twis, - uarte_ns as uarte, - uicr_s as uicr, - vmc_ns as vmc, - wdt_ns as wdt, - }; - - /// Non-Secure mode (NS) peripherals - pub mod ns { - #[doc(no_inline)] - pub use nrf_pac::{ - CLOCK_NS as CLOCK, - DPPIC_NS as DPPIC, - EGU0_NS as EGU0, - EGU1_NS as EGU1, - EGU2_NS as EGU2, - EGU3_NS as EGU3, - EGU4_NS as EGU4, - EGU5_NS as EGU5, - FPU_NS as FPU, - GPIOTE1_NS as GPIOTE1, - I2S_NS as I2S, - IPC_NS as IPC, - KMU_NS as KMU, - NVMC_NS as NVMC, - P0_NS as P0, - PDM_NS as PDM, - POWER_NS as POWER, - PWM0_NS as PWM0, - PWM1_NS as PWM1, - PWM2_NS as PWM2, - PWM3_NS as PWM3, - REGULATORS_NS as REGULATORS, - RTC0_NS as RTC0, - RTC1_NS as RTC1, - SAADC_NS as SAADC, - SPIM0_NS as SPIM0, - SPIM1_NS as SPIM1, - SPIM2_NS as SPIM2, - SPIM3_NS as SPIM3, - SPIS0_NS as SPIS0, - SPIS1_NS as SPIS1, - SPIS2_NS as SPIS2, - SPIS3_NS as SPIS3, - TIMER0_NS as TIMER0, - TIMER1_NS as TIMER1, - TIMER2_NS as TIMER2, - TWIM0_NS as TWIM0, - TWIM1_NS as TWIM1, - TWIM2_NS as TWIM2, - TWIM3_NS as TWIM3, - TWIS0_NS as TWIS0, - TWIS1_NS as TWIS1, - TWIS2_NS as TWIS2, - TWIS3_NS as TWIS3, - UARTE0_NS as UARTE0, - UARTE1_NS as UARTE1, - UARTE2_NS as UARTE2, - UARTE3_NS as UARTE3, - VMC_NS as VMC, - WDT_NS as WDT, - }; - } - - /// Secure mode (S) peripherals - pub mod s { - #[doc(no_inline)] - pub use nrf_pac::{ - CC_HOST_RGF_S as CC_HOST_RGF, - CLOCK_S as CLOCK, - CRYPTOCELL_S as CRYPTOCELL, - CTRL_AP_PERI_S as CTRL_AP_PERI, - DPPIC_S as DPPIC, - EGU0_S as EGU0, - EGU1_S as EGU1, - EGU2_S as EGU2, - EGU3_S as EGU3, - EGU4_S as EGU4, - EGU5_S as EGU5, - FICR_S as FICR, - FPU_NS as FPU, - GPIOTE0_S as GPIOTE0, - I2S_S as I2S, - IPC_S as IPC, - KMU_S as KMU, - NVMC_S as NVMC, - P0_S as P0, - PDM_S as PDM, - POWER_S as POWER, - PWM0_S as PWM0, - PWM1_S as PWM1, - PWM2_S as PWM2, - PWM3_S as PWM3, - REGULATORS_S as REGULATORS, - RTC0_S as RTC0, - RTC1_S as RTC1, - SAADC_S as SAADC, - SPIM0_S as SPIM0, - SPIM1_S as SPIM1, - SPIM2_S as SPIM2, - SPIM3_S as SPIM3, - SPIS0_S as SPIS0, - SPIS1_S as SPIS1, - SPIS2_S as SPIS2, - SPIS3_S as SPIS3, - SPU_S as SPU, - TAD_S as TAD, - TIMER0_S as TIMER0, - TIMER1_S as TIMER1, - TIMER2_S as TIMER2, - TWIM0_S as TWIM0, - TWIM1_S as TWIM1, - TWIM2_S as TWIM2, - TWIM3_S as TWIM3, - TWIS0_S as TWIS0, - TWIS1_S as TWIS1, - TWIS2_S as TWIS2, - TWIS3_S as TWIS3, - UARTE0_S as UARTE0, - UARTE1_S as UARTE1, - UARTE2_S as UARTE2, - UARTE3_S as UARTE3, - UICR_S as UICR, - VMC_S as VMC, - WDT_S as WDT, - }; - } + pub use nrf_pac::*; #[cfg(feature = "_ns")] - pub use ns::*; + #[doc(no_inline)] + pub use nrf_pac::{ + CLOCK_NS as CLOCK, + DPPIC_NS as DPPIC, + EGU0_NS as EGU0, + EGU1_NS as EGU1, + EGU2_NS as EGU2, + EGU3_NS as EGU3, + EGU4_NS as EGU4, + EGU5_NS as EGU5, + FPU_NS as FPU, + GPIOTE1_NS as GPIOTE1, + I2S_NS as I2S, + IPC_NS as IPC, + KMU_NS as KMU, + NVMC_NS as NVMC, + P0_NS as P0, + PDM_NS as PDM, + POWER_NS as POWER, + PWM0_NS as PWM0, + PWM1_NS as PWM1, + PWM2_NS as PWM2, + PWM3_NS as PWM3, + REGULATORS_NS as REGULATORS, + RTC0_NS as RTC0, + RTC1_NS as RTC1, + SAADC_NS as SAADC, + SPIM0_NS as SPIM0, + SPIM1_NS as SPIM1, + SPIM2_NS as SPIM2, + SPIM3_NS as SPIM3, + SPIS0_NS as SPIS0, + SPIS1_NS as SPIS1, + SPIS2_NS as SPIS2, + SPIS3_NS as SPIS3, + TIMER0_NS as TIMER0, + TIMER1_NS as TIMER1, + TIMER2_NS as TIMER2, + TWIM0_NS as TWIM0, + TWIM1_NS as TWIM1, + TWIM2_NS as TWIM2, + TWIM3_NS as TWIM3, + TWIS0_NS as TWIS0, + TWIS1_NS as TWIS1, + TWIS2_NS as TWIS2, + TWIS3_NS as TWIS3, + UARTE0_NS as UARTE0, + UARTE1_NS as UARTE1, + UARTE2_NS as UARTE2, + UARTE3_NS as UARTE3, + VMC_NS as VMC, + WDT_NS as WDT, + }; + #[cfg(feature = "_s")] - pub use s::*; + #[doc(no_inline)] + pub use nrf_pac::{ + CC_HOST_RGF_S as CC_HOST_RGF, + CLOCK_S as CLOCK, + CRYPTOCELL_S as CRYPTOCELL, + CTRL_AP_PERI_S as CTRL_AP_PERI, + DPPIC_S as DPPIC, + EGU0_S as EGU0, + EGU1_S as EGU1, + EGU2_S as EGU2, + EGU3_S as EGU3, + EGU4_S as EGU4, + EGU5_S as EGU5, + FICR_S as FICR, + FPU_NS as FPU, + GPIOTE0_S as GPIOTE0, + I2S_S as I2S, + IPC_S as IPC, + KMU_S as KMU, + NVMC_S as NVMC, + P0_S as P0, + PDM_S as PDM, + POWER_S as POWER, + PWM0_S as PWM0, + PWM1_S as PWM1, + PWM2_S as PWM2, + PWM3_S as PWM3, + REGULATORS_S as REGULATORS, + RTC0_S as RTC0, + RTC1_S as RTC1, + SAADC_S as SAADC, + SPIM0_S as SPIM0, + SPIM1_S as SPIM1, + SPIM2_S as SPIM2, + SPIM3_S as SPIM3, + SPIS0_S as SPIS0, + SPIS1_S as SPIS1, + SPIS2_S as SPIS2, + SPIS3_S as SPIS3, + SPU_S as SPU, + TAD_S as TAD, + TIMER0_S as TIMER0, + TIMER1_S as TIMER1, + TIMER2_S as TIMER2, + TWIM0_S as TWIM0, + TWIM1_S as TWIM1, + TWIM2_S as TWIM2, + TWIM3_S as TWIM3, + TWIS0_S as TWIS0, + TWIS1_S as TWIS1, + TWIS2_S as TWIS2, + TWIS3_S as TWIS3, + UARTE0_S as UARTE0, + UARTE1_S as UARTE1, + UARTE2_S as UARTE2, + UARTE3_S as UARTE3, + UICR_S as UICR, + VMC_S as VMC, + WDT_S as WDT, + }; } /// The maximum buffer size that the EasyDMA can send/recv in one operation. @@ -295,30 +240,30 @@ embassy_hal_internal::peripherals! { EGU5, } -impl_uarte!(SERIAL0, UARTE0, SPIM0_SPIS0_TWIM0_TWIS0_UARTE0); -impl_uarte!(SERIAL1, UARTE1, SPIM1_SPIS1_TWIM1_TWIS1_UARTE1); -impl_uarte!(SERIAL2, UARTE2, SPIM2_SPIS2_TWIM2_TWIS2_UARTE2); -impl_uarte!(SERIAL3, UARTE3, SPIM3_SPIS3_TWIM3_TWIS3_UARTE3); +impl_uarte!(SERIAL0, UARTE0, SERIAL0); +impl_uarte!(SERIAL1, UARTE1, SERIAL1); +impl_uarte!(SERIAL2, UARTE2, SERIAL2); +impl_uarte!(SERIAL3, UARTE3, SERIAL3); -impl_spim!(SERIAL0, SPIM0, SPIM0_SPIS0_TWIM0_TWIS0_UARTE0); -impl_spim!(SERIAL1, SPIM1, SPIM1_SPIS1_TWIM1_TWIS1_UARTE1); -impl_spim!(SERIAL2, SPIM2, SPIM2_SPIS2_TWIM2_TWIS2_UARTE2); -impl_spim!(SERIAL3, SPIM3, SPIM3_SPIS3_TWIM3_TWIS3_UARTE3); +impl_spim!(SERIAL0, SPIM0, SERIAL0); +impl_spim!(SERIAL1, SPIM1, SERIAL1); +impl_spim!(SERIAL2, SPIM2, SERIAL2); +impl_spim!(SERIAL3, SPIM3, SERIAL3); -impl_spis!(SERIAL0, SPIS0, SPIM0_SPIS0_TWIM0_TWIS0_UARTE0); -impl_spis!(SERIAL1, SPIS1, SPIM1_SPIS1_TWIM1_TWIS1_UARTE1); -impl_spis!(SERIAL2, SPIS2, SPIM2_SPIS2_TWIM2_TWIS2_UARTE2); -impl_spis!(SERIAL3, SPIS3, SPIM3_SPIS3_TWIM3_TWIS3_UARTE3); +impl_spis!(SERIAL0, SPIS0, SERIAL0); +impl_spis!(SERIAL1, SPIS1, SERIAL1); +impl_spis!(SERIAL2, SPIS2, SERIAL2); +impl_spis!(SERIAL3, SPIS3, SERIAL3); -impl_twim!(SERIAL0, TWIM0, SPIM0_SPIS0_TWIM0_TWIS0_UARTE0); -impl_twim!(SERIAL1, TWIM1, SPIM1_SPIS1_TWIM1_TWIS1_UARTE1); -impl_twim!(SERIAL2, TWIM2, SPIM2_SPIS2_TWIM2_TWIS2_UARTE2); -impl_twim!(SERIAL3, TWIM3, SPIM3_SPIS3_TWIM3_TWIS3_UARTE3); +impl_twim!(SERIAL0, TWIM0, SERIAL0); +impl_twim!(SERIAL1, TWIM1, SERIAL1); +impl_twim!(SERIAL2, TWIM2, SERIAL2); +impl_twim!(SERIAL3, TWIM3, SERIAL3); -impl_twis!(SERIAL0, TWIS0, SPIM0_SPIS0_TWIM0_TWIS0_UARTE0); -impl_twis!(SERIAL1, TWIS1, SPIM1_SPIS1_TWIM1_TWIS1_UARTE1); -impl_twis!(SERIAL2, TWIS2, SPIM2_SPIS2_TWIM2_TWIS2_UARTE2); -impl_twis!(SERIAL3, TWIS3, SPIM3_SPIS3_TWIM3_TWIS3_UARTE3); +impl_twis!(SERIAL0, TWIS0, SERIAL0); +impl_twis!(SERIAL1, TWIS1, SERIAL1); +impl_twis!(SERIAL2, TWIS2, SERIAL2); +impl_twis!(SERIAL3, TWIS3, SERIAL3); impl_pwm!(PWM0, PWM0, PWM0); impl_pwm!(PWM1, PWM1, PWM1); @@ -400,10 +345,10 @@ impl_egu!(EGU5, EGU5, EGU5); embassy_hal_internal::interrupt_mod!( SPU, CLOCK_POWER, - SPIM0_SPIS0_TWIM0_TWIS0_UARTE0, - SPIM1_SPIS1_TWIM1_TWIS1_UARTE1, - SPIM2_SPIS2_TWIM2_TWIS2_UARTE2, - SPIM3_SPIS3_TWIM3_TWIS3_UARTE3, + SERIAL0, + SERIAL1, + SERIAL2, + SERIAL3, GPIOTE0, SAADC, TIMER0, @@ -421,8 +366,8 @@ embassy_hal_internal::interrupt_mod!( PWM0, PWM1, PWM2, - PDM, PWM3, + PDM, I2S, IPC, FPU, diff --git a/embassy-nrf/src/chips/nrf9160.rs b/embassy-nrf/src/chips/nrf9160.rs index dba3d1ef5..b0981e3b5 100644 --- a/embassy-nrf/src/chips/nrf9160.rs +++ b/embassy-nrf/src/chips/nrf9160.rs @@ -2,179 +2,124 @@ #[allow(unused_imports)] #[rustfmt::skip] pub mod pac { - // The nRF9160 has a secure and non-secure (NS) mode. - // To avoid cfg spam, we remove _ns or _s suffixes here. - - #[cfg(feature="rt")] - pub use nrf_pac::NVIC_PRIO_BITS; - pub use nrf_pac::{common, shared}; - - #[cfg(feature="rt")] - #[doc(no_inline)] - pub use nrf_pac::interrupt; - - #[doc(no_inline)] - pub use nrf_pac::{ - Interrupt, - - cc_host_rgf_s as cc_host_rgf, - clock_ns as clock, - cryptocell_s as cryptocell, - ctrl_ap_peri_s as ctrl_ap_peri, - dppic_ns as dppic, - egu_ns as egu, - ficr_s as ficr, - fpu_ns as fpu, - gpiote_s as gpiote, - i2s_ns as i2s, - ipc_ns as ipc, - kmu_ns as kmu, - nvmc_ns as nvmc, - gpio_ns as gpio, - pdm_ns as pdm, - power_ns as power, - pwm_ns as pwm, - regulators_ns as regulators, - rtc_ns as rtc, - saadc_ns as saadc, - spim_ns as spim, - spis_ns as spis, - spu_s as spu, - tad_s as tad, - timer_ns as timer, - twim_ns as twim, - twis_ns as twis, - uarte_ns as uarte, - uicr_s as uicr, - vmc_ns as vmc, - wdt_ns as wdt, - }; - - /// Non-Secure mode (NS) peripherals - pub mod ns { - #[doc(no_inline)] - pub use nrf_pac::{ - CLOCK_NS as CLOCK, - DPPIC_NS as DPPIC, - EGU0_NS as EGU0, - EGU1_NS as EGU1, - EGU2_NS as EGU2, - EGU3_NS as EGU3, - EGU4_NS as EGU4, - EGU5_NS as EGU5, - FPU_NS as FPU, - GPIOTE1_NS as GPIOTE1, - I2S_NS as I2S, - IPC_NS as IPC, - KMU_NS as KMU, - NVMC_NS as NVMC, - P0_NS as P0, - PDM_NS as PDM, - POWER_NS as POWER, - PWM0_NS as PWM0, - PWM1_NS as PWM1, - PWM2_NS as PWM2, - PWM3_NS as PWM3, - REGULATORS_NS as REGULATORS, - RTC0_NS as RTC0, - RTC1_NS as RTC1, - SAADC_NS as SAADC, - SPIM0_NS as SPIM0, - SPIM1_NS as SPIM1, - SPIM2_NS as SPIM2, - SPIM3_NS as SPIM3, - SPIS0_NS as SPIS0, - SPIS1_NS as SPIS1, - SPIS2_NS as SPIS2, - SPIS3_NS as SPIS3, - TIMER0_NS as TIMER0, - TIMER1_NS as TIMER1, - TIMER2_NS as TIMER2, - TWIM0_NS as TWIM0, - TWIM1_NS as TWIM1, - TWIM2_NS as TWIM2, - TWIM3_NS as TWIM3, - TWIS0_NS as TWIS0, - TWIS1_NS as TWIS1, - TWIS2_NS as TWIS2, - TWIS3_NS as TWIS3, - UARTE0_NS as UARTE0, - UARTE1_NS as UARTE1, - UARTE2_NS as UARTE2, - UARTE3_NS as UARTE3, - VMC_NS as VMC, - WDT_NS as WDT, - }; - } - - /// Secure mode (S) peripherals - pub mod s { - #[doc(no_inline)] - pub use nrf_pac::{ - CC_HOST_RGF_S as CC_HOST_RGF, - CLOCK_S as CLOCK, - CRYPTOCELL_S as CRYPTOCELL, - CTRL_AP_PERI_S as CTRL_AP_PERI, - DPPIC_S as DPPIC, - EGU0_S as EGU0, - EGU1_S as EGU1, - EGU2_S as EGU2, - EGU3_S as EGU3, - EGU4_S as EGU4, - EGU5_S as EGU5, - FICR_S as FICR, - FPU_S as FPU, - GPIOTE0_S as GPIOTE0, - I2S_S as I2S, - IPC_S as IPC, - KMU_S as KMU, - NVMC_S as NVMC, - P0_S as P0, - PDM_S as PDM, - POWER_S as POWER, - PWM0_S as PWM0, - PWM1_S as PWM1, - PWM2_S as PWM2, - PWM3_S as PWM3, - REGULATORS_S as REGULATORS, - RTC0_S as RTC0, - RTC1_S as RTC1, - SAADC_S as SAADC, - SPIM0_S as SPIM0, - SPIM1_S as SPIM1, - SPIM2_S as SPIM2, - SPIM3_S as SPIM3, - SPIS0_S as SPIS0, - SPIS1_S as SPIS1, - SPIS2_S as SPIS2, - SPIS3_S as SPIS3, - SPU_S as SPU, - TAD_S as TAD, - TIMER0_S as TIMER0, - TIMER1_S as TIMER1, - TIMER2_S as TIMER2, - TWIM0_S as TWIM0, - TWIM1_S as TWIM1, - TWIM2_S as TWIM2, - TWIM3_S as TWIM3, - TWIS0_S as TWIS0, - TWIS1_S as TWIS1, - TWIS2_S as TWIS2, - TWIS3_S as TWIS3, - UARTE0_S as UARTE0, - UARTE1_S as UARTE1, - UARTE2_S as UARTE2, - UARTE3_S as UARTE3, - UICR_S as UICR, - VMC_S as VMC, - WDT_S as WDT, - }; - } + pub use nrf_pac::*; #[cfg(feature = "_ns")] - pub use ns::*; + #[doc(no_inline)] + pub use nrf_pac::{ + CLOCK_NS as CLOCK, + DPPIC_NS as DPPIC, + EGU0_NS as EGU0, + EGU1_NS as EGU1, + EGU2_NS as EGU2, + EGU3_NS as EGU3, + EGU4_NS as EGU4, + EGU5_NS as EGU5, + FPU_NS as FPU, + GPIOTE1_NS as GPIOTE1, + I2S_NS as I2S, + IPC_NS as IPC, + KMU_NS as KMU, + NVMC_NS as NVMC, + P0_NS as P0, + PDM_NS as PDM, + POWER_NS as POWER, + PWM0_NS as PWM0, + PWM1_NS as PWM1, + PWM2_NS as PWM2, + PWM3_NS as PWM3, + REGULATORS_NS as REGULATORS, + RTC0_NS as RTC0, + RTC1_NS as RTC1, + SAADC_NS as SAADC, + SPIM0_NS as SPIM0, + SPIM1_NS as SPIM1, + SPIM2_NS as SPIM2, + SPIM3_NS as SPIM3, + SPIS0_NS as SPIS0, + SPIS1_NS as SPIS1, + SPIS2_NS as SPIS2, + SPIS3_NS as SPIS3, + TIMER0_NS as TIMER0, + TIMER1_NS as TIMER1, + TIMER2_NS as TIMER2, + TWIM0_NS as TWIM0, + TWIM1_NS as TWIM1, + TWIM2_NS as TWIM2, + TWIM3_NS as TWIM3, + TWIS0_NS as TWIS0, + TWIS1_NS as TWIS1, + TWIS2_NS as TWIS2, + TWIS3_NS as TWIS3, + UARTE0_NS as UARTE0, + UARTE1_NS as UARTE1, + UARTE2_NS as UARTE2, + UARTE3_NS as UARTE3, + VMC_NS as VMC, + WDT_NS as WDT, + }; + #[cfg(feature = "_s")] - pub use s::*; + #[doc(no_inline)] + pub use nrf_pac::{ + CC_HOST_RGF_S as CC_HOST_RGF, + CLOCK_S as CLOCK, + CRYPTOCELL_S as CRYPTOCELL, + CTRL_AP_PERI_S as CTRL_AP_PERI, + DPPIC_S as DPPIC, + EGU0_S as EGU0, + EGU1_S as EGU1, + EGU2_S as EGU2, + EGU3_S as EGU3, + EGU4_S as EGU4, + EGU5_S as EGU5, + FICR_S as FICR, + FPU_S as FPU, + GPIOTE0_S as GPIOTE0, + I2S_S as I2S, + IPC_S as IPC, + KMU_S as KMU, + NVMC_S as NVMC, + P0_S as P0, + PDM_S as PDM, + POWER_S as POWER, + PWM0_S as PWM0, + PWM1_S as PWM1, + PWM2_S as PWM2, + PWM3_S as PWM3, + REGULATORS_S as REGULATORS, + RTC0_S as RTC0, + RTC1_S as RTC1, + SAADC_S as SAADC, + SPIM0_S as SPIM0, + SPIM1_S as SPIM1, + SPIM2_S as SPIM2, + SPIM3_S as SPIM3, + SPIS0_S as SPIS0, + SPIS1_S as SPIS1, + SPIS2_S as SPIS2, + SPIS3_S as SPIS3, + SPU_S as SPU, + TAD_S as TAD, + TIMER0_S as TIMER0, + TIMER1_S as TIMER1, + TIMER2_S as TIMER2, + TWIM0_S as TWIM0, + TWIM1_S as TWIM1, + TWIM2_S as TWIM2, + TWIM3_S as TWIM3, + TWIS0_S as TWIS0, + TWIS1_S as TWIS1, + TWIS2_S as TWIS2, + TWIS3_S as TWIS3, + UARTE0_S as UARTE0, + UARTE1_S as UARTE1, + UARTE2_S as UARTE2, + UARTE3_S as UARTE3, + UICR_S as UICR, + VMC_S as VMC, + WDT_S as WDT, + }; } /// The maximum buffer size that the EasyDMA can send/recv in one operation. @@ -295,30 +240,30 @@ embassy_hal_internal::peripherals! { EGU5, } -impl_uarte!(SERIAL0, UARTE0, UARTE0_SPIM0_SPIS0_TWIM0_TWIS0); -impl_uarte!(SERIAL1, UARTE1, UARTE1_SPIM1_SPIS1_TWIM1_TWIS1); -impl_uarte!(SERIAL2, UARTE2, UARTE2_SPIM2_SPIS2_TWIM2_TWIS2); -impl_uarte!(SERIAL3, UARTE3, UARTE3_SPIM3_SPIS3_TWIM3_TWIS3); +impl_uarte!(SERIAL0, UARTE0, SERIAL0); +impl_uarte!(SERIAL1, UARTE1, SERIAL1); +impl_uarte!(SERIAL2, UARTE2, SERIAL2); +impl_uarte!(SERIAL3, UARTE3, SERIAL3); -impl_spim!(SERIAL0, SPIM0, UARTE0_SPIM0_SPIS0_TWIM0_TWIS0); -impl_spim!(SERIAL1, SPIM1, UARTE1_SPIM1_SPIS1_TWIM1_TWIS1); -impl_spim!(SERIAL2, SPIM2, UARTE2_SPIM2_SPIS2_TWIM2_TWIS2); -impl_spim!(SERIAL3, SPIM3, UARTE3_SPIM3_SPIS3_TWIM3_TWIS3); +impl_spim!(SERIAL0, SPIM0, SERIAL0); +impl_spim!(SERIAL1, SPIM1, SERIAL1); +impl_spim!(SERIAL2, SPIM2, SERIAL2); +impl_spim!(SERIAL3, SPIM3, SERIAL3); -impl_spis!(SERIAL0, SPIS0, UARTE0_SPIM0_SPIS0_TWIM0_TWIS0); -impl_spis!(SERIAL1, SPIS1, UARTE1_SPIM1_SPIS1_TWIM1_TWIS1); -impl_spis!(SERIAL2, SPIS2, UARTE2_SPIM2_SPIS2_TWIM2_TWIS2); -impl_spis!(SERIAL3, SPIS3, UARTE3_SPIM3_SPIS3_TWIM3_TWIS3); +impl_spis!(SERIAL0, SPIS0, SERIAL0); +impl_spis!(SERIAL1, SPIS1, SERIAL1); +impl_spis!(SERIAL2, SPIS2, SERIAL2); +impl_spis!(SERIAL3, SPIS3, SERIAL3); -impl_twim!(SERIAL0, TWIM0, UARTE0_SPIM0_SPIS0_TWIM0_TWIS0); -impl_twim!(SERIAL1, TWIM1, UARTE1_SPIM1_SPIS1_TWIM1_TWIS1); -impl_twim!(SERIAL2, TWIM2, UARTE2_SPIM2_SPIS2_TWIM2_TWIS2); -impl_twim!(SERIAL3, TWIM3, UARTE3_SPIM3_SPIS3_TWIM3_TWIS3); +impl_twim!(SERIAL0, TWIM0, SERIAL0); +impl_twim!(SERIAL1, TWIM1, SERIAL1); +impl_twim!(SERIAL2, TWIM2, SERIAL2); +impl_twim!(SERIAL3, TWIM3, SERIAL3); -impl_twis!(SERIAL0, TWIS0, UARTE0_SPIM0_SPIS0_TWIM0_TWIS0); -impl_twis!(SERIAL1, TWIS1, UARTE1_SPIM1_SPIS1_TWIM1_TWIS1); -impl_twis!(SERIAL2, TWIS2, UARTE2_SPIM2_SPIS2_TWIM2_TWIS2); -impl_twis!(SERIAL3, TWIS3, UARTE3_SPIM3_SPIS3_TWIM3_TWIS3); +impl_twis!(SERIAL0, TWIS0, SERIAL0); +impl_twis!(SERIAL1, TWIS1, SERIAL1); +impl_twis!(SERIAL2, TWIS2, SERIAL2); +impl_twis!(SERIAL3, TWIS3, SERIAL3); impl_pwm!(PWM0, PWM0, PWM0); impl_pwm!(PWM1, PWM1, PWM1); @@ -400,10 +345,10 @@ impl_egu!(EGU5, EGU5, EGU5); embassy_hal_internal::interrupt_mod!( SPU, CLOCK_POWER, - UARTE0_SPIM0_SPIS0_TWIM0_TWIS0, - UARTE1_SPIM1_SPIS1_TWIM1_TWIS1, - UARTE2_SPIM2_SPIS2_TWIM2_TWIS2, - UARTE3_SPIM3_SPIS3_TWIM3_TWIS3, + SERIAL0, + SERIAL1, + SERIAL2, + SERIAL3, GPIOTE0, SAADC, TIMER0, @@ -421,8 +366,8 @@ embassy_hal_internal::interrupt_mod!( PWM0, PWM1, PWM2, - PDM, PWM3, + PDM, I2S, IPC, FPU, diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index 430b6fae7..8167b44f3 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs @@ -170,7 +170,7 @@ mod chip; /// /// bind_interrupts!(struct Irqs { /// SPIM3 => spim::InterruptHandler; -/// SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0 => twim::InterruptHandler; +/// TWISPI0 => twim::InterruptHandler; /// }); /// ``` diff --git a/embassy-nrf/src/time_driver.rs b/embassy-nrf/src/time_driver.rs index e39c4ed52..b6492ac97 100644 --- a/embassy-nrf/src/time_driver.rs +++ b/embassy-nrf/src/time_driver.rs @@ -132,7 +132,7 @@ impl RtcDriver { r.intenset().write(|w| { w.set_ovrflw(true); - w.set_compare3(true); + w.set_compare(3, true); }); r.tasks_clear().write_value(1); diff --git a/embassy-nrf/src/usb/vbus_detect.rs b/embassy-nrf/src/usb/vbus_detect.rs index 7f816a5ad..bdc088dcb 100644 --- a/embassy-nrf/src/usb/vbus_detect.rs +++ b/embassy-nrf/src/usb/vbus_detect.rs @@ -29,14 +29,14 @@ pub trait VbusDetect { } #[cfg(not(feature = "_nrf5340"))] -type UsbRegIrq = interrupt::typelevel::POWER_CLOCK; +type UsbRegIrq = interrupt::typelevel::CLOCK_POWER; #[cfg(feature = "_nrf5340")] type UsbRegIrq = interrupt::typelevel::USBREGULATOR; #[cfg(not(feature = "_nrf5340"))] const USB_REG_PERI: pac::power::Power = pac::POWER; #[cfg(feature = "_nrf5340")] -const USB_REG_PERI: pac::usbregulator::Usbregulator = pac::USBREGULATOR; +const USB_REG_PERI: pac::usbreg::Usbreg = pac::USBREGULATOR; /// Interrupt handler. pub struct InterruptHandler { diff --git a/examples/nrf52840-rtic/src/bin/blinky.rs b/examples/nrf52840-rtic/src/bin/blinky.rs index 060bb9ebc..5a074ea17 100644 --- a/examples/nrf52840-rtic/src/bin/blinky.rs +++ b/examples/nrf52840-rtic/src/bin/blinky.rs @@ -4,7 +4,7 @@ use {defmt_rtt as _, panic_probe as _}; -#[rtic::app(device = embassy_nrf, peripherals = false, dispatchers = [SWI0_EGU0, SWI1_EGU1])] +#[rtic::app(device = embassy_nrf, peripherals = false, dispatchers = [EGU0_SWI0, EGU1_SWI1])] mod app { use defmt::info; use embassy_nrf::gpio::{Level, Output, OutputDrive}; diff --git a/examples/nrf52840/src/bin/buffered_uart.rs b/examples/nrf52840/src/bin/buffered_uart.rs index 6ac72bcaf..77d017964 100644 --- a/examples/nrf52840/src/bin/buffered_uart.rs +++ b/examples/nrf52840/src/bin/buffered_uart.rs @@ -9,7 +9,7 @@ use embedded_io_async::Write; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { - UARTE0_UART0 => buffered_uarte::InterruptHandler; + UARTE0 => buffered_uarte::InterruptHandler; }); #[embassy_executor::main] diff --git a/examples/nrf52840/src/bin/multiprio.rs b/examples/nrf52840/src/bin/multiprio.rs index 797be93a7..d58613da4 100644 --- a/examples/nrf52840/src/bin/multiprio.rs +++ b/examples/nrf52840/src/bin/multiprio.rs @@ -112,12 +112,12 @@ static EXECUTOR_MED: InterruptExecutor = InterruptExecutor::new(); static EXECUTOR_LOW: StaticCell = StaticCell::new(); #[interrupt] -unsafe fn SWI1_EGU1() { +unsafe fn EGU1_SWI1() { EXECUTOR_HIGH.on_interrupt() } #[interrupt] -unsafe fn SWI0_EGU0() { +unsafe fn EGU0_SWI0() { EXECUTOR_MED.on_interrupt() } @@ -127,14 +127,14 @@ fn main() -> ! { let _p = embassy_nrf::init(Default::default()); - // High-priority executor: SWI1_EGU1, priority level 6 - interrupt::SWI1_EGU1.set_priority(Priority::P6); - let spawner = EXECUTOR_HIGH.start(interrupt::SWI1_EGU1); + // High-priority executor: EGU1_SWI1, priority level 6 + interrupt::EGU1_SWI1.set_priority(Priority::P6); + let spawner = EXECUTOR_HIGH.start(interrupt::EGU1_SWI1); unwrap!(spawner.spawn(run_high())); - // Medium-priority executor: SWI0_EGU0, priority level 7 - interrupt::SWI0_EGU0.set_priority(Priority::P7); - let spawner = EXECUTOR_MED.start(interrupt::SWI0_EGU0); + // Medium-priority executor: EGU0_SWI0, priority level 7 + interrupt::EGU0_SWI0.set_priority(Priority::P7); + let spawner = EXECUTOR_MED.start(interrupt::EGU0_SWI0); unwrap!(spawner.spawn(run_med())); // Low priority executor: runs in thread mode, using WFE/SEV diff --git a/examples/nrf52840/src/bin/spis.rs b/examples/nrf52840/src/bin/spis.rs index 613cd37ab..4f28da07e 100644 --- a/examples/nrf52840/src/bin/spis.rs +++ b/examples/nrf52840/src/bin/spis.rs @@ -8,7 +8,7 @@ use embassy_nrf::{bind_interrupts, peripherals, spis}; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { - SPIM2_SPIS2_SPI2 => spis::InterruptHandler; + SPI2 => spis::InterruptHandler; }); #[embassy_executor::main] diff --git a/examples/nrf52840/src/bin/twim.rs b/examples/nrf52840/src/bin/twim.rs index a9a0765e8..ceaafd784 100644 --- a/examples/nrf52840/src/bin/twim.rs +++ b/examples/nrf52840/src/bin/twim.rs @@ -14,7 +14,7 @@ use {defmt_rtt as _, panic_probe as _}; const ADDRESS: u8 = 0x50; bind_interrupts!(struct Irqs { - SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0 => twim::InterruptHandler; + TWISPI0 => twim::InterruptHandler; }); #[embassy_executor::main] diff --git a/examples/nrf52840/src/bin/twim_lowpower.rs b/examples/nrf52840/src/bin/twim_lowpower.rs index c743614b8..e2efbdd8d 100644 --- a/examples/nrf52840/src/bin/twim_lowpower.rs +++ b/examples/nrf52840/src/bin/twim_lowpower.rs @@ -19,7 +19,7 @@ use {defmt_rtt as _, panic_probe as _}; const ADDRESS: u8 = 0x50; bind_interrupts!(struct Irqs { - SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0 => twim::InterruptHandler; + TWISPI0 => twim::InterruptHandler; }); #[embassy_executor::main] diff --git a/examples/nrf52840/src/bin/twis.rs b/examples/nrf52840/src/bin/twis.rs index 88bd4cceb..856b34140 100644 --- a/examples/nrf52840/src/bin/twis.rs +++ b/examples/nrf52840/src/bin/twis.rs @@ -10,7 +10,7 @@ use embassy_nrf::{bind_interrupts, peripherals}; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { - SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0 => twis::InterruptHandler; + TWISPI0 => twis::InterruptHandler; }); #[embassy_executor::main] diff --git a/examples/nrf52840/src/bin/uart.rs b/examples/nrf52840/src/bin/uart.rs index accaccea1..23154672f 100644 --- a/examples/nrf52840/src/bin/uart.rs +++ b/examples/nrf52840/src/bin/uart.rs @@ -7,7 +7,7 @@ use embassy_nrf::{bind_interrupts, peripherals, uarte}; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { - UARTE0_UART0 => uarte::InterruptHandler; + UARTE0 => uarte::InterruptHandler; }); #[embassy_executor::main] diff --git a/examples/nrf52840/src/bin/uart_idle.rs b/examples/nrf52840/src/bin/uart_idle.rs index fa93bcf21..a42e84fa4 100644 --- a/examples/nrf52840/src/bin/uart_idle.rs +++ b/examples/nrf52840/src/bin/uart_idle.rs @@ -8,7 +8,7 @@ use embassy_nrf::{bind_interrupts, uarte}; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { - UARTE0_UART0 => uarte::InterruptHandler; + UARTE0 => uarte::InterruptHandler; }); #[embassy_executor::main] diff --git a/examples/nrf52840/src/bin/uart_split.rs b/examples/nrf52840/src/bin/uart_split.rs index c7510a9a8..94af4be86 100644 --- a/examples/nrf52840/src/bin/uart_split.rs +++ b/examples/nrf52840/src/bin/uart_split.rs @@ -13,7 +13,7 @@ use {defmt_rtt as _, panic_probe as _}; static CHANNEL: Channel = Channel::new(); bind_interrupts!(struct Irqs { - UARTE0_UART0 => uarte::InterruptHandler; + UARTE0 => uarte::InterruptHandler; }); #[embassy_executor::main] diff --git a/examples/nrf52840/src/bin/usb_ethernet.rs b/examples/nrf52840/src/bin/usb_ethernet.rs index 82364ded8..88314b749 100644 --- a/examples/nrf52840/src/bin/usb_ethernet.rs +++ b/examples/nrf52840/src/bin/usb_ethernet.rs @@ -18,7 +18,7 @@ use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { USBD => usb::InterruptHandler; - POWER_CLOCK => usb::vbus_detect::InterruptHandler; + CLOCK_POWER => usb::vbus_detect::InterruptHandler; RNG => rng::InterruptHandler; }); diff --git a/examples/nrf52840/src/bin/usb_hid_keyboard.rs b/examples/nrf52840/src/bin/usb_hid_keyboard.rs index 3b752fd16..5a9dc90a2 100644 --- a/examples/nrf52840/src/bin/usb_hid_keyboard.rs +++ b/examples/nrf52840/src/bin/usb_hid_keyboard.rs @@ -21,7 +21,7 @@ use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { USBD => usb::InterruptHandler; - POWER_CLOCK => usb::vbus_detect::InterruptHandler; + CLOCK_POWER => usb::vbus_detect::InterruptHandler; }); static SUSPENDED: AtomicBool = AtomicBool::new(false); diff --git a/examples/nrf52840/src/bin/usb_hid_mouse.rs b/examples/nrf52840/src/bin/usb_hid_mouse.rs index 3f13a014e..80cda70e3 100644 --- a/examples/nrf52840/src/bin/usb_hid_mouse.rs +++ b/examples/nrf52840/src/bin/usb_hid_mouse.rs @@ -16,7 +16,7 @@ use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { USBD => usb::InterruptHandler; - POWER_CLOCK => usb::vbus_detect::InterruptHandler; + CLOCK_POWER => usb::vbus_detect::InterruptHandler; }); #[embassy_executor::main] diff --git a/examples/nrf52840/src/bin/usb_serial.rs b/examples/nrf52840/src/bin/usb_serial.rs index 30fe103ad..a534046d9 100644 --- a/examples/nrf52840/src/bin/usb_serial.rs +++ b/examples/nrf52840/src/bin/usb_serial.rs @@ -14,7 +14,7 @@ use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { USBD => usb::InterruptHandler; - POWER_CLOCK => usb::vbus_detect::InterruptHandler; + CLOCK_POWER => usb::vbus_detect::InterruptHandler; }); #[embassy_executor::main] diff --git a/examples/nrf52840/src/bin/usb_serial_multitask.rs b/examples/nrf52840/src/bin/usb_serial_multitask.rs index 05b5f0ec9..32fc5e094 100644 --- a/examples/nrf52840/src/bin/usb_serial_multitask.rs +++ b/examples/nrf52840/src/bin/usb_serial_multitask.rs @@ -14,7 +14,7 @@ use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { USBD => usb::InterruptHandler; - POWER_CLOCK => usb::vbus_detect::InterruptHandler; + CLOCK_POWER => usb::vbus_detect::InterruptHandler; }); type MyDriver = Driver<'static, peripherals::USBD, HardwareVbusDetect>; diff --git a/examples/nrf52840/src/bin/usb_serial_winusb.rs b/examples/nrf52840/src/bin/usb_serial_winusb.rs index 7c07158e0..0352f9c66 100644 --- a/examples/nrf52840/src/bin/usb_serial_winusb.rs +++ b/examples/nrf52840/src/bin/usb_serial_winusb.rs @@ -16,7 +16,7 @@ use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { USBD => usb::InterruptHandler; - POWER_CLOCK => usb::vbus_detect::InterruptHandler; + CLOCK_POWER => usb::vbus_detect::InterruptHandler; }); // This is a randomly generated GUID to allow clients on Windows to find our device diff --git a/examples/nrf9151/ns/src/bin/uart.rs b/examples/nrf9151/ns/src/bin/uart.rs index 2220dccfb..234ff35f2 100644 --- a/examples/nrf9151/ns/src/bin/uart.rs +++ b/examples/nrf9151/ns/src/bin/uart.rs @@ -7,7 +7,7 @@ use embassy_nrf::{bind_interrupts, peripherals, uarte}; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { - SPIM0_SPIS0_TWIM0_TWIS0_UARTE0 => uarte::InterruptHandler; + SERIAL0 => uarte::InterruptHandler; }); #[embassy_executor::main] diff --git a/examples/nrf9160/src/bin/modem_tcp_client.rs b/examples/nrf9160/src/bin/modem_tcp_client.rs index 067ec4276..35900cdd8 100644 --- a/examples/nrf9160/src/bin/modem_tcp_client.rs +++ b/examples/nrf9160/src/bin/modem_tcp_client.rs @@ -28,7 +28,7 @@ fn IPC() { } bind_interrupts!(struct Irqs { - UARTE0_SPIM0_SPIS0_TWIM0_TWIS0 => buffered_uarte::InterruptHandler; + SERIAL0 => buffered_uarte::InterruptHandler; }); #[embassy_executor::task] diff --git a/tests/nrf/src/common.rs b/tests/nrf/src/common.rs index c588dabf5..ebd332d15 100644 --- a/tests/nrf/src/common.rs +++ b/tests/nrf/src/common.rs @@ -55,9 +55,9 @@ define_peris!( PIN_X = P0_13, UART0 = UARTE0, SPIM0 = TWISPI0, - @irq UART0 = {UARTE0_UART0 => uarte::InterruptHandler;}, - @irq UART0_BUFFERED = {UARTE0_UART0 => buffered_uarte::InterruptHandler;}, - @irq SPIM0 = {SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0 => spim::InterruptHandler;}, + @irq UART0 = {UARTE0 => uarte::InterruptHandler;}, + @irq UART0_BUFFERED = {UARTE0 => buffered_uarte::InterruptHandler;}, + @irq SPIM0 = {TWISPI0 => spim::InterruptHandler;}, ); #[cfg(feature = "nrf52833")] @@ -67,11 +67,11 @@ define_peris!( UART0 = UARTE0, UART1 = UARTE1, SPIM0 = TWISPI0, - @irq UART0 = {UARTE0_UART0 => uarte::InterruptHandler;}, + @irq UART0 = {UARTE0 => uarte::InterruptHandler;}, @irq UART1 = {UARTE1 => uarte::InterruptHandler;}, - @irq UART0_BUFFERED = {UARTE0_UART0 => buffered_uarte::InterruptHandler;}, + @irq UART0_BUFFERED = {UARTE0 => buffered_uarte::InterruptHandler;}, @irq UART1_BUFFERED = {UARTE1 => buffered_uarte::InterruptHandler;}, - @irq SPIM0 = {SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0 => spim::InterruptHandler;}, + @irq SPIM0 = {TWISPI0 => spim::InterruptHandler;}, ); #[cfg(feature = "nrf52840")] @@ -81,11 +81,11 @@ define_peris!( UART0 = UARTE0, UART1 = UARTE1, SPIM0 = TWISPI0, - @irq UART0 = {UARTE0_UART0 => uarte::InterruptHandler;}, + @irq UART0 = {UARTE0 => uarte::InterruptHandler;}, @irq UART1 = {UARTE1 => uarte::InterruptHandler;}, - @irq UART0_BUFFERED = {UARTE0_UART0 => buffered_uarte::InterruptHandler;}, + @irq UART0_BUFFERED = {UARTE0 => buffered_uarte::InterruptHandler;}, @irq UART1_BUFFERED = {UARTE1 => buffered_uarte::InterruptHandler;}, - @irq SPIM0 = {SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0 => spim::InterruptHandler;}, + @irq SPIM0 = {TWISPI0 => spim::InterruptHandler;}, ); #[cfg(feature = "nrf5340")] @@ -109,9 +109,9 @@ define_peris!( UART0 = SERIAL0, UART1 = SERIAL1, SPIM0 = SERIAL0, - @irq UART0 = {UARTE0_SPIM0_SPIS0_TWIM0_TWIS0 => uarte::InterruptHandler;}, - @irq UART1 = {UARTE1_SPIM1_SPIS1_TWIM1_TWIS1 => uarte::InterruptHandler;}, - @irq UART0_BUFFERED = {UARTE0_SPIM0_SPIS0_TWIM0_TWIS0 => buffered_uarte::InterruptHandler;}, - @irq UART1_BUFFERED = {UARTE1_SPIM1_SPIS1_TWIM1_TWIS1 => buffered_uarte::InterruptHandler;}, - @irq SPIM0 = {UARTE0_SPIM0_SPIS0_TWIM0_TWIS0 => spim::InterruptHandler;}, + @irq UART0 = {SERIAL0 => uarte::InterruptHandler;}, + @irq UART1 = {SERIAL1 => uarte::InterruptHandler;}, + @irq UART0_BUFFERED = {SERIAL0 => buffered_uarte::InterruptHandler;}, + @irq UART1_BUFFERED = {SERIAL1 => buffered_uarte::InterruptHandler;}, + @irq SPIM0 = {SERIAL0 => spim::InterruptHandler;}, ); From d592875ca6d4df2b126e67603d32ed7f3e71910b Mon Sep 17 00:00:00 2001 From: elagil Date: Sat, 16 Nov 2024 15:02:32 +0100 Subject: [PATCH 0355/1217] fix(SAI): disallow start without initial write --- embassy-stm32/src/dma/dma_bdma.rs | 3 --- embassy-stm32/src/sai/mod.rs | 27 ++++++++++++++------------- examples/stm32h7/src/bin/sai.rs | 1 - 3 files changed, 14 insertions(+), 17 deletions(-) diff --git a/embassy-stm32/src/dma/dma_bdma.rs b/embassy-stm32/src/dma/dma_bdma.rs index cdc603e2c..08c7a5508 100644 --- a/embassy-stm32/src/dma/dma_bdma.rs +++ b/embassy-stm32/src/dma/dma_bdma.rs @@ -828,7 +828,6 @@ impl<'a, W: Word> ReadableRingBuffer<'a, W> { /// You must call this after creating it for it to work. pub fn start(&mut self) { self.channel.start(); - self.clear(); } /// Clear all data in the ring buffer. @@ -981,7 +980,6 @@ impl<'a, W: Word> WritableRingBuffer<'a, W> { /// You must call this after creating it for it to work. pub fn start(&mut self) { self.channel.start(); - self.clear(); } /// Clear all data in the ring buffer. @@ -991,7 +989,6 @@ impl<'a, W: Word> WritableRingBuffer<'a, W> { /// Write elements directly to the raw buffer. /// This can be used to fill the buffer before starting the DMA transfer. - #[allow(dead_code)] pub fn write_immediate(&mut self, buf: &[W]) -> Result<(usize, usize), Error> { self.ringbuf.write_immediate(buf) } diff --git a/embassy-stm32/src/sai/mod.rs b/embassy-stm32/src/sai/mod.rs index 62b44b77f..057b21980 100644 --- a/embassy-stm32/src/sai/mod.rs +++ b/embassy-stm32/src/sai/mod.rs @@ -958,13 +958,14 @@ impl<'d, T: Instance, W: word::Word> Sai<'d, T, W> { } /// Start the SAI driver. - pub fn start(&mut self) { + /// + /// Only receivers can be started. Transmitters are started on the first writing operation. + pub fn start(&mut self) -> Result<(), Error> { match self.ring_buffer { - RingBuffer::Writable(ref mut rb) => { - rb.start(); - } + RingBuffer::Writable(_) => Err(Error::NotAReceiver), RingBuffer::Readable(ref mut rb) => { rb.start(); + Ok(()) } } } @@ -981,14 +982,6 @@ impl<'d, T: Instance, W: word::Word> Sai<'d, T, W> { rcc::enable_and_reset::(); } - /// Flush. - pub fn flush(&mut self) { - let ch = T::REGS.ch(self.sub_block as usize); - ch.cr1().modify(|w| w.set_saien(false)); - ch.cr2().modify(|w| w.set_fflush(true)); - ch.cr1().modify(|w| w.set_saien(true)); - } - /// Enable or disable mute. pub fn set_mute(&mut self, value: bool) { let ch = T::REGS.ch(self.sub_block as usize); @@ -1012,6 +1005,9 @@ impl<'d, T: Instance, W: word::Word> Sai<'d, T, W> { /// Write data to the SAI ringbuffer. /// + /// The first write starts the DMA after filling the ring buffer with the provided data. + /// This ensures that the DMA does not run before data is available in the ring buffer. + /// /// This appends the data to the buffer and returns immediately. The /// data will be transmitted in the background. /// @@ -1019,7 +1015,12 @@ impl<'d, T: Instance, W: word::Word> Sai<'d, T, W> { pub async fn write(&mut self, data: &[W]) -> Result<(), Error> { match &mut self.ring_buffer { RingBuffer::Writable(buffer) => { - buffer.write_exact(data).await?; + if buffer.is_running() { + buffer.write_exact(data).await?; + } else { + buffer.write_immediate(data)?; + buffer.start(); + } Ok(()) } _ => return Err(Error::NotATransmitter), diff --git a/examples/stm32h7/src/bin/sai.rs b/examples/stm32h7/src/bin/sai.rs index 04d14bd6b..0594c838a 100644 --- a/examples/stm32h7/src/bin/sai.rs +++ b/examples/stm32h7/src/bin/sai.rs @@ -108,7 +108,6 @@ async fn main(_spawner: Spawner) { let mut sai_receiver = Sai::new_synchronous(sub_block_rx, p.PE3, p.DMA1_CH1, rx_buffer, rx_config); sai_receiver.start(); - sai_transmitter.start(); let mut buf = [0u32; HALF_DMA_BUFFER_LENGTH]; From f2a46e2ac3d8764a205cdde20a1e2af3cbd7ec1e Mon Sep 17 00:00:00 2001 From: elagil Date: Sat, 16 Nov 2024 15:09:47 +0100 Subject: [PATCH 0356/1217] fix: unwrap sai receiver `start()` --- examples/stm32h7/src/bin/sai.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/stm32h7/src/bin/sai.rs b/examples/stm32h7/src/bin/sai.rs index 0594c838a..95ffe257a 100644 --- a/examples/stm32h7/src/bin/sai.rs +++ b/examples/stm32h7/src/bin/sai.rs @@ -107,7 +107,7 @@ async fn main(_spawner: Spawner) { let mut sai_receiver = Sai::new_synchronous(sub_block_rx, p.PE3, p.DMA1_CH1, rx_buffer, rx_config); - sai_receiver.start(); + sai_receiver.start().unwrap(); let mut buf = [0u32; HALF_DMA_BUFFER_LENGTH]; From 69cb30ebf3772a20612f53202ab4b8e880b0583c Mon Sep 17 00:00:00 2001 From: Ugljesa Jovanovic Date: Sat, 16 Nov 2024 22:22:47 +0100 Subject: [PATCH 0357/1217] Add OTP write --- embassy-rp/src/otp.rs | 71 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 69 insertions(+), 2 deletions(-) diff --git a/embassy-rp/src/otp.rs b/embassy-rp/src/otp.rs index cdaf5bded..6091f71b2 100644 --- a/embassy-rp/src/otp.rs +++ b/embassy-rp/src/otp.rs @@ -3,15 +3,24 @@ // Credit: taken from `rp-hal` (also licensed Apache+MIT) // https://github.com/rp-rs/rp-hal/blob/main/rp235x-hal/src/rom_data.rs -/// The ways in which we can fail to read OTP +use crate::rom_data::otp_access; + +/// The ways in which we can fail to access OTP #[derive(Debug, Clone)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum Error { /// The user passed an invalid index to a function. InvalidIndex, /// The hardware refused to let us read this word, probably due to - /// read lock set earlier in the boot process. + /// read or write lock set earlier in the boot process. InvalidPermissions, + /// Modification is impossible based on current state; e.g. + /// attempted to clear an OTP bit. + UnsupportedModification, + /// Value being written is bigger than 24 bits allowed for raw writes. + Overflow, + /// An unexpected failure that contains the exact return code + UnexpectedFailure(i32), } /// OTP read address, using automatic Error Correction. @@ -34,6 +43,9 @@ pub const NUM_ROWS_PER_PAGE: usize = 64; /// How many rows in OTP (post error-correction) pub const NUM_ROWS: usize = NUM_PAGES * NUM_ROWS_PER_PAGE; +/// 24bit mask for raw writes +pub const RAW_WRITE_BIT_MASK: u32 = 0x00FF_FFFF; + /// Read one ECC protected word from the OTP pub fn read_ecc_word(row: usize) -> Result { if row >= NUM_ROWS { @@ -72,6 +84,61 @@ pub fn read_raw_word(row: usize) -> Result { Ok(value) } } +/// Write one raw word to the OTP +/// +/// 24 bit value will be written to the OTP +pub fn write_raw_word(row: usize, data: u32) -> Result<(), Error> { + if data > RAW_WRITE_BIT_MASK { + return Err(Error::Overflow); + } + if row >= NUM_ROWS { + return Err(Error::InvalidIndex); + } + let row_with_write_bit = row | 0x00010000; + // # Safety + // + // We checked this row was in range already. + let result = unsafe { otp_access(data.to_le_bytes().as_mut_ptr(), 4, row_with_write_bit as u32) }; + if result == 0 { + Ok(()) + } else { + // 5.4.3. API Function Return Codes + let error = match result { + -4 => Error::InvalidPermissions, + -18 => Error::UnsupportedModification, + _ => Error::UnexpectedFailure(result), + }; + Err(error) + } +} + +/// Write one raw word to the OTP with ECC +/// +/// 16 bit value will be written + ECC +pub fn write_ecc_word(row: usize, data: u16) -> Result<(), Error> { + if row >= NUM_ROWS { + return Err(Error::InvalidIndex); + } + let row_with_write_and_ecc_bit = row | 0x00030000; + + // # Safety + // + // We checked this row was in range already. + + let result = unsafe { otp_access(data.to_le_bytes().as_mut_ptr(), 2, row_with_write_and_ecc_bit as u32) }; + if result == 0 { + Ok(()) + } else { + // 5.4.3. API Function Return Codes + // 5.4.3. API Function Return Codes + let error = match result { + -4 => Error::InvalidPermissions, + -18 => Error::UnsupportedModification, + _ => Error::UnexpectedFailure(result), + }; + Err(error) + } +} /// Get the random 64bit chipid from rows 0x0-0x3. pub fn get_chipid() -> Result { From a8d7a5eb1e2038d0961e5dda8b1d5d04826fe1fd Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sun, 17 Nov 2024 14:32:35 +0100 Subject: [PATCH 0358/1217] nrf: add nrf54l base: gpio and time driver. --- ci.sh | 3 + embassy-net-nrf91/Cargo.toml | 2 +- embassy-nrf/Cargo.toml | 12 +- embassy-nrf/src/chips/nrf54l15_app.rs | 346 ++++++++++++++++++++++++++ embassy-nrf/src/gpio.rs | 131 +++++++++- embassy-nrf/src/lib.rs | 84 +++++-- embassy-nrf/src/pwm.rs | 16 +- embassy-nrf/src/spim.rs | 4 +- embassy-nrf/src/spis.rs | 2 +- embassy-nrf/src/time_driver.rs | 25 +- examples/nrf54l15/.cargo/config.toml | 9 + examples/nrf54l15/Cargo.toml | 20 ++ examples/nrf54l15/build.rs | 35 +++ examples/nrf54l15/memory.x | 5 + examples/nrf54l15/src/bin/blinky.rs | 23 ++ 15 files changed, 668 insertions(+), 49 deletions(-) create mode 100644 embassy-nrf/src/chips/nrf54l15_app.rs create mode 100644 examples/nrf54l15/.cargo/config.toml create mode 100644 examples/nrf54l15/Cargo.toml create mode 100644 examples/nrf54l15/build.rs create mode 100644 examples/nrf54l15/memory.x create mode 100644 examples/nrf54l15/src/bin/blinky.rs diff --git a/ci.sh b/ci.sh index 9f7a7a037..307e268c4 100755 --- a/ci.sh +++ b/ci.sh @@ -70,6 +70,8 @@ cargo batch \ --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features nrf5340-app-s,gpiote,time,time-driver-rtc1 \ --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features nrf5340-app-ns,gpiote,time,time-driver-rtc1 \ --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features nrf5340-net,gpiote,time,time-driver-rtc1 \ + --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features nrf54l15-app-s,gpiote,time,time-driver-rtc1 \ + --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features nrf54l15-app-ns,gpiote,time,time-driver-rtc1 \ --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52840,gpiote,time \ --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52840,gpiote,time-driver-rtc1 \ --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52840,gpiote,time,time-driver-rtc1 \ @@ -197,6 +199,7 @@ cargo batch \ --- build --release --manifest-path examples/nrf52810/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/nrf52810 \ --- build --release --manifest-path examples/nrf52840/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/nrf52840 \ --- build --release --manifest-path examples/nrf5340/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/nrf5340 \ + --- build --release --manifest-path examples/nrf54l15/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/nrf54l15 \ --- build --release --manifest-path examples/nrf9160/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/nrf9160 \ --- build --release --manifest-path examples/nrf9151/s/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/nrf9151/s \ --- build --release --manifest-path examples/nrf9151/ns/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/nrf9151/ns \ diff --git a/embassy-net-nrf91/Cargo.toml b/embassy-net-nrf91/Cargo.toml index 77a1c4cb5..bc31f93f4 100644 --- a/embassy-net-nrf91/Cargo.toml +++ b/embassy-net-nrf91/Cargo.toml @@ -17,7 +17,7 @@ log = [ "dep:log" ] defmt = { version = "0.3", optional = true } log = { version = "0.4.14", optional = true } -nrf-pac = { git = "https://github.com/embassy-rs/nrf-pac", rev = "12e2461859acb0bfea9b2ef5cd73f1283c139ac0" } +nrf-pac = { git = "https://github.com/embassy-rs/nrf-pac", rev = "52e3a757f06035c94291bfc42b0c03f71e4d677e" } cortex-m = "0.7.7" embassy-time = { version = "0.3.1", path = "../embassy-time" } diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml index 7b20d2643..ed9aba4e7 100644 --- a/embassy-nrf/Cargo.toml +++ b/embassy-nrf/Cargo.toml @@ -83,6 +83,11 @@ nrf5340-app-s = ["_nrf5340-app", "_s"] nrf5340-app-ns = ["_nrf5340-app", "_ns"] ## nRF5340 network core nrf5340-net = ["_nrf5340-net"] +## nRF54L15 application core in Secure mode +nrf54l15-app-s = ["_nrf54l15-app", "_s"] +## nRF54L15 application core in Non-Secure mode +nrf54l15-app-ns = ["_nrf54l15-app", "_ns"] + ## nRF9160 in Secure mode nrf9160-s = ["_nrf9160", "_s", "_nrf91"] ## nRF9160 in Non-Secure mode @@ -103,6 +108,10 @@ nrf9161-ns = ["nrf9120-ns"] _nrf5340-app = ["_nrf5340", "nrf-pac/nrf5340-app"] _nrf5340-net = ["_nrf5340", "nrf-pac/nrf5340-net"] _nrf5340 = ["_gpio-p1", "_dppi"] +_nrf54l15-app = ["_nrf54l15", "nrf-pac/nrf54l15-app"] +_nrf54l15 = ["_nrf54l", "_gpio-p1", "_gpio-p2"] +_nrf54l = ["_dppi"] + _nrf9160 = ["nrf-pac/nrf9160", "_dppi"] _nrf9120 = ["nrf-pac/nrf9120", "_dppi"] _nrf52 = ["_ppi"] @@ -118,6 +127,7 @@ _ns = [] _ppi = [] _dppi = [] _gpio-p1 = [] +_gpio-p2 = [] # Errata workarounds _nrf52832_anomaly_109 = [] @@ -136,7 +146,7 @@ embedded-hal-async = { version = "1.0" } embedded-io = { version = "0.6.0" } embedded-io-async = { version = "0.6.1" } -nrf-pac = { git = "https://github.com/embassy-rs/nrf-pac", rev = "12e2461859acb0bfea9b2ef5cd73f1283c139ac0" } +nrf-pac = { git = "https://github.com/embassy-rs/nrf-pac", rev = "52e3a757f06035c94291bfc42b0c03f71e4d677e" } defmt = { version = "0.3", optional = true } bitflags = "2.4.2" diff --git a/embassy-nrf/src/chips/nrf54l15_app.rs b/embassy-nrf/src/chips/nrf54l15_app.rs new file mode 100644 index 000000000..b133eb565 --- /dev/null +++ b/embassy-nrf/src/chips/nrf54l15_app.rs @@ -0,0 +1,346 @@ +/// Peripheral Access Crate +#[allow(unused_imports)] +#[rustfmt::skip] +pub mod pac { + pub use nrf_pac::*; + + #[cfg(feature = "_ns")] + #[doc(no_inline)] + pub use nrf_pac::{ + FICR_NS as FICR, + DPPIC00_NS as DPPIC00, + PPIB00_NS as PPIB00, + PPIB01_NS as PPIB01, + AAR00_NS as AAR00, + CCM00_NS as CCM00, + ECB00_NS as ECB00, + SPIM00_NS as SPIM00, + SPIS00_NS as SPIS00, + UARTE00_NS as UARTE00, + VPR00_NS as VPR00, + P2_NS as P2, + CTRLAP_NS as CTRLAP, + TAD_NS as TAD, + TIMER00_NS as TIMER00, + DPPIC10_NS as DPPIC10, + PPIB10_NS as PPIB10, + PPIB11_NS as PPIB11, + TIMER10_NS as TIMER10, + RTC10_NS as RTC10, + EGU10_NS as EGU10, + RADIO_NS as RADIO, + DPPIC20_NS as DPPIC20, + PPIB20_NS as PPIB20, + PPIB21_NS as PPIB21, + PPIB22_NS as PPIB22, + SPIM20_NS as SPIM20, + SPIS20_NS as SPIS20, + TWIM20_NS as TWIM20, + TWIS20_NS as TWIS20, + UARTE20_NS as UARTE20, + SPIM21_NS as SPIM21, + SPIS21_NS as SPIS21, + TWIM21_NS as TWIM21, + TWIS21_NS as TWIS21, + UARTE21_NS as UARTE21, + SPIM22_NS as SPIM22, + SPIS22_NS as SPIS22, + TWIM22_NS as TWIM22, + TWIS22_NS as TWIS22, + UARTE22_NS as UARTE22, + EGU20_NS as EGU20, + TIMER20_NS as TIMER20, + TIMER21_NS as TIMER21, + TIMER22_NS as TIMER22, + TIMER23_NS as TIMER23, + TIMER24_NS as TIMER24, + MEMCONF_NS as MEMCONF, + PDM20_NS as PDM20, + PDM21_NS as PDM21, + PWM20_NS as PWM20, + PWM21_NS as PWM21, + PWM22_NS as PWM22, + SAADC_NS as SAADC, + NFCT_NS as NFCT, + TEMP_NS as TEMP, + P1_NS as P1, + GPIOTE20_NS as GPIOTE20, + I2S20_NS as I2S20, + QDEC20_NS as QDEC20, + QDEC21_NS as QDEC21, + GRTC_NS as GRTC, + DPPIC30_NS as DPPIC30, + PPIB30_NS as PPIB30, + SPIM30_NS as SPIM30, + SPIS30_NS as SPIS30, + TWIM30_NS as TWIM30, + TWIS30_NS as TWIS30, + UARTE30_NS as UARTE30, + RTC30_NS as RTC30, + COMP_NS as COMP, + LPCOMP_NS as LPCOMP, + WDT31_NS as WDT31, + P0_NS as P0, + GPIOTE30_NS as GPIOTE30, + CLOCK_NS as CLOCK, + POWER_NS as POWER, + RESET_NS as RESET, + OSCILLATORS_NS as OSCILLATORS, + REGULATORS_NS as REGULATORS, + TPIU_NS as TPIU, + ETM_NS as ETM, + }; + + #[cfg(feature = "_s")] + #[doc(no_inline)] + pub use nrf_pac::{ + SICR_S as SICR, + ICACHEDATA_S as ICACHEDATA, + ICACHEINFO_S as ICACHEINFO, + SWI00_S as SWI00, + SWI01_S as SWI01, + SWI02_S as SWI02, + SWI03_S as SWI03, + SPU00_S as SPU00, + MPC00_S as MPC00, + DPPIC00_S as DPPIC00, + PPIB00_S as PPIB00, + PPIB01_S as PPIB01, + KMU_S as KMU, + AAR00_S as AAR00, + CCM00_S as CCM00, + ECB00_S as ECB00, + CRACEN_S as CRACEN, + SPIM00_S as SPIM00, + SPIS00_S as SPIS00, + UARTE00_S as UARTE00, + GLITCHDET_S as GLITCHDET, + RRAMC_S as RRAMC, + VPR00_S as VPR00, + P2_S as P2, + CTRLAP_S as CTRLAP, + TAD_S as TAD, + TIMER00_S as TIMER00, + SPU10_S as SPU10, + DPPIC10_S as DPPIC10, + PPIB10_S as PPIB10, + PPIB11_S as PPIB11, + TIMER10_S as TIMER10, + RTC10_S as RTC10, + EGU10_S as EGU10, + RADIO_S as RADIO, + SPU20_S as SPU20, + DPPIC20_S as DPPIC20, + PPIB20_S as PPIB20, + PPIB21_S as PPIB21, + PPIB22_S as PPIB22, + SPIM20_S as SPIM20, + SPIS20_S as SPIS20, + TWIM20_S as TWIM20, + TWIS20_S as TWIS20, + UARTE20_S as UARTE20, + SPIM21_S as SPIM21, + SPIS21_S as SPIS21, + TWIM21_S as TWIM21, + TWIS21_S as TWIS21, + UARTE21_S as UARTE21, + SPIM22_S as SPIM22, + SPIS22_S as SPIS22, + TWIM22_S as TWIM22, + TWIS22_S as TWIS22, + UARTE22_S as UARTE22, + EGU20_S as EGU20, + TIMER20_S as TIMER20, + TIMER21_S as TIMER21, + TIMER22_S as TIMER22, + TIMER23_S as TIMER23, + TIMER24_S as TIMER24, + MEMCONF_S as MEMCONF, + PDM20_S as PDM20, + PDM21_S as PDM21, + PWM20_S as PWM20, + PWM21_S as PWM21, + PWM22_S as PWM22, + SAADC_S as SAADC, + NFCT_S as NFCT, + TEMP_S as TEMP, + P1_S as P1, + GPIOTE20_S as GPIOTE20, + TAMPC_S as TAMPC, + I2S20_S as I2S20, + QDEC20_S as QDEC20, + QDEC21_S as QDEC21, + GRTC_S as GRTC, + SPU30_S as SPU30, + DPPIC30_S as DPPIC30, + PPIB30_S as PPIB30, + SPIM30_S as SPIM30, + SPIS30_S as SPIS30, + TWIM30_S as TWIM30, + TWIS30_S as TWIS30, + UARTE30_S as UARTE30, + RTC30_S as RTC30, + COMP_S as COMP, + LPCOMP_S as LPCOMP, + WDT30_S as WDT30, + WDT31_S as WDT31, + P0_S as P0, + GPIOTE30_S as GPIOTE30, + CLOCK_S as CLOCK, + POWER_S as POWER, + RESET_S as RESET, + OSCILLATORS_S as OSCILLATORS, + REGULATORS_S as REGULATORS, + CRACENCORE_S as CRACENCORE, + CPUC_S as CPUC, + ICACHE_S as ICACHE, + }; +} + +/// The maximum buffer size that the EasyDMA can send/recv in one operation. +pub const EASY_DMA_SIZE: usize = (1 << 16) - 1; +//pub const FORCE_COPY_BUFFER_SIZE: usize = 1024; + +//pub const FLASH_SIZE: usize = 1024 * 1024; + +embassy_hal_internal::peripherals! { + // GPIO port 0 + P0_00, + P0_01, + P0_02, + P0_03, + P0_04, + P0_05, + P0_06, + + // GPIO port 1 + P1_00, + P1_01, + P1_02, + P1_03, + P1_04, + P1_05, + P1_06, + P1_07, + P1_08, + P1_09, + P1_10, + P1_11, + P1_12, + P1_13, + P1_14, + P1_15, + P1_16, + + + // GPIO port 2 + P2_00, + P2_01, + P2_02, + P2_03, + P2_04, + P2_05, + P2_06, + P2_07, + P2_08, + P2_09, + P2_10, +} + +impl_pin!(P0_00, 0, 0); +impl_pin!(P0_01, 0, 1); +impl_pin!(P0_02, 0, 2); +impl_pin!(P0_03, 0, 3); +impl_pin!(P0_04, 0, 4); +impl_pin!(P0_05, 0, 5); +impl_pin!(P0_06, 0, 6); + +impl_pin!(P1_00, 1, 0); +impl_pin!(P1_01, 1, 1); +impl_pin!(P1_02, 1, 2); +impl_pin!(P1_03, 1, 3); +impl_pin!(P1_04, 1, 4); +impl_pin!(P1_05, 1, 5); +impl_pin!(P1_06, 1, 6); +impl_pin!(P1_07, 1, 7); +impl_pin!(P1_08, 1, 8); +impl_pin!(P1_09, 1, 9); +impl_pin!(P1_10, 1, 10); +impl_pin!(P1_11, 1, 11); +impl_pin!(P1_12, 1, 12); +impl_pin!(P1_13, 1, 13); +impl_pin!(P1_14, 1, 14); +impl_pin!(P1_15, 1, 15); +impl_pin!(P1_16, 1, 16); + +impl_pin!(P2_00, 2, 0); +impl_pin!(P2_01, 2, 1); +impl_pin!(P2_02, 2, 2); +impl_pin!(P2_03, 2, 3); +impl_pin!(P2_04, 2, 4); +impl_pin!(P2_05, 2, 5); +impl_pin!(P2_06, 2, 6); +impl_pin!(P2_07, 2, 7); +impl_pin!(P2_08, 2, 8); +impl_pin!(P2_09, 2, 9); +impl_pin!(P2_10, 2, 10); + +embassy_hal_internal::interrupt_mod!( + SWI00, + SWI01, + SWI02, + SWI03, + SPU00, + MPC00, + AAR00_CCM00, + ECB00, + CRACEN, + SERIAL00, + RRAMC, + VPR00, + CTRLAP, + TIMER00, + SPU10, + TIMER10, + RTC10, + EGU10, + RADIO_0, + RADIO_1, + SPU20, + SERIAL20, + SERIAL21, + SERIAL22, + EGU20, + TIMER20, + TIMER21, + TIMER22, + TIMER23, + TIMER24, + PDM20, + PDM21, + PWM20, + PWM21, + PWM22, + SAADC, + NFCT, + TEMP, + GPIOTE20_0, + GPIOTE20_1, + TAMPC, + I2S20, + QDEC20, + QDEC21, + GRTC_0, + GRTC_1, + GRTC_2, + GRTC_3, + SPU30, + SERIAL30, + RTC30, + COMP_LPCOMP, + WDT30, + WDT31, + GPIOTE30_0, + GPIOTE30_1, + CLOCK_POWER, +); diff --git a/embassy-nrf/src/gpio.rs b/embassy-nrf/src/gpio.rs index 35b0f2e7b..d271dbcff 100644 --- a/embassy-nrf/src/gpio.rs +++ b/embassy-nrf/src/gpio.rs @@ -23,6 +23,10 @@ pub enum Port { /// Port 1, only available on some MCUs. #[cfg(feature = "_gpio-p1")] Port1, + + /// Port 2, only available on some MCUs. + #[cfg(feature = "_gpio-p2")] + Port2, } /// Pull setting for an input. @@ -99,8 +103,83 @@ impl From for bool { } } +/// Drive strength settings for a given output level. +// These numbers match vals::Drive exactly so hopefully the compiler will unify them. +#[cfg(feature = "_nrf54l")] +#[derive(Clone, Copy, Debug, PartialEq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[repr(u8)] +pub enum LevelDrive { + /// Disconnect (do not drive the output at all) + Disconnect = 2, + /// Standard + Standard = 0, + /// High drive + High = 1, + /// Extra high drive + ExtraHigh = 3, +} + +/// Drive strength settings for an output pin. +/// +/// This is a combination of two drive levels, used when the pin is set +/// low and high respectively. +#[cfg(feature = "_nrf54l")] +#[derive(Clone, Copy, Debug, PartialEq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct OutputDrive { + low: LevelDrive, + high: LevelDrive, +} + +#[cfg(feature = "_nrf54l")] +#[allow(non_upper_case_globals)] +impl OutputDrive { + /// Standard '0', standard '1' + pub const Standard: Self = Self { + low: LevelDrive::Standard, + high: LevelDrive::Standard, + }; + /// High drive '0', standard '1' + pub const HighDrive0Standard1: Self = Self { + low: LevelDrive::High, + high: LevelDrive::Standard, + }; + /// Standard '0', high drive '1' + pub const Standard0HighDrive1: Self = Self { + low: LevelDrive::Standard, + high: LevelDrive::High, + }; + /// High drive '0', high 'drive '1' + pub const HighDrive: Self = Self { + low: LevelDrive::High, + high: LevelDrive::High, + }; + /// Disconnect '0' standard '1' (normally used for wired-or connections) + pub const Disconnect0Standard1: Self = Self { + low: LevelDrive::Disconnect, + high: LevelDrive::Standard, + }; + /// Disconnect '0', high drive '1' (normally used for wired-or connections) + pub const Disconnect0HighDrive1: Self = Self { + low: LevelDrive::Disconnect, + high: LevelDrive::High, + }; + /// Standard '0'. disconnect '1' (also known as "open drain", normally used for wired-and connections) + pub const Standard0Disconnect1: Self = Self { + low: LevelDrive::Standard, + high: LevelDrive::Disconnect, + }; + /// High drive '0', disconnect '1' (also known as "open drain", normally used for wired-and connections) + pub const HighDrive0Disconnect1: Self = Self { + low: LevelDrive::High, + high: LevelDrive::Disconnect, + }; +} + /// Drive strength settings for an output pin. // These numbers match vals::Drive exactly so hopefully the compiler will unify them. +#[cfg(not(feature = "_nrf54l"))] #[derive(Clone, Copy, Debug, PartialEq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[repr(u8)] @@ -185,16 +264,35 @@ impl<'d> Output<'d> { } } -pub(crate) fn convert_drive(drive: OutputDrive) -> vals::Drive { - match drive { - OutputDrive::Standard => vals::Drive::S0S1, - OutputDrive::HighDrive0Standard1 => vals::Drive::H0S1, - OutputDrive::Standard0HighDrive1 => vals::Drive::S0H1, - OutputDrive::HighDrive => vals::Drive::H0H1, - OutputDrive::Disconnect0Standard1 => vals::Drive::D0S1, - OutputDrive::Disconnect0HighDrive1 => vals::Drive::D0H1, - OutputDrive::Standard0Disconnect1 => vals::Drive::S0D1, - OutputDrive::HighDrive0Disconnect1 => vals::Drive::H0D1, +pub(crate) fn convert_drive(w: &mut pac::gpio::regs::PinCnf, drive: OutputDrive) { + #[cfg(not(feature = "_nrf54l"))] + { + let drive = match drive { + OutputDrive::Standard => vals::Drive::S0S1, + OutputDrive::HighDrive0Standard1 => vals::Drive::H0S1, + OutputDrive::Standard0HighDrive1 => vals::Drive::S0H1, + OutputDrive::HighDrive => vals::Drive::H0H1, + OutputDrive::Disconnect0Standard1 => vals::Drive::D0S1, + OutputDrive::Disconnect0HighDrive1 => vals::Drive::D0H1, + OutputDrive::Standard0Disconnect1 => vals::Drive::S0D1, + OutputDrive::HighDrive0Disconnect1 => vals::Drive::H0D1, + }; + w.set_drive(drive); + } + + #[cfg(feature = "_nrf54l")] + { + fn convert(d: LevelDrive) -> vals::Drive { + match d { + LevelDrive::Disconnect => vals::Drive::D, + LevelDrive::Standard => vals::Drive::S, + LevelDrive::High => vals::Drive::H, + LevelDrive::ExtraHigh => vals::Drive::E, + } + } + + w.set_drive0(convert(drive.low)); + w.set_drive0(convert(drive.high)); } } @@ -234,7 +332,7 @@ impl<'d> Flex<'d> { w.set_dir(vals::Dir::INPUT); w.set_input(vals::Input::CONNECT); w.set_pull(convert_pull(pull)); - w.set_drive(vals::Drive::S0S1); + convert_drive(w, OutputDrive::Standard); w.set_sense(vals::Sense::DISABLED); }); } @@ -249,9 +347,10 @@ impl<'d> Flex<'d> { w.set_dir(vals::Dir::OUTPUT); w.set_input(vals::Input::DISCONNECT); w.set_pull(vals::Pull::DISABLED); - w.set_drive(convert_drive(drive)); + convert_drive(w, drive); w.set_sense(vals::Sense::DISABLED); }); + info!("pin_cnf: {:08x}", self.pin.conf().read().0); } /// Put the pin into input + output mode. @@ -269,7 +368,7 @@ impl<'d> Flex<'d> { w.set_dir(vals::Dir::OUTPUT); w.set_input(vals::Input::CONNECT); w.set_pull(convert_pull(pull)); - w.set_drive(convert_drive(drive)); + convert_drive(w, drive); w.set_sense(vals::Sense::DISABLED); }); } @@ -377,6 +476,8 @@ pub(crate) trait SealedPin { 0 => pac::P0, #[cfg(feature = "_gpio-p1")] 1 => pac::P1, + #[cfg(feature = "_gpio-p2")] + 2 => pac::P2, _ => unsafe { unreachable_unchecked() }, } } @@ -415,6 +516,8 @@ pub trait Pin: Peripheral

+ Into + SealedPin + Sized + 'static 0 => Port::Port0, #[cfg(feature = "_gpio-p1")] 1 => Port::Port1, + #[cfg(feature = "_gpio-p2")] + 2 => Port::Port2, _ => unsafe { unreachable_unchecked() }, } } @@ -463,6 +566,7 @@ impl SealedPin for AnyPin { // ==================== #[cfg(not(feature = "_nrf51"))] +#[cfg_attr(feature = "_nrf54l", allow(unused))] // TODO pub(crate) trait PselBits { fn psel_bits(&self) -> pac::shared::regs::Psel; } @@ -479,6 +583,7 @@ impl<'a, P: Pin> PselBits for Option> { } #[cfg(not(feature = "_nrf51"))] +#[cfg_attr(feature = "_nrf54l", allow(unused))] // TODO pub(crate) const DISCONNECTED: Psel = Psel(1 << 31); #[cfg(not(feature = "_nrf51"))] diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index 8167b44f3..33111e1bd 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs @@ -22,6 +22,8 @@ feature = "nrf5340-app-s", feature = "nrf5340-app-ns", feature = "nrf5340-net", + feature = "nrf54l15-app-s", + feature = "nrf54l15-app-ns", feature = "nrf9160-s", feature = "nrf9160-ns", feature = "nrf9120-s", @@ -44,6 +46,8 @@ compile_error!( nrf5340-app-s, nrf5340-app-ns, nrf5340-net, + nrf54l15-app-s, + nrf54l15-app-ns, nrf9160-s, nrf9160-ns, nrf9120-s, @@ -68,21 +72,22 @@ pub(crate) mod util; #[cfg(feature = "_time-driver")] mod time_driver; +#[cfg(not(feature = "_nrf54l"))] // TODO #[cfg(not(feature = "_nrf51"))] pub mod buffered_uarte; -pub mod gpio; -#[cfg(feature = "gpiote")] -pub mod gpiote; - -// TODO: tested on other chips -#[cfg(not(any(feature = "_nrf91", feature = "_nrf5340-app")))] -pub mod radio; - +#[cfg(not(feature = "_nrf54l"))] // TODO #[cfg(not(feature = "_nrf51"))] pub mod egu; +pub mod gpio; +#[cfg(not(feature = "_nrf54l"))] // TODO +#[cfg(feature = "gpiote")] +pub mod gpiote; +#[cfg(not(feature = "_nrf54l"))] // TODO #[cfg(any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840"))] pub mod i2s; +#[cfg(not(feature = "_nrf54l"))] // TODO pub mod nvmc; +#[cfg(not(feature = "_nrf54l"))] // TODO #[cfg(any( feature = "nrf52810", feature = "nrf52811", @@ -93,7 +98,9 @@ pub mod nvmc; feature = "_nrf91", ))] pub mod pdm; +#[cfg(not(feature = "_nrf54l"))] // TODO pub mod ppi; +#[cfg(not(feature = "_nrf54l"))] // TODO #[cfg(not(any( feature = "_nrf51", feature = "nrf52805", @@ -101,27 +108,42 @@ pub mod ppi; feature = "_nrf5340-net" )))] pub mod pwm; +#[cfg(not(feature = "_nrf54l"))] // TODO #[cfg(not(any(feature = "_nrf51", feature = "_nrf91", feature = "_nrf5340-net")))] pub mod qdec; +#[cfg(not(feature = "_nrf54l"))] // TODO #[cfg(any(feature = "nrf52840", feature = "_nrf5340-app"))] pub mod qspi; +#[cfg(not(feature = "_nrf54l"))] // TODO +#[cfg(not(any(feature = "_nrf91", feature = "_nrf5340-app")))] +pub mod radio; +#[cfg(not(feature = "_nrf54l"))] // TODO #[cfg(not(any(feature = "_nrf5340-app", feature = "_nrf91")))] pub mod rng; +#[cfg(not(feature = "_nrf54l"))] // TODO #[cfg(not(any(feature = "_nrf51", feature = "nrf52820", feature = "_nrf5340-net")))] pub mod saadc; +#[cfg(not(feature = "_nrf54l"))] // TODO #[cfg(not(feature = "_nrf51"))] pub mod spim; +#[cfg(not(feature = "_nrf54l"))] // TODO #[cfg(not(feature = "_nrf51"))] pub mod spis; +#[cfg(not(feature = "_nrf54l"))] // TODO #[cfg(not(any(feature = "_nrf5340", feature = "_nrf91")))] pub mod temp; +#[cfg(not(feature = "_nrf54l"))] // TODO pub mod timer; +#[cfg(not(feature = "_nrf54l"))] // TODO #[cfg(not(feature = "_nrf51"))] pub mod twim; +#[cfg(not(feature = "_nrf54l"))] // TODO #[cfg(not(feature = "_nrf51"))] pub mod twis; +#[cfg(not(feature = "_nrf54l"))] // TODO #[cfg(not(feature = "_nrf51"))] pub mod uarte; +#[cfg(not(feature = "_nrf54l"))] // TODO #[cfg(any( feature = "_nrf5340-app", feature = "nrf52820", @@ -129,6 +151,7 @@ pub mod uarte; feature = "nrf52840" ))] pub mod usb; +#[cfg(not(feature = "_nrf54l"))] // TODO #[cfg(not(feature = "_nrf5340"))] pub mod wdt; @@ -143,6 +166,7 @@ pub mod wdt; #[cfg_attr(feature = "nrf52840", path = "chips/nrf52840.rs")] #[cfg_attr(feature = "_nrf5340-app", path = "chips/nrf5340_app.rs")] #[cfg_attr(feature = "_nrf5340-net", path = "chips/nrf5340_net.rs")] +#[cfg_attr(feature = "_nrf54l15-app", path = "chips/nrf54l15_app.rs")] #[cfg_attr(feature = "_nrf9160", path = "chips/nrf9160.rs")] #[cfg_attr(feature = "_nrf9120", path = "chips/nrf9120.rs")] mod chip; @@ -249,10 +273,10 @@ pub mod config { /// External source from xtal. ExternalXtal, /// External source from xtal with low swing applied. - #[cfg(not(any(feature = "_nrf5340", feature = "_nrf91")))] + #[cfg(not(any(feature = "_nrf5340", feature = "_nrf91", feature = "_nrf54l")))] ExternalLowSwing, /// External source from xtal with full swing applied. - #[cfg(not(any(feature = "_nrf5340", feature = "_nrf91")))] + #[cfg(not(any(feature = "_nrf5340", feature = "_nrf91", feature = "_nrf54l")))] ExternalFullSwing, } @@ -325,7 +349,7 @@ pub mod config { pub hfclk_source: HfclkSource, /// Low frequency clock source. pub lfclk_source: LfclkSource, - #[cfg(not(feature = "_nrf5340-net"))] + #[cfg(not(any(feature = "_nrf5340-net", feature = "_nrf54l")))] /// DCDC configuration. pub dcdc: DcdcConfig, /// GPIOTE interrupt priority. Should be lower priority than softdevice if used. @@ -346,7 +370,7 @@ pub mod config { // xtals if they know they have them. hfclk_source: HfclkSource::Internal, lfclk_source: LfclkSource::InternalRC, - #[cfg(not(any(feature = "_nrf5340", feature = "_nrf91")))] + #[cfg(not(any(feature = "_nrf5340", feature = "_nrf91", feature = "_nrf54l")))] dcdc: DcdcConfig { #[cfg(feature = "nrf52840")] reg0: false, @@ -415,7 +439,7 @@ mod consts { pub const APPROTECT_DISABLED: u32 = 0x0000_005a; } -#[cfg(not(feature = "_nrf51"))] +#[cfg(not(any(feature = "_nrf51", feature = "_nrf54l")))] #[derive(Debug, Copy, Clone, Eq, PartialEq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] enum WriteResult { @@ -427,12 +451,12 @@ enum WriteResult { Failed, } -#[cfg(not(feature = "_nrf51"))] +#[cfg(not(any(feature = "_nrf51", feature = "_nrf54l")))] unsafe fn uicr_write(address: *mut u32, value: u32) -> WriteResult { uicr_write_masked(address, value, 0xFFFF_FFFF) } -#[cfg(not(feature = "_nrf51"))] +#[cfg(not(any(feature = "_nrf51", feature = "_nrf54l")))] unsafe fn uicr_write_masked(address: *mut u32, value: u32, mask: u32) -> WriteResult { let curr_val = address.read_volatile(); if curr_val & mask == value & mask { @@ -469,6 +493,7 @@ pub fn init(config: config::Config) -> Peripherals { let mut needs_reset = false; // Setup debug protection. + #[cfg(not(feature = "_nrf54l"))] // TODO #[cfg(not(feature = "_nrf51"))] match config.debug { config::Debug::Allowed => { @@ -592,15 +617,25 @@ pub fn init(config: config::Config) -> Peripherals { match config.hfclk_source { config::HfclkSource::Internal => {} config::HfclkSource::ExternalXtal => { - // Datasheet says this is likely to take 0.36ms - r.events_hfclkstarted().write_value(0); - r.tasks_hfclkstart().write_value(1); - while r.events_hfclkstarted().read() == 0 {} + #[cfg(feature = "_nrf54l")] + { + r.events_xostarted().write_value(0); + r.tasks_xostart().write_value(1); + while r.events_xostarted().read() == 0 {} + } + + #[cfg(not(feature = "_nrf54l"))] + { + // Datasheet says this is likely to take 0.36ms + r.events_hfclkstarted().write_value(0); + r.tasks_hfclkstart().write_value(1); + while r.events_hfclkstarted().read() == 0 {} + } } } // Configure LFCLK. - #[cfg(not(any(feature = "_nrf51", feature = "_nrf5340", feature = "_nrf91")))] + #[cfg(not(any(feature = "_nrf51", feature = "_nrf5340", feature = "_nrf91", feature = "_nrf54l")))] match config.lfclk_source { config::LfclkSource::InternalRC => r.lfclksrc().write(|w| w.set_src(pac::clock::vals::Lfclksrc::RC)), config::LfclkSource::Synthesized => r.lfclksrc().write(|w| w.set_src(pac::clock::vals::Lfclksrc::SYNTH)), @@ -621,6 +656,12 @@ pub fn init(config: config::Config) -> Peripherals { config::LfclkSource::InternalRC => r.lfclksrc().write(|w| w.set_src(pac::clock::vals::Lfclksrc::LFRC)), config::LfclkSource::ExternalXtal => r.lfclksrc().write(|w| w.set_src(pac::clock::vals::Lfclksrc::LFXO)), } + #[cfg(feature = "_nrf54l")] + match config.lfclk_source { + config::LfclkSource::InternalRC => r.lfclk().src().write(|w| w.set_src(pac::clock::vals::Lfclksrc::LFRC)), + config::LfclkSource::Synthesized => r.lfclk().src().write(|w| w.set_src(pac::clock::vals::Lfclksrc::LFSYNT)), + config::LfclkSource::ExternalXtal => r.lfclk().src().write(|w| w.set_src(pac::clock::vals::Lfclksrc::LFXO)), + } // Start LFCLK. // Datasheet says this could take 100us from synth source @@ -629,7 +670,7 @@ pub fn init(config: config::Config) -> Peripherals { r.tasks_lfclkstart().write_value(1); while r.events_lfclkstarted().read() == 0 {} - #[cfg(not(any(feature = "_nrf5340", feature = "_nrf91")))] + #[cfg(not(any(feature = "_nrf5340", feature = "_nrf91", feature = "_nrf54l")))] { // Setup DCDCs. #[cfg(feature = "nrf52840")] @@ -663,6 +704,7 @@ pub fn init(config: config::Config) -> Peripherals { } // Init GPIOTE + #[cfg(not(feature = "_nrf54l"))] // TODO #[cfg(feature = "gpiote")] gpiote::init(config.gpiote_interrupt_priority); diff --git a/embassy-nrf/src/pwm.rs b/embassy-nrf/src/pwm.rs index 7f1f568f4..6247ff6a5 100644 --- a/embassy-nrf/src/pwm.rs +++ b/embassy-nrf/src/pwm.rs @@ -133,7 +133,7 @@ impl<'d, T: Instance> SequencePwm<'d, T> { pin.conf().write(|w| { w.set_dir(gpiovals::Dir::OUTPUT); w.set_input(gpiovals::Input::DISCONNECT); - w.set_drive(convert_drive(config.ch0_drive)); + convert_drive(w, config.ch0_drive); }); } if let Some(pin) = &ch1 { @@ -141,7 +141,7 @@ impl<'d, T: Instance> SequencePwm<'d, T> { pin.conf().write(|w| { w.set_dir(gpiovals::Dir::OUTPUT); w.set_input(gpiovals::Input::DISCONNECT); - w.set_drive(convert_drive(config.ch1_drive)); + convert_drive(w, config.ch1_drive); }); } if let Some(pin) = &ch2 { @@ -149,7 +149,7 @@ impl<'d, T: Instance> SequencePwm<'d, T> { pin.conf().write(|w| { w.set_dir(gpiovals::Dir::OUTPUT); w.set_input(gpiovals::Input::DISCONNECT); - w.set_drive(convert_drive(config.ch2_drive)); + convert_drive(w, config.ch2_drive); }); } if let Some(pin) = &ch3 { @@ -157,7 +157,7 @@ impl<'d, T: Instance> SequencePwm<'d, T> { pin.conf().write(|w| { w.set_dir(gpiovals::Dir::OUTPUT); w.set_input(gpiovals::Input::DISCONNECT); - w.set_drive(convert_drive(config.ch3_drive)); + convert_drive(w, config.ch3_drive); }); } @@ -832,7 +832,7 @@ impl<'d, T: Instance> SimplePwm<'d, T> { #[inline(always)] pub fn set_ch0_drive(&self, drive: OutputDrive) { if let Some(pin) = &self.ch0 { - pin.conf().modify(|w| w.set_drive(convert_drive(drive))); + pin.conf().modify(|w| convert_drive(w, drive)); } } @@ -840,7 +840,7 @@ impl<'d, T: Instance> SimplePwm<'d, T> { #[inline(always)] pub fn set_ch1_drive(&self, drive: OutputDrive) { if let Some(pin) = &self.ch1 { - pin.conf().modify(|w| w.set_drive(convert_drive(drive))); + pin.conf().modify(|w| convert_drive(w, drive)); } } @@ -848,7 +848,7 @@ impl<'d, T: Instance> SimplePwm<'d, T> { #[inline(always)] pub fn set_ch2_drive(&self, drive: OutputDrive) { if let Some(pin) = &self.ch2 { - pin.conf().modify(|w| w.set_drive(convert_drive(drive))); + pin.conf().modify(|w| convert_drive(w, drive)); } } @@ -856,7 +856,7 @@ impl<'d, T: Instance> SimplePwm<'d, T> { #[inline(always)] pub fn set_ch3_drive(&self, drive: OutputDrive) { if let Some(pin) = &self.ch3 { - pin.conf().modify(|w| w.set_drive(convert_drive(drive))); + pin.conf().modify(|w| convert_drive(w, drive)); } } } diff --git a/embassy-nrf/src/spim.rs b/embassy-nrf/src/spim.rs index ffaee2dc5..bd193cfe8 100644 --- a/embassy-nrf/src/spim.rs +++ b/embassy-nrf/src/spim.rs @@ -173,13 +173,13 @@ impl<'d, T: Instance> Spim<'d, T> { if let Some(sck) = &sck { sck.conf().write(|w| { w.set_dir(gpiovals::Dir::OUTPUT); - w.set_drive(convert_drive(config.sck_drive)) + convert_drive(w, config.sck_drive); }); } if let Some(mosi) = &mosi { mosi.conf().write(|w| { w.set_dir(gpiovals::Dir::OUTPUT); - w.set_drive(convert_drive(config.mosi_drive)) + convert_drive(w, config.mosi_drive); }); } if let Some(miso) = &miso { diff --git a/embassy-nrf/src/spis.rs b/embassy-nrf/src/spis.rs index a363e5909..88230fa26 100644 --- a/embassy-nrf/src/spis.rs +++ b/embassy-nrf/src/spis.rs @@ -203,7 +203,7 @@ impl<'d, T: Instance> Spis<'d, T> { if let Some(miso) = &miso { miso.conf().write(|w| { w.set_dir(gpiovals::Dir::OUTPUT); - w.set_drive(convert_drive(config.miso_drive)) + convert_drive(w, config.miso_drive); }); r.psel().miso().write_value(miso.psel_bits()); } diff --git a/embassy-nrf/src/time_driver.rs b/embassy-nrf/src/time_driver.rs index b6492ac97..81aabb11c 100644 --- a/embassy-nrf/src/time_driver.rs +++ b/embassy-nrf/src/time_driver.rs @@ -10,6 +10,11 @@ use embassy_time_driver::{AlarmHandle, Driver}; use crate::interrupt::InterruptExt; use crate::{interrupt, pac}; +#[cfg(feature = "_nrf54l")] +fn rtc() -> pac::rtc::Rtc { + pac::RTC30 +} +#[cfg(not(feature = "_nrf54l"))] fn rtc() -> pac::rtc::Rtc { pac::RTC1 } @@ -141,8 +146,16 @@ impl RtcDriver { // Wait for clear while r.counter().read().0 != 0 {} - interrupt::RTC1.set_priority(irq_prio); - unsafe { interrupt::RTC1.enable() }; + #[cfg(feature = "_nrf54l")] + { + interrupt::RTC30.set_priority(irq_prio); + unsafe { interrupt::RTC30.enable() }; + } + #[cfg(not(feature = "_nrf54l"))] + { + interrupt::RTC1.set_priority(irq_prio); + unsafe { interrupt::RTC1.enable() }; + } } fn on_interrupt(&self) { @@ -292,6 +305,14 @@ impl Driver for RtcDriver { } } +#[cfg(feature = "_nrf54l")] +#[cfg(feature = "rt")] +#[interrupt] +fn RTC30() { + DRIVER.on_interrupt() +} + +#[cfg(not(feature = "_nrf54l"))] #[cfg(feature = "rt")] #[interrupt] fn RTC1() { diff --git a/examples/nrf54l15/.cargo/config.toml b/examples/nrf54l15/.cargo/config.toml new file mode 100644 index 000000000..4a026ebbd --- /dev/null +++ b/examples/nrf54l15/.cargo/config.toml @@ -0,0 +1,9 @@ +[target.'cfg(all(target_arch = "arm", target_os = "none"))'] +# replace nRF82840_xxAA with your chip as listed in `probe-rs chip list` +runner = "../../sshprobe.sh" + +[build] +target = "thumbv8m.main-none-eabihf" + +[env] +DEFMT_LOG = "trace" diff --git a/examples/nrf54l15/Cargo.toml b/examples/nrf54l15/Cargo.toml new file mode 100644 index 000000000..6d11269f7 --- /dev/null +++ b/examples/nrf54l15/Cargo.toml @@ -0,0 +1,20 @@ +[package] +edition = "2021" +name = "embassy-nrf54l15-examples" +version = "0.1.0" +license = "MIT OR Apache-2.0" + +[dependencies] +embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } +embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf54l15-app-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } + +defmt = "0.3" +defmt-rtt = "0.4" +panic-probe = { version = "0.3", features = ["print-defmt"] } + +cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } +cortex-m-rt = "0.7.0" + +[profile.release] +debug = 2 diff --git a/examples/nrf54l15/build.rs b/examples/nrf54l15/build.rs new file mode 100644 index 000000000..30691aa97 --- /dev/null +++ b/examples/nrf54l15/build.rs @@ -0,0 +1,35 @@ +//! This build script copies the `memory.x` file from the crate root into +//! a directory where the linker can always find it at build time. +//! For many projects this is optional, as the linker always searches the +//! project root directory -- wherever `Cargo.toml` is. However, if you +//! are using a workspace or have a more complicated build setup, this +//! build script becomes required. Additionally, by requesting that +//! Cargo re-run the build script whenever `memory.x` is changed, +//! updating `memory.x` ensures a rebuild of the application with the +//! new memory settings. + +use std::env; +use std::fs::File; +use std::io::Write; +use std::path::PathBuf; + +fn main() { + // Put `memory.x` in our output directory and ensure it's + // on the linker search path. + let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); + File::create(out.join("memory.x")) + .unwrap() + .write_all(include_bytes!("memory.x")) + .unwrap(); + println!("cargo:rustc-link-search={}", out.display()); + + // By default, Cargo will re-run a build script whenever + // any file in the project changes. By specifying `memory.x` + // here, we ensure the build script is only re-run when + // `memory.x` is changed. + println!("cargo:rerun-if-changed=memory.x"); + + println!("cargo:rustc-link-arg-bins=--nmagic"); + println!("cargo:rustc-link-arg-bins=-Tlink.x"); + println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); +} diff --git a/examples/nrf54l15/memory.x b/examples/nrf54l15/memory.x new file mode 100644 index 000000000..1064c8a5c --- /dev/null +++ b/examples/nrf54l15/memory.x @@ -0,0 +1,5 @@ +MEMORY +{ + FLASH : ORIGIN = 0x00000000, LENGTH = 1536K + RAM : ORIGIN = 0x20000000, LENGTH = 256K +} diff --git a/examples/nrf54l15/src/bin/blinky.rs b/examples/nrf54l15/src/bin/blinky.rs new file mode 100644 index 000000000..71fcc461f --- /dev/null +++ b/examples/nrf54l15/src/bin/blinky.rs @@ -0,0 +1,23 @@ +#![no_std] +#![no_main] + +use defmt::info; +use embassy_executor::Spawner; +use embassy_nrf::gpio::{Level, Output, OutputDrive}; +use embassy_time::Timer; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_nrf::init(Default::default()); + let mut led = Output::new(p.P2_09, Level::Low, OutputDrive::Standard); + + loop { + info!("high!"); + led.set_high(); + Timer::after_millis(300).await; + info!("low!"); + led.set_low(); + Timer::after_millis(300).await; + } +} From f99d733b616e748eb9c7122b77d6521297d53171 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sun, 17 Nov 2024 23:01:00 +0100 Subject: [PATCH 0359/1217] nrf: add docs build for nrf54. --- embassy-nrf/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml index ed9aba4e7..9e62bcca4 100644 --- a/embassy-nrf/Cargo.toml +++ b/embassy-nrf/Cargo.toml @@ -18,6 +18,7 @@ flavors = [ { regex_feature = "nrf51", target = "thumbv6m-none-eabi" }, { regex_feature = "nrf52.*", target = "thumbv7em-none-eabihf" }, { regex_feature = "nrf53.*", target = "thumbv8m.main-none-eabihf" }, + { regex_feature = "nrf54.*", target = "thumbv8m.main-none-eabihf" }, { regex_feature = "nrf91.*", target = "thumbv8m.main-none-eabihf" }, ] From 7ae28163414d0042c4e06cc02de900e67b62df01 Mon Sep 17 00:00:00 2001 From: elagil Date: Sun, 17 Nov 2024 23:09:51 +0100 Subject: [PATCH 0360/1217] feat: SAI/ringbuffer add function to wait for any write error --- embassy-stm32/src/dma/dma_bdma.rs | 7 +++++++ embassy-stm32/src/dma/ringbuffer/mod.rs | 13 +++++++++++++ embassy-stm32/src/sai/mod.rs | 16 ++++++++++++++++ 3 files changed, 36 insertions(+) diff --git a/embassy-stm32/src/dma/dma_bdma.rs b/embassy-stm32/src/dma/dma_bdma.rs index 08c7a5508..90160ed50 100644 --- a/embassy-stm32/src/dma/dma_bdma.rs +++ b/embassy-stm32/src/dma/dma_bdma.rs @@ -1006,6 +1006,13 @@ impl<'a, W: Word> WritableRingBuffer<'a, W> { .await } + /// Wait for any ring buffer write error. + pub async fn write_error(&mut self) -> Result { + self.ringbuf + .write_error(&mut DmaCtrlImpl(self.channel.reborrow())) + .await + } + /// The current length of the ringbuffer pub fn len(&mut self) -> Result { Ok(self.ringbuf.len(&mut DmaCtrlImpl(self.channel.reborrow()))?) diff --git a/embassy-stm32/src/dma/ringbuffer/mod.rs b/embassy-stm32/src/dma/ringbuffer/mod.rs index 0da8c374f..b7f98fbce 100644 --- a/embassy-stm32/src/dma/ringbuffer/mod.rs +++ b/embassy-stm32/src/dma/ringbuffer/mod.rs @@ -260,6 +260,19 @@ impl<'a, W: Word> WritableDmaRingBuffer<'a, W> { Ok((written, self.cap() - written)) } + /// Wait for any ring buffer write error. + pub async fn write_error(&mut self, dma: &mut impl DmaCtrl) -> Result { + poll_fn(|cx| { + dma.set_waker(cx.waker()); + + match self.len(dma) { + Ok(_) => Poll::Pending, + Err(e) => Poll::Ready(Err(e)), + } + }) + .await + } + /// Write an exact number of elements to the ringbuffer. pub async fn write_exact(&mut self, dma: &mut impl DmaCtrl, buffer: &[W]) -> Result { let mut written_data = 0; diff --git a/embassy-stm32/src/sai/mod.rs b/embassy-stm32/src/sai/mod.rs index 057b21980..fd61e5339 100644 --- a/embassy-stm32/src/sai/mod.rs +++ b/embassy-stm32/src/sai/mod.rs @@ -1003,6 +1003,22 @@ impl<'d, T: Instance, W: word::Word> Sai<'d, T, W> { } } + /// Wait until any SAI write error occurs. + /// + /// One useful application for this is stopping playback as soon as the SAI + /// experiences an overrun of the ring buffer. Then, instead of letting + /// the SAI peripheral play the last written buffer over and over again, SAI + /// can be muted or dropped instead. + pub async fn write_error(&mut self) -> Result<(), Error> { + match &mut self.ring_buffer { + RingBuffer::Writable(buffer) => { + buffer.write_error().await?; + Ok(()) + } + _ => return Err(Error::NotATransmitter), + } + } + /// Write data to the SAI ringbuffer. /// /// The first write starts the DMA after filling the ring buffer with the provided data. From ee9ca4470370ae9e0e98a54ceb94ec83da20eb19 Mon Sep 17 00:00:00 2001 From: elagil Date: Sun, 17 Nov 2024 23:56:45 +0100 Subject: [PATCH 0361/1217] refactor: naming of wait functions --- embassy-stm32/src/dma/dma_bdma.rs | 4 ++-- embassy-stm32/src/dma/ringbuffer/mod.rs | 2 +- embassy-stm32/src/sai/mod.rs | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/embassy-stm32/src/dma/dma_bdma.rs b/embassy-stm32/src/dma/dma_bdma.rs index 90160ed50..1945c3587 100644 --- a/embassy-stm32/src/dma/dma_bdma.rs +++ b/embassy-stm32/src/dma/dma_bdma.rs @@ -1007,9 +1007,9 @@ impl<'a, W: Word> WritableRingBuffer<'a, W> { } /// Wait for any ring buffer write error. - pub async fn write_error(&mut self) -> Result { + pub async fn wait_write_error(&mut self) -> Result { self.ringbuf - .write_error(&mut DmaCtrlImpl(self.channel.reborrow())) + .wait_write_error(&mut DmaCtrlImpl(self.channel.reborrow())) .await } diff --git a/embassy-stm32/src/dma/ringbuffer/mod.rs b/embassy-stm32/src/dma/ringbuffer/mod.rs index b7f98fbce..25bdc7522 100644 --- a/embassy-stm32/src/dma/ringbuffer/mod.rs +++ b/embassy-stm32/src/dma/ringbuffer/mod.rs @@ -261,7 +261,7 @@ impl<'a, W: Word> WritableDmaRingBuffer<'a, W> { } /// Wait for any ring buffer write error. - pub async fn write_error(&mut self, dma: &mut impl DmaCtrl) -> Result { + pub async fn wait_write_error(&mut self, dma: &mut impl DmaCtrl) -> Result { poll_fn(|cx| { dma.set_waker(cx.waker()); diff --git a/embassy-stm32/src/sai/mod.rs b/embassy-stm32/src/sai/mod.rs index fd61e5339..a8d02f825 100644 --- a/embassy-stm32/src/sai/mod.rs +++ b/embassy-stm32/src/sai/mod.rs @@ -1009,10 +1009,10 @@ impl<'d, T: Instance, W: word::Word> Sai<'d, T, W> { /// experiences an overrun of the ring buffer. Then, instead of letting /// the SAI peripheral play the last written buffer over and over again, SAI /// can be muted or dropped instead. - pub async fn write_error(&mut self) -> Result<(), Error> { + pub async fn wait_write_error(&mut self) -> Result<(), Error> { match &mut self.ring_buffer { RingBuffer::Writable(buffer) => { - buffer.write_error().await?; + buffer.wait_write_error().await?; Ok(()) } _ => return Err(Error::NotATransmitter), From e09e4e96127aaa77e58152901745b97860f22e6b Mon Sep 17 00:00:00 2001 From: Christian Enderle Date: Sat, 9 Nov 2024 20:35:19 +0100 Subject: [PATCH 0362/1217] Enable user to choose to pass lse clock to peripherals --- embassy-stm32/src/rcc/bd.rs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/embassy-stm32/src/rcc/bd.rs b/embassy-stm32/src/rcc/bd.rs index 9ccca8a2a..78ecbfb94 100644 --- a/embassy-stm32/src/rcc/bd.rs +++ b/embassy-stm32/src/rcc/bd.rs @@ -20,6 +20,9 @@ pub enum LseMode { pub struct LseConfig { pub frequency: Hertz, pub mode: LseMode, + /// If peripherals other than RTC/TAMP or RCC functions need the lse this bit must be set + #[cfg(any(rcc_l5, rcc_u5, rcc_wle, rcc_wl5, rcc_wba))] + pub peripherals_clocked: bool, } #[allow(dead_code)] @@ -95,6 +98,8 @@ impl LsConfig { lse: Some(LseConfig { frequency: Hertz(32_768), mode: LseMode::Oscillator(LseDrive::MediumHigh), + #[cfg(any(rcc_l5, rcc_u5, rcc_wle, rcc_wl5, rcc_wba))] + peripherals_clocked: false, }), lsi: false, } @@ -148,6 +153,12 @@ impl LsConfig { }, None => (false, false, None), }; + #[cfg(any(rcc_l5, rcc_u5, rcc_wle, rcc_wl5, rcc_wba))] + let lse_sysen = if let Some(lse) = self.lse { + Some(lse.peripherals_clocked) + } else { + None + }; _ = lse_drv; // not all chips have it. // Disable backup domain write protection @@ -188,6 +199,10 @@ impl LsConfig { } ok &= reg.lseon() == lse_en; ok &= reg.lsebyp() == lse_byp; + #[cfg(any(rcc_l5, rcc_u5, rcc_wle, rcc_wl5, rcc_wba))] + if let Some(lse_sysen) = lse_sysen { + ok &= reg.lsesysen() == lse_sysen; + } #[cfg(not(any(rcc_f1, rcc_f1cl, rcc_f100, rcc_f2, rcc_f4, rcc_f410, rcc_l1)))] if let Some(lse_drv) = lse_drv { ok &= reg.lsedrv() == lse_drv.into(); @@ -235,6 +250,15 @@ impl LsConfig { }); while !bdcr().read().lserdy() {} + + #[cfg(any(rcc_l5, rcc_u5, rcc_wle, rcc_wl5, rcc_wba))] + if let Some(lse_sysen) = lse_sysen { + bdcr().modify(|w| { + w.set_lsesysen(lse_sysen); + }); + + while !bdcr().read().lsesysrdy() {} + } } if self.rtc != RtcClockSource::DISABLE { From e76473ae95b24d9772711ab4ece464e44e9558f6 Mon Sep 17 00:00:00 2001 From: Christian Enderle Date: Mon, 18 Nov 2024 12:20:15 +0100 Subject: [PATCH 0363/1217] fixed hanging when lse_sysen disabled --- embassy-stm32/src/rcc/bd.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/embassy-stm32/src/rcc/bd.rs b/embassy-stm32/src/rcc/bd.rs index 78ecbfb94..4aec3756f 100644 --- a/embassy-stm32/src/rcc/bd.rs +++ b/embassy-stm32/src/rcc/bd.rs @@ -257,7 +257,9 @@ impl LsConfig { w.set_lsesysen(lse_sysen); }); - while !bdcr().read().lsesysrdy() {} + if lse_sysen { + while !bdcr().read().lsesysrdy() {} + } } } From 62dbdcd45adfa7f3b74b377f0b4ef7eafaef78fd Mon Sep 17 00:00:00 2001 From: elagil Date: Mon, 18 Nov 2024 20:51:22 +0100 Subject: [PATCH 0364/1217] feat: add SPDIFRX driver --- embassy-stm32/build.rs | 12 ++ embassy-stm32/src/lib.rs | 2 + embassy-stm32/src/spdifrx/mod.rs | 336 +++++++++++++++++++++++++++++++ 3 files changed, 350 insertions(+) create mode 100644 embassy-stm32/src/spdifrx/mod.rs diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 71bfb3747..348d48b9b 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -1220,6 +1220,17 @@ fn main() { impl_dac_pin!( #peri, #pin_name, #ch); }) } + + if regs.kind == "spdifrx" { + let peri = format_ident!("{}", p.name); + let pin_name = format_ident!("{}", pin.pin); + let af = pin.af.unwrap_or(0); + let sel: u8 = pin.signal.strip_prefix("IN").unwrap().parse().unwrap(); + + g.extend(quote! { + impl_spdifrx_pin!( #peri, #pin_name, #af, #sel); + }) + } } } } @@ -1244,6 +1255,7 @@ fn main() { (("sai", "B"), quote!(crate::sai::Dma)), (("spi", "RX"), quote!(crate::spi::RxDma)), (("spi", "TX"), quote!(crate::spi::TxDma)), + (("spdifrx", "RX"), quote!(crate::spdifrx::Dma)), (("i2c", "RX"), quote!(crate::i2c::RxDma)), (("i2c", "TX"), quote!(crate::i2c::TxDma)), (("dcmi", "DCMI"), quote!(crate::dcmi::FrameDma)), diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 286a18da2..e189351d1 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -107,6 +107,8 @@ pub mod rtc; pub mod sai; #[cfg(sdmmc)] pub mod sdmmc; +#[cfg(spdifrx)] +pub mod spdifrx; #[cfg(spi)] pub mod spi; #[cfg(tsc)] diff --git a/embassy-stm32/src/spdifrx/mod.rs b/embassy-stm32/src/spdifrx/mod.rs new file mode 100644 index 000000000..bfc8bff29 --- /dev/null +++ b/embassy-stm32/src/spdifrx/mod.rs @@ -0,0 +1,336 @@ +//! S/PDIF receiver +#![macro_use] +#![cfg_attr(gpdma, allow(unused))] + +use core::marker::PhantomData; + +use embassy_hal_internal::{into_ref, PeripheralRef}; +use embassy_sync::waitqueue::AtomicWaker; + +use crate::dma::ringbuffer::Error as RingbufferError; +pub use crate::dma::word; +#[cfg(not(gpdma))] +use crate::dma::ReadableRingBuffer; +use crate::dma::{Channel, TransferOptions}; +use crate::gpio::{AfType, AnyPin, Pull, SealedPin as _}; +use crate::interrupt::typelevel::Interrupt; +use crate::pac::spdifrx::Spdifrx as Regs; +use crate::rcc::{RccInfo, SealedRccPeripheral}; +use crate::{interrupt, peripherals, Peripheral}; + +/// Possible S/PDIF preamble types. +#[allow(dead_code)] +#[repr(u8)] +enum PreambleType { + Unused = 0x00, + /// The preamble changes to preamble “B†once every 192 frames to identify the start of the block structure used to + /// organize the channel status and user information. + B = 0x01, + /// The first sub-frame (left or “A†channel in stereophonic operation and primary channel in monophonic operation) + /// normally starts with preamble “M†+ M = 0x02, + /// The second sub-frame (right or “B†channel in stereophonic operation and secondary channel in monophonic + /// operation) always starts with preamble “Wâ€. + W = 0x03, +} + +macro_rules! new_spdifrx_pin { + ($name:ident, $af_type:expr) => {{ + let pin = $name.into_ref(); + let input_sel = pin.input_sel(); + pin.set_as_af(pin.af_num(), $af_type); + (Some(pin.map_into()), input_sel) + }}; +} + +macro_rules! impl_spdifrx_pin { + ($inst:ident, $pin:ident, $af:expr, $sel:expr) => { + impl crate::spdifrx::InPin for crate::peripherals::$pin { + fn af_num(&self) -> u8 { + $af + } + fn input_sel(&self) -> u8 { + $sel + } + } + }; +} + +/// Ring-buffered SPDIFRX driver. +/// +/// Data is read by DMAs and stored in a ring buffer. +#[cfg(not(gpdma))] +pub struct Spdifrx<'d, T: Instance> { + _peri: PeripheralRef<'d, T>, + spdifrx_in: Option>, + data_ring_buffer: ReadableRingBuffer<'d, u32>, +} + +/// Gives the address of the data register. +fn dr_address(r: Regs) -> *mut u32 { + #[cfg(spdifrx_v1)] + let address = r.dr().as_ptr() as _; + #[cfg(spdifrx_h7)] + let address = r.fmt0_dr().as_ptr() as _; // All fmtx_dr() implementations have the same address. + + return address; +} + +/// Gives the address of the channel status register. +#[allow(unused)] +fn csr_address(r: Regs) -> *mut u32 { + r.csr().as_ptr() as _ +} + +/// Select the channel for capturing control information. +pub enum ControlChannelSelection { + /// Capture control info from channel A. + A, + /// Capture control info from channel B. + B, +} + +/// Configuration options for the SPDIFRX driver. +pub struct Config { + /// Select the channel for capturing control information. + pub control_channel_selection: ControlChannelSelection, +} + +/// S/PDIF errors. +#[derive(Debug)] +pub enum Error { + /// DMA overrun error. + RingbufferError(RingbufferError), + /// Left/right channel synchronization error. + ChannelSyncError, +} + +impl From for Error { + fn from(error: RingbufferError) -> Self { + Self::RingbufferError(error) + } +} + +impl Default for Config { + fn default() -> Self { + Self { + control_channel_selection: ControlChannelSelection::A, + } + } +} + +#[cfg(not(gpdma))] +impl<'d, T: Instance> Spdifrx<'d, T> { + fn dma_opts() -> TransferOptions { + TransferOptions { + half_transfer_ir: true, + // new_write() and new_read() always use circular mode + ..Default::default() + } + } + + /// Create a new `Spdifrx` instance. + pub fn new( + peri: impl Peripheral

+ 'd, + _irq: impl interrupt::typelevel::Binding> + 'd, + config: Config, + spdifrx_in: impl Peripheral

> + 'd, + data_dma: impl Peripheral

> + 'd, + data_dma_buf: &'d mut [u32], + ) -> Self { + let (spdifrx_in, input_sel) = new_spdifrx_pin!(spdifrx_in, AfType::input(Pull::None)); + Self::setup(config, input_sel); + + into_ref!(peri, data_dma); + + let regs = T::info().regs; + let dr_request = data_dma.request(); + let dr_ring_buffer = + unsafe { ReadableRingBuffer::new(data_dma, dr_request, dr_address(regs), data_dma_buf, Self::dma_opts()) }; + + Self { + _peri: peri, + spdifrx_in, + data_ring_buffer: dr_ring_buffer, + } + } + + fn setup(config: Config, input_sel: u8) { + T::info().rcc.enable_and_reset(); + T::GlobalInterrupt::unpend(); + unsafe { T::GlobalInterrupt::enable() }; + + let regs = T::info().regs; + + regs.imr().write(|imr| { + imr.set_ifeie(true); // Enables interrupts for TERR, SERR, FERR. + imr.set_syncdie(true); // Enables SYNCD interrupt. + }); + + regs.cr().write(|cr| { + cr.set_spdifen(0x00); // Disable SPDIF receiver synchronization. + cr.set_rxdmaen(true); // Use RX DMA for data. Enabled on `read`. + cr.set_cbdmaen(false); // Do not capture channel info. + cr.set_rxsteo(true); // Operate in stereo mode. + cr.set_drfmt(0x01); // Data is left-aligned (MSB). + + // Disable all status fields in the data register. + // Status can be obtained directly with the status register DMA. + cr.set_pmsk(false); // Write parity bit to the data register. FIXME: Add parity check. + cr.set_vmsk(false); // Write validity to the data register. + cr.set_cumsk(true); // Do not write C and U bits to the data register. + cr.set_ptmsk(false); // Write preamble bits to the data register. + + cr.set_chsel(match config.control_channel_selection { + ControlChannelSelection::A => false, + ControlChannelSelection::B => true, + }); // Select channel status source. + + cr.set_nbtr(0x02); // 16 attempts are allowed. + cr.set_wfa(true); // Wait for activity before going to synchronization phase. + cr.set_insel(input_sel); // Input pin selection. + + #[cfg(stm32h7)] + cr.set_cksen(true); // Generate a symbol clock. + + #[cfg(stm32h7)] + cr.set_cksbkpen(false); // Do not generate a backup symbol clock. + }); + } + + /// Start the SPDIFRX driver. + pub fn start(&mut self) { + self.data_ring_buffer.start(); + + T::info().regs.cr().modify(|cr| { + cr.set_spdifen(0x03); // Enable S/PDIF receiver. + }); + } + + /// Read from the SPDIFRX data ring buffer. + /// + /// SPDIFRX is always receiving data in the background. This function pops already-received + /// data from the buffer. + /// + /// If there's less than `data.len()` data in the buffer, this waits until there is. + pub async fn read(&mut self, data: &mut [u32]) -> Result<(), Error> { + self.data_ring_buffer.read_exact(data).await?; + + let first_preamble = (data[0] >> 4) & 0b11_u32; + if (first_preamble as u8) == (PreambleType::W as u8) { + trace!("S/PDIF left/right mismatch"); + + // Resynchronize until the first sample is for the left channel. + self.data_ring_buffer.clear(); + return Err(Error::ChannelSyncError); + }; + + for sample in data.as_mut() { + if (*sample & (0x0002_u32)) == 0x0001 { + // Discard invalid samples, setting them to mute level. + *sample = 0; + } else { + // Discard status information in the lowest byte. + *sample &= 0xFFFFFF00; + } + } + + Ok(()) + } +} + +#[cfg(not(gpdma))] +impl<'d, T: Instance> Drop for Spdifrx<'d, T> { + fn drop(&mut self) { + T::info().regs.cr().modify(|cr| cr.set_spdifen(0x00)); + self.spdifrx_in.as_ref().map(|x| x.set_as_disconnected()); + } +} + +struct State { + #[allow(unused)] + waker: AtomicWaker, +} + +impl State { + const fn new() -> Self { + Self { + waker: AtomicWaker::new(), + } + } +} + +struct Info { + regs: crate::pac::spdifrx::Spdifrx, + rcc: RccInfo, +} + +peri_trait!( + irqs: [GlobalInterrupt], +); + +/// SPIDFRX pin trait +pub trait InPin: crate::gpio::Pin { + /// Get the GPIO AF number needed to use this pin. + fn af_num(&self) -> u8; + /// Get the SPIDFRX INSEL number needed to use this pin. + fn input_sel(&self) -> u8; +} + +dma_trait!(Dma, Instance); + +/// Global interrupt handler. +pub struct GlobalInterruptHandler { + _phantom: PhantomData, +} + +impl interrupt::typelevel::Handler for GlobalInterruptHandler { + unsafe fn on_interrupt() { + T::state().waker.wake(); + + let regs = T::info().regs; + let sr = regs.sr().read(); + + if sr.serr() || sr.terr() || sr.ferr() { + trace!("SPDIFRX error, resync"); + + // Clear errors by disabling SPDIFRX, then reenable. + regs.cr().modify(|cr| cr.set_spdifen(0x00)); + regs.cr().modify(|cr| cr.set_spdifen(0x03)); + } else if sr.syncd() { + // Synchronization was successful. + trace!("SPDIFRX sync success"); + } + + // Clear interrupt flags. + regs.ifcr().write(|ifcr| { + ifcr.set_perrcf(true); // Clears parity error flag. + ifcr.set_ovrcf(true); // Clears overrun error flag. + ifcr.set_sbdcf(true); // Clears synchronization block detected flag. + ifcr.set_syncdcf(true); // Clears SYNCD from SR (was read above). + }); + } +} + +foreach_peripheral!( + (spdifrx, $inst:ident) => { + #[allow(private_interfaces)] + impl SealedInstance for peripherals::$inst { + fn info() -> &'static Info { + static INFO: Info = Info{ + regs: crate::pac::$inst, + rcc: crate::peripherals::$inst::RCC_INFO, + }; + &INFO + } + fn state() -> &'static State { + static STATE: State = State::new(); + &STATE + } + } + + impl Instance for peripherals::$inst { + type GlobalInterrupt = crate::_generated::peripheral_interrupts::$inst::GLOBAL; + } + }; +); From 1ce1e193b71a5addd8c809722e6f4c6e0cb78284 Mon Sep 17 00:00:00 2001 From: elagil Date: Mon, 18 Nov 2024 20:51:23 +0100 Subject: [PATCH 0365/1217] feat: Add SPDIFRX example --- examples/stm32h723/.cargo/config.toml | 8 ++ examples/stm32h723/Cargo.toml | 69 +++++++++++ examples/stm32h723/build.rs | 35 ++++++ examples/stm32h723/memory.x | 106 +++++++++++++++++ examples/stm32h723/src/bin/spdifrx.rs | 161 ++++++++++++++++++++++++++ 5 files changed, 379 insertions(+) create mode 100644 examples/stm32h723/.cargo/config.toml create mode 100644 examples/stm32h723/Cargo.toml create mode 100644 examples/stm32h723/build.rs create mode 100644 examples/stm32h723/memory.x create mode 100644 examples/stm32h723/src/bin/spdifrx.rs diff --git a/examples/stm32h723/.cargo/config.toml b/examples/stm32h723/.cargo/config.toml new file mode 100644 index 000000000..2e53663c5 --- /dev/null +++ b/examples/stm32h723/.cargo/config.toml @@ -0,0 +1,8 @@ +[target.thumbv7em-none-eabihf] +runner = 'probe-rs run --chip STM32H723ZGTx' + +[build] +target = "thumbv7em-none-eabihf" # Cortex-M4F and Cortex-M7F (with FPU) + +[env] +DEFMT_LOG = "trace" diff --git a/examples/stm32h723/Cargo.toml b/examples/stm32h723/Cargo.toml new file mode 100644 index 000000000..8ebc1051f --- /dev/null +++ b/examples/stm32h723/Cargo.toml @@ -0,0 +1,69 @@ +[package] +edition = "2021" +name = "embassy-stm32h7-examples" +version = "0.1.0" +license = "MIT OR Apache-2.0" + +[dependencies] +# Change stm32h723zg to your chip name, if necessary. +embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h723zg", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } +embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } + +defmt = "0.3" +defmt-rtt = "0.4" + +cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } +cortex-m-rt = "0.7.0" +embedded-hal = "0.2.6" +embedded-hal-1 = { package = "embedded-hal", version = "1.0" } +embedded-hal-async = { version = "1.0" } +embedded-nal-async = "0.8.0" +embedded-io-async = { version = "0.6.1" } +panic-probe = { version = "0.3", features = ["print-defmt"] } +heapless = { version = "0.8", default-features = false } +rand_core = "0.6.3" +critical-section = "1.1" +static_cell = "2" +chrono = { version = "^0.4", default-features = false } +grounded = "0.2.0" + +# cargo build/run +[profile.dev] +codegen-units = 1 +debug = 2 +debug-assertions = true # <- +incremental = false +opt-level = 3 # <- +overflow-checks = true # <- + +# cargo test +[profile.test] +codegen-units = 1 +debug = 2 +debug-assertions = true # <- +incremental = false +opt-level = 3 # <- +overflow-checks = true # <- + +# cargo build/run --release +[profile.release] +codegen-units = 1 +debug = 2 +debug-assertions = false # <- +incremental = false +lto = 'fat' +opt-level = 3 # <- +overflow-checks = false # <- + +# cargo test --release +[profile.bench] +codegen-units = 1 +debug = 2 +debug-assertions = false # <- +incremental = false +lto = 'fat' +opt-level = 3 # <- +overflow-checks = false # <- diff --git a/examples/stm32h723/build.rs b/examples/stm32h723/build.rs new file mode 100644 index 000000000..30691aa97 --- /dev/null +++ b/examples/stm32h723/build.rs @@ -0,0 +1,35 @@ +//! This build script copies the `memory.x` file from the crate root into +//! a directory where the linker can always find it at build time. +//! For many projects this is optional, as the linker always searches the +//! project root directory -- wherever `Cargo.toml` is. However, if you +//! are using a workspace or have a more complicated build setup, this +//! build script becomes required. Additionally, by requesting that +//! Cargo re-run the build script whenever `memory.x` is changed, +//! updating `memory.x` ensures a rebuild of the application with the +//! new memory settings. + +use std::env; +use std::fs::File; +use std::io::Write; +use std::path::PathBuf; + +fn main() { + // Put `memory.x` in our output directory and ensure it's + // on the linker search path. + let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); + File::create(out.join("memory.x")) + .unwrap() + .write_all(include_bytes!("memory.x")) + .unwrap(); + println!("cargo:rustc-link-search={}", out.display()); + + // By default, Cargo will re-run a build script whenever + // any file in the project changes. By specifying `memory.x` + // here, we ensure the build script is only re-run when + // `memory.x` is changed. + println!("cargo:rerun-if-changed=memory.x"); + + println!("cargo:rustc-link-arg-bins=--nmagic"); + println!("cargo:rustc-link-arg-bins=-Tlink.x"); + println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); +} diff --git a/examples/stm32h723/memory.x b/examples/stm32h723/memory.x new file mode 100644 index 000000000..aa4c00505 --- /dev/null +++ b/examples/stm32h723/memory.x @@ -0,0 +1,106 @@ +MEMORY +{ + /* This file is intended for parts in the STM32H723 family. (RM0468) */ + /* - FLASH and RAM are mandatory memory sections. */ + /* - The sum of all non-FLASH sections must add to 564k total device RAM. */ + /* - The FLASH section size must match your device, see table below. */ + + /* FLASH */ + /* Select the appropriate FLASH size for your device. */ + /* - STM32H730xB 128K */ + /* - STM32H723xE/725xE 512K */ + /* - STM32H723xG/725xG/733xG/735xG 1M */ + FLASH1 : ORIGIN = 0x08000000, LENGTH = 1M + + /* Data TCM */ + /* - Two contiguous 64KB RAMs. */ + /* - Used for interrupt handlers, stacks and general RAM. */ + /* - Zero wait-states. */ + /* - The DTCM is taken as the origin of the base ram. (See below.) */ + /* This is also where the interrupt table and such will live, */ + /* which is required for deterministic performance. */ + DTCM : ORIGIN = 0x20000000, LENGTH = 128K + + /* Instruction TCM */ + /* - More memory can be assigned to ITCM. See AXI SRAM notes, below. */ + /* - Used for latency-critical interrupt handlers etc. */ + /* - Zero wait-states. */ + ITCM : ORIGIN = 0x00000000, LENGTH = 64K + 0K + + /* AXI SRAM */ + /* - AXISRAM is in D1 and accessible by all system masters except BDMA. */ + /* - Suitable for application data not stored in DTCM. */ + /* - Zero wait-states. */ + /* - The 192k of extra shared RAM is fully allotted to the AXI SRAM by default. */ + /* As a result: 64k (64k + 0k) for ITCM and 320k (128k + 192k) for AXI SRAM. */ + /* This can be re-configured via the TCM_AXI_SHARED[1,0] register when more */ + /* ITCM is required. */ + AXISRAM : ORIGIN = 0x24000000, LENGTH = 128K + 192K + + /* AHB SRAM */ + /* - SRAM1-2 are in D2 and accessible by all system masters except BDMA, LTDC */ + /* and SDMMC1. Suitable for use as DMA buffers. */ + /* - SRAM4 is in D3 and additionally accessible by the BDMA. Used for BDMA */ + /* buffers, for storing application data in lower-power modes. */ + /* - Zero wait-states. */ + SRAM1 : ORIGIN = 0x30000000, LENGTH = 16K + SRAM2 : ORIGIN = 0x30040000, LENGTH = 16K + SRAM4 : ORIGIN = 0x38000000, LENGTH = 16K + + /* Backup SRAM */ + /* Used to store data during low-power sleeps. */ + BSRAM : ORIGIN = 0x38800000, LENGTH = 4K +} + +/* +/* Assign the memory regions defined above for use. */ +/* + +/* Provide the mandatory FLASH and RAM definitions for cortex-m-rt's linker script. */ +REGION_ALIAS(FLASH, FLASH1); +REGION_ALIAS(RAM, DTCM); + +/* The location of the stack can be overridden using the `_stack_start` symbol. */ +/* - Set the stack location at the end of RAM, using all remaining space. */ +_stack_start = ORIGIN(RAM) + LENGTH(RAM); + +/* The location of the .text section can be overridden using the */ +/* `_stext` symbol. By default it will place after .vector_table. */ +/* _stext = ORIGIN(FLASH) + 0x40c; */ + +/* Define sections for placing symbols into the extra memory regions above. */ +/* This makes them accessible from code. */ +/* - ITCM, DTCM and AXISRAM connect to a 64-bit wide bus -> align to 8 bytes. */ +/* - All other memories connect to a 32-bit wide bus -> align to 4 bytes. */ +SECTIONS { + .itcm (NOLOAD) : ALIGN(8) { + *(.itcm .itcm.*); + . = ALIGN(8); + } > ITCM + + .axisram (NOLOAD) : ALIGN(8) { + *(.axisram .axisram.*); + . = ALIGN(8); + } > AXISRAM + + .sram1 (NOLOAD) : ALIGN(4) { + *(.sram1 .sram1.*); + . = ALIGN(4); + } > SRAM1 + + .sram2 (NOLOAD) : ALIGN(4) { + *(.sram2 .sram2.*); + . = ALIGN(4); + } > SRAM2 + + .sram4 (NOLOAD) : ALIGN(4) { + *(.sram4 .sram4.*); + . = ALIGN(4); + } > SRAM4 + + .bsram (NOLOAD) : ALIGN(4) { + *(.bsram .bsram.*); + . = ALIGN(4); + } > BSRAM + +}; diff --git a/examples/stm32h723/src/bin/spdifrx.rs b/examples/stm32h723/src/bin/spdifrx.rs new file mode 100644 index 000000000..deee5ca8d --- /dev/null +++ b/examples/stm32h723/src/bin/spdifrx.rs @@ -0,0 +1,161 @@ +//! This example receives inputs on SPDIFRX and outputs on SAI4. +//! +//! Only very few controllers connect the SPDIFRX symbol clock to a SAI peripheral's clock input. +//! However, this is necessary for synchronizing the symbol rates and avoiding glitches. +#![no_std] +#![no_main] + +use defmt::{info, trace}; +use embassy_executor::Spawner; +use embassy_stm32::spdifrx::{self, Spdifrx}; +use embassy_stm32::{bind_interrupts, peripherals, sai}; +use grounded::uninit::GroundedArrayCell; +use hal::sai::*; +use {defmt_rtt as _, embassy_stm32 as hal, panic_probe as _}; + +bind_interrupts!(struct Irqs { + SPDIF_RX => spdifrx::GlobalInterruptHandler; +}); + +const CHANNEL_COUNT: usize = 2; +const BLOCK_LENGTH: usize = 64; +const HALF_DMA_BUFFER_LENGTH: usize = BLOCK_LENGTH * CHANNEL_COUNT; +const DMA_BUFFER_LENGTH: usize = HALF_DMA_BUFFER_LENGTH * 2; // 2 half-blocks + +// DMA buffers must be in special regions. Refer https://embassy.dev/book/#_stm32_bdma_only_working_out_of_some_ram_regions +#[link_section = ".sram1"] +static mut SPDIFRX_BUFFER: GroundedArrayCell = GroundedArrayCell::uninit(); + +#[link_section = ".sram4"] +static mut SAI_BUFFER: GroundedArrayCell = GroundedArrayCell::uninit(); + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let mut peripheral_config = embassy_stm32::Config::default(); + { + use embassy_stm32::rcc::*; + peripheral_config.rcc.hsi = Some(HSIPrescaler::DIV1); + peripheral_config.rcc.pll1 = Some(Pll { + source: PllSource::HSI, + prediv: PllPreDiv::DIV16, + mul: PllMul::MUL200, + divp: Some(PllDiv::DIV2), // 400 MHz + divq: Some(PllDiv::DIV2), + divr: Some(PllDiv::DIV2), + }); + peripheral_config.rcc.sys = Sysclk::PLL1_P; + peripheral_config.rcc.ahb_pre = AHBPrescaler::DIV2; + peripheral_config.rcc.apb1_pre = APBPrescaler::DIV2; + peripheral_config.rcc.apb2_pre = APBPrescaler::DIV2; + peripheral_config.rcc.apb3_pre = APBPrescaler::DIV2; + peripheral_config.rcc.apb4_pre = APBPrescaler::DIV2; + + peripheral_config.rcc.mux.spdifrxsel = mux::Spdifrxsel::PLL1_Q; + } + let mut p = embassy_stm32::init(peripheral_config); + + info!("SPDIFRX to SAI4 bridge"); + + // Use SPDIFRX clock for SAI. + // This ensures equal rates of sample production and consumption. + let clk_source = embassy_stm32::pac::rcc::vals::Saiasel::_RESERVED_5; + embassy_stm32::pac::RCC.d3ccipr().modify(|w| { + w.set_sai4asel(clk_source); + }); + + let sai_buffer: &mut [u32] = unsafe { + SAI_BUFFER.initialize_all_copied(0); + let (ptr, len) = SAI_BUFFER.get_ptr_len(); + core::slice::from_raw_parts_mut(ptr, len) + }; + + let spdifrx_buffer: &mut [u32] = unsafe { + SPDIFRX_BUFFER.initialize_all_copied(0); + let (ptr, len) = SPDIFRX_BUFFER.get_ptr_len(); + core::slice::from_raw_parts_mut(ptr, len) + }; + + let mut spdif_receiver = new_spdif_receiver(&mut p.SPDIFRX1, &mut p.PD7, &mut p.DMA2_CH7, spdifrx_buffer); + let mut sai_transmitter = new_sai_transmitter( + &mut p.SAI4, + &mut p.PD13, + &mut p.PC1, + &mut p.PD12, + &mut p.BDMA_CH0, + sai_buffer, + ); + + spdif_receiver.start(); + sai_transmitter.start(); + + loop { + let mut buf = [0u32; HALF_DMA_BUFFER_LENGTH]; + + match spdif_receiver.read_data(&mut buf).await { + Ok(_) => (), + Err(spdifrx::Error::RingbufferError(_)) => { + trace!("SPDIFRX ringbuffer error. Renew."); + drop(spdif_receiver); + spdif_receiver = new_spdif_receiver(&mut p.SPDIFRX1, &mut p.PD7, &mut p.DMA2_CH7, spdifrx_buffer); + spdif_receiver.start(); + continue; + } + Err(spdifrx::Error::ChannelSyncError) => { + trace!("SPDIFRX channel sync (left/right assignment) error."); + continue; + } + Err(spdifrx::Error::SourceSyncError) => { + trace!("SPDIFRX source sync error, e.g. disconnect."); + continue; + } + }; + + if sai_transmitter.write(&buf).await.is_err() { + trace!("Renew SAI."); + drop(sai_transmitter); + sai_transmitter = new_sai_transmitter( + &mut p.SAI4, + &mut p.PD13, + &mut p.PC1, + &mut p.PD12, + &mut p.BDMA_CH0, + sai_buffer, + ); + sai_transmitter.start(); + } + } +} + +/// Creates a new SPDIFRX instance for receiving sample data. +/// +/// Used (again) after dropping the SPDIFRX instance, in case of errors (e.g. source disconnect). +fn new_spdif_receiver<'d>( + spdifrx: &'d mut peripherals::SPDIFRX1, + input_pin: &'d mut peripherals::PD7, + dma: &'d mut peripherals::DMA2_CH7, + buf: &'d mut [u32], +) -> Spdifrx<'d, peripherals::SPDIFRX1> { + Spdifrx::new_data_only(spdifrx, Irqs, spdifrx::Config::default(), input_pin, dma, buf) +} + +/// Creates a new SAI4 instance for transmitting sample data. +/// +/// Used (again) after dropping the SAI4 instance, in case of errors (e.g. buffer overrun). +fn new_sai_transmitter<'d>( + sai: &'d mut peripherals::SAI4, + sck: &'d mut peripherals::PD13, + sd: &'d mut peripherals::PC1, + fs: &'d mut peripherals::PD12, + dma: &'d mut peripherals::BDMA_CH0, + buf: &'d mut [u32], +) -> Sai<'d, peripherals::SAI4, u32> { + let mut sai_config = hal::sai::Config::default(); + sai_config.slot_count = hal::sai::word::U4(CHANNEL_COUNT as u8); + sai_config.slot_enable = 0xFFFF; // All slots + sai_config.data_size = sai::DataSize::Data32; + sai_config.frame_length = (CHANNEL_COUNT * 32) as u8; + sai_config.master_clock_divider = hal::sai::MasterClockDivider::MasterClockDisabled; + + let (sub_block_tx, _) = hal::sai::split_subblocks(sai); + Sai::new_asynchronous(sub_block_tx, sck, sd, fs, dma, buf, sai_config) +} From de7fae18226e88cfeccf904974d46a51d9ed893e Mon Sep 17 00:00:00 2001 From: elagil Date: Mon, 18 Nov 2024 20:51:23 +0100 Subject: [PATCH 0366/1217] fix: enable backup symbol clock --- embassy-stm32/src/spdifrx/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/src/spdifrx/mod.rs b/embassy-stm32/src/spdifrx/mod.rs index bfc8bff29..a205780ad 100644 --- a/embassy-stm32/src/spdifrx/mod.rs +++ b/embassy-stm32/src/spdifrx/mod.rs @@ -194,7 +194,7 @@ impl<'d, T: Instance> Spdifrx<'d, T> { cr.set_cksen(true); // Generate a symbol clock. #[cfg(stm32h7)] - cr.set_cksbkpen(false); // Do not generate a backup symbol clock. + cr.set_cksbkpen(true); // Generate a backup symbol clock. }); } From e8b03b75ec9be06a4d9bc476a2ebc1e1b14ac517 Mon Sep 17 00:00:00 2001 From: elagil Date: Mon, 18 Nov 2024 20:51:23 +0100 Subject: [PATCH 0367/1217] fix: use latest SAI driver --- examples/stm32h723/src/bin/spdifrx.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/stm32h723/src/bin/spdifrx.rs b/examples/stm32h723/src/bin/spdifrx.rs index deee5ca8d..36c017592 100644 --- a/examples/stm32h723/src/bin/spdifrx.rs +++ b/examples/stm32h723/src/bin/spdifrx.rs @@ -86,7 +86,6 @@ async fn main(_spawner: Spawner) { ); spdif_receiver.start(); - sai_transmitter.start(); loop { let mut buf = [0u32; HALF_DMA_BUFFER_LENGTH]; From 99dd5e79db88cf91ee700c00cce87387c6a67d6f Mon Sep 17 00:00:00 2001 From: elagil Date: Mon, 18 Nov 2024 20:51:23 +0100 Subject: [PATCH 0368/1217] chore: update for latest SAI features --- examples/stm32h723/src/bin/spdifrx.rs | 53 +++++++++++++++------------ 1 file changed, 29 insertions(+), 24 deletions(-) diff --git a/examples/stm32h723/src/bin/spdifrx.rs b/examples/stm32h723/src/bin/spdifrx.rs index 36c017592..69ef5cd07 100644 --- a/examples/stm32h723/src/bin/spdifrx.rs +++ b/examples/stm32h723/src/bin/spdifrx.rs @@ -7,6 +7,7 @@ use defmt::{info, trace}; use embassy_executor::Spawner; +use embassy_futures::select::{self, select, Either}; use embassy_stm32::spdifrx::{self, Spdifrx}; use embassy_stm32::{bind_interrupts, peripherals, sai}; use grounded::uninit::GroundedArrayCell; @@ -75,7 +76,6 @@ async fn main(_spawner: Spawner) { core::slice::from_raw_parts_mut(ptr, len) }; - let mut spdif_receiver = new_spdif_receiver(&mut p.SPDIFRX1, &mut p.PD7, &mut p.DMA2_CH7, spdifrx_buffer); let mut sai_transmitter = new_sai_transmitter( &mut p.SAI4, &mut p.PD13, @@ -84,32 +84,15 @@ async fn main(_spawner: Spawner) { &mut p.BDMA_CH0, sai_buffer, ); - + let mut spdif_receiver = new_spdif_receiver(&mut p.SPDIFRX1, &mut p.PD7, &mut p.DMA2_CH7, spdifrx_buffer); spdif_receiver.start(); + let mut renew_sai = false; loop { let mut buf = [0u32; HALF_DMA_BUFFER_LENGTH]; - match spdif_receiver.read_data(&mut buf).await { - Ok(_) => (), - Err(spdifrx::Error::RingbufferError(_)) => { - trace!("SPDIFRX ringbuffer error. Renew."); - drop(spdif_receiver); - spdif_receiver = new_spdif_receiver(&mut p.SPDIFRX1, &mut p.PD7, &mut p.DMA2_CH7, spdifrx_buffer); - spdif_receiver.start(); - continue; - } - Err(spdifrx::Error::ChannelSyncError) => { - trace!("SPDIFRX channel sync (left/right assignment) error."); - continue; - } - Err(spdifrx::Error::SourceSyncError) => { - trace!("SPDIFRX source sync error, e.g. disconnect."); - continue; - } - }; - - if sai_transmitter.write(&buf).await.is_err() { + if renew_sai { + renew_sai = false; trace!("Renew SAI."); drop(sai_transmitter); sai_transmitter = new_sai_transmitter( @@ -120,8 +103,30 @@ async fn main(_spawner: Spawner) { &mut p.BDMA_CH0, sai_buffer, ); - sai_transmitter.start(); } + + match select(spdif_receiver.read(&mut buf), sai_transmitter.wait_write_error()).await { + Either::First(spdif_read_result) => match spdif_read_result { + Ok(_) => (), + Err(spdifrx::Error::RingbufferError(_)) => { + trace!("SPDIFRX ringbuffer error. Renew."); + drop(spdif_receiver); + spdif_receiver = new_spdif_receiver(&mut p.SPDIFRX1, &mut p.PD7, &mut p.DMA2_CH7, spdifrx_buffer); + spdif_receiver.start(); + continue; + } + Err(spdifrx::Error::ChannelSyncError) => { + trace!("SPDIFRX channel sync (left/right assignment) error."); + continue; + } + }, + Either::Second(_) => { + renew_sai = true; + continue; + } + }; + + renew_sai = sai_transmitter.write(&buf).await.is_err(); } } @@ -134,7 +139,7 @@ fn new_spdif_receiver<'d>( dma: &'d mut peripherals::DMA2_CH7, buf: &'d mut [u32], ) -> Spdifrx<'d, peripherals::SPDIFRX1> { - Spdifrx::new_data_only(spdifrx, Irqs, spdifrx::Config::default(), input_pin, dma, buf) + Spdifrx::new(spdifrx, Irqs, spdifrx::Config::default(), input_pin, dma, buf) } /// Creates a new SAI4 instance for transmitting sample data. From 1e0b6eefb79d478216d81437ec41474cbe8408e6 Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Tue, 19 Nov 2024 09:55:39 +0200 Subject: [PATCH 0369/1217] nrf: Remove leftover info message and fix link to errata --- embassy-nrf/src/gpio.rs | 1 - embassy-nrf/src/qspi.rs | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/embassy-nrf/src/gpio.rs b/embassy-nrf/src/gpio.rs index d271dbcff..130339c15 100644 --- a/embassy-nrf/src/gpio.rs +++ b/embassy-nrf/src/gpio.rs @@ -350,7 +350,6 @@ impl<'d> Flex<'d> { convert_drive(w, drive); w.set_sense(vals::Sense::DISABLED); }); - info!("pin_cnf: {:08x}", self.pin.conf().read().0); } /// Put the pin into input + output mode. diff --git a/embassy-nrf/src/qspi.rs b/embassy-nrf/src/qspi.rs index de9c268c1..255b43c33 100755 --- a/embassy-nrf/src/qspi.rs +++ b/embassy-nrf/src/qspi.rs @@ -546,7 +546,7 @@ impl<'d, T: Instance> Drop for Qspi<'d, T> { // it seems events_ready is not generated in response to deactivate. nrfx doesn't wait for it. r.tasks_deactivate().write_value(1); - // Workaround https://infocenter.nordicsemi.com/topic/errata_nRF52840_Rev1/ERR/nRF52840/Rev1/latest/anomaly_840_122.html?cp=4_0_1_2_1_7 + // Workaround https://docs.nordicsemi.com/bundle/errata_nRF52840_Rev3/page/ERR/nRF52840/Rev3/latest/anomaly_840_122.html // Note that the doc has 2 register writes, but the first one is really the write to tasks_deactivate, // so we only do the second one here. unsafe { ptr::write_volatile(0x40029054 as *mut u32, 1) } From ff02ee1a221122ede6e30a94156c42e22b400578 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Tue, 19 Nov 2024 14:39:32 +0100 Subject: [PATCH 0370/1217] Only set callback once --- embassy-executor/CHANGELOG.md | 2 ++ embassy-executor/src/raw/mod.rs | 12 +++++++----- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/embassy-executor/CHANGELOG.md b/embassy-executor/CHANGELOG.md index e07e3924f..eae5e3c2b 100644 --- a/embassy-executor/CHANGELOG.md +++ b/embassy-executor/CHANGELOG.md @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +- Only set integrated-timers callbacks once per executor. + ## 0.6.3 - 2024-11-12 - Building with the `nightly` feature now works with the Xtensa Rust compiler 1.82. diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs index d9ea5c005..e8a5b8970 100644 --- a/embassy-executor/src/raw/mod.rs +++ b/embassy-executor/src/raw/mod.rs @@ -328,7 +328,7 @@ impl SyncExecutor { #[cfg(feature = "integrated-timers")] let alarm = unsafe { unwrap!(embassy_time_driver::allocate_alarm()) }; - Self { + let this = Self { run_queue: RunQueue::new(), pender, @@ -336,7 +336,12 @@ impl SyncExecutor { timer_queue: timer_queue::TimerQueue::new(), #[cfg(feature = "integrated-timers")] alarm, - } + }; + + #[cfg(feature = "integrated-timers")] + embassy_time_driver::set_alarm_callback(this.alarm, Self::alarm_callback, &this as *const _ as *mut ()); + + this } /// Enqueue a task in the task queue @@ -374,9 +379,6 @@ impl SyncExecutor { /// /// Same as [`Executor::poll`], plus you must only call this on the thread this executor was created. pub(crate) unsafe fn poll(&'static self) { - #[cfg(feature = "integrated-timers")] - embassy_time_driver::set_alarm_callback(self.alarm, Self::alarm_callback, self as *const _ as *mut ()); - #[allow(clippy::never_loop)] loop { #[cfg(feature = "integrated-timers")] From 8ebe059ecb311ee949f92dde33f2cb8d972b0f7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Tue, 19 Nov 2024 15:59:31 +0100 Subject: [PATCH 0371/1217] Add initialize --- embassy-executor/CHANGELOG.md | 2 +- embassy-executor/src/arch/avr.rs | 4 ++++ embassy-executor/src/arch/cortex_m.rs | 6 ++++++ embassy-executor/src/arch/riscv32.rs | 4 ++++ embassy-executor/src/arch/spin.rs | 4 ++++ embassy-executor/src/arch/std.rs | 4 ++++ embassy-executor/src/arch/wasm.rs | 4 ++++ embassy-executor/src/raw/mod.rs | 21 ++++++++++++++++----- embassy-executor/tests/test.rs | 4 ++++ embassy-stm32/src/low_power.rs | 12 +++++++++--- 10 files changed, 56 insertions(+), 9 deletions(-) diff --git a/embassy-executor/CHANGELOG.md b/embassy-executor/CHANGELOG.md index eae5e3c2b..00b1bef28 100644 --- a/embassy-executor/CHANGELOG.md +++ b/embassy-executor/CHANGELOG.md @@ -7,7 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased -- Only set integrated-timers callbacks once per executor. +- `raw::Executor` now has an `fn initialize` that must be called once before starting to poll it. ## 0.6.3 - 2024-11-12 diff --git a/embassy-executor/src/arch/avr.rs b/embassy-executor/src/arch/avr.rs index 70085d04d..7f9ed4421 100644 --- a/embassy-executor/src/arch/avr.rs +++ b/embassy-executor/src/arch/avr.rs @@ -53,6 +53,10 @@ mod thread { /// /// This function never returns. pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! { + unsafe { + self.inner.initialize(); + } + init(self.inner.spawner()); loop { diff --git a/embassy-executor/src/arch/cortex_m.rs b/embassy-executor/src/arch/cortex_m.rs index 5c517e0a2..0c2af88a6 100644 --- a/embassy-executor/src/arch/cortex_m.rs +++ b/embassy-executor/src/arch/cortex_m.rs @@ -98,6 +98,9 @@ mod thread { /// /// This function never returns. pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! { + unsafe { + self.inner.initialize(); + } init(self.inner.spawner()); loop { @@ -207,6 +210,9 @@ mod interrupt { } let executor = unsafe { (&*self.executor.get()).assume_init_ref() }; + unsafe { + executor.initialize(); + } unsafe { NVIC::unmask(irq) } diff --git a/embassy-executor/src/arch/riscv32.rs b/embassy-executor/src/arch/riscv32.rs index 01e63a9fd..715e5f3cf 100644 --- a/embassy-executor/src/arch/riscv32.rs +++ b/embassy-executor/src/arch/riscv32.rs @@ -54,6 +54,10 @@ mod thread { /// /// This function never returns. pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! { + unsafe { + self.inner.initialize(); + } + init(self.inner.spawner()); loop { diff --git a/embassy-executor/src/arch/spin.rs b/embassy-executor/src/arch/spin.rs index 340023620..54c7458b3 100644 --- a/embassy-executor/src/arch/spin.rs +++ b/embassy-executor/src/arch/spin.rs @@ -48,6 +48,10 @@ mod thread { /// /// This function never returns. pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! { + unsafe { + self.inner.initialize(); + } + init(self.inner.spawner()); loop { diff --git a/embassy-executor/src/arch/std.rs b/embassy-executor/src/arch/std.rs index b02b15988..948c7711b 100644 --- a/embassy-executor/src/arch/std.rs +++ b/embassy-executor/src/arch/std.rs @@ -55,6 +55,10 @@ mod thread { /// /// This function never returns. pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! { + unsafe { + self.inner.initialize(); + } + init(self.inner.spawner()); loop { diff --git a/embassy-executor/src/arch/wasm.rs b/embassy-executor/src/arch/wasm.rs index f9d0f935c..35025f11f 100644 --- a/embassy-executor/src/arch/wasm.rs +++ b/embassy-executor/src/arch/wasm.rs @@ -70,6 +70,10 @@ mod thread { /// - a `static mut` (unsafe) /// - a local variable in a function you know never returns (like `fn main() -> !`), upgrading its lifetime with `transmute`. (unsafe) pub fn start(&'static mut self, init: impl FnOnce(Spawner)) { + unsafe { + self.inner.initialize(); + } + unsafe { let executor = &self.inner; let future = Closure::new(move |_| { diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs index e8a5b8970..ebabee1ba 100644 --- a/embassy-executor/src/raw/mod.rs +++ b/embassy-executor/src/raw/mod.rs @@ -328,7 +328,7 @@ impl SyncExecutor { #[cfg(feature = "integrated-timers")] let alarm = unsafe { unwrap!(embassy_time_driver::allocate_alarm()) }; - let this = Self { + Self { run_queue: RunQueue::new(), pender, @@ -336,12 +336,12 @@ impl SyncExecutor { timer_queue: timer_queue::TimerQueue::new(), #[cfg(feature = "integrated-timers")] alarm, - }; + } + } + pub(crate) unsafe fn initialize(&'static self) { #[cfg(feature = "integrated-timers")] - embassy_time_driver::set_alarm_callback(this.alarm, Self::alarm_callback, &this as *const _ as *mut ()); - - this + embassy_time_driver::set_alarm_callback(self.alarm, Self::alarm_callback, self as *const _ as *mut ()); } /// Enqueue a task in the task queue @@ -494,6 +494,15 @@ impl Executor { } } + /// Initializes the executor. + /// + /// # Safety + /// + /// This function must be called once before any other method is called. + pub unsafe fn initialize(&'static self) { + self.inner.initialize(); + } + /// Spawn a task in this executor. /// /// # Safety @@ -518,6 +527,8 @@ impl Executor { /// /// # Safety /// + /// You must call `initialize` before calling this method. + /// /// You must NOT call `poll` reentrantly on the same executor. /// /// In particular, note that `poll` may call the pender synchronously. Therefore, you diff --git a/embassy-executor/tests/test.rs b/embassy-executor/tests/test.rs index 348cc7dc4..8054bf7eb 100644 --- a/embassy-executor/tests/test.rs +++ b/embassy-executor/tests/test.rs @@ -40,6 +40,10 @@ fn setup() -> (&'static Executor, Trace) { let trace = Trace::new(); let context = Box::leak(Box::new(trace.clone())) as *mut _ as *mut (); let executor = &*Box::leak(Box::new(Executor::new(context))); + unsafe { + executor.initialize(); + } + (executor, trace) } diff --git a/embassy-stm32/src/low_power.rs b/embassy-stm32/src/low_power.rs index a779b8a09..d74221864 100644 --- a/embassy-stm32/src/low_power.rs +++ b/embassy-stm32/src/low_power.rs @@ -155,7 +155,9 @@ impl Executor { time_driver: get_driver(), }); - EXECUTOR.as_mut().unwrap() + let executor = EXECUTOR.as_mut().unwrap(); + + executor }) } @@ -241,11 +243,15 @@ impl Executor { /// /// This function never returns. pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! { - init(unsafe { EXECUTOR.as_mut().unwrap() }.inner.spawner()); + let executor = unsafe { EXECUTOR.as_mut().unwrap() }; + unsafe { + executor.inner.initialize(); + } + init(executor.inner.spawner()); loop { unsafe { - EXECUTOR.as_mut().unwrap().inner.poll(); + executor.inner.poll(); self.configure_pwr(); asm!("wfe"); }; From 448db47263701bf09352eaba785492baa968e76f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Tue, 19 Nov 2024 17:30:31 +0100 Subject: [PATCH 0372/1217] Remove noop from queue_generic --- embassy-time/src/queue_generic.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/embassy-time/src/queue_generic.rs b/embassy-time/src/queue_generic.rs index 4882afd3e..0068edae8 100644 --- a/embassy-time/src/queue_generic.rs +++ b/embassy-time/src/queue_generic.rs @@ -142,8 +142,6 @@ impl Queue { critical_section::with(|cs| { let mut inner = self.inner.borrow_ref_mut(cs); - if inner.is_none() {} - inner .get_or_insert_with(|| { let handle = unsafe { allocate_alarm() }.unwrap(); From 3402e76f9876d58d271501102e2d80c9b2c389b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Jacobs?= Date: Tue, 19 Nov 2024 17:26:45 +0100 Subject: [PATCH 0373/1217] stm32/timer: avoid max_compare_value >= u16::MAX With STM32 32 bits timers, the max_compare_value (AKA, ARR register) can currently be set greater than u16::MAX, which leads to the following assert!(max < u16::MAX as u32) in max_duty_cycle() when setting up a 1 kHz SimplePwm on 84 MHz MCU. The issue is fixed by forcing a max_compare_value that fits into 16 bits when setting the frequency for a PWM. --- embassy-stm32/src/timer/complementary_pwm.rs | 2 +- embassy-stm32/src/timer/low_level.rs | 24 +++++++++++++------- embassy-stm32/src/timer/simple_pwm.rs | 2 +- 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/embassy-stm32/src/timer/complementary_pwm.rs b/embassy-stm32/src/timer/complementary_pwm.rs index 46ccbf3df..02c01e900 100644 --- a/embassy-stm32/src/timer/complementary_pwm.rs +++ b/embassy-stm32/src/timer/complementary_pwm.rs @@ -116,7 +116,7 @@ impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> { } else { 1u8 }; - self.inner.set_frequency(freq * multiplier); + self.inner.set_frequency_internal(freq * multiplier, 16); } /// Get max duty value. diff --git a/embassy-stm32/src/timer/low_level.rs b/embassy-stm32/src/timer/low_level.rs index 3136ea4e9..7360d6aef 100644 --- a/embassy-stm32/src/timer/low_level.rs +++ b/embassy-stm32/src/timer/low_level.rs @@ -242,16 +242,28 @@ impl<'d, T: CoreInstance> Timer<'d, T> { /// In center-aligned mode (which not all timers support), the wrap-around frequency is effectively halved /// because it needs to count up and down. pub fn set_frequency(&self, frequency: Hertz) { + match T::BITS { + TimerBits::Bits16 => { + self.set_frequency_internal(frequency, 16); + } + #[cfg(not(stm32l0))] + TimerBits::Bits32 => { + self.set_frequency_internal(frequency, 32); + } + } + } + + pub(crate) fn set_frequency_internal(&self, frequency: Hertz, max_divide_by_bits: u8) { let f = frequency.0; assert!(f > 0); let timer_f = T::frequency().0; + let pclk_ticks_per_timer_period = (timer_f / f) as u64; + let psc: u16 = unwrap!(((pclk_ticks_per_timer_period - 1) / (1 << max_divide_by_bits)).try_into()); + let divide_by = pclk_ticks_per_timer_period / (u64::from(psc) + 1); + match T::BITS { TimerBits::Bits16 => { - let pclk_ticks_per_timer_period = timer_f / f; - let psc: u16 = unwrap!(((pclk_ticks_per_timer_period - 1) / (1 << 16)).try_into()); - let divide_by = pclk_ticks_per_timer_period / (u32::from(psc) + 1); - // the timer counts `0..=arr`, we want it to count `0..divide_by` let arr = unwrap!(u16::try_from(divide_by - 1)); @@ -265,10 +277,6 @@ impl<'d, T: CoreInstance> Timer<'d, T> { } #[cfg(not(stm32l0))] TimerBits::Bits32 => { - let pclk_ticks_per_timer_period = (timer_f / f) as u64; - let psc: u16 = unwrap!(((pclk_ticks_per_timer_period - 1) / (1 << 32)).try_into()); - let divide_by = pclk_ticks_per_timer_period / (u64::from(psc) + 1); - // the timer counts `0..=arr`, we want it to count `0..divide_by` let arr: u32 = unwrap!(u32::try_from(divide_by - 1)); diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs index 9e4a09095..56fb1871e 100644 --- a/embassy-stm32/src/timer/simple_pwm.rs +++ b/embassy-stm32/src/timer/simple_pwm.rs @@ -278,7 +278,7 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> { } else { 1u8 }; - self.inner.set_frequency(freq * multiplier); + self.inner.set_frequency_internal(freq * multiplier, 16); } /// Get max duty value. From 0740b235ac546081d54d103b0cdd018e7ef2581c Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Wed, 20 Nov 2024 23:19:37 +0100 Subject: [PATCH 0374/1217] nrf: Add NFCT driver. Co-Authored-By: turbocool3r Co-Authored-By: ferris --- embassy-nrf/src/chips/nrf52832.rs | 3 + embassy-nrf/src/chips/nrf52833.rs | 3 + embassy-nrf/src/chips/nrf52840.rs | 3 + embassy-nrf/src/chips/nrf5340_app.rs | 3 + embassy-nrf/src/lib.rs | 8 + embassy-nrf/src/nfct.rs | 409 +++++++++++++++++++++++++++ examples/nrf52840/src/bin/nfct.rs | 79 ++++++ 7 files changed, 508 insertions(+) create mode 100644 embassy-nrf/src/nfct.rs create mode 100644 examples/nrf52840/src/bin/nfct.rs diff --git a/embassy-nrf/src/chips/nrf52832.rs b/embassy-nrf/src/chips/nrf52832.rs index 7ff58d63e..2d9346229 100644 --- a/embassy-nrf/src/chips/nrf52832.rs +++ b/embassy-nrf/src/chips/nrf52832.rs @@ -161,6 +161,9 @@ embassy_hal_internal::peripherals! { EGU3, EGU4, EGU5, + + // NFC + NFCT, } impl_uarte!(UARTE0, UARTE0, UARTE0); diff --git a/embassy-nrf/src/chips/nrf52833.rs b/embassy-nrf/src/chips/nrf52833.rs index a6273452a..4e4915c32 100644 --- a/embassy-nrf/src/chips/nrf52833.rs +++ b/embassy-nrf/src/chips/nrf52833.rs @@ -181,6 +181,9 @@ embassy_hal_internal::peripherals! { EGU3, EGU4, EGU5, + + // NFC + NFCT, } impl_usb!(USBD, USBD, USBD); diff --git a/embassy-nrf/src/chips/nrf52840.rs b/embassy-nrf/src/chips/nrf52840.rs index fb341afd5..70a56971b 100644 --- a/embassy-nrf/src/chips/nrf52840.rs +++ b/embassy-nrf/src/chips/nrf52840.rs @@ -184,6 +184,9 @@ embassy_hal_internal::peripherals! { EGU3, EGU4, EGU5, + + // NFC + NFCT, } impl_usb!(USBD, USBD, USBD); diff --git a/embassy-nrf/src/chips/nrf5340_app.rs b/embassy-nrf/src/chips/nrf5340_app.rs index 6dc64fb4f..bc613e351 100644 --- a/embassy-nrf/src/chips/nrf5340_app.rs +++ b/embassy-nrf/src/chips/nrf5340_app.rs @@ -176,6 +176,9 @@ embassy_hal_internal::peripherals! { // NVMC NVMC, + // NFC + NFCT, + // UARTE, TWI & SPI SERIAL0, SERIAL1, diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index 33111e1bd..7c5dd7c83 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs @@ -86,6 +86,14 @@ pub mod gpiote; #[cfg(any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840"))] pub mod i2s; #[cfg(not(feature = "_nrf54l"))] // TODO +#[cfg(any( + feature = "nrf52832", + feature = "nrf52833", + feature = "nrf52840", + feature = "_nrf5340-app" +))] +pub mod nfct; +#[cfg(not(feature = "_nrf54l"))] // TODO pub mod nvmc; #[cfg(not(feature = "_nrf54l"))] // TODO #[cfg(any( diff --git a/embassy-nrf/src/nfct.rs b/embassy-nrf/src/nfct.rs new file mode 100644 index 000000000..2756c7952 --- /dev/null +++ b/embassy-nrf/src/nfct.rs @@ -0,0 +1,409 @@ +//! NFC tag emulator driver. +//! +//! This driver implements support for emulating an ISO14443-3 card. Anticollision and selection +//! are handled automatically in hardware, then the driver lets you receive and reply to +//! raw ISO14443-3 frames in software. +//! +//! Higher layers such as ISO14443-4 aka ISO-DEP and ISO7816 must be handled on top +//! in software. + +#![macro_use] + +use core::future::poll_fn; +use core::sync::atomic::{compiler_fence, Ordering}; +use core::task::Poll; + +use embassy_hal_internal::{into_ref, PeripheralRef}; +use embassy_sync::waitqueue::AtomicWaker; +pub use vals::{Bitframesdd as SddPat, Discardmode as DiscardMode}; + +use crate::interrupt::InterruptExt; +use crate::pac::nfct::vals; +use crate::peripherals::NFCT; +use crate::util::slice_in_ram; +use crate::{interrupt, pac, Peripheral}; + +/// NFCID1 (aka UID) of different sizes. +#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] +pub enum NfcId { + /// 4-byte UID. + SingleSize([u8; 4]), + /// 7-byte UID. + DoubleSize([u8; 7]), + /// 10-byte UID. + TripleSize([u8; 10]), +} + +/// The protocol field to be sent in the `SEL_RES` response byte (b6-b7). +#[derive(Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] +pub enum SelResProtocol { + /// Configured for Type 2 Tag platform. + #[default] + Type2 = 0, + /// Configured for Type 4A Tag platform, compliant with ISO/IEC_14443. + Type4A = 1, + /// Configured for the NFC-DEP Protocol. + NfcDep = 2, + /// Configured for the NFC-DEP Protocol and Type 4A Tag platform. + NfcDepAndType4A = 3, +} + +/// Config for the `NFCT` peripheral driver. +#[derive(Clone)] +pub struct Config { + /// NFCID1 to use during autocollision. + pub nfcid1: NfcId, + /// SDD pattern to be sent in `SENS_RES`. + pub sdd_pat: SddPat, + /// Platform config to be sent in `SEL_RES`. + pub plat_conf: u8, + /// Protocol to be sent in the `SEL_RES` response. + pub protocol: SelResProtocol, +} + +/// Interrupt handler. +pub struct InterruptHandler { + _private: (), +} + +impl interrupt::typelevel::Handler for InterruptHandler { + unsafe fn on_interrupt() { + trace!("irq"); + pac::NFCT.inten().write(|w| w.0 = 0); + WAKER.wake(); + } +} + +static WAKER: AtomicWaker = AtomicWaker::new(); + +/// NFC error. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[non_exhaustive] +pub enum Error { + /// Rx Error received while waiting for frame + RxError, + /// Rx buffer was overrun, increase your buffer size to resolve this + RxOverrun, + /// Lost field. + Deactivated, + /// Collision + Collision, + /// The buffer is not in data RAM. It's most likely in flash, and nRF's DMA cannot access flash. + BufferNotInRAM, +} + +/// NFC tag emulator driver. +pub struct NfcT<'d> { + _p: PeripheralRef<'d, NFCT>, + rx_buf: [u8; 256], + tx_buf: [u8; 256], +} + +impl<'d> NfcT<'d> { + /// Create an Nfc Tag driver + pub fn new( + _p: impl Peripheral

+ 'd, + _irq: impl interrupt::typelevel::Binding + 'd, + config: &Config, + ) -> Self { + into_ref!(_p); + + let r = pac::NFCT; + + unsafe { + let reset = (r.as_ptr() as *mut u32).add(0xFFC / 4); + reset.write_volatile(0); + reset.read_volatile(); + reset.write_volatile(1); + } + + let nfcid_size = match &config.nfcid1 { + NfcId::SingleSize(bytes) => { + r.nfcid1_last().write(|w| w.0 = u32::from_be_bytes(*bytes)); + + vals::Nfcidsize::NFCID1SINGLE + } + NfcId::DoubleSize(bytes) => { + let (bytes, chunk) = bytes.split_last_chunk::<4>().unwrap(); + r.nfcid1_last().write(|w| w.0 = u32::from_be_bytes(*chunk)); + + let mut chunk = [0u8; 4]; + chunk[1..].copy_from_slice(bytes); + r.nfcid1_2nd_last().write(|w| w.0 = u32::from_be_bytes(chunk)); + + vals::Nfcidsize::NFCID1DOUBLE + } + NfcId::TripleSize(bytes) => { + let (bytes, chunk) = bytes.split_last_chunk::<4>().unwrap(); + r.nfcid1_last().write(|w| w.0 = u32::from_be_bytes(*chunk)); + + let (bytes, chunk2) = bytes.split_last_chunk::<3>().unwrap(); + let mut chunk = [0u8; 4]; + chunk[1..].copy_from_slice(chunk2); + r.nfcid1_2nd_last().write(|w| w.0 = u32::from_be_bytes(chunk)); + + let mut chunk = [0u8; 4]; + chunk[1..].copy_from_slice(bytes); + r.nfcid1_3rd_last().write(|w| w.0 = u32::from_be_bytes(chunk)); + + vals::Nfcidsize::NFCID1TRIPLE + } + }; + + r.sensres().write(|w| { + w.set_nfcidsize(nfcid_size); + w.set_bitframesdd(config.sdd_pat); + w.set_platfconfig(config.plat_conf & 0xF); + }); + + r.selres().write(|w| { + w.set_protocol(config.protocol as u8); + }); + + // errata + #[cfg(feature = "nrf52832")] + unsafe { + // Errata 57 nrf52832 only + //(0x40005610 as *mut u32).write_volatile(0x00000005); + //(0x40005688 as *mut u32).write_volatile(0x00000001); + //(0x40005618 as *mut u32).write_volatile(0x00000000); + //(0x40005614 as *mut u32).write_volatile(0x0000003F); + + // Errata 98 + (0x4000568C as *mut u32).write_volatile(0x00038148); + } + + r.inten().write(|w| w.0 = 0); + + interrupt::NFCT.unpend(); + unsafe { interrupt::NFCT.enable() }; + + // clear all shorts + r.shorts().write(|_| {}); + + let res = Self { + _p, + tx_buf: [0u8; 256], + rx_buf: [0u8; 256], + }; + + assert!(slice_in_ram(&res.tx_buf), "TX Buf not in ram"); + assert!(slice_in_ram(&res.rx_buf), "RX Buf not in ram"); + + res + } + + /// Wait for field on and select. + /// + /// This waits for the field to become on, and then for a reader to select us. The ISO14443-3 + /// sense, anticollision and select procedure is handled entirely in hardware. + /// + /// When this returns, we have successfully been selected as a card. You must then + /// loop calling [`receive`](Self::receive) and responding with [`transmit`](Self::transmit). + pub async fn activate(&mut self) { + let r = pac::NFCT; + loop { + r.events_fieldlost().write_value(0); + r.events_fielddetected().write_value(0); + r.tasks_sense().write_value(1); + + // enable autocoll + #[cfg(not(feature = "nrf52832"))] + r.autocolresconfig().write(|w| w.0 = 0b10); + + r.framedelaymode().write(|w| { + w.set_framedelaymode(vals::Framedelaymode::WINDOW_GRID); + }); + + info!("waiting for field"); + poll_fn(|cx| { + WAKER.register(cx.waker()); + + if r.events_fielddetected().read() != 0 { + r.events_fielddetected().write_value(0); + return Poll::Ready(()); + } + + r.inten().write(|w| { + w.set_fielddetected(true); + }); + Poll::Pending + }) + .await; + + #[cfg(feature = "time")] + embassy_time::Timer::after_millis(1).await; // workaround errata 190 + + r.events_selected().write_value(0); + r.tasks_activate().write_value(1); + + trace!("Waiting to be selected"); + poll_fn(|cx| { + let r = pac::NFCT; + + WAKER.register(cx.waker()); + + if r.events_selected().read() != 0 || r.events_fieldlost().read() != 0 { + return Poll::Ready(()); + } + + r.inten().write(|w| { + w.set_selected(true); + w.set_fieldlost(true); + }); + Poll::Pending + }) + .await; + if r.events_fieldlost().read() != 0 { + continue; + } + + // TODO: add support for "window" frame delay, which is technically + // needed to be compliant with iso14443-4 + r.framedelaymode().write(|w| { + w.set_framedelaymode(vals::Framedelaymode::FREE_RUN); + }); + + // disable autocoll + #[cfg(not(feature = "nrf52832"))] + r.autocolresconfig().write(|w| w.0 = 0b11u32); + + return; + } + } + + /// Transmit an ISO14443-3 frame to the reader. + /// + /// You must call this only after receiving a frame with [`receive`](Self::receive), + /// and only once. Higher-layer protocols usually define timeouts, so calling this + /// too late can cause things to fail. + /// + /// This will fail with [`Error::Deactivated`] if we have been deselected due to either + /// the field being switched off or due to the ISO14443 state machine. When this happens, + /// you must stop calling [`receive`](Self::receive) and [`transmit`](Self::transmit), reset + /// all protocol state, and go back to calling [`activate`](Self::activate). + pub async fn transmit(&mut self, buf: &[u8]) -> Result<(), Error> { + let r = pac::NFCT; + + //Setup DMA + self.tx_buf[..buf.len()].copy_from_slice(buf); + r.packetptr().write_value(self.tx_buf.as_ptr() as u32); + r.maxlen().write(|w| w.0 = buf.len() as _); + + // Set packet length + r.txd().amount().write(|w| { + w.set_txdatabits(0); + w.set_txdatabytes(buf.len() as _); + }); + + r.txd().frameconfig().write(|w| { + w.set_crcmodetx(true); + w.set_discardmode(DiscardMode::DISCARD_END); + w.set_parity(true); + w.set_sof(true); + }); + + r.events_error().write_value(0); + r.events_txframeend().write_value(0); + r.errorstatus().write(|w| w.0 = 0xffff_ffff); + + // Start starttx task + compiler_fence(Ordering::SeqCst); + r.tasks_starttx().write_value(1); + + poll_fn(move |cx| { + trace!("polling tx"); + let r = pac::NFCT; + WAKER.register(cx.waker()); + + if r.events_fieldlost().read() != 0 { + return Poll::Ready(Err(Error::Deactivated)); + } + + if r.events_txframeend().read() != 0 { + trace!("Txframend hit, should be finished trasmitting"); + return Poll::Ready(Ok(())); + } + + if r.events_error().read() != 0 { + trace!("Got error?"); + warn!("errors: {:08x}", r.errorstatus().read().0); + r.events_error().write_value(0); + return Poll::Ready(Err(Error::RxError)); + } + + r.inten().write(|w| { + w.set_txframeend(true); + w.set_error(true); + w.set_fieldlost(true); + }); + + Poll::Pending + }) + .await + } + + /// Receive an ISO14443-3 frame from the reader. + /// + /// After calling this, you must send back a response with [`transmit`](Self::transmit), + /// and only once. Higher-layer protocols usually define timeouts, so calling this + /// too late can cause things to fail. + pub async fn receive(&mut self, buf: &mut [u8]) -> Result { + let r = pac::NFCT; + + r.rxd().frameconfig().write(|w| { + w.set_crcmoderx(true); + w.set_parity(true); + w.set_sof(true); + }); + + //Setup DMA + r.packetptr().write_value(self.rx_buf.as_mut_ptr() as u32); + r.maxlen().write(|w| w.0 = self.rx_buf.len() as _); + + // Reset and enable the end event + r.events_rxframeend().write_value(0); + r.events_rxerror().write_value(0); + + // Start enablerxdata only after configs are finished writing + compiler_fence(Ordering::SeqCst); + r.tasks_enablerxdata().write_value(1); + + poll_fn(move |cx| { + trace!("polling rx"); + let r = pac::NFCT; + WAKER.register(cx.waker()); + + if r.events_fieldlost().read() != 0 { + return Poll::Ready(Err(Error::Deactivated)); + } + + if r.events_rxerror().read() != 0 { + trace!("RXerror got in recv frame, should be back in idle state"); + r.events_rxerror().write_value(0); + warn!("errors: {:08x}", r.errorstatus().read().0); + return Poll::Ready(Err(Error::RxError)); + } + + if r.events_rxframeend().read() != 0 { + trace!("RX Frameend got in recv frame, should have data"); + r.events_rxframeend().write_value(0); + return Poll::Ready(Ok(())); + } + + r.inten().write(|w| { + w.set_rxframeend(true); + w.set_rxerror(true); + w.set_fieldlost(true); + }); + + Poll::Pending + }) + .await?; + + let n = r.rxd().amount().read().rxdatabytes() as usize - 2; + buf[..n].copy_from_slice(&self.rx_buf[..n]); + Ok(n) + } +} diff --git a/examples/nrf52840/src/bin/nfct.rs b/examples/nrf52840/src/bin/nfct.rs new file mode 100644 index 000000000..d559d006a --- /dev/null +++ b/examples/nrf52840/src/bin/nfct.rs @@ -0,0 +1,79 @@ +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_nrf::config::HfclkSource; +use embassy_nrf::nfct::{Config as NfcConfig, NfcId, NfcT}; +use embassy_nrf::{bind_interrupts, nfct}; +use {defmt_rtt as _, embassy_nrf as _, panic_probe as _}; + +bind_interrupts!(struct Irqs { + NFCT => nfct::InterruptHandler; +}); + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let mut config = embassy_nrf::config::Config::default(); + config.hfclk_source = HfclkSource::ExternalXtal; + let p = embassy_nrf::init(config); + + dbg!("Setting up..."); + let config = NfcConfig { + nfcid1: NfcId::DoubleSize([0x04, 0x68, 0x95, 0x71, 0xFA, 0x5C, 0x64]), + sdd_pat: nfct::SddPat::SDD00100, + plat_conf: 0b0000, + protocol: nfct::SelResProtocol::Type4A, + }; + + let mut nfc = NfcT::new(p.NFCT, Irqs, &config); + + let mut buf = [0u8; 256]; + + loop { + info!("activating"); + nfc.activate().await; + + loop { + info!("rxing"); + let n = match nfc.receive(&mut buf).await { + Ok(n) => n, + Err(e) => { + error!("rx error {}", e); + break; + } + }; + let req = &buf[..n]; + info!("received frame {:02x}", req); + + let mut deselect = false; + let resp = match req { + [0xe0, ..] => { + info!("Got RATS, tx'ing ATS"); + &[0x06, 0x77, 0x77, 0x81, 0x02, 0x80][..] + } + [0xc2] => { + info!("Got deselect!"); + deselect = true; + &[0xc2] + } + _ => { + info!("Got unknown command!"); + &[0xFF] + } + }; + + match nfc.transmit(resp).await { + Ok(()) => {} + Err(e) => { + error!("tx error {}", e); + break; + } + } + + if deselect { + break; + } + } + } +} From be6eec772673ae6c46a6a022838b78cdc167bae4 Mon Sep 17 00:00:00 2001 From: Joseph <239260+simryang@users.noreply.github.com> Date: Thu, 21 Nov 2024 09:46:10 +0900 Subject: [PATCH 0375/1217] Update README.md (#3553) Fixed broken link to w5500-evb-pico --- embassy-net-wiznet/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-net-wiznet/README.md b/embassy-net-wiznet/README.md index 786aab18d..b66619821 100644 --- a/embassy-net-wiznet/README.md +++ b/embassy-net-wiznet/README.md @@ -2,7 +2,7 @@ [`embassy-net`](https://crates.io/crates/embassy-net) integration for the WIZnet SPI ethernet chips, operating in MACRAW mode. -See [`examples`](https://github.com/embassy-rs/embassy/tree/main/examples/rp) directory for usage examples with the rp2040 [`WIZnet W5500-EVB-Pico`](https://www.wiznet.io/product-item/w5500-evb-pico/) module. +See [`examples`](https://github.com/embassy-rs/embassy/tree/main/examples/rp) directory for usage examples with the rp2040 [`WIZnet W5500-EVB-Pico`](https://docs.wiznet.io/Product/iEthernet/W5500/w5500-evb-pico)) module. ## Supported chips From f598cae3766cd24894e665c145181a5bbeac24c2 Mon Sep 17 00:00:00 2001 From: Christian Enderle Date: Thu, 21 Nov 2024 12:12:00 +0100 Subject: [PATCH 0376/1217] compute lse and lsi frequency for STM32L and STM32U0 series --- embassy-stm32/src/rcc/l.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/rcc/l.rs b/embassy-stm32/src/rcc/l.rs index 6120d33be..8223a657b 100644 --- a/embassy-stm32/src/rcc/l.rs +++ b/embassy-stm32/src/rcc/l.rs @@ -5,6 +5,7 @@ use crate::pac::rcc::regs::Cfgr; pub use crate::pac::rcc::vals::Hsepre as HsePrescaler; pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Msirange as MSIRange, Ppre as APBPrescaler, Sw as Sysclk}; use crate::pac::{FLASH, RCC}; +use crate::rcc::LSI_FREQ; use crate::time::Hertz; /// HSI speed @@ -182,6 +183,9 @@ pub(crate) unsafe fn init(config: Config) { let rtc = config.ls.init(); + let lse = config.ls.lse.map(|l| l.frequency); + let lsi = config.ls.lsi.then_some(LSI_FREQ); + let msi = config.msi.map(|range| { msi_enable(range); msirange_to_hertz(range) @@ -425,12 +429,12 @@ pub(crate) unsafe fn init(config: Config) { dsi_phy: None, // DSI PLL clock not supported, don't call `RccPeripheral::frequency()` in the drivers rtc: rtc, + lse: lse, + lsi: lsi, // TODO sai1_extclk: None, sai2_extclk: None, - lsi: None, - lse: None, ); } From bd65906d149719ef3da214e72876b13579e8d392 Mon Sep 17 00:00:00 2001 From: Gabriel Smith Date: Thu, 21 Nov 2024 17:23:46 -0500 Subject: [PATCH 0377/1217] STM32H5xx ADC (#3557) * stm32: Update STM32 data source * stm32h5: Add ADC example --- embassy-stm32/Cargo.toml | 4 +-- embassy-stm32/src/lib.rs | 2 +- examples/stm32h5/src/bin/adc.rs | 59 +++++++++++++++++++++++++++++++++ 3 files changed, 62 insertions(+), 3 deletions(-) create mode 100644 examples/stm32h5/src/bin/adc.rs diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 4fe4ff358..91d218da4 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -72,7 +72,7 @@ rand_core = "0.6.3" sdio-host = "0.5.0" critical-section = "1.1" #stm32-metapac = { version = "15" } -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-7bb5f235587c3a6886a7be1c8f58fdf22c5257f3" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-55b491ee982e52f80a21276a0ccbde4907982b5d" } vcell = "0.1.3" nb = "1.0.0" @@ -101,7 +101,7 @@ proc-macro2 = "1.0.36" quote = "1.0.15" #stm32-metapac = { version = "15", default-features = false, features = ["metadata"]} -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-7bb5f235587c3a6886a7be1c8f58fdf22c5257f3", default-features = false, features = ["metadata"] } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-55b491ee982e52f80a21276a0ccbde4907982b5d", default-features = false, features = ["metadata"] } [features] default = ["rt"] diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index e189351d1..39f3dfd61 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -440,7 +440,7 @@ fn init_hw(config: Config) -> Peripherals { cr.set_stop(config.enable_debug_during_sleep); cr.set_standby(config.enable_debug_during_sleep); } - #[cfg(any(dbgmcu_f0, dbgmcu_c0, dbgmcu_g0, dbgmcu_u5, dbgmcu_wba, dbgmcu_l5))] + #[cfg(any(dbgmcu_f0, dbgmcu_c0, dbgmcu_g0, dbgmcu_u0, dbgmcu_u5, dbgmcu_wba, dbgmcu_l5))] { cr.set_dbg_stop(config.enable_debug_during_sleep); cr.set_dbg_standby(config.enable_debug_during_sleep); diff --git a/examples/stm32h5/src/bin/adc.rs b/examples/stm32h5/src/bin/adc.rs new file mode 100644 index 000000000..c5d508ece --- /dev/null +++ b/examples/stm32h5/src/bin/adc.rs @@ -0,0 +1,59 @@ +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::adc::{Adc, SampleTime}; +use embassy_stm32::Config; +use embassy_time::Timer; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let mut config = Config::default(); + { + use embassy_stm32::rcc::*; + config.rcc.hsi = Some(HSIPrescaler::DIV1); + config.rcc.csi = true; + config.rcc.pll1 = Some(Pll { + source: PllSource::HSI, + prediv: PllPreDiv::DIV4, + mul: PllMul::MUL25, + divp: Some(PllDiv::DIV2), + divq: Some(PllDiv::DIV4), // SPI1 cksel defaults to pll1_q + divr: None, + }); + config.rcc.pll2 = Some(Pll { + source: PllSource::HSI, + prediv: PllPreDiv::DIV4, + mul: PllMul::MUL25, + divp: None, + divq: None, + divr: Some(PllDiv::DIV4), // 100mhz + }); + config.rcc.sys = Sysclk::PLL1_P; // 200 Mhz + config.rcc.ahb_pre = AHBPrescaler::DIV1; // 200 Mhz + config.rcc.apb1_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.apb2_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.voltage_scale = VoltageScale::Scale1; + config.rcc.mux.adcdacsel = mux::Adcdacsel::PLL2_R; + } + let mut p = embassy_stm32::init(config); + + info!("Hello World!"); + + let mut adc = Adc::new(p.ADC1); + + adc.set_sample_time(SampleTime::CYCLES24_5); + + let mut vrefint_channel = adc.enable_vrefint(); + + loop { + let vrefint = adc.blocking_read(&mut vrefint_channel); + info!("vrefint: {}", vrefint); + let measured = adc.blocking_read(&mut p.PA0); + info!("measured: {}", measured); + Timer::after_millis(500).await; + } +} From e05f6da2692f2b61986ef2b77789e27d68e4e74a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Fri, 22 Nov 2024 09:21:44 +0100 Subject: [PATCH 0378/1217] Generalize AtomicWaker --- embassy-sync/CHANGELOG.md | 1 + embassy-sync/src/waitqueue/atomic_waker.rs | 42 ++++++++++++++++------ 2 files changed, 33 insertions(+), 10 deletions(-) diff --git a/embassy-sync/CHANGELOG.md b/embassy-sync/CHANGELOG.md index a7dd6f66e..d12f0a74a 100644 --- a/embassy-sync/CHANGELOG.md +++ b/embassy-sync/CHANGELOG.md @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Add `clear`, `len`, `is_empty` and `is_full` functions to `zerocopy_channel`. - Add `capacity`, `free_capacity`, `clear`, `len`, `is_empty` and `is_full` functions to `channel::{Sender, Receiver}`. - Add `capacity`, `free_capacity`, `clear`, `len`, `is_empty` and `is_full` functions to `priority_channel::{Sender, Receiver}`. +- Add `GenericAtomicWaker` utility. ## 0.6.0 - 2024-05-29 diff --git a/embassy-sync/src/waitqueue/atomic_waker.rs b/embassy-sync/src/waitqueue/atomic_waker.rs index 63fe04a6e..231902c5a 100644 --- a/embassy-sync/src/waitqueue/atomic_waker.rs +++ b/embassy-sync/src/waitqueue/atomic_waker.rs @@ -1,26 +1,25 @@ use core::cell::Cell; use core::task::Waker; -use crate::blocking_mutex::raw::CriticalSectionRawMutex; +use crate::blocking_mutex::raw::{CriticalSectionRawMutex, RawMutex}; use crate::blocking_mutex::Mutex; /// Utility struct to register and wake a waker. -pub struct AtomicWaker { - waker: Mutex>>, +pub struct GenericAtomicWaker { + waker: Mutex>>, } -impl AtomicWaker { +impl GenericAtomicWaker { /// Create a new `AtomicWaker`. - pub const fn new() -> Self { + pub const fn new(mutex: M) -> Self { Self { - waker: Mutex::const_new(CriticalSectionRawMutex::new(), Cell::new(None)), + waker: Mutex::const_new(mutex, Cell::new(None)), } } /// Register a waker. Overwrites the previous waker, if any. pub fn register(&self, w: &Waker) { - critical_section::with(|cs| { - let cell = self.waker.borrow(cs); + self.waker.lock(|cell| { cell.set(match cell.replace(None) { Some(w2) if (w2.will_wake(w)) => Some(w2), _ => Some(w.clone()), @@ -30,8 +29,7 @@ impl AtomicWaker { /// Wake the registered waker, if any. pub fn wake(&self) { - critical_section::with(|cs| { - let cell = self.waker.borrow(cs); + self.waker.lock(|cell| { if let Some(w) = cell.replace(None) { w.wake_by_ref(); cell.set(Some(w)); @@ -39,3 +37,27 @@ impl AtomicWaker { }) } } + +/// Utility struct to register and wake a waker. +pub struct AtomicWaker { + waker: GenericAtomicWaker, +} + +impl AtomicWaker { + /// Create a new `AtomicWaker`. + pub const fn new() -> Self { + Self { + waker: GenericAtomicWaker::new(CriticalSectionRawMutex::new()), + } + } + + /// Register a waker. Overwrites the previous waker, if any. + pub fn register(&self, w: &Waker) { + self.waker.register(w); + } + + /// Wake the registered waker, if any. + pub fn wake(&self) { + self.waker.wake(); + } +} From 48fd80919a3248e8e6ce5f188cd0364f9fb3dc85 Mon Sep 17 00:00:00 2001 From: Christian Enderle Date: Thu, 21 Nov 2024 19:41:41 +0100 Subject: [PATCH 0379/1217] rcc: enable lse for stm32u0 --- embassy-stm32/src/rcc/bd.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/rcc/bd.rs b/embassy-stm32/src/rcc/bd.rs index 4aec3756f..791367954 100644 --- a/embassy-stm32/src/rcc/bd.rs +++ b/embassy-stm32/src/rcc/bd.rs @@ -159,6 +159,9 @@ impl LsConfig { } else { None }; + #[cfg(rcc_u0)] + let lse_sysen = Some(lse_en); + _ = lse_drv; // not all chips have it. // Disable backup domain write protection @@ -199,7 +202,7 @@ impl LsConfig { } ok &= reg.lseon() == lse_en; ok &= reg.lsebyp() == lse_byp; - #[cfg(any(rcc_l5, rcc_u5, rcc_wle, rcc_wl5, rcc_wba))] + #[cfg(any(rcc_l5, rcc_u5, rcc_wle, rcc_wl5, rcc_wba, rcc_u0))] if let Some(lse_sysen) = lse_sysen { ok &= reg.lsesysen() == lse_sysen; } @@ -251,7 +254,7 @@ impl LsConfig { while !bdcr().read().lserdy() {} - #[cfg(any(rcc_l5, rcc_u5, rcc_wle, rcc_wl5, rcc_wba))] + #[cfg(any(rcc_l5, rcc_u5, rcc_wle, rcc_wl5, rcc_wba, rcc_u0))] if let Some(lse_sysen) = lse_sysen { bdcr().modify(|w| { w.set_lsesysen(lse_sysen); From 29934237a5d6fa783a3f7a83ab569c8aef9b95fe Mon Sep 17 00:00:00 2001 From: Christian Enderle Date: Thu, 21 Nov 2024 19:44:01 +0100 Subject: [PATCH 0380/1217] rtc: reorganize low-power SealedInstance --- embassy-stm32/src/rtc/v3.rs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/embassy-stm32/src/rtc/v3.rs b/embassy-stm32/src/rtc/v3.rs index 12cb10bc7..a15d6ddc8 100644 --- a/embassy-stm32/src/rtc/v3.rs +++ b/embassy-stm32/src/rtc/v3.rs @@ -133,14 +133,20 @@ impl SealedInstance for crate::peripherals::RTC { cfg_if::cfg_if!( if #[cfg(stm32g4)] { const EXTI_WAKEUP_LINE: usize = 20; - type WakeupInterrupt = crate::interrupt::typelevel::RTC_WKUP; } else if #[cfg(stm32g0)] { const EXTI_WAKEUP_LINE: usize = 19; - type WakeupInterrupt = crate::interrupt::typelevel::RTC_TAMP; } else if #[cfg(any(stm32l5, stm32h5))] { const EXTI_WAKEUP_LINE: usize = 17; - type WakeupInterrupt = crate::interrupt::typelevel::RTC; - } else if #[cfg(stm32u5)] { + } + ); + + #[cfg(feature = "low-power")] + cfg_if::cfg_if!( + if #[cfg(stm32g4)] { + type WakeupInterrupt = crate::interrupt::typelevel::RTC_WKUP; + } else if #[cfg(any(stm32g0))] { + type WakeupInterrupt = crate::interrupt::typelevel::RTC_TAMP; + } else if #[cfg(any(stm32l5, stm32h5, stm32u5))] { type WakeupInterrupt = crate::interrupt::typelevel::RTC; } ); From a49289ce7be3e0d213d26acc1055c37bcb98f4ba Mon Sep 17 00:00:00 2001 From: Christian Enderle Date: Thu, 21 Nov 2024 19:44:48 +0100 Subject: [PATCH 0381/1217] low-power: add basic support for stm32u0 --- embassy-stm32/src/low_power.rs | 11 +++++++++++ embassy-stm32/src/rtc/low_power.rs | 6 +++--- embassy-stm32/src/rtc/mod.rs | 2 +- embassy-stm32/src/rtc/v3.rs | 2 +- 4 files changed, 16 insertions(+), 5 deletions(-) diff --git a/embassy-stm32/src/low_power.rs b/embassy-stm32/src/low_power.rs index d74221864..1423c9538 100644 --- a/embassy-stm32/src/low_power.rs +++ b/embassy-stm32/src/low_power.rs @@ -80,6 +80,17 @@ foreach_interrupt! { }; } +// only relevant for stm32u0 +foreach_interrupt! { + (RTC, rtc, $block:ident, TAMP, $irq:ident) => { + #[interrupt] + #[allow(non_snake_case)] + unsafe fn $irq() { + EXECUTOR.as_mut().unwrap().on_wakeup_irq(); + } + }; +} + #[allow(dead_code)] pub(crate) unsafe fn on_wakeup_irq() { EXECUTOR.as_mut().unwrap().on_wakeup_irq(); diff --git a/embassy-stm32/src/rtc/low_power.rs b/embassy-stm32/src/rtc/low_power.rs index bba359f31..5bf8742de 100644 --- a/embassy-stm32/src/rtc/low_power.rs +++ b/embassy-stm32/src/rtc/low_power.rs @@ -65,7 +65,7 @@ pub(crate) enum WakeupPrescaler { Div16 = 16, } -#[cfg(any(stm32f4, stm32l0, stm32g4, stm32l4, stm32l5, stm32wb, stm32h5, stm32g0, stm32u5))] +#[cfg(any(stm32f4, stm32l0, stm32g4, stm32l4, stm32l5, stm32wb, stm32h5, stm32g0, stm32u5, stm32u0))] impl From for crate::pac::rtc::vals::Wucksel { fn from(val: WakeupPrescaler) -> Self { use crate::pac::rtc::vals::Wucksel; @@ -79,7 +79,7 @@ impl From for crate::pac::rtc::vals::Wucksel { } } -#[cfg(any(stm32f4, stm32l0, stm32g4, stm32l4, stm32l5, stm32wb, stm32h5, stm32g0, stm32u5))] +#[cfg(any(stm32f4, stm32l0, stm32g4, stm32l4, stm32l5, stm32wb, stm32h5, stm32g0, stm32u5, stm32u0))] impl From for WakeupPrescaler { fn from(val: crate::pac::rtc::vals::Wucksel) -> Self { use crate::pac::rtc::vals::Wucksel; @@ -223,7 +223,7 @@ impl Rtc { ::WakeupInterrupt::unpend(); unsafe { ::WakeupInterrupt::enable() }; - #[cfg(not(stm32u5))] + #[cfg(not(any(stm32u5, stm32u0)))] { use crate::pac::EXTI; EXTI.rtsr(0).modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true)); diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs index 3722d11ab..1a668cb37 100644 --- a/embassy-stm32/src/rtc/mod.rs +++ b/embassy-stm32/src/rtc/mod.rs @@ -285,7 +285,7 @@ trait SealedInstance { const BACKUP_REGISTER_COUNT: usize; #[cfg(feature = "low-power")] - #[cfg(not(stm32u5))] + #[cfg(not(any(stm32u5, stm32u0)))] const EXTI_WAKEUP_LINE: usize; #[cfg(feature = "low-power")] diff --git a/embassy-stm32/src/rtc/v3.rs b/embassy-stm32/src/rtc/v3.rs index a15d6ddc8..d543955a4 100644 --- a/embassy-stm32/src/rtc/v3.rs +++ b/embassy-stm32/src/rtc/v3.rs @@ -144,7 +144,7 @@ impl SealedInstance for crate::peripherals::RTC { cfg_if::cfg_if!( if #[cfg(stm32g4)] { type WakeupInterrupt = crate::interrupt::typelevel::RTC_WKUP; - } else if #[cfg(any(stm32g0))] { + } else if #[cfg(any(stm32g0, stm32u0))] { type WakeupInterrupt = crate::interrupt::typelevel::RTC_TAMP; } else if #[cfg(any(stm32l5, stm32h5, stm32u5))] { type WakeupInterrupt = crate::interrupt::typelevel::RTC; From 1fbb419f72a2663b472f31ae1e172bec0e4e6d1a Mon Sep 17 00:00:00 2001 From: Christian Enderle Date: Thu, 21 Nov 2024 19:49:32 +0100 Subject: [PATCH 0382/1217] low-power: add support for stop for stm32u0 --- embassy-stm32/src/low_power.rs | 9 +++++---- embassy-stm32/src/rtc/low_power.rs | 8 ++++++-- embassy-stm32/src/rtc/v3.rs | 2 +- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/embassy-stm32/src/low_power.rs b/embassy-stm32/src/low_power.rs index 1423c9538..0b87bd95a 100644 --- a/embassy-stm32/src/low_power.rs +++ b/embassy-stm32/src/low_power.rs @@ -70,6 +70,7 @@ use crate::rtc::Rtc; static mut EXECUTOR: Option = None; +#[cfg(not(stm32u0))] foreach_interrupt! { (RTC, rtc, $block:ident, WKUP, $irq:ident) => { #[interrupt] @@ -80,7 +81,7 @@ foreach_interrupt! { }; } -// only relevant for stm32u0 +#[cfg(stm32u0)] foreach_interrupt! { (RTC, rtc, $block:ident, TAMP, $irq:ident) => { #[interrupt] @@ -123,10 +124,10 @@ pub enum StopMode { Stop2, } -#[cfg(any(stm32l4, stm32l5, stm32u5))] +#[cfg(any(stm32l4, stm32l5, stm32u5, stm32u0))] use stm32_metapac::pwr::vals::Lpms; -#[cfg(any(stm32l4, stm32l5, stm32u5))] +#[cfg(any(stm32l4, stm32l5, stm32u5, stm32u0))] impl Into for StopMode { fn into(self) -> Lpms { match self { @@ -197,7 +198,7 @@ impl Executor { #[allow(unused_variables)] fn configure_stop(&mut self, stop_mode: StopMode) { - #[cfg(any(stm32l4, stm32l5, stm32u5))] + #[cfg(any(stm32l4, stm32l5, stm32u5, stm32u0))] crate::pac::PWR.cr1().modify(|m| m.set_lpms(stop_mode.into())); #[cfg(stm32h5)] crate::pac::PWR.pmcr().modify(|v| { diff --git a/embassy-stm32/src/rtc/low_power.rs b/embassy-stm32/src/rtc/low_power.rs index 5bf8742de..cf7c4bb28 100644 --- a/embassy-stm32/src/rtc/low_power.rs +++ b/embassy-stm32/src/rtc/low_power.rs @@ -65,7 +65,9 @@ pub(crate) enum WakeupPrescaler { Div16 = 16, } -#[cfg(any(stm32f4, stm32l0, stm32g4, stm32l4, stm32l5, stm32wb, stm32h5, stm32g0, stm32u5, stm32u0))] +#[cfg(any( + stm32f4, stm32l0, stm32g4, stm32l4, stm32l5, stm32wb, stm32h5, stm32g0, stm32u5, stm32u0 +))] impl From for crate::pac::rtc::vals::Wucksel { fn from(val: WakeupPrescaler) -> Self { use crate::pac::rtc::vals::Wucksel; @@ -79,7 +81,9 @@ impl From for crate::pac::rtc::vals::Wucksel { } } -#[cfg(any(stm32f4, stm32l0, stm32g4, stm32l4, stm32l5, stm32wb, stm32h5, stm32g0, stm32u5, stm32u0))] +#[cfg(any( + stm32f4, stm32l0, stm32g4, stm32l4, stm32l5, stm32wb, stm32h5, stm32g0, stm32u5, stm32u0 +))] impl From for WakeupPrescaler { fn from(val: crate::pac::rtc::vals::Wucksel) -> Self { use crate::pac::rtc::vals::Wucksel; diff --git a/embassy-stm32/src/rtc/v3.rs b/embassy-stm32/src/rtc/v3.rs index d543955a4..de2c202bc 100644 --- a/embassy-stm32/src/rtc/v3.rs +++ b/embassy-stm32/src/rtc/v3.rs @@ -139,7 +139,7 @@ impl SealedInstance for crate::peripherals::RTC { const EXTI_WAKEUP_LINE: usize = 17; } ); - + #[cfg(feature = "low-power")] cfg_if::cfg_if!( if #[cfg(stm32g4)] { From c9abff53d77dfc71deb597ce93f358e25588775a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Fri, 22 Nov 2024 21:16:11 +0100 Subject: [PATCH 0383/1217] Bump sync version (#3562) * Bump sync version * Use old embassy-sync in rp bluetooth example * Downgrade update to minor --- cyw43/Cargo.toml | 2 +- embassy-boot-nrf/Cargo.toml | 2 +- embassy-boot-rp/Cargo.toml | 2 +- embassy-boot-stm32/Cargo.toml | 2 +- embassy-boot/Cargo.toml | 2 +- embassy-embedded-hal/Cargo.toml | 2 +- embassy-net-driver-channel/Cargo.toml | 2 +- embassy-net-esp-hosted/Cargo.toml | 2 +- embassy-net-nrf91/Cargo.toml | 2 +- embassy-net-ppp/Cargo.toml | 2 +- embassy-net/Cargo.toml | 2 +- embassy-nrf/Cargo.toml | 2 +- embassy-nxp/Cargo.toml | 2 +- embassy-rp/Cargo.toml | 2 +- embassy-stm32-wpan/Cargo.toml | 2 +- embassy-stm32/Cargo.toml | 2 +- embassy-sync/CHANGELOG.md | 2 +- embassy-sync/Cargo.toml | 2 +- embassy-usb-dfu/Cargo.toml | 2 +- embassy-usb-logger/Cargo.toml | 2 +- embassy-usb-synopsys-otg/Cargo.toml | 2 +- embassy-usb/Cargo.toml | 2 +- examples/boot/application/nrf/Cargo.toml | 2 +- examples/boot/application/rp/Cargo.toml | 2 +- examples/boot/application/stm32f3/Cargo.toml | 2 +- examples/boot/application/stm32f7/Cargo.toml | 2 +- examples/boot/application/stm32h7/Cargo.toml | 2 +- examples/boot/application/stm32l0/Cargo.toml | 2 +- examples/boot/application/stm32l1/Cargo.toml | 2 +- examples/boot/application/stm32l4/Cargo.toml | 2 +- examples/boot/application/stm32wb-dfu/Cargo.toml | 2 +- examples/boot/application/stm32wl/Cargo.toml | 2 +- examples/boot/bootloader/nrf/Cargo.toml | 2 +- examples/boot/bootloader/rp/Cargo.toml | 2 +- examples/boot/bootloader/stm32-dual-bank/Cargo.toml | 2 +- examples/boot/bootloader/stm32/Cargo.toml | 2 +- examples/boot/bootloader/stm32wb-dfu/Cargo.toml | 2 +- examples/lpc55s69/Cargo.toml | 2 +- examples/nrf-rtos-trace/Cargo.toml | 2 +- examples/nrf52810/Cargo.toml | 2 +- examples/nrf52840-rtic/Cargo.toml | 2 +- examples/nrf52840/Cargo.toml | 2 +- examples/nrf5340/Cargo.toml | 2 +- examples/rp/Cargo.toml | 2 +- examples/rp23/Cargo.toml | 2 +- examples/std/Cargo.toml | 2 +- examples/stm32c0/Cargo.toml | 2 +- examples/stm32f0/Cargo.toml | 2 +- examples/stm32f1/Cargo.toml | 2 +- examples/stm32f2/Cargo.toml | 2 +- examples/stm32f3/Cargo.toml | 2 +- examples/stm32f334/Cargo.toml | 2 +- examples/stm32f4/Cargo.toml | 2 +- examples/stm32f7/Cargo.toml | 2 +- examples/stm32g0/Cargo.toml | 2 +- examples/stm32g4/Cargo.toml | 2 +- examples/stm32h5/Cargo.toml | 2 +- examples/stm32h7/Cargo.toml | 2 +- examples/stm32h723/Cargo.toml | 2 +- examples/stm32h735/Cargo.toml | 2 +- examples/stm32h755cm4/Cargo.toml | 2 +- examples/stm32h755cm7/Cargo.toml | 2 +- examples/stm32h7b0/Cargo.toml | 2 +- examples/stm32h7rs/Cargo.toml | 2 +- examples/stm32l0/Cargo.toml | 2 +- examples/stm32l1/Cargo.toml | 2 +- examples/stm32l4/Cargo.toml | 2 +- examples/stm32l5/Cargo.toml | 2 +- examples/stm32u0/Cargo.toml | 2 +- examples/stm32u5/Cargo.toml | 2 +- examples/stm32wb/Cargo.toml | 2 +- examples/stm32wba/Cargo.toml | 2 +- examples/stm32wl/Cargo.toml | 2 +- examples/wasm/Cargo.toml | 2 +- tests/nrf/Cargo.toml | 2 +- tests/riscv32/Cargo.toml | 2 +- tests/rp/Cargo.toml | 2 +- tests/stm32/Cargo.toml | 2 +- 78 files changed, 78 insertions(+), 78 deletions(-) diff --git a/cyw43/Cargo.toml b/cyw43/Cargo.toml index 751e59a69..7c0260868 100644 --- a/cyw43/Cargo.toml +++ b/cyw43/Cargo.toml @@ -19,7 +19,7 @@ firmware-logs = [] [dependencies] embassy-time = { version = "0.3.2", path = "../embassy-time"} -embassy-sync = { version = "0.6.0", path = "../embassy-sync"} +embassy-sync = { version = "0.6.1", path = "../embassy-sync"} embassy-futures = { version = "0.1.0", path = "../embassy-futures"} embassy-net-driver-channel = { version = "0.3.0", path = "../embassy-net-driver-channel"} diff --git a/embassy-boot-nrf/Cargo.toml b/embassy-boot-nrf/Cargo.toml index 27407ae92..dd5c0780e 100644 --- a/embassy-boot-nrf/Cargo.toml +++ b/embassy-boot-nrf/Cargo.toml @@ -24,7 +24,7 @@ target = "thumbv7em-none-eabi" defmt = { version = "0.3", optional = true } log = { version = "0.4.17", optional = true } -embassy-sync = { version = "0.6.0", path = "../embassy-sync" } +embassy-sync = { version = "0.6.1", path = "../embassy-sync" } embassy-nrf = { version = "0.2.0", path = "../embassy-nrf", default-features = false } embassy-boot = { version = "0.3.0", path = "../embassy-boot" } cortex-m = { version = "0.7.6" } diff --git a/embassy-boot-rp/Cargo.toml b/embassy-boot-rp/Cargo.toml index bf5f34abe..fa603047e 100644 --- a/embassy-boot-rp/Cargo.toml +++ b/embassy-boot-rp/Cargo.toml @@ -24,7 +24,7 @@ features = ["embassy-rp/rp2040"] defmt = { version = "0.3", optional = true } log = { version = "0.4", optional = true } -embassy-sync = { version = "0.6.0", path = "../embassy-sync" } +embassy-sync = { version = "0.6.1", path = "../embassy-sync" } embassy-rp = { version = "0.2.0", path = "../embassy-rp", default-features = false } embassy-boot = { version = "0.3.0", path = "../embassy-boot" } embassy-time = { version = "0.3.2", path = "../embassy-time" } diff --git a/embassy-boot-stm32/Cargo.toml b/embassy-boot-stm32/Cargo.toml index e4ef9a612..1afdde75a 100644 --- a/embassy-boot-stm32/Cargo.toml +++ b/embassy-boot-stm32/Cargo.toml @@ -24,7 +24,7 @@ target = "thumbv7em-none-eabi" defmt = { version = "0.3", optional = true } log = { version = "0.4", optional = true } -embassy-sync = { version = "0.6.0", path = "../embassy-sync" } +embassy-sync = { version = "0.6.1", path = "../embassy-sync" } embassy-stm32 = { version = "0.1.0", path = "../embassy-stm32", default-features = false } embassy-boot = { version = "0.3.0", path = "../embassy-boot" } cortex-m = { version = "0.7.6" } diff --git a/embassy-boot/Cargo.toml b/embassy-boot/Cargo.toml index 79ba6456a..b385020cc 100644 --- a/embassy-boot/Cargo.toml +++ b/embassy-boot/Cargo.toml @@ -29,7 +29,7 @@ digest = "0.10" log = { version = "0.4", optional = true } ed25519-dalek = { version = "2", default-features = false, features = ["digest"], optional = true } embassy-embedded-hal = { version = "0.2.0", path = "../embassy-embedded-hal" } -embassy-sync = { version = "0.6.0", path = "../embassy-sync" } +embassy-sync = { version = "0.6.1", path = "../embassy-sync" } embedded-storage = "0.3.1" embedded-storage-async = { version = "0.4.1" } salty = { version = "0.3", optional = true } diff --git a/embassy-embedded-hal/Cargo.toml b/embassy-embedded-hal/Cargo.toml index 345dc3420..b7728c411 100644 --- a/embassy-embedded-hal/Cargo.toml +++ b/embassy-embedded-hal/Cargo.toml @@ -28,7 +28,7 @@ default = ["time"] [dependencies] embassy-futures = { version = "0.1.0", path = "../embassy-futures" } -embassy-sync = { version = "0.6.0", path = "../embassy-sync" } +embassy-sync = { version = "0.6.1", path = "../embassy-sync" } embassy-time = { version = "0.3.2", path = "../embassy-time", optional = true } embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = [ "unproven", diff --git a/embassy-net-driver-channel/Cargo.toml b/embassy-net-driver-channel/Cargo.toml index abce9315b..cabc0c38f 100644 --- a/embassy-net-driver-channel/Cargo.toml +++ b/embassy-net-driver-channel/Cargo.toml @@ -25,6 +25,6 @@ features = ["defmt"] defmt = { version = "0.3", optional = true } log = { version = "0.4.14", optional = true } -embassy-sync = { version = "0.6.0", path = "../embassy-sync" } +embassy-sync = { version = "0.6.1", path = "../embassy-sync" } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver" } diff --git a/embassy-net-esp-hosted/Cargo.toml b/embassy-net-esp-hosted/Cargo.toml index 915eba7a0..d22ccb101 100644 --- a/embassy-net-esp-hosted/Cargo.toml +++ b/embassy-net-esp-hosted/Cargo.toml @@ -18,7 +18,7 @@ defmt = { version = "0.3", optional = true } log = { version = "0.4.14", optional = true } embassy-time = { version = "0.3.2", path = "../embassy-time" } -embassy-sync = { version = "0.6.0", path = "../embassy-sync"} +embassy-sync = { version = "0.6.1", path = "../embassy-sync"} embassy-futures = { version = "0.1.0", path = "../embassy-futures"} embassy-net-driver-channel = { version = "0.3.0", path = "../embassy-net-driver-channel"} diff --git a/embassy-net-nrf91/Cargo.toml b/embassy-net-nrf91/Cargo.toml index bc31f93f4..f9e55c0b1 100644 --- a/embassy-net-nrf91/Cargo.toml +++ b/embassy-net-nrf91/Cargo.toml @@ -21,7 +21,7 @@ nrf-pac = { git = "https://github.com/embassy-rs/nrf-pac", rev = "52e3a757f06035 cortex-m = "0.7.7" embassy-time = { version = "0.3.1", path = "../embassy-time" } -embassy-sync = { version = "0.6.0", path = "../embassy-sync"} +embassy-sync = { version = "0.6.1", path = "../embassy-sync"} embassy-futures = { version = "0.1.0", path = "../embassy-futures"} embassy-net-driver-channel = { version = "0.3.0", path = "../embassy-net-driver-channel"} diff --git a/embassy-net-ppp/Cargo.toml b/embassy-net-ppp/Cargo.toml index d2f43ef45..9c214d5ae 100644 --- a/embassy-net-ppp/Cargo.toml +++ b/embassy-net-ppp/Cargo.toml @@ -21,7 +21,7 @@ embedded-io-async = { version = "0.6.1" } embassy-net-driver-channel = { version = "0.3.0", path = "../embassy-net-driver-channel" } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } ppproto = { version = "0.2.0"} -embassy-sync = { version = "0.6.0", path = "../embassy-sync" } +embassy-sync = { version = "0.6.1", path = "../embassy-sync" } [package.metadata.embassy_docs] src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-ppp-v$VERSION/embassy-net-ppp/src/" diff --git a/embassy-net/Cargo.toml b/embassy-net/Cargo.toml index 1090892e0..2c33ecc14 100644 --- a/embassy-net/Cargo.toml +++ b/embassy-net/Cargo.toml @@ -75,7 +75,7 @@ smoltcp = { git="https://github.com/smoltcp-rs/smoltcp", rev="fe0b4d102253465850 embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver" } embassy-time = { version = "0.3.2", path = "../embassy-time" } -embassy-sync = { version = "0.6.0", path = "../embassy-sync" } +embassy-sync = { version = "0.6.1", path = "../embassy-sync" } embedded-io-async = { version = "0.6.1" } managed = { version = "0.8.0", default-features = false, features = [ "map" ] } diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml index 9e62bcca4..9da050a22 100644 --- a/embassy-nrf/Cargo.toml +++ b/embassy-nrf/Cargo.toml @@ -136,7 +136,7 @@ _nrf52832_anomaly_109 = [] [dependencies] embassy-time-driver = { version = "0.1", path = "../embassy-time-driver", optional = true } embassy-time = { version = "0.3.2", path = "../embassy-time", optional = true } -embassy-sync = { version = "0.6.0", path = "../embassy-sync" } +embassy-sync = { version = "0.6.1", path = "../embassy-sync" } embassy-hal-internal = {version = "0.2.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-3"] } embassy-embedded-hal = {version = "0.2.0", path = "../embassy-embedded-hal" } embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver" } diff --git a/embassy-nxp/Cargo.toml b/embassy-nxp/Cargo.toml index df329be66..b0f73b63c 100644 --- a/embassy-nxp/Cargo.toml +++ b/embassy-nxp/Cargo.toml @@ -8,7 +8,7 @@ cortex-m = "0.7.7" cortex-m-rt = "0.7.0" critical-section = "1.1.2" embassy-hal-internal = {version = "0.2.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-2"] } -embassy-sync = { version = "0.6.0", path = "../embassy-sync" } +embassy-sync = { version = "0.6.1", path = "../embassy-sync" } lpc55-pac = "0.5.0" defmt = "0.3.8" diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index 401ecd215..3809f1894 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml @@ -108,7 +108,7 @@ _test = [] binary-info = ["rt", "dep:rp-binary-info", "rp-binary-info?/binary-info"] [dependencies] -embassy-sync = { version = "0.6.0", path = "../embassy-sync" } +embassy-sync = { version = "0.6.1", path = "../embassy-sync" } embassy-time-driver = { version = "0.1", path = "../embassy-time-driver", optional = true } embassy-time = { version = "0.3.2", path = "../embassy-time" } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } diff --git a/embassy-stm32-wpan/Cargo.toml b/embassy-stm32-wpan/Cargo.toml index 54dfd39a6..7dd1bc677 100644 --- a/embassy-stm32-wpan/Cargo.toml +++ b/embassy-stm32-wpan/Cargo.toml @@ -20,7 +20,7 @@ features = ["stm32wb55rg"] [dependencies] embassy-stm32 = { version = "0.1.0", path = "../embassy-stm32" } -embassy-sync = { version = "0.6.0", path = "../embassy-sync" } +embassy-sync = { version = "0.6.1", path = "../embassy-sync" } embassy-time = { version = "0.3.2", path = "../embassy-time", optional = true } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } embassy-hal-internal = { version = "0.2.0", path = "../embassy-hal-internal" } diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 91d218da4..0872afbd9 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -42,7 +42,7 @@ features = ["defmt", "unstable-pac", "exti", "time-driver-any", "time", "stm32h7 rustdoc-args = ["--cfg", "docsrs"] [dependencies] -embassy-sync = { version = "0.6.0", path = "../embassy-sync" } +embassy-sync = { version = "0.6.1", path = "../embassy-sync" } embassy-time = { version = "0.3.2", path = "../embassy-time", optional = true } embassy-time-driver = { version = "0.1", path = "../embassy-time-driver", optional = true } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } diff --git a/embassy-sync/CHANGELOG.md b/embassy-sync/CHANGELOG.md index d12f0a74a..a7547422f 100644 --- a/embassy-sync/CHANGELOG.md +++ b/embassy-sync/CHANGELOG.md @@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## Unreleased +## 0.6.1 - 2024-11-22 - Add `LazyLock` sync primitive. - Add `Watch` sync primitive. diff --git a/embassy-sync/Cargo.toml b/embassy-sync/Cargo.toml index 2f049b6bc..1bd2f290e 100644 --- a/embassy-sync/Cargo.toml +++ b/embassy-sync/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "embassy-sync" -version = "0.6.0" +version = "0.6.1" edition = "2021" description = "no-std, no-alloc synchronization primitives with async support" repository = "https://github.com/embassy-rs/embassy" diff --git a/embassy-usb-dfu/Cargo.toml b/embassy-usb-dfu/Cargo.toml index 481b2699a..16da468bd 100644 --- a/embassy-usb-dfu/Cargo.toml +++ b/embassy-usb-dfu/Cargo.toml @@ -33,7 +33,7 @@ bitflags = "2.4.1" cortex-m = { version = "0.7.7", features = ["inline-asm"], optional = true } embassy-boot = { version = "0.3.0", path = "../embassy-boot" } embassy-futures = { version = "0.1.1", path = "../embassy-futures" } -embassy-sync = { version = "0.6.0", path = "../embassy-sync" } +embassy-sync = { version = "0.6.1", path = "../embassy-sync" } embassy-time = { version = "0.3.2", path = "../embassy-time" } embassy-usb = { version = "0.3.0", path = "../embassy-usb", default-features = false } embedded-storage = { version = "0.3.1" } diff --git a/embassy-usb-logger/Cargo.toml b/embassy-usb-logger/Cargo.toml index d796e5d8e..d5147de49 100644 --- a/embassy-usb-logger/Cargo.toml +++ b/embassy-usb-logger/Cargo.toml @@ -16,6 +16,6 @@ target = "thumbv7em-none-eabi" [dependencies] embassy-usb = { version = "0.3.0", path = "../embassy-usb" } -embassy-sync = { version = "0.6.0", path = "../embassy-sync" } +embassy-sync = { version = "0.6.1", path = "../embassy-sync" } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } log = "0.4" diff --git a/embassy-usb-synopsys-otg/Cargo.toml b/embassy-usb-synopsys-otg/Cargo.toml index 68ab0415f..d621577bf 100644 --- a/embassy-usb-synopsys-otg/Cargo.toml +++ b/embassy-usb-synopsys-otg/Cargo.toml @@ -18,7 +18,7 @@ target = "thumbv7em-none-eabi" [dependencies] critical-section = "1.1" -embassy-sync = { version = "0.6.0", path = "../embassy-sync" } +embassy-sync = { version = "0.6.1", path = "../embassy-sync" } embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver" } defmt = { version = "0.3", optional = true } diff --git a/embassy-usb/Cargo.toml b/embassy-usb/Cargo.toml index e310d8bae..9abf2f200 100644 --- a/embassy-usb/Cargo.toml +++ b/embassy-usb/Cargo.toml @@ -48,7 +48,7 @@ max-handler-count-8 = [] [dependencies] embassy-futures = { version = "0.1.0", path = "../embassy-futures" } embassy-usb-driver = { version = "0.1.0", path = "../embassy-usb-driver" } -embassy-sync = { version = "0.6.0", path = "../embassy-sync" } +embassy-sync = { version = "0.6.1", path = "../embassy-sync" } embassy-net-driver-channel = { version = "0.3.0", path = "../embassy-net-driver-channel" } defmt = { version = "0.3", optional = true } diff --git a/examples/boot/application/nrf/Cargo.toml b/examples/boot/application/nrf/Cargo.toml index 3bf33d212..046571e05 100644 --- a/examples/boot/application/nrf/Cargo.toml +++ b/examples/boot/application/nrf/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } +embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } embassy-executor = { version = "0.6.3", path = "../../../../embassy-executor", features = ["task-arena-size-16384", "arch-cortex-m", "executor-thread", "integrated-timers", "arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [] } embassy-nrf = { version = "0.2.0", path = "../../../../embassy-nrf", features = ["time-driver-rtc1", "gpiote", ] } diff --git a/examples/boot/application/rp/Cargo.toml b/examples/boot/application/rp/Cargo.toml index 85515abc5..f859ddbc6 100644 --- a/examples/boot/application/rp/Cargo.toml +++ b/examples/boot/application/rp/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } +embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } embassy-executor = { version = "0.6.3", path = "../../../../embassy-executor", features = ["task-arena-size-16384", "arch-cortex-m", "executor-thread", "integrated-timers", "arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [] } embassy-rp = { version = "0.2.0", path = "../../../../embassy-rp", features = ["time-driver", "rp2040"] } diff --git a/examples/boot/application/stm32f3/Cargo.toml b/examples/boot/application/stm32f3/Cargo.toml index 45394f1d5..d5b26d698 100644 --- a/examples/boot/application/stm32f3/Cargo.toml +++ b/examples/boot/application/stm32f3/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } +embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } embassy-executor = { version = "0.6.3", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32f303re", "time-driver-any", "exti"] } diff --git a/examples/boot/application/stm32f7/Cargo.toml b/examples/boot/application/stm32f7/Cargo.toml index 8bb6c5df3..d13692aa8 100644 --- a/examples/boot/application/stm32f7/Cargo.toml +++ b/examples/boot/application/stm32f7/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } +embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } embassy-executor = { version = "0.6.3", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32f767zi", "time-driver-any", "exti"] } diff --git a/examples/boot/application/stm32h7/Cargo.toml b/examples/boot/application/stm32h7/Cargo.toml index 85d3af65f..a2de827aa 100644 --- a/examples/boot/application/stm32h7/Cargo.toml +++ b/examples/boot/application/stm32h7/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } +embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } embassy-executor = { version = "0.6.3", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32h743zi", "time-driver-any", "exti"] } diff --git a/examples/boot/application/stm32l0/Cargo.toml b/examples/boot/application/stm32l0/Cargo.toml index a8a6f0bab..ddfddf652 100644 --- a/examples/boot/application/stm32l0/Cargo.toml +++ b/examples/boot/application/stm32l0/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } +embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } embassy-executor = { version = "0.6.3", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l072cz", "time-driver-any", "exti", "memory-x"] } diff --git a/examples/boot/application/stm32l1/Cargo.toml b/examples/boot/application/stm32l1/Cargo.toml index 0a8447aa6..4780c20f4 100644 --- a/examples/boot/application/stm32l1/Cargo.toml +++ b/examples/boot/application/stm32l1/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } +embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } embassy-executor = { version = "0.6.3", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l151cb-a", "time-driver-any", "exti"] } diff --git a/examples/boot/application/stm32l4/Cargo.toml b/examples/boot/application/stm32l4/Cargo.toml index 1b5d33f78..0a31d6b62 100644 --- a/examples/boot/application/stm32l4/Cargo.toml +++ b/examples/boot/application/stm32l4/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } +embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } embassy-executor = { version = "0.6.3", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l475vg", "time-driver-any", "exti"] } diff --git a/examples/boot/application/stm32wb-dfu/Cargo.toml b/examples/boot/application/stm32wb-dfu/Cargo.toml index cde4a3ae6..67f6bde11 100644 --- a/examples/boot/application/stm32wb-dfu/Cargo.toml +++ b/examples/boot/application/stm32wb-dfu/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } +embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } embassy-executor = { version = "0.6.3", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32wb55rg", "time-driver-any", "exti"] } diff --git a/examples/boot/application/stm32wl/Cargo.toml b/examples/boot/application/stm32wl/Cargo.toml index 8e94051ce..da27d4601 100644 --- a/examples/boot/application/stm32wl/Cargo.toml +++ b/examples/boot/application/stm32wl/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } +embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } embassy-executor = { version = "0.6.3", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32wl55jc-cm4", "time-driver-any", "exti"] } diff --git a/examples/boot/bootloader/nrf/Cargo.toml b/examples/boot/bootloader/nrf/Cargo.toml index 9d5d51a13..c2e8bbe53 100644 --- a/examples/boot/bootloader/nrf/Cargo.toml +++ b/examples/boot/bootloader/nrf/Cargo.toml @@ -12,7 +12,7 @@ defmt-rtt = { version = "0.4", optional = true } embassy-nrf = { path = "../../../../embassy-nrf", features = [] } embassy-boot-nrf = { path = "../../../../embassy-boot-nrf" } cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } -embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } +embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } cortex-m-rt = { version = "0.7" } cfg-if = "1.0.0" diff --git a/examples/boot/bootloader/rp/Cargo.toml b/examples/boot/bootloader/rp/Cargo.toml index 9df396e5e..24df3da82 100644 --- a/examples/boot/bootloader/rp/Cargo.toml +++ b/examples/boot/bootloader/rp/Cargo.toml @@ -11,7 +11,7 @@ defmt-rtt = { version = "0.4", optional = true } embassy-rp = { path = "../../../../embassy-rp", features = ["rp2040"] } embassy-boot-rp = { path = "../../../../embassy-boot-rp" } -embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } +embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } embassy-time = { path = "../../../../embassy-time", features = [] } cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } diff --git a/examples/boot/bootloader/stm32-dual-bank/Cargo.toml b/examples/boot/bootloader/stm32-dual-bank/Cargo.toml index b91b05412..81e0026c6 100644 --- a/examples/boot/bootloader/stm32-dual-bank/Cargo.toml +++ b/examples/boot/bootloader/stm32-dual-bank/Cargo.toml @@ -15,7 +15,7 @@ cortex-m = { version = "0.7.6", features = [ "inline-asm", "critical-section-single-core", ] } -embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } +embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } cortex-m-rt = { version = "0.7" } embedded-storage = "0.3.1" embedded-storage-async = "0.4.0" diff --git a/examples/boot/bootloader/stm32/Cargo.toml b/examples/boot/bootloader/stm32/Cargo.toml index 541186949..f35e4e713 100644 --- a/examples/boot/bootloader/stm32/Cargo.toml +++ b/examples/boot/bootloader/stm32/Cargo.toml @@ -12,7 +12,7 @@ defmt-rtt = { version = "0.4", optional = true } embassy-stm32 = { path = "../../../../embassy-stm32", features = [] } embassy-boot-stm32 = { path = "../../../../embassy-boot-stm32" } cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } -embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } +embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } cortex-m-rt = { version = "0.7" } embedded-storage = "0.3.1" embedded-storage-async = "0.4.0" diff --git a/examples/boot/bootloader/stm32wb-dfu/Cargo.toml b/examples/boot/bootloader/stm32wb-dfu/Cargo.toml index 050b672ce..1431e7cc3 100644 --- a/examples/boot/bootloader/stm32wb-dfu/Cargo.toml +++ b/examples/boot/bootloader/stm32wb-dfu/Cargo.toml @@ -12,7 +12,7 @@ defmt-rtt = { version = "0.4", optional = true } embassy-stm32 = { path = "../../../../embassy-stm32", features = [] } embassy-boot-stm32 = { path = "../../../../embassy-boot-stm32" } cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } -embassy-sync = { version = "0.6.0", path = "../../../../embassy-sync" } +embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } cortex-m-rt = { version = "0.7" } embedded-storage = "0.3.1" embedded-storage-async = "0.4.0" diff --git a/examples/lpc55s69/Cargo.toml b/examples/lpc55s69/Cargo.toml index ee0c09dd3..41a88f082 100644 --- a/examples/lpc55s69/Cargo.toml +++ b/examples/lpc55s69/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-nxp = { version = "0.1.0", path = "../../embassy-nxp", features = ["rt"] } embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt"] } -embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt"] } panic-halt = "0.2.0" cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } diff --git a/examples/nrf-rtos-trace/Cargo.toml b/examples/nrf-rtos-trace/Cargo.toml index ae8d62100..449056409 100644 --- a/examples/nrf-rtos-trace/Cargo.toml +++ b/examples/nrf-rtos-trace/Cargo.toml @@ -15,7 +15,7 @@ log = [ ] [dependencies] -embassy-sync = { version = "0.6.0", path = "../../embassy-sync" } +embassy-sync = { version = "0.6.1", path = "../../embassy-sync" } embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "rtos-trace", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time" } embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] } diff --git a/examples/nrf52810/Cargo.toml b/examples/nrf52810/Cargo.toml index 3cc88ed7e..b0b73417b 100644 --- a/examples/nrf52810/Cargo.toml +++ b/examples/nrf52810/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } -embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf52810", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } diff --git a/examples/nrf52840-rtic/Cargo.toml b/examples/nrf52840-rtic/Cargo.toml index 7fae7aefc..290b2fdb1 100644 --- a/examples/nrf52840-rtic/Cargo.toml +++ b/examples/nrf52840-rtic/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" rtic = { version = "2", features = ["thumbv7-backend"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } -embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = [ "defmt", "defmt-timestamp-uptime", "generic-queue"] } embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = [ "defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } diff --git a/examples/nrf52840/Cargo.toml b/examples/nrf52840/Cargo.toml index 9ac6e3594..9623c04b5 100644 --- a/examples/nrf52840/Cargo.toml +++ b/examples/nrf52840/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } -embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } diff --git a/examples/nrf5340/Cargo.toml b/examples/nrf5340/Cargo.toml index 9103db907..8c8f74d15 100644 --- a/examples/nrf5340/Cargo.toml +++ b/examples/nrf5340/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } -embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf5340-app-s", "time-driver-rtc1", "gpiote", "unstable-pac"] } diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index 7e3b6812d..1448306a1 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal", features = ["defmt"] } -embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-98304", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-rp = { version = "0.2.0", path = "../../embassy-rp", features = ["defmt", "unstable-pac", "time-driver", "critical-section-impl", "rp2040"] } diff --git a/examples/rp23/Cargo.toml b/examples/rp23/Cargo.toml index 3ea92f208..6738339c0 100644 --- a/examples/rp23/Cargo.toml +++ b/examples/rp23/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal", features = ["defmt"] } -embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-98304", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-rp = { version = "0.2.0", path = "../../embassy-rp", features = ["defmt", "unstable-pac", "time-driver", "critical-section-impl", "rp235xa", "binary-info"] } diff --git a/examples/std/Cargo.toml b/examples/std/Cargo.toml index 6e918366c..f6b209d06 100644 --- a/examples/std/Cargo.toml +++ b/examples/std/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["log"] } +embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["log"] } embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-std", "executor-thread", "log", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["log", "std", ] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features=[ "std", "log", "medium-ethernet", "medium-ip", "tcp", "udp", "dns", "dhcpv4", "proto-ipv6"] } diff --git a/examples/stm32c0/Cargo.toml b/examples/stm32c0/Cargo.toml index 06f11ef00..895e668da 100644 --- a/examples/stm32c0/Cargo.toml +++ b/examples/stm32c0/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32c031c6 to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32c031c6", "memory-x", "unstable-pac", "exti"] } -embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } diff --git a/examples/stm32f0/Cargo.toml b/examples/stm32f0/Cargo.toml index d80a7503b..056f8470d 100644 --- a/examples/stm32f0/Cargo.toml +++ b/examples/stm32f0/Cargo.toml @@ -12,7 +12,7 @@ cortex-m-rt = "0.7.0" defmt = "0.3" defmt-rtt = "0.4" panic-probe = { version = "0.3", features = ["print-defmt"] } -embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } static_cell = "2" diff --git a/examples/stm32f1/Cargo.toml b/examples/stm32f1/Cargo.toml index 846dcfd7c..c081333d7 100644 --- a/examples/stm32f1/Cargo.toml +++ b/examples/stm32f1/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32f103c8 to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f103c8", "unstable-pac", "memory-x", "time-driver-any" ] } -embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/stm32f2/Cargo.toml b/examples/stm32f2/Cargo.toml index ad87c973b..f7993497c 100644 --- a/examples/stm32f2/Cargo.toml +++ b/examples/stm32f2/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32f207zg to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f207zg", "unstable-pac", "memory-x", "time-driver-any", "exti"] } -embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } diff --git a/examples/stm32f3/Cargo.toml b/examples/stm32f3/Cargo.toml index 9c97e32d3..a7b8935a9 100644 --- a/examples/stm32f3/Cargo.toml +++ b/examples/stm32f3/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32f303ze to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f303ze", "unstable-pac", "memory-x", "time-driver-tim2", "exti"] } -embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/stm32f334/Cargo.toml b/examples/stm32f334/Cargo.toml index 548ec1289..ed8348772 100644 --- a/examples/stm32f334/Cargo.toml +++ b/examples/stm32f334/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f334r8", "unstable-pac", "memory-x", "time-driver-any", "exti"] } diff --git a/examples/stm32f4/Cargo.toml b/examples/stm32f4/Cargo.toml index cb8392922..75e315e82 100644 --- a/examples/stm32f4/Cargo.toml +++ b/examples/stm32f4/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32f429zi to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32f429zi", "unstable-pac", "memory-x", "time-driver-tim4", "exti", "chrono"] } -embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt" ] } diff --git a/examples/stm32f7/Cargo.toml b/examples/stm32f7/Cargo.toml index 4f24d0eda..822d8152d 100644 --- a/examples/stm32f7/Cargo.toml +++ b/examples/stm32f7/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32f777zi to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32f777zi", "memory-x", "unstable-pac", "time-driver-any", "exti"] } -embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } diff --git a/examples/stm32g0/Cargo.toml b/examples/stm32g0/Cargo.toml index ed74f1ba9..66cac1885 100644 --- a/examples/stm32g0/Cargo.toml +++ b/examples/stm32g0/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32g0b1re to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32g0b1re", "memory-x", "unstable-pac", "exti"] } -embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", default-features = false, features = ["defmt"] } diff --git a/examples/stm32g4/Cargo.toml b/examples/stm32g4/Cargo.toml index 3d5dd8069..36bef4787 100644 --- a/examples/stm32g4/Cargo.toml +++ b/examples/stm32g4/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32g491re to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32g491re", "memory-x", "unstable-pac", "exti"] } -embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/stm32h5/Cargo.toml b/examples/stm32h5/Cargo.toml index c71ad2db0..91ca43845 100644 --- a/examples/stm32h5/Cargo.toml +++ b/examples/stm32h5/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32h563zi to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h563zi", "memory-x", "time-driver-any", "exti", "unstable-pac", "low-power"] } -embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6"] } diff --git a/examples/stm32h7/Cargo.toml b/examples/stm32h7/Cargo.toml index 4a82d487f..949cefe1e 100644 --- a/examples/stm32h7/Cargo.toml +++ b/examples/stm32h7/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32h743bi to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h743bi", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } -embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } diff --git a/examples/stm32h723/Cargo.toml b/examples/stm32h723/Cargo.toml index 8ebc1051f..f68c91597 100644 --- a/examples/stm32h723/Cargo.toml +++ b/examples/stm32h723/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32h723zg to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h723zg", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } -embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32h735/Cargo.toml b/examples/stm32h735/Cargo.toml index e66e344d2..a9c66ec48 100644 --- a/examples/stm32h735/Cargo.toml +++ b/examples/stm32h735/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h735ig", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } -embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } diff --git a/examples/stm32h755cm4/Cargo.toml b/examples/stm32h755cm4/Cargo.toml index 8b46c3952..18a17dbaf 100644 --- a/examples/stm32h755cm4/Cargo.toml +++ b/examples/stm32h755cm4/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32h755zi-cm4 to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h755zi-cm4", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } -embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } diff --git a/examples/stm32h755cm7/Cargo.toml b/examples/stm32h755cm7/Cargo.toml index 1db5143a4..02f1fcbaf 100644 --- a/examples/stm32h755cm7/Cargo.toml +++ b/examples/stm32h755cm7/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32h743bi to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h755zi-cm7", "time-driver-tim3", "exti", "memory-x", "unstable-pac", "chrono"] } -embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } diff --git a/examples/stm32h7b0/Cargo.toml b/examples/stm32h7b0/Cargo.toml index e22548bf0..78f65a4cc 100644 --- a/examples/stm32h7b0/Cargo.toml +++ b/examples/stm32h7b0/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h7b0vb", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } -embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } diff --git a/examples/stm32h7rs/Cargo.toml b/examples/stm32h7rs/Cargo.toml index 07c69977d..60013cb88 100644 --- a/examples/stm32h7rs/Cargo.toml +++ b/examples/stm32h7rs/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32h743bi to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h7s3l8", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } -embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } diff --git a/examples/stm32l0/Cargo.toml b/examples/stm32l0/Cargo.toml index f67fa6b00..95e215b6f 100644 --- a/examples/stm32l0/Cargo.toml +++ b/examples/stm32l0/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32l072cz to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32l072cz", "unstable-pac", "time-driver-any", "exti", "memory-x"] } -embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } diff --git a/examples/stm32l1/Cargo.toml b/examples/stm32l1/Cargo.toml index 4d382f16e..33e4f96e5 100644 --- a/examples/stm32l1/Cargo.toml +++ b/examples/stm32l1/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32l151cb-a", "time-driver-any", "memory-x"] } diff --git a/examples/stm32l4/Cargo.toml b/examples/stm32l4/Cargo.toml index 699358388..9673b097f 100644 --- a/examples/stm32l4/Cargo.toml +++ b/examples/stm32l4/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32l4s5vi to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32l4s5qi", "memory-x", "time-driver-any", "exti", "chrono"] } -embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768", ] } embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } diff --git a/examples/stm32l5/Cargo.toml b/examples/stm32l5/Cargo.toml index ce9c76441..014a3c4c8 100644 --- a/examples/stm32l5/Cargo.toml +++ b/examples/stm32l5/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32l552ze to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32l552ze", "time-driver-any", "exti", "memory-x", "low-power"] } -embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/stm32u0/Cargo.toml b/examples/stm32u0/Cargo.toml index 6dd9bc7fa..fef695c82 100644 --- a/examples/stm32u0/Cargo.toml +++ b/examples/stm32u0/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32u083rc to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32u083rc", "memory-x", "unstable-pac", "exti", "chrono"] } -embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", default-features = false, features = ["defmt"] } diff --git a/examples/stm32u5/Cargo.toml b/examples/stm32u5/Cargo.toml index 9a2b1dccf..528429f4c 100644 --- a/examples/stm32u5/Cargo.toml +++ b/examples/stm32u5/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32u5g9zj to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "unstable-pac", "stm32u5g9zj", "time-driver-any", "memory-x" ] } -embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/stm32wb/Cargo.toml b/examples/stm32wb/Cargo.toml index 9a050e31e..3da74e535 100644 --- a/examples/stm32wb/Cargo.toml +++ b/examples/stm32wb/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32wb55rg to your chip name in both dependencies, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32wb55rg", "time-driver-any", "memory-x", "exti"] } embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", features = ["defmt", "stm32wb55rg"] } -embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", ], optional=true } diff --git a/examples/stm32wba/Cargo.toml b/examples/stm32wba/Cargo.toml index 1697ffa1c..2c033ff7f 100644 --- a/examples/stm32wba/Cargo.toml +++ b/examples/stm32wba/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32wba52cg", "time-driver-any", "memory-x", "exti"] } -embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", ], optional=true } diff --git a/examples/stm32wl/Cargo.toml b/examples/stm32wl/Cargo.toml index eeb13608c..6507fd1eb 100644 --- a/examples/stm32wl/Cargo.toml +++ b/examples/stm32wl/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32wl55jc-cm4 to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32wl55jc-cm4", "time-driver-any", "memory-x", "unstable-pac", "exti", "chrono"] } -embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-4096", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } diff --git a/examples/wasm/Cargo.toml b/examples/wasm/Cargo.toml index 8c1b8a4f6..5e4d352b5 100644 --- a/examples/wasm/Cargo.toml +++ b/examples/wasm/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" crate-type = ["cdylib"] [dependencies] -embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["log"] } +embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["log"] } embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-wasm", "executor-thread", "log", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["log", "wasm", ] } diff --git a/tests/nrf/Cargo.toml b/tests/nrf/Cargo.toml index 0e58487d2..00dfda6d6 100644 --- a/tests/nrf/Cargo.toml +++ b/tests/nrf/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" teleprobe-meta = "1" embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } -embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt", ] } +embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt", ] } embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "task-arena-size-16384", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "time-driver-rtc1", "gpiote", "unstable-pac"] } diff --git a/tests/riscv32/Cargo.toml b/tests/riscv32/Cargo.toml index ae60dac10..e76e07d7c 100644 --- a/tests/riscv32/Cargo.toml +++ b/tests/riscv32/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] critical-section = { version = "1.1.1", features = ["restore-state-bool"] } -embassy-sync = { version = "0.6.0", path = "../../embassy-sync" } +embassy-sync = { version = "0.6.1", path = "../../embassy-sync" } embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-riscv32", "executor-thread"] } embassy-time = { version = "0.3.2", path = "../../embassy-time" } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/tests/rp/Cargo.toml b/tests/rp/Cargo.toml index 359dae3bc..91854e659 100644 --- a/tests/rp/Cargo.toml +++ b/tests/rp/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] teleprobe-meta = "1.1" -embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", ] } embassy-rp = { version = "0.2.0", path = "../../embassy-rp", features = [ "defmt", "unstable-pac", "time-driver", "critical-section-impl", "intrinsics", "rom-v2-intrinsics", "run-from-ram", "rp2040"] } diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml index 58da8c1b5..288c438bd 100644 --- a/tests/stm32/Cargo.toml +++ b/tests/stm32/Cargo.toml @@ -59,7 +59,7 @@ cm0 = ["portable-atomic/unsafe-assume-single-core"] [dependencies] teleprobe-meta = "1" -embassy-sync = { version = "0.6.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "tick-hz-131_072", "defmt-timestamp-uptime"] } embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "memory-x", "time-driver-any"] } From 54b39ba49237f315e757ede8ef97ca88118ea807 Mon Sep 17 00:00:00 2001 From: Ivan Li Date: Sat, 23 Nov 2024 12:30:09 +0800 Subject: [PATCH 0384/1217] stm32 adc g4 async read Signed-off-by: Ivan Li --- embassy-stm32/src/adc/g4.rs | 171 +++++++++++++++++++++++++++++++++--- 1 file changed, 160 insertions(+), 11 deletions(-) diff --git a/embassy-stm32/src/adc/g4.rs b/embassy-stm32/src/adc/g4.rs index 3e9ba8ae2..872cf3f06 100644 --- a/embassy-stm32/src/adc/g4.rs +++ b/embassy-stm32/src/adc/g4.rs @@ -5,8 +5,11 @@ use pac::adc::vals::{Adcaldif, Difsel, Exten}; #[cfg(stm32g4)] use pac::adc::vals::{Adcaldif, Difsel, Exten, Rovsm, Trovs}; use pac::adccommon::vals::Presc; +use stm32_metapac::adc::vals::{Adstp, Dmacfg, Dmaen}; -use super::{blocking_delay_us, Adc, AdcChannel, Instance, Resolution, SampleTime}; +use super::{blocking_delay_us, Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime}; +use crate::adc::SealedAdcChannel; +use crate::dma::Transfer; use crate::time::Hertz; use crate::{pac, rcc, Peripheral}; @@ -191,10 +194,24 @@ impl<'d, T: Instance> Adc<'d, T> { } fn enable(&mut self) { - T::regs().isr().write(|w| w.set_adrdy(true)); - T::regs().cr().modify(|w| w.set_aden(true)); - while !T::regs().isr().read().adrdy() {} - T::regs().isr().write(|w| w.set_adrdy(true)); + // Make sure bits are off + while T::regs().cr().read().addis() { + // spin + } + + if !T::regs().cr().read().aden() { + // Enable ADC + T::regs().isr().modify(|reg| { + reg.set_adrdy(true); + }); + T::regs().cr().modify(|reg| { + reg.set_aden(true); + }); + + while !T::regs().isr().read().adrdy() { + // spin + } + } } fn configure(&mut self) { @@ -327,23 +344,146 @@ impl<'d, T: Instance> Adc<'d, T> { pub fn blocking_read(&mut self, channel: &mut impl AdcChannel) -> u16 { channel.setup(); - self.read_channel(channel.channel()) + self.read_channel(channel) } - fn read_channel(&mut self, channel: u8) -> u16 { - // Configure channel - Self::set_channel_sample_time(channel, self.sample_time); + /// Read one or multiple ADC channels using DMA. + /// + /// `sequence` iterator and `readings` must have the same length. + /// + /// Example + /// ```rust,ignore + /// use embassy_stm32::adc::{Adc, AdcChannel} + /// + /// let mut adc = Adc::new(p.ADC1); + /// let mut adc_pin0 = p.PA0.degrade_adc(); + /// let mut adc_pin1 = p.PA1.degrade_adc(); + /// let mut measurements = [0u16; 2]; + /// + /// adc.read_async( + /// p.DMA1_CH2, + /// [ + /// (&mut *adc_pin0, SampleTime::CYCLES160_5), + /// (&mut *adc_pin1, SampleTime::CYCLES160_5), + /// ] + /// .into_iter(), + /// &mut measurements, + /// ) + /// .await; + /// defmt::info!("measurements: {}", measurements); + /// ``` + pub async fn read( + &mut self, + rx_dma: &mut impl RxDma, + sequence: impl ExactSizeIterator, SampleTime)>, + readings: &mut [u16], + ) { + assert!(sequence.len() != 0, "Asynchronous read sequence cannot be empty"); + assert!( + sequence.len() == readings.len(), + "Sequence length must be equal to readings length" + ); + assert!( + sequence.len() <= 16, + "Asynchronous read sequence cannot be more than 16 in length" + ); + // Ensure no conversions are ongoing and ADC is enabled. + Self::cancel_conversions(); + self.enable(); + + // Set sequence length + T::regs().sqr1().modify(|w| { + w.set_l(sequence.len() as u8 - 1); + }); + + // Configure channels and ranks + for (_i, (channel, sample_time)) in sequence.enumerate() { + Self::configure_channel(channel, sample_time); + + match _i { + 0..=3 => { + T::regs().sqr1().modify(|w| { + w.set_sq(_i, channel.channel()); + }); + } + 4..=8 => { + T::regs().sqr2().modify(|w| { + w.set_sq(_i - 4, channel.channel()); + }); + } + 9..=13 => { + T::regs().sqr3().modify(|w| { + w.set_sq(_i - 9, channel.channel()); + }); + } + 14..=15 => { + T::regs().sqr4().modify(|w| { + w.set_sq(_i - 14, channel.channel()); + }); + } + _ => unreachable!(), + } + } + + // Set continuous mode with oneshot dma. + // Clear overrun flag before starting transfer. + T::regs().isr().modify(|reg| { + reg.set_ovr(true); + }); + + T::regs().cfgr().modify(|reg| { + reg.set_discen(false); + reg.set_cont(true); + reg.set_dmacfg(Dmacfg::ONESHOT); + reg.set_dmaen(Dmaen::ENABLE); + }); + + let request = rx_dma.request(); + let transfer = unsafe { + Transfer::new_read( + rx_dma, + request, + T::regs().dr().as_ptr() as *mut u16, + readings, + Default::default(), + ) + }; + + // Start conversion + T::regs().cr().modify(|reg| { + reg.set_adstart(true); + }); + + // Wait for conversion sequence to finish. + transfer.await; + + // Ensure conversions are finished. + Self::cancel_conversions(); + + // Reset configuration. + T::regs().cfgr().modify(|reg| { + reg.set_cont(false); + }); + } + + fn configure_channel(channel: &mut impl AdcChannel, sample_time: SampleTime) { + // Configure channel + Self::set_channel_sample_time(channel.channel(), sample_time); + } + + fn read_channel(&mut self, channel: &mut impl AdcChannel) -> u16 { + Self::configure_channel(channel, self.sample_time); #[cfg(stm32h7)] { T::regs().cfgr2().modify(|w| w.set_lshift(0)); T::regs() .pcsel() - .write(|w| w.set_pcsel(channel as _, Pcsel::PRESELECTED)); + .write(|w| w.set_pcsel(channel.channel() as _, Pcsel::PRESELECTED)); } T::regs().sqr1().write(|reg| { - reg.set_sq(0, channel); + reg.set_sq(0, channel.channel()); reg.set_l(0); }); @@ -358,4 +498,13 @@ impl<'d, T: Instance> Adc<'d, T> { T::regs().smpr2().modify(|reg| reg.set_smp((ch - 10) as _, sample_time)); } } + + fn cancel_conversions() { + if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() { + T::regs().cr().modify(|reg| { + reg.set_adstp(Adstp::STOP); + }); + while T::regs().cr().read().adstart() {} + } + } } From b1bbe6bcf21b5e89f9abb15abbece7063127f303 Mon Sep 17 00:00:00 2001 From: Ivan Li Date: Sat, 23 Nov 2024 12:47:56 +0800 Subject: [PATCH 0385/1217] stm32 adc g4: example of async read Signed-off-by: Ivan Li --- examples/stm32g4/src/bin/adc_dma.rs | 60 +++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 examples/stm32g4/src/bin/adc_dma.rs diff --git a/examples/stm32g4/src/bin/adc_dma.rs b/examples/stm32g4/src/bin/adc_dma.rs new file mode 100644 index 000000000..970623b32 --- /dev/null +++ b/examples/stm32g4/src/bin/adc_dma.rs @@ -0,0 +1,60 @@ +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::adc::{Adc, AdcChannel as _, SampleTime}; +use embassy_stm32::Config; +use embassy_time::Timer; +use {defmt_rtt as _, panic_probe as _}; + +static mut DMA_BUF: [u16; 2] = [0; 2]; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let mut read_buffer = unsafe { &mut DMA_BUF[..] }; + + let mut config = Config::default(); + { + use embassy_stm32::rcc::*; + config.rcc.pll = Some(Pll { + source: PllSource::HSI, + prediv: PllPreDiv::DIV4, + mul: PllMul::MUL85, + divp: None, + divq: None, + // Main system clock at 170 MHz + divr: Some(PllRDiv::DIV2), + }); + config.rcc.mux.adc12sel = mux::Adcsel::SYS; + config.rcc.sys = Sysclk::PLL1_R; + } + let p = embassy_stm32::init(config); + + info!("Hello World!"); + + let mut adc = Adc::new(p.ADC1); + + let mut dma = p.DMA1_CH1; + let mut vrefint_channel = adc.enable_vrefint().degrade_adc(); + let mut pa0 = p.PA0.degrade_adc(); + + loop { + adc.read( + &mut dma, + [ + (&mut vrefint_channel, SampleTime::CYCLES247_5), + (&mut pa0, SampleTime::CYCLES247_5), + ] + .into_iter(), + &mut read_buffer, + ) + .await; + + let vrefint = read_buffer[0]; + let measured = read_buffer[1]; + info!("vrefint: {}", vrefint); + info!("measured: {}", measured); + Timer::after_millis(500).await; + } +} From 1ca53e286b4e65f8b7ecceaee16bc553011f4b49 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sat, 23 Nov 2024 00:10:48 +0100 Subject: [PATCH 0386/1217] otg: fix build with defmt enabled. --- embassy-stm32/Cargo.toml | 12 ++- embassy-usb-synopsys-otg/src/otg_v1.rs | 108 ++++++++++++------------- 2 files changed, 65 insertions(+), 55 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 0872afbd9..ebcfb73c9 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -110,7 +110,17 @@ default = ["rt"] rt = ["stm32-metapac/rt"] ## Use [`defmt`](https://docs.rs/defmt/latest/defmt/) for logging -defmt = ["dep:defmt", "embassy-sync/defmt", "embassy-embedded-hal/defmt", "embassy-hal-internal/defmt", "embedded-io-async/defmt-03", "embassy-usb-driver/defmt", "embassy-net-driver/defmt", "embassy-time?/defmt"] +defmt = [ + "dep:defmt", + "embassy-sync/defmt", + "embassy-embedded-hal/defmt", + "embassy-hal-internal/defmt", + "embedded-io-async/defmt-03", + "embassy-usb-driver/defmt", + "embassy-net-driver/defmt", + "embassy-time?/defmt", + "embassy-usb-synopsys-otg/defmt", +] exti = [] low-power = [ "dep:embassy-executor", "embassy-executor?/arch-cortex-m", "time" ] diff --git a/embassy-usb-synopsys-otg/src/otg_v1.rs b/embassy-usb-synopsys-otg/src/otg_v1.rs index 18e760fd1..9e65f2315 100644 --- a/embassy-usb-synopsys-otg/src/otg_v1.rs +++ b/embassy-usb-synopsys-otg/src/otg_v1.rs @@ -108,287 +108,287 @@ impl Otg { } #[doc = "Control and status register"] #[inline(always)] - pub const fn gotgctl(self) -> Reg { + pub fn gotgctl(self) -> Reg { unsafe { Reg::from_ptr(self.ptr.add(0x0usize) as _) } } #[doc = "Interrupt register"] #[inline(always)] - pub const fn gotgint(self) -> Reg { + pub fn gotgint(self) -> Reg { unsafe { Reg::from_ptr(self.ptr.add(0x04usize) as _) } } #[doc = "AHB configuration register"] #[inline(always)] - pub const fn gahbcfg(self) -> Reg { + pub fn gahbcfg(self) -> Reg { unsafe { Reg::from_ptr(self.ptr.add(0x08usize) as _) } } #[doc = "USB configuration register"] #[inline(always)] - pub const fn gusbcfg(self) -> Reg { + pub fn gusbcfg(self) -> Reg { unsafe { Reg::from_ptr(self.ptr.add(0x0cusize) as _) } } #[doc = "Reset register"] #[inline(always)] - pub const fn grstctl(self) -> Reg { + pub fn grstctl(self) -> Reg { unsafe { Reg::from_ptr(self.ptr.add(0x10usize) as _) } } #[doc = "Core interrupt register"] #[inline(always)] - pub const fn gintsts(self) -> Reg { + pub fn gintsts(self) -> Reg { unsafe { Reg::from_ptr(self.ptr.add(0x14usize) as _) } } #[doc = "Interrupt mask register"] #[inline(always)] - pub const fn gintmsk(self) -> Reg { + pub fn gintmsk(self) -> Reg { unsafe { Reg::from_ptr(self.ptr.add(0x18usize) as _) } } #[doc = "Receive status debug read register"] #[inline(always)] - pub const fn grxstsr(self) -> Reg { + pub fn grxstsr(self) -> Reg { unsafe { Reg::from_ptr(self.ptr.add(0x1cusize) as _) } } #[doc = "Status read and pop register"] #[inline(always)] - pub const fn grxstsp(self) -> Reg { + pub fn grxstsp(self) -> Reg { unsafe { Reg::from_ptr(self.ptr.add(0x20usize) as _) } } #[doc = "Receive FIFO size register"] #[inline(always)] - pub const fn grxfsiz(self) -> Reg { + pub fn grxfsiz(self) -> Reg { unsafe { Reg::from_ptr(self.ptr.add(0x24usize) as _) } } #[doc = "Endpoint 0 transmit FIFO size register (device mode)"] #[inline(always)] - pub const fn dieptxf0(self) -> Reg { + pub fn dieptxf0(self) -> Reg { unsafe { Reg::from_ptr(self.ptr.add(0x28usize) as _) } } #[doc = "Non-periodic transmit FIFO size register (host mode)"] #[inline(always)] - pub const fn hnptxfsiz(self) -> Reg { + pub fn hnptxfsiz(self) -> Reg { unsafe { Reg::from_ptr(self.ptr.add(0x28usize) as _) } } #[doc = "Non-periodic transmit FIFO/queue status register (host mode)"] #[inline(always)] - pub const fn hnptxsts(self) -> Reg { + pub fn hnptxsts(self) -> Reg { unsafe { Reg::from_ptr(self.ptr.add(0x2cusize) as _) } } #[doc = "OTG I2C access register"] #[inline(always)] - pub const fn gi2cctl(self) -> Reg { + pub fn gi2cctl(self) -> Reg { unsafe { Reg::from_ptr(self.ptr.add(0x30usize) as _) } } #[doc = "General core configuration register, for core_id 0x0000_1xxx"] #[inline(always)] - pub const fn gccfg_v1(self) -> Reg { + pub fn gccfg_v1(self) -> Reg { unsafe { Reg::from_ptr(self.ptr.add(0x38usize) as _) } } #[doc = "General core configuration register, for core_id 0x0000_\\[23\\]xxx"] #[inline(always)] - pub const fn gccfg_v2(self) -> Reg { + pub fn gccfg_v2(self) -> Reg { unsafe { Reg::from_ptr(self.ptr.add(0x38usize) as _) } } #[doc = "General core configuration register, for core_id 0x0000_5xxx"] #[inline(always)] - pub const fn gccfg_v3(self) -> Reg { + pub fn gccfg_v3(self) -> Reg { unsafe { Reg::from_ptr(self.ptr.add(0x38usize) as _) } } #[doc = "Core ID register"] #[inline(always)] - pub const fn cid(self) -> Reg { + pub fn cid(self) -> Reg { unsafe { Reg::from_ptr(self.ptr.add(0x3cusize) as _) } } #[doc = "OTG core LPM configuration register"] #[inline(always)] - pub const fn glpmcfg(self) -> Reg { + pub fn glpmcfg(self) -> Reg { unsafe { Reg::from_ptr(self.ptr.add(0x54usize) as _) } } #[doc = "Host periodic transmit FIFO size register"] #[inline(always)] - pub const fn hptxfsiz(self) -> Reg { + pub fn hptxfsiz(self) -> Reg { unsafe { Reg::from_ptr(self.ptr.add(0x0100usize) as _) } } #[doc = "Device IN endpoint transmit FIFO size register"] #[inline(always)] - pub const fn dieptxf(self, n: usize) -> Reg { + pub fn dieptxf(self, n: usize) -> Reg { assert!(n < 7usize); unsafe { Reg::from_ptr(self.ptr.add(0x0104usize + n * 4usize) as _) } } #[doc = "Host configuration register"] #[inline(always)] - pub const fn hcfg(self) -> Reg { + pub fn hcfg(self) -> Reg { unsafe { Reg::from_ptr(self.ptr.add(0x0400usize) as _) } } #[doc = "Host frame interval register"] #[inline(always)] - pub const fn hfir(self) -> Reg { + pub fn hfir(self) -> Reg { unsafe { Reg::from_ptr(self.ptr.add(0x0404usize) as _) } } #[doc = "Host frame number/frame time remaining register"] #[inline(always)] - pub const fn hfnum(self) -> Reg { + pub fn hfnum(self) -> Reg { unsafe { Reg::from_ptr(self.ptr.add(0x0408usize) as _) } } #[doc = "Periodic transmit FIFO/queue status register"] #[inline(always)] - pub const fn hptxsts(self) -> Reg { + pub fn hptxsts(self) -> Reg { unsafe { Reg::from_ptr(self.ptr.add(0x0410usize) as _) } } #[doc = "Host all channels interrupt register"] #[inline(always)] - pub const fn haint(self) -> Reg { + pub fn haint(self) -> Reg { unsafe { Reg::from_ptr(self.ptr.add(0x0414usize) as _) } } #[doc = "Host all channels interrupt mask register"] #[inline(always)] - pub const fn haintmsk(self) -> Reg { + pub fn haintmsk(self) -> Reg { unsafe { Reg::from_ptr(self.ptr.add(0x0418usize) as _) } } #[doc = "Host port control and status register"] #[inline(always)] - pub const fn hprt(self) -> Reg { + pub fn hprt(self) -> Reg { unsafe { Reg::from_ptr(self.ptr.add(0x0440usize) as _) } } #[doc = "Host channel characteristics register"] #[inline(always)] - pub const fn hcchar(self, n: usize) -> Reg { + pub fn hcchar(self, n: usize) -> Reg { assert!(n < 12usize); unsafe { Reg::from_ptr(self.ptr.add(0x0500usize + n * 32usize) as _) } } #[doc = "Host channel split control register"] #[inline(always)] - pub const fn hcsplt(self, n: usize) -> Reg { + pub fn hcsplt(self, n: usize) -> Reg { assert!(n < 12usize); unsafe { Reg::from_ptr(self.ptr.add(0x0504usize + n * 32usize) as _) } } #[doc = "Host channel interrupt register"] #[inline(always)] - pub const fn hcint(self, n: usize) -> Reg { + pub fn hcint(self, n: usize) -> Reg { assert!(n < 12usize); unsafe { Reg::from_ptr(self.ptr.add(0x0508usize + n * 32usize) as _) } } #[doc = "Host channel mask register"] #[inline(always)] - pub const fn hcintmsk(self, n: usize) -> Reg { + pub fn hcintmsk(self, n: usize) -> Reg { assert!(n < 12usize); unsafe { Reg::from_ptr(self.ptr.add(0x050cusize + n * 32usize) as _) } } #[doc = "Host channel transfer size register"] #[inline(always)] - pub const fn hctsiz(self, n: usize) -> Reg { + pub fn hctsiz(self, n: usize) -> Reg { assert!(n < 12usize); unsafe { Reg::from_ptr(self.ptr.add(0x0510usize + n * 32usize) as _) } } #[doc = "Host channel DMA address register"] #[inline(always)] - pub const fn hcdma(self, n: usize) -> Reg { + pub fn hcdma(self, n: usize) -> Reg { assert!(n < 12usize); unsafe { Reg::from_ptr(self.ptr.add(0x0514usize + n * 32usize) as _) } } #[doc = "Device configuration register"] #[inline(always)] - pub const fn dcfg(self) -> Reg { + pub fn dcfg(self) -> Reg { unsafe { Reg::from_ptr(self.ptr.add(0x0800usize) as _) } } #[doc = "Device control register"] #[inline(always)] - pub const fn dctl(self) -> Reg { + pub fn dctl(self) -> Reg { unsafe { Reg::from_ptr(self.ptr.add(0x0804usize) as _) } } #[doc = "Device status register"] #[inline(always)] - pub const fn dsts(self) -> Reg { + pub fn dsts(self) -> Reg { unsafe { Reg::from_ptr(self.ptr.add(0x0808usize) as _) } } #[doc = "Device IN endpoint common interrupt mask register"] #[inline(always)] - pub const fn diepmsk(self) -> Reg { + pub fn diepmsk(self) -> Reg { unsafe { Reg::from_ptr(self.ptr.add(0x0810usize) as _) } } #[doc = "Device OUT endpoint common interrupt mask register"] #[inline(always)] - pub const fn doepmsk(self) -> Reg { + pub fn doepmsk(self) -> Reg { unsafe { Reg::from_ptr(self.ptr.add(0x0814usize) as _) } } #[doc = "Device all endpoints interrupt register"] #[inline(always)] - pub const fn daint(self) -> Reg { + pub fn daint(self) -> Reg { unsafe { Reg::from_ptr(self.ptr.add(0x0818usize) as _) } } #[doc = "All endpoints interrupt mask register"] #[inline(always)] - pub const fn daintmsk(self) -> Reg { + pub fn daintmsk(self) -> Reg { unsafe { Reg::from_ptr(self.ptr.add(0x081cusize) as _) } } #[doc = "Device VBUS discharge time register"] #[inline(always)] - pub const fn dvbusdis(self) -> Reg { + pub fn dvbusdis(self) -> Reg { unsafe { Reg::from_ptr(self.ptr.add(0x0828usize) as _) } } #[doc = "Device VBUS pulsing time register"] #[inline(always)] - pub const fn dvbuspulse(self) -> Reg { + pub fn dvbuspulse(self) -> Reg { unsafe { Reg::from_ptr(self.ptr.add(0x082cusize) as _) } } #[doc = "Device IN endpoint FIFO empty interrupt mask register"] #[inline(always)] - pub const fn diepempmsk(self) -> Reg { + pub fn diepempmsk(self) -> Reg { unsafe { Reg::from_ptr(self.ptr.add(0x0834usize) as _) } } #[doc = "Device IN endpoint control register"] #[inline(always)] - pub const fn diepctl(self, n: usize) -> Reg { + pub fn diepctl(self, n: usize) -> Reg { assert!(n < 16usize); unsafe { Reg::from_ptr(self.ptr.add(0x0900usize + n * 32usize) as _) } } #[doc = "Device IN endpoint interrupt register"] #[inline(always)] - pub const fn diepint(self, n: usize) -> Reg { + pub fn diepint(self, n: usize) -> Reg { assert!(n < 16usize); unsafe { Reg::from_ptr(self.ptr.add(0x0908usize + n * 32usize) as _) } } #[doc = "Device IN endpoint transfer size register"] #[inline(always)] - pub const fn dieptsiz(self, n: usize) -> Reg { + pub fn dieptsiz(self, n: usize) -> Reg { assert!(n < 16usize); unsafe { Reg::from_ptr(self.ptr.add(0x0910usize + n * 32usize) as _) } } #[doc = "Device IN endpoint transmit FIFO status register"] #[inline(always)] - pub const fn dtxfsts(self, n: usize) -> Reg { + pub fn dtxfsts(self, n: usize) -> Reg { assert!(n < 16usize); unsafe { Reg::from_ptr(self.ptr.add(0x0918usize + n * 32usize) as _) } } #[doc = "Device OUT endpoint control register"] #[inline(always)] - pub const fn doepctl(self, n: usize) -> Reg { + pub fn doepctl(self, n: usize) -> Reg { assert!(n < 16usize); unsafe { Reg::from_ptr(self.ptr.add(0x0b00usize + n * 32usize) as _) } } #[doc = "Device OUT endpoint interrupt register"] #[inline(always)] - pub const fn doepint(self, n: usize) -> Reg { + pub fn doepint(self, n: usize) -> Reg { assert!(n < 16usize); unsafe { Reg::from_ptr(self.ptr.add(0x0b08usize + n * 32usize) as _) } } #[doc = "Device OUT endpoint transfer size register"] #[inline(always)] - pub const fn doeptsiz(self, n: usize) -> Reg { + pub fn doeptsiz(self, n: usize) -> Reg { assert!(n < 16usize); unsafe { Reg::from_ptr(self.ptr.add(0x0b10usize + n * 32usize) as _) } } #[doc = "Device OUT/IN endpoint DMA address register"] #[inline(always)] - pub const fn doepdma(self, n: usize) -> Reg { + pub fn doepdma(self, n: usize) -> Reg { assert!(n < 16usize); unsafe { Reg::from_ptr(self.ptr.add(0x0b14usize + n * 32usize) as _) } } #[doc = "Power and clock gating control register"] #[inline(always)] - pub const fn pcgcctl(self) -> Reg { + pub fn pcgcctl(self) -> Reg { unsafe { Reg::from_ptr(self.ptr.add(0x0e00usize) as _) } } #[doc = "Device endpoint / host channel FIFO register"] #[inline(always)] - pub const fn fifo(self, n: usize) -> Reg { + pub fn fifo(self, n: usize) -> Reg { assert!(n < 16usize); unsafe { Reg::from_ptr(self.ptr.add(0x1000usize + n * 4096usize) as _) } } From 4f459bb91846ed9d72a26c0b751e56cfb0098d21 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sat, 23 Nov 2024 00:13:15 +0100 Subject: [PATCH 0387/1217] otg: improve trace logging, print bytes as hex. --- embassy-stm32/src/usb/otg.rs | 1 - embassy-usb-synopsys-otg/src/lib.rs | 12 ++++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/embassy-stm32/src/usb/otg.rs b/embassy-stm32/src/usb/otg.rs index 00cafe6e4..153542fbd 100644 --- a/embassy-stm32/src/usb/otg.rs +++ b/embassy-stm32/src/usb/otg.rs @@ -24,7 +24,6 @@ pub struct InterruptHandler { impl interrupt::typelevel::Handler for InterruptHandler { unsafe fn on_interrupt() { - trace!("irq"); let r = T::regs(); let state = T::state(); diff --git a/embassy-usb-synopsys-otg/src/lib.rs b/embassy-usb-synopsys-otg/src/lib.rs index f90403936..bd0ef04b0 100644 --- a/embassy-usb-synopsys-otg/src/lib.rs +++ b/embassy-usb-synopsys-otg/src/lib.rs @@ -18,6 +18,8 @@ use embassy_usb_driver::{ EndpointType, Event, Unsupported, }; +use crate::fmt::Bytes; + pub mod otg_v1; use otg_v1::{regs, vals, Otg}; @@ -29,6 +31,8 @@ pub unsafe fn on_interrupt( ep_count: usize, quirk_setup_late_cnak: bool, ) { + trace!("irq"); + let ints = r.gintsts().read(); if ints.wkupint() || ints.usbsusp() || ints.usbrst() || ints.enumdne() || ints.otgint() || ints.srqint() { // Mask interrupts and notify `Bus` to process them @@ -1126,7 +1130,7 @@ impl<'d> embassy_usb_driver::EndpointOut for Endpoint<'d, Out> { impl<'d> embassy_usb_driver::EndpointIn for Endpoint<'d, In> { async fn write(&mut self, buf: &[u8]) -> Result<(), EndpointError> { - trace!("write ep={:?} data={:?}", self.info.addr, buf); + trace!("write ep={:?} data={:?}", self.info.addr, Bytes(buf)); if buf.len() > self.info.max_packet_size as usize { return Err(EndpointError::BufferOverflow); @@ -1267,7 +1271,7 @@ impl<'d> embassy_usb_driver::ControlPipe for ControlPipe<'d> { .modify(|w| w.set_cnak(true)); } - trace!("SETUP received: {:?}", data); + trace!("SETUP received: {:?}", Bytes(&data)); Poll::Ready(data) } else { trace!("SETUP waiting"); @@ -1280,12 +1284,12 @@ impl<'d> embassy_usb_driver::ControlPipe for ControlPipe<'d> { async fn data_out(&mut self, buf: &mut [u8], _first: bool, _last: bool) -> Result { trace!("control: data_out"); let len = self.ep_out.read(buf).await?; - trace!("control: data_out read: {:?}", &buf[..len]); + trace!("control: data_out read: {:?}", Bytes(&buf[..len])); Ok(len) } async fn data_in(&mut self, data: &[u8], _first: bool, last: bool) -> Result<(), EndpointError> { - trace!("control: data_in write: {:?}", data); + trace!("control: data_in write: {:?}", Bytes(data)); self.ep_in.write(data).await?; // wait for status response from host after sending the last packet From 032af9d512140d8464680a444debc76f36222a31 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sat, 23 Nov 2024 00:23:40 +0100 Subject: [PATCH 0388/1217] otg: fix corruption in CONTROL OUT transfers in stm32f4. The RM says we have to process STUP (and therefore clear CNAK to start the data stage) in the DOEPINT STUP interrupt. Seems doing it in RXFLVL when we receive the data is too early. This makes it work consistently on all chips, so the quirk is no longer needed. Fixes #3493 Fixes #3459 --- embassy-stm32/src/usb/otg.rs | 20 +---- embassy-usb-synopsys-otg/src/lib.rs | 109 ++++++++++++---------------- 2 files changed, 50 insertions(+), 79 deletions(-) diff --git a/embassy-stm32/src/usb/otg.rs b/embassy-stm32/src/usb/otg.rs index 153542fbd..6ca28b156 100644 --- a/embassy-stm32/src/usb/otg.rs +++ b/embassy-stm32/src/usb/otg.rs @@ -27,9 +27,7 @@ impl interrupt::typelevel::Handler for InterruptHandl let r = T::regs(); let state = T::state(); - let setup_late_cnak = quirk_setup_late_cnak(r); - - on_interrupt_impl(r, state, T::ENDPOINT_COUNT, setup_late_cnak); + on_interrupt_impl(r, state, T::ENDPOINT_COUNT); } } @@ -86,7 +84,6 @@ impl<'d, T: Instance> Driver<'d, T> { extra_rx_fifo_words: RX_FIFO_EXTRA_SIZE_WORDS, endpoint_count: T::ENDPOINT_COUNT, phy_type: PhyType::InternalFullSpeed, - quirk_setup_late_cnak: quirk_setup_late_cnak(regs), calculate_trdt_fn: calculate_trdt::, }; @@ -116,16 +113,13 @@ impl<'d, T: Instance> Driver<'d, T> { dp.set_as_af(dp.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh)); dm.set_as_af(dm.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh)); - let regs = T::regs(); - let instance = OtgInstance { - regs, + regs: T::regs(), state: T::state(), fifo_depth_words: T::FIFO_DEPTH_WORDS, extra_rx_fifo_words: RX_FIFO_EXTRA_SIZE_WORDS, endpoint_count: T::ENDPOINT_COUNT, phy_type: PhyType::InternalHighSpeed, - quirk_setup_late_cnak: quirk_setup_late_cnak(regs), calculate_trdt_fn: calculate_trdt::, }; @@ -165,8 +159,6 @@ impl<'d, T: Instance> Driver<'d, T> { ulpi_d7 ); - let regs = T::regs(); - let instance = OtgInstance { regs: T::regs(), state: T::state(), @@ -174,7 +166,6 @@ impl<'d, T: Instance> Driver<'d, T> { extra_rx_fifo_words: RX_FIFO_EXTRA_SIZE_WORDS, endpoint_count: T::ENDPOINT_COUNT, phy_type: PhyType::ExternalFullSpeed, - quirk_setup_late_cnak: quirk_setup_late_cnak(regs), calculate_trdt_fn: calculate_trdt::, }; @@ -216,8 +207,6 @@ impl<'d, T: Instance> Driver<'d, T> { ulpi_d7 ); - let regs = T::regs(); - let instance = OtgInstance { regs: T::regs(), state: T::state(), @@ -225,7 +214,6 @@ impl<'d, T: Instance> Driver<'d, T> { extra_rx_fifo_words: RX_FIFO_EXTRA_SIZE_WORDS, endpoint_count: T::ENDPOINT_COUNT, phy_type: PhyType::ExternalHighSpeed, - quirk_setup_late_cnak: quirk_setup_late_cnak(regs), calculate_trdt_fn: calculate_trdt::, }; @@ -578,7 +566,3 @@ fn calculate_trdt(speed: Dspd) -> u8 { _ => unimplemented!(), } } - -fn quirk_setup_late_cnak(r: Otg) -> bool { - r.cid().read().0 & 0xf000 == 0x1000 -} diff --git a/embassy-usb-synopsys-otg/src/lib.rs b/embassy-usb-synopsys-otg/src/lib.rs index bd0ef04b0..615faa2fc 100644 --- a/embassy-usb-synopsys-otg/src/lib.rs +++ b/embassy-usb-synopsys-otg/src/lib.rs @@ -9,7 +9,7 @@ mod fmt; use core::cell::UnsafeCell; use core::future::poll_fn; use core::marker::PhantomData; -use core::sync::atomic::{AtomicBool, AtomicU16, Ordering}; +use core::sync::atomic::{AtomicBool, AtomicU16, AtomicU32, Ordering}; use core::task::Poll; use embassy_sync::waitqueue::AtomicWaker; @@ -25,18 +25,17 @@ pub mod otg_v1; use otg_v1::{regs, vals, Otg}; /// Handle interrupts. -pub unsafe fn on_interrupt( - r: Otg, - state: &State, - ep_count: usize, - quirk_setup_late_cnak: bool, -) { +pub unsafe fn on_interrupt(r: Otg, state: &State, ep_count: usize) { trace!("irq"); let ints = r.gintsts().read(); if ints.wkupint() || ints.usbsusp() || ints.usbrst() || ints.enumdne() || ints.otgint() || ints.srqint() { // Mask interrupts and notify `Bus` to process them - r.gintmsk().write(|_| {}); + r.gintmsk().write(|w| { + w.set_iepint(true); + w.set_oepint(true); + w.set_rxflvlm(true); + }); state.bus_waker.wake(); } @@ -64,19 +63,9 @@ pub unsafe fn on_interrupt( while r.grstctl().read().txfflsh() {} } - if state.cp_state.setup_ready.load(Ordering::Relaxed) == false { - // SAFETY: exclusive access ensured by atomic bool - let data = unsafe { &mut *state.cp_state.setup_data.get() }; - data[0..4].copy_from_slice(&r.fifo(0).read().0.to_ne_bytes()); - data[4..8].copy_from_slice(&r.fifo(0).read().0.to_ne_bytes()); - state.cp_state.setup_ready.store(true, Ordering::Release); - state.ep_states[0].out_waker.wake(); - } else { - error!("received SETUP before previous finished processing"); - // discard FIFO - r.fifo(0).read(); - r.fifo(0).read(); - } + let data = &state.cp_state.setup_data; + data[0].store(r.fifo(0).read().data(), Ordering::Relaxed); + data[1].store(r.fifo(0).read().data(), Ordering::Relaxed); } vals::Pktstsd::OUT_DATA_RX => { trace!("OUT_DATA_RX ep={} len={}", ep_num, len); @@ -110,11 +99,6 @@ pub unsafe fn on_interrupt( } vals::Pktstsd::SETUP_DATA_DONE => { trace!("SETUP_DATA_DONE ep={}", ep_num); - - if quirk_setup_late_cnak { - // Clear NAK to indicate we are ready to receive more data - r.doepctl(ep_num).modify(|w| w.set_cnak(true)); - } } x => trace!("unknown PKTSTS: {}", x.to_bits()), } @@ -151,25 +135,30 @@ pub unsafe fn on_interrupt( } } - // not needed? reception handled in rxflvl - // OUT endpoint interrupt - // if ints.oepint() { - // let mut ep_mask = r.daint().read().oepint(); - // let mut ep_num = 0; + // out endpoint interrupt + if ints.oepint() { + trace!("oepint"); + let mut ep_mask = r.daint().read().oepint(); + let mut ep_num = 0; - // while ep_mask != 0 { - // if ep_mask & 1 != 0 { - // let ep_ints = r.doepint(ep_num).read(); - // // clear all - // r.doepint(ep_num).write_value(ep_ints); - // state.ep_out_wakers[ep_num].wake(); - // trace!("out ep={} irq val={:08x}", ep_num, ep_ints.0); - // } + // Iterate over endpoints while there are non-zero bits in the mask + while ep_mask != 0 { + if ep_mask & 1 != 0 { + let ep_ints = r.doepint(ep_num).read(); + // clear all + r.doepint(ep_num).write_value(ep_ints); - // ep_mask >>= 1; - // ep_num += 1; - // } - // } + if ep_ints.stup() { + state.cp_state.setup_ready.store(true, Ordering::Release); + } + state.ep_states[ep_num].out_waker.wake(); + trace!("out ep={} irq val={:08x}", ep_num, ep_ints.0); + } + + ep_mask >>= 1; + ep_num += 1; + } + } } /// USB PHY type @@ -236,7 +225,7 @@ unsafe impl Sync for EpState {} struct ControlPipeSetupState { /// Holds received SETUP packets. Available if [Ep0State::setup_ready] is true. - setup_data: UnsafeCell<[u8; 8]>, + setup_data: [AtomicU32; 2], setup_ready: AtomicBool, } @@ -265,7 +254,7 @@ impl State { Self { cp_state: ControlPipeSetupState { - setup_data: UnsafeCell::new([0u8; 8]), + setup_data: [const { AtomicU32::new(0) }; 2], setup_ready: AtomicBool::new(false), }, ep_states: [NEW_EP_STATE; EP_COUNT], @@ -480,7 +469,6 @@ impl<'d, const MAX_EP_COUNT: usize> embassy_usb_driver::Driver<'d> for Driver<'d trace!("start"); let regs = self.instance.regs; - let quirk_setup_late_cnak = self.instance.quirk_setup_late_cnak; let cp_setup_state = &self.instance.state.cp_state; ( Bus { @@ -496,7 +484,6 @@ impl<'d, const MAX_EP_COUNT: usize> embassy_usb_driver::Driver<'d> for Driver<'d ep_out, ep_in, regs, - quirk_setup_late_cnak, }, ) } @@ -632,6 +619,11 @@ impl<'d, const MAX_EP_COUNT: usize> Bus<'d, MAX_EP_COUNT> { w.set_xfrcm(true); }); + // Unmask SETUP received EP interrupt + r.doepmsk().write(|w| { + w.set_stupm(true); + }); + // Unmask and clear core interrupts self.restore_irqs(); r.gintsts().write_value(regs::Gintsts(0xFFFF_FFFF)); @@ -743,7 +735,7 @@ impl<'d, const MAX_EP_COUNT: usize> Bus<'d, MAX_EP_COUNT> { regs.doeptsiz(index).modify(|w| { w.set_xfrsiz(ep.max_packet_size as _); if index == 0 { - w.set_rxdpid_stupcnt(1); + w.set_rxdpid_stupcnt(3); } else { w.set_pktcnt(1); } @@ -755,8 +747,7 @@ impl<'d, const MAX_EP_COUNT: usize> Bus<'d, MAX_EP_COUNT> { // Enable IRQs for allocated endpoints regs.daintmsk().modify(|w| { w.set_iepm(ep_irq_mask(&self.ep_in)); - // OUT interrupts not used, handled in RXFLVL - // w.set_oepm(ep_irq_mask(&self.ep_out)); + w.set_oepm(ep_irq_mask(&self.ep_out)); }); } @@ -1242,7 +1233,6 @@ pub struct ControlPipe<'d> { setup_state: &'d ControlPipeSetupState, ep_in: Endpoint<'d, In>, ep_out: Endpoint<'d, Out>, - quirk_setup_late_cnak: bool, } impl<'d> embassy_usb_driver::ControlPipe for ControlPipe<'d> { @@ -1255,21 +1245,20 @@ impl<'d> embassy_usb_driver::ControlPipe for ControlPipe<'d> { self.ep_out.state.out_waker.register(cx.waker()); if self.setup_state.setup_ready.load(Ordering::Relaxed) { - let data = unsafe { *self.setup_state.setup_data.get() }; + let mut data = [0; 8]; + data[0..4].copy_from_slice(&self.setup_state.setup_data[0].load(Ordering::Relaxed).to_ne_bytes()); + data[4..8].copy_from_slice(&self.setup_state.setup_data[1].load(Ordering::Relaxed).to_ne_bytes()); self.setup_state.setup_ready.store(false, Ordering::Release); // EP0 should not be controlled by `Bus` so this RMW does not need a critical section - // Receive 1 SETUP packet self.regs.doeptsiz(self.ep_out.info.addr.index()).modify(|w| { - w.set_rxdpid_stupcnt(1); + w.set_rxdpid_stupcnt(3); }); // Clear NAK to indicate we are ready to receive more data - if !self.quirk_setup_late_cnak { - self.regs - .doepctl(self.ep_out.info.addr.index()) - .modify(|w| w.set_cnak(true)); - } + self.regs + .doepctl(self.ep_out.info.addr.index()) + .modify(|w| w.set_cnak(true)); trace!("SETUP received: {:?}", Bytes(&data)); Poll::Ready(data) @@ -1389,8 +1378,6 @@ pub struct OtgInstance<'d, const MAX_EP_COUNT: usize> { pub phy_type: PhyType, /// Extra RX FIFO words needed by some implementations. pub extra_rx_fifo_words: u16, - /// Whether to set up late cnak - pub quirk_setup_late_cnak: bool, /// Function to calculate TRDT value based on some internal clock speed. pub calculate_trdt_fn: fn(speed: vals::Dspd) -> u8, } From bc7372d7011c36157e4d55e05d0a3c5a82ba6f1c Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sat, 23 Nov 2024 00:29:38 +0100 Subject: [PATCH 0389/1217] otg: use const blocks for init. --- embassy-usb-synopsys-otg/src/lib.rs | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/embassy-usb-synopsys-otg/src/lib.rs b/embassy-usb-synopsys-otg/src/lib.rs index 615faa2fc..44b2bd093 100644 --- a/embassy-usb-synopsys-otg/src/lib.rs +++ b/embassy-usb-synopsys-otg/src/lib.rs @@ -242,23 +242,20 @@ unsafe impl Sync for State {} impl State { /// Create a new State. pub const fn new() -> Self { - const NEW_AW: AtomicWaker = AtomicWaker::new(); - const NEW_BUF: UnsafeCell<*mut u8> = UnsafeCell::new(0 as _); - const NEW_SIZE: AtomicU16 = AtomicU16::new(EP_OUT_BUFFER_EMPTY); - const NEW_EP_STATE: EpState = EpState { - in_waker: NEW_AW, - out_waker: NEW_AW, - out_buffer: NEW_BUF, - out_size: NEW_SIZE, - }; - Self { cp_state: ControlPipeSetupState { setup_data: [const { AtomicU32::new(0) }; 2], setup_ready: AtomicBool::new(false), }, - ep_states: [NEW_EP_STATE; EP_COUNT], - bus_waker: NEW_AW, + ep_states: [const { + EpState { + in_waker: AtomicWaker::new(), + out_waker: AtomicWaker::new(), + out_buffer: UnsafeCell::new(0 as _), + out_size: AtomicU16::new(EP_OUT_BUFFER_EMPTY), + } + }; EP_COUNT], + bus_waker: AtomicWaker::new(), } } } From ffc7b732e90af9715a31526c7f179e76c2a96062 Mon Sep 17 00:00:00 2001 From: elagil Date: Sat, 2 Nov 2024 20:01:20 +0100 Subject: [PATCH 0390/1217] feat(usb): add USB Audio Class 1 --- embassy-usb/src/class/mod.rs | 1 + embassy-usb/src/class/uac1/class_codes.rs | 151 ++++ embassy-usb/src/class/uac1/mod.rs | 134 ++++ embassy-usb/src/class/uac1/speaker.rs | 778 ++++++++++++++++++++ embassy-usb/src/class/uac1/terminal_type.rs | 50 ++ 5 files changed, 1114 insertions(+) create mode 100644 embassy-usb/src/class/uac1/class_codes.rs create mode 100644 embassy-usb/src/class/uac1/mod.rs create mode 100644 embassy-usb/src/class/uac1/speaker.rs create mode 100644 embassy-usb/src/class/uac1/terminal_type.rs diff --git a/embassy-usb/src/class/mod.rs b/embassy-usb/src/class/mod.rs index b883ed4e5..4bd89eb66 100644 --- a/embassy-usb/src/class/mod.rs +++ b/embassy-usb/src/class/mod.rs @@ -3,4 +3,5 @@ pub mod cdc_acm; pub mod cdc_ncm; pub mod hid; pub mod midi; +pub mod uac1; pub mod web_usb; diff --git a/embassy-usb/src/class/uac1/class_codes.rs b/embassy-usb/src/class/uac1/class_codes.rs new file mode 100644 index 000000000..3f6956771 --- /dev/null +++ b/embassy-usb/src/class/uac1/class_codes.rs @@ -0,0 +1,151 @@ +//! Audio Device Class Codes as defined in Universal Serial Bus Device Class +//! Definition for Audio Devices, Release 1.0, Appendix A and Universal Serial +//! Bus Device Class Definition for Audio Data Formats, Release 1.0, Appendix +//! A.1.1 (Audio Data Format Type I Codes) +#![allow(dead_code)] + +/// The current version of the ADC specification (1.0) +pub const ADC_VERSION: u16 = 0x0100; + +/// The current version of the USB device (1.0) +pub const DEVICE_VERSION: u16 = 0x0100; + +/// Audio Interface Class Code +pub const USB_AUDIO_CLASS: u8 = 0x01; + +// Audio Interface Subclass Codes +pub const USB_UNDEFINED_SUBCLASS: u8 = 0x00; +pub const USB_AUDIOCONTROL_SUBCLASS: u8 = 0x01; +pub const USB_AUDIOSTREAMING_SUBCLASS: u8 = 0x02; +pub const USB_MIDISTREAMING_SUBCLASS: u8 = 0x03; + +// Audio Protocol Code +pub const PROTOCOL_NONE: u8 = 0x00; + +// Audio Class-Specific Descriptor Types +pub const CS_UNDEFINED: u8 = 0x20; +pub const CS_DEVICE: u8 = 0x21; +pub const CS_CONFIGURATION: u8 = 0x22; +pub const CS_STRING: u8 = 0x23; +pub const CS_INTERFACE: u8 = 0x24; +pub const CS_ENDPOINT: u8 = 0x25; + +// Descriptor Subtype +pub const AC_DESCRIPTOR_UNDEFINED: u8 = 0x00; +pub const HEADER_SUBTYPE: u8 = 0x01; +pub const INPUT_TERMINAL: u8 = 0x02; +pub const OUTPUT_TERMINAL: u8 = 0x03; +pub const MIXER_UNIT: u8 = 0x04; +pub const SELECTOR_UNIT: u8 = 0x05; +pub const FEATURE_UNIT: u8 = 0x06; +pub const PROCESSING_UNIT: u8 = 0x07; +pub const EXTENSION_UNIT: u8 = 0x08; + +// Audio Class-Specific AS Interface Descriptor Subtypes +pub const AS_DESCRIPTOR_UNDEFINED: u8 = 0x00; +pub const AS_GENERAL: u8 = 0x01; +pub const FORMAT_TYPE: u8 = 0x02; +pub const FORMAT_SPECIFIC: u8 = 0x03; + +// Processing Unit Process Types +pub const PROCESS_UNDEFINED: u16 = 0x00; +pub const UP_DOWNMIX_PROCESS: u16 = 0x01; +pub const DOLBY_PROLOGIC_PROCESS: u16 = 0x02; +pub const DDD_STEREO_EXTENDER_PROCESS: u16 = 0x03; +pub const REVERBERATION_PROCESS: u16 = 0x04; +pub const CHORUS_PROCESS: u16 = 0x05; +pub const DYN_RANGE_COMP_PROCESS: u16 = 0x06; + +// Audio Class-Specific Endpoint Descriptor Subtypes +pub const EP_DESCRIPTOR_UNDEFINED: u8 = 0x00; +pub const EP_GENERAL: u8 = 0x01; + +// Audio Class-Specific Request Codes +pub const REQUEST_CODE_UNDEFINED: u8 = 0x00; +pub const SET_CUR: u8 = 0x01; +pub const GET_CUR: u8 = 0x81; +pub const SET_MIN: u8 = 0x02; +pub const GET_MIN: u8 = 0x82; +pub const SET_MAX: u8 = 0x03; +pub const GET_MAX: u8 = 0x83; +pub const SET_RES: u8 = 0x04; +pub const GET_RES: u8 = 0x84; +pub const SET_MEM: u8 = 0x05; +pub const GET_MEM: u8 = 0x85; +pub const GET_STAT: u8 = 0xFF; + +// Terminal Control Selectors +pub const TE_CONTROL_UNDEFINED: u8 = 0x00; +pub const COPY_PROTECT_CONTROL: u8 = 0x01; + +// Feature Unit Control Selectors +pub const FU_CONTROL_UNDEFINED: u8 = 0x00; +pub const MUTE_CONTROL: u8 = 0x01; +pub const VOLUME_CONTROL: u8 = 0x02; +pub const BASS_CONTROL: u8 = 0x03; +pub const MID_CONTROL: u8 = 0x04; +pub const TREBLE_CONTROL: u8 = 0x05; +pub const GRAPHIC_EQUALIZER_CONTROL: u8 = 0x06; +pub const AUTOMATIC_GAIN_CONTROL: u8 = 0x07; +pub const DELAY_CONTROL: u8 = 0x08; +pub const BASS_BOOST_CONTROL: u8 = 0x09; +pub const LOUDNESS_CONTROL: u8 = 0x0A; + +// Up/Down-mix Processing Unit Control Selectors +pub const UD_CONTROL_UNDEFINED: u8 = 0x00; +pub const UD_ENABLE_CONTROL: u8 = 0x01; +pub const UD_MODE_SELECT_CONTROL: u8 = 0x02; + +// Dolby Prologic Processing Unit Control Selectors +pub const DP_CONTROL_UNDEFINED: u8 = 0x00; +pub const DP_ENABLE_CONTROL: u8 = 0x01; +pub const DP_MODE_SELECT_CONTROL: u8 = 0x2; + +// 3D Stereo Extender Processing Unit Control Selectors +pub const DDD_CONTROL_UNDEFINED: u8 = 0x00; +pub const DDD_ENABLE_CONTROL: u8 = 0x01; +pub const DDD_SPACIOUSNESS_CONTROL: u8 = 0x03; + +// Reverberation Processing Unit Control Selectors +pub const RV_CONTROL_UNDEFINED: u8 = 0x00; +pub const RV_ENABLE_CONTROL: u8 = 0x01; +pub const REVERB_LEVEL_CONTROL: u8 = 0x02; +pub const REVERB_TIME_CONTROL: u8 = 0x03; +pub const REVERB_FEEDBACK_CONTROL: u8 = 0x04; + +// Chorus Processing Unit Control Selectors +pub const CH_CONTROL_UNDEFINED: u8 = 0x00; +pub const CH_ENABLE_CONTROL: u8 = 0x01; +pub const CHORUS_LEVEL_CONTROL: u8 = 0x02; +pub const CHORUS_RATE_CONTROL: u8 = 0x03; +pub const CHORUS_DEPTH_CONTROL: u8 = 0x04; + +// Dynamic Range Compressor Processing Unit Control Selectors +pub const DR_CONTROL_UNDEFINED: u8 = 0x00; +pub const DR_ENABLE_CONTROL: u8 = 0x01; +pub const COMPRESSION_RATE_CONTROL: u8 = 0x02; +pub const MAXAMPL_CONTROL: u8 = 0x03; +pub const THRESHOLD_CONTROL: u8 = 0x04; +pub const ATTACK_TIME: u8 = 0x05; +pub const RELEASE_TIME: u8 = 0x06; + +// Extension Unit Control Selectors +pub const XU_CONTROL_UNDEFINED: u16 = 0x00; +pub const XU_ENABLE_CONTROL: u16 = 0x01; + +// Endpoint Control Selectors +pub const EP_CONTROL_UNDEFINED: u8 = 0x00; +pub const SAMPLING_FREQ_CONTROL: u8 = 0x01; +pub const PITCH_CONTROL: u8 = 0x02; + +// Format Type Codes +pub const FORMAT_TYPE_UNDEFINED: u8 = 0x00; +pub const FORMAT_TYPE_I: u8 = 0x01; + +// Audio Data Format Type I Codes +pub const TYPE_I_UNDEFINED: u16 = 0x0000; +pub const PCM: u16 = 0x0001; +pub const PCM8: u16 = 0x0002; +pub const IEEE_FLOAT: u16 = 0x0003; +pub const ALAW: u16 = 0x0004; +pub const MULAW: u16 = 0x0005; diff --git a/embassy-usb/src/class/uac1/mod.rs b/embassy-usb/src/class/uac1/mod.rs new file mode 100644 index 000000000..3d5f4e524 --- /dev/null +++ b/embassy-usb/src/class/uac1/mod.rs @@ -0,0 +1,134 @@ +//! USB Audio Class 1.0 implementations for different applications. +//! +//! Contains: +//! - The `speaker` class with a single audio streaming interface (host to device) + +pub mod speaker; + +mod class_codes; +mod terminal_type; + +/// The maximum supported audio channel index (corresponds to `Top`). +/// FIXME: Use `core::mem::variant_count(...)` when stabilized. +const MAX_AUDIO_CHANNEL_INDEX: usize = 12; + +/// The maximum number of supported audio channels. +/// +/// Includes all twelve channels from `Channel`, plus the Master channel. +const MAX_AUDIO_CHANNEL_COUNT: usize = MAX_AUDIO_CHANNEL_INDEX + 1; + +/// USB Audio Channel +#[derive(Debug, Clone, Copy, PartialEq)] +#[allow(missing_docs)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum Channel { + LeftFront, + RightFront, + CenterFront, + Lfe, + LeftSurround, + RightSurround, + LeftOfCenter, + RightOfCenter, + Surround, + SideLeft, + SideRight, + Top, +} + +impl Channel { + /// Map a `Channel` to its corresponding USB Audio `ChannelConfig`. + fn get_channel_config(&self) -> ChannelConfig { + match self { + Channel::LeftFront => ChannelConfig::LeftFront, + Channel::RightFront => ChannelConfig::RightFront, + Channel::CenterFront => ChannelConfig::CenterFront, + Channel::Lfe => ChannelConfig::Lfe, + Channel::LeftSurround => ChannelConfig::LeftSurround, + Channel::RightSurround => ChannelConfig::RightSurround, + Channel::LeftOfCenter => ChannelConfig::LeftOfCenter, + Channel::RightOfCenter => ChannelConfig::RightOfCenter, + Channel::Surround => ChannelConfig::Surround, + Channel::SideLeft => ChannelConfig::SideLeft, + Channel::SideRight => ChannelConfig::SideRight, + Channel::Top => ChannelConfig::Top, + } + } +} + +/// USB Audio Channel configuration +#[repr(u16)] +#[non_exhaustive] +// #[derive(Copy, Clone, Eq, PartialEq, Debug)] +enum ChannelConfig { + None = 0x0000, + LeftFront = 0x0001, + RightFront = 0x0002, + CenterFront = 0x0004, + Lfe = 0x0008, + LeftSurround = 0x0010, + RightSurround = 0x0020, + LeftOfCenter = 0x0040, + RightOfCenter = 0x0080, + Surround = 0x0100, + SideLeft = 0x0200, + SideRight = 0x0400, + Top = 0x0800, +} + +impl From for u16 { + fn from(t: ChannelConfig) -> u16 { + t as u16 + } +} + +/// Feedback period adjustment `bRefresh` [UAC 3.7.2.2] +/// +/// From the specification: "A new Ff value is available every 2^(10 – P) frames with P ranging from 1 to 9. The +/// bRefresh field of the synch standard endpoint descriptor is used to report the exponent (10-P) to the Host." +/// +/// This means: +/// - 512 ms (2^9 frames) to 2 ms (2^1 frames) for USB full-speed +/// - 64 ms (2^9 microframes) to 0.25 ms (2^1 microframes) for USB high-speed +#[repr(u8)] +#[allow(missing_docs)] +#[derive(Clone, Copy)] +pub enum FeedbackRefresh { + Period2Frames = 1, + Period4Frames = 2, + Period8Frames = 3, + Period16Frames = 4, + Period32Frames = 5, + Period64Frames = 6, + Period128Frames = 7, + Period256Frames = 8, + Period512Frames = 9, +} + +impl FeedbackRefresh { + /// Gets the number of frames, after which a new feedback frame is returned. + pub const fn frame_count(&self) -> usize { + 1 << (*self as usize) + } +} + +/// Audio sample width. +/// +/// Stored in number of bytes per sample. +#[repr(u8)] +#[derive(Clone, Copy)] +pub enum SampleWidth { + /// 16 bit audio + Width2Byte = 2, + /// 24 bit audio + Width3Byte = 3, + /// 32 bit audio + Width4Byte = 4, +} + +impl SampleWidth { + /// Get the audio sample resolution in number of bit. + pub const fn in_bit(self) -> usize { + 8 * self as usize + } +} diff --git a/embassy-usb/src/class/uac1/speaker.rs b/embassy-usb/src/class/uac1/speaker.rs new file mode 100644 index 000000000..96456d94a --- /dev/null +++ b/embassy-usb/src/class/uac1/speaker.rs @@ -0,0 +1,778 @@ +//! USB Audio Class 1.0 - Speaker device +//! +//! Provides a class with a single audio streaming interface (host to device), +//! that advertises itself as a speaker. Includes explicit sample rate feedback. +//! +//! Various aspects of the audio stream can be configured, for example: +//! - sample rate +//! - sample resolution +//! - audio channel count and assignment +//! +//! The class provides volume and mute controls for each channel. + +use core::cell::{Cell, RefCell}; +use core::future::poll_fn; +use core::marker::PhantomData; +use core::sync::atomic::{AtomicBool, AtomicU32, Ordering}; +use core::task::Poll; + +use embassy_sync::blocking_mutex::CriticalSectionMutex; +use embassy_sync::waitqueue::WakerRegistration; +use heapless::Vec; + +use super::class_codes::*; +use super::terminal_type::TerminalType; +use super::{Channel, ChannelConfig, FeedbackRefresh, SampleWidth, MAX_AUDIO_CHANNEL_COUNT, MAX_AUDIO_CHANNEL_INDEX}; +use crate::control::{self, InResponse, OutResponse, Recipient, Request, RequestType}; +use crate::descriptor::{SynchronizationType, UsageType}; +use crate::driver::{Driver, Endpoint, EndpointError, EndpointIn, EndpointOut, EndpointType}; +use crate::types::InterfaceNumber; +use crate::{Builder, Handler}; + +/// Maximum allowed sampling rate (3 bytes) in Hz. +const MAX_SAMPLE_RATE_HZ: u32 = 0x7FFFFF; + +/// Arbitrary unique identifier for the input unit. +const INPUT_UNIT_ID: u8 = 0x01; + +/// Arbitrary unique identifier for the feature unit. +const FEATURE_UNIT_ID: u8 = 0x02; + +/// Arbitrary unique identifier for the output unit. +const OUTPUT_UNIT_ID: u8 = 0x03; + +// Volume settings go from -25600 to 0, in steps of 256. +// Therefore, the volume settings are 8q8 values in units of dB. +const VOLUME_STEPS_PER_DB: i16 = 256; +const MIN_VOLUME_DB: i16 = -100; +const MAX_VOLUME_DB: i16 = 0; + +// Maximum number of supported discrete sample rates. +const MAX_SAMPLE_RATE_COUNT: usize = 10; + +/// The volume of an audio channel. +#[derive(Debug, Clone, Copy)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum Volume { + /// The channel is muted. + Muted, + /// The channel volume in dB. Ranges from `MIN_VOLUME_DB` (quietest) to `MAX_VOLUME_DB` (loudest). + DeciBel(f32), +} + +/// Internal state for the USB Audio Class. +pub struct State<'d> { + control: Option>, + shared: SharedControl<'d>, +} + +impl<'d> Default for State<'d> { + fn default() -> Self { + Self::new() + } +} + +impl<'d> State<'d> { + /// Create a new `State`. + pub fn new() -> Self { + Self { + control: None, + shared: SharedControl::default(), + } + } +} + +/// Implementation of the USB audio class 1.0. +pub struct Speaker<'d, D: Driver<'d>> { + phantom: PhantomData<&'d D>, +} + +impl<'d, D: Driver<'d>> Speaker<'d, D> { + /// Creates a new [`Speaker`] device, split into a stream, feedback, and a control change notifier. + /// + /// The packet size should be chosen, based on the expected transfer size of samples per (micro)frame. + /// For example, a stereo stream at 32 bit resolution and 48 kHz sample rate yields packets of 384 byte for + /// full-speed USB (1 ms frame interval) or 48 byte for high-speed USB (125 us microframe interval). + /// When using feedback, the packet size varies and thus, the `max_packet_size` should be increased (e.g. to double). + /// + /// # Arguments + /// + /// * `builder` - The builder for the class. + /// * `state` - The internal state of the class. + /// * `max_packet_size` - The maximum packet size per (micro)frame. + /// * `resolution` - The audio sample resolution. + /// * `sample_rates_hz` - The supported sample rates in Hz. + /// * `channels` - The advertised audio channels (up to 12). Entries must be unique, or this function panics. + /// * `feedback_refresh_period` - The refresh period for the feedback value. + pub fn new( + builder: &mut Builder<'d, D>, + state: &'d mut State<'d>, + max_packet_size: u16, + resolution: SampleWidth, + sample_rates_hz: &[u32], + channels: &'d [Channel], + feedback_refresh_period: FeedbackRefresh, + ) -> (Stream<'d, D>, Feedback<'d, D>, ControlMonitor<'d>) { + // The class and subclass fields of the IAD aren't required to match the class and subclass fields of + // the interfaces in the interface collection that the IAD describes. Microsoft recommends that + // the first interface of the collection has class and subclass fields that match the class and + // subclass fields of the IAD. + let mut func = builder.function(USB_AUDIO_CLASS, USB_AUDIOCONTROL_SUBCLASS, PROTOCOL_NONE); + + // Audio control interface (mandatory) [UAC 4.3.1] + let mut interface = func.interface(); + let control_interface = interface.interface_number().into(); + let streaming_interface = u8::from(control_interface) + 1; + let mut alt = interface.alt_setting(USB_AUDIO_CLASS, USB_AUDIOCONTROL_SUBCLASS, PROTOCOL_NONE, None); + + // Terminal topology: + // Input terminal (receives audio stream) -> Feature Unit (mute and volume) -> Output terminal (e.g. towards speaker) + + // ======================================= + // Input Terminal Descriptor [UAC 3.3.2.1] + // Audio input + let terminal_type: u16 = TerminalType::UsbStreaming.into(); + + // Assemble channel configuration field + let mut channel_config: u16 = ChannelConfig::None.into(); + for channel in channels { + let channel: u16 = channel.get_channel_config().into(); + + if channel_config & channel != 0 { + panic!("Invalid channel config, duplicate channel {}.", channel); + } + channel_config |= channel; + } + + let input_terminal_descriptor = [ + INPUT_TERMINAL, // bDescriptorSubtype + INPUT_UNIT_ID, // bTerminalID + terminal_type as u8, + (terminal_type >> 8) as u8, // wTerminalType + 0x00, // bAssocTerminal (none) + channels.len() as u8, // bNrChannels + channel_config as u8, + (channel_config >> 8) as u8, // wChannelConfig + 0x00, // iChannelNames (none) + 0x00, // iTerminal (none) + ]; + + // ======================================== + // Output Terminal Descriptor [UAC 4.3.2.2] + // Speaker output + let terminal_type: u16 = TerminalType::OutSpeaker.into(); + let output_terminal_descriptor = [ + OUTPUT_TERMINAL, // bDescriptorSubtype + OUTPUT_UNIT_ID, // bTerminalID + terminal_type as u8, + (terminal_type >> 8) as u8, // wTerminalType + 0x00, // bAssocTerminal (none) + FEATURE_UNIT_ID, // bSourceID (the feature unit) + 0x00, // iTerminal (none) + ]; + + // ===================================== + // Feature Unit Descriptor [UAC 4.3.2.5] + // Mute and volume control + let controls = MUTE_CONTROL | VOLUME_CONTROL; + + const FEATURE_UNIT_DESCRIPTOR_SIZE: usize = 5; + let mut feature_unit_descriptor: Vec = + Vec::from_slice(&[ + FEATURE_UNIT, // bDescriptorSubtype (Feature Unit) + FEATURE_UNIT_ID, // bUnitID + INPUT_UNIT_ID, // bSourceID + 1, // bControlSize (one byte per control) + FU_CONTROL_UNDEFINED, // Master controls (disabled, use only per-channel control) + ]) + .unwrap(); + + // Add per-channel controls + for _channel in channels { + feature_unit_descriptor.push(controls).unwrap(); + } + feature_unit_descriptor.push(0x00).unwrap(); // iFeature (none) + + // =============================================== + // Format desciptor [UAC 4.5.3] + // Used later, for operational streaming interface + let mut format_descriptor: Vec = Vec::from_slice(&[ + FORMAT_TYPE, // bDescriptorSubtype + FORMAT_TYPE_I, // bFormatType + channels.len() as u8, // bNrChannels + resolution as u8, // bSubframeSize + resolution.in_bit() as u8, // bBitResolution + ]) + .unwrap(); + + format_descriptor.push(sample_rates_hz.len() as u8).unwrap(); + + for sample_rate_hz in sample_rates_hz { + assert!(*sample_rate_hz <= MAX_SAMPLE_RATE_HZ); + format_descriptor.push((sample_rate_hz & 0xFF) as u8).unwrap(); + format_descriptor.push(((sample_rate_hz >> 8) & 0xFF) as u8).unwrap(); + format_descriptor.push(((sample_rate_hz >> 16) & 0xFF) as u8).unwrap(); + } + + // ================================================== + // Class-specific AC Interface Descriptor [UAC 4.3.2] + const DESCRIPTOR_HEADER_SIZE: usize = 2; + const INTERFACE_DESCRIPTOR_SIZE: usize = 7; + + let mut total_descriptor_length = 0; + + for size in [ + INTERFACE_DESCRIPTOR_SIZE, + input_terminal_descriptor.len(), + feature_unit_descriptor.len(), + output_terminal_descriptor.len(), + ] { + total_descriptor_length += size + DESCRIPTOR_HEADER_SIZE; + } + + let interface_descriptor: [u8; INTERFACE_DESCRIPTOR_SIZE] = [ + HEADER_SUBTYPE, // bDescriptorSubtype (Header) + ADC_VERSION as u8, + (ADC_VERSION >> 8) as u8, // bcdADC + total_descriptor_length as u8, + (total_descriptor_length >> 8) as u8, // wTotalLength + 0x01, // bInCollection (1 streaming interface) + streaming_interface, // baInterfaceNr + ]; + + alt.descriptor(CS_INTERFACE, &interface_descriptor); + alt.descriptor(CS_INTERFACE, &input_terminal_descriptor); + alt.descriptor(CS_INTERFACE, &feature_unit_descriptor); + alt.descriptor(CS_INTERFACE, &output_terminal_descriptor); + + // ===================================================== + // Audio streaming interface, zero-bandwidth [UAC 4.5.1] + let mut interface = func.interface(); + let alt = interface.alt_setting(USB_AUDIO_CLASS, USB_AUDIOSTREAMING_SUBCLASS, PROTOCOL_NONE, None); + drop(alt); + + // ================================================== + // Audio streaming interface, operational [UAC 4.5.1] + let mut alt = interface.alt_setting(USB_AUDIO_CLASS, USB_AUDIOSTREAMING_SUBCLASS, PROTOCOL_NONE, None); + + alt.descriptor( + CS_INTERFACE, + &[ + AS_GENERAL, // bDescriptorSubtype + INPUT_UNIT_ID, // bTerminalLink + 0x00, // bDelay (none) + PCM as u8, + (PCM >> 8) as u8, // wFormatTag (PCM format) + ], + ); + + alt.descriptor(CS_INTERFACE, &format_descriptor); + + let streaming_endpoint = alt.alloc_endpoint_out(EndpointType::Isochronous, max_packet_size, 1); + let feedback_endpoint = alt.alloc_endpoint_in( + EndpointType::Isochronous, + 4, // Feedback packets are 24 bit (10.14 format). + 1, + ); + + // Write the descriptor for the streaming endpoint, after knowing the address of the feedback endpoint. + alt.endpoint_descriptor( + streaming_endpoint.info(), + SynchronizationType::Asynchronous, + UsageType::DataEndpoint, + &[ + 0x00, // bRefresh (0) + feedback_endpoint.info().addr.into(), // bSynchAddress (the feedback endpoint) + ], + ); + + alt.descriptor( + CS_ENDPOINT, + &[ + AS_GENERAL, // bDescriptorSubtype (General) + SAMPLING_FREQ_CONTROL, // bmAttributes (support sampling frequency control) + 0x02, // bLockDelayUnits (PCM) + 0x0000 as u8, + (0x0000 >> 8) as u8, // wLockDelay (0) + ], + ); + + // Write the feedback endpoint descriptor after the streaming endpoint descriptor + // This is demanded by the USB audio class specification. + alt.endpoint_descriptor( + feedback_endpoint.info(), + SynchronizationType::NoSynchronization, + UsageType::FeedbackEndpoint, + &[ + feedback_refresh_period as u8, // bRefresh + 0x00, // bSynchAddress (none) + ], + ); + + // Free up the builder. + drop(func); + + // Store channel information + state.shared.channels = channels; + + state.control = Some(Control { + shared: &state.shared, + streaming_endpoint_address: streaming_endpoint.info().addr.into(), + control_interface_number: control_interface, + }); + + builder.handler(state.control.as_mut().unwrap()); + + let control = &state.shared; + + ( + Stream { streaming_endpoint }, + Feedback { feedback_endpoint }, + ControlMonitor { shared: control }, + ) + } +} + +/// Audio settings for the feature unit. +/// +/// Contains volume and mute control. +#[derive(Clone, Copy, Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct AudioSettings { + /// Channel mute states. + muted: [bool; MAX_AUDIO_CHANNEL_COUNT], + /// Channel volume levels in 8.8 format (in dB). + volume_8q8_db: [i16; MAX_AUDIO_CHANNEL_COUNT], +} + +impl Default for AudioSettings { + fn default() -> Self { + AudioSettings { + muted: [true; MAX_AUDIO_CHANNEL_COUNT], + volume_8q8_db: [MAX_VOLUME_DB * VOLUME_STEPS_PER_DB; MAX_AUDIO_CHANNEL_COUNT], + } + } +} + +struct Control<'d> { + control_interface_number: InterfaceNumber, + streaming_endpoint_address: u8, + shared: &'d SharedControl<'d>, +} + +/// Shared data between [`Control`] and the [`Speaker`] class. +struct SharedControl<'d> { + /// The collection of audio settings (volumes, mute states). + audio_settings: CriticalSectionMutex>, + + /// Channel assignments. + channels: &'d [Channel], + + /// The audio sample rate in Hz. + sample_rate_hz: AtomicU32, + + // Notification mechanism. + waker: RefCell, + changed: AtomicBool, +} + +impl<'d> Default for SharedControl<'d> { + fn default() -> Self { + SharedControl { + audio_settings: CriticalSectionMutex::new(Cell::new(AudioSettings::default())), + channels: &[], + sample_rate_hz: AtomicU32::new(0), + waker: RefCell::new(WakerRegistration::new()), + changed: AtomicBool::new(false), + } + } +} + +impl<'d> SharedControl<'d> { + async fn changed(&self) { + poll_fn(|context| { + if self.changed.load(Ordering::Relaxed) { + self.changed.store(false, Ordering::Relaxed); + Poll::Ready(()) + } else { + self.waker.borrow_mut().register(context.waker()); + Poll::Pending + } + }) + .await; + } +} + +/// Used for reading audio frames. +pub struct Stream<'d, D: Driver<'d>> { + streaming_endpoint: D::EndpointOut, +} + +impl<'d, D: Driver<'d>> Stream<'d, D> { + /// Reads a single packet from the OUT endpoint + pub async fn read_packet(&mut self, data: &mut [u8]) -> Result { + self.streaming_endpoint.read(data).await + } + + /// Waits for the USB host to enable this interface + pub async fn wait_connection(&mut self) { + self.streaming_endpoint.wait_enabled().await; + } +} + +/// Used for writing sample rate information over the feedback endpoint. +pub struct Feedback<'d, D: Driver<'d>> { + feedback_endpoint: D::EndpointIn, +} + +impl<'d, D: Driver<'d>> Feedback<'d, D> { + /// Writes a single packet into the IN endpoint. + pub async fn write_packet(&mut self, data: &[u8]) -> Result<(), EndpointError> { + self.feedback_endpoint.write(data).await + } + + /// Waits for the USB host to enable this interface. + pub async fn wait_connection(&mut self) { + self.feedback_endpoint.wait_enabled().await; + } +} + +/// Control status change monitor +/// +/// Await [`ControlMonitor::changed`] for being notified of configuration changes. Afterwards, the updated +/// configuration settings can be read with [`ControlMonitor::volume`] and [`ControlMonitor::sample_rate_hz`]. +pub struct ControlMonitor<'d> { + shared: &'d SharedControl<'d>, +} + +impl<'d> ControlMonitor<'d> { + fn audio_settings(&self) -> AudioSettings { + let audio_settings = self.shared.audio_settings.lock(|x| x.get()); + + audio_settings + } + + fn get_logical_channel(&self, search_channel: Channel) -> Option { + let index = self.shared.channels.iter().position(|&c| c == search_channel)?; + + // The logical channels start at one (zero is the master channel). + Some(index + 1) + } + + /// Get the volume of a selected channel. + pub fn volume(&self, channel: Channel) -> Option { + let channel_index = self.get_logical_channel(channel)?; + + if self.audio_settings().muted[channel_index] { + return Some(Volume::Muted); + } + + Some(Volume::DeciBel( + (self.audio_settings().volume_8q8_db[channel_index] as f32) / 256.0f32, + )) + } + + /// Get the streaming endpoint's sample rate in Hz. + pub fn sample_rate_hz(&self) -> u32 { + self.shared.sample_rate_hz.load(Ordering::Relaxed) + } + + /// Return a future for when the control settings change. + pub async fn changed(&self) { + self.shared.changed().await; + } +} + +impl<'d> Control<'d> { + fn changed(&mut self) { + self.shared.changed.store(true, Ordering::Relaxed); + self.shared.waker.borrow_mut().wake(); + } + + fn interface_set_mute_state( + &mut self, + audio_settings: &mut AudioSettings, + channel_index: u8, + data: &[u8], + ) -> OutResponse { + let mute_state = data[0] != 0; + + match channel_index as usize { + ..=MAX_AUDIO_CHANNEL_INDEX => { + audio_settings.muted[channel_index as usize] = mute_state; + } + _ => { + debug!("Failed to set channel {} mute state: {}", channel_index, mute_state); + return OutResponse::Rejected; + } + } + + debug!("Set channel {} mute state: {}", channel_index, mute_state); + OutResponse::Accepted + } + + fn interface_set_volume( + &mut self, + audio_settings: &mut AudioSettings, + channel_index: u8, + data: &[u8], + ) -> OutResponse { + let volume = i16::from_ne_bytes(data[..2].try_into().expect("Failed to read volume.")); + + match channel_index as usize { + ..=MAX_AUDIO_CHANNEL_INDEX => { + audio_settings.volume_8q8_db[channel_index as usize] = volume; + } + _ => { + debug!("Failed to set channel {} volume: {}", channel_index, volume); + return OutResponse::Rejected; + } + } + + debug!("Set channel {} volume: {}", channel_index, volume); + OutResponse::Accepted + } + + fn interface_set_request(&mut self, req: control::Request, data: &[u8]) -> Option { + let interface_number = req.index as u8; + let entity_index = (req.index >> 8) as u8; + let channel_index = req.value as u8; + let control_unit = (req.value >> 8) as u8; + + if interface_number != self.control_interface_number.into() { + debug!("Unhandled interface set request for interface {}", interface_number); + return None; + } + + if entity_index != FEATURE_UNIT_ID { + debug!("Unsupported interface set request for entity {}", entity_index); + return Some(OutResponse::Rejected); + } + + if req.request != SET_CUR { + debug!("Unsupported interface set request type {}", req.request); + return Some(OutResponse::Rejected); + } + + let mut audio_settings = self.shared.audio_settings.lock(|x| x.get()); + let response = match control_unit { + MUTE_CONTROL => self.interface_set_mute_state(&mut audio_settings, channel_index, data), + VOLUME_CONTROL => self.interface_set_volume(&mut audio_settings, channel_index, data), + _ => OutResponse::Rejected, + }; + + if response == OutResponse::Rejected { + return Some(response); + } + + // Store updated settings + self.shared.audio_settings.lock(|x| x.set(audio_settings)); + + self.changed(); + + Some(OutResponse::Accepted) + } + + fn endpoint_set_request(&mut self, req: control::Request, data: &[u8]) -> Option { + let control_selector = (req.value >> 8) as u8; + let endpoint_address = req.index as u8; + + if endpoint_address != self.streaming_endpoint_address { + debug!( + "Unhandled endpoint set request for endpoint {} and control {} with data {}", + endpoint_address, control_selector, data + ); + return None; + } + + if control_selector != SAMPLING_FREQ_CONTROL { + debug!( + "Unsupported endpoint set request for control selector {}", + control_selector + ); + return Some(OutResponse::Rejected); + } + + let sample_rate_hz: u32 = (data[0] as u32) | (data[1] as u32) << 8 | (data[2] as u32) << 16; + self.shared.sample_rate_hz.store(sample_rate_hz, Ordering::Relaxed); + + debug!("Set endpoint {} sample rate to {} Hz", endpoint_address, sample_rate_hz); + + self.changed(); + + Some(OutResponse::Accepted) + } + + fn interface_get_request<'r>(&'r mut self, req: Request, buf: &'r mut [u8]) -> Option> { + let interface_number = req.index as u8; + let entity_index = (req.index >> 8) as u8; + let channel_index = req.value as u8; + let control_unit = (req.value >> 8) as u8; + + if interface_number != self.control_interface_number.into() { + debug!("Unhandled interface get request for interface {}.", interface_number); + return None; + } + + if entity_index != FEATURE_UNIT_ID { + // Only this function unit can be handled at the moment. + debug!("Unsupported interface get request for entity {}.", entity_index); + return Some(InResponse::Rejected); + } + + let audio_settings = self.shared.audio_settings.lock(|x| x.get()); + + match req.request { + GET_CUR => match control_unit { + VOLUME_CONTROL => { + let volume: i16; + + match channel_index as usize { + ..=MAX_AUDIO_CHANNEL_INDEX => volume = audio_settings.volume_8q8_db[channel_index as usize], + _ => return Some(InResponse::Rejected), + } + + buf[0] = volume as u8; + buf[1] = (volume >> 8) as u8; + + debug!("Got channel {} volume: {}.", channel_index, volume); + return Some(InResponse::Accepted(&buf[..2])); + } + MUTE_CONTROL => { + let mute_state: bool; + + match channel_index as usize { + ..=MAX_AUDIO_CHANNEL_INDEX => mute_state = audio_settings.muted[channel_index as usize], + _ => return Some(InResponse::Rejected), + } + + buf[0] = mute_state.into(); + debug!("Got channel {} mute state: {}.", channel_index, mute_state); + return Some(InResponse::Accepted(&buf[..1])); + } + _ => return Some(InResponse::Rejected), + }, + GET_MIN => match control_unit { + VOLUME_CONTROL => { + let min_volume = MIN_VOLUME_DB * VOLUME_STEPS_PER_DB; + buf[0] = min_volume as u8; + buf[1] = (min_volume >> 8) as u8; + return Some(InResponse::Accepted(&buf[..2])); + } + _ => return Some(InResponse::Rejected), + }, + GET_MAX => match control_unit { + VOLUME_CONTROL => { + let max_volume = MAX_VOLUME_DB * VOLUME_STEPS_PER_DB; + buf[0] = max_volume as u8; + buf[1] = (max_volume >> 8) as u8; + return Some(InResponse::Accepted(&buf[..2])); + } + _ => return Some(InResponse::Rejected), + }, + GET_RES => match control_unit { + VOLUME_CONTROL => { + buf[0] = VOLUME_STEPS_PER_DB as u8; + buf[1] = (VOLUME_STEPS_PER_DB >> 8) as u8; + return Some(InResponse::Accepted(&buf[..2])); + } + _ => return Some(InResponse::Rejected), + }, + _ => return Some(InResponse::Rejected), + } + } + + fn endpoint_get_request<'r>(&'r mut self, req: Request, buf: &'r mut [u8]) -> Option> { + let control_selector = (req.value >> 8) as u8; + let endpoint_address = req.index as u8; + + if endpoint_address != self.streaming_endpoint_address { + debug!("Unhandled endpoint get request for endpoint {}.", endpoint_address); + return None; + } + + if control_selector != SAMPLING_FREQ_CONTROL as u8 { + debug!( + "Unsupported endpoint get request for control selector {}.", + control_selector + ); + return Some(InResponse::Rejected); + } + + let sample_rate_hz = self.shared.sample_rate_hz.load(Ordering::Relaxed); + + buf[0] = (sample_rate_hz & 0xFF) as u8; + buf[1] = ((sample_rate_hz >> 8) & 0xFF) as u8; + buf[2] = ((sample_rate_hz >> 16) & 0xFF) as u8; + + Some(InResponse::Accepted(&buf[..3])) + } +} + +impl<'d> Handler for Control<'d> { + /// Called when the USB device has been enabled or disabled. + fn enabled(&mut self, enabled: bool) { + debug!("USB device enabled: {}", enabled); + } + + /// Called when the host has set the address of the device to `addr`. + fn addressed(&mut self, addr: u8) { + debug!("Host set address to: {}", addr); + } + + /// Called when the host has enabled or disabled the configuration of the device. + fn configured(&mut self, configured: bool) { + debug!("USB device configured: {}", configured); + } + + /// Called when remote wakeup feature is enabled or disabled. + fn remote_wakeup_enabled(&mut self, enabled: bool) { + debug!("USB remote wakeup enabled: {}", enabled); + } + + /// Called when a "set alternate setting" control request is done on the interface. + fn set_alternate_setting(&mut self, iface: InterfaceNumber, alternate_setting: u8) { + debug!( + "USB set interface number {} to alt setting {}.", + iface, alternate_setting + ); + } + + /// Called after a USB reset after the bus reset sequence is complete. + fn reset(&mut self) { + let shared = self.shared; + shared.audio_settings.lock(|x| x.set(AudioSettings::default())); + + shared.changed.store(true, Ordering::Relaxed); + shared.waker.borrow_mut().wake(); + } + + /// Called when the bus has entered or exited the suspend state. + fn suspended(&mut self, suspended: bool) { + debug!("USB device suspended: {}", suspended); + } + + // Handle control set requests. + fn control_out(&mut self, req: control::Request, data: &[u8]) -> Option { + match req.request_type { + RequestType::Class => match req.recipient { + Recipient::Interface => self.interface_set_request(req, data), + Recipient::Endpoint => self.endpoint_set_request(req, data), + _ => Some(OutResponse::Rejected), + }, + _ => None, + } + } + + // Handle control get requests. + fn control_in<'a>(&'a mut self, req: Request, buf: &'a mut [u8]) -> Option> { + match req.request_type { + RequestType::Class => match req.recipient { + Recipient::Interface => self.interface_get_request(req, buf), + Recipient::Endpoint => self.endpoint_get_request(req, buf), + _ => None, + }, + _ => None, + } + } +} diff --git a/embassy-usb/src/class/uac1/terminal_type.rs b/embassy-usb/src/class/uac1/terminal_type.rs new file mode 100644 index 000000000..65474a714 --- /dev/null +++ b/embassy-usb/src/class/uac1/terminal_type.rs @@ -0,0 +1,50 @@ +//! USB Audio Terminal Types from Universal Serial Bus Device Class Definition +//! for Terminal Types, Release 1.0 + +/// USB Audio Terminal Types from "Universal Serial Bus Device Class Definition +/// for Terminal Types, Release 1.0" +#[repr(u16)] +#[non_exhaustive] +#[derive(Copy, Clone, Eq, PartialEq, Debug)] +#[allow(missing_docs)] +pub enum TerminalType { + // USB Terminal Types + UsbUndefined = 0x0100, + UsbStreaming = 0x0101, + UsbVendor = 0x01ff, + + // Input Terminal Types + InUndefined = 0x0200, + InMicrophone = 0x0201, + InDesktopMicrophone = 0x0202, + InPersonalMicrophone = 0x0203, + InOmniDirectionalMicrophone = 0x0204, + InMicrophoneArray = 0x0205, + InProcessingMicrophoneArray = 0x0206, + + // Output Terminal Types + OutUndefined = 0x0300, + OutSpeaker = 0x0301, + OutHeadphones = 0x0302, + OutHeadMountedDisplayAudio = 0x0303, + OutDesktopSpeaker = 0x0304, + OutRoomSpeaker = 0x0305, + OutCommunicationSpeaker = 0x0306, + OutLowFrequencyEffectsSpeaker = 0x0307, + + // External Terminal Types + ExtUndefined = 0x0600, + ExtAnalogConnector = 0x0601, + ExtDigitalAudioInterface = 0x0602, + ExtLineConnector = 0x0603, + ExtLegacyAudioConnector = 0x0604, + ExtSpdifConnector = 0x0605, + Ext1394DaStream = 0x0606, + Ext1394DvStreamSoundtrack = 0x0607, +} + +impl From for u16 { + fn from(t: TerminalType) -> u16 { + t as u16 + } +} From 0d299301efaa0843d3da09909f02e795eeffc035 Mon Sep 17 00:00:00 2001 From: elagil Date: Sat, 2 Nov 2024 20:01:20 +0100 Subject: [PATCH 0391/1217] feat(stm32f4): add usb audio example --- examples/stm32f4/Cargo.toml | 1 + examples/stm32f4/src/bin/usb_uac_speaker.rs | 375 ++++++++++++++++++++ 2 files changed, 376 insertions(+) create mode 100644 examples/stm32f4/src/bin/usb_uac_speaker.rs diff --git a/examples/stm32f4/Cargo.toml b/examples/stm32f4/Cargo.toml index 75e315e82..435b0b43c 100644 --- a/examples/stm32f4/Cargo.toml +++ b/examples/stm32f4/Cargo.toml @@ -27,6 +27,7 @@ embedded-io-async = { version = "0.6.1" } panic-probe = { version = "0.3", features = ["print-defmt"] } futures-util = { version = "0.3.30", default-features = false } heapless = { version = "0.8", default-features = false } +critical-section = "1.1" nb = "1.0.0" embedded-storage = "0.3.1" micromath = "2.0.0" diff --git a/examples/stm32f4/src/bin/usb_uac_speaker.rs b/examples/stm32f4/src/bin/usb_uac_speaker.rs new file mode 100644 index 000000000..77c693ace --- /dev/null +++ b/examples/stm32f4/src/bin/usb_uac_speaker.rs @@ -0,0 +1,375 @@ +#![no_std] +#![no_main] + +use core::cell::RefCell; + +use defmt::{panic, *}; +use embassy_executor::Spawner; +use embassy_stm32::time::Hertz; +use embassy_stm32::{bind_interrupts, interrupt, peripherals, timer, usb, Config}; +use embassy_sync::blocking_mutex::raw::{CriticalSectionRawMutex, NoopRawMutex}; +use embassy_sync::blocking_mutex::Mutex; +use embassy_sync::signal::Signal; +use embassy_sync::zerocopy_channel; +use embassy_usb::class::uac1; +use embassy_usb::class::uac1::speaker::{self, Speaker}; +use embassy_usb::driver::EndpointError; +use heapless::Vec; +use micromath::F32Ext; +use static_cell::StaticCell; +use {defmt_rtt as _, panic_probe as _}; + +bind_interrupts!(struct Irqs { + OTG_FS => usb::InterruptHandler; +}); + +static TIMER: Mutex>>> = + Mutex::new(RefCell::new(None)); + +// A counter signal that is written by the feedback timer, once every `FEEDBACK_REFRESH_PERIOD`. +// At that point, a feedback value is sent to the host. +pub static FEEDBACK_SIGNAL: Signal = Signal::new(); + +// Stereo input +pub const INPUT_CHANNEL_COUNT: usize = 2; + +// This example uses a fixed sample rate of 48 kHz. +pub const SAMPLE_RATE_HZ: u32 = 48_000; +pub const FEEDBACK_COUNTER_TICK_RATE: u32 = 42_000_000; + +// Use 32 bit samples, which allow for a lot of (software) volume adjustment without degradation of quality. +pub const SAMPLE_WIDTH: uac1::SampleWidth = uac1::SampleWidth::Width4Byte; +pub const SAMPLE_WIDTH_BIT: usize = SAMPLE_WIDTH.in_bit(); +pub const SAMPLE_SIZE: usize = SAMPLE_WIDTH as usize; +pub const SAMPLE_SIZE_PER_S: usize = (SAMPLE_RATE_HZ as usize) * INPUT_CHANNEL_COUNT * SAMPLE_SIZE; + +// Size of audio samples per 1 ms - for the full-speed USB frame period of 1 ms. +pub const USB_FRAME_SIZE: usize = SAMPLE_SIZE_PER_S.div_ceil(1000); + +// Select front left and right audio channels. +pub const AUDIO_CHANNELS: [uac1::Channel; INPUT_CHANNEL_COUNT] = [uac1::Channel::LeftFront, uac1::Channel::RightFront]; + +// Factor of two as a margin for feedback (this is an excessive amount) +pub const USB_MAX_PACKET_SIZE: usize = 2 * USB_FRAME_SIZE; +pub const USB_MAX_SAMPLE_COUNT: usize = USB_MAX_PACKET_SIZE / SAMPLE_SIZE; + +// The data type that is exchanged via the zero-copy channel (a sample vector). +pub type SampleBlock = Vec; + +// Feedback is provided in 10.14 format for full-speed endpoints. +pub const FEEDBACK_REFRESH_PERIOD: uac1::FeedbackRefresh = uac1::FeedbackRefresh::Period8Frames; +const FEEDBACK_SHIFT: usize = 14; + +const TICKS_PER_SAMPLE: f32 = (FEEDBACK_COUNTER_TICK_RATE as f32) / (SAMPLE_RATE_HZ as f32); + +struct Disconnected {} + +impl From for Disconnected { + fn from(val: EndpointError) -> Self { + match val { + EndpointError::BufferOverflow => panic!("Buffer overflow"), + EndpointError::Disabled => Disconnected {}, + } + } +} + +/// Sends feedback messages to the host. +async fn feedback_handler<'d, T: usb::Instance + 'd>( + feedback: &mut speaker::Feedback<'d, usb::Driver<'d, T>>, + feedback_factor: f32, +) -> Result<(), Disconnected> { + let mut packet: Vec = Vec::new(); + + // Collects the fractional component of the feedback value that is lost by rounding. + let mut rest = 0.0_f32; + + loop { + let counter = FEEDBACK_SIGNAL.wait().await; + + packet.clear(); + + let raw_value = counter as f32 * feedback_factor + rest; + let value = raw_value.round(); + rest = raw_value - value; + + let value = value as u32; + packet.push(value as u8).unwrap(); + packet.push((value >> 8) as u8).unwrap(); + packet.push((value >> 16) as u8).unwrap(); + + feedback.write_packet(&packet).await?; + } +} + +/// Handles streaming of audio data from the host. +async fn stream_handler<'d, T: usb::Instance + 'd>( + stream: &mut speaker::Stream<'d, usb::Driver<'d, T>>, + sender: &mut zerocopy_channel::Sender<'static, NoopRawMutex, SampleBlock>, +) -> Result<(), Disconnected> { + loop { + let mut usb_data = [0u8; USB_MAX_PACKET_SIZE]; + let data_size = stream.read_packet(&mut usb_data).await?; + + let word_count = data_size / SAMPLE_SIZE; + + if word_count * SAMPLE_SIZE == data_size { + // Obtain a buffer from the channel + let samples = sender.send().await; + samples.clear(); + + for w in 0..word_count { + let byte_offset = w * SAMPLE_SIZE; + let sample = u32::from_le_bytes(usb_data[byte_offset..byte_offset + SAMPLE_SIZE].try_into().unwrap()); + + // Fill the sample buffer with data. + samples.push(sample).unwrap(); + } + + sender.send_done(); + } else { + debug!("Invalid USB buffer size of {}, skipped.", data_size); + } + } +} + +/// Receives audio samples from the USB streaming task and can play them back. +#[embassy_executor::task] +async fn audio_receiver_task(mut usb_audio_receiver: zerocopy_channel::Receiver<'static, NoopRawMutex, SampleBlock>) { + loop { + let _samples = usb_audio_receiver.receive().await; + // Use the samples, for example play back via the SAI peripheral. + + // Notify the channel that the buffer is now ready to be reused + usb_audio_receiver.receive_done(); + } +} + +/// Receives audio samples from the host. +#[embassy_executor::task] +async fn usb_streaming_task( + mut stream: speaker::Stream<'static, usb::Driver<'static, peripherals::USB_OTG_FS>>, + mut sender: zerocopy_channel::Sender<'static, NoopRawMutex, SampleBlock>, +) { + loop { + stream.wait_connection().await; + _ = stream_handler(&mut stream, &mut sender).await; + } +} + +/// Sends sample rate feedback to the host. +/// +/// The `feedback_factor` scales the feedback timer's counter value so that the result is the number of samples that +/// this device played back or "consumed" during one SOF period (1 ms) - in 10.14 format. +/// +/// Ideally, the `feedback_factor` that is calculated below would be an integer for avoiding numerical errors. +/// This is achieved by having `TICKS_PER_SAMPLE` be a power of two. For audio applications at a sample rate of 48 kHz, +/// 24.576 MHz would be one such option. +/// +/// A good choice for the STM32F4, which also has to generate a 48 MHz clock from its HSE (e.g. running at 8 MHz) +/// for USB, is to clock the feedback timer from the MCLK output of the SAI peripheral. The SAI peripheral then uses an +/// external clock. In that case, wiring the MCLK output to the timer clock input is required. +/// +/// This simple example just uses the internal clocks for supplying the feedback timer, +/// and does not even set up a SAI peripheral. +#[embassy_executor::task] +async fn usb_feedback_task(mut feedback: speaker::Feedback<'static, usb::Driver<'static, peripherals::USB_OTG_FS>>) { + let feedback_factor = + ((1 << FEEDBACK_SHIFT) as f32 / TICKS_PER_SAMPLE) / FEEDBACK_REFRESH_PERIOD.frame_count() as f32; + + // Should be 2.3405714285714287... + info!("Using a feedback factor of {}.", feedback_factor); + + loop { + feedback.wait_connection().await; + _ = feedback_handler(&mut feedback, feedback_factor).await; + } +} + +#[embassy_executor::task] +async fn usb_task(mut usb_device: embassy_usb::UsbDevice<'static, usb::Driver<'static, peripherals::USB_OTG_FS>>) { + usb_device.run().await; +} + +/// Checks for changes on the control monitor of the class. +/// +/// In this case, monitor changes of volume or mute state. +#[embassy_executor::task] +async fn usb_control_task(control_monitor: speaker::ControlMonitor<'static>) { + loop { + control_monitor.changed().await; + + for channel in AUDIO_CHANNELS { + let volume = control_monitor.volume(channel).unwrap(); + info!("Volume changed to {} on channel {}.", volume, channel); + } + } +} + +/// Feedback value measurement and calculation +/// +/// Used for measuring/calculating the number of samples that were received from the host during the +/// `FEEDBACK_REFRESH_PERIOD`. +/// +/// Configured in this example with +/// - a refresh period of 8 ms, and +/// - a tick rate of 42 MHz. +/// +/// This gives an (ideal) counter value of 336.000 for every update of the `FEEDBACK_SIGNAL`. +#[interrupt] +fn TIM2() { + static mut LAST_TICKS: u32 = 0; + static mut FRAME_COUNT: usize = 0; + + critical_section::with(|cs| { + // Read timer counter. + let ticks = TIMER.borrow(cs).borrow().as_ref().unwrap().regs_gp32().cnt().read(); + + // Clear trigger interrupt flag. + TIMER + .borrow(cs) + .borrow_mut() + .as_mut() + .unwrap() + .regs_gp32() + .sr() + .modify(|r| r.set_tif(false)); + + // Count up frames and emit a signal, when the refresh period is reached (here, every 8 ms). + *FRAME_COUNT += 1; + if *FRAME_COUNT >= FEEDBACK_REFRESH_PERIOD.frame_count() { + *FRAME_COUNT = 0; + FEEDBACK_SIGNAL.signal(ticks.wrapping_sub(*LAST_TICKS)); + *LAST_TICKS = ticks; + } + }); +} + +// If you are trying this and your USB device doesn't connect, the most +// common issues are the RCC config and vbus_detection +// +// See https://embassy.dev/book/#_the_usb_examples_are_not_working_on_my_board_is_there_anything_else_i_need_to_configure +// for more information. +#[embassy_executor::main] +async fn main(spawner: Spawner) { + info!("Hello World!"); + + let mut config = Config::default(); + { + use embassy_stm32::rcc::*; + config.rcc.hse = Some(Hse { + freq: Hertz(8_000_000), + mode: HseMode::Bypass, + }); + config.rcc.pll_src = PllSource::HSE; + config.rcc.pll = Some(Pll { + prediv: PllPreDiv::DIV4, + mul: PllMul::MUL168, + divp: Some(PllPDiv::DIV2), // ((8 MHz / 4) * 168) / 2 = 168 Mhz. + divq: Some(PllQDiv::DIV7), // ((8 MHz / 4) * 168) / 7 = 48 Mhz. + divr: None, + }); + config.rcc.ahb_pre = AHBPrescaler::DIV1; + config.rcc.apb1_pre = APBPrescaler::DIV4; + config.rcc.apb2_pre = APBPrescaler::DIV2; + config.rcc.sys = Sysclk::PLL1_P; + config.rcc.mux.clk48sel = mux::Clk48sel::PLL1_Q; + } + let p = embassy_stm32::init(config); + + // Configure all required buffers in a static way. + debug!("USB packet size is {} byte", USB_MAX_PACKET_SIZE); + static CONFIG_DESCRIPTOR: StaticCell<[u8; 256]> = StaticCell::new(); + let config_descriptor = CONFIG_DESCRIPTOR.init([0; 256]); + + static BOS_DESCRIPTOR: StaticCell<[u8; 32]> = StaticCell::new(); + let bos_descriptor = BOS_DESCRIPTOR.init([0; 32]); + + const CONTROL_BUF_SIZE: usize = 64; + static CONTROL_BUF: StaticCell<[u8; CONTROL_BUF_SIZE]> = StaticCell::new(); + let control_buf = CONTROL_BUF.init([0; CONTROL_BUF_SIZE]); + + const FEEDBACK_BUF_SIZE: usize = 4; + static EP_OUT_BUFFER: StaticCell<[u8; FEEDBACK_BUF_SIZE + CONTROL_BUF_SIZE + USB_MAX_PACKET_SIZE]> = + StaticCell::new(); + let ep_out_buffer = EP_OUT_BUFFER.init([0u8; FEEDBACK_BUF_SIZE + CONTROL_BUF_SIZE + USB_MAX_PACKET_SIZE]); + + static STATE: StaticCell = StaticCell::new(); + let state = STATE.init(speaker::State::new()); + + // Create the driver, from the HAL. + let mut usb_config = usb::Config::default(); + + // Do not enable vbus_detection. This is a safe default that works in all boards. + // However, if your USB device is self-powered (can stay powered on if USB is unplugged), you need + // to enable vbus_detection to comply with the USB spec. If you enable it, the board + // has to support it or USB won't work at all. See docs on `vbus_detection` for details. + usb_config.vbus_detection = false; + + let usb_driver = usb::Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, ep_out_buffer, usb_config); + + // Basic USB device configuration + let mut config = embassy_usb::Config::new(0xc0de, 0xcafe); + config.manufacturer = Some("Embassy"); + config.product = Some("USB-audio-speaker example"); + config.serial_number = Some("12345678"); + + // Required for windows compatibility. + // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help + config.device_class = 0xEF; + config.device_sub_class = 0x02; + config.device_protocol = 0x01; + config.composite_with_iads = true; + + let mut builder = embassy_usb::Builder::new( + usb_driver, + config, + config_descriptor, + bos_descriptor, + &mut [], // no msos descriptors + control_buf, + ); + + // Create the UAC1 Speaker class components + let (stream, feedback, control_monitor) = Speaker::new( + &mut builder, + state, + USB_MAX_PACKET_SIZE as u16, + uac1::SampleWidth::Width4Byte, + &[SAMPLE_RATE_HZ], + &AUDIO_CHANNELS, + FEEDBACK_REFRESH_PERIOD, + ); + + // Create the USB device + let usb_device = builder.build(); + + // Establish a zero-copy channel for transferring received audio samples between tasks + static SAMPLE_BLOCKS: StaticCell<[SampleBlock; 2]> = StaticCell::new(); + let sample_blocks = SAMPLE_BLOCKS.init([Vec::new(), Vec::new()]); + + static CHANNEL: StaticCell> = StaticCell::new(); + let channel = CHANNEL.init(zerocopy_channel::Channel::new(sample_blocks)); + let (sender, receiver) = channel.split(); + + // Run a timer for counting between SOF interrupts. + let mut tim2 = timer::low_level::Timer::new(p.TIM2); + tim2.set_tick_freq(Hertz(FEEDBACK_COUNTER_TICK_RATE)); + tim2.set_trigger_source(timer::low_level::TriggerSource::ITR1); // The USB SOF signal. + tim2.set_slave_mode(timer::low_level::SlaveMode::TRIGGER_MODE); + tim2.regs_gp16().dier().modify(|r| r.set_tie(true)); // Enable the trigger interrupt. + tim2.start(); + + TIMER.lock(|p| p.borrow_mut().replace(tim2)); + + // Unmask the TIM2 interrupt. + unsafe { + cortex_m::peripheral::NVIC::unmask(interrupt::TIM2); + } + + // Launch USB audio tasks. + unwrap!(spawner.spawn(usb_control_task(control_monitor))); + unwrap!(spawner.spawn(usb_streaming_task(stream, sender))); + unwrap!(spawner.spawn(usb_feedback_task(feedback))); + unwrap!(spawner.spawn(usb_task(usb_device))); + unwrap!(spawner.spawn(audio_receiver_task(receiver))); +} From 36292ada6228bff99cb0baa916786da394e05a42 Mon Sep 17 00:00:00 2001 From: elagil Date: Sat, 2 Nov 2024 20:01:20 +0100 Subject: [PATCH 0392/1217] feat(stm32h5): add usb audio example --- examples/stm32h5/src/bin/usb_uac_speaker.rs | 367 ++++++++++++++++++++ 1 file changed, 367 insertions(+) create mode 100644 examples/stm32h5/src/bin/usb_uac_speaker.rs diff --git a/examples/stm32h5/src/bin/usb_uac_speaker.rs b/examples/stm32h5/src/bin/usb_uac_speaker.rs new file mode 100644 index 000000000..6b992690f --- /dev/null +++ b/examples/stm32h5/src/bin/usb_uac_speaker.rs @@ -0,0 +1,367 @@ +#![no_std] +#![no_main] + +use core::cell::RefCell; + +use defmt::{panic, *}; +use embassy_executor::Spawner; +use embassy_stm32::time::Hertz; +use embassy_stm32::{bind_interrupts, interrupt, peripherals, timer, usb, Config}; +use embassy_sync::blocking_mutex::raw::{CriticalSectionRawMutex, NoopRawMutex}; +use embassy_sync::blocking_mutex::Mutex; +use embassy_sync::signal::Signal; +use embassy_sync::zerocopy_channel; +use embassy_usb::class::uac1; +use embassy_usb::class::uac1::speaker::{self, Speaker}; +use embassy_usb::driver::EndpointError; +use heapless::Vec; +use micromath::F32Ext; +use static_cell::StaticCell; +use {defmt_rtt as _, panic_probe as _}; + +bind_interrupts!(struct Irqs { + USB_DRD_FS => usb::InterruptHandler; +}); + +static TIMER: Mutex>>> = + Mutex::new(RefCell::new(None)); + +// A counter signal that is written by the feedback timer, once every `FEEDBACK_REFRESH_PERIOD`. +// At that point, a feedback value is sent to the host. +pub static FEEDBACK_SIGNAL: Signal = Signal::new(); + +// Stereo input +pub const INPUT_CHANNEL_COUNT: usize = 2; + +// This example uses a fixed sample rate of 48 kHz. +pub const SAMPLE_RATE_HZ: u32 = 48_000; +pub const FEEDBACK_COUNTER_TICK_RATE: u32 = 31_250_000; + +// Use 32 bit samples, which allow for a lot of (software) volume adjustment without degradation of quality. +pub const SAMPLE_WIDTH: uac1::SampleWidth = uac1::SampleWidth::Width4Byte; +pub const SAMPLE_WIDTH_BIT: usize = SAMPLE_WIDTH.in_bit(); +pub const SAMPLE_SIZE: usize = SAMPLE_WIDTH as usize; +pub const SAMPLE_SIZE_PER_S: usize = (SAMPLE_RATE_HZ as usize) * INPUT_CHANNEL_COUNT * SAMPLE_SIZE; + +// Size of audio samples per 1 ms - for the full-speed USB frame period of 1 ms. +pub const USB_FRAME_SIZE: usize = SAMPLE_SIZE_PER_S.div_ceil(1000); + +// Select front left and right audio channels. +pub const AUDIO_CHANNELS: [uac1::Channel; INPUT_CHANNEL_COUNT] = [uac1::Channel::LeftFront, uac1::Channel::RightFront]; + +// Factor of two as a margin for feedback (this is an excessive amount) +pub const USB_MAX_PACKET_SIZE: usize = 2 * USB_FRAME_SIZE; +pub const USB_MAX_SAMPLE_COUNT: usize = USB_MAX_PACKET_SIZE / SAMPLE_SIZE; + +// The data type that is exchanged via the zero-copy channel (a sample vector). +pub type SampleBlock = Vec; + +// Feedback is provided in 10.14 format for full-speed endpoints. +pub const FEEDBACK_REFRESH_PERIOD: uac1::FeedbackRefresh = uac1::FeedbackRefresh::Period8Frames; +const FEEDBACK_SHIFT: usize = 14; + +const TICKS_PER_SAMPLE: f32 = (FEEDBACK_COUNTER_TICK_RATE as f32) / (SAMPLE_RATE_HZ as f32); + +struct Disconnected {} + +impl From for Disconnected { + fn from(val: EndpointError) -> Self { + match val { + EndpointError::BufferOverflow => panic!("Buffer overflow"), + EndpointError::Disabled => Disconnected {}, + } + } +} + +/// Sends feedback messages to the host. +async fn feedback_handler<'d, T: usb::Instance + 'd>( + feedback: &mut speaker::Feedback<'d, usb::Driver<'d, T>>, + feedback_factor: f32, +) -> Result<(), Disconnected> { + let mut packet: Vec = Vec::new(); + + // Collects the fractional component of the feedback value that is lost by rounding. + let mut rest = 0.0_f32; + + loop { + let counter = FEEDBACK_SIGNAL.wait().await; + + packet.clear(); + + let raw_value = counter as f32 * feedback_factor + rest; + let value = raw_value.round(); + rest = raw_value - value; + + let value = value as u32; + + packet.push(value as u8).unwrap(); + packet.push((value >> 8) as u8).unwrap(); + packet.push((value >> 16) as u8).unwrap(); + + feedback.write_packet(&packet).await?; + } +} + +/// Handles streaming of audio data from the host. +async fn stream_handler<'d, T: usb::Instance + 'd>( + stream: &mut speaker::Stream<'d, usb::Driver<'d, T>>, + sender: &mut zerocopy_channel::Sender<'static, NoopRawMutex, SampleBlock>, +) -> Result<(), Disconnected> { + loop { + let mut usb_data = [0u8; USB_MAX_PACKET_SIZE]; + let data_size = stream.read_packet(&mut usb_data).await?; + + let word_count = data_size / SAMPLE_SIZE; + + if word_count * SAMPLE_SIZE == data_size { + // Obtain a buffer from the channel + let samples = sender.send().await; + samples.clear(); + + for w in 0..word_count { + let byte_offset = w * SAMPLE_SIZE; + let sample = u32::from_le_bytes(usb_data[byte_offset..byte_offset + SAMPLE_SIZE].try_into().unwrap()); + + // Fill the sample buffer with data. + samples.push(sample).unwrap(); + } + + sender.send_done(); + } else { + debug!("Invalid USB buffer size of {}, skipped.", data_size); + } + } +} + +/// Receives audio samples from the USB streaming task and can play them back. +#[embassy_executor::task] +async fn audio_receiver_task(mut usb_audio_receiver: zerocopy_channel::Receiver<'static, NoopRawMutex, SampleBlock>) { + loop { + let _samples = usb_audio_receiver.receive().await; + // Use the samples, for example play back via the SAI peripheral. + + // Notify the channel that the buffer is now ready to be reused + usb_audio_receiver.receive_done(); + } +} + +/// Receives audio samples from the host. +#[embassy_executor::task] +async fn usb_streaming_task( + mut stream: speaker::Stream<'static, usb::Driver<'static, peripherals::USB>>, + mut sender: zerocopy_channel::Sender<'static, NoopRawMutex, SampleBlock>, +) { + loop { + stream.wait_connection().await; + info!("USB connected."); + _ = stream_handler(&mut stream, &mut sender).await; + info!("USB disconnected."); + } +} + +/// Sends sample rate feedback to the host. +/// +/// The `feedback_factor` scales the feedback timer's counter value so that the result is the number of samples that +/// this device played back or "consumed" during one SOF period (1 ms) - in 10.14 format. +/// +/// Ideally, the `feedback_factor` that is calculated below would be an integer for avoiding numerical errors. +/// This is achieved by having `TICKS_PER_SAMPLE` be a power of two. For audio applications at a sample rate of 48 kHz, +/// 24.576 MHz would be one such option. +#[embassy_executor::task] +async fn usb_feedback_task(mut feedback: speaker::Feedback<'static, usb::Driver<'static, peripherals::USB>>) { + let feedback_factor = + ((1 << FEEDBACK_SHIFT) as f32 / TICKS_PER_SAMPLE) / FEEDBACK_REFRESH_PERIOD.frame_count() as f32; + + loop { + feedback.wait_connection().await; + _ = feedback_handler(&mut feedback, feedback_factor).await; + } +} + +#[embassy_executor::task] +async fn usb_task(mut usb_device: embassy_usb::UsbDevice<'static, usb::Driver<'static, peripherals::USB>>) { + usb_device.run().await; +} + +/// Checks for changes on the control monitor of the class. +/// +/// In this case, monitor changes of volume or mute state. +#[embassy_executor::task] +async fn usb_control_task(control_monitor: speaker::ControlMonitor<'static>) { + loop { + control_monitor.changed().await; + + for channel in AUDIO_CHANNELS { + let volume = control_monitor.volume(channel).unwrap(); + info!("Volume changed to {} on channel {}.", volume, channel); + } + } +} + +/// Feedback value measurement and calculation +/// +/// Used for measuring/calculating the number of samples that were received from the host during the +/// `FEEDBACK_REFRESH_PERIOD`. +/// +/// Configured in this example with +/// - a refresh period of 8 ms, and +/// - a tick rate of 42 MHz. +/// +/// This gives an (ideal) counter value of 336.000 for every update of the `FEEDBACK_SIGNAL`. +#[interrupt] +fn TIM5() { + static mut LAST_TICKS: u32 = 0; + static mut FRAME_COUNT: usize = 0; + + critical_section::with(|cs| { + // Read timer counter. + let ticks = TIMER.borrow(cs).borrow().as_ref().unwrap().regs_gp32().cnt().read(); + + // Clear trigger interrupt flag. + TIMER + .borrow(cs) + .borrow_mut() + .as_mut() + .unwrap() + .regs_gp32() + .sr() + .modify(|r| r.set_tif(false)); + + // Count up frames and emit a signal, when the refresh period is reached (here, every 8 ms). + *FRAME_COUNT += 1; + if *FRAME_COUNT >= FEEDBACK_REFRESH_PERIOD.frame_count() { + *FRAME_COUNT = 0; + FEEDBACK_SIGNAL.signal(ticks.wrapping_sub(*LAST_TICKS)); + *LAST_TICKS = ticks; + } + }); +} + +// If you are trying this and your USB device doesn't connect, the most +// common issues are the RCC config and vbus_detection +// +// See https://embassy.dev/book/#_the_usb_examples_are_not_working_on_my_board_is_there_anything_else_i_need_to_configure +// for more information. +#[embassy_executor::main] +async fn main(spawner: Spawner) { + let mut config = Config::default(); + { + use embassy_stm32::rcc::*; + config.rcc.hsi = None; + config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); // needed for USB + config.rcc.hse = Some(Hse { + freq: Hertz(8_000_000), + mode: HseMode::BypassDigital, + }); + config.rcc.pll1 = Some(Pll { + source: PllSource::HSE, + prediv: PllPreDiv::DIV2, + mul: PllMul::MUL125, + divp: Some(PllDiv::DIV2), // 250 Mhz + divq: None, + divr: None, + }); + config.rcc.pll2 = Some(Pll { + source: PllSource::HSE, + prediv: PllPreDiv::DIV4, + mul: PllMul::MUL123, + divp: Some(PllDiv::DIV20), // 12.3 Mhz, close to 12.288 MHz for 48 kHz audio + divq: None, + divr: None, + }); + config.rcc.ahb_pre = AHBPrescaler::DIV2; + config.rcc.apb1_pre = APBPrescaler::DIV4; + config.rcc.apb2_pre = APBPrescaler::DIV2; + config.rcc.apb3_pre = APBPrescaler::DIV4; + config.rcc.sys = Sysclk::PLL1_P; + config.rcc.voltage_scale = VoltageScale::Scale0; + config.rcc.mux.usbsel = mux::Usbsel::HSI48; + config.rcc.mux.sai2sel = mux::Saisel::PLL2_P; + } + let p = embassy_stm32::init(config); + + info!("Hello World!"); + + // Configure all required buffers in a static way. + debug!("USB packet size is {} byte", USB_MAX_PACKET_SIZE); + static CONFIG_DESCRIPTOR: StaticCell<[u8; 256]> = StaticCell::new(); + let config_descriptor = CONFIG_DESCRIPTOR.init([0; 256]); + + static BOS_DESCRIPTOR: StaticCell<[u8; 32]> = StaticCell::new(); + let bos_descriptor = BOS_DESCRIPTOR.init([0; 32]); + + const CONTROL_BUF_SIZE: usize = 64; + static CONTROL_BUF: StaticCell<[u8; CONTROL_BUF_SIZE]> = StaticCell::new(); + let control_buf = CONTROL_BUF.init([0; CONTROL_BUF_SIZE]); + + static STATE: StaticCell = StaticCell::new(); + let state = STATE.init(speaker::State::new()); + + let usb_driver = usb::Driver::new(p.USB, Irqs, p.PA12, p.PA11); + + // Basic USB device configuration + let mut config = embassy_usb::Config::new(0xc0de, 0xcafe); + config.manufacturer = Some("Embassy"); + config.product = Some("USB-audio-speaker example"); + config.serial_number = Some("12345678"); + + // Required for windows compatibility. + // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help + config.device_class = 0xEF; + config.device_sub_class = 0x02; + config.device_protocol = 0x01; + config.composite_with_iads = true; + + let mut builder = embassy_usb::Builder::new( + usb_driver, + config, + config_descriptor, + bos_descriptor, + &mut [], // no msos descriptors + control_buf, + ); + + // Create the UAC1 Speaker class components + let (stream, feedback, control_monitor) = Speaker::new( + &mut builder, + state, + USB_MAX_PACKET_SIZE as u16, + uac1::SampleWidth::Width4Byte, + &[SAMPLE_RATE_HZ], + &AUDIO_CHANNELS, + FEEDBACK_REFRESH_PERIOD, + ); + + // Create the USB device + let usb_device = builder.build(); + + // Establish a zero-copy channel for transferring received audio samples between tasks + static SAMPLE_BLOCKS: StaticCell<[SampleBlock; 2]> = StaticCell::new(); + let sample_blocks = SAMPLE_BLOCKS.init([Vec::new(), Vec::new()]); + + static CHANNEL: StaticCell> = StaticCell::new(); + let channel = CHANNEL.init(zerocopy_channel::Channel::new(sample_blocks)); + let (sender, receiver) = channel.split(); + + // Run a timer for counting between SOF interrupts. + let mut tim5 = timer::low_level::Timer::new(p.TIM5); + tim5.set_tick_freq(Hertz(FEEDBACK_COUNTER_TICK_RATE)); + tim5.set_trigger_source(timer::low_level::TriggerSource::ITR12); // The USB SOF signal. + tim5.set_slave_mode(timer::low_level::SlaveMode::TRIGGER_MODE); + tim5.regs_gp16().dier().modify(|r| r.set_tie(true)); // Enable the trigger interrupt. + tim5.start(); + + TIMER.lock(|p| p.borrow_mut().replace(tim5)); + + // Unmask the TIM5 interrupt. + unsafe { + cortex_m::peripheral::NVIC::unmask(interrupt::TIM5); + } + + // Launch USB audio tasks. + unwrap!(spawner.spawn(usb_control_task(control_monitor))); + unwrap!(spawner.spawn(usb_streaming_task(stream, sender))); + unwrap!(spawner.spawn(usb_feedback_task(feedback))); + unwrap!(spawner.spawn(usb_task(usb_device))); + unwrap!(spawner.spawn(audio_receiver_task(receiver))); +} From cc4b5ae9cb4d79f9fa378b2a06073eb7ae96d369 Mon Sep 17 00:00:00 2001 From: elagil Date: Sat, 23 Nov 2024 22:52:43 +0100 Subject: [PATCH 0393/1217] feat: change SOF timer to input capture --- examples/stm32f4/src/bin/usb_uac_speaker.rs | 50 +++++++++++++-------- examples/stm32h5/src/bin/usb_uac_speaker.rs | 49 ++++++++++++-------- 2 files changed, 61 insertions(+), 38 deletions(-) diff --git a/examples/stm32f4/src/bin/usb_uac_speaker.rs b/examples/stm32f4/src/bin/usb_uac_speaker.rs index 77c693ace..8d83afd1a 100644 --- a/examples/stm32f4/src/bin/usb_uac_speaker.rs +++ b/examples/stm32f4/src/bin/usb_uac_speaker.rs @@ -222,25 +222,24 @@ fn TIM2() { critical_section::with(|cs| { // Read timer counter. - let ticks = TIMER.borrow(cs).borrow().as_ref().unwrap().regs_gp32().cnt().read(); + let timer = TIMER.borrow(cs).borrow().as_ref().unwrap().regs_gp32(); + + let status = timer.sr().read(); + + const CHANNEL_INDEX: usize = 0; + if status.ccif(CHANNEL_INDEX) { + let ticks = timer.ccr(CHANNEL_INDEX).read(); + + *FRAME_COUNT += 1; + if *FRAME_COUNT >= FEEDBACK_REFRESH_PERIOD.frame_count() { + *FRAME_COUNT = 0; + FEEDBACK_SIGNAL.signal(ticks.wrapping_sub(*LAST_TICKS)); + *LAST_TICKS = ticks; + } + }; // Clear trigger interrupt flag. - TIMER - .borrow(cs) - .borrow_mut() - .as_mut() - .unwrap() - .regs_gp32() - .sr() - .modify(|r| r.set_tif(false)); - - // Count up frames and emit a signal, when the refresh period is reached (here, every 8 ms). - *FRAME_COUNT += 1; - if *FRAME_COUNT >= FEEDBACK_REFRESH_PERIOD.frame_count() { - *FRAME_COUNT = 0; - FEEDBACK_SIGNAL.signal(ticks.wrapping_sub(*LAST_TICKS)); - *LAST_TICKS = ticks; - } + timer.sr().modify(|r| r.set_tif(false)); }); } @@ -355,8 +354,21 @@ async fn main(spawner: Spawner) { let mut tim2 = timer::low_level::Timer::new(p.TIM2); tim2.set_tick_freq(Hertz(FEEDBACK_COUNTER_TICK_RATE)); tim2.set_trigger_source(timer::low_level::TriggerSource::ITR1); // The USB SOF signal. - tim2.set_slave_mode(timer::low_level::SlaveMode::TRIGGER_MODE); - tim2.regs_gp16().dier().modify(|r| r.set_tie(true)); // Enable the trigger interrupt. + + const TIMER_CHANNEL: timer::Channel = timer::Channel::Ch1; + tim2.set_input_ti_selection(TIMER_CHANNEL, timer::low_level::InputTISelection::TRC); + tim2.set_input_capture_prescaler(TIMER_CHANNEL, 0); + tim2.set_input_capture_filter(TIMER_CHANNEL, timer::low_level::FilterValue::FCK_INT_N2); + + // Reset all interrupt flags. + tim2.regs_gp32().sr().write(|r| r.0 = 0); + + // Enable routing of SOF to the timer. + tim2.regs_gp32().or().write(|r| *r = 0b10 << 10); + + tim2.enable_channel(TIMER_CHANNEL, true); + tim2.enable_input_interrupt(TIMER_CHANNEL, true); + tim2.start(); TIMER.lock(|p| p.borrow_mut().replace(tim2)); diff --git a/examples/stm32h5/src/bin/usb_uac_speaker.rs b/examples/stm32h5/src/bin/usb_uac_speaker.rs index 6b992690f..4fd4ccbbd 100644 --- a/examples/stm32h5/src/bin/usb_uac_speaker.rs +++ b/examples/stm32h5/src/bin/usb_uac_speaker.rs @@ -94,6 +94,8 @@ async fn feedback_handler<'d, T: usb::Instance + 'd>( let value = value as u32; + debug!("Feedback value: {}", value); + packet.push(value as u8).unwrap(); packet.push((value >> 8) as u8).unwrap(); packet.push((value >> 16) as u8).unwrap(); @@ -215,25 +217,24 @@ fn TIM5() { critical_section::with(|cs| { // Read timer counter. - let ticks = TIMER.borrow(cs).borrow().as_ref().unwrap().regs_gp32().cnt().read(); + let timer = TIMER.borrow(cs).borrow().as_ref().unwrap().regs_gp32(); + + let status = timer.sr().read(); + + const CHANNEL_INDEX: usize = 0; + if status.ccif(CHANNEL_INDEX) { + let ticks = timer.ccr(CHANNEL_INDEX).read(); + + *FRAME_COUNT += 1; + if *FRAME_COUNT >= FEEDBACK_REFRESH_PERIOD.frame_count() { + *FRAME_COUNT = 0; + FEEDBACK_SIGNAL.signal(ticks.wrapping_sub(*LAST_TICKS)); + *LAST_TICKS = ticks; + } + }; // Clear trigger interrupt flag. - TIMER - .borrow(cs) - .borrow_mut() - .as_mut() - .unwrap() - .regs_gp32() - .sr() - .modify(|r| r.set_tif(false)); - - // Count up frames and emit a signal, when the refresh period is reached (here, every 8 ms). - *FRAME_COUNT += 1; - if *FRAME_COUNT >= FEEDBACK_REFRESH_PERIOD.frame_count() { - *FRAME_COUNT = 0; - FEEDBACK_SIGNAL.signal(ticks.wrapping_sub(*LAST_TICKS)); - *LAST_TICKS = ticks; - } + timer.sr().modify(|r| r.set_tif(false)); }); } @@ -347,8 +348,18 @@ async fn main(spawner: Spawner) { let mut tim5 = timer::low_level::Timer::new(p.TIM5); tim5.set_tick_freq(Hertz(FEEDBACK_COUNTER_TICK_RATE)); tim5.set_trigger_source(timer::low_level::TriggerSource::ITR12); // The USB SOF signal. - tim5.set_slave_mode(timer::low_level::SlaveMode::TRIGGER_MODE); - tim5.regs_gp16().dier().modify(|r| r.set_tie(true)); // Enable the trigger interrupt. + + const TIMER_CHANNEL: timer::Channel = timer::Channel::Ch1; + tim5.set_input_ti_selection(TIMER_CHANNEL, timer::low_level::InputTISelection::TRC); + tim5.set_input_capture_prescaler(TIMER_CHANNEL, 0); + tim5.set_input_capture_filter(TIMER_CHANNEL, timer::low_level::FilterValue::FCK_INT_N2); + + // Reset all interrupt flags. + tim5.regs_gp32().sr().write(|r| r.0 = 0); + + tim5.enable_channel(TIMER_CHANNEL, true); + tim5.enable_input_interrupt(TIMER_CHANNEL, true); + tim5.start(); TIMER.lock(|p| p.borrow_mut().replace(tim5)); From aaad8450e990f74c6b398aca9a6ec495720bf845 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sun, 24 Nov 2024 20:58:48 +0100 Subject: [PATCH 0394/1217] Use inline const for initializing arrays. (#3567) --- embassy-net-driver-channel/src/lib.rs | 6 ++---- embassy-nrf/src/gpiote.rs | 5 ++--- embassy-nrf/src/time_driver.rs | 3 +-- embassy-nrf/src/usb/mod.rs | 9 ++++----- embassy-nrf/src/wdt.rs | 3 +-- embassy-nxp/src/pint.rs | 16 +++++++++------- embassy-rp/src/dma.rs | 3 +-- embassy-rp/src/gpio.rs | 6 ++---- embassy-rp/src/pio/mod.rs | 4 +--- embassy-rp/src/time_driver.rs | 9 ++++----- embassy-rp/src/usb.rs | 7 +++---- embassy-stm32/src/eth/mod.rs | 6 ++---- embassy-stm32/src/exti.rs | 3 +-- embassy-stm32/src/ipcc.rs | 6 ++---- embassy-stm32/src/time_driver.rs | 5 +---- embassy-stm32/src/timer/mod.rs | 5 ++--- embassy-stm32/src/usb/usb.rs | 11 ++++------- embassy-time/src/driver_std.rs | 4 ++-- embassy-time/src/driver_wasm.rs | 4 ++-- 19 files changed, 46 insertions(+), 69 deletions(-) diff --git a/embassy-net-driver-channel/src/lib.rs b/embassy-net-driver-channel/src/lib.rs index 6390502a8..600efd9e5 100644 --- a/embassy-net-driver-channel/src/lib.rs +++ b/embassy-net-driver-channel/src/lib.rs @@ -26,13 +26,11 @@ pub struct State { } impl State { - const NEW_PACKET: PacketBuf = PacketBuf::new(); - /// Create a new channel state. pub const fn new() -> Self { Self { - rx: [Self::NEW_PACKET; N_RX], - tx: [Self::NEW_PACKET; N_TX], + rx: [const { PacketBuf::new() }; N_RX], + tx: [const { PacketBuf::new() }; N_TX], inner: MaybeUninit::uninit(), } } diff --git a/embassy-nrf/src/gpiote.rs b/embassy-nrf/src/gpiote.rs index 87bb405f4..8771f9f08 100644 --- a/embassy-nrf/src/gpiote.rs +++ b/embassy-nrf/src/gpiote.rs @@ -29,9 +29,8 @@ const PIN_COUNT: usize = 48; const PIN_COUNT: usize = 32; #[allow(clippy::declare_interior_mutable_const)] -const NEW_AW: AtomicWaker = AtomicWaker::new(); -static CHANNEL_WAKERS: [AtomicWaker; CHANNEL_COUNT] = [NEW_AW; CHANNEL_COUNT]; -static PORT_WAKERS: [AtomicWaker; PIN_COUNT] = [NEW_AW; PIN_COUNT]; +static CHANNEL_WAKERS: [AtomicWaker; CHANNEL_COUNT] = [const { AtomicWaker::new() }; CHANNEL_COUNT]; +static PORT_WAKERS: [AtomicWaker; PIN_COUNT] = [const { AtomicWaker::new() }; PIN_COUNT]; /// Polarity for listening to events for GPIOTE input channels. pub enum InputChannelPolarity { diff --git a/embassy-nrf/src/time_driver.rs b/embassy-nrf/src/time_driver.rs index 81aabb11c..9ba38ec1b 100644 --- a/embassy-nrf/src/time_driver.rs +++ b/embassy-nrf/src/time_driver.rs @@ -123,11 +123,10 @@ struct RtcDriver { alarms: Mutex<[AlarmState; ALARM_COUNT]>, } -const ALARM_STATE_NEW: AlarmState = AlarmState::new(); embassy_time_driver::time_driver_impl!(static DRIVER: RtcDriver = RtcDriver { period: AtomicU32::new(0), alarm_count: AtomicU8::new(0), - alarms: Mutex::const_new(CriticalSectionRawMutex::new(), [ALARM_STATE_NEW; ALARM_COUNT]), + alarms: Mutex::const_new(CriticalSectionRawMutex::new(), [const {AlarmState::new()}; ALARM_COUNT]), }); impl RtcDriver { diff --git a/embassy-nrf/src/usb/mod.rs b/embassy-nrf/src/usb/mod.rs index 52c9c532b..a9bf16708 100644 --- a/embassy-nrf/src/usb/mod.rs +++ b/embassy-nrf/src/usb/mod.rs @@ -22,11 +22,10 @@ use crate::pac::usbd::vals; use crate::util::slice_in_ram; use crate::{interrupt, pac, Peripheral}; -const NEW_AW: AtomicWaker = AtomicWaker::new(); -static BUS_WAKER: AtomicWaker = NEW_AW; -static EP0_WAKER: AtomicWaker = NEW_AW; -static EP_IN_WAKERS: [AtomicWaker; 8] = [NEW_AW; 8]; -static EP_OUT_WAKERS: [AtomicWaker; 8] = [NEW_AW; 8]; +static BUS_WAKER: AtomicWaker = AtomicWaker::new(); +static EP0_WAKER: AtomicWaker = AtomicWaker::new(); +static EP_IN_WAKERS: [AtomicWaker; 8] = [const { AtomicWaker::new() }; 8]; +static EP_OUT_WAKERS: [AtomicWaker; 8] = [const { AtomicWaker::new() }; 8]; static READY_ENDPOINTS: AtomicU32 = AtomicU32::new(0); /// Interrupt handler. diff --git a/embassy-nrf/src/wdt.rs b/embassy-nrf/src/wdt.rs index dfe6cbec3..f7812258c 100644 --- a/embassy-nrf/src/wdt.rs +++ b/embassy-nrf/src/wdt.rs @@ -112,8 +112,7 @@ impl Watchdog { let this = Self { _private: () }; - const DUMMY_HANDLE: WatchdogHandle = WatchdogHandle { index: 0 }; - let mut handles = [DUMMY_HANDLE; N]; + let mut handles = [const { WatchdogHandle { index: 0 } }; N]; for i in 0..N { handles[i] = WatchdogHandle { index: i as u8 }; handles[i].pet(); diff --git a/embassy-nxp/src/pint.rs b/embassy-nxp/src/pint.rs index 3313f91a6..809be4bff 100644 --- a/embassy-nxp/src/pint.rs +++ b/embassy-nxp/src/pint.rs @@ -52,14 +52,16 @@ impl PinInterrupt { } } -const NEW_PIN_INTERRUPT: PinInterrupt = PinInterrupt { - assigned: false, - waker: AtomicWaker::new(), - at_fault: false, -}; const INTERUPT_COUNT: usize = 8; -static PIN_INTERRUPTS: Mutex> = - Mutex::new(RefCell::new([NEW_PIN_INTERRUPT; INTERUPT_COUNT])); +static PIN_INTERRUPTS: Mutex> = Mutex::new(RefCell::new( + [const { + PinInterrupt { + assigned: false, + waker: AtomicWaker::new(), + at_fault: false, + } + }; INTERUPT_COUNT], +)); fn next_available_interrupt() -> Option { critical_section::with(|cs| { diff --git a/embassy-rp/src/dma.rs b/embassy-rp/src/dma.rs index 34abe3e2d..2edcfdf5b 100644 --- a/embassy-rp/src/dma.rs +++ b/embassy-rp/src/dma.rs @@ -212,8 +212,7 @@ impl<'a, C: Channel> Future for Transfer<'a, C> { pub(crate) const CHANNEL_COUNT: usize = 12; #[cfg(feature = "_rp235x")] pub(crate) const CHANNEL_COUNT: usize = 16; -const NEW_AW: AtomicWaker = AtomicWaker::new(); -static CHANNEL_WAKERS: [AtomicWaker; CHANNEL_COUNT] = [NEW_AW; CHANNEL_COUNT]; +static CHANNEL_WAKERS: [AtomicWaker; CHANNEL_COUNT] = [const { AtomicWaker::new() }; CHANNEL_COUNT]; trait SealedChannel {} trait SealedWord {} diff --git a/embassy-rp/src/gpio.rs b/embassy-rp/src/gpio.rs index cb54375e4..203192827 100644 --- a/embassy-rp/src/gpio.rs +++ b/embassy-rp/src/gpio.rs @@ -13,18 +13,16 @@ use crate::pac::common::{Reg, RW}; use crate::pac::SIO; use crate::{interrupt, pac, peripherals, Peripheral, RegExt}; -const NEW_AW: AtomicWaker = AtomicWaker::new(); - #[cfg(any(feature = "rp2040", feature = "rp235xa"))] pub(crate) const BANK0_PIN_COUNT: usize = 30; #[cfg(feature = "rp235xb")] pub(crate) const BANK0_PIN_COUNT: usize = 48; -static BANK0_WAKERS: [AtomicWaker; BANK0_PIN_COUNT] = [NEW_AW; BANK0_PIN_COUNT]; +static BANK0_WAKERS: [AtomicWaker; BANK0_PIN_COUNT] = [const { AtomicWaker::new() }; BANK0_PIN_COUNT]; #[cfg(feature = "qspi-as-gpio")] const QSPI_PIN_COUNT: usize = 6; #[cfg(feature = "qspi-as-gpio")] -static QSPI_WAKERS: [AtomicWaker; QSPI_PIN_COUNT] = [NEW_AW; QSPI_PIN_COUNT]; +static QSPI_WAKERS: [AtomicWaker; QSPI_PIN_COUNT] = [const { AtomicWaker::new() }; QSPI_PIN_COUNT]; /// Represents a digital input or output level. #[derive(Debug, Eq, PartialEq, Clone, Copy)] diff --git a/embassy-rp/src/pio/mod.rs b/embassy-rp/src/pio/mod.rs index 98f4f8943..e3c25020f 100644 --- a/embassy-rp/src/pio/mod.rs +++ b/embassy-rp/src/pio/mod.rs @@ -1270,9 +1270,7 @@ trait SealedInstance { #[inline] fn wakers() -> &'static Wakers { - const NEW_AW: AtomicWaker = AtomicWaker::new(); - static WAKERS: Wakers = Wakers([NEW_AW; 12]); - + static WAKERS: Wakers = Wakers([const { AtomicWaker::new() }; 12]); &WAKERS } diff --git a/embassy-rp/src/time_driver.rs b/embassy-rp/src/time_driver.rs index e5b407a29..40fc71bb1 100644 --- a/embassy-rp/src/time_driver.rs +++ b/embassy-rp/src/time_driver.rs @@ -21,10 +21,6 @@ struct AlarmState { unsafe impl Send for AlarmState {} const ALARM_COUNT: usize = 4; -const DUMMY_ALARM: AlarmState = AlarmState { - timestamp: Cell::new(0), - callback: Cell::new(None), -}; struct TimerDriver { alarms: Mutex, @@ -32,7 +28,10 @@ struct TimerDriver { } embassy_time_driver::time_driver_impl!(static DRIVER: TimerDriver = TimerDriver{ - alarms: Mutex::const_new(CriticalSectionRawMutex::new(), [DUMMY_ALARM; ALARM_COUNT]), + alarms: Mutex::const_new(CriticalSectionRawMutex::new(), [const{AlarmState { + timestamp: Cell::new(0), + callback: Cell::new(None), + }}; ALARM_COUNT]), next_alarm: AtomicU8::new(0), }); diff --git a/embassy-rp/src/usb.rs b/embassy-rp/src/usb.rs index 20ef881f9..26cb90d89 100644 --- a/embassy-rp/src/usb.rs +++ b/embassy-rp/src/usb.rs @@ -43,10 +43,9 @@ const EP_COUNT: usize = 16; const EP_MEMORY_SIZE: usize = 4096; const EP_MEMORY: *mut u8 = pac::USB_DPRAM.as_ptr() as *mut u8; -const NEW_AW: AtomicWaker = AtomicWaker::new(); -static BUS_WAKER: AtomicWaker = NEW_AW; -static EP_IN_WAKERS: [AtomicWaker; EP_COUNT] = [NEW_AW; EP_COUNT]; -static EP_OUT_WAKERS: [AtomicWaker; EP_COUNT] = [NEW_AW; EP_COUNT]; +static BUS_WAKER: AtomicWaker = AtomicWaker::new(); +static EP_IN_WAKERS: [AtomicWaker; EP_COUNT] = [const { AtomicWaker::new() }; EP_COUNT]; +static EP_OUT_WAKERS: [AtomicWaker; EP_COUNT] = [const { AtomicWaker::new() }; EP_COUNT]; struct EndpointBuffer { addr: u16, diff --git a/embassy-stm32/src/eth/mod.rs b/embassy-stm32/src/eth/mod.rs index 1b875b71a..773452bf2 100644 --- a/embassy-stm32/src/eth/mod.rs +++ b/embassy-stm32/src/eth/mod.rs @@ -42,11 +42,9 @@ pub struct PacketQueue { impl PacketQueue { /// Create a new packet queue. pub const fn new() -> Self { - const NEW_TDES: TDes = TDes::new(); - const NEW_RDES: RDes = RDes::new(); Self { - tx_desc: [NEW_TDES; TX], - rx_desc: [NEW_RDES; RX], + tx_desc: [const { TDes::new() }; TX], + rx_desc: [const { RDes::new() }; RX], tx_buf: [Packet([0; TX_BUFFER_SIZE]); TX], rx_buf: [Packet([0; RX_BUFFER_SIZE]); RX], } diff --git a/embassy-stm32/src/exti.rs b/embassy-stm32/src/exti.rs index 87512c92d..5cff74264 100644 --- a/embassy-stm32/src/exti.rs +++ b/embassy-stm32/src/exti.rs @@ -14,8 +14,7 @@ use crate::pac::EXTI; use crate::{interrupt, pac, peripherals, Peripheral}; const EXTI_COUNT: usize = 16; -const NEW_AW: AtomicWaker = AtomicWaker::new(); -static EXTI_WAKERS: [AtomicWaker; EXTI_COUNT] = [NEW_AW; EXTI_COUNT]; +static EXTI_WAKERS: [AtomicWaker; EXTI_COUNT] = [const { AtomicWaker::new() }; EXTI_COUNT]; #[cfg(exti_w)] fn cpu_regs() -> pac::exti::Cpu { diff --git a/embassy-stm32/src/ipcc.rs b/embassy-stm32/src/ipcc.rs index 6c8347311..20cd20dca 100644 --- a/embassy-stm32/src/ipcc.rs +++ b/embassy-stm32/src/ipcc.rs @@ -229,11 +229,9 @@ struct State { impl State { const fn new() -> Self { - const WAKER: AtomicWaker = AtomicWaker::new(); - Self { - rx_wakers: [WAKER; 6], - tx_wakers: [WAKER; 6], + rx_wakers: [const { AtomicWaker::new() }; 6], + tx_wakers: [const { AtomicWaker::new() }; 6], } } diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs index f8041bf1e..74e4d0575 100644 --- a/embassy-stm32/src/time_driver.rs +++ b/embassy-stm32/src/time_driver.rs @@ -261,13 +261,10 @@ pub(crate) struct RtcDriver { rtc: Mutex>>, } -#[allow(clippy::declare_interior_mutable_const)] -const ALARM_STATE_NEW: AlarmState = AlarmState::new(); - embassy_time_driver::time_driver_impl!(static DRIVER: RtcDriver = RtcDriver { period: AtomicU32::new(0), alarm_count: AtomicU8::new(0), - alarms: Mutex::const_new(CriticalSectionRawMutex::new(), [ALARM_STATE_NEW; ALARM_COUNT]), + alarms: Mutex::const_new(CriticalSectionRawMutex::new(), [const{AlarmState::new()}; ALARM_COUNT]), #[cfg(feature = "low-power")] rtc: Mutex::const_new(CriticalSectionRawMutex::new(), Cell::new(None)), }); diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs index aa9dd91d9..97740c2ed 100644 --- a/embassy-stm32/src/timer/mod.rs +++ b/embassy-stm32/src/timer/mod.rs @@ -59,10 +59,9 @@ struct State { impl State { const fn new() -> Self { - const NEW_AW: AtomicWaker = AtomicWaker::new(); Self { - up_waker: NEW_AW, - cc_waker: [NEW_AW; 4], + up_waker: AtomicWaker::new(), + cc_waker: [const { AtomicWaker::new() }; 4], } } } diff --git a/embassy-stm32/src/usb/usb.rs b/embassy-stm32/src/usb/usb.rs index 0ab2306c8..94af00b6e 100644 --- a/embassy-stm32/src/usb/usb.rs +++ b/embassy-stm32/src/usb/usb.rs @@ -119,15 +119,12 @@ const USBRAM_ALIGN: usize = 2; #[cfg(any(usbram_32_2048, usbram_32_1024))] const USBRAM_ALIGN: usize = 4; -const NEW_AW: AtomicWaker = AtomicWaker::new(); -static BUS_WAKER: AtomicWaker = NEW_AW; +static BUS_WAKER: AtomicWaker = AtomicWaker::new(); static EP0_SETUP: AtomicBool = AtomicBool::new(false); -const NEW_CTR_TRIGGERED: AtomicBool = AtomicBool::new(false); -static CTR_TRIGGERED: [AtomicBool; EP_COUNT] = [NEW_CTR_TRIGGERED; EP_COUNT]; - -static EP_IN_WAKERS: [AtomicWaker; EP_COUNT] = [NEW_AW; EP_COUNT]; -static EP_OUT_WAKERS: [AtomicWaker; EP_COUNT] = [NEW_AW; EP_COUNT]; +static CTR_TRIGGERED: [AtomicBool; EP_COUNT] = [const { AtomicBool::new(false) }; EP_COUNT]; +static EP_IN_WAKERS: [AtomicWaker; EP_COUNT] = [const { AtomicWaker::new() }; EP_COUNT]; +static EP_OUT_WAKERS: [AtomicWaker; EP_COUNT] = [const { AtomicWaker::new() }; EP_COUNT]; static IRQ_RESET: AtomicBool = AtomicBool::new(false); static IRQ_SUSPEND: AtomicBool = AtomicBool::new(false); static IRQ_RESUME: AtomicBool = AtomicBool::new(false); diff --git a/embassy-time/src/driver_std.rs b/embassy-time/src/driver_std.rs index d182f8331..cbef7aae1 100644 --- a/embassy-time/src/driver_std.rs +++ b/embassy-time/src/driver_std.rs @@ -43,7 +43,6 @@ struct TimeDriver { signaler: UninitCell, } -const ALARM_NEW: AlarmState = AlarmState::new(); embassy_time_driver::time_driver_impl!(static DRIVER: TimeDriver = TimeDriver { alarm_count: AtomicU8::new(0), @@ -56,7 +55,8 @@ embassy_time_driver::time_driver_impl!(static DRIVER: TimeDriver = TimeDriver { impl TimeDriver { fn init(&self) { self.once.call_once(|| unsafe { - self.alarms.write(CsMutex::new(RefCell::new([ALARM_NEW; ALARM_COUNT]))); + self.alarms + .write(CsMutex::new(RefCell::new([const { AlarmState::new() }; ALARM_COUNT]))); self.zero_instant.write(StdInstant::now()); self.signaler.write(Signaler::new()); diff --git a/embassy-time/src/driver_wasm.rs b/embassy-time/src/driver_wasm.rs index ad884f060..d65629e49 100644 --- a/embassy-time/src/driver_wasm.rs +++ b/embassy-time/src/driver_wasm.rs @@ -40,7 +40,6 @@ struct TimeDriver { zero_instant: UninitCell, } -const ALARM_NEW: AlarmState = AlarmState::new(); embassy_time_driver::time_driver_impl!(static DRIVER: TimeDriver = TimeDriver { alarm_count: AtomicU8::new(0), once: Once::new(), @@ -51,7 +50,8 @@ embassy_time_driver::time_driver_impl!(static DRIVER: TimeDriver = TimeDriver { impl TimeDriver { fn init(&self) { self.once.call_once(|| unsafe { - self.alarms.write(Mutex::new([ALARM_NEW; ALARM_COUNT])); + self.alarms + .write(Mutex::new([const { AlarmState::new() }; ALARM_COUNT])); self.zero_instant.write(StdInstant::now()); }); } From 20e2da677f65515b558c6bc4afef8bf7068ad3a7 Mon Sep 17 00:00:00 2001 From: elagil Date: Sun, 24 Nov 2024 22:50:51 +0100 Subject: [PATCH 0395/1217] chore: use latest metapac --- embassy-stm32/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index ebcfb73c9..5b0a88404 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -72,7 +72,7 @@ rand_core = "0.6.3" sdio-host = "0.5.0" critical-section = "1.1" #stm32-metapac = { version = "15" } -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-55b491ee982e52f80a21276a0ccbde4907982b5d" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-04833817666290047257c65c6547d28e1bd10dc9" } vcell = "0.1.3" nb = "1.0.0" @@ -101,7 +101,7 @@ proc-macro2 = "1.0.36" quote = "1.0.15" #stm32-metapac = { version = "15", default-features = false, features = ["metadata"]} -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-55b491ee982e52f80a21276a0ccbde4907982b5d", default-features = false, features = ["metadata"] } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-04833817666290047257c65c6547d28e1bd10dc9", default-features = false, features = ["metadata"] } [features] default = ["rt"] From 8eaa3c8fd3385d50bbf844c6fff0790884ac56af Mon Sep 17 00:00:00 2001 From: Bing Wen Date: Tue, 26 Nov 2024 12:27:43 +0800 Subject: [PATCH 0396/1217] Add new feature to enable overclocking --- embassy-stm32/Cargo.toml | 4 ++++ embassy-stm32/src/rcc/c0.rs | 13 +++++++++---- embassy-stm32/src/rcc/f013.rs | 18 ++++++++++++------ embassy-stm32/src/rcc/f247.rs | 14 ++++++++++---- embassy-stm32/src/rcc/g0.rs | 19 ++++++++++++++----- embassy-stm32/src/rcc/g4.rs | 18 ++++++++++++++---- 6 files changed, 63 insertions(+), 23 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index ebcfb73c9..363bc9797 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -138,6 +138,10 @@ trustzone-secure = [] ## There are no plans to make this stable. unstable-pac = [] +## Enable this feature to disable the overclocking check. +## DO NOT ENABLE THIS FEATURE UNLESS YOU KNOW WHAT YOU'RE DOING. +unchecked-overclocking = [] + #! ## Time ## Enables additional driver features that depend on embassy-time diff --git a/embassy-stm32/src/rcc/c0.rs b/embassy-stm32/src/rcc/c0.rs index 6712aedc4..c6ac46491 100644 --- a/embassy-stm32/src/rcc/c0.rs +++ b/embassy-stm32/src/rcc/c0.rs @@ -109,9 +109,12 @@ pub(crate) unsafe fn init(config: Config) { None } Some(hse) => { - match hse.mode { - HseMode::Bypass => assert!(max::HSE_BYP.contains(&hse.freq)), - HseMode::Oscillator => assert!(max::HSE_OSC.contains(&hse.freq)), + #[cfg(not(feature = "unchecked-overclocking"))] + { + match hse.mode { + HseMode::Bypass => assert!(max::HSE_BYP.contains(&hse.freq)), + HseMode::Oscillator => assert!(max::HSE_OSC.contains(&hse.freq)), + } } RCC.cr().modify(|w| w.set_hsebyp(hse.mode != HseMode::Oscillator)); @@ -126,14 +129,16 @@ pub(crate) unsafe fn init(config: Config) { Sysclk::HSE => unwrap!(hse), _ => unreachable!(), }; - + #[cfg(not(feature = "unchecked-overclocking"))] assert!(max::SYSCLK.contains(&sys)); // Calculate the AHB frequency (HCLK), among other things so we can calculate the correct flash read latency. let hclk = sys / config.ahb_pre; + #[cfg(not(feature = "unchecked-overclocking"))] assert!(max::HCLK.contains(&hclk)); let (pclk1, pclk1_tim) = super::util::calc_pclk(hclk, config.apb1_pre); + #[cfg(not(feature = "unchecked-overclocking"))] assert!(max::PCLK.contains(&pclk1)); let latency = match hclk.0 { diff --git a/embassy-stm32/src/rcc/f013.rs b/embassy-stm32/src/rcc/f013.rs index 60577b213..20a0f3940 100644 --- a/embassy-stm32/src/rcc/f013.rs +++ b/embassy-stm32/src/rcc/f013.rs @@ -157,9 +157,12 @@ pub(crate) unsafe fn init(config: Config) { None } Some(hse) => { - match hse.mode { - HseMode::Bypass => assert!(max::HSE_BYP.contains(&hse.freq)), - HseMode::Oscillator => assert!(max::HSE_OSC.contains(&hse.freq)), + #[cfg(not(feature = "unchecked-overclocking"))] + { + match hse.mode { + HseMode::Bypass => assert!(max::HSE_BYP.contains(&hse.freq)), + HseMode::Oscillator => assert!(max::HSE_OSC.contains(&hse.freq)), + } } RCC.cr().modify(|w| w.set_hsebyp(hse.mode != HseMode::Oscillator)); @@ -192,7 +195,9 @@ pub(crate) unsafe fn init(config: Config) { PllSource::HSI48 => (Pllsrc::HSI48_DIV_PREDIV, unwrap!(hsi48)), }; let in_freq = src_freq / pll.prediv; + #[cfg(not(feature = "unchecked-overclocking"))] assert!(max::PLL_IN.contains(&in_freq)); + #[cfg(not(feature = "unchecked-overclocking"))] let out_freq = in_freq * pll.mul; assert!(max::PLL_OUT.contains(&out_freq)); @@ -238,15 +243,16 @@ pub(crate) unsafe fn init(config: Config) { let (pclk2, pclk2_tim) = super::util::calc_pclk(hclk, config.apb2_pre); #[cfg(stm32f0)] let (pclk2, pclk2_tim) = (pclk1, pclk1_tim); - + #[cfg(not(feature = "unchecked-overclocking"))] assert!(max::HCLK.contains(&hclk)); + #[cfg(not(feature = "unchecked-overclocking"))] assert!(max::PCLK1.contains(&pclk1)); - #[cfg(not(stm32f0))] + #[cfg(all(not(feature = "unchecked-overclocking"), not(stm32f0)))] assert!(max::PCLK2.contains(&pclk2)); #[cfg(stm32f1)] let adc = pclk2 / config.adc_pre; - #[cfg(stm32f1)] + #[cfg(all(not(feature = "unchecked-overclocking"), stm32f1))] assert!(max::ADC.contains(&adc)); // Set latency based on HCLK frquency diff --git a/embassy-stm32/src/rcc/f247.rs b/embassy-stm32/src/rcc/f247.rs index 58056301a..83d4428cc 100644 --- a/embassy-stm32/src/rcc/f247.rs +++ b/embassy-stm32/src/rcc/f247.rs @@ -169,9 +169,12 @@ pub(crate) unsafe fn init(config: Config) { None } Some(hse) => { - match hse.mode { - HseMode::Bypass => assert!(max::HSE_BYP.contains(&hse.freq)), - HseMode::Oscillator => assert!(max::HSE_OSC.contains(&hse.freq)), + #[cfg(not(feature = "unchecked-overclocking"))] + { + match hse.mode { + HseMode::Bypass => assert!(max::HSE_BYP.contains(&hse.freq)), + HseMode::Oscillator => assert!(max::HSE_OSC.contains(&hse.freq)), + } } RCC.cr().modify(|w| w.set_hsebyp(hse.mode != HseMode::Oscillator)); @@ -204,10 +207,13 @@ pub(crate) unsafe fn init(config: Config) { let hclk = sys / config.ahb_pre; let (pclk1, pclk1_tim) = super::util::calc_pclk(hclk, config.apb1_pre); let (pclk2, pclk2_tim) = super::util::calc_pclk(hclk, config.apb2_pre); - + #[cfg(not(feature = "unchecked-overclocking"))] assert!(max::SYSCLK.contains(&sys)); + #[cfg(not(feature = "unchecked-overclocking"))] assert!(max::HCLK.contains(&hclk)); + #[cfg(not(feature = "unchecked-overclocking"))] assert!(max::PCLK1.contains(&pclk1)); + #[cfg(not(feature = "unchecked-overclocking"))] assert!(max::PCLK2.contains(&pclk2)); let rtc = config.ls.init(); diff --git a/embassy-stm32/src/rcc/g0.rs b/embassy-stm32/src/rcc/g0.rs index c53c83b0e..9e1351eae 100644 --- a/embassy-stm32/src/rcc/g0.rs +++ b/embassy-stm32/src/rcc/g0.rs @@ -139,9 +139,12 @@ pub(crate) unsafe fn init(config: Config) { None } Some(hse) => { - match hse.mode { - HseMode::Bypass => assert!(max::HSE_BYP.contains(&hse.freq)), - HseMode::Oscillator => assert!(max::HSE_OSC.contains(&hse.freq)), + #[cfg(not(feature = "unchecked-overclocking"))] + { + match hse.mode { + HseMode::Bypass => assert!(max::HSE_BYP.contains(&hse.freq)), + HseMode::Oscillator => assert!(max::HSE_OSC.contains(&hse.freq)), + } } RCC.cr().modify(|w| w.set_hsebyp(hse.mode != HseMode::Oscillator)); @@ -169,9 +172,10 @@ pub(crate) unsafe fn init(config: Config) { while RCC.cr().read().pllrdy() {} let in_freq = src_freq / pll_config.prediv; + #[cfg(not(feature = "unchecked-overclocking"))] assert!(max::PLL_IN.contains(&in_freq)); let internal_freq = in_freq * pll_config.mul; - + #[cfg(not(feature = "unchecked-overclocking"))] assert!(max::PLL_VCO.contains(&internal_freq)); RCC.pllcfgr().write(|w| { @@ -186,6 +190,7 @@ pub(crate) unsafe fn init(config: Config) { w.set_pllpen(true); }); let freq = internal_freq / div_p; + #[cfg(not(feature = "unchecked-overclocking"))] assert!(max::PLL_P.contains(&freq)); freq }); @@ -196,6 +201,7 @@ pub(crate) unsafe fn init(config: Config) { w.set_pllqen(true); }); let freq = internal_freq / div_q; + #[cfg(not(feature = "unchecked-overclocking"))] assert!(max::PLL_Q.contains(&freq)); freq }); @@ -206,6 +212,7 @@ pub(crate) unsafe fn init(config: Config) { w.set_pllren(true); }); let freq = internal_freq / div_r; + #[cfg(not(feature = "unchecked-overclocking"))] assert!(max::PLL_R.contains(&freq)); freq }); @@ -228,14 +235,16 @@ pub(crate) unsafe fn init(config: Config) { Sysclk::PLL1_R => unwrap!(pll.pll_r), _ => unreachable!(), }; - + #[cfg(not(feature = "unchecked-overclocking"))] assert!(max::SYSCLK.contains(&sys)); // Calculate the AHB frequency (HCLK), among other things so we can calculate the correct flash read latency. let hclk = sys / config.ahb_pre; + #[cfg(not(feature = "unchecked-overclocking"))] assert!(max::HCLK.contains(&hclk)); let (pclk1, pclk1_tim) = super::util::calc_pclk(hclk, config.apb1_pre); + #[cfg(not(feature = "unchecked-overclocking"))] assert!(max::PCLK.contains(&pclk1)); let latency = match (config.voltage_range, hclk.0) { diff --git a/embassy-stm32/src/rcc/g4.rs b/embassy-stm32/src/rcc/g4.rs index 16561f908..09b2a8de8 100644 --- a/embassy-stm32/src/rcc/g4.rs +++ b/embassy-stm32/src/rcc/g4.rs @@ -140,9 +140,12 @@ pub(crate) unsafe fn init(config: Config) { None } Some(hse) => { - match hse.mode { - HseMode::Bypass => assert!(max::HSE_BYP.contains(&hse.freq)), - HseMode::Oscillator => assert!(max::HSE_OSC.contains(&hse.freq)), + #[cfg(not(feature = "unchecked-overclocking"))] + { + match hse.mode { + HseMode::Bypass => assert!(max::HSE_BYP.contains(&hse.freq)), + HseMode::Oscillator => assert!(max::HSE_OSC.contains(&hse.freq)), + } } RCC.cr().modify(|w| w.set_hsebyp(hse.mode != HseMode::Oscillator)); @@ -169,9 +172,11 @@ pub(crate) unsafe fn init(config: Config) { while RCC.cr().read().pllrdy() {} let in_freq = src_freq / pll_config.prediv; + #[cfg(not(feature = "unchecked-overclocking"))] assert!(max::PLL_IN.contains(&in_freq)); let internal_freq = in_freq * pll_config.mul; + #[cfg(not(feature = "unchecked-overclocking"))] assert!(max::PLL_VCO.contains(&internal_freq)); RCC.pllcfgr().write(|w| { @@ -186,6 +191,7 @@ pub(crate) unsafe fn init(config: Config) { w.set_pllpen(true); }); let freq = internal_freq / div_p; + #[cfg(not(feature = "unchecked-overclocking"))] assert!(max::PLL_P.contains(&freq)); freq }); @@ -196,6 +202,7 @@ pub(crate) unsafe fn init(config: Config) { w.set_pllqen(true); }); let freq = internal_freq / div_q; + #[cfg(not(feature = "unchecked-overclocking"))] assert!(max::PLL_Q.contains(&freq)); freq }); @@ -206,6 +213,7 @@ pub(crate) unsafe fn init(config: Config) { w.set_pllren(true); }); let freq = internal_freq / div_r; + #[cfg(not(feature = "unchecked-overclocking"))] assert!(max::PLL_R.contains(&freq)); freq }); @@ -229,15 +237,17 @@ pub(crate) unsafe fn init(config: Config) { _ => unreachable!(), }; + #[cfg(not(feature = "unchecked-overclocking"))] assert!(max::SYSCLK.contains(&sys)); // Calculate the AHB frequency (HCLK), among other things so we can calculate the correct flash read latency. let hclk = sys / config.ahb_pre; + #[cfg(not(feature = "unchecked-overclocking"))] assert!(max::HCLK.contains(&hclk)); let (pclk1, pclk1_tim) = super::util::calc_pclk(hclk, config.apb1_pre); let (pclk2, pclk2_tim) = super::util::calc_pclk(hclk, config.apb2_pre); - assert!(max::PCLK.contains(&pclk2)); + #[cfg(not(feature = "unchecked-overclocking"))] assert!(max::PCLK.contains(&pclk2)); // Configure Core Boost mode ([RM0440] p234 – inverted because setting r1mode to 0 enables boost mode!) From 52ab015facf9f5039f89cd772d0f178ec70d878b Mon Sep 17 00:00:00 2001 From: Bing Wen Date: Wed, 27 Nov 2024 12:23:13 +0800 Subject: [PATCH 0397/1217] Add new --- embassy-stm32/src/fmt.rs | 19 +++++++++++++++++++ embassy-stm32/src/rcc/c0.rs | 18 ++++++------------ embassy-stm32/src/rcc/f013.rs | 29 +++++++++++------------------ embassy-stm32/src/rcc/f247.rs | 22 ++++++++-------------- embassy-stm32/src/rcc/g0.rs | 33 +++++++++++---------------------- embassy-stm32/src/rcc/g4.rs | 33 +++++++++++---------------------- 6 files changed, 66 insertions(+), 88 deletions(-) diff --git a/embassy-stm32/src/fmt.rs b/embassy-stm32/src/fmt.rs index 8ca61bc39..660407569 100644 --- a/embassy-stm32/src/fmt.rs +++ b/embassy-stm32/src/fmt.rs @@ -6,6 +6,25 @@ use core::fmt::{Debug, Display, LowerHex}; #[cfg(all(feature = "defmt", feature = "log"))] compile_error!("You may not enable both `defmt` and `log` features."); +#[collapse_debuginfo(yes)] +macro_rules! rcc_assert { + ($($x:tt)*) => { + { + if cfg!(feature = "unchecked-overclocking") { + #[cfg(not(feature = "defmt"))] + ::core::assert!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::assert!($($x)*); + } else { + #[cfg(feature = "log")] + ::log::warn!("`rcc_assert!` skipped: `unchecked-overclocking` feature is enabled."); + #[cfg(feature = "defmt")] + ::defmt::warn!("`rcc_assert!` skipped: `unchecked-overclocking` feature is enabled."); + } + } + }; +} + #[collapse_debuginfo(yes)] macro_rules! assert { ($($x:tt)*) => { diff --git a/embassy-stm32/src/rcc/c0.rs b/embassy-stm32/src/rcc/c0.rs index c6ac46491..c989a3891 100644 --- a/embassy-stm32/src/rcc/c0.rs +++ b/embassy-stm32/src/rcc/c0.rs @@ -109,12 +109,9 @@ pub(crate) unsafe fn init(config: Config) { None } Some(hse) => { - #[cfg(not(feature = "unchecked-overclocking"))] - { - match hse.mode { - HseMode::Bypass => assert!(max::HSE_BYP.contains(&hse.freq)), - HseMode::Oscillator => assert!(max::HSE_OSC.contains(&hse.freq)), - } + match hse.mode { + HseMode::Bypass => rcc_assert!(max::HSE_BYP.contains(&hse.freq)), + HseMode::Oscillator => rcc_assert!(max::HSE_OSC.contains(&hse.freq)), } RCC.cr().modify(|w| w.set_hsebyp(hse.mode != HseMode::Oscillator)); @@ -129,17 +126,14 @@ pub(crate) unsafe fn init(config: Config) { Sysclk::HSE => unwrap!(hse), _ => unreachable!(), }; - #[cfg(not(feature = "unchecked-overclocking"))] - assert!(max::SYSCLK.contains(&sys)); + rcc_assert!(max::SYSCLK.contains(&sys)); // Calculate the AHB frequency (HCLK), among other things so we can calculate the correct flash read latency. let hclk = sys / config.ahb_pre; - #[cfg(not(feature = "unchecked-overclocking"))] - assert!(max::HCLK.contains(&hclk)); + rcc_assert!(max::HCLK.contains(&hclk)); let (pclk1, pclk1_tim) = super::util::calc_pclk(hclk, config.apb1_pre); - #[cfg(not(feature = "unchecked-overclocking"))] - assert!(max::PCLK.contains(&pclk1)); + rcc_assert(max::PCLK.contains(&pclk1)); let latency = match hclk.0 { ..=24_000_000 => Latency::WS0, diff --git a/embassy-stm32/src/rcc/f013.rs b/embassy-stm32/src/rcc/f013.rs index 20a0f3940..cfe44ce54 100644 --- a/embassy-stm32/src/rcc/f013.rs +++ b/embassy-stm32/src/rcc/f013.rs @@ -157,12 +157,9 @@ pub(crate) unsafe fn init(config: Config) { None } Some(hse) => { - #[cfg(not(feature = "unchecked-overclocking"))] - { - match hse.mode { - HseMode::Bypass => assert!(max::HSE_BYP.contains(&hse.freq)), - HseMode::Oscillator => assert!(max::HSE_OSC.contains(&hse.freq)), - } + match hse.mode { + HseMode::Bypass => rcc_assert!(max::HSE_BYP.contains(&hse.freq)), + HseMode::Oscillator => rcc_assert!(max::HSE_OSC.contains(&hse.freq)), } RCC.cr().modify(|w| w.set_hsebyp(hse.mode != HseMode::Oscillator)); @@ -195,11 +192,9 @@ pub(crate) unsafe fn init(config: Config) { PllSource::HSI48 => (Pllsrc::HSI48_DIV_PREDIV, unwrap!(hsi48)), }; let in_freq = src_freq / pll.prediv; - #[cfg(not(feature = "unchecked-overclocking"))] - assert!(max::PLL_IN.contains(&in_freq)); - #[cfg(not(feature = "unchecked-overclocking"))] + rcc_assert!(max::PLL_IN.contains(&in_freq)); let out_freq = in_freq * pll.mul; - assert!(max::PLL_OUT.contains(&out_freq)); + rcc_assert!(max::PLL_OUT.contains(&out_freq)); #[cfg(not(stm32f1))] RCC.cfgr2().modify(|w| w.set_prediv(pll.prediv)); @@ -243,17 +238,15 @@ pub(crate) unsafe fn init(config: Config) { let (pclk2, pclk2_tim) = super::util::calc_pclk(hclk, config.apb2_pre); #[cfg(stm32f0)] let (pclk2, pclk2_tim) = (pclk1, pclk1_tim); - #[cfg(not(feature = "unchecked-overclocking"))] - assert!(max::HCLK.contains(&hclk)); - #[cfg(not(feature = "unchecked-overclocking"))] - assert!(max::PCLK1.contains(&pclk1)); - #[cfg(all(not(feature = "unchecked-overclocking"), not(stm32f0)))] - assert!(max::PCLK2.contains(&pclk2)); + rcc_assert!(max::HCLK.contains(&hclk)); + rcc_assert!(max::PCLK1.contains(&pclk1)); + #[cfg(not(stm32f0))] + rcc_assert!(max::PCLK2.contains(&pclk2)); #[cfg(stm32f1)] let adc = pclk2 / config.adc_pre; - #[cfg(all(not(feature = "unchecked-overclocking"), stm32f1))] - assert!(max::ADC.contains(&adc)); + #[cfg(stm32f1)] + rcc_assert!(max::ADC.contains(&adc)); // Set latency based on HCLK frquency #[cfg(stm32f0)] diff --git a/embassy-stm32/src/rcc/f247.rs b/embassy-stm32/src/rcc/f247.rs index 83d4428cc..3e7aff02d 100644 --- a/embassy-stm32/src/rcc/f247.rs +++ b/embassy-stm32/src/rcc/f247.rs @@ -169,12 +169,9 @@ pub(crate) unsafe fn init(config: Config) { None } Some(hse) => { - #[cfg(not(feature = "unchecked-overclocking"))] - { - match hse.mode { - HseMode::Bypass => assert!(max::HSE_BYP.contains(&hse.freq)), - HseMode::Oscillator => assert!(max::HSE_OSC.contains(&hse.freq)), - } + match hse.mode { + HseMode::Bypass => rcc_assert!(max::HSE_BYP.contains(&hse.freq)), + HseMode::Oscillator => rcc_assert!(max::HSE_OSC.contains(&hse.freq)), } RCC.cr().modify(|w| w.set_hsebyp(hse.mode != HseMode::Oscillator)); @@ -207,14 +204,11 @@ pub(crate) unsafe fn init(config: Config) { let hclk = sys / config.ahb_pre; let (pclk1, pclk1_tim) = super::util::calc_pclk(hclk, config.apb1_pre); let (pclk2, pclk2_tim) = super::util::calc_pclk(hclk, config.apb2_pre); - #[cfg(not(feature = "unchecked-overclocking"))] - assert!(max::SYSCLK.contains(&sys)); - #[cfg(not(feature = "unchecked-overclocking"))] - assert!(max::HCLK.contains(&hclk)); - #[cfg(not(feature = "unchecked-overclocking"))] - assert!(max::PCLK1.contains(&pclk1)); - #[cfg(not(feature = "unchecked-overclocking"))] - assert!(max::PCLK2.contains(&pclk2)); + + rcc_assert!(max::SYSCLK.contains(&sys)); + rcc_assert!(max::HCLK.contains(&hclk)); + rcc_assert!(max::PCLK1.contains(&pclk1)); + rcc_assert!(max::PCLK2.contains(&pclk2)); let rtc = config.ls.init(); diff --git a/embassy-stm32/src/rcc/g0.rs b/embassy-stm32/src/rcc/g0.rs index 9e1351eae..71e524a20 100644 --- a/embassy-stm32/src/rcc/g0.rs +++ b/embassy-stm32/src/rcc/g0.rs @@ -139,12 +139,9 @@ pub(crate) unsafe fn init(config: Config) { None } Some(hse) => { - #[cfg(not(feature = "unchecked-overclocking"))] - { - match hse.mode { - HseMode::Bypass => assert!(max::HSE_BYP.contains(&hse.freq)), - HseMode::Oscillator => assert!(max::HSE_OSC.contains(&hse.freq)), - } + match hse.mode { + HseMode::Bypass => rcc_assert!(max::HSE_BYP.contains(&hse.freq)), + HseMode::Oscillator => rcc_assert!(max::HSE_OSC.contains(&hse.freq)), } RCC.cr().modify(|w| w.set_hsebyp(hse.mode != HseMode::Oscillator)); @@ -172,11 +169,9 @@ pub(crate) unsafe fn init(config: Config) { while RCC.cr().read().pllrdy() {} let in_freq = src_freq / pll_config.prediv; - #[cfg(not(feature = "unchecked-overclocking"))] - assert!(max::PLL_IN.contains(&in_freq)); + rcc_assert!(max::PLL_IN.contains(&in_freq)); let internal_freq = in_freq * pll_config.mul; - #[cfg(not(feature = "unchecked-overclocking"))] - assert!(max::PLL_VCO.contains(&internal_freq)); + rcc_assert!(max::PLL_VCO.contains(&internal_freq)); RCC.pllcfgr().write(|w| { w.set_plln(pll_config.mul); @@ -190,8 +185,7 @@ pub(crate) unsafe fn init(config: Config) { w.set_pllpen(true); }); let freq = internal_freq / div_p; - #[cfg(not(feature = "unchecked-overclocking"))] - assert!(max::PLL_P.contains(&freq)); + rcc_assert!(max::PLL_P.contains(&freq)); freq }); @@ -201,8 +195,7 @@ pub(crate) unsafe fn init(config: Config) { w.set_pllqen(true); }); let freq = internal_freq / div_q; - #[cfg(not(feature = "unchecked-overclocking"))] - assert!(max::PLL_Q.contains(&freq)); + rcc_assert!(max::PLL_Q.contains(&freq)); freq }); @@ -212,8 +205,7 @@ pub(crate) unsafe fn init(config: Config) { w.set_pllren(true); }); let freq = internal_freq / div_r; - #[cfg(not(feature = "unchecked-overclocking"))] - assert!(max::PLL_R.contains(&freq)); + rcc_assert!(max::PLL_R.contains(&freq)); freq }); @@ -235,17 +227,14 @@ pub(crate) unsafe fn init(config: Config) { Sysclk::PLL1_R => unwrap!(pll.pll_r), _ => unreachable!(), }; - #[cfg(not(feature = "unchecked-overclocking"))] - assert!(max::SYSCLK.contains(&sys)); + rcc_assert!(max::SYSCLK.contains(&sys)); // Calculate the AHB frequency (HCLK), among other things so we can calculate the correct flash read latency. let hclk = sys / config.ahb_pre; - #[cfg(not(feature = "unchecked-overclocking"))] - assert!(max::HCLK.contains(&hclk)); + rcc_assert!(max::HCLK.contains(&hclk)); let (pclk1, pclk1_tim) = super::util::calc_pclk(hclk, config.apb1_pre); - #[cfg(not(feature = "unchecked-overclocking"))] - assert!(max::PCLK.contains(&pclk1)); + rcc_assert!(max::PCLK.contains(&pclk1)); let latency = match (config.voltage_range, hclk.0) { (VoltageRange::RANGE1, ..=24_000_000) => Latency::WS0, diff --git a/embassy-stm32/src/rcc/g4.rs b/embassy-stm32/src/rcc/g4.rs index 09b2a8de8..e09b2915e 100644 --- a/embassy-stm32/src/rcc/g4.rs +++ b/embassy-stm32/src/rcc/g4.rs @@ -140,12 +140,9 @@ pub(crate) unsafe fn init(config: Config) { None } Some(hse) => { - #[cfg(not(feature = "unchecked-overclocking"))] - { - match hse.mode { - HseMode::Bypass => assert!(max::HSE_BYP.contains(&hse.freq)), - HseMode::Oscillator => assert!(max::HSE_OSC.contains(&hse.freq)), - } + match hse.mode { + HseMode::Bypass => rcc_assert!(max::HSE_BYP.contains(&hse.freq)), + HseMode::Oscillator => rcc_assert!(max::HSE_OSC.contains(&hse.freq)), } RCC.cr().modify(|w| w.set_hsebyp(hse.mode != HseMode::Oscillator)); @@ -172,12 +169,10 @@ pub(crate) unsafe fn init(config: Config) { while RCC.cr().read().pllrdy() {} let in_freq = src_freq / pll_config.prediv; - #[cfg(not(feature = "unchecked-overclocking"))] - assert!(max::PLL_IN.contains(&in_freq)); + rcc_assert!(max::PLL_IN.contains(&in_freq)); let internal_freq = in_freq * pll_config.mul; - #[cfg(not(feature = "unchecked-overclocking"))] - assert!(max::PLL_VCO.contains(&internal_freq)); + rcc_assert!(max::PLL_VCO.contains(&internal_freq)); RCC.pllcfgr().write(|w| { w.set_plln(pll_config.mul); @@ -191,8 +186,7 @@ pub(crate) unsafe fn init(config: Config) { w.set_pllpen(true); }); let freq = internal_freq / div_p; - #[cfg(not(feature = "unchecked-overclocking"))] - assert!(max::PLL_P.contains(&freq)); + rcc_assert!(max::PLL_P.contains(&freq)); freq }); @@ -202,8 +196,7 @@ pub(crate) unsafe fn init(config: Config) { w.set_pllqen(true); }); let freq = internal_freq / div_q; - #[cfg(not(feature = "unchecked-overclocking"))] - assert!(max::PLL_Q.contains(&freq)); + rcc_assert!(max::PLL_Q.contains(&freq)); freq }); @@ -213,8 +206,7 @@ pub(crate) unsafe fn init(config: Config) { w.set_pllren(true); }); let freq = internal_freq / div_r; - #[cfg(not(feature = "unchecked-overclocking"))] - assert!(max::PLL_R.contains(&freq)); + rcc_assert!(max::PLL_R.contains(&freq)); freq }); @@ -237,18 +229,15 @@ pub(crate) unsafe fn init(config: Config) { _ => unreachable!(), }; - #[cfg(not(feature = "unchecked-overclocking"))] - assert!(max::SYSCLK.contains(&sys)); + rcc_assert!(max::SYSCLK.contains(&sys)); // Calculate the AHB frequency (HCLK), among other things so we can calculate the correct flash read latency. let hclk = sys / config.ahb_pre; - #[cfg(not(feature = "unchecked-overclocking"))] - assert!(max::HCLK.contains(&hclk)); + rcc_assert!(max::HCLK.contains(&hclk)); let (pclk1, pclk1_tim) = super::util::calc_pclk(hclk, config.apb1_pre); let (pclk2, pclk2_tim) = super::util::calc_pclk(hclk, config.apb2_pre); - #[cfg(not(feature = "unchecked-overclocking"))] - assert!(max::PCLK.contains(&pclk2)); + rcc_assert!(max::PCLK.contains(&pclk2)); // Configure Core Boost mode ([RM0440] p234 – inverted because setting r1mode to 0 enables boost mode!) if config.boost { From d0340ad2971232b505be13a1a5e353674d838c35 Mon Sep 17 00:00:00 2001 From: Bing Wen Date: Wed, 27 Nov 2024 12:33:32 +0800 Subject: [PATCH 0398/1217] Fix & Revert --- embassy-stm32/src/rcc/c0.rs | 3 ++- embassy-stm32/src/rcc/f013.rs | 1 + embassy-stm32/src/rcc/g0.rs | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/embassy-stm32/src/rcc/c0.rs b/embassy-stm32/src/rcc/c0.rs index c989a3891..977b2e7a2 100644 --- a/embassy-stm32/src/rcc/c0.rs +++ b/embassy-stm32/src/rcc/c0.rs @@ -126,6 +126,7 @@ pub(crate) unsafe fn init(config: Config) { Sysclk::HSE => unwrap!(hse), _ => unreachable!(), }; + rcc_assert!(max::SYSCLK.contains(&sys)); // Calculate the AHB frequency (HCLK), among other things so we can calculate the correct flash read latency. @@ -133,7 +134,7 @@ pub(crate) unsafe fn init(config: Config) { rcc_assert!(max::HCLK.contains(&hclk)); let (pclk1, pclk1_tim) = super::util::calc_pclk(hclk, config.apb1_pre); - rcc_assert(max::PCLK.contains(&pclk1)); + rcc_assert!(max::PCLK.contains(&pclk1)); let latency = match hclk.0 { ..=24_000_000 => Latency::WS0, diff --git a/embassy-stm32/src/rcc/f013.rs b/embassy-stm32/src/rcc/f013.rs index cfe44ce54..c915f1b16 100644 --- a/embassy-stm32/src/rcc/f013.rs +++ b/embassy-stm32/src/rcc/f013.rs @@ -238,6 +238,7 @@ pub(crate) unsafe fn init(config: Config) { let (pclk2, pclk2_tim) = super::util::calc_pclk(hclk, config.apb2_pre); #[cfg(stm32f0)] let (pclk2, pclk2_tim) = (pclk1, pclk1_tim); + rcc_assert!(max::HCLK.contains(&hclk)); rcc_assert!(max::PCLK1.contains(&pclk1)); #[cfg(not(stm32f0))] diff --git a/embassy-stm32/src/rcc/g0.rs b/embassy-stm32/src/rcc/g0.rs index 71e524a20..5da33720c 100644 --- a/embassy-stm32/src/rcc/g0.rs +++ b/embassy-stm32/src/rcc/g0.rs @@ -227,6 +227,7 @@ pub(crate) unsafe fn init(config: Config) { Sysclk::PLL1_R => unwrap!(pll.pll_r), _ => unreachable!(), }; + rcc_assert!(max::SYSCLK.contains(&sys)); // Calculate the AHB frequency (HCLK), among other things so we can calculate the correct flash read latency. From b225d73dc5ea6632c35d5ba063467e8b32abd14c Mon Sep 17 00:00:00 2001 From: Bing Wen Date: Wed, 27 Nov 2024 14:00:45 +0800 Subject: [PATCH 0399/1217] Change compile condition --- embassy-stm32/src/fmt.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/fmt.rs b/embassy-stm32/src/fmt.rs index 660407569..b6ae24ee8 100644 --- a/embassy-stm32/src/fmt.rs +++ b/embassy-stm32/src/fmt.rs @@ -10,12 +10,15 @@ compile_error!("You may not enable both `defmt` and `log` features."); macro_rules! rcc_assert { ($($x:tt)*) => { { - if cfg!(feature = "unchecked-overclocking") { + #[cfg(not(feature = "unchecked-overclocking"))] + { #[cfg(not(feature = "defmt"))] ::core::assert!($($x)*); #[cfg(feature = "defmt")] ::defmt::assert!($($x)*); - } else { + } + #[cfg(feature = "unchecked-overclocking")] + { #[cfg(feature = "log")] ::log::warn!("`rcc_assert!` skipped: `unchecked-overclocking` feature is enabled."); #[cfg(feature = "defmt")] From 09c9f64b8e0bf12cccc0474fb689c313d2b58ff3 Mon Sep 17 00:00:00 2001 From: Bing Wen Date: Wed, 27 Nov 2024 17:44:03 +0800 Subject: [PATCH 0400/1217] Add missing clock check --- embassy-stm32/src/rcc/g4.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/embassy-stm32/src/rcc/g4.rs b/embassy-stm32/src/rcc/g4.rs index e09b2915e..6b34aa306 100644 --- a/embassy-stm32/src/rcc/g4.rs +++ b/embassy-stm32/src/rcc/g4.rs @@ -237,6 +237,7 @@ pub(crate) unsafe fn init(config: Config) { let (pclk1, pclk1_tim) = super::util::calc_pclk(hclk, config.apb1_pre); let (pclk2, pclk2_tim) = super::util::calc_pclk(hclk, config.apb2_pre); + rcc_assert!(max::PCLK.contains(&pclk1)); rcc_assert!(max::PCLK.contains(&pclk2)); // Configure Core Boost mode ([RM0440] p234 – inverted because setting r1mode to 0 enables boost mode!) From 7a9c4889960aa2fdc48af99d3765a6277da30e8e Mon Sep 17 00:00:00 2001 From: William <174336620+williams-one@users.noreply.github.com> Date: Wed, 27 Nov 2024 16:52:26 +0100 Subject: [PATCH 0401/1217] stm32: Update STM32 data source --- embassy-stm32/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index f6ffa29fa..09b7f805a 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -72,7 +72,7 @@ rand_core = "0.6.3" sdio-host = "0.5.0" critical-section = "1.1" #stm32-metapac = { version = "15" } -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-04833817666290047257c65c6547d28e1bd10dc9" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-ab0ec4c19f81854189bab8215544ccd1256e1045" } vcell = "0.1.3" nb = "1.0.0" @@ -101,7 +101,7 @@ proc-macro2 = "1.0.36" quote = "1.0.15" #stm32-metapac = { version = "15", default-features = false, features = ["metadata"]} -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-04833817666290047257c65c6547d28e1bd10dc9", default-features = false, features = ["metadata"] } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-ab0ec4c19f81854189bab8215544ccd1256e1045", default-features = false, features = ["metadata"] } [features] default = ["rt"] From b035ff114502b0e63f578441250b6ff94c5efda1 Mon Sep 17 00:00:00 2001 From: William <174336620+williams-one@users.noreply.github.com> Date: Wed, 27 Nov 2024 17:29:08 +0100 Subject: [PATCH 0402/1217] stm32u5: Add flash bank selection when erasing a sector --- embassy-stm32/src/flash/u5.rs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/embassy-stm32/src/flash/u5.rs b/embassy-stm32/src/flash/u5.rs index 0601017ce..e5af4f1f7 100644 --- a/embassy-stm32/src/flash/u5.rs +++ b/embassy-stm32/src/flash/u5.rs @@ -1,7 +1,7 @@ use core::ptr::write_volatile; use core::sync::atomic::{fence, Ordering}; -use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; +use super::{FlashBank, FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; use crate::flash::Error; use crate::pac; @@ -70,12 +70,22 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E #[cfg(feature = "trustzone-secure")] pac::FLASH.seccr().modify(|w| { w.set_per(pac::flash::vals::SeccrPer::B_0X1); - w.set_pnb(sector.index_in_bank) + w.set_pnb(sector.index_in_bank); + // TODO: add check for bank swap + w.set_bker(match sector.bank { + FlashBank::Bank1 => pac::flash::vals::SeccrBker::B_0X0, + FlashBank::Bank2 => pac::flash::vals::SeccrBker::B_0X1, + }); }); #[cfg(not(feature = "trustzone-secure"))] pac::FLASH.nscr().modify(|w| { w.set_per(pac::flash::vals::NscrPer::B_0X1); - w.set_pnb(sector.index_in_bank) + w.set_pnb(sector.index_in_bank); + // TODO: add check for bank swap + w.set_bker(match sector.bank { + FlashBank::Bank1 => pac::flash::vals::NscrBker::B_0X0, + FlashBank::Bank2 => pac::flash::vals::NscrBker::B_0X1, + }); }); #[cfg(feature = "trustzone-secure")] From 8b8b7fa05ef0524a337a050584835026afa3015a Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 28 Nov 2024 01:30:27 +0100 Subject: [PATCH 0403/1217] net: update to smoltcp v0.12.0 --- embassy-net/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-net/Cargo.toml b/embassy-net/Cargo.toml index 2c33ecc14..23748973a 100644 --- a/embassy-net/Cargo.toml +++ b/embassy-net/Cargo.toml @@ -68,7 +68,7 @@ multicast = ["smoltcp/multicast"] defmt = { version = "0.3.8", optional = true } log = { version = "0.4.14", optional = true } -smoltcp = { git="https://github.com/smoltcp-rs/smoltcp", rev="fe0b4d102253465850cd1cf39cd33d4721a4a8d5", default-features = false, features = [ +smoltcp = { version = "0.12.0", default-features = false, features = [ "socket", "async", ] } From c12ebb3a80fec9a98793d89c43c2193b4607ee91 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 28 Nov 2024 01:33:23 +0100 Subject: [PATCH 0404/1217] net: release v0.5.0 --- embassy-net/CHANGELOG.md | 28 ++++++++++++++++++++++++++++ embassy-net/Cargo.toml | 2 +- examples/nrf52840/Cargo.toml | 2 +- examples/nrf5340/Cargo.toml | 2 +- examples/nrf9160/Cargo.toml | 2 +- examples/rp/Cargo.toml | 2 +- examples/rp23/Cargo.toml | 2 +- examples/std/Cargo.toml | 2 +- examples/stm32f4/Cargo.toml | 2 +- examples/stm32f7/Cargo.toml | 2 +- examples/stm32h5/Cargo.toml | 2 +- examples/stm32h7/Cargo.toml | 2 +- examples/stm32h755cm4/Cargo.toml | 2 +- examples/stm32h755cm7/Cargo.toml | 2 +- examples/stm32h7b0/Cargo.toml | 2 +- examples/stm32h7rs/Cargo.toml | 2 +- examples/stm32l4/Cargo.toml | 2 +- examples/stm32l5/Cargo.toml | 2 +- examples/stm32wb/Cargo.toml | 2 +- examples/stm32wba/Cargo.toml | 2 +- tests/nrf/Cargo.toml | 2 +- tests/perf-client/Cargo.toml | 2 +- tests/rp/Cargo.toml | 2 +- tests/stm32/Cargo.toml | 2 +- 24 files changed, 51 insertions(+), 23 deletions(-) diff --git a/embassy-net/CHANGELOG.md b/embassy-net/CHANGELOG.md index 56e245b92..c4ccff277 100644 --- a/embassy-net/CHANGELOG.md +++ b/embassy-net/CHANGELOG.md @@ -7,6 +7,34 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +No unreleased changes yet... Quick, go send a PR! + +## 0.5 - 2024-11-28 + +- Refactor the API structure, simplifying lifetimes and generics. + - Stack is now a thin handle that implements `Copy+Clone`. Instead of passing `&Stack` around, you can now pass `Stack`. + - `Stack` and `DnsSocket` no longer need a generic parameter for the device driver. + - The `run()` method has been moved to a new `Runner` struct. + - Sockets are covariant wrt their lifetime. + - An implication of the refactor is now you need only one `StaticCell` instead of two if you need to share the network stack between tasks. +- Use standard `core::net` IP types instead of custom ones from smoltcp. +- Update to `smoltcp` v0.12. +- Add `mdns` Cargo feature. +- dns: properly handle `AddrType::Either` in `get_host_by_name()` +- dns: truncate instead of panic if the DHCP server gives us more DNS servers than the configured maximum. +- stack: add `wait_link_up()`, `wait_link_down()`, `wait_config_down()`. +- tcp: Add `recv_queue()`, `send_queue()`. +- tcp: Add `wait_read_ready()`, `wait_write_ready()`. +- tcp: allow setting timeout through `embedded-nal` client. +- tcp: fix `flush()` hanging forever if socket is closed with pending data. +- tcp: fix `flush()` not waiting for ACK of FIN. +- tcp: implement `ReadReady`, `WriteReady` traits from `embedded-io`. +- udp, raw: Add `wait_send_ready()`, `wait_recv_ready()`, `flush()`. +- udp: add `recv_from_with()`, `send_to_with()` methods, allowing for IO with one less copy. +- udp: send/recv now takes/returns full `UdpMetadata` instead of just the remote `IpEndpoint`. +- raw: add raw sockets. + + ## 0.4 - 2024-01-11 - Update to `embassy-time` v0.3. diff --git a/embassy-net/Cargo.toml b/embassy-net/Cargo.toml index 23748973a..1d79a2a07 100644 --- a/embassy-net/Cargo.toml +++ b/embassy-net/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "embassy-net" -version = "0.4.0" +version = "0.5.0" edition = "2021" license = "MIT OR Apache-2.0" description = "Async TCP/IP network stack for embedded systems" diff --git a/examples/nrf52840/Cargo.toml b/examples/nrf52840/Cargo.toml index 9623c04b5..701911a30 100644 --- a/examples/nrf52840/Cargo.toml +++ b/examples/nrf52840/Cargo.toml @@ -10,7 +10,7 @@ embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["de embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } -embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } +embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embedded-io = { version = "0.6.0", features = ["defmt-03"] } embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } diff --git a/examples/nrf5340/Cargo.toml b/examples/nrf5340/Cargo.toml index 8c8f74d15..13442405d 100644 --- a/examples/nrf5340/Cargo.toml +++ b/examples/nrf5340/Cargo.toml @@ -10,7 +10,7 @@ embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["de embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf5340-app-s", "time-driver-rtc1", "gpiote", "unstable-pac"] } -embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } +embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embedded-io-async = { version = "0.6.1" } diff --git a/examples/nrf9160/Cargo.toml b/examples/nrf9160/Cargo.toml index 47eba5552..3b404c730 100644 --- a/examples/nrf9160/Cargo.toml +++ b/examples/nrf9160/Cargo.toml @@ -9,7 +9,7 @@ embassy-executor = { version = "0.6.3", path = "../../embassy-executor", feature embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf9160-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } embassy-net-nrf91 = { version = "0.1.0", path = "../../embassy-net-nrf91", features = ["defmt"] } -embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "proto-ipv4", "medium-ip"] } +embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "proto-ipv4", "medium-ip"] } defmt = "0.3" defmt-rtt = "0.4" diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index 1448306a1..2dce1676a 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml @@ -12,7 +12,7 @@ embassy-executor = { version = "0.6.3", path = "../../embassy-executor", feature embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-rp = { version = "0.2.0", path = "../../embassy-rp", features = ["defmt", "unstable-pac", "time-driver", "critical-section-impl", "rp2040"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } -embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "raw", "dhcpv4", "medium-ethernet", "dns", "proto-ipv4", "proto-ipv6", "multicast"] } +embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "raw", "dhcpv4", "medium-ethernet", "dns", "proto-ipv4", "proto-ipv6", "multicast"] } embassy-net-wiznet = { version = "0.1.0", path = "../../embassy-net-wiznet", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-usb-logger = { version = "0.2.0", path = "../../embassy-usb-logger" } diff --git a/examples/rp23/Cargo.toml b/examples/rp23/Cargo.toml index 6738339c0..2fcad247d 100644 --- a/examples/rp23/Cargo.toml +++ b/examples/rp23/Cargo.toml @@ -12,7 +12,7 @@ embassy-executor = { version = "0.6.3", path = "../../embassy-executor", feature embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-rp = { version = "0.2.0", path = "../../embassy-rp", features = ["defmt", "unstable-pac", "time-driver", "critical-section-impl", "rp235xa", "binary-info"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } -embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "raw", "dhcpv4", "medium-ethernet", "dns"] } +embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "raw", "dhcpv4", "medium-ethernet", "dns"] } embassy-net-wiznet = { version = "0.1.0", path = "../../embassy-net-wiznet", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-usb-logger = { version = "0.2.0", path = "../../embassy-usb-logger" } diff --git a/examples/std/Cargo.toml b/examples/std/Cargo.toml index f6b209d06..77948515a 100644 --- a/examples/std/Cargo.toml +++ b/examples/std/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["log"] } embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-std", "executor-thread", "log", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["log", "std", ] } -embassy-net = { version = "0.4.0", path = "../../embassy-net", features=[ "std", "log", "medium-ethernet", "medium-ip", "tcp", "udp", "dns", "dhcpv4", "proto-ipv6"] } +embassy-net = { version = "0.5.0", path = "../../embassy-net", features=[ "std", "log", "medium-ethernet", "medium-ip", "tcp", "udp", "dns", "dhcpv4", "proto-ipv6"] } embassy-net-tuntap = { version = "0.1.0", path = "../../embassy-net-tuntap" } embassy-net-ppp = { version = "0.1.0", path = "../../embassy-net-ppp", features = ["log"]} embedded-io-async = { version = "0.6.1" } diff --git a/examples/stm32f4/Cargo.toml b/examples/stm32f4/Cargo.toml index 435b0b43c..2a0b7c507 100644 --- a/examples/stm32f4/Cargo.toml +++ b/examples/stm32f4/Cargo.toml @@ -11,7 +11,7 @@ embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["de embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt" ] } -embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", ] } +embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", ] } embassy-net-wiznet = { version = "0.1.0", path = "../../embassy-net-wiznet", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32f7/Cargo.toml b/examples/stm32f7/Cargo.toml index 822d8152d..480694dca 100644 --- a/examples/stm32f7/Cargo.toml +++ b/examples/stm32f7/Cargo.toml @@ -10,7 +10,7 @@ embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [" embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } -embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } +embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } embedded-io-async = { version = "0.6.1" } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32h5/Cargo.toml b/examples/stm32h5/Cargo.toml index 91ca43845..1a5791c83 100644 --- a/examples/stm32h5/Cargo.toml +++ b/examples/stm32h5/Cargo.toml @@ -10,7 +10,7 @@ embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [" embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } -embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6"] } +embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32h7/Cargo.toml b/examples/stm32h7/Cargo.toml index 949cefe1e..b90a6a455 100644 --- a/examples/stm32h7/Cargo.toml +++ b/examples/stm32h7/Cargo.toml @@ -11,7 +11,7 @@ embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["de embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } -embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } +embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32h755cm4/Cargo.toml b/examples/stm32h755cm4/Cargo.toml index 18a17dbaf..455dee98b 100644 --- a/examples/stm32h755cm4/Cargo.toml +++ b/examples/stm32h755cm4/Cargo.toml @@ -11,7 +11,7 @@ embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["de embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } -embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } +embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32h755cm7/Cargo.toml b/examples/stm32h755cm7/Cargo.toml index 02f1fcbaf..4d6167ab2 100644 --- a/examples/stm32h755cm7/Cargo.toml +++ b/examples/stm32h755cm7/Cargo.toml @@ -11,7 +11,7 @@ embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["de embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } -embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } +embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32h7b0/Cargo.toml b/examples/stm32h7b0/Cargo.toml index 78f65a4cc..41f0fb5ca 100644 --- a/examples/stm32h7b0/Cargo.toml +++ b/examples/stm32h7b0/Cargo.toml @@ -10,7 +10,7 @@ embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["de embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } -embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } +embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32h7rs/Cargo.toml b/examples/stm32h7rs/Cargo.toml index 60013cb88..24065dbce 100644 --- a/examples/stm32h7rs/Cargo.toml +++ b/examples/stm32h7rs/Cargo.toml @@ -10,7 +10,7 @@ embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [" embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } -embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } +embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32l4/Cargo.toml b/examples/stm32l4/Cargo.toml index 9673b097f..b172878c1 100644 --- a/examples/stm32l4/Cargo.toml +++ b/examples/stm32l4/Cargo.toml @@ -13,7 +13,7 @@ embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["de embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embassy-net-adin1110 = { version = "0.2.0", path = "../../embassy-net-adin1110" } -embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "udp", "tcp", "dhcpv4", "medium-ethernet"] } +embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "udp", "tcp", "dhcpv4", "medium-ethernet"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } embedded-io = { version = "0.6.0", features = ["defmt-03"] } diff --git a/examples/stm32l5/Cargo.toml b/examples/stm32l5/Cargo.toml index 014a3c4c8..e09311f9d 100644 --- a/examples/stm32l5/Cargo.toml +++ b/examples/stm32l5/Cargo.toml @@ -11,7 +11,7 @@ embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["de embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } -embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } +embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } usbd-hid = "0.8.1" diff --git a/examples/stm32wb/Cargo.toml b/examples/stm32wb/Cargo.toml index 3da74e535..400c7b20c 100644 --- a/examples/stm32wb/Cargo.toml +++ b/examples/stm32wb/Cargo.toml @@ -11,7 +11,7 @@ embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", fea embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } -embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", ], optional=true } +embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", ], optional=true } defmt = "0.3" defmt-rtt = "0.4" diff --git a/examples/stm32wba/Cargo.toml b/examples/stm32wba/Cargo.toml index 2c033ff7f..9e4251ce1 100644 --- a/examples/stm32wba/Cargo.toml +++ b/examples/stm32wba/Cargo.toml @@ -9,7 +9,7 @@ embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } -embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", ], optional=true } +embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", ], optional=true } defmt = "0.3" defmt-rtt = "0.4" diff --git a/tests/nrf/Cargo.toml b/tests/nrf/Cargo.toml index 00dfda6d6..f91ab8b06 100644 --- a/tests/nrf/Cargo.toml +++ b/tests/nrf/Cargo.toml @@ -13,7 +13,7 @@ embassy-executor = { version = "0.6.3", path = "../../embassy-executor", feature embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "time-driver-rtc1", "gpiote", "unstable-pac"] } embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } -embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", ] } +embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", ] } embassy-net-esp-hosted = { version = "0.1.0", path = "../../embassy-net-esp-hosted", features = ["defmt"] } embassy-net-enc28j60 = { version = "0.1.0", path = "../../embassy-net-enc28j60", features = ["defmt"] } embedded-hal-async = { version = "1.0" } diff --git a/tests/perf-client/Cargo.toml b/tests/perf-client/Cargo.toml index eb2a33a30..3bbc1b613 100644 --- a/tests/perf-client/Cargo.toml +++ b/tests/perf-client/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" edition = "2021" [dependencies] -embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4"] } +embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", ] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } defmt = "0.3.0" diff --git a/tests/rp/Cargo.toml b/tests/rp/Cargo.toml index 91854e659..7fb791578 100644 --- a/tests/rp/Cargo.toml +++ b/tests/rp/Cargo.toml @@ -12,7 +12,7 @@ embassy-executor = { version = "0.6.3", path = "../../embassy-executor", feature embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", ] } embassy-rp = { version = "0.2.0", path = "../../embassy-rp", features = [ "defmt", "unstable-pac", "time-driver", "critical-section-impl", "intrinsics", "rom-v2-intrinsics", "run-from-ram", "rp2040"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } -embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "dhcpv4", "medium-ethernet"] } +embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "dhcpv4", "medium-ethernet"] } embassy-net-wiznet = { version = "0.1.0", path = "../../embassy-net-wiznet", features = ["defmt"] } embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal/"} cyw43 = { path = "../../cyw43", features = ["defmt", "firmware-logs"] } diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml index 288c438bd..599f7c702 100644 --- a/tests/stm32/Cargo.toml +++ b/tests/stm32/Cargo.toml @@ -65,7 +65,7 @@ embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["de embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "memory-x", "time-driver-any"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", optional = true, features = ["defmt", "stm32wb55rg", "ble"] } -embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "dhcpv4", "medium-ethernet"] } +embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "dhcpv4", "medium-ethernet"] } perf-client = { path = "../perf-client" } defmt = "0.3.0" From f3e674a79cc6530d8185d3ff02e6bed1d7533c11 Mon Sep 17 00:00:00 2001 From: eZio Pan Date: Thu, 28 Nov 2024 15:48:27 +0800 Subject: [PATCH 0405/1217] stm32: remove redundant time-driver macro --- embassy-stm32/src/time_driver.rs | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs index 74e4d0575..88b6c48bb 100644 --- a/embassy-stm32/src/time_driver.rs +++ b/embassy-stm32/src/time_driver.rs @@ -67,14 +67,6 @@ type T = peripherals::TIM23; type T = peripherals::TIM24; foreach_interrupt! { - (TIM1, timer, $block:ident, CC, $irq:ident) => { - #[cfg(time_driver_tim1)] - #[cfg(feature = "rt")] - #[interrupt] - fn $irq() { - DRIVER.on_interrupt() - } - }; (TIM1, timer, $block:ident, CC, $irq:ident) => { #[cfg(time_driver_tim1)] #[cfg(feature = "rt")] @@ -123,14 +115,6 @@ foreach_interrupt! { DRIVER.on_interrupt() } }; - (TIM8, timer, $block:ident, CC, $irq:ident) => { - #[cfg(time_driver_tim8)] - #[cfg(feature = "rt")] - #[interrupt] - fn $irq() { - DRIVER.on_interrupt() - } - }; (TIM9, timer, $block:ident, CC, $irq:ident) => { #[cfg(time_driver_tim9)] #[cfg(feature = "rt")] @@ -163,14 +147,6 @@ foreach_interrupt! { DRIVER.on_interrupt() } }; - (TIM20, timer, $block:ident, CC, $irq:ident) => { - #[cfg(time_driver_tim20)] - #[cfg(feature = "rt")] - #[interrupt] - fn $irq() { - DRIVER.on_interrupt() - } - }; (TIM21, timer, $block:ident, CC, $irq:ident) => { #[cfg(time_driver_tim21)] #[cfg(feature = "rt")] From 152d8ee0d9526a9b5d41350385ee2b2102c0c43f Mon Sep 17 00:00:00 2001 From: elagil Date: Thu, 28 Nov 2024 17:36:14 +0100 Subject: [PATCH 0406/1217] fix: make `write_immediate()` for ring buffers right-aligned --- embassy-stm32/src/dma/ringbuffer/mod.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/embassy-stm32/src/dma/ringbuffer/mod.rs b/embassy-stm32/src/dma/ringbuffer/mod.rs index 25bdc7522..4dc1b51a9 100644 --- a/embassy-stm32/src/dma/ringbuffer/mod.rs +++ b/embassy-stm32/src/dma/ringbuffer/mod.rs @@ -252,9 +252,13 @@ impl<'a, W: Word> WritableDmaRingBuffer<'a, W> { } /// Write elements directly to the buffer. + /// + /// Data is aligned towards the end of the buffer. pub fn write_immediate(&mut self, buf: &[W]) -> Result<(usize, usize), Error> { + let start = self.cap() - buf.len(); + for (i, data) in buf.iter().enumerate() { - self.write_buf(i, *data) + self.write_buf(start + i, *data) } let written = buf.len().min(self.cap()); Ok((written, self.cap() - written)) From 5d2b38c979b045d69fee1e2b1bb7f209043ceece Mon Sep 17 00:00:00 2001 From: elagil Date: Thu, 28 Nov 2024 17:45:00 +0100 Subject: [PATCH 0407/1217] doc: improve comment --- embassy-stm32/src/dma/ringbuffer/mod.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/embassy-stm32/src/dma/ringbuffer/mod.rs b/embassy-stm32/src/dma/ringbuffer/mod.rs index 4dc1b51a9..44ea497fe 100644 --- a/embassy-stm32/src/dma/ringbuffer/mod.rs +++ b/embassy-stm32/src/dma/ringbuffer/mod.rs @@ -253,10 +253,17 @@ impl<'a, W: Word> WritableDmaRingBuffer<'a, W> { /// Write elements directly to the buffer. /// + /// Subsequent writes will overwrite the content of the buffer, so it is not useful to call this more than once. /// Data is aligned towards the end of the buffer. + /// + /// In case of success, returns the written length, and the empty space in front of the written block. + /// Fails if the data to write exceeds the buffer capacity. pub fn write_immediate(&mut self, buf: &[W]) -> Result<(usize, usize), Error> { - let start = self.cap() - buf.len(); + if buf.len() > self.cap() { + return Err(Error::Overrun); + } + let start = self.cap() - buf.len(); for (i, data) in buf.iter().enumerate() { self.write_buf(start + i, *data) } From d147161879ecf96b8e7ba7cd6f189c4283a5f61d Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Fri, 29 Nov 2024 09:59:24 +0100 Subject: [PATCH 0408/1217] Rename example crate to remove warning --- examples/stm32h723/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/stm32h723/Cargo.toml b/examples/stm32h723/Cargo.toml index f68c91597..6e3f0dd03 100644 --- a/examples/stm32h723/Cargo.toml +++ b/examples/stm32h723/Cargo.toml @@ -1,6 +1,6 @@ [package] edition = "2021" -name = "embassy-stm32h7-examples" +name = "embassy-stm32h723-examples" version = "0.1.0" license = "MIT OR Apache-2.0" From 721c6820d4a6e3bbf2546997205a32975e6bad8b Mon Sep 17 00:00:00 2001 From: michel Date: Wed, 7 Aug 2024 21:58:49 +0200 Subject: [PATCH 0409/1217] STM32-TSC: enable discriminating between pins within same TSC group and improve TSC library in general --- .gitignore | 3 + embassy-stm32/src/tsc/acquisition_banks.rs | 209 ++++ embassy-stm32/src/tsc/config.rs | 175 +++ embassy-stm32/src/tsc/errors.rs | 21 + embassy-stm32/src/tsc/mod.rs | 1011 ++--------------- embassy-stm32/src/tsc/pin_groups.rs | 675 +++++++++++ embassy-stm32/src/tsc/tsc.rs | 456 ++++++++ .../src/tsc/{enums.rs => tsc_io_pin.rs} | 202 ++-- embassy-stm32/src/tsc/types.rs | 93 ++ examples/stm32f3/README.md | 24 + examples/stm32f3/src/bin/blocking-tsc.rs | 98 -- examples/stm32f3/src/bin/tsc_blocking.rs | 138 +++ examples/stm32l0/.cargo/config.toml | 2 +- examples/stm32l0/Cargo.toml | 2 +- examples/stm32l0/README.md | 24 + examples/stm32l0/src/bin/async-tsc.rs | 122 -- examples/stm32l0/src/bin/blocking-tsc.rs | 116 -- examples/stm32l0/src/bin/tsc_async.rs | 116 ++ examples/stm32l0/src/bin/tsc_blocking.rs | 142 +++ examples/stm32l0/src/bin/tsc_multipin.rs | 233 ++++ examples/stm32l4/.cargo/config.toml | 3 +- examples/stm32l4/Cargo.toml | 2 +- examples/stm32l4/README.md | 24 + examples/stm32l4/src/bin/tsc_async.rs | 108 ++ examples/stm32l4/src/bin/tsc_blocking.rs | 147 +++ examples/stm32l4/src/bin/tsc_multipin.rs | 222 ++++ examples/stm32u5/src/bin/tsc.rs | 77 +- 27 files changed, 3007 insertions(+), 1438 deletions(-) create mode 100644 embassy-stm32/src/tsc/acquisition_banks.rs create mode 100644 embassy-stm32/src/tsc/config.rs create mode 100644 embassy-stm32/src/tsc/errors.rs create mode 100644 embassy-stm32/src/tsc/pin_groups.rs create mode 100644 embassy-stm32/src/tsc/tsc.rs rename embassy-stm32/src/tsc/{enums.rs => tsc_io_pin.rs} (52%) create mode 100644 embassy-stm32/src/tsc/types.rs create mode 100644 examples/stm32f3/README.md delete mode 100644 examples/stm32f3/src/bin/blocking-tsc.rs create mode 100644 examples/stm32f3/src/bin/tsc_blocking.rs create mode 100644 examples/stm32l0/README.md delete mode 100644 examples/stm32l0/src/bin/async-tsc.rs delete mode 100644 examples/stm32l0/src/bin/blocking-tsc.rs create mode 100644 examples/stm32l0/src/bin/tsc_async.rs create mode 100644 examples/stm32l0/src/bin/tsc_blocking.rs create mode 100644 examples/stm32l0/src/bin/tsc_multipin.rs create mode 100644 examples/stm32l4/README.md create mode 100644 examples/stm32l4/src/bin/tsc_async.rs create mode 100644 examples/stm32l4/src/bin/tsc_blocking.rs create mode 100644 examples/stm32l4/src/bin/tsc_multipin.rs diff --git a/.gitignore b/.gitignore index a0b5d6a70..352c1f1af 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,7 @@ Cargo.lock third_party /Cargo.toml out/ +# editor artifacts .zed +.neoconf.json +*.vim diff --git a/embassy-stm32/src/tsc/acquisition_banks.rs b/embassy-stm32/src/tsc/acquisition_banks.rs new file mode 100644 index 000000000..21a5c3f87 --- /dev/null +++ b/embassy-stm32/src/tsc/acquisition_banks.rs @@ -0,0 +1,209 @@ +#[cfg(any(tsc_v2, tsc_v3))] +use super::pin_groups::G7; +#[cfg(tsc_v3)] +use super::pin_groups::G8; +use super::pin_groups::{tsc_pin_roles, G1, G2, G3, G4, G5, G6}; +use super::tsc_io_pin::*; +use super::types::{Group, GroupStatus}; +use super::TSC_NUM_GROUPS; + +/// Represents a collection of TSC (Touch Sensing Controller) pins for an acquisition bank. +/// +/// This struct holds optional `TscIOPin` values for each TSC group, allowing for flexible +/// configuration of TSC acquisition banks. Each field corresponds to a specific TSC group +/// and can be set to `Some(TscIOPin)` if that group is to be included in the acquisition, +/// or `None` if it should be excluded. +#[allow(missing_docs)] +#[derive(Default)] +pub struct TscAcquisitionBankPins { + pub g1_pin: Option>, + pub g2_pin: Option>, + pub g3_pin: Option>, + pub g4_pin: Option>, + pub g5_pin: Option>, + pub g6_pin: Option>, + #[cfg(any(tsc_v2, tsc_v3))] + pub g7_pin: Option>, + #[cfg(tsc_v3)] + pub g8_pin: Option>, +} + +impl TscAcquisitionBankPins { + /// Returns an iterator over the pins in this acquisition bank. + /// + /// This method allows for easy traversal of all configured pins in the bank. + pub fn iter(&self) -> TscAcquisitionBankPinsIterator { + TscAcquisitionBankPinsIterator(TscAcquisitionBankIterator::new(self)) + } +} + +/// Iterator for TSC acquisition banks. +/// +/// This iterator allows traversing through the pins of a `TscAcquisitionBankPins` struct, +/// yielding each configured pin in order of the TSC groups. +pub struct TscAcquisitionBankIterator<'a> { + pins: &'a TscAcquisitionBankPins, + current_group: u8, +} + +impl<'a> TscAcquisitionBankIterator<'a> { + fn new(pins: &'a TscAcquisitionBankPins) -> Self { + Self { pins, current_group: 0 } + } + + fn next_pin(&mut self) -> Option { + while self.current_group < TSC_NUM_GROUPS as u8 { + let pin = match self.current_group { + 0 => self.pins.g1_pin.map(TscIOPinWithRole::get_pin), + 1 => self.pins.g2_pin.map(TscIOPinWithRole::get_pin), + 2 => self.pins.g3_pin.map(TscIOPinWithRole::get_pin), + 3 => self.pins.g4_pin.map(TscIOPinWithRole::get_pin), + 4 => self.pins.g5_pin.map(TscIOPinWithRole::get_pin), + 5 => self.pins.g6_pin.map(TscIOPinWithRole::get_pin), + #[cfg(any(tsc_v2, tsc_v3))] + 6 => self.pins.g7_pin.map(TscIOPinWithRole::get_pin), + #[cfg(tsc_v3)] + 7 => self.pins.g8_pin.map(TscIOPinWithRole::get_pin), + _ => None, + }; + self.current_group += 1; + if pin.is_some() { + return pin; + } + } + None + } +} + +/// Iterator for TSC acquisition bank pins. +/// +/// This iterator yields `TscIOPin` values for each configured pin in the acquisition bank. +pub struct TscAcquisitionBankPinsIterator<'a>(TscAcquisitionBankIterator<'a>); + +impl<'a> Iterator for TscAcquisitionBankPinsIterator<'a> { + type Item = TscIOPin; + + fn next(&mut self) -> Option { + self.0.next_pin() + } +} + +impl TscAcquisitionBankPins { + /// Returns an iterator over the available pins in the bank + pub fn pins_iterator(&self) -> TscAcquisitionBankPinsIterator { + TscAcquisitionBankPinsIterator(TscAcquisitionBankIterator::new(self)) + } +} + +/// Represents a collection of TSC pins to be acquired simultaneously. +/// +/// This struct contains a set of pins to be used in a TSC acquisition with a pre-computed and +/// verified mask for efficiently setting up the TSC peripheral before performing an acquisition. +/// It ensures that only one channel pin per TSC group is included, adhering to hardware limitations. +pub struct TscAcquisitionBank { + pub(super) pins: TscAcquisitionBankPins, + pub(super) mask: u32, +} + +impl TscAcquisitionBank { + /// Returns an iterator over the available pins in the bank. + pub fn pins_iterator(&self) -> TscAcquisitionBankPinsIterator { + self.pins.pins_iterator() + } + + /// Returns the mask for this bank. + pub fn mask(&self) -> u32 { + self.mask + } + + /// Retrieves the TSC I/O pin for a given group in this acquisition bank. + /// + /// # Arguments + /// * `group` - The TSC group to retrieve the pin for. + /// + /// # Returns + /// An `Option` containing the pin if it exists for the given group, or `None` if not. + pub fn get_pin(&self, group: Group) -> Option { + match group { + Group::One => self.pins.g1_pin.map(|p| p.pin), + Group::Two => self.pins.g2_pin.map(|p| p.pin), + Group::Three => self.pins.g3_pin.map(|p| p.pin), + Group::Four => self.pins.g4_pin.map(|p| p.pin), + Group::Five => self.pins.g5_pin.map(|p| p.pin), + Group::Six => self.pins.g6_pin.map(|p| p.pin), + #[cfg(any(tsc_v2, tsc_v3))] + Group::Seven => self.pins.g7_pin.map(|p| p.pin), + #[cfg(tsc_v3)] + Group::Eight => self.pins.g8_pin.map(|p| p.pin), + } + } +} + +/// Represents the status of all TSC groups in an acquisition bank +#[derive(Default)] +pub struct TscAcquisitionBankStatus { + pub(super) groups: [Option; TSC_NUM_GROUPS], +} + +impl TscAcquisitionBankStatus { + /// Check if all groups in the bank are complete + pub fn all_complete(&self) -> bool { + self.groups + .iter() + .all(|&status| status.map_or(true, |s| s == GroupStatus::Complete)) + } + + /// Check if any group in the bank is ongoing + pub fn any_ongoing(&self) -> bool { + self.groups.iter().any(|&status| status == Some(GroupStatus::Ongoing)) + } + + /// Get the status of a specific group, if the group is present in the bank + pub fn get_group_status(&self, group: Group) -> Option { + let index: usize = group.into(); + self.groups[index] + } + + /// Iterator for groups present in the bank + pub fn iter(&self) -> impl Iterator + '_ { + self.groups.iter().enumerate().filter_map(|(group_num, status)| { + status.and_then(|s| Group::try_from(group_num).ok().map(|group| (group, s))) + }) + } +} + +/// Represents the result of a Touch Sensing Controller (TSC) acquisition for a specific pin. +/// +/// This struct contains a reference to the `TscIOPin` from which a value was read, +/// along with the actual sensor reading for that pin. It provides a convenient way +/// to associate TSC readings with their corresponding pins after an acquisition. +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[derive(Clone, Copy, Debug)] +pub struct TscChannelReading { + /// The sensor reading value obtained from the TSC acquisition. + /// Lower values typically indicate a detected touch, while higher values indicate no touch. + pub sensor_value: u16, + + /// The `TscIOPin` associated with this reading. + /// This allows for easy identification of which pin the reading corresponds to. + pub tsc_pin: TscIOPin, +} + +/// Represents the readings from all TSC groups +#[derive(Default)] +pub struct TscAcquisitionBankReadings { + pub(super) groups: [Option; TSC_NUM_GROUPS], +} + +impl TscAcquisitionBankReadings { + /// Get the reading for a specific group, if the group is present in the bank + pub fn get_group_reading(&self, group: Group) -> Option { + let index: usize = group.into(); + self.groups[index] + } + + /// Iterator for readings for groups present in the bank + pub fn iter(&self) -> impl Iterator + '_ { + self.groups.iter().filter_map(|&x| x) + } +} diff --git a/embassy-stm32/src/tsc/config.rs b/embassy-stm32/src/tsc/config.rs new file mode 100644 index 000000000..efa1f9a0d --- /dev/null +++ b/embassy-stm32/src/tsc/config.rs @@ -0,0 +1,175 @@ +/// Charge transfer pulse cycles +#[allow(missing_docs)] +#[derive(Copy, Clone, PartialEq)] +pub enum ChargeTransferPulseCycle { + _1, + _2, + _3, + _4, + _5, + _6, + _7, + _8, + _9, + _10, + _11, + _12, + _13, + _14, + _15, + _16, +} + +impl Into for ChargeTransferPulseCycle { + fn into(self) -> u8 { + match self { + ChargeTransferPulseCycle::_1 => 0, + ChargeTransferPulseCycle::_2 => 1, + ChargeTransferPulseCycle::_3 => 2, + ChargeTransferPulseCycle::_4 => 3, + ChargeTransferPulseCycle::_5 => 4, + ChargeTransferPulseCycle::_6 => 5, + ChargeTransferPulseCycle::_7 => 6, + ChargeTransferPulseCycle::_8 => 7, + ChargeTransferPulseCycle::_9 => 8, + ChargeTransferPulseCycle::_10 => 9, + ChargeTransferPulseCycle::_11 => 10, + ChargeTransferPulseCycle::_12 => 11, + ChargeTransferPulseCycle::_13 => 12, + ChargeTransferPulseCycle::_14 => 13, + ChargeTransferPulseCycle::_15 => 14, + ChargeTransferPulseCycle::_16 => 15, + } + } +} + +/// Max count +#[allow(missing_docs)] +#[derive(Copy, Clone)] +pub enum MaxCount { + _255, + _511, + _1023, + _2047, + _4095, + _8191, + _16383, +} + +impl Into for MaxCount { + fn into(self) -> u8 { + match self { + MaxCount::_255 => 0, + MaxCount::_511 => 1, + MaxCount::_1023 => 2, + MaxCount::_2047 => 3, + MaxCount::_4095 => 4, + MaxCount::_8191 => 5, + MaxCount::_16383 => 6, + } + } +} + +/// Prescaler divider +#[allow(missing_docs)] +#[derive(Copy, Clone, PartialEq)] +pub enum PGPrescalerDivider { + _1, + _2, + _4, + _8, + _16, + _32, + _64, + _128, +} + +impl Into for PGPrescalerDivider { + fn into(self) -> u8 { + match self { + PGPrescalerDivider::_1 => 0, + PGPrescalerDivider::_2 => 1, + PGPrescalerDivider::_4 => 2, + PGPrescalerDivider::_8 => 3, + PGPrescalerDivider::_16 => 4, + PGPrescalerDivider::_32 => 5, + PGPrescalerDivider::_64 => 6, + PGPrescalerDivider::_128 => 7, + } + } +} + +/// Error type for SSDeviation +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum SSDeviationError { + /// The provided value is too low (0) + ValueTooLow, + /// The provided value is too high (greater than 128) + ValueTooHigh, +} + +/// Spread Spectrum Deviation +#[derive(Copy, Clone)] +pub struct SSDeviation(u8); +impl SSDeviation { + /// Create new deviation value, acceptable inputs are 1-128 + pub fn new(val: u8) -> Result { + if val == 0 { + return Err(SSDeviationError::ValueTooLow); + } else if val > 128 { + return Err(SSDeviationError::ValueTooHigh); + } + Ok(Self(val - 1)) + } +} + +impl Into for SSDeviation { + fn into(self) -> u8 { + self.0 + } +} + +/// Peripheral configuration +#[derive(Clone, Copy)] +pub struct Config { + /// Duration of high state of the charge transfer pulse + pub ct_pulse_high_length: ChargeTransferPulseCycle, + /// Duration of the low state of the charge transfer pulse + pub ct_pulse_low_length: ChargeTransferPulseCycle, + /// Enable/disable of spread spectrum feature + pub spread_spectrum: bool, + /// Adds variable number of periods of the SS clk to pulse high state + pub spread_spectrum_deviation: SSDeviation, + /// Selects AHB clock divider used to generate SS clk + pub spread_spectrum_prescaler: bool, + /// Selects AHB clock divider used to generate pulse generator clk + pub pulse_generator_prescaler: PGPrescalerDivider, + /// Maximum number of charge transfer pulses that can be generated before error + pub max_count_value: MaxCount, + /// Defines config of all IOs when no ongoing acquisition + pub io_default_mode: bool, + /// Polarity of sync input pin + pub synchro_pin_polarity: bool, + /// Acquisition starts when start bit is set or with sync pin input + pub acquisition_mode: bool, + /// Enable max count interrupt + pub max_count_interrupt: bool, +} + +impl Default for Config { + fn default() -> Self { + Self { + ct_pulse_high_length: ChargeTransferPulseCycle::_1, + ct_pulse_low_length: ChargeTransferPulseCycle::_1, + spread_spectrum: false, + spread_spectrum_deviation: SSDeviation::new(1).unwrap(), + spread_spectrum_prescaler: false, + pulse_generator_prescaler: PGPrescalerDivider::_1, + max_count_value: MaxCount::_255, + io_default_mode: false, + synchro_pin_polarity: false, + acquisition_mode: false, + max_count_interrupt: false, + } + } +} diff --git a/embassy-stm32/src/tsc/errors.rs b/embassy-stm32/src/tsc/errors.rs new file mode 100644 index 000000000..21f6441ba --- /dev/null +++ b/embassy-stm32/src/tsc/errors.rs @@ -0,0 +1,21 @@ +/// Represents errors that can occur when configuring or validating TSC pin groups. +#[derive(Debug)] +pub enum GroupError { + /// Error when a group has no sampling capacitor + NoSamplingCapacitor, + /// Error when a group has neither channel IOs nor a shield IO + NoChannelOrShield, + /// Error when a group has both channel IOs and a shield IO + MixedChannelAndShield, + /// Error when there is more than one shield IO across all groups + MultipleShields, +} + +/// Error returned when attempting to set an invalid channel pin as active in the TSC. +#[derive(Debug)] +pub enum AcquisitionBankError { + /// Indicates that one or more of the provided pins is not a valid channel pin. + InvalidChannelPin, + /// Indicates that multiple channels from the same group were provided. + MultipleChannelsPerGroup, +} diff --git a/embassy-stm32/src/tsc/mod.rs b/embassy-stm32/src/tsc/mod.rs index 17240e6bc..2df3847bc 100644 --- a/embassy-stm32/src/tsc/mod.rs +++ b/embassy-stm32/src/tsc/mod.rs @@ -1,90 +1,119 @@ //! TSC Peripheral Interface //! +//! This module provides an interface for the Touch Sensing Controller (TSC) peripheral. +//! It supports both blocking and async modes of operation, as well as different TSC versions (v1, v2, v3). +//! +//! # Key Concepts +//! +//! - **Pin Groups**: TSC pins are organized into groups, each containing up to four IOs. +//! - **Pin Roles**: Each pin in a group can have a role: Channel, Sample, or Shield. +//! - **Acquisition Banks**: Used for efficient, repeated TSC acquisitions on specific sets of pins. //! //! # Example (stm32) -//! ``` rust, ignore -//! -//! let mut device_config = embassy_stm32::Config::default(); -//! { -//! device_config.rcc.mux = ClockSrc::MSI(Msirange::RANGE_4MHZ); -//! } //! +//! ```rust +//! let device_config = embassy_stm32::Config::default(); //! let context = embassy_stm32::init(device_config); //! //! let config = tsc::Config { -//! ct_pulse_high_length: ChargeTransferPulseCycle::_2, -//! ct_pulse_low_length: ChargeTransferPulseCycle::_2, +//! ct_pulse_high_length: ChargeTransferPulseCycle::_4, +//! ct_pulse_low_length: ChargeTransferPulseCycle::_4, //! spread_spectrum: false, //! spread_spectrum_deviation: SSDeviation::new(2).unwrap(), //! spread_spectrum_prescaler: false, -//! pulse_generator_prescaler: PGPrescalerDivider::_4, -//! max_count_value: MaxCount::_8191, +//! pulse_generator_prescaler: PGPrescalerDivider::_16, +//! max_count_value: MaxCount::_255, //! io_default_mode: false, //! synchro_pin_polarity: false, //! acquisition_mode: false, //! max_count_interrupt: false, -//! channel_ios: TscIOPin::Group2Io2 | TscIOPin::Group7Io3, -//! shield_ios: TscIOPin::Group1Io3.into(), -//! sampling_ios: TscIOPin::Group1Io2 | TscIOPin::Group2Io1 | TscIOPin::Group7Io2, //! }; //! -//! let mut g1: PinGroup = PinGroup::new(); -//! g1.set_io2(context.PB13, PinType::Sample); -//! g1.set_io3(context.PB14, PinType::Shield); +//! let mut g2: PinGroupWithRoles = PinGroupWithRoles::new(); +//! g2.set_io1::(context.PB4); +//! let sensor_pin = g2.set_io2::(context.PB5); //! -//! let mut g2: PinGroup = PinGroup::new(); -//! g2.set_io1(context.PB4, PinType::Sample); -//! g2.set_io2(context.PB5, PinType::Channel); -//! -//! let mut g7: PinGroup = PinGroup::new(); -//! g7.set_io2(context.PE3, PinType::Sample); -//! g7.set_io3(context.PE4, PinType::Channel); +//! let pin_groups = PinGroups { +//! g2: Some(g2.pin_group), +//! ..Default::default() +//! }; //! //! let mut touch_controller = tsc::Tsc::new_blocking( //! context.TSC, -//! Some(g1), -//! Some(g2), -//! None, -//! None, -//! None, -//! None, -//! Some(g7), -//! None, +//! pin_groups, //! config, -//! ); +//! ).unwrap(); //! -//! touch_controller.discharge_io(true); -//! Timer::after_millis(1).await; +//! let discharge_delay = 5; // ms //! -//! touch_controller.start(); +//! loop { +//! touch_controller.set_active_channels_mask(sensor_pin.pin.into()); +//! touch_controller.start(); +//! touch_controller.poll_for_acquisition(); +//! touch_controller.discharge_io(true); +//! Timer::after_millis(discharge_delay).await; //! +//! match touch_controller.group_get_status(sensor_pin.pin.group()) { +//! GroupStatus::Complete => { +//! let group_val = touch_controller.group_get_value(sensor_pin.pin.group()); +//! // Process the touch value +//! // ... +//! } +//! GroupStatus::Ongoing => { +//! // Handle ongoing acquisition +//! // ... +//! } +//! } +//! } //! ``` +//! +//! # Async Usage +//! +//! For async operation, use `Tsc::new_async` and `pend_for_acquisition` instead of polling. #![macro_use] -/// Enums defined for peripheral parameters -pub mod enums; +/// Configuration structures and enums for the TSC peripheral. +pub mod config; + +/// Definitions and implementations for TSC pin groups. +pub mod pin_groups; + +/// Definitions and implementations for individual TSC I/O pins. +pub mod tsc_io_pin; + +/// Structures and implementations for TSC acquisition banks. +pub mod acquisition_banks; + +/// Core implementation of the TSC (Touch Sensing Controller) driver. +pub mod tsc; + +/// Type definitions used throughout the TSC module. +pub mod types; + +/// Error types and definitions for the TSC module. +pub mod errors; -use core::future::poll_fn; use core::marker::PhantomData; -use core::task::Poll; -use embassy_hal_internal::{into_ref, PeripheralRef}; +pub use acquisition_banks::*; +pub use config::*; use embassy_sync::waitqueue::AtomicWaker; -pub use enums::*; +pub use errors::*; +pub use pin_groups::*; +pub use tsc::*; +pub use tsc_io_pin::*; +pub use types::*; -use crate::gpio::{AfType, AnyPin, OutputType, Speed}; -use crate::interrupt::typelevel::Interrupt; -use crate::mode::{Async, Blocking, Mode as PeriMode}; -use crate::rcc::{self, RccPeripheral}; +use crate::rcc::RccPeripheral; use crate::{interrupt, peripherals, Peripheral}; #[cfg(tsc_v1)] -const TSC_NUM_GROUPS: u32 = 6; +const TSC_NUM_GROUPS: usize = 6; #[cfg(tsc_v2)] -const TSC_NUM_GROUPS: u32 = 7; +const TSC_NUM_GROUPS: usize = 7; #[cfg(tsc_v3)] -const TSC_NUM_GROUPS: u32 = 8; +const TSC_NUM_GROUPS: usize = 8; /// Error type defined for TSC #[derive(Debug, Clone, Copy)] @@ -106,859 +135,6 @@ impl interrupt::typelevel::Handler for InterruptHandl } } -/// Pin type definition to control IO parameters -pub enum PinType { - /// Sensing channel pin connected to an electrode - Channel, - /// Sampling capacitor pin, one required for every pin group - Sample, - /// Shield pin connected to capacitive sensing shield - Shield, -} - -/// Peripheral state -#[derive(PartialEq, Clone, Copy)] -pub enum State { - /// Peripheral is being setup or reconfigured - Reset, - /// Ready to start acquisition - Ready, - /// In process of sensor acquisition - Busy, - /// Error occured during acquisition - Error, -} - -/// Individual group status checked after acquisition reported as complete -/// For groups with multiple channel pins, may take longer because acquisitions -/// are done sequentially. Check this status before pulling count for each -/// sampled channel -#[derive(PartialEq)] -pub enum GroupStatus { - /// Acquisition for channel still in progress - Ongoing, - /// Acquisition either not started or complete - Complete, -} - -/// Group identifier used to interrogate status -#[allow(missing_docs)] -pub enum Group { - One, - Two, - Three, - Four, - Five, - Six, - #[cfg(any(tsc_v2, tsc_v3))] - Seven, - #[cfg(tsc_v3)] - Eight, -} - -impl Into for Group { - fn into(self) -> usize { - match self { - Group::One => 0, - Group::Two => 1, - Group::Three => 2, - Group::Four => 3, - Group::Five => 4, - Group::Six => 5, - #[cfg(any(tsc_v2, tsc_v3))] - Group::Seven => 6, - #[cfg(tsc_v3)] - Group::Eight => 7, - } - } -} - -/// Peripheral configuration -#[derive(Clone, Copy)] -pub struct Config { - /// Duration of high state of the charge transfer pulse - pub ct_pulse_high_length: ChargeTransferPulseCycle, - /// Duration of the low state of the charge transfer pulse - pub ct_pulse_low_length: ChargeTransferPulseCycle, - /// Enable/disable of spread spectrum feature - pub spread_spectrum: bool, - /// Adds variable number of periods of the SS clk to pulse high state - pub spread_spectrum_deviation: SSDeviation, - /// Selects AHB clock divider used to generate SS clk - pub spread_spectrum_prescaler: bool, - /// Selects AHB clock divider used to generate pulse generator clk - pub pulse_generator_prescaler: PGPrescalerDivider, - /// Maximum number of charge transfer pulses that can be generated before error - pub max_count_value: MaxCount, - /// Defines config of all IOs when no ongoing acquisition - pub io_default_mode: bool, - /// Polarity of sync input pin - pub synchro_pin_polarity: bool, - /// Acquisition starts when start bit is set or with sync pin input - pub acquisition_mode: bool, - /// Enable max count interrupt - pub max_count_interrupt: bool, - /// Channel IO mask - pub channel_ios: u32, - /// Shield IO mask - pub shield_ios: u32, - /// Sampling IO mask - pub sampling_ios: u32, -} - -impl Default for Config { - fn default() -> Self { - Self { - ct_pulse_high_length: ChargeTransferPulseCycle::_1, - ct_pulse_low_length: ChargeTransferPulseCycle::_1, - spread_spectrum: false, - spread_spectrum_deviation: SSDeviation::new(1).unwrap(), - spread_spectrum_prescaler: false, - pulse_generator_prescaler: PGPrescalerDivider::_1, - max_count_value: MaxCount::_255, - io_default_mode: false, - synchro_pin_polarity: false, - acquisition_mode: false, - max_count_interrupt: false, - channel_ios: 0, - shield_ios: 0, - sampling_ios: 0, - } - } -} - -/// Pin struct that maintains usage -#[allow(missing_docs)] -pub struct TscPin<'d, T, C> { - _pin: PeripheralRef<'d, AnyPin>, - role: PinType, - phantom: PhantomData<(T, C)>, -} - -enum GroupError { - NoSample, - ChannelShield, -} - -/// Pin group definition -/// Pins are organized into groups of four IOs, all groups with a -/// sampling channel must also have a sampling capacitor channel. -#[allow(missing_docs)] -#[derive(Default)] -pub struct PinGroup<'d, T, C> { - d1: Option>, - d2: Option>, - d3: Option>, - d4: Option>, -} - -impl<'d, T: Instance, C> PinGroup<'d, T, C> { - /// Create new sensing group - pub fn new() -> Self { - Self { - d1: None, - d2: None, - d3: None, - d4: None, - } - } - - fn contains_shield(&self) -> bool { - let mut shield_count = 0; - - if let Some(pin) = &self.d1 { - if let PinType::Shield = pin.role { - shield_count += 1; - } - } - - if let Some(pin) = &self.d2 { - if let PinType::Shield = pin.role { - shield_count += 1; - } - } - - if let Some(pin) = &self.d3 { - if let PinType::Shield = pin.role { - shield_count += 1; - } - } - - if let Some(pin) = &self.d4 { - if let PinType::Shield = pin.role { - shield_count += 1; - } - } - - shield_count == 1 - } - - fn check_group(&self) -> Result<(), GroupError> { - let mut channel_count = 0; - let mut shield_count = 0; - let mut sample_count = 0; - if let Some(pin) = &self.d1 { - match pin.role { - PinType::Channel => { - channel_count += 1; - } - PinType::Shield => { - shield_count += 1; - } - PinType::Sample => { - sample_count += 1; - } - } - } - - if let Some(pin) = &self.d2 { - match pin.role { - PinType::Channel => { - channel_count += 1; - } - PinType::Shield => { - shield_count += 1; - } - PinType::Sample => { - sample_count += 1; - } - } - } - - if let Some(pin) = &self.d3 { - match pin.role { - PinType::Channel => { - channel_count += 1; - } - PinType::Shield => { - shield_count += 1; - } - PinType::Sample => { - sample_count += 1; - } - } - } - - if let Some(pin) = &self.d4 { - match pin.role { - PinType::Channel => { - channel_count += 1; - } - PinType::Shield => { - shield_count += 1; - } - PinType::Sample => { - sample_count += 1; - } - } - } - - // Every group requires one sampling capacitor - if sample_count != 1 { - return Err(GroupError::NoSample); - } - - // Each group must have at least one shield or channel IO - if shield_count == 0 && channel_count == 0 { - return Err(GroupError::ChannelShield); - } - - // Any group can either contain channel ios or a shield IO - if shield_count != 0 && channel_count != 0 { - return Err(GroupError::ChannelShield); - } - - // No more than one shield IO is allow per group and amongst all groups - if shield_count > 1 { - return Err(GroupError::ChannelShield); - } - - Ok(()) - } -} - -macro_rules! group_impl { - ($group:ident, $trait1:ident, $trait2:ident, $trait3:ident, $trait4:ident) => { - impl<'d, T: Instance> PinGroup<'d, T, $group> { - #[doc = concat!("Create a new pin1 for ", stringify!($group), " TSC group instance.")] - pub fn set_io1(&mut self, pin: impl Peripheral

> + 'd, role: PinType) { - into_ref!(pin); - critical_section::with(|_| { - pin.set_low(); - pin.set_as_af( - pin.af_num(), - AfType::output( - match role { - PinType::Channel => OutputType::PushPull, - PinType::Sample => OutputType::OpenDrain, - PinType::Shield => OutputType::PushPull, - }, - Speed::VeryHigh, - ), - ); - self.d1 = Some(TscPin { - _pin: pin.map_into(), - role: role, - phantom: PhantomData, - }) - }) - } - - #[doc = concat!("Create a new pin2 for ", stringify!($group), " TSC group instance.")] - pub fn set_io2(&mut self, pin: impl Peripheral

> + 'd, role: PinType) { - into_ref!(pin); - critical_section::with(|_| { - pin.set_low(); - pin.set_as_af( - pin.af_num(), - AfType::output( - match role { - PinType::Channel => OutputType::PushPull, - PinType::Sample => OutputType::OpenDrain, - PinType::Shield => OutputType::PushPull, - }, - Speed::VeryHigh, - ), - ); - self.d2 = Some(TscPin { - _pin: pin.map_into(), - role: role, - phantom: PhantomData, - }) - }) - } - - #[doc = concat!("Create a new pin3 for ", stringify!($group), " TSC group instance.")] - pub fn set_io3(&mut self, pin: impl Peripheral

> + 'd, role: PinType) { - into_ref!(pin); - critical_section::with(|_| { - pin.set_low(); - pin.set_as_af( - pin.af_num(), - AfType::output( - match role { - PinType::Channel => OutputType::PushPull, - PinType::Sample => OutputType::OpenDrain, - PinType::Shield => OutputType::PushPull, - }, - Speed::VeryHigh, - ), - ); - self.d3 = Some(TscPin { - _pin: pin.map_into(), - role: role, - phantom: PhantomData, - }) - }) - } - - #[doc = concat!("Create a new pin4 for ", stringify!($group), " TSC group instance.")] - pub fn set_io4(&mut self, pin: impl Peripheral

> + 'd, role: PinType) { - into_ref!(pin); - critical_section::with(|_| { - pin.set_low(); - pin.set_as_af( - pin.af_num(), - AfType::output( - match role { - PinType::Channel => OutputType::PushPull, - PinType::Sample => OutputType::OpenDrain, - PinType::Shield => OutputType::PushPull, - }, - Speed::VeryHigh, - ), - ); - self.d4 = Some(TscPin { - _pin: pin.map_into(), - role: role, - phantom: PhantomData, - }) - }) - } - } - }; -} - -group_impl!(G1, G1IO1Pin, G1IO2Pin, G1IO3Pin, G1IO4Pin); -group_impl!(G2, G2IO1Pin, G2IO2Pin, G2IO3Pin, G2IO4Pin); -group_impl!(G3, G3IO1Pin, G3IO2Pin, G3IO3Pin, G3IO4Pin); -group_impl!(G4, G4IO1Pin, G4IO2Pin, G4IO3Pin, G4IO4Pin); -group_impl!(G5, G5IO1Pin, G5IO2Pin, G5IO3Pin, G5IO4Pin); -group_impl!(G6, G6IO1Pin, G6IO2Pin, G6IO3Pin, G6IO4Pin); -group_impl!(G7, G7IO1Pin, G7IO2Pin, G7IO3Pin, G7IO4Pin); -group_impl!(G8, G8IO1Pin, G8IO2Pin, G8IO3Pin, G8IO4Pin); - -/// Group 1 marker type. -pub enum G1 {} -/// Group 2 marker type. -pub enum G2 {} -/// Group 3 marker type. -pub enum G3 {} -/// Group 4 marker type. -pub enum G4 {} -/// Group 5 marker type. -pub enum G5 {} -/// Group 6 marker type. -pub enum G6 {} -/// Group 7 marker type. -pub enum G7 {} -/// Group 8 marker type. -pub enum G8 {} - -/// TSC driver -pub struct Tsc<'d, T: Instance, K: PeriMode> { - _peri: PeripheralRef<'d, T>, - _g1: Option>, - _g2: Option>, - _g3: Option>, - _g4: Option>, - _g5: Option>, - _g6: Option>, - #[cfg(any(tsc_v2, tsc_v3))] - _g7: Option>, - #[cfg(tsc_v3)] - _g8: Option>, - state: State, - config: Config, - _kind: PhantomData, -} - -impl<'d, T: Instance> Tsc<'d, T, Async> { - /// Create a Tsc instance that can be awaited for completion - pub fn new_async( - peri: impl Peripheral

+ 'd, - g1: Option>, - g2: Option>, - g3: Option>, - g4: Option>, - g5: Option>, - g6: Option>, - #[cfg(any(tsc_v2, tsc_v3))] g7: Option>, - #[cfg(tsc_v3)] g8: Option>, - config: Config, - _irq: impl interrupt::typelevel::Binding> + 'd, - ) -> Self { - // Need to check valid pin configuration input - let g1 = g1.filter(|b| b.check_group().is_ok()); - let g2 = g2.filter(|b| b.check_group().is_ok()); - let g3 = g3.filter(|b| b.check_group().is_ok()); - let g4 = g4.filter(|b| b.check_group().is_ok()); - let g5 = g5.filter(|b| b.check_group().is_ok()); - let g6 = g6.filter(|b| b.check_group().is_ok()); - #[cfg(any(tsc_v2, tsc_v3))] - let g7 = g7.filter(|b| b.check_group().is_ok()); - #[cfg(tsc_v3)] - let g8 = g8.filter(|b| b.check_group().is_ok()); - - match Self::check_shields( - &g1, - &g2, - &g3, - &g4, - &g5, - &g6, - #[cfg(any(tsc_v2, tsc_v3))] - &g7, - #[cfg(tsc_v3)] - &g8, - ) { - Ok(()) => Self::new_inner( - peri, - g1, - g2, - g3, - g4, - g5, - g6, - #[cfg(any(tsc_v2, tsc_v3))] - g7, - #[cfg(tsc_v3)] - g8, - config, - ), - Err(_) => Self::new_inner( - peri, - None, - None, - None, - None, - None, - None, - #[cfg(any(tsc_v2, tsc_v3))] - None, - #[cfg(tsc_v3)] - None, - config, - ), - } - } - /// Asyncronously wait for the end of an acquisition - pub async fn pend_for_acquisition(&mut self) { - poll_fn(|cx| match self.get_state() { - State::Busy => { - T::waker().register(cx.waker()); - T::regs().ier().write(|w| w.set_eoaie(true)); - if self.get_state() != State::Busy { - T::regs().ier().write(|w| w.set_eoaie(false)); - return Poll::Ready(()); - } - Poll::Pending - } - _ => { - T::regs().ier().write(|w| w.set_eoaie(false)); - Poll::Ready(()) - } - }) - .await; - } -} - -impl<'d, T: Instance> Tsc<'d, T, Blocking> { - /// Create a Tsc instance that must be polled for completion - pub fn new_blocking( - peri: impl Peripheral

+ 'd, - g1: Option>, - g2: Option>, - g3: Option>, - g4: Option>, - g5: Option>, - g6: Option>, - #[cfg(any(tsc_v2, tsc_v3))] g7: Option>, - #[cfg(tsc_v3)] g8: Option>, - config: Config, - ) -> Self { - // Need to check valid pin configuration input - let g1 = g1.filter(|b| b.check_group().is_ok()); - let g2 = g2.filter(|b| b.check_group().is_ok()); - let g3 = g3.filter(|b| b.check_group().is_ok()); - let g4 = g4.filter(|b| b.check_group().is_ok()); - let g5 = g5.filter(|b| b.check_group().is_ok()); - let g6 = g6.filter(|b| b.check_group().is_ok()); - #[cfg(any(tsc_v2, tsc_v3))] - let g7 = g7.filter(|b| b.check_group().is_ok()); - #[cfg(tsc_v3)] - let g8 = g8.filter(|b| b.check_group().is_ok()); - - match Self::check_shields( - &g1, - &g2, - &g3, - &g4, - &g5, - &g6, - #[cfg(any(tsc_v2, tsc_v3))] - &g7, - #[cfg(tsc_v3)] - &g8, - ) { - Ok(()) => Self::new_inner( - peri, - g1, - g2, - g3, - g4, - g5, - g6, - #[cfg(any(tsc_v2, tsc_v3))] - g7, - #[cfg(tsc_v3)] - g8, - config, - ), - Err(_) => Self::new_inner( - peri, - None, - None, - None, - None, - None, - None, - #[cfg(any(tsc_v2, tsc_v3))] - None, - #[cfg(tsc_v3)] - None, - config, - ), - } - } - /// Wait for end of acquisition - pub fn poll_for_acquisition(&mut self) { - while self.get_state() == State::Busy {} - } -} - -impl<'d, T: Instance, K: PeriMode> Tsc<'d, T, K> { - /// Create new TSC driver - fn check_shields( - g1: &Option>, - g2: &Option>, - g3: &Option>, - g4: &Option>, - g5: &Option>, - g6: &Option>, - #[cfg(any(tsc_v2, tsc_v3))] g7: &Option>, - #[cfg(tsc_v3)] g8: &Option>, - ) -> Result<(), GroupError> { - let mut shield_count = 0; - - if let Some(pin_group) = g1 { - if pin_group.contains_shield() { - shield_count += 1; - } - }; - if let Some(pin_group) = g2 { - if pin_group.contains_shield() { - shield_count += 1; - } - }; - if let Some(pin_group) = g3 { - if pin_group.contains_shield() { - shield_count += 1; - } - }; - if let Some(pin_group) = g4 { - if pin_group.contains_shield() { - shield_count += 1; - } - }; - if let Some(pin_group) = g5 { - if pin_group.contains_shield() { - shield_count += 1; - } - }; - if let Some(pin_group) = g6 { - if pin_group.contains_shield() { - shield_count += 1; - } - }; - #[cfg(any(tsc_v2, tsc_v3))] - if let Some(pin_group) = g7 { - if pin_group.contains_shield() { - shield_count += 1; - } - }; - #[cfg(tsc_v3)] - if let Some(pin_group) = g8 { - if pin_group.contains_shield() { - shield_count += 1; - } - }; - - if shield_count > 1 { - return Err(GroupError::ChannelShield); - } - - Ok(()) - } - - fn extract_groups(io_mask: u32) -> u32 { - let mut groups: u32 = 0; - for idx in 0..TSC_NUM_GROUPS { - if io_mask & (0x0F << idx * 4) != 0 { - groups |= 1 << idx - } - } - groups - } - - fn new_inner( - peri: impl Peripheral

+ 'd, - g1: Option>, - g2: Option>, - g3: Option>, - g4: Option>, - g5: Option>, - g6: Option>, - #[cfg(any(tsc_v2, tsc_v3))] g7: Option>, - #[cfg(tsc_v3)] g8: Option>, - config: Config, - ) -> Self { - into_ref!(peri); - - rcc::enable_and_reset::(); - - T::regs().cr().modify(|w| { - w.set_tsce(true); - w.set_ctph(config.ct_pulse_high_length.into()); - w.set_ctpl(config.ct_pulse_low_length.into()); - w.set_sse(config.spread_spectrum); - // Prevent invalid configuration for pulse generator prescaler - if config.ct_pulse_low_length == ChargeTransferPulseCycle::_1 - && (config.pulse_generator_prescaler == PGPrescalerDivider::_1 - || config.pulse_generator_prescaler == PGPrescalerDivider::_2) - { - w.set_pgpsc(PGPrescalerDivider::_4.into()); - } else if config.ct_pulse_low_length == ChargeTransferPulseCycle::_2 - && config.pulse_generator_prescaler == PGPrescalerDivider::_1 - { - w.set_pgpsc(PGPrescalerDivider::_2.into()); - } else { - w.set_pgpsc(config.pulse_generator_prescaler.into()); - } - w.set_ssd(config.spread_spectrum_deviation.into()); - w.set_sspsc(config.spread_spectrum_prescaler); - - w.set_mcv(config.max_count_value.into()); - w.set_syncpol(config.synchro_pin_polarity); - w.set_am(config.acquisition_mode); - }); - - // Set IO configuration - // Disable Schmitt trigger hysteresis on all used TSC IOs - T::regs() - .iohcr() - .write(|w| w.0 = !(config.channel_ios | config.shield_ios | config.sampling_ios)); - - // Set channel and shield IOs - T::regs() - .ioccr() - .write(|w| w.0 = config.channel_ios | config.shield_ios); - - // Set sampling IOs - T::regs().ioscr().write(|w| w.0 = config.sampling_ios); - - // Set the groups to be acquired - T::regs() - .iogcsr() - .write(|w| w.0 = Self::extract_groups(config.channel_ios)); - - // Disable interrupts - T::regs().ier().modify(|w| { - w.set_eoaie(false); - w.set_mceie(false); - }); - - // Clear flags - T::regs().icr().modify(|w| { - w.set_eoaic(true); - w.set_mceic(true); - }); - - unsafe { - T::Interrupt::enable(); - } - - Self { - _peri: peri, - _g1: g1, - _g2: g2, - _g3: g3, - _g4: g4, - _g5: g5, - _g6: g6, - #[cfg(any(tsc_v2, tsc_v3))] - _g7: g7, - #[cfg(tsc_v3)] - _g8: g8, - state: State::Ready, - config, - _kind: PhantomData, - } - } - - /// Start charge transfer acquisition - pub fn start(&mut self) { - self.state = State::Busy; - - // Disable interrupts - T::regs().ier().modify(|w| { - w.set_eoaie(false); - w.set_mceie(false); - }); - - // Clear flags - T::regs().icr().modify(|w| { - w.set_eoaic(true); - w.set_mceic(true); - }); - - // Set the touch sensing IOs not acquired to the default mode - T::regs().cr().modify(|w| { - w.set_iodef(self.config.io_default_mode); - }); - - // Start the acquisition - T::regs().cr().modify(|w| { - w.set_start(true); - }); - } - - /// Stop charge transfer acquisition - pub fn stop(&mut self) { - T::regs().cr().modify(|w| { - w.set_start(false); - }); - - // Set the touch sensing IOs in low power mode - T::regs().cr().modify(|w| { - w.set_iodef(false); - }); - - // Clear flags - T::regs().icr().modify(|w| { - w.set_eoaic(true); - w.set_mceic(true); - }); - - self.state = State::Ready; - } - - /// Get current state of acquisition - pub fn get_state(&mut self) -> State { - if self.state == State::Busy { - if T::regs().isr().read().eoaf() { - if T::regs().isr().read().mcef() { - self.state = State::Error - } else { - self.state = State::Ready - } - } - } - self.state - } - - /// Get the individual group status to check acquisition complete - pub fn group_get_status(&mut self, index: Group) -> GroupStatus { - // Status bits are set by hardware when the acquisition on the corresponding - // enabled analog IO group is complete, cleared when new acquisition is started - let status = match index { - Group::One => T::regs().iogcsr().read().g1s(), - Group::Two => T::regs().iogcsr().read().g2s(), - Group::Three => T::regs().iogcsr().read().g3s(), - Group::Four => T::regs().iogcsr().read().g4s(), - Group::Five => T::regs().iogcsr().read().g5s(), - Group::Six => T::regs().iogcsr().read().g6s(), - #[cfg(any(tsc_v2, tsc_v3))] - Group::Seven => T::regs().iogcsr().read().g7s(), - #[cfg(tsc_v3)] - Group::Eight => T::regs().iogcsr().read().g8s(), - }; - match status { - true => GroupStatus::Complete, - false => GroupStatus::Ongoing, - } - } - - /// Get the count for the acquisiton, valid once group status is set - pub fn group_get_value(&mut self, index: Group) -> u16 { - T::regs().iogcr(index.into()).read().cnt() - } - - /// Discharge the IOs for subsequent acquisition - pub fn discharge_io(&mut self, status: bool) { - // Set the touch sensing IOs in low power mode - T::regs().cr().modify(|w| { - w.set_iodef(!status); - }); - } -} - -impl<'d, T: Instance, K: PeriMode> Drop for Tsc<'d, T, K> { - fn drop(&mut self) { - rcc::disable::(); - } -} - pub(crate) trait SealedInstance { fn regs() -> crate::pac::tsc::Tsc; fn waker() -> &'static AtomicWaker; @@ -988,36 +164,3 @@ foreach_interrupt!( } }; ); - -pin_trait!(G1IO1Pin, Instance); -pin_trait!(G1IO2Pin, Instance); -pin_trait!(G1IO3Pin, Instance); -pin_trait!(G1IO4Pin, Instance); -pin_trait!(G2IO1Pin, Instance); -pin_trait!(G2IO2Pin, Instance); -pin_trait!(G2IO3Pin, Instance); -pin_trait!(G2IO4Pin, Instance); -pin_trait!(G3IO1Pin, Instance); -pin_trait!(G3IO2Pin, Instance); -pin_trait!(G3IO3Pin, Instance); -pin_trait!(G3IO4Pin, Instance); -pin_trait!(G4IO1Pin, Instance); -pin_trait!(G4IO2Pin, Instance); -pin_trait!(G4IO3Pin, Instance); -pin_trait!(G4IO4Pin, Instance); -pin_trait!(G5IO1Pin, Instance); -pin_trait!(G5IO2Pin, Instance); -pin_trait!(G5IO3Pin, Instance); -pin_trait!(G5IO4Pin, Instance); -pin_trait!(G6IO1Pin, Instance); -pin_trait!(G6IO2Pin, Instance); -pin_trait!(G6IO3Pin, Instance); -pin_trait!(G6IO4Pin, Instance); -pin_trait!(G7IO1Pin, Instance); -pin_trait!(G7IO2Pin, Instance); -pin_trait!(G7IO3Pin, Instance); -pin_trait!(G7IO4Pin, Instance); -pin_trait!(G8IO1Pin, Instance); -pin_trait!(G8IO2Pin, Instance); -pin_trait!(G8IO3Pin, Instance); -pin_trait!(G8IO4Pin, Instance); diff --git a/embassy-stm32/src/tsc/pin_groups.rs b/embassy-stm32/src/tsc/pin_groups.rs new file mode 100644 index 000000000..b15890d6f --- /dev/null +++ b/embassy-stm32/src/tsc/pin_groups.rs @@ -0,0 +1,675 @@ +use core::marker::PhantomData; +use core::ops::BitOr; + +use embassy_hal_internal::{into_ref, PeripheralRef}; + +use super::errors::GroupError; +use super::tsc_io_pin::*; +use super::Instance; +use crate::gpio::{AfType, AnyPin, OutputType, Speed}; +use crate::Peripheral; + +/// Pin type definition to control IO parameters +#[derive(PartialEq, Clone, Copy)] +pub enum PinType { + /// Sensing channel pin connected to an electrode + Channel, + /// Sampling capacitor pin, one required for every pin group + Sample, + /// Shield pin connected to capacitive sensing shield + Shield, +} + +/// Pin struct that maintains usage +#[allow(missing_docs)] +pub struct TscPin<'d, T, Group> { + _pin: PeripheralRef<'d, AnyPin>, + role: PinType, + tsc_io_pin: TscIOPin, + phantom: PhantomData<(T, Group)>, +} + +impl<'d, T, Group> TscPin<'d, T, Group> { + /// Returns the role of this TSC pin. + /// + /// The role indicates whether this pin is configured as a channel, + /// sampling capacitor, or shield in the TSC group. + /// + /// # Returns + /// The `PinType` representing the role of this pin. + pub fn role(&self) -> PinType { + self.role + } + + /// Returns the TSC IO pin associated with this pin. + /// + /// This method provides access to the specific TSC IO pin configuration, + /// which includes information about the pin's group and position within that group. + /// + /// # Returns + /// The `TscIOPin` representing this pin's TSC-specific configuration. + pub fn tsc_io_pin(&self) -> TscIOPin { + self.tsc_io_pin + } +} + +/// Represents a group of TSC (Touch Sensing Controller) pins. +/// +/// In the TSC peripheral, pins are organized into groups of four IOs. Each group +/// must have exactly one sampling capacitor pin and can have multiple channel pins +/// or a single shield pin. This structure encapsulates these pin configurations +/// for a single TSC group. +/// +/// # Pin Roles +/// - Sampling Capacitor: One required per group, used for charge transfer. +/// - Channel: Sensing pins connected to electrodes for touch detection. +/// - Shield: Optional, used for active shielding to improve sensitivity. +/// +/// # Constraints +/// - Each group must have exactly one sampling capacitor pin. +/// - A group can have either channel pins or a shield pin, but not both. +/// - No more than one shield pin is allowed across all groups. +#[allow(missing_docs)] +pub struct PinGroup<'d, T, Group> { + pin1: Option>, + pin2: Option>, + pin3: Option>, + pin4: Option>, +} + +impl<'d, T, G> Default for PinGroup<'d, T, G> { + fn default() -> Self { + Self { + pin1: None, + pin2: None, + pin3: None, + pin4: None, + } + } +} + +/// Defines roles and traits for TSC (Touch Sensing Controller) pins. +/// +/// This module contains marker types and traits that represent different roles +/// a TSC pin can have, such as channel, sample, or shield. +pub mod tsc_pin_roles { + use super::{OutputType, PinType}; + + /// Marker type for a TSC channel pin. + #[derive(PartialEq, Clone, Copy, Debug)] + pub struct Channel; + + /// Marker type for a TSC sampling pin. + #[derive(PartialEq, Clone, Copy, Debug)] + pub struct Sample; + + /// Marker type for a TSC shield pin. + #[derive(PartialEq, Clone, Copy, Debug)] + pub struct Shield; + + /// Trait for TSC pin roles. + /// + /// This trait defines the behavior and properties of different TSC pin roles. + /// It is implemented by the marker types `Channel`, `Sample`, and `Shield`. + pub trait Role { + /// Returns the `PinType` associated with this role. + fn pin_type() -> PinType; + + /// Returns the `OutputType` associated with this role. + fn output_type() -> OutputType; + } + + impl Role for Channel { + fn pin_type() -> PinType { + PinType::Channel + } + fn output_type() -> OutputType { + OutputType::PushPull + } + } + + impl Role for Sample { + fn pin_type() -> PinType { + PinType::Sample + } + fn output_type() -> OutputType { + OutputType::OpenDrain + } + } + + impl Role for Shield { + fn pin_type() -> PinType { + PinType::Shield + } + fn output_type() -> OutputType { + OutputType::PushPull + } + } +} + +/// Represents a group of TSC pins with their associated roles. +/// +/// This struct allows for type-safe configuration of TSC pin groups, +/// ensuring that pins are assigned appropriate roles within their group. +/// This type is essentially just a wrapper type around a `PinGroup` value. +/// +/// # Type Parameters +/// - `'d`: Lifetime of the pin group. +/// - `T`: The TSC instance type. +/// - `G`: The group identifier. +/// - `R1`, `R2`, `R3`, `R4`: Role types for each pin in the group, defaulting to `Channel`. +pub struct PinGroupWithRoles< + 'd, + T: Instance, + G, + R1 = tsc_pin_roles::Channel, + R2 = tsc_pin_roles::Channel, + R3 = tsc_pin_roles::Channel, + R4 = tsc_pin_roles::Channel, +> { + /// The underlying pin group without role information. + pub pin_group: PinGroup<'d, T, G>, + _phantom: PhantomData<(R1, R2, R3, R4)>, +} + +impl<'d, T: Instance, G, R1, R2, R3, R4> Default for PinGroupWithRoles<'d, T, G, R1, R2, R3, R4> { + fn default() -> Self { + Self { + pin_group: PinGroup::default(), + _phantom: PhantomData, + } + } +} + +impl<'d, T: Instance, G> PinGroup<'d, T, G> { + fn contains_exactly_one_shield_pin(&self) -> bool { + let shield_count = self.shield_pins().count(); + shield_count == 1 + } + + fn check_group(&self) -> Result<(), GroupError> { + let mut channel_count = 0; + let mut shield_count = 0; + let mut sample_count = 0; + for pin in self.pins().into_iter().flatten() { + match pin.role { + PinType::Channel => { + channel_count += 1; + } + PinType::Shield => { + shield_count += 1; + } + PinType::Sample => { + sample_count += 1; + } + } + } + + // Every group requires exactly one sampling capacitor + if sample_count != 1 { + return Err(GroupError::NoSamplingCapacitor); + } + + // Each group must have at least one shield or channel IO + if shield_count == 0 && channel_count == 0 { + return Err(GroupError::NoChannelOrShield); + } + + // Any group can either contain channel ios or a shield IO. + // (An active shield requires its own sampling capacitor) + if shield_count != 0 && channel_count != 0 { + return Err(GroupError::MixedChannelAndShield); + } + + // No more than one shield IO is allow per group and amongst all groups + if shield_count > 1 { + return Err(GroupError::MultipleShields); + } + + Ok(()) + } + + /// Returns a reference to the first pin in the group, if configured. + pub fn pin1(&self) -> Option<&TscPin<'d, T, G>> { + self.pin1.as_ref() + } + + /// Returns a reference to the second pin in the group, if configured. + pub fn pin2(&self) -> Option<&TscPin<'d, T, G>> { + self.pin2.as_ref() + } + + /// Returns a reference to the third pin in the group, if configured. + pub fn pin3(&self) -> Option<&TscPin<'d, T, G>> { + self.pin3.as_ref() + } + + /// Returns a reference to the fourth pin in the group, if configured. + pub fn pin4(&self) -> Option<&TscPin<'d, T, G>> { + self.pin4.as_ref() + } + + fn sample_pins(&self) -> impl Iterator + '_ { + self.pins_filtered(PinType::Sample) + } + + fn shield_pins(&self) -> impl Iterator + '_ { + self.pins_filtered(PinType::Shield) + } + + fn channel_pins(&self) -> impl Iterator + '_ { + self.pins_filtered(PinType::Channel) + } + + fn pins_filtered(&self, pin_type: PinType) -> impl Iterator + '_ { + self.pins().into_iter().filter_map(move |pin| { + pin.as_ref() + .and_then(|p| if p.role == pin_type { Some(p.tsc_io_pin) } else { None }) + }) + } + + fn make_channel_ios_mask(&self) -> u32 { + self.channel_pins().fold(0, u32::bitor) + } + + fn make_shield_ios_mask(&self) -> u32 { + self.shield_pins().fold(0, u32::bitor) + } + + fn make_sample_ios_mask(&self) -> u32 { + self.sample_pins().fold(0, u32::bitor) + } + + fn pins(&self) -> [&Option>; 4] { + [&self.pin1, &self.pin2, &self.pin3, &self.pin4] + } + + fn pins_mut(&mut self) -> [&mut Option>; 4] { + [&mut self.pin1, &mut self.pin2, &mut self.pin3, &mut self.pin4] + } +} + +#[cfg(any(tsc_v2, tsc_v3))] +macro_rules! TSC_V2_V3_GUARD { + ($e:expr) => {{ + #[cfg(any(tsc_v2, tsc_v3))] + { + $e + } + #[cfg(not(any(tsc_v2, tsc_v3)))] + { + compile_error!("Group 7 is not supported in this TSC version") + } + }}; +} + +#[cfg(tsc_v3)] +macro_rules! TSC_V3_GUARD { + ($e:expr) => {{ + #[cfg(tsc_v3)] + { + $e + } + #[cfg(not(tsc_v3))] + { + compile_error!("Group 8 is not supported in this TSC version") + } + }}; +} + +macro_rules! trait_to_tsc_io_pin { + (G1IO1Pin) => { + TscIOPin::Group1Io1 + }; + (G1IO2Pin) => { + TscIOPin::Group1Io2 + }; + (G1IO3Pin) => { + TscIOPin::Group1Io3 + }; + (G1IO4Pin) => { + TscIOPin::Group1Io4 + }; + + (G2IO1Pin) => { + TscIOPin::Group2Io1 + }; + (G2IO2Pin) => { + TscIOPin::Group2Io2 + }; + (G2IO3Pin) => { + TscIOPin::Group2Io3 + }; + (G2IO4Pin) => { + TscIOPin::Group2Io4 + }; + + (G3IO1Pin) => { + TscIOPin::Group3Io1 + }; + (G3IO2Pin) => { + TscIOPin::Group3Io2 + }; + (G3IO3Pin) => { + TscIOPin::Group3Io3 + }; + (G3IO4Pin) => { + TscIOPin::Group3Io4 + }; + + (G4IO1Pin) => { + TscIOPin::Group4Io1 + }; + (G4IO2Pin) => { + TscIOPin::Group4Io2 + }; + (G4IO3Pin) => { + TscIOPin::Group4Io3 + }; + (G4IO4Pin) => { + TscIOPin::Group4Io4 + }; + + (G5IO1Pin) => { + TscIOPin::Group5Io1 + }; + (G5IO2Pin) => { + TscIOPin::Group5Io2 + }; + (G5IO3Pin) => { + TscIOPin::Group5Io3 + }; + (G5IO4Pin) => { + TscIOPin::Group5Io4 + }; + + (G6IO1Pin) => { + TscIOPin::Group6Io1 + }; + (G6IO2Pin) => { + TscIOPin::Group6Io2 + }; + (G6IO3Pin) => { + TscIOPin::Group6Io3 + }; + (G6IO4Pin) => { + TscIOPin::Group6Io4 + }; + + (G7IO1Pin) => { + TSC_V2_V3_GUARD!(TscIOPin::Group7Io1) + }; + (G7IO2Pin) => { + TSC_V2_V3_GUARD!(TscIOPin::Group7Io2) + }; + (G7IO3Pin) => { + TSC_V2_V3_GUARD!(TscIOPin::Group7Io3) + }; + (G7IO4Pin) => { + TSC_V2_V3_GUARD!(TscIOPin::Group7Io4) + }; + + (G8IO1Pin) => { + TSC_V3_GUARD!(TscIOPin::Group8Io1) + }; + (G8IO2Pin) => { + TSC_V3_GUARD!(TscIOPin::Group8Io2) + }; + (G8IO3Pin) => { + TSC_V3_GUARD!(TscIOPin::Group8Io3) + }; + (G8IO4Pin) => { + TSC_V3_GUARD!(TscIOPin::Group8Io4) + }; +} + +macro_rules! impl_set_io { + ($method:ident, $group:ident, $trait:ident, $index:expr) => { + #[doc = concat!("Create a new pin1 for ", stringify!($group), " TSC group instance.")] + pub fn $method( + &mut self, + pin: impl Peripheral

> + 'd, + ) -> TscIOPinWithRole<$group, Role> { + into_ref!(pin); + critical_section::with(|_| { + pin.set_low(); + pin.set_as_af(pin.af_num(), AfType::output(Role::output_type(), Speed::VeryHigh)); + let tsc_io_pin = trait_to_tsc_io_pin!($trait); + let new_pin = TscPin { + _pin: pin.map_into(), + role: Role::pin_type(), + tsc_io_pin, + phantom: PhantomData, + }; + *self.pin_group.pins_mut()[$index] = Some(new_pin); + TscIOPinWithRole { + pin: tsc_io_pin, + phantom: PhantomData, + } + }) + } + }; +} + +macro_rules! group_impl { + ($group:ident, $trait1:ident, $trait2:ident, $trait3:ident, $trait4:ident) => { + impl< + 'd, + T: Instance, + R1: tsc_pin_roles::Role, + R2: tsc_pin_roles::Role, + R3: tsc_pin_roles::Role, + R4: tsc_pin_roles::Role, + > PinGroupWithRoles<'d, T, $group, R1, R2, R3, R4> + { + impl_set_io!(set_io1, $group, $trait1, 0); + impl_set_io!(set_io2, $group, $trait2, 1); + impl_set_io!(set_io3, $group, $trait3, 2); + impl_set_io!(set_io4, $group, $trait4, 3); + } + }; +} + +group_impl!(G1, G1IO1Pin, G1IO2Pin, G1IO3Pin, G1IO4Pin); +group_impl!(G2, G2IO1Pin, G2IO2Pin, G2IO3Pin, G2IO4Pin); +group_impl!(G3, G3IO1Pin, G3IO2Pin, G3IO3Pin, G3IO4Pin); +group_impl!(G4, G4IO1Pin, G4IO2Pin, G4IO3Pin, G4IO4Pin); +group_impl!(G5, G5IO1Pin, G5IO2Pin, G5IO3Pin, G5IO4Pin); +group_impl!(G6, G6IO1Pin, G6IO2Pin, G6IO3Pin, G6IO4Pin); +#[cfg(any(tsc_v2, tsc_v3))] +group_impl!(G7, G7IO1Pin, G7IO2Pin, G7IO3Pin, G7IO4Pin); +#[cfg(tsc_v3)] +group_impl!(G8, G8IO1Pin, G8IO2Pin, G8IO3Pin, G8IO4Pin); + +/// Group 1 marker type. +#[derive(Clone, Copy, Debug)] +pub enum G1 {} +/// Group 2 marker type. +#[derive(Clone, Copy, Debug)] +pub enum G2 {} +/// Group 3 marker type. +#[derive(Clone, Copy, Debug)] +pub enum G3 {} +/// Group 4 marker type. +#[derive(Clone, Copy, Debug)] +pub enum G4 {} +/// Group 5 marker type. +#[derive(Clone, Copy, Debug)] +pub enum G5 {} +/// Group 6 marker type. +#[derive(Clone, Copy, Debug)] +pub enum G6 {} +/// Group 7 marker type. +#[derive(Clone, Copy, Debug)] +pub enum G7 {} +/// Group 8 marker type. +#[derive(Clone, Copy, Debug)] +pub enum G8 {} + +/// Represents the collection of pin groups for the Touch Sensing Controller (TSC). +/// +/// Each field corresponds to a specific group of TSC pins: +#[allow(missing_docs)] +pub struct PinGroups<'d, T: Instance> { + pub g1: Option>, + pub g2: Option>, + pub g3: Option>, + pub g4: Option>, + pub g5: Option>, + pub g6: Option>, + #[cfg(any(tsc_v2, tsc_v3))] + pub g7: Option>, + #[cfg(tsc_v3)] + pub g8: Option>, +} + +impl<'d, T: Instance> PinGroups<'d, T> { + pub(super) fn check(&self) -> Result<(), GroupError> { + let mut shield_count = 0; + + // Helper function to check a single group + fn check_group( + group: &Option>, + shield_count: &mut u32, + ) -> Result<(), GroupError> { + if let Some(group) = group { + group.check_group()?; + if group.contains_exactly_one_shield_pin() { + *shield_count += 1; + if *shield_count > 1 { + return Err(GroupError::MultipleShields); + } + } + } + Ok(()) + } + + // Check each group + check_group(&self.g1, &mut shield_count)?; + check_group(&self.g2, &mut shield_count)?; + check_group(&self.g3, &mut shield_count)?; + check_group(&self.g4, &mut shield_count)?; + check_group(&self.g5, &mut shield_count)?; + check_group(&self.g6, &mut shield_count)?; + #[cfg(any(tsc_v2, tsc_v3))] + check_group(&self.g7, &mut shield_count)?; + #[cfg(tsc_v3)] + check_group(&self.g8, &mut shield_count)?; + + Ok(()) + } + + pub(super) fn make_channel_ios_mask(&self) -> u32 { + #[allow(unused_mut)] + let mut mask = self.g1.as_ref().map_or(0, |g| g.make_channel_ios_mask()) + | self.g2.as_ref().map_or(0, |g| g.make_channel_ios_mask()) + | self.g3.as_ref().map_or(0, |g| g.make_channel_ios_mask()) + | self.g4.as_ref().map_or(0, |g| g.make_channel_ios_mask()) + | self.g5.as_ref().map_or(0, |g| g.make_channel_ios_mask()) + | self.g6.as_ref().map_or(0, |g| g.make_channel_ios_mask()); + #[cfg(any(tsc_v2, tsc_v3))] + { + mask |= self.g7.as_ref().map_or(0, |g| g.make_channel_ios_mask()); + } + #[cfg(tsc_v3)] + { + mask |= self.g8.as_ref().map_or(0, |g| g.make_channel_ios_mask()); + } + mask + } + + pub(super) fn make_shield_ios_mask(&self) -> u32 { + #[allow(unused_mut)] + let mut mask = self.g1.as_ref().map_or(0, |g| g.make_shield_ios_mask()) + | self.g2.as_ref().map_or(0, |g| g.make_shield_ios_mask()) + | self.g3.as_ref().map_or(0, |g| g.make_shield_ios_mask()) + | self.g4.as_ref().map_or(0, |g| g.make_shield_ios_mask()) + | self.g5.as_ref().map_or(0, |g| g.make_shield_ios_mask()) + | self.g6.as_ref().map_or(0, |g| g.make_shield_ios_mask()); + #[cfg(any(tsc_v2, tsc_v3))] + { + mask |= self.g7.as_ref().map_or(0, |g| g.make_shield_ios_mask()); + } + #[cfg(tsc_v3)] + { + mask |= self.g8.as_ref().map_or(0, |g| g.make_shield_ios_mask()); + } + mask + } + + pub(super) fn make_sample_ios_mask(&self) -> u32 { + #[allow(unused_mut)] + let mut mask = self.g1.as_ref().map_or(0, |g| g.make_sample_ios_mask()) + | self.g2.as_ref().map_or(0, |g| g.make_sample_ios_mask()) + | self.g3.as_ref().map_or(0, |g| g.make_sample_ios_mask()) + | self.g4.as_ref().map_or(0, |g| g.make_sample_ios_mask()) + | self.g5.as_ref().map_or(0, |g| g.make_sample_ios_mask()) + | self.g6.as_ref().map_or(0, |g| g.make_sample_ios_mask()); + #[cfg(any(tsc_v2, tsc_v3))] + { + mask |= self.g7.as_ref().map_or(0, |g| g.make_sample_ios_mask()); + } + #[cfg(tsc_v3)] + { + mask |= self.g8.as_ref().map_or(0, |g| g.make_sample_ios_mask()); + } + mask + } +} + +impl<'d, T: Instance> Default for PinGroups<'d, T> { + fn default() -> Self { + Self { + g1: None, + g2: None, + g3: None, + g4: None, + g5: None, + g6: None, + #[cfg(any(tsc_v2, tsc_v3))] + g7: None, + #[cfg(tsc_v3)] + g8: None, + } + } +} + +pin_trait!(G1IO1Pin, Instance); +pin_trait!(G1IO2Pin, Instance); +pin_trait!(G1IO3Pin, Instance); +pin_trait!(G1IO4Pin, Instance); + +pin_trait!(G2IO1Pin, Instance); +pin_trait!(G2IO2Pin, Instance); +pin_trait!(G2IO3Pin, Instance); +pin_trait!(G2IO4Pin, Instance); + +pin_trait!(G3IO1Pin, Instance); +pin_trait!(G3IO2Pin, Instance); +pin_trait!(G3IO3Pin, Instance); +pin_trait!(G3IO4Pin, Instance); + +pin_trait!(G4IO1Pin, Instance); +pin_trait!(G4IO2Pin, Instance); +pin_trait!(G4IO3Pin, Instance); +pin_trait!(G4IO4Pin, Instance); + +pin_trait!(G5IO1Pin, Instance); +pin_trait!(G5IO2Pin, Instance); +pin_trait!(G5IO3Pin, Instance); +pin_trait!(G5IO4Pin, Instance); + +pin_trait!(G6IO1Pin, Instance); +pin_trait!(G6IO2Pin, Instance); +pin_trait!(G6IO3Pin, Instance); +pin_trait!(G6IO4Pin, Instance); + +pin_trait!(G7IO1Pin, Instance); +pin_trait!(G7IO2Pin, Instance); +pin_trait!(G7IO3Pin, Instance); +pin_trait!(G7IO4Pin, Instance); + +pin_trait!(G8IO1Pin, Instance); +pin_trait!(G8IO2Pin, Instance); +pin_trait!(G8IO3Pin, Instance); +pin_trait!(G8IO4Pin, Instance); diff --git a/embassy-stm32/src/tsc/tsc.rs b/embassy-stm32/src/tsc/tsc.rs new file mode 100644 index 000000000..58f9d9d2e --- /dev/null +++ b/embassy-stm32/src/tsc/tsc.rs @@ -0,0 +1,456 @@ +use core::future::poll_fn; +use core::marker::PhantomData; +use core::ops::BitOr; +use core::task::Poll; + +use embassy_hal_internal::{into_ref, PeripheralRef}; + +use super::acquisition_banks::*; +use super::config::*; +use super::errors::*; +use super::pin_groups::*; +use super::tsc_io_pin::*; +use super::types::*; +use super::{Instance, InterruptHandler, TSC_NUM_GROUPS}; +use crate::interrupt::typelevel::Interrupt; +use crate::mode::{Async, Blocking, Mode as PeriMode}; +use crate::{interrupt, rcc, Peripheral}; + +/// Internal structure holding masks for different types of TSC IOs. +/// +/// These masks are used during the initial configuration of the TSC peripheral +/// and for validating pin types during operations like creating acquisition banks. +struct TscIOMasks { + /// Mask representing all configured channel IOs + channel_ios: u32, + /// Mask representing all configured shield IOs + shield_ios: u32, + /// Mask representing all configured sampling IOs + sampling_ios: u32, +} + +/// TSC driver +pub struct Tsc<'d, T: Instance, K: PeriMode> { + _peri: PeripheralRef<'d, T>, + _pin_groups: PinGroups<'d, T>, + state: State, + config: Config, + masks: TscIOMasks, + _kind: PhantomData, +} + +impl<'d, T: Instance, K: PeriMode> Tsc<'d, T, K> { + // Helper method to check if a pin is a channel pin + fn is_channel_pin(&self, pin: TscIOPin) -> bool { + (self.masks.channel_ios & pin) != 0 + } + + /// Get the status of all groups involved in a TscAcquisitionBank + pub fn get_acquisition_bank_status(&self, bank: &TscAcquisitionBank) -> TscAcquisitionBankStatus { + let mut bank_status = TscAcquisitionBankStatus::default(); + for pin in bank.pins_iterator() { + let group = pin.group(); + let group_status = self.group_get_status(group); + let index: usize = group.into(); + bank_status.groups[index] = Some(group_status); + } + bank_status + } + + /// Get the values for all channels involved in a TscAcquisitionBank + pub fn get_acquisition_bank_values(&self, bank: &TscAcquisitionBank) -> TscAcquisitionBankReadings { + let mut bank_readings = TscAcquisitionBankReadings::default(); + for pin in bank.pins_iterator() { + let group = pin.group(); + let value = self.group_get_value(group); + let reading = TscChannelReading { + sensor_value: value, + tsc_pin: pin, + }; + let index: usize = group.into(); + bank_readings.groups[index] = Some(reading); + } + bank_readings + } + + /// Creates a new TSC acquisition bank from the provided pin configuration. + /// + /// This method creates a `TscAcquisitionBank` that can be used for efficient, + /// repeated TSC acquisitions. It automatically generates the appropriate mask + /// for the provided pins. + /// + /// # Note on TSC Hardware Limitation + /// + /// The TSC hardware can only read one channel pin from each TSC group per acquisition. + /// + /// # Arguments + /// * `acquisition_bank_pins` - The pin configuration for the acquisition bank. + /// + /// # Returns + /// A new `TscAcquisitionBank` instance. + /// + /// # Example + /// + /// ``` + /// let tsc = // ... initialize TSC + /// let tsc_sensor1: TscIOPinWithRole = ...; + /// let tsc_sensor2: TscIOPinWithRole = ...; + /// + /// let bank = tsc.create_acquisition_bank(TscAcquisitionBankPins { + /// g1_pin: Some(tsc_sensor1), + /// g2_pin: Some(tsc_sensor2), + /// ..Default::default() + /// }); + /// + /// // Use the bank for acquisitions + /// tsc.set_active_channels_bank(&bank); + /// tsc.start(); + /// // ... perform acquisition ... + /// ``` + pub fn create_acquisition_bank(&self, acquisition_bank_pins: TscAcquisitionBankPins) -> TscAcquisitionBank { + let bank_mask = acquisition_bank_pins.iter().fold(0u32, BitOr::bitor); + + TscAcquisitionBank { + pins: acquisition_bank_pins, + mask: bank_mask, + } + } + + fn make_channels_mask(&self, channels: Itt) -> Result + where + Itt: IntoIterator, + { + let mut group_mask = 0u32; + let mut channel_mask = 0u32; + + for channel in channels { + if !self.is_channel_pin(channel) { + return Err(AcquisitionBankError::InvalidChannelPin); + } + + let group = channel.group(); + let group_bit: u32 = 1 << Into::::into(group); + if group_mask & group_bit != 0 { + return Err(AcquisitionBankError::MultipleChannelsPerGroup); + } + + group_mask |= group_bit; + channel_mask |= channel; + } + + Ok(channel_mask) + } + + /// Sets the active channels for the next TSC acquisition. + /// + /// This is a low-level method that directly sets the channel mask. For most use cases, + /// consider using `set_active_channels_bank` with a `TscAcquisitionBank` instead, which + /// provides a higher-level interface and additional safety checks. + /// + /// This method configures which sensor channels will be read during the next + /// touch sensing acquisition cycle. It should be called before starting a new + /// acquisition with the start() method. + /// + /// # Arguments + /// * `mask` - A 32-bit mask where each bit represents a channel. Set bits indicate + /// active channels. + /// + /// # Note + /// Only one pin from each TSC group can be read for each acquisition. This method + /// does not perform checks to ensure this limitation is met. Incorrect masks may + /// lead to unexpected behavior. + /// + /// # Safety + /// This method doesn't perform extensive checks on the provided mask. Ensure that + /// the mask is valid and adheres to hardware limitations to avoid undefined behavior. + pub fn set_active_channels_mask(&mut self, mask: u32) { + T::regs().ioccr().write(|w| w.0 = mask | self.masks.shield_ios); + } + + /// Convenience method for setting active channels directly from a slice of TscIOPin. + /// This method performs safety checks but is less efficient for repeated use. + pub fn set_active_channels(&mut self, channels: &[TscIOPin]) -> Result<(), AcquisitionBankError> { + let mask = self.make_channels_mask(channels.iter().cloned())?; + self.set_active_channels_mask(mask); + Ok(()) + } + + /// Sets the active channels for the next TSC acquisition using a pre-configured acquisition bank. + /// + /// This method efficiently configures the TSC peripheral to read the channels specified + /// in the provided `TscAcquisitionBank`. It's the recommended way to set up + /// channel configurations for acquisition, especially when using the same set of channels repeatedly. + /// + /// # Arguments + /// + /// * `bank` - A reference to a `TscAcquisitionBank` containing the pre-configured + /// TSC channel mask. + /// + /// # Example + /// + /// ``` + /// let tsc_sensor1: TscIOPinWithRole = ...; + /// let tsc_sensor2: TscIOPinWithRole = ...; + /// let mut touch_controller: Tsc<'_, TSC, Async> = ...; + /// let bank = touch_controller.create_acquisition_bank(TscAcquisitionBankPins { + /// g1_pin: Some(tsc_sensor1), + /// g2_pin: Some(tsc_sensor2), + /// ..Default::default() + /// }); + /// + /// touch_controller.set_active_channels_bank(&bank); + /// touch_controller.start(); + /// // ... perform acquisition ... + /// ``` + /// + /// This method should be called before starting a new acquisition with the `start()` method. + pub fn set_active_channels_bank(&mut self, bank: &TscAcquisitionBank) { + self.set_active_channels_mask(bank.mask) + } + + fn extract_groups(io_mask: u32) -> u32 { + let mut groups: u32 = 0; + for idx in 0..TSC_NUM_GROUPS { + if io_mask & (0x0F << (idx * 4)) != 0 { + groups |= 1 << idx + } + } + groups + } + + fn new_inner( + peri: impl Peripheral

+ 'd, + pin_groups: PinGroups<'d, T>, + config: Config, + ) -> Result { + into_ref!(peri); + + pin_groups.check()?; + + let masks = TscIOMasks { + channel_ios: pin_groups.make_channel_ios_mask(), + shield_ios: pin_groups.make_shield_ios_mask(), + sampling_ios: pin_groups.make_sample_ios_mask(), + }; + + rcc::enable_and_reset::(); + + T::regs().cr().modify(|w| { + w.set_tsce(true); + w.set_ctph(config.ct_pulse_high_length.into()); + w.set_ctpl(config.ct_pulse_low_length.into()); + w.set_sse(config.spread_spectrum); + // Prevent invalid configuration for pulse generator prescaler + if config.ct_pulse_low_length == ChargeTransferPulseCycle::_1 + && (config.pulse_generator_prescaler == PGPrescalerDivider::_1 + || config.pulse_generator_prescaler == PGPrescalerDivider::_2) + { + w.set_pgpsc(PGPrescalerDivider::_4.into()); + } else if config.ct_pulse_low_length == ChargeTransferPulseCycle::_2 + && config.pulse_generator_prescaler == PGPrescalerDivider::_1 + { + w.set_pgpsc(PGPrescalerDivider::_2.into()); + } else { + w.set_pgpsc(config.pulse_generator_prescaler.into()); + } + w.set_ssd(config.spread_spectrum_deviation.into()); + w.set_sspsc(config.spread_spectrum_prescaler); + + w.set_mcv(config.max_count_value.into()); + w.set_syncpol(config.synchro_pin_polarity); + w.set_am(config.acquisition_mode); + }); + + // Set IO configuration + // Disable Schmitt trigger hysteresis on all used TSC IOs + T::regs() + .iohcr() + .write(|w| w.0 = !(masks.channel_ios | masks.shield_ios | masks.sampling_ios)); + + // Set channel and shield IOs + T::regs().ioccr().write(|w| w.0 = masks.channel_ios | masks.shield_ios); + + // Set sampling IOs + T::regs().ioscr().write(|w| w.0 = masks.sampling_ios); + + // Set the groups to be acquired + // Lower bits of `iogcsr` are for enabling groups, while the higher bits are for reading + // status of acquisiton for a group, see method `Tsc::group_get_status`. + T::regs() + .iogcsr() + .write(|w| w.0 = Self::extract_groups(masks.channel_ios)); + + // Disable interrupts + T::regs().ier().modify(|w| { + w.set_eoaie(false); + w.set_mceie(false); + }); + + // Clear flags + T::regs().icr().modify(|w| { + w.set_eoaic(true); + w.set_mceic(true); + }); + + unsafe { + T::Interrupt::enable(); + } + + Ok(Self { + _peri: peri, + _pin_groups: pin_groups, + state: State::Ready, + config, + masks, + _kind: PhantomData, + }) + } + + /// Start charge transfer acquisition + pub fn start(&mut self) { + self.state = State::Busy; + + // Disable interrupts + T::regs().ier().modify(|w| { + w.set_eoaie(false); + w.set_mceie(false); + }); + + // Clear flags + T::regs().icr().modify(|w| { + w.set_eoaic(true); + w.set_mceic(true); + }); + + // Set the touch sensing IOs not acquired to the default mode + T::regs().cr().modify(|w| { + w.set_iodef(self.config.io_default_mode); + }); + + // Start the acquisition + T::regs().cr().modify(|w| { + w.set_start(true); + }); + } + + /// Stop charge transfer acquisition + pub fn stop(&mut self) { + T::regs().cr().modify(|w| { + w.set_start(false); + }); + + // Set the touch sensing IOs in low power mode + T::regs().cr().modify(|w| { + w.set_iodef(false); + }); + + // Clear flags + T::regs().icr().modify(|w| { + w.set_eoaic(true); + w.set_mceic(true); + }); + + self.state = State::Ready; + } + + /// Get current state of acquisition + pub fn get_state(&mut self) -> State { + if self.state == State::Busy && T::regs().isr().read().eoaf() { + if T::regs().isr().read().mcef() { + self.state = State::Error + } else { + self.state = State::Ready + } + } + self.state + } + + /// Get the individual group status to check acquisition complete + pub fn group_get_status(&self, index: Group) -> GroupStatus { + // Status bits are set by hardware when the acquisition on the corresponding + // enabled analog IO group is complete, cleared when new acquisition is started + let status = match index { + Group::One => T::regs().iogcsr().read().g1s(), + Group::Two => T::regs().iogcsr().read().g2s(), + Group::Three => T::regs().iogcsr().read().g3s(), + Group::Four => T::regs().iogcsr().read().g4s(), + Group::Five => T::regs().iogcsr().read().g5s(), + Group::Six => T::regs().iogcsr().read().g6s(), + #[cfg(any(tsc_v2, tsc_v3))] + Group::Seven => T::regs().iogcsr().read().g7s(), + #[cfg(tsc_v3)] + Group::Eight => T::regs().iogcsr().read().g8s(), + }; + match status { + true => GroupStatus::Complete, + false => GroupStatus::Ongoing, + } + } + + /// Get the count for the acquisiton, valid once group status is set + pub fn group_get_value(&self, index: Group) -> u16 { + T::regs().iogcr(index.into()).read().cnt() + } + + /// Discharge the IOs for subsequent acquisition + pub fn discharge_io(&mut self, status: bool) { + // Set the touch sensing IOs in low power mode + T::regs().cr().modify(|w| { + w.set_iodef(!status); + }); + } +} + +impl<'d, T: Instance, K: PeriMode> Drop for Tsc<'d, T, K> { + fn drop(&mut self) { + rcc::disable::(); + } +} + +impl<'d, T: Instance> Tsc<'d, T, Async> { + /// Create a Tsc instance that can be awaited for completion + pub fn new_async( + peri: impl Peripheral

+ 'd, + pin_groups: PinGroups<'d, T>, + config: Config, + _irq: impl interrupt::typelevel::Binding> + 'd, + ) -> Result { + Self::new_inner(peri, pin_groups, config) + } + + /// Asyncronously wait for the end of an acquisition + pub async fn pend_for_acquisition(&mut self) { + poll_fn(|cx| match self.get_state() { + State::Busy => { + T::waker().register(cx.waker()); + T::regs().ier().write(|w| w.set_eoaie(true)); + if self.get_state() != State::Busy { + T::regs().ier().write(|w| w.set_eoaie(false)); + return Poll::Ready(()); + } + Poll::Pending + } + _ => { + T::regs().ier().write(|w| w.set_eoaie(false)); + Poll::Ready(()) + } + }) + .await; + } +} + +impl<'d, T: Instance> Tsc<'d, T, Blocking> { + /// Create a Tsc instance that must be polled for completion + pub fn new_blocking( + peri: impl Peripheral

+ 'd, + pin_groups: PinGroups<'d, T>, + config: Config, + ) -> Result { + Self::new_inner(peri, pin_groups, config) + } + + /// Wait for end of acquisition + pub fn poll_for_acquisition(&mut self) { + while self.get_state() == State::Busy {} + } +} diff --git a/embassy-stm32/src/tsc/enums.rs b/embassy-stm32/src/tsc/tsc_io_pin.rs similarity index 52% rename from embassy-stm32/src/tsc/enums.rs rename to embassy-stm32/src/tsc/tsc_io_pin.rs index 0d34a43ec..38b27d0b3 100644 --- a/embassy-stm32/src/tsc/enums.rs +++ b/embassy-stm32/src/tsc/tsc_io_pin.rs @@ -1,7 +1,13 @@ -use core::ops::BitOr; +use core::marker::PhantomData; +use core::ops::{BitAnd, BitOr, BitOrAssign}; + +use super::tsc_pin_roles; +use super::types::Group; /// Pin defines #[allow(missing_docs)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[derive(PartialEq, Clone, Copy, Debug)] pub enum TscIOPin { Group1Io1, Group1Io2, @@ -45,6 +51,53 @@ pub enum TscIOPin { Group8Io4, } +/// Represents a TSC I/O pin with associated group and role information. +/// +/// This type combines a `TscIOPin` with phantom type parameters to statically +/// encode the pin's group and role. This allows for type-safe operations +/// on TSC pins within their specific contexts. +/// +/// - `Group`: A type parameter representing the TSC group (e.g., `G1`, `G2`). +/// - `Role`: A type parameter representing the pin's role (e.g., `Channel`, `Sample`). +#[derive(Clone, Copy, Debug)] +pub struct TscIOPinWithRole { + /// The underlying TSC I/O pin. + pub pin: TscIOPin, + pub(super) phantom: PhantomData<(Group, Role)>, +} + +impl TscIOPinWithRole { + pub(super) fn get_pin(wrapped_pin: TscIOPinWithRole) -> TscIOPin { + wrapped_pin.pin + } +} + +impl TscIOPin { + /// Maps this TscIOPin to the Group it belongs to. + /// + /// This method provides a convenient way to determine which Group + /// a specific TSC I/O pin is associated with. + pub const fn group(&self) -> Group { + match self { + TscIOPin::Group1Io1 | TscIOPin::Group1Io2 | TscIOPin::Group1Io3 | TscIOPin::Group1Io4 => Group::One, + TscIOPin::Group2Io1 | TscIOPin::Group2Io2 | TscIOPin::Group2Io3 | TscIOPin::Group2Io4 => Group::Two, + TscIOPin::Group3Io1 | TscIOPin::Group3Io2 | TscIOPin::Group3Io3 | TscIOPin::Group3Io4 => Group::Three, + TscIOPin::Group4Io1 | TscIOPin::Group4Io2 | TscIOPin::Group4Io3 | TscIOPin::Group4Io4 => Group::Four, + TscIOPin::Group5Io1 | TscIOPin::Group5Io2 | TscIOPin::Group5Io3 | TscIOPin::Group5Io4 => Group::Five, + TscIOPin::Group6Io1 | TscIOPin::Group6Io2 | TscIOPin::Group6Io3 | TscIOPin::Group6Io4 => Group::Six, + #[cfg(any(tsc_v2, tsc_v3))] + TscIOPin::Group7Io1 | TscIOPin::Group7Io2 | TscIOPin::Group7Io3 | TscIOPin::Group7Io4 => Group::Seven, + #[cfg(tsc_v3)] + TscIOPin::Group8Io1 | TscIOPin::Group8Io2 | TscIOPin::Group8Io3 | TscIOPin::Group8Io4 => Group::Eight, + } + } + + /// Returns the `Group` associated with the given `TscIOPin`. + pub fn get_group(pin: TscIOPin) -> Group { + pin.group() + } +} + impl BitOr for u32 { type Output = u32; fn bitor(self, rhs: TscIOPin) -> Self::Output { @@ -70,8 +123,31 @@ impl BitOr for TscIOPin { } } -impl Into for TscIOPin { - fn into(self) -> u32 { +impl BitOrAssign for u32 { + fn bitor_assign(&mut self, rhs: TscIOPin) { + let rhs: u32 = rhs.into(); + *self |= rhs; + } +} + +impl BitAnd for u32 { + type Output = u32; + fn bitand(self, rhs: TscIOPin) -> Self::Output { + let rhs: u32 = rhs.into(); + self & rhs + } +} + +impl BitAnd for TscIOPin { + type Output = u32; + fn bitand(self, rhs: u32) -> Self::Output { + let val: u32 = self.into(); + val & rhs + } +} + +impl TscIOPin { + const fn to_u32(self) -> u32 { match self { TscIOPin::Group1Io1 => 0x00000001, TscIOPin::Group1Io2 => 0x00000002, @@ -117,122 +193,8 @@ impl Into for TscIOPin { } } -/// Spread Spectrum Deviation -#[derive(Copy, Clone)] -pub struct SSDeviation(u8); -impl SSDeviation { - /// Create new deviation value, acceptable inputs are 1-128 - pub fn new(val: u8) -> Result { - if val == 0 || val > 128 { - return Err(()); - } - Ok(Self(val - 1)) - } -} - -impl Into for SSDeviation { - fn into(self) -> u8 { - self.0 - } -} - -/// Charge transfer pulse cycles -#[allow(missing_docs)] -#[derive(Copy, Clone, PartialEq)] -pub enum ChargeTransferPulseCycle { - _1, - _2, - _3, - _4, - _5, - _6, - _7, - _8, - _9, - _10, - _11, - _12, - _13, - _14, - _15, - _16, -} - -impl Into for ChargeTransferPulseCycle { - fn into(self) -> u8 { - match self { - ChargeTransferPulseCycle::_1 => 0, - ChargeTransferPulseCycle::_2 => 1, - ChargeTransferPulseCycle::_3 => 2, - ChargeTransferPulseCycle::_4 => 3, - ChargeTransferPulseCycle::_5 => 4, - ChargeTransferPulseCycle::_6 => 5, - ChargeTransferPulseCycle::_7 => 6, - ChargeTransferPulseCycle::_8 => 7, - ChargeTransferPulseCycle::_9 => 8, - ChargeTransferPulseCycle::_10 => 9, - ChargeTransferPulseCycle::_11 => 10, - ChargeTransferPulseCycle::_12 => 11, - ChargeTransferPulseCycle::_13 => 12, - ChargeTransferPulseCycle::_14 => 13, - ChargeTransferPulseCycle::_15 => 14, - ChargeTransferPulseCycle::_16 => 15, - } - } -} - -/// Prescaler divider -#[allow(missing_docs)] -#[derive(Copy, Clone, PartialEq)] -pub enum PGPrescalerDivider { - _1, - _2, - _4, - _8, - _16, - _32, - _64, - _128, -} - -impl Into for PGPrescalerDivider { - fn into(self) -> u8 { - match self { - PGPrescalerDivider::_1 => 0, - PGPrescalerDivider::_2 => 1, - PGPrescalerDivider::_4 => 2, - PGPrescalerDivider::_8 => 3, - PGPrescalerDivider::_16 => 4, - PGPrescalerDivider::_32 => 5, - PGPrescalerDivider::_64 => 6, - PGPrescalerDivider::_128 => 7, - } - } -} - -/// Max count -#[allow(missing_docs)] -#[derive(Copy, Clone)] -pub enum MaxCount { - _255, - _511, - _1023, - _2047, - _4095, - _8191, - _16383, -} - -impl Into for MaxCount { - fn into(self) -> u8 { - match self { - MaxCount::_255 => 0, - MaxCount::_511 => 1, - MaxCount::_1023 => 2, - MaxCount::_2047 => 3, - MaxCount::_4095 => 4, - MaxCount::_8191 => 5, - MaxCount::_16383 => 6, - } +impl Into for TscIOPin { + fn into(self) -> u32 { + self.to_u32() } } diff --git a/embassy-stm32/src/tsc/types.rs b/embassy-stm32/src/tsc/types.rs new file mode 100644 index 000000000..0e8fa7f28 --- /dev/null +++ b/embassy-stm32/src/tsc/types.rs @@ -0,0 +1,93 @@ +/// Peripheral state +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[derive(PartialEq, Clone, Copy)] +pub enum State { + /// Peripheral is being setup or reconfigured + Reset, + /// Ready to start acquisition + Ready, + /// In process of sensor acquisition + Busy, + /// Error occured during acquisition + Error, +} + +/// Individual group status checked after acquisition reported as complete +/// For groups with multiple channel pins, may take longer because acquisitions +/// are done sequentially. Check this status before pulling count for each +/// sampled channel +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[derive(PartialEq, Clone, Copy)] +pub enum GroupStatus { + /// Acquisition for channel still in progress + Ongoing, + /// Acquisition either not started or complete + Complete, +} + +/// Group identifier used to interrogate status +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[allow(missing_docs)] +#[derive(PartialEq, Clone, Copy)] +pub enum Group { + One, + Two, + Three, + Four, + Five, + Six, + #[cfg(any(tsc_v2, tsc_v3))] + Seven, + #[cfg(tsc_v3)] + Eight, +} + +impl Into for Group { + fn into(self) -> usize { + match self { + Group::One => 0, + Group::Two => 1, + Group::Three => 2, + Group::Four => 3, + Group::Five => 4, + Group::Six => 5, + #[cfg(any(tsc_v2, tsc_v3))] + Group::Seven => 6, + #[cfg(tsc_v3)] + Group::Eight => 7, + } + } +} + +/// Error returned when attempting to create a Group from an invalid numeric value. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct InvalidGroupError { + invalid_value: usize, +} + +impl InvalidGroupError { + #[allow(missing_docs)] + pub fn new(value: usize) -> Self { + Self { invalid_value: value } + } +} + +impl TryFrom for Group { + type Error = InvalidGroupError; + + fn try_from(value: usize) -> Result { + match value { + 0 => Ok(Group::One), + 1 => Ok(Group::Two), + 2 => Ok(Group::Three), + 3 => Ok(Group::Four), + 4 => Ok(Group::Five), + 5 => Ok(Group::Six), + #[cfg(any(tsc_v2, tsc_v3))] + 6 => Ok(Group::Two), + #[cfg(tsc_v3)] + 7 => Ok(Group::Two), + n => Err(InvalidGroupError::new(n)), + } + } +} diff --git a/examples/stm32f3/README.md b/examples/stm32f3/README.md new file mode 100644 index 000000000..0a85c4858 --- /dev/null +++ b/examples/stm32f3/README.md @@ -0,0 +1,24 @@ +# Examples for STM32F3 family +Run individual examples with +``` +cargo run --bin +``` +for example +``` +cargo run --bin blinky +``` + +## Checklist before running examples +You might need to adjust `.cargo/config.toml`, `Cargo.toml` and possibly update pin numbers or peripherals to match the specific MCU or board you are using. + +* [ ] Update .cargo/config.toml with the correct probe-rs command to use your specific MCU. For example for F303ZE it should be `probe-rs run --chip STM32F303ZETx`. (use `probe-rs chip list` to find your chip) +* [ ] Update Cargo.toml to have the correct `embassy-stm32` feature. For example for F303ZE it should be `stm32f303ze`. Look in the `Cargo.toml` file of the `embassy-stm32` project to find the correct feature flag for your chip. +* [ ] If your board has a special clock or power configuration, make sure that it is set up appropriately. +* [ ] If your board has different pin mapping, update any pin numbers or peripherals in the given example code to match your schematic + +If you are unsure, please drop by the Embassy Matrix chat for support, and let us know: + +* Which example you are trying to run +* Which chip and board you are using + +Embassy Chat: https://matrix.to/#/#embassy-rs:matrix.org diff --git a/examples/stm32f3/src/bin/blocking-tsc.rs b/examples/stm32f3/src/bin/blocking-tsc.rs deleted file mode 100644 index 5c8dac94f..000000000 --- a/examples/stm32f3/src/bin/blocking-tsc.rs +++ /dev/null @@ -1,98 +0,0 @@ -// Example of polling TSC (Touch Sensing Controller) that lights an LED when touch is detected. -// -// Suggested physical setup on STM32F303ZE Nucleo board: -// - Connect a 1000pF capacitor between pin A0 and GND. This is your sampling capacitor. -// - Connect one end of a 1K resistor to pin A1 and leave the other end loose. -// The loose end will act as touch sensor which will register your touch. -// -// Troubleshooting the setup: -// - If no touch seems to be registered, then try to disconnect the sampling capacitor from GND momentarily, -// now the led should light up. Next try using a different value for the sampling capacitor. -// Also experiment with increasing the values for `ct_pulse_high_length`, `ct_pulse_low_length`, `pulse_generator_prescaler`, `max_count_value` and `discharge_delay`. -// -// All configuration values and sampling capacitor value have been determined experimentally. -// Suitable configuration and discharge delay values are highly dependent on the value of the sample capacitor. For example, a shorter discharge delay can be used with smaller capacitor values. -// -#![no_std] -#![no_main] - -use defmt::*; -use embassy_stm32::gpio::{Level, Output, Speed}; -use embassy_stm32::tsc::{self, *}; -use embassy_time::Timer; -use {defmt_rtt as _, panic_probe as _}; - -/// This example is written for the nucleo-stm32f303ze, with a stm32f303ze chip. -/// -/// Make sure you check/update the following (whether you use the F303ZE or another board): -/// -/// * [ ] Update .cargo/config.toml with the correct `probe-rs run --chip STM32F303ZETx`chip name. -/// * [ ] Update Cargo.toml to have the correct `embassy-stm32` feature, for F303ZE it should be `stm32f303ze`. -/// * [ ] If your board has a special clock or power configuration, make sure that it is -/// set up appropriately. -/// * [ ] If your board has different pin mapping, update any pin numbers or peripherals -/// to match your schematic -/// -/// If you are unsure, please drop by the Embassy Matrix chat for support, and let us know: -/// -/// * Which example you are trying to run -/// * Which chip and board you are using -/// -/// Embassy Chat: https://matrix.to/#/#embassy-rs:matrix.org -#[embassy_executor::main] -async fn main(_spawner: embassy_executor::Spawner) { - let device_config = embassy_stm32::Config::default(); - let context = embassy_stm32::init(device_config); - - let tsc_conf = Config { - ct_pulse_high_length: ChargeTransferPulseCycle::_8, - ct_pulse_low_length: ChargeTransferPulseCycle::_8, - spread_spectrum: false, - spread_spectrum_deviation: SSDeviation::new(2).unwrap(), - spread_spectrum_prescaler: false, - pulse_generator_prescaler: PGPrescalerDivider::_32, - max_count_value: MaxCount::_255, - io_default_mode: false, - synchro_pin_polarity: false, - acquisition_mode: false, - max_count_interrupt: false, - channel_ios: TscIOPin::Group1Io1.into(), - shield_ios: 0, // no shield - sampling_ios: TscIOPin::Group1Io2.into(), - }; - - let mut g1: PinGroup = PinGroup::new(); - g1.set_io1(context.PA0, PinType::Sample); - g1.set_io2(context.PA1, PinType::Channel); - - let mut touch_controller = tsc::Tsc::new_blocking(context.TSC, Some(g1), None, None, None, None, None, tsc_conf); - - // LED2 on the STM32F303ZE nucleo-board - let mut led = Output::new(context.PB7, Level::High, Speed::Low); - - // smaller sample capacitor discharge faster and can be used with shorter delay. - let discharge_delay = 5; // ms - - // the interval at which the loop polls for new touch sensor values - let polling_interval = 100; // ms - - info!("polling for touch"); - loop { - touch_controller.start(); - touch_controller.poll_for_acquisition(); - touch_controller.discharge_io(true); - Timer::after_millis(discharge_delay).await; - - let grp1_status = touch_controller.group_get_status(Group::One); - match grp1_status { - GroupStatus::Complete => { - let group_one_val = touch_controller.group_get_value(Group::One); - info!("{}", group_one_val); - led.set_high(); - } - GroupStatus::Ongoing => led.set_low(), - } - - Timer::after_millis(polling_interval).await; - } -} diff --git a/examples/stm32f3/src/bin/tsc_blocking.rs b/examples/stm32f3/src/bin/tsc_blocking.rs new file mode 100644 index 000000000..fa7f718e6 --- /dev/null +++ b/examples/stm32f3/src/bin/tsc_blocking.rs @@ -0,0 +1,138 @@ +// Example of blocking TSC (Touch Sensing Controller) that lights an LED when touch is detected. +// +// This example demonstrates: +// 1. Configuring a single TSC channel pin +// 2. Using the blocking TSC interface with polling +// 3. Waiting for acquisition completion using `poll_for_acquisition` +// 4. Reading touch values and controlling an LED based on the results +// +// Suggested physical setup on STM32F303ZE Nucleo board: +// - Connect a 1000pF capacitor between pin PA10 and GND. This is your sampling capacitor. +// - Connect one end of a 1K resistor to pin PA9 and leave the other end loose. +// The loose end will act as the touch sensor which will register your touch. +// +// The example uses two pins from Group 4 of the TSC: +// - PA10 as the sampling capacitor, TSC group 4 IO2 (D68 on the STM32F303ZE nucleo-board) +// - PA9 as the channel pin, TSC group 4 IO1 (D69 on the STM32F303ZE nucleo-board) +// +// The program continuously reads the touch sensor value: +// - It starts acquisition, waits for completion using `poll_for_acquisition`, and reads the value. +// - The LED is turned on when touch is detected (sensor value < 40). +// - Touch values are logged to the console. +// +// Troubleshooting: +// - If touch is not detected, try adjusting the SENSOR_THRESHOLD value. +// - Experiment with different values for ct_pulse_high_length, ct_pulse_low_length, +// pulse_generator_prescaler, max_count_value, and discharge_delay to optimize sensitivity. +// +// Note: Configuration values and sampling capacitor value have been determined experimentally. +// Optimal values may vary based on your specific hardware setup. +// Pins have been chosen for their convenient locations on the STM32F303ZE board. Refer to the +// official relevant STM32 datasheets and user nucleo-board user manuals to find suitable +// alternative pins. + +#![no_std] +#![no_main] + +use defmt::*; +use embassy_stm32::gpio::{Level, Output, Speed}; +use embassy_stm32::tsc::{self, *}; +use embassy_stm32::{mode, peripherals}; +use embassy_time::Timer; +use {defmt_rtt as _, panic_probe as _}; + +const SENSOR_THRESHOLD: u16 = 25; // Adjust this value based on your setup + +#[embassy_executor::main] +async fn main(_spawner: embassy_executor::Spawner) { + let device_config = embassy_stm32::Config::default(); + let context = embassy_stm32::init(device_config); + + let tsc_conf = Config { + ct_pulse_high_length: ChargeTransferPulseCycle::_4, + ct_pulse_low_length: ChargeTransferPulseCycle::_4, + spread_spectrum: false, + spread_spectrum_deviation: SSDeviation::new(2).unwrap(), + spread_spectrum_prescaler: false, + pulse_generator_prescaler: PGPrescalerDivider::_16, + max_count_value: MaxCount::_255, + io_default_mode: false, + synchro_pin_polarity: false, + acquisition_mode: false, + max_count_interrupt: false, + }; + + let mut g: PinGroupWithRoles = PinGroupWithRoles::default(); + // D68 on the STM32F303ZE nucleo-board + g.set_io2::(context.PA10); + // D69 on the STM32F303ZE nucleo-board + let tsc_sensor = g.set_io1::(context.PA9); + + let pin_groups: PinGroups = PinGroups { + g4: Some(g.pin_group), + ..Default::default() + }; + + let mut touch_controller = tsc::Tsc::new_blocking(context.TSC, pin_groups, tsc_conf).unwrap(); + + // Check if TSC is ready + if touch_controller.get_state() != State::Ready { + crate::panic!("TSC not ready!"); + } + info!("TSC initialized successfully"); + + // LED2 on the STM32F303ZE nucleo-board + let mut led = Output::new(context.PB7, Level::High, Speed::Low); + + // smaller sample capacitor discharge faster and can be used with shorter delay. + let discharge_delay = 5; // ms + + // the interval at which the loop polls for new touch sensor values + let polling_interval = 100; // ms + + info!("polling for touch"); + loop { + touch_controller.set_active_channels_mask(tsc_sensor.pin.into()); + touch_controller.start(); + touch_controller.poll_for_acquisition(); + touch_controller.discharge_io(true); + Timer::after_millis(discharge_delay).await; + + match read_touch_value(&mut touch_controller, tsc_sensor.pin).await { + Some(v) => { + info!("sensor value {}", v); + if v < SENSOR_THRESHOLD { + led.set_high(); + } else { + led.set_low(); + } + } + None => led.set_low(), + } + + Timer::after_millis(polling_interval).await; + } +} + +const MAX_GROUP_STATUS_READ_ATTEMPTS: usize = 10; + +// attempt to read group status and delay when still ongoing +async fn read_touch_value( + touch_controller: &mut tsc::Tsc<'_, peripherals::TSC, mode::Blocking>, + sensor_pin: TscIOPin, +) -> Option { + for _ in 0..MAX_GROUP_STATUS_READ_ATTEMPTS { + match touch_controller.group_get_status(sensor_pin.group()) { + GroupStatus::Complete => { + return Some(touch_controller.group_get_value(sensor_pin.group())); + } + GroupStatus::Ongoing => { + // if you end up here a lot, then you prob need to increase discharge_delay + // or consider changing the code to adjust the discharge_delay dynamically + info!("Acquisition still ongoing"); + Timer::after_millis(1).await; + } + } + } + None +} diff --git a/examples/stm32l0/.cargo/config.toml b/examples/stm32l0/.cargo/config.toml index b050334b2..fed9cf9ce 100644 --- a/examples/stm32l0/.cargo/config.toml +++ b/examples/stm32l0/.cargo/config.toml @@ -1,6 +1,6 @@ [target.'cfg(all(target_arch = "arm", target_os = "none"))'] # replace your chip as listed in `probe-rs chip list` -runner = "probe-rs run --chip STM32L053R8Tx" +runner = "probe-rs run --chip STM32L073RZTx" [build] target = "thumbv6m-none-eabi" diff --git a/examples/stm32l0/Cargo.toml b/examples/stm32l0/Cargo.toml index 95e215b6f..9d234804a 100644 --- a/examples/stm32l0/Cargo.toml +++ b/examples/stm32l0/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32l072cz to your chip name, if necessary. -embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32l072cz", "unstable-pac", "time-driver-any", "exti", "memory-x"] } +embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32l073rz", "unstable-pac", "time-driver-any", "exti", "memory-x"] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } diff --git a/examples/stm32l0/README.md b/examples/stm32l0/README.md new file mode 100644 index 000000000..82d222027 --- /dev/null +++ b/examples/stm32l0/README.md @@ -0,0 +1,24 @@ +# Examples for STM32L0 family +Run individual examples with +``` +cargo run --bin +``` +for example +``` +cargo run --bin blinky +``` + +## Checklist before running examples +You might need to adjust `.cargo/config.toml`, `Cargo.toml` and possibly update pin numbers or peripherals to match the specific MCU or board you are using. + +* [ ] Update .cargo/config.toml with the correct probe-rs command to use your specific MCU. For example for L073RZ it should be `probe-rs run --chip STM32L073RZTx`. (use `probe-rs chip list` to find your chip) +* [ ] Update Cargo.toml to have the correct `embassy-stm32` feature. For example for L073RZ it should be `stm32l073rz`. Look in the `Cargo.toml` file of the `embassy-stm32` project to find the correct feature flag for your chip. +* [ ] If your board has a special clock or power configuration, make sure that it is set up appropriately. +* [ ] If your board has different pin mapping, update any pin numbers or peripherals in the given example code to match your schematic + +If you are unsure, please drop by the Embassy Matrix chat for support, and let us know: + +* Which example you are trying to run +* Which chip and board you are using + +Embassy Chat: https://matrix.to/#/#embassy-rs:matrix.org diff --git a/examples/stm32l0/src/bin/async-tsc.rs b/examples/stm32l0/src/bin/async-tsc.rs deleted file mode 100644 index c40b86af9..000000000 --- a/examples/stm32l0/src/bin/async-tsc.rs +++ /dev/null @@ -1,122 +0,0 @@ -// Example of async TSC (Touch Sensing Controller) that lights an LED when touch is detected. -// -// Suggested physical setup on STM32L073RZ Nucleo board: -// - Connect a 1000pF capacitor between pin A0 and GND. This is your sampling capacitor. -// - Connect one end of a 1K resistor to pin A1 and leave the other end loose. -// The loose end will act as touch sensor which will register your touch. -// -// Troubleshooting the setup: -// - If no touch seems to be registered, then try to disconnect the sampling capacitor from GND momentarily, -// now the led should light up. Next try using a different value for the sampling capacitor. -// Also experiment with increasing the values for `ct_pulse_high_length`, `ct_pulse_low_length`, `pulse_generator_prescaler`, `max_count_value` and `discharge_delay`. -// -// All configuration values and sampling capacitor value have been determined experimentally. -// Suitable configuration and discharge delay values are highly dependent on the value of the sample capacitor. For example, a shorter discharge delay can be used with smaller capacitor values. -// -#![no_std] -#![no_main] - -use defmt::*; -use embassy_stm32::bind_interrupts; -use embassy_stm32::gpio::{Level, Output, Speed}; -use embassy_stm32::tsc::{self, *}; -use embassy_time::Timer; -use {defmt_rtt as _, panic_probe as _}; - -bind_interrupts!(struct Irqs { - TSC => InterruptHandler; -}); - -#[cortex_m_rt::exception] -unsafe fn HardFault(_: &cortex_m_rt::ExceptionFrame) -> ! { - cortex_m::peripheral::SCB::sys_reset(); -} - -/// This example is written for the nucleo-stm32l073rz, with a stm32l073rz chip. -/// -/// Make sure you check/update the following (whether you use the L073RZ or another board): -/// -/// * [ ] Update .cargo/config.toml with the correct `probe-rs run --chip STM32L073RZTx`chip name. -/// * [ ] Update Cargo.toml to have the correct `embassy-stm32` feature, for L073RZ it should be `stm32l073rz`. -/// * [ ] If your board has a special clock or power configuration, make sure that it is -/// set up appropriately. -/// * [ ] If your board has different pin mapping, update any pin numbers or peripherals -/// to match your schematic -/// -/// If you are unsure, please drop by the Embassy Matrix chat for support, and let us know: -/// -/// * Which example you are trying to run -/// * Which chip and board you are using -/// -/// Embassy Chat: https://matrix.to/#/#embassy-rs:matrix.org -#[embassy_executor::main] -async fn main(_spawner: embassy_executor::Spawner) { - let device_config = embassy_stm32::Config::default(); - let context = embassy_stm32::init(device_config); - - let config = tsc::Config { - ct_pulse_high_length: ChargeTransferPulseCycle::_4, - ct_pulse_low_length: ChargeTransferPulseCycle::_4, - spread_spectrum: false, - spread_spectrum_deviation: SSDeviation::new(2).unwrap(), - spread_spectrum_prescaler: false, - pulse_generator_prescaler: PGPrescalerDivider::_16, - max_count_value: MaxCount::_255, - io_default_mode: false, - synchro_pin_polarity: false, - acquisition_mode: false, - max_count_interrupt: false, - channel_ios: TscIOPin::Group1Io1.into(), - shield_ios: 0, // no shield - sampling_ios: TscIOPin::Group1Io2.into(), - }; - - let mut g1: PinGroup = PinGroup::new(); - g1.set_io1(context.PA0, PinType::Sample); - g1.set_io2(context.PA1, PinType::Channel); - - let mut touch_controller = tsc::Tsc::new_async( - context.TSC, - Some(g1), - None, - None, - None, - None, - None, - None, - None, - config, - Irqs, - ); - - // Check if TSC is ready - if touch_controller.get_state() != State::Ready { - info!("TSC not ready!"); - loop {} // Halt execution - } - info!("TSC initialized successfully"); - - // LED2 on the STM32L073RZ nucleo-board (PA5) - let mut led = Output::new(context.PA5, Level::High, Speed::Low); - - // smaller sample capacitor discharge faster and can be used with shorter delay. - let discharge_delay = 5; // ms - - info!("Starting touch_controller interface"); - loop { - touch_controller.start(); - touch_controller.pend_for_acquisition().await; - touch_controller.discharge_io(true); - Timer::after_millis(discharge_delay).await; - - let grp1_status = touch_controller.group_get_status(Group::One); - match grp1_status { - GroupStatus::Complete => { - let group_one_val = touch_controller.group_get_value(Group::One); - info!("{}", group_one_val); - led.set_high(); - } - GroupStatus::Ongoing => led.set_low(), - } - } -} diff --git a/examples/stm32l0/src/bin/blocking-tsc.rs b/examples/stm32l0/src/bin/blocking-tsc.rs deleted file mode 100644 index 7e4f40946..000000000 --- a/examples/stm32l0/src/bin/blocking-tsc.rs +++ /dev/null @@ -1,116 +0,0 @@ -// Example of polling TSC (Touch Sensing Controller) that lights an LED when touch is detected. -// -// Suggested physical setup on STM32L073RZ Nucleo board: -// - Connect a 1000pF capacitor between pin A0 and GND. This is your sampling capacitor. -// - Connect one end of a 1K resistor to pin A1 and leave the other end loose. -// The loose end will act as touch sensor which will register your touch. -// -// Troubleshooting the setup: -// - If no touch seems to be registered, then try to disconnect the sampling capacitor from GND momentarily, -// now the led should light up. Next try using a different value for the sampling capacitor. -// Also experiment with increasing the values for `ct_pulse_high_length`, `ct_pulse_low_length`, `pulse_generator_prescaler`, `max_count_value` and `discharge_delay`. -// -// All configuration values and sampling capacitor value have been determined experimentally. -// Suitable configuration and discharge delay values are highly dependent on the value of the sample capacitor. For example, a shorter discharge delay can be used with smaller capacitor values. -// -#![no_std] -#![no_main] - -use defmt::*; -use embassy_stm32::gpio::{Level, Output, Speed}; -use embassy_stm32::tsc::{self, *}; -use embassy_time::Timer; -use {defmt_rtt as _, panic_probe as _}; - -/// This example is written for the nucleo-stm32l073rz, with a stm32l073rz chip. -/// -/// Make sure you check/update the following (whether you use the L073RZ or another board): -/// -/// * [ ] Update .cargo/config.toml with the correct `probe-rs run --chip STM32L073RZTx`chip name. -/// * [ ] Update Cargo.toml to have the correct `embassy-stm32` feature, for L073RZ it should be `stm32l073rz`. -/// * [ ] If your board has a special clock or power configuration, make sure that it is -/// set up appropriately. -/// * [ ] If your board has different pin mapping, update any pin numbers or peripherals -/// to match your schematic -/// -/// If you are unsure, please drop by the Embassy Matrix chat for support, and let us know: -/// -/// * Which example you are trying to run -/// * Which chip and board you are using -/// -/// Embassy Chat: https://matrix.to/#/#embassy-rs:matrix.org -#[embassy_executor::main] -async fn main(_spawner: embassy_executor::Spawner) { - let device_config = embassy_stm32::Config::default(); - let context = embassy_stm32::init(device_config); - - let tsc_conf = Config { - ct_pulse_high_length: ChargeTransferPulseCycle::_4, - ct_pulse_low_length: ChargeTransferPulseCycle::_4, - spread_spectrum: false, - spread_spectrum_deviation: SSDeviation::new(2).unwrap(), - spread_spectrum_prescaler: false, - pulse_generator_prescaler: PGPrescalerDivider::_16, - max_count_value: MaxCount::_255, - io_default_mode: false, - synchro_pin_polarity: false, - acquisition_mode: false, - max_count_interrupt: false, - channel_ios: TscIOPin::Group1Io1.into(), - shield_ios: 0, // no shield - sampling_ios: TscIOPin::Group1Io2.into(), - }; - - let mut g1: PinGroup = PinGroup::new(); - g1.set_io1(context.PA0, PinType::Sample); - g1.set_io2(context.PA1, PinType::Channel); - - let mut touch_controller = tsc::Tsc::new_blocking( - context.TSC, - Some(g1), - None, - None, - None, - None, - None, - None, - None, - tsc_conf, - ); - - // Check if TSC is ready - if touch_controller.get_state() != State::Ready { - info!("TSC not ready!"); - loop {} // Halt execution - } - info!("TSC initialized successfully"); - - // LED2 on the STM32L073RZ nucleo-board (PA5) - let mut led = Output::new(context.PA5, Level::High, Speed::Low); - - // smaller sample capacitor discharge faster and can be used with shorter delay. - let discharge_delay = 5; // ms - - // the interval at which the loop polls for new touch sensor values - let polling_interval = 100; // ms - - info!("polling for touch"); - loop { - touch_controller.start(); - touch_controller.poll_for_acquisition(); - touch_controller.discharge_io(true); - Timer::after_millis(discharge_delay).await; - - let grp1_status = touch_controller.group_get_status(Group::One); - match grp1_status { - GroupStatus::Complete => { - let group_one_val = touch_controller.group_get_value(Group::One); - info!("{}", group_one_val); - led.set_high(); - } - GroupStatus::Ongoing => led.set_low(), - } - - Timer::after_millis(polling_interval).await; - } -} diff --git a/examples/stm32l0/src/bin/tsc_async.rs b/examples/stm32l0/src/bin/tsc_async.rs new file mode 100644 index 000000000..cebe9712f --- /dev/null +++ b/examples/stm32l0/src/bin/tsc_async.rs @@ -0,0 +1,116 @@ +// Example of async TSC (Touch Sensing Controller) that lights an LED when touch is detected. +// +// This example demonstrates: +// 1. Configuring a single TSC channel pin +// 2. Using the blocking TSC interface with polling +// 3. Waiting for acquisition completion using `poll_for_acquisition` +// 4. Reading touch values and controlling an LED based on the results +// +// Suggested physical setup on STM32L073RZ Nucleo board: +// - Connect a 1000pF capacitor between pin PA0 and GND. This is your sampling capacitor. +// - Connect one end of a 1K resistor to pin PA1 and leave the other end loose. +// The loose end will act as the touch sensor which will register your touch. +// +// The example uses two pins from Group 1 of the TSC on the STM32L073RZ Nucleo board: +// - PA0 as the sampling capacitor, TSC group 1 IO1 (label A0) +// - PA1 as the channel pin, TSC group 1 IO2 (label A1) +// +// The program continuously reads the touch sensor value: +// - It starts acquisition, waits for completion using `poll_for_acquisition`, and reads the value. +// - The LED is turned on when touch is detected (sensor value < 25). +// - Touch values are logged to the console. +// +// Troubleshooting: +// - If touch is not detected, try adjusting the SENSOR_THRESHOLD value. +// - Experiment with different values for ct_pulse_high_length, ct_pulse_low_length, +// pulse_generator_prescaler, max_count_value, and discharge_delay to optimize sensitivity. +// +// Note: Configuration values and sampling capacitor value have been determined experimentally. +// Optimal values may vary based on your specific hardware setup. +// Pins have been chosen for their convenient locations on the STM32L073RZ board. Refer to the +// official relevant STM32 datasheets and nucleo-board user manuals to find suitable +// alternative pins. +// +// Beware for STM32L073RZ nucleo-board, that PA2 and PA3 is used for the uart connection to +// the programmer chip. If you try to use these two pins for TSC, you will get strange +// readings, unless you somehow reconfigure/re-wire your nucleo-board. +// No errors or warnings will be emitted, they will just silently not work as expected. +// (see nucleo user manual UM1724, Rev 14, page 25) + +#![no_std] +#![no_main] + +use defmt::*; +use embassy_stm32::gpio::{Level, Output, Speed}; +use embassy_stm32::tsc::{self, *}; +use embassy_stm32::{bind_interrupts, peripherals}; +use embassy_time::Timer; +use {defmt_rtt as _, panic_probe as _}; + +bind_interrupts!(struct Irqs { + TSC => InterruptHandler; +}); +const SENSOR_THRESHOLD: u16 = 25; // Adjust this value based on your setup + +#[embassy_executor::main] +async fn main(_spawner: embassy_executor::Spawner) { + let device_config = embassy_stm32::Config::default(); + let context = embassy_stm32::init(device_config); + + let mut pin_group: PinGroupWithRoles = PinGroupWithRoles::default(); + pin_group.set_io1::(context.PA0); + let sensor = pin_group.set_io2::(context.PA1); + + let tsc_conf = Config { + ct_pulse_high_length: ChargeTransferPulseCycle::_4, + ct_pulse_low_length: ChargeTransferPulseCycle::_4, + spread_spectrum: false, + spread_spectrum_deviation: SSDeviation::new(2).unwrap(), + spread_spectrum_prescaler: false, + pulse_generator_prescaler: PGPrescalerDivider::_16, + max_count_value: MaxCount::_255, + io_default_mode: false, + synchro_pin_polarity: false, + acquisition_mode: false, + max_count_interrupt: false, + }; + + let pin_groups: PinGroups = PinGroups { + g1: Some(pin_group.pin_group), + ..Default::default() + }; + + let mut touch_controller = tsc::Tsc::new_async(context.TSC, pin_groups, tsc_conf, Irqs).unwrap(); + + // Check if TSC is ready + if touch_controller.get_state() != State::Ready { + info!("TSC not ready!"); + return; + } + info!("TSC initialized successfully"); + + // LED2 on the STM32L073RZ nucleo-board (PA5) + let mut led = Output::new(context.PA5, Level::Low, Speed::Low); + + let discharge_delay = 5; // ms + + info!("Starting touch_controller interface"); + loop { + touch_controller.set_active_channels_mask(sensor.pin.into()); + touch_controller.start(); + touch_controller.pend_for_acquisition().await; + touch_controller.discharge_io(true); + Timer::after_millis(discharge_delay).await; + + let group_val = touch_controller.group_get_value(sensor.pin.group()); + info!("Touch value: {}", group_val); + + if group_val < SENSOR_THRESHOLD { + led.set_high(); + } else { + led.set_low(); + } + + Timer::after_millis(100).await; + } +} diff --git a/examples/stm32l0/src/bin/tsc_blocking.rs b/examples/stm32l0/src/bin/tsc_blocking.rs new file mode 100644 index 000000000..65203925c --- /dev/null +++ b/examples/stm32l0/src/bin/tsc_blocking.rs @@ -0,0 +1,142 @@ +// Example of blocking TSC (Touch Sensing Controller) that lights an LED when touch is detected. +// +// This example demonstrates: +// 1. Configuring a single TSC channel pin +// 2. Using the blocking TSC interface with polling +// 3. Waiting for acquisition completion using `poll_for_acquisition` +// 4. Reading touch values and controlling an LED based on the results +// +// Suggested physical setup on STM32L073RZ Nucleo board: +// - Connect a 1000pF capacitor between pin PA0 and GND. This is your sampling capacitor. +// - Connect one end of a 1K resistor to pin PA1 and leave the other end loose. +// The loose end will act as the touch sensor which will register your touch. +// +// The example uses two pins from Group 1 of the TSC on the STM32L073RZ Nucleo board: +// - PA0 as the sampling capacitor, TSC group 1 IO1 (label A0) +// - PA1 as the channel pin, TSC group 1 IO2 (label A1) +// +// The program continuously reads the touch sensor value: +// - It starts acquisition, waits for completion using `poll_for_acquisition`, and reads the value. +// - The LED is turned on when touch is detected (sensor value < 25). +// - Touch values are logged to the console. +// +// Troubleshooting: +// - If touch is not detected, try adjusting the SENSOR_THRESHOLD value. +// - Experiment with different values for ct_pulse_high_length, ct_pulse_low_length, +// pulse_generator_prescaler, max_count_value, and discharge_delay to optimize sensitivity. +// +// Note: Configuration values and sampling capacitor value have been determined experimentally. +// Optimal values may vary based on your specific hardware setup. +// Pins have been chosen for their convenient locations on the STM32L073RZ board. Refer to the +// official relevant STM32 datasheets and nucleo-board user manuals to find suitable +// alternative pins. +// +// Beware for STM32L073RZ nucleo-board, that PA2 and PA3 is used for the uart connection to +// the programmer chip. If you try to use these two pins for TSC, you will get strange +// readings, unless you somehow reconfigure/re-wire your nucleo-board. +// No errors or warnings will be emitted, they will just silently not work as expected. +// (see nucleo user manual UM1724, Rev 14, page 25) + +#![no_std] +#![no_main] + +use defmt::*; +use embassy_stm32::gpio::{Level, Output, Speed}; +use embassy_stm32::tsc::{self, *}; +use embassy_stm32::{mode, peripherals}; +use embassy_time::Timer; +use {defmt_rtt as _, panic_probe as _}; + +const SENSOR_THRESHOLD: u16 = 25; // Adjust this value based on your setup + +#[embassy_executor::main] +async fn main(_spawner: embassy_executor::Spawner) { + let device_config = embassy_stm32::Config::default(); + let context = embassy_stm32::init(device_config); + + let tsc_conf = Config { + ct_pulse_high_length: ChargeTransferPulseCycle::_4, + ct_pulse_low_length: ChargeTransferPulseCycle::_4, + spread_spectrum: false, + spread_spectrum_deviation: SSDeviation::new(2).unwrap(), + spread_spectrum_prescaler: false, + pulse_generator_prescaler: PGPrescalerDivider::_16, + max_count_value: MaxCount::_255, + io_default_mode: false, + synchro_pin_polarity: false, + acquisition_mode: false, + max_count_interrupt: false, + }; + + let mut g1: PinGroupWithRoles = PinGroupWithRoles::default(); + g1.set_io1::(context.PA0); + let tsc_sensor = g1.set_io2::(context.PA1); + + let pin_groups: PinGroups = PinGroups { + g1: Some(g1.pin_group), + ..Default::default() + }; + + let mut touch_controller = tsc::Tsc::new_blocking(context.TSC, pin_groups, tsc_conf).unwrap(); + + // Check if TSC is ready + if touch_controller.get_state() != State::Ready { + crate::panic!("TSC not ready!"); + } + info!("TSC initialized successfully"); + + // LED2 on the STM32L073RZ nucleo-board (PA5) + let mut led = Output::new(context.PA5, Level::High, Speed::Low); + + // smaller sample capacitor discharge faster and can be used with shorter delay. + let discharge_delay = 5; // ms + + // the interval at which the loop polls for new touch sensor values + let polling_interval = 100; // ms + + info!("polling for touch"); + loop { + touch_controller.set_active_channels_mask(tsc_sensor.pin.into()); + touch_controller.start(); + touch_controller.poll_for_acquisition(); + touch_controller.discharge_io(true); + Timer::after_millis(discharge_delay).await; + + match read_touch_value(&mut touch_controller, tsc_sensor.pin).await { + Some(v) => { + info!("sensor value {}", v); + if v < SENSOR_THRESHOLD { + led.set_high(); + } else { + led.set_low(); + } + } + None => led.set_low(), + } + + Timer::after_millis(polling_interval).await; + } +} + +const MAX_GROUP_STATUS_READ_ATTEMPTS: usize = 10; + +// attempt to read group status and delay when still ongoing +async fn read_touch_value( + touch_controller: &mut tsc::Tsc<'_, peripherals::TSC, mode::Blocking>, + sensor_pin: TscIOPin, +) -> Option { + for _ in 0..MAX_GROUP_STATUS_READ_ATTEMPTS { + match touch_controller.group_get_status(sensor_pin.group()) { + GroupStatus::Complete => { + return Some(touch_controller.group_get_value(sensor_pin.group())); + } + GroupStatus::Ongoing => { + // if you end up here a lot, then you prob need to increase discharge_delay + // or consider changing the code to adjust the discharge_delay dynamically + info!("Acquisition still ongoing"); + Timer::after_millis(1).await; + } + } + } + None +} diff --git a/examples/stm32l0/src/bin/tsc_multipin.rs b/examples/stm32l0/src/bin/tsc_multipin.rs new file mode 100644 index 000000000..6170d0799 --- /dev/null +++ b/examples/stm32l0/src/bin/tsc_multipin.rs @@ -0,0 +1,233 @@ +// Example of TSC (Touch Sensing Controller) using multiple pins from the same tsc-group. +// +// What is special about using multiple TSC pins as sensor channels from the same TSC group, +// is that only one TSC pin for each TSC group can be acquired and read at the time. +// To control which channel pins are acquired and read, we must write a mask before initiating an +// acquisition. To help manage and abstract all this business away, we can organize our channel +// pins into acquisition banks. Each acquisition bank can contain exactly one channel pin per TSC +// group and it will contain the relevant mask. +// +// This example demonstrates how to: +// 1. Configure multiple channel pins within a single TSC group +// 2. Use the set_active_channels method to switch between different channels +// 3. Read and interpret touch values from multiple channels in the same group +// +// Suggested physical setup on STM32L073RZ Nucleo board: +// - Connect a 1000pF capacitor between pin PA0 (label A0) and GND. This is the sampling capacitor for TSC +// group 1. +// - Connect one end of a 1K resistor to pin PA1 (label A1) and leave the other end loose. +// The loose end will act as a touch sensor. +// +// - Connect a 1000pF capacitor between pin PB3 (label D3) and GND. This is the sampling capacitor for TSC +// group 5. +// - Connect one end of another 1K resistor to pin PB4 and leave the other end loose. +// The loose end will act as a touch sensor. +// - Connect one end of another 1K resistor to pin PB6 and leave the other end loose. +// The loose end will act as a touch sensor. +// +// The example uses pins from two TSC groups. +// - PA0 as sampling capacitor, TSC group 1 IO1 (label A0) +// - PA1 as channel, TSC group 1 IO2 (label A1) +// - PB3 as sampling capacitor, TSC group 5 IO1 (label D3) +// - PB4 as channel, TSC group 5 IO2 (label D3) +// - PB6 as channel, TSC group 5 IO3 (label D5) +// +// The pins have been chosen to make it easy to simply add capacitors directly onto the board and +// connect one leg to GND, and to easily add resistors to the board with no special connectors, +// breadboards, special wires or soldering required. All you need is the capacitors and resistors. +// +// The program reads the designated channel pins and adjusts the LED blinking +// pattern based on which sensor(s) are touched: +// - No touch: LED off +// - one sensor touched: Slow blinking +// - two sensors touched: Fast blinking +// - three sensors touched: LED constantly on +// +// Troubleshooting: +// - If touch is not detected, try adjusting the SENSOR_THRESHOLD value. +// - Experiment with different values for ct_pulse_high_length, ct_pulse_low_length, +// pulse_generator_prescaler, max_count_value, and discharge_delay to optimize sensitivity. +// +// Note: Configuration values and sampling capacitor value have been determined experimentally. +// Optimal values may vary based on your specific hardware setup. +// Pins have been chosen for their convenient locations on the STM32L073RZ board. Refer to the +// official relevant STM32 datasheets and nucleo-board user manuals to find suitable +// alternative pins. +// +// Beware for STM32L073RZ nucleo-board, that PA2 and PA3 is used for the uart connection to +// the programmer chip. If you try to use these two pins for TSC, you will get strange +// readings, unless you somehow reconfigure/re-wire your nucleo-board. +// No errors or warnings will be emitted, they will just silently not work as expected. +// (see nucleo user manual UM1724, Rev 14, page 25) + +#![no_std] +#![no_main] + +use defmt::*; +use embassy_stm32::gpio::{Level, Output, Speed}; +use embassy_stm32::tsc::{self, *}; +use embassy_stm32::{bind_interrupts, mode, peripherals}; +use embassy_time::Timer; +use {defmt_rtt as _, panic_probe as _}; + +bind_interrupts!(struct Irqs { + TSC => InterruptHandler; +}); + +const MAX_GROUP_STATUS_READ_ATTEMPTS: usize = 10; + +async fn read_touch_values( + touch_controller: &mut tsc::Tsc<'_, peripherals::TSC, mode::Async>, + tsc_acquisition_bank: &TscAcquisitionBank, +) -> Option { + for _ in 0..MAX_GROUP_STATUS_READ_ATTEMPTS { + let status = touch_controller.get_acquisition_bank_status(tsc_acquisition_bank); + if status.all_complete() { + let r = touch_controller.get_acquisition_bank_values(tsc_acquisition_bank); + return Some(r); + } else { + info!("Acquisition still ongoing"); + Timer::after_millis(1).await; + } + } + info!("Acquisition failed after {} attempts", MAX_GROUP_STATUS_READ_ATTEMPTS); + None +} + +const SENSOR_THRESHOLD: u16 = 35; + +async fn acquire_sensors( + touch_controller: &mut Tsc<'static, peripherals::TSC, mode::Async>, + tsc_acquisition_bank: &TscAcquisitionBank, +) { + touch_controller.set_active_channels_mask(tsc_acquisition_bank.mask()); + touch_controller.start(); + touch_controller.pend_for_acquisition().await; + touch_controller.discharge_io(true); + let discharge_delay = 5; // ms + Timer::after_millis(discharge_delay).await; +} + +#[embassy_executor::main] +async fn main(_spawner: embassy_executor::Spawner) { + let device_config = embassy_stm32::Config::default(); + let context = embassy_stm32::init(device_config); + + // ---------- initial configuration of TSC ---------- + let mut pin_group1: PinGroupWithRoles = PinGroupWithRoles::default(); + pin_group1.set_io1::(context.PA0); + let tsc_sensor0 = pin_group1.set_io2(context.PA1); + + let mut pin_group5: PinGroupWithRoles = PinGroupWithRoles::default(); + pin_group5.set_io1::(context.PB3); + let tsc_sensor1 = pin_group5.set_io2(context.PB4); + let tsc_sensor2 = pin_group5.set_io3(context.PB6); + + let config = tsc::Config { + ct_pulse_high_length: ChargeTransferPulseCycle::_16, + ct_pulse_low_length: ChargeTransferPulseCycle::_16, + spread_spectrum: false, + spread_spectrum_deviation: SSDeviation::new(2).unwrap(), + spread_spectrum_prescaler: false, + pulse_generator_prescaler: PGPrescalerDivider::_16, + max_count_value: MaxCount::_255, + io_default_mode: false, + synchro_pin_polarity: false, + acquisition_mode: false, + max_count_interrupt: false, + }; + + let pin_groups: PinGroups = PinGroups { + g1: Some(pin_group1.pin_group), + g5: Some(pin_group5.pin_group), + ..Default::default() + }; + + let mut touch_controller = tsc::Tsc::new_async(context.TSC, pin_groups, config, Irqs).unwrap(); + + // ---------- setting up acquisition banks ---------- + // sensor0 and sensor1 in this example belong to different TSC-groups, + // therefore we can acquire and read them both in one go. + let bank1 = touch_controller.create_acquisition_bank(TscAcquisitionBankPins { + g1_pin: Some(tsc_sensor0), + g5_pin: Some(tsc_sensor1), + ..Default::default() + }); + // `sensor1` and `sensor2` belongs to the same TSC-group, therefore we must make sure to + // acquire them one at the time. Therefore, we organize them into different acquisition banks. + let bank2 = touch_controller.create_acquisition_bank(TscAcquisitionBankPins { + g5_pin: Some(tsc_sensor2), + ..Default::default() + }); + + // Check if TSC is ready + if touch_controller.get_state() != State::Ready { + crate::panic!("TSC not ready!"); + } + + info!("TSC initialized successfully"); + + // LED2 on the STM32L073RZ nucleo-board (PA5) + let mut led = Output::new(context.PA5, Level::High, Speed::Low); + + let mut led_state = false; + + loop { + acquire_sensors(&mut touch_controller, &bank1).await; + let readings1: TscAcquisitionBankReadings = read_touch_values(&mut touch_controller, &bank1) + .await + .expect("should be able to read values for bank 1"); + acquire_sensors(&mut touch_controller, &bank2).await; + let readings2: TscAcquisitionBankReadings = read_touch_values(&mut touch_controller, &bank2) + .await + .expect("should be able to read values for bank 2"); + + let mut touched_sensors_count = 0; + for reading in readings1.iter() { + info!("{}", reading); + if reading.sensor_value < SENSOR_THRESHOLD { + touched_sensors_count += 1; + } + } + for reading in readings2.iter() { + info!("{}", reading); + if reading.sensor_value < SENSOR_THRESHOLD { + touched_sensors_count += 1; + } + } + + match touched_sensors_count { + 0 => { + // No sensors touched, turn off the LED + led.set_low(); + led_state = false; + } + 1 => { + // One sensor touched, blink slowly + led_state = !led_state; + if led_state { + led.set_high(); + } else { + led.set_low(); + } + Timer::after_millis(200).await; + } + 2 => { + // Two sensors touched, blink faster + led_state = !led_state; + if led_state { + led.set_high(); + } else { + led.set_low(); + } + Timer::after_millis(50).await; + } + 3 => { + // All three sensors touched, LED constantly on + led.set_high(); + led_state = true; + } + _ => crate::unreachable!(), // This case should never occur with 3 sensors + } + } +} diff --git a/examples/stm32l4/.cargo/config.toml b/examples/stm32l4/.cargo/config.toml index 83fc6d6f8..d71fb1517 100644 --- a/examples/stm32l4/.cargo/config.toml +++ b/examples/stm32l4/.cargo/config.toml @@ -2,7 +2,8 @@ # replace STM32F429ZITx with your chip as listed in `probe-rs chip list` #runner = "probe-rs run --chip STM32L475VGT6" #runner = "probe-rs run --chip STM32L475VG" -runner = "probe-rs run --chip STM32L4S5QI" +#runner = "probe-rs run --chip STM32L4S5QI" +runner = "probe-rs run --chip STM32L4R5ZITxP" [build] target = "thumbv7em-none-eabi" diff --git a/examples/stm32l4/Cargo.toml b/examples/stm32l4/Cargo.toml index b172878c1..512bb8064 100644 --- a/examples/stm32l4/Cargo.toml +++ b/examples/stm32l4/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32l4s5vi to your chip name, if necessary. -embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32l4s5qi", "memory-x", "time-driver-any", "exti", "chrono"] } +embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32l4r5zi", "memory-x", "time-driver-any", "exti", "chrono"] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768", ] } diff --git a/examples/stm32l4/README.md b/examples/stm32l4/README.md new file mode 100644 index 000000000..e463c18a0 --- /dev/null +++ b/examples/stm32l4/README.md @@ -0,0 +1,24 @@ +# Examples for STM32L4 family +Run individual examples with +``` +cargo run --bin +``` +for example +``` +cargo run --bin blinky +``` + +## Checklist before running examples +You might need to adjust `.cargo/config.toml`, `Cargo.toml` and possibly update pin numbers or peripherals to match the specific MCU or board you are using. + +* [ ] Update .cargo/config.toml with the correct probe-rs command to use your specific MCU. For example for L4R5ZI-P it should be `probe-rs run --chip STM32L4R5ZITxP`. (use `probe-rs chip list` to find your chip) +* [ ] Update Cargo.toml to have the correct `embassy-stm32` feature. For example for L4R5ZI-P it should be `stm32l4r5zi`. Look in the `Cargo.toml` file of the `embassy-stm32` project to find the correct feature flag for your chip. +* [ ] If your board has a special clock or power configuration, make sure that it is set up appropriately. +* [ ] If your board has different pin mapping, update any pin numbers or peripherals in the given example code to match your schematic + +If you are unsure, please drop by the Embassy Matrix chat for support, and let us know: + +* Which example you are trying to run +* Which chip and board you are using + +Embassy Chat: https://matrix.to/#/#embassy-rs:matrix.org diff --git a/examples/stm32l4/src/bin/tsc_async.rs b/examples/stm32l4/src/bin/tsc_async.rs new file mode 100644 index 000000000..ada2c468f --- /dev/null +++ b/examples/stm32l4/src/bin/tsc_async.rs @@ -0,0 +1,108 @@ +// Example of async TSC (Touch Sensing Controller) that lights an LED when touch is detected. +// +// This example demonstrates: +// 1. Configuring a single TSC channel pin +// 2. Using the async TSC interface +// 3. Waiting for acquisition completion using `pend_for_acquisition` +// 4. Reading touch values and controlling an LED based on the results +// +// Suggested physical setup on STM32L4R5ZI-P board: +// - Connect a 1000pF capacitor between pin PB4 (D25) and GND. This is your sampling capacitor. +// - Connect one end of a 1K resistor to pin PB5 (D21) and leave the other end loose. +// The loose end will act as the touch sensor which will register your touch. +// +// The example uses two pins from Group 2 of the TSC: +// - PB4 (D25) as the sampling capacitor, TSC group 2 IO1 +// - PB5 (D21) as the channel pin, TSC group 2 IO2 +// +// The program continuously reads the touch sensor value: +// - It starts acquisition, waits for completion using `pend_for_acquisition`, and reads the value. +// - The LED (connected to PB14) is turned on when touch is detected (sensor value < SENSOR_THRESHOLD). +// - Touch values are logged to the console. +// +// Troubleshooting: +// - If touch is not detected, try adjusting the SENSOR_THRESHOLD value. +// - Experiment with different values for ct_pulse_high_length, ct_pulse_low_length, +// pulse_generator_prescaler, max_count_value, and discharge_delay to optimize sensitivity. +// +// Note: Configuration values and sampling capacitor value have been determined experimentally. +// Optimal values may vary based on your specific hardware setup. + +#![no_std] +#![no_main] + +use defmt::*; +use embassy_stm32::gpio::{Level, Output, Speed}; +use embassy_stm32::tsc::{self, *}; +use embassy_stm32::{bind_interrupts, peripherals}; +use embassy_time::Timer; +use {defmt_rtt as _, panic_probe as _}; + +bind_interrupts!(struct Irqs { + TSC => InterruptHandler; +}); +const SENSOR_THRESHOLD: u16 = 25; // Adjust this value based on your setup + +#[embassy_executor::main] +async fn main(_spawner: embassy_executor::Spawner) { + let device_config = embassy_stm32::Config::default(); + let context = embassy_stm32::init(device_config); + + let mut pin_group: PinGroupWithRoles = PinGroupWithRoles::default(); + // D25 + pin_group.set_io1::(context.PB4); + // D21 + let tsc_sensor = pin_group.set_io2::(context.PB5); + + let pin_groups: PinGroups = PinGroups { + g2: Some(pin_group.pin_group), + ..Default::default() + }; + + let tsc_conf = Config { + ct_pulse_high_length: ChargeTransferPulseCycle::_4, + ct_pulse_low_length: ChargeTransferPulseCycle::_4, + spread_spectrum: false, + spread_spectrum_deviation: SSDeviation::new(2).unwrap(), + spread_spectrum_prescaler: false, + pulse_generator_prescaler: PGPrescalerDivider::_16, + max_count_value: MaxCount::_255, + io_default_mode: false, + synchro_pin_polarity: false, + acquisition_mode: false, + max_count_interrupt: false, + }; + + let mut touch_controller = tsc::Tsc::new_async(context.TSC, pin_groups, tsc_conf, Irqs).unwrap(); + + // Check if TSC is ready + if touch_controller.get_state() != State::Ready { + info!("TSC not ready!"); + return; + } + info!("TSC initialized successfully"); + + let mut led = Output::new(context.PB14, Level::High, Speed::Low); + + let discharge_delay = 1; // ms + + info!("Starting touch_controller interface"); + loop { + touch_controller.set_active_channels_mask(tsc_sensor.pin.into()); + touch_controller.start(); + touch_controller.pend_for_acquisition().await; + touch_controller.discharge_io(true); + Timer::after_millis(discharge_delay).await; + + let group_val = touch_controller.group_get_value(tsc_sensor.pin.group()); + info!("Touch value: {}", group_val); + + if group_val < SENSOR_THRESHOLD { + led.set_high(); + } else { + led.set_low(); + } + + Timer::after_millis(100).await; + } +} diff --git a/examples/stm32l4/src/bin/tsc_blocking.rs b/examples/stm32l4/src/bin/tsc_blocking.rs new file mode 100644 index 000000000..76aba55ba --- /dev/null +++ b/examples/stm32l4/src/bin/tsc_blocking.rs @@ -0,0 +1,147 @@ +// # Example of blocking TSC (Touch Sensing Controller) that lights an LED when touch is detected +// +// This example demonstrates how to use the Touch Sensing Controller (TSC) in blocking mode on an STM32L4R5ZI-P board. +// +// ## This example demonstrates: +// +// 1. Configuring a single TSC channel pin +// 2. Using the blocking TSC interface with polling +// 3. Waiting for acquisition completion using `poll_for_acquisition` +// 4. Reading touch values and controlling an LED based on the results +// +// ## Suggested physical setup on STM32L4R5ZI-P board: +// +// - Connect a 1000pF capacitor between pin PB4 (D25) and GND. This is your sampling capacitor. +// - Connect one end of a 1K resistor to pin PB5 (D21) and leave the other end loose. +// The loose end will act as the touch sensor which will register your touch. +// +// ## Pin Configuration: +// +// The example uses two pins from Group 2 of the TSC: +// - PB4 (D25) as the sampling capacitor, TSC group 2 IO1 +// - PB5 (D21) as the channel pin, TSC group 2 IO2 +// +// ## Program Behavior: +// +// The program continuously reads the touch sensor value: +// - It starts acquisition, waits for completion using `poll_for_acquisition`, and reads the value. +// - The LED (connected to PB14) is turned on when touch is detected (sensor value < SENSOR_THRESHOLD). +// - Touch values are logged to the console. +// +// ## Troubleshooting: +// +// - If touch is not detected, try adjusting the SENSOR_THRESHOLD value (currently set to 25). +// - Experiment with different values for ct_pulse_high_length, ct_pulse_low_length, +// pulse_generator_prescaler, max_count_value, and discharge_delay to optimize sensitivity. +// - Be aware that for some boards, there might be overlapping concerns between some pins, +// such as UART connections for the programmer. No errors or warnings will be emitted if you +// try to use such a pin for TSC, but you may get strange sensor readings. +// +// Note: Configuration values and sampling capacitor value have been determined experimentally. +// Optimal values may vary based on your specific hardware setup. Refer to the official +// STM32L4R5ZI-P datasheet and user manuals for more information on pin configurations and TSC functionality. + +#![no_std] +#![no_main] + +use defmt::*; +use embassy_stm32::gpio::{Level, Output, Speed}; +use embassy_stm32::tsc::{self, *}; +use embassy_stm32::{mode, peripherals}; +use embassy_time::Timer; +use {defmt_rtt as _, panic_probe as _}; + +const SENSOR_THRESHOLD: u16 = 25; // Adjust this value based on your setup + +#[embassy_executor::main] +async fn main(_spawner: embassy_executor::Spawner) { + let device_config = embassy_stm32::Config::default(); + let context = embassy_stm32::init(device_config); + + let tsc_conf = Config { + ct_pulse_high_length: ChargeTransferPulseCycle::_4, + ct_pulse_low_length: ChargeTransferPulseCycle::_4, + spread_spectrum: false, + spread_spectrum_deviation: SSDeviation::new(2).unwrap(), + spread_spectrum_prescaler: false, + pulse_generator_prescaler: PGPrescalerDivider::_16, + max_count_value: MaxCount::_255, + io_default_mode: false, + synchro_pin_polarity: false, + acquisition_mode: false, + max_count_interrupt: false, + }; + + let mut g2: PinGroupWithRoles = PinGroupWithRoles::default(); + // D25 + g2.set_io1::(context.PB4); + // D21 + let tsc_sensor = g2.set_io2::(context.PB5); + + let pin_groups: PinGroups = PinGroups { + g2: Some(g2.pin_group), + ..Default::default() + }; + + let mut touch_controller = tsc::Tsc::new_blocking(context.TSC, pin_groups, tsc_conf).unwrap(); + + // Check if TSC is ready + if touch_controller.get_state() != State::Ready { + crate::panic!("TSC not ready!"); + } + info!("TSC initialized successfully"); + + let mut led = Output::new(context.PB14, Level::High, Speed::Low); + + // smaller sample capacitor discharge faster and can be used with shorter delay. + let discharge_delay = 5; // ms + + // the interval at which the loop polls for new touch sensor values + let polling_interval = 100; // ms + + info!("polling for touch"); + loop { + touch_controller.set_active_channels_mask(tsc_sensor.pin.into()); + touch_controller.start(); + touch_controller.poll_for_acquisition(); + touch_controller.discharge_io(true); + Timer::after_millis(discharge_delay).await; + + match read_touch_value(&mut touch_controller, tsc_sensor.pin).await { + Some(v) => { + info!("sensor value {}", v); + if v < SENSOR_THRESHOLD { + led.set_high(); + } else { + led.set_low(); + } + } + None => led.set_low(), + } + + Timer::after_millis(polling_interval).await; + } +} + +const MAX_GROUP_STATUS_READ_ATTEMPTS: usize = 10; + +// attempt to read group status and delay when still ongoing +async fn read_touch_value( + touch_controller: &mut tsc::Tsc<'_, peripherals::TSC, mode::Blocking>, + sensor_pin: TscIOPin, +) -> Option { + for _ in 0..MAX_GROUP_STATUS_READ_ATTEMPTS { + match touch_controller.group_get_status(sensor_pin.group()) { + GroupStatus::Complete => { + return Some(touch_controller.group_get_value(sensor_pin.group())); + } + GroupStatus::Ongoing => { + // if you end up here a lot, then you prob need to increase discharge_delay + // or consider changing the code to adjust the discharge_delay dynamically + info!("Acquisition still ongoing"); + Timer::after_millis(1).await; + } + } + } + None +} diff --git a/examples/stm32l4/src/bin/tsc_multipin.rs b/examples/stm32l4/src/bin/tsc_multipin.rs new file mode 100644 index 000000000..20a559514 --- /dev/null +++ b/examples/stm32l4/src/bin/tsc_multipin.rs @@ -0,0 +1,222 @@ +// # Example of TSC (Touch Sensing Controller) using multiple pins from the same TSC group +// +// This example demonstrates how to use the Touch Sensing Controller (TSC) with multiple pins, including pins from the same TSC group, on an STM32L4R5ZI-P board. +// +// ## Key Concepts +// +// - Only one TSC pin for each TSC group can be acquired and read at a time. +// - To control which channel pins are acquired and read, we must write a mask before initiating an acquisition. +// - We organize channel pins into acquisition banks to manage this process efficiently. +// - Each acquisition bank can contain exactly one channel pin per TSC group and will contain the relevant mask. +// +// ## This example demonstrates how to: +// +// 1. Configure multiple channel pins within a single TSC group +// 2. Use the set_active_channels method to switch between different channels +// 3. Read and interpret touch values from multiple channels in the same group +// +// ## Suggested physical setup on STM32L4R5ZI-P board: +// +// - Connect a 1000pF capacitor between pin PB12 (D19) and GND. This is the sampling capacitor for TSC group 1. +// - Connect one end of a 1K resistor to pin PB13 (D18) and leave the other end loose. This will act as a touch sensor. +// - Connect a 1000pF capacitor between pin PB4 (D25) and GND. This is the sampling capacitor for TSC group 2. +// - Connect one end of a 1K resistor to pin PB5 (D22) and leave the other end loose. This will act as a touch sensor. +// - Connect one end of another 1K resistor to pin PB6 (D71) and leave the other end loose. This will act as a touch sensor. +// +// ## Pin Configuration: +// +// The example uses pins from two TSC groups: +// +// - Group 1: +// - PB12 (D19) as sampling capacitor (TSC group 1 IO1) +// - PB13 (D18) as channel (TSC group 1 IO2) +// - Group 2: +// - PB4 (D25) as sampling capacitor (TSC group 2 IO1) +// - PB5 (D22) as channel (TSC group 2 IO2) +// - PB6 (D71) as channel (TSC group 2 IO3) +// +// The pins have been chosen for their convenient locations on the STM32L4R5ZI-P board, making it easy to add capacitors and resistors directly to the board without special connectors, breadboards, or soldering. +// +// ## Program Behavior: +// +// The program reads the designated channel pins and adjusts the LED (connected to PB14) blinking pattern based on which sensor(s) are touched: +// +// - No touch: LED off +// - One sensor touched: Slow blinking +// - Two sensors touched: Fast blinking +// - Three sensors touched: LED constantly on +// +// ## Troubleshooting: +// +// - If touch is not detected, try adjusting the SENSOR_THRESHOLD value (currently set to 20). +// - Experiment with different values for ct_pulse_high_length, ct_pulse_low_length, pulse_generator_prescaler, max_count_value, and discharge_delay to optimize sensitivity. +// - Be aware that for some boards there will be overlapping concerns between some pins, for +// example UART connection for the programmer to the MCU and a TSC pin. No errors or warning will +// be emitted if you try to use such a pin for TSC, but you will get strange sensor readings. +// +// Note: Configuration values and sampling capacitor values have been determined experimentally. Optimal values may vary based on your specific hardware setup. Refer to the official STM32L4R5ZI-P datasheet and user manuals for more information on pin configurations and TSC functionality. + +#![no_std] +#![no_main] + +use defmt::*; +use embassy_stm32::gpio::{Level, Output, Speed}; +use embassy_stm32::tsc::{self, *}; +use embassy_stm32::{bind_interrupts, mode, peripherals}; +use embassy_time::Timer; +use {defmt_rtt as _, panic_probe as _}; + +bind_interrupts!(struct Irqs { + TSC => InterruptHandler; +}); + +const MAX_GROUP_STATUS_READ_ATTEMPTS: usize = 10; + +async fn read_touch_values( + touch_controller: &mut tsc::Tsc<'_, peripherals::TSC, mode::Async>, + tsc_acquisition_bank: &TscAcquisitionBank, +) -> Option { + for _ in 0..MAX_GROUP_STATUS_READ_ATTEMPTS { + let status = touch_controller.get_acquisition_bank_status(tsc_acquisition_bank); + if status.all_complete() { + let r = touch_controller.get_acquisition_bank_values(tsc_acquisition_bank); + return Some(r); + } else { + info!("Acquisition still ongoing"); + Timer::after_millis(1).await; + } + } + info!("Acquisition failed after {} attempts", MAX_GROUP_STATUS_READ_ATTEMPTS); + None +} + +const SENSOR_THRESHOLD: u16 = 20; + +async fn acquire_sensors( + touch_controller: &mut Tsc<'static, peripherals::TSC, mode::Async>, + tsc_acquisition_bank: &TscAcquisitionBank, +) { + touch_controller.set_active_channels_mask(tsc_acquisition_bank.mask()); + touch_controller.start(); + touch_controller.pend_for_acquisition().await; + touch_controller.discharge_io(true); + let discharge_delay = 1; // ms + Timer::after_millis(discharge_delay).await; +} + +#[embassy_executor::main] +async fn main(_spawner: embassy_executor::Spawner) { + let device_config = embassy_stm32::Config::default(); + let context = embassy_stm32::init(device_config); + + // ---------- initial configuration of TSC ---------- + let mut g1: PinGroupWithRoles = PinGroupWithRoles::default(); + g1.set_io1::(context.PB12); + let sensor0 = g1.set_io2::(context.PB13); + + let mut g2: PinGroupWithRoles = PinGroupWithRoles::default(); + g2.set_io1::(context.PB4); + let sensor1 = g2.set_io2(context.PB5); + let sensor2 = g2.set_io3(context.PB6); + + let config = tsc::Config { + ct_pulse_high_length: ChargeTransferPulseCycle::_16, + ct_pulse_low_length: ChargeTransferPulseCycle::_16, + spread_spectrum: false, + spread_spectrum_deviation: SSDeviation::new(2).unwrap(), + spread_spectrum_prescaler: false, + pulse_generator_prescaler: PGPrescalerDivider::_16, + max_count_value: MaxCount::_255, + io_default_mode: false, + synchro_pin_polarity: false, + acquisition_mode: false, + max_count_interrupt: false, + }; + + let pin_groups: PinGroups = PinGroups { + g1: Some(g1.pin_group), + g2: Some(g2.pin_group), + ..Default::default() + }; + + let mut touch_controller = tsc::Tsc::new_async(context.TSC, pin_groups, config, Irqs).unwrap(); + + // ---------- setting up acquisition banks ---------- + // sensor0 and sensor1 belong to different TSC-groups, therefore we can acquire and + // read them both in one go. + let bank1 = touch_controller.create_acquisition_bank(TscAcquisitionBankPins { + g1_pin: Some(sensor0), + g2_pin: Some(sensor1), + ..Default::default() + }); + // `sensor1` and `sensor2` belongs to the same TSC-group, therefore we must make sure to + // acquire them one at the time. We do this by organizing them into different acquisition banks. + let bank2 = touch_controller.create_acquisition_bank(TscAcquisitionBankPins { + g2_pin: Some(sensor2), + ..Default::default() + }); + + // Check if TSC is ready + if touch_controller.get_state() != State::Ready { + crate::panic!("TSC not ready!"); + } + + info!("TSC initialized successfully"); + + let mut led = Output::new(context.PB14, Level::High, Speed::Low); + + let mut led_state = false; + + loop { + acquire_sensors(&mut touch_controller, &bank1).await; + let readings1: TscAcquisitionBankReadings = read_touch_values(&mut touch_controller, &bank1) + .await + .expect("should be able to read values for bank 1"); + acquire_sensors(&mut touch_controller, &bank2).await; + let readings2: TscAcquisitionBankReadings = read_touch_values(&mut touch_controller, &bank2) + .await + .expect("should be able to read values for bank 2"); + + let mut touched_sensors_count = 0; + for reading in readings1.iter().chain(readings2.iter()) { + info!("{}", reading); + if reading.sensor_value < SENSOR_THRESHOLD { + touched_sensors_count += 1; + } + } + + match touched_sensors_count { + 0 => { + // No sensors touched, turn off the LED + led.set_low(); + led_state = false; + } + 1 => { + // One sensor touched, blink slowly + led_state = !led_state; + if led_state { + led.set_high(); + } else { + led.set_low(); + } + Timer::after_millis(200).await; + } + 2 => { + // Two sensors touched, blink faster + led_state = !led_state; + if led_state { + led.set_high(); + } else { + led.set_low(); + } + Timer::after_millis(50).await; + } + 3 => { + // All three sensors touched, LED constantly on + led.set_high(); + led_state = true; + } + _ => crate::unreachable!(), // This case should never occur with 3 sensors + } + } +} diff --git a/examples/stm32u5/src/bin/tsc.rs b/examples/stm32u5/src/bin/tsc.rs index eb15d275a..800486665 100644 --- a/examples/stm32u5/src/bin/tsc.rs +++ b/examples/stm32u5/src/bin/tsc.rs @@ -2,8 +2,8 @@ #![no_main] use defmt::*; -use embassy_stm32::bind_interrupts; use embassy_stm32::tsc::{self, *}; +use embassy_stm32::{bind_interrupts, peripherals}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; @@ -33,63 +33,52 @@ async fn main(_spawner: embassy_executor::Spawner) { synchro_pin_polarity: false, acquisition_mode: false, max_count_interrupt: false, - channel_ios: TscIOPin::Group2Io2 | TscIOPin::Group7Io3, - shield_ios: TscIOPin::Group1Io3.into(), - sampling_ios: TscIOPin::Group1Io2 | TscIOPin::Group2Io1 | TscIOPin::Group7Io2, }; - let mut g1: PinGroup = PinGroup::new(); - g1.set_io2(context.PB13, PinType::Sample); - g1.set_io3(context.PB14, PinType::Shield); + let mut g1: PinGroupWithRoles = PinGroupWithRoles::default(); + g1.set_io2::(context.PB13); + g1.set_io3::(context.PB14); - let mut g2: PinGroup = PinGroup::new(); - g2.set_io1(context.PB4, PinType::Sample); - g2.set_io2(context.PB5, PinType::Channel); + let mut g2: PinGroupWithRoles = PinGroupWithRoles::default(); + g2.set_io1::(context.PB4); + let sensor0 = g2.set_io2(context.PB5); - let mut g7: PinGroup = PinGroup::new(); - g7.set_io2(context.PE3, PinType::Sample); - g7.set_io3(context.PE4, PinType::Channel); + let mut g7: PinGroupWithRoles = PinGroupWithRoles::default(); + g7.set_io2::(context.PE3); + let sensor1 = g7.set_io3(context.PE4); - let mut touch_controller = tsc::Tsc::new_async( - context.TSC, - Some(g1), - Some(g2), - None, - None, - None, - None, - Some(g7), - None, - config, - Irqs, - ); + let pin_groups: PinGroups = PinGroups { + g1: Some(g1.pin_group), + g2: Some(g2.pin_group), + g7: Some(g7.pin_group), + ..Default::default() + }; - touch_controller.discharge_io(true); - Timer::after_millis(1).await; + let mut touch_controller = tsc::Tsc::new_async(context.TSC, pin_groups, config, Irqs).unwrap(); - touch_controller.start(); + let acquisition_bank = touch_controller.create_acquisition_bank(TscAcquisitionBankPins { + g2_pin: Some(sensor0), + g7_pin: Some(sensor1), + ..Default::default() + }); + + touch_controller.set_active_channels_bank(&acquisition_bank); - let mut group_two_val = 0; - let mut group_seven_val = 0; info!("Starting touch_controller interface"); loop { + touch_controller.start(); touch_controller.pend_for_acquisition().await; touch_controller.discharge_io(true); Timer::after_millis(1).await; - if touch_controller.group_get_status(Group::Two) == GroupStatus::Complete { - group_two_val = touch_controller.group_get_value(Group::Two); + let status = touch_controller.get_acquisition_bank_status(&acquisition_bank); + + if status.all_complete() { + let read_values = touch_controller.get_acquisition_bank_values(&acquisition_bank); + let group2_reading = read_values.get_group_reading(Group::Two).unwrap(); + let group7_reading = read_values.get_group_reading(Group::Seven).unwrap(); + info!("group 2 value: {}", group2_reading.sensor_value); + info!("group 7 value: {}", group7_reading.sensor_value); } - - if touch_controller.group_get_status(Group::Seven) == GroupStatus::Complete { - group_seven_val = touch_controller.group_get_value(Group::Seven); - } - - info!( - "Group Two value: {}, Group Seven value: {},", - group_two_val, group_seven_val - ); - - touch_controller.start(); } } From a5b34a7980edaba5d8de05c68a48972dd9239f75 Mon Sep 17 00:00:00 2001 From: michel Date: Thu, 10 Oct 2024 14:53:04 +0200 Subject: [PATCH 0410/1217] stm32 multipin examples: remove check for group status since we are using the async pending method --- examples/stm32l0/src/bin/tsc_multipin.rs | 28 ++---------------------- examples/stm32l4/src/bin/tsc_multipin.rs | 28 ++---------------------- 2 files changed, 4 insertions(+), 52 deletions(-) diff --git a/examples/stm32l0/src/bin/tsc_multipin.rs b/examples/stm32l0/src/bin/tsc_multipin.rs index 6170d0799..85feb50b0 100644 --- a/examples/stm32l0/src/bin/tsc_multipin.rs +++ b/examples/stm32l0/src/bin/tsc_multipin.rs @@ -74,26 +74,6 @@ bind_interrupts!(struct Irqs { TSC => InterruptHandler; }); -const MAX_GROUP_STATUS_READ_ATTEMPTS: usize = 10; - -async fn read_touch_values( - touch_controller: &mut tsc::Tsc<'_, peripherals::TSC, mode::Async>, - tsc_acquisition_bank: &TscAcquisitionBank, -) -> Option { - for _ in 0..MAX_GROUP_STATUS_READ_ATTEMPTS { - let status = touch_controller.get_acquisition_bank_status(tsc_acquisition_bank); - if status.all_complete() { - let r = touch_controller.get_acquisition_bank_values(tsc_acquisition_bank); - return Some(r); - } else { - info!("Acquisition still ongoing"); - Timer::after_millis(1).await; - } - } - info!("Acquisition failed after {} attempts", MAX_GROUP_STATUS_READ_ATTEMPTS); - None -} - const SENSOR_THRESHOLD: u16 = 35; async fn acquire_sensors( @@ -174,13 +154,9 @@ async fn main(_spawner: embassy_executor::Spawner) { loop { acquire_sensors(&mut touch_controller, &bank1).await; - let readings1: TscAcquisitionBankReadings = read_touch_values(&mut touch_controller, &bank1) - .await - .expect("should be able to read values for bank 1"); + let readings1 = touch_controller.get_acquisition_bank_values(&bank1); acquire_sensors(&mut touch_controller, &bank2).await; - let readings2: TscAcquisitionBankReadings = read_touch_values(&mut touch_controller, &bank2) - .await - .expect("should be able to read values for bank 2"); + let readings2 = touch_controller.get_acquisition_bank_values(&bank1); let mut touched_sensors_count = 0; for reading in readings1.iter() { diff --git a/examples/stm32l4/src/bin/tsc_multipin.rs b/examples/stm32l4/src/bin/tsc_multipin.rs index 20a559514..f26a6f4eb 100644 --- a/examples/stm32l4/src/bin/tsc_multipin.rs +++ b/examples/stm32l4/src/bin/tsc_multipin.rs @@ -70,26 +70,6 @@ bind_interrupts!(struct Irqs { TSC => InterruptHandler; }); -const MAX_GROUP_STATUS_READ_ATTEMPTS: usize = 10; - -async fn read_touch_values( - touch_controller: &mut tsc::Tsc<'_, peripherals::TSC, mode::Async>, - tsc_acquisition_bank: &TscAcquisitionBank, -) -> Option { - for _ in 0..MAX_GROUP_STATUS_READ_ATTEMPTS { - let status = touch_controller.get_acquisition_bank_status(tsc_acquisition_bank); - if status.all_complete() { - let r = touch_controller.get_acquisition_bank_values(tsc_acquisition_bank); - return Some(r); - } else { - info!("Acquisition still ongoing"); - Timer::after_millis(1).await; - } - } - info!("Acquisition failed after {} attempts", MAX_GROUP_STATUS_READ_ATTEMPTS); - None -} - const SENSOR_THRESHOLD: u16 = 20; async fn acquire_sensors( @@ -169,13 +149,9 @@ async fn main(_spawner: embassy_executor::Spawner) { loop { acquire_sensors(&mut touch_controller, &bank1).await; - let readings1: TscAcquisitionBankReadings = read_touch_values(&mut touch_controller, &bank1) - .await - .expect("should be able to read values for bank 1"); + let readings1 = touch_controller.get_acquisition_bank_values(&bank1); acquire_sensors(&mut touch_controller, &bank2).await; - let readings2: TscAcquisitionBankReadings = read_touch_values(&mut touch_controller, &bank2) - .await - .expect("should be able to read values for bank 2"); + let readings2 = touch_controller.get_acquisition_bank_values(&bank2); let mut touched_sensors_count = 0; for reading in readings1.iter().chain(readings2.iter()) { From 31da5155e840d97e432cf2fa06c6fa4c2a19bf9a Mon Sep 17 00:00:00 2001 From: michel Date: Thu, 10 Oct 2024 15:14:53 +0200 Subject: [PATCH 0411/1217] Refactor TSC module: Remove redundant 'Tsc' prefixes for improved naming consistency --- embassy-stm32/src/tsc/acquisition_banks.rs | 108 +++++------ embassy-stm32/src/tsc/io_pin.rs | 200 +++++++++++++++++++++ embassy-stm32/src/tsc/mod.rs | 4 +- embassy-stm32/src/tsc/pin_groups.rs | 136 +++++++------- embassy-stm32/src/tsc/tsc.rs | 58 +++--- embassy-stm32/src/tsc/tsc_io_pin.rs | 200 --------------------- examples/stm32f3/src/bin/tsc_blocking.rs | 6 +- examples/stm32l0/src/bin/tsc_async.rs | 4 +- examples/stm32l0/src/bin/tsc_blocking.rs | 6 +- examples/stm32l0/src/bin/tsc_multipin.rs | 10 +- examples/stm32l4/src/bin/tsc_async.rs | 4 +- examples/stm32l4/src/bin/tsc_blocking.rs | 6 +- examples/stm32l4/src/bin/tsc_multipin.rs | 12 +- examples/stm32u5/src/bin/tsc.rs | 10 +- 14 files changed, 379 insertions(+), 385 deletions(-) create mode 100644 embassy-stm32/src/tsc/io_pin.rs delete mode 100644 embassy-stm32/src/tsc/tsc_io_pin.rs diff --git a/embassy-stm32/src/tsc/acquisition_banks.rs b/embassy-stm32/src/tsc/acquisition_banks.rs index 21a5c3f87..6791ef6c1 100644 --- a/embassy-stm32/src/tsc/acquisition_banks.rs +++ b/embassy-stm32/src/tsc/acquisition_banks.rs @@ -1,69 +1,69 @@ +use super::io_pin::*; #[cfg(any(tsc_v2, tsc_v3))] use super::pin_groups::G7; #[cfg(tsc_v3)] use super::pin_groups::G8; -use super::pin_groups::{tsc_pin_roles, G1, G2, G3, G4, G5, G6}; -use super::tsc_io_pin::*; +use super::pin_groups::{pin_roles, G1, G2, G3, G4, G5, G6}; use super::types::{Group, GroupStatus}; use super::TSC_NUM_GROUPS; /// Represents a collection of TSC (Touch Sensing Controller) pins for an acquisition bank. /// -/// This struct holds optional `TscIOPin` values for each TSC group, allowing for flexible +/// This struct holds optional `tsc::IOPin` values for each TSC group, allowing for flexible /// configuration of TSC acquisition banks. Each field corresponds to a specific TSC group -/// and can be set to `Some(TscIOPin)` if that group is to be included in the acquisition, +/// and can be set to `Some(tsc::IOPin)` if that group is to be included in the acquisition, /// or `None` if it should be excluded. #[allow(missing_docs)] #[derive(Default)] -pub struct TscAcquisitionBankPins { - pub g1_pin: Option>, - pub g2_pin: Option>, - pub g3_pin: Option>, - pub g4_pin: Option>, - pub g5_pin: Option>, - pub g6_pin: Option>, +pub struct AcquisitionBankPins { + pub g1_pin: Option>, + pub g2_pin: Option>, + pub g3_pin: Option>, + pub g4_pin: Option>, + pub g5_pin: Option>, + pub g6_pin: Option>, #[cfg(any(tsc_v2, tsc_v3))] - pub g7_pin: Option>, + pub g7_pin: Option>, #[cfg(tsc_v3)] - pub g8_pin: Option>, + pub g8_pin: Option>, } -impl TscAcquisitionBankPins { +impl AcquisitionBankPins { /// Returns an iterator over the pins in this acquisition bank. /// /// This method allows for easy traversal of all configured pins in the bank. - pub fn iter(&self) -> TscAcquisitionBankPinsIterator { - TscAcquisitionBankPinsIterator(TscAcquisitionBankIterator::new(self)) + pub fn iter(&self) -> AcquisitionBankPinsIterator { + AcquisitionBankPinsIterator(AcquisitionBankIterator::new(self)) } } /// Iterator for TSC acquisition banks. /// -/// This iterator allows traversing through the pins of a `TscAcquisitionBankPins` struct, +/// This iterator allows traversing through the pins of a `AcquisitionBankPins` struct, /// yielding each configured pin in order of the TSC groups. -pub struct TscAcquisitionBankIterator<'a> { - pins: &'a TscAcquisitionBankPins, +pub struct AcquisitionBankIterator<'a> { + pins: &'a AcquisitionBankPins, current_group: u8, } -impl<'a> TscAcquisitionBankIterator<'a> { - fn new(pins: &'a TscAcquisitionBankPins) -> Self { +impl<'a> AcquisitionBankIterator<'a> { + fn new(pins: &'a AcquisitionBankPins) -> Self { Self { pins, current_group: 0 } } - fn next_pin(&mut self) -> Option { + fn next_pin(&mut self) -> Option { while self.current_group < TSC_NUM_GROUPS as u8 { let pin = match self.current_group { - 0 => self.pins.g1_pin.map(TscIOPinWithRole::get_pin), - 1 => self.pins.g2_pin.map(TscIOPinWithRole::get_pin), - 2 => self.pins.g3_pin.map(TscIOPinWithRole::get_pin), - 3 => self.pins.g4_pin.map(TscIOPinWithRole::get_pin), - 4 => self.pins.g5_pin.map(TscIOPinWithRole::get_pin), - 5 => self.pins.g6_pin.map(TscIOPinWithRole::get_pin), + 0 => self.pins.g1_pin.map(IOPinWithRole::get_pin), + 1 => self.pins.g2_pin.map(IOPinWithRole::get_pin), + 2 => self.pins.g3_pin.map(IOPinWithRole::get_pin), + 3 => self.pins.g4_pin.map(IOPinWithRole::get_pin), + 4 => self.pins.g5_pin.map(IOPinWithRole::get_pin), + 5 => self.pins.g6_pin.map(IOPinWithRole::get_pin), #[cfg(any(tsc_v2, tsc_v3))] - 6 => self.pins.g7_pin.map(TscIOPinWithRole::get_pin), + 6 => self.pins.g7_pin.map(IOPinWithRole::get_pin), #[cfg(tsc_v3)] - 7 => self.pins.g8_pin.map(TscIOPinWithRole::get_pin), + 7 => self.pins.g8_pin.map(IOPinWithRole::get_pin), _ => None, }; self.current_group += 1; @@ -77,21 +77,21 @@ impl<'a> TscAcquisitionBankIterator<'a> { /// Iterator for TSC acquisition bank pins. /// -/// This iterator yields `TscIOPin` values for each configured pin in the acquisition bank. -pub struct TscAcquisitionBankPinsIterator<'a>(TscAcquisitionBankIterator<'a>); +/// This iterator yields `tsc::IOPin` values for each configured pin in the acquisition bank. +pub struct AcquisitionBankPinsIterator<'a>(AcquisitionBankIterator<'a>); -impl<'a> Iterator for TscAcquisitionBankPinsIterator<'a> { - type Item = TscIOPin; +impl<'a> Iterator for AcquisitionBankPinsIterator<'a> { + type Item = IOPin; fn next(&mut self) -> Option { self.0.next_pin() } } -impl TscAcquisitionBankPins { +impl AcquisitionBankPins { /// Returns an iterator over the available pins in the bank - pub fn pins_iterator(&self) -> TscAcquisitionBankPinsIterator { - TscAcquisitionBankPinsIterator(TscAcquisitionBankIterator::new(self)) + pub fn pins_iterator(&self) -> AcquisitionBankPinsIterator { + AcquisitionBankPinsIterator(AcquisitionBankIterator::new(self)) } } @@ -100,14 +100,14 @@ impl TscAcquisitionBankPins { /// This struct contains a set of pins to be used in a TSC acquisition with a pre-computed and /// verified mask for efficiently setting up the TSC peripheral before performing an acquisition. /// It ensures that only one channel pin per TSC group is included, adhering to hardware limitations. -pub struct TscAcquisitionBank { - pub(super) pins: TscAcquisitionBankPins, +pub struct AcquisitionBank { + pub(super) pins: AcquisitionBankPins, pub(super) mask: u32, } -impl TscAcquisitionBank { +impl AcquisitionBank { /// Returns an iterator over the available pins in the bank. - pub fn pins_iterator(&self) -> TscAcquisitionBankPinsIterator { + pub fn pins_iterator(&self) -> AcquisitionBankPinsIterator { self.pins.pins_iterator() } @@ -122,8 +122,8 @@ impl TscAcquisitionBank { /// * `group` - The TSC group to retrieve the pin for. /// /// # Returns - /// An `Option` containing the pin if it exists for the given group, or `None` if not. - pub fn get_pin(&self, group: Group) -> Option { + /// An `Option` containing the pin if it exists for the given group, or `None` if not. + pub fn get_pin(&self, group: Group) -> Option { match group { Group::One => self.pins.g1_pin.map(|p| p.pin), Group::Two => self.pins.g2_pin.map(|p| p.pin), @@ -141,11 +141,11 @@ impl TscAcquisitionBank { /// Represents the status of all TSC groups in an acquisition bank #[derive(Default)] -pub struct TscAcquisitionBankStatus { +pub struct AcquisitionBankStatus { pub(super) groups: [Option; TSC_NUM_GROUPS], } -impl TscAcquisitionBankStatus { +impl AcquisitionBankStatus { /// Check if all groups in the bank are complete pub fn all_complete(&self) -> bool { self.groups @@ -174,36 +174,36 @@ impl TscAcquisitionBankStatus { /// Represents the result of a Touch Sensing Controller (TSC) acquisition for a specific pin. /// -/// This struct contains a reference to the `TscIOPin` from which a value was read, +/// This struct contains a reference to the `tsc::IOPin` from which a value was read, /// along with the actual sensor reading for that pin. It provides a convenient way /// to associate TSC readings with their corresponding pins after an acquisition. #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[derive(Clone, Copy, Debug)] -pub struct TscChannelReading { +pub struct ChannelReading { /// The sensor reading value obtained from the TSC acquisition. /// Lower values typically indicate a detected touch, while higher values indicate no touch. pub sensor_value: u16, - /// The `TscIOPin` associated with this reading. + /// The `tsc::IOPin` associated with this reading. /// This allows for easy identification of which pin the reading corresponds to. - pub tsc_pin: TscIOPin, + pub tsc_pin: IOPin, } /// Represents the readings from all TSC groups #[derive(Default)] -pub struct TscAcquisitionBankReadings { - pub(super) groups: [Option; TSC_NUM_GROUPS], +pub struct AcquisitionBankReadings { + pub(super) groups: [Option; TSC_NUM_GROUPS], } -impl TscAcquisitionBankReadings { +impl AcquisitionBankReadings { /// Get the reading for a specific group, if the group is present in the bank - pub fn get_group_reading(&self, group: Group) -> Option { + pub fn get_group_reading(&self, group: Group) -> Option { let index: usize = group.into(); self.groups[index] } /// Iterator for readings for groups present in the bank - pub fn iter(&self) -> impl Iterator + '_ { + pub fn iter(&self) -> impl Iterator + '_ { self.groups.iter().filter_map(|&x| x) } } diff --git a/embassy-stm32/src/tsc/io_pin.rs b/embassy-stm32/src/tsc/io_pin.rs new file mode 100644 index 000000000..ad2010ed7 --- /dev/null +++ b/embassy-stm32/src/tsc/io_pin.rs @@ -0,0 +1,200 @@ +use core::marker::PhantomData; +use core::ops::{BitAnd, BitOr, BitOrAssign}; + +use super::pin_roles; +use super::types::Group; + +/// Pin defines +#[allow(missing_docs)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[derive(PartialEq, Clone, Copy, Debug)] +pub enum IOPin { + Group1Io1, + Group1Io2, + Group1Io3, + Group1Io4, + Group2Io1, + Group2Io2, + Group2Io3, + Group2Io4, + Group3Io1, + Group3Io2, + Group3Io3, + Group3Io4, + Group4Io1, + Group4Io2, + Group4Io3, + Group4Io4, + Group5Io1, + Group5Io2, + Group5Io3, + Group5Io4, + Group6Io1, + Group6Io2, + Group6Io3, + Group6Io4, + #[cfg(any(tsc_v2, tsc_v3))] + Group7Io1, + #[cfg(any(tsc_v2, tsc_v3))] + Group7Io2, + #[cfg(any(tsc_v2, tsc_v3))] + Group7Io3, + #[cfg(any(tsc_v2, tsc_v3))] + Group7Io4, + #[cfg(tsc_v3)] + Group8Io1, + #[cfg(tsc_v3)] + Group8Io2, + #[cfg(tsc_v3)] + Group8Io3, + #[cfg(tsc_v3)] + Group8Io4, +} + +/// Represents a TSC I/O pin with associated group and role information. +/// +/// This type combines an `tsc::IOPin` with phantom type parameters to statically +/// encode the pin's group and role. This allows for type-safe operations +/// on TSC pins within their specific contexts. +/// +/// - `Group`: A type parameter representing the TSC group (e.g., `G1`, `G2`). +/// - `Role`: A type parameter representing the pin's role (e.g., `Channel`, `Sample`). +#[derive(Clone, Copy, Debug)] +pub struct IOPinWithRole { + /// The underlying TSC I/O pin. + pub pin: IOPin, + pub(super) phantom: PhantomData<(Group, Role)>, +} + +impl IOPinWithRole { + pub(super) fn get_pin(wrapped_pin: IOPinWithRole) -> IOPin { + wrapped_pin.pin + } +} + +impl IOPin { + /// Maps this IOPin to the Group it belongs to. + /// + /// This method provides a convenient way to determine which Group + /// a specific TSC I/O pin is associated with. + pub const fn group(&self) -> Group { + match self { + IOPin::Group1Io1 | IOPin::Group1Io2 | IOPin::Group1Io3 | IOPin::Group1Io4 => Group::One, + IOPin::Group2Io1 | IOPin::Group2Io2 | IOPin::Group2Io3 | IOPin::Group2Io4 => Group::Two, + IOPin::Group3Io1 | IOPin::Group3Io2 | IOPin::Group3Io3 | IOPin::Group3Io4 => Group::Three, + IOPin::Group4Io1 | IOPin::Group4Io2 | IOPin::Group4Io3 | IOPin::Group4Io4 => Group::Four, + IOPin::Group5Io1 | IOPin::Group5Io2 | IOPin::Group5Io3 | IOPin::Group5Io4 => Group::Five, + IOPin::Group6Io1 | IOPin::Group6Io2 | IOPin::Group6Io3 | IOPin::Group6Io4 => Group::Six, + #[cfg(any(tsc_v2, tsc_v3))] + IOPin::Group7Io1 | IOPin::Group7Io2 | IOPin::Group7Io3 | IOPin::Group7Io4 => Group::Seven, + #[cfg(tsc_v3)] + IOPin::Group8Io1 | IOPin::Group8Io2 | IOPin::Group8Io3 | IOPin::Group8Io4 => Group::Eight, + } + } + + /// Returns the `Group` associated with the given `IOPin`. + pub fn get_group(pin: IOPin) -> Group { + pin.group() + } +} + +impl BitOr for u32 { + type Output = u32; + fn bitor(self, rhs: IOPin) -> Self::Output { + let rhs: u32 = rhs.into(); + self | rhs + } +} + +impl BitOr for IOPin { + type Output = u32; + fn bitor(self, rhs: u32) -> Self::Output { + let val: u32 = self.into(); + val | rhs + } +} + +impl BitOr for IOPin { + type Output = u32; + fn bitor(self, rhs: Self) -> Self::Output { + let val: u32 = self.into(); + let rhs: u32 = rhs.into(); + val | rhs + } +} + +impl BitOrAssign for u32 { + fn bitor_assign(&mut self, rhs: IOPin) { + let rhs: u32 = rhs.into(); + *self |= rhs; + } +} + +impl BitAnd for u32 { + type Output = u32; + fn bitand(self, rhs: IOPin) -> Self::Output { + let rhs: u32 = rhs.into(); + self & rhs + } +} + +impl BitAnd for IOPin { + type Output = u32; + fn bitand(self, rhs: u32) -> Self::Output { + let val: u32 = self.into(); + val & rhs + } +} + +impl IOPin { + const fn to_u32(self) -> u32 { + match self { + IOPin::Group1Io1 => 0x00000001, + IOPin::Group1Io2 => 0x00000002, + IOPin::Group1Io3 => 0x00000004, + IOPin::Group1Io4 => 0x00000008, + IOPin::Group2Io1 => 0x00000010, + IOPin::Group2Io2 => 0x00000020, + IOPin::Group2Io3 => 0x00000040, + IOPin::Group2Io4 => 0x00000080, + IOPin::Group3Io1 => 0x00000100, + IOPin::Group3Io2 => 0x00000200, + IOPin::Group3Io3 => 0x00000400, + IOPin::Group3Io4 => 0x00000800, + IOPin::Group4Io1 => 0x00001000, + IOPin::Group4Io2 => 0x00002000, + IOPin::Group4Io3 => 0x00004000, + IOPin::Group4Io4 => 0x00008000, + IOPin::Group5Io1 => 0x00010000, + IOPin::Group5Io2 => 0x00020000, + IOPin::Group5Io3 => 0x00040000, + IOPin::Group5Io4 => 0x00080000, + IOPin::Group6Io1 => 0x00100000, + IOPin::Group6Io2 => 0x00200000, + IOPin::Group6Io3 => 0x00400000, + IOPin::Group6Io4 => 0x00800000, + #[cfg(any(tsc_v2, tsc_v3))] + IOPin::Group7Io1 => 0x01000000, + #[cfg(any(tsc_v2, tsc_v3))] + IOPin::Group7Io2 => 0x02000000, + #[cfg(any(tsc_v2, tsc_v3))] + IOPin::Group7Io3 => 0x04000000, + #[cfg(any(tsc_v2, tsc_v3))] + IOPin::Group7Io4 => 0x08000000, + #[cfg(tsc_v3)] + IOPin::Group8Io1 => 0x10000000, + #[cfg(tsc_v3)] + IOPin::Group8Io2 => 0x20000000, + #[cfg(tsc_v3)] + IOPin::Group8Io3 => 0x40000000, + #[cfg(tsc_v3)] + IOPin::Group8Io4 => 0x80000000, + } + } +} + +impl Into for IOPin { + fn into(self) -> u32 { + self.to_u32() + } +} diff --git a/embassy-stm32/src/tsc/mod.rs b/embassy-stm32/src/tsc/mod.rs index 2df3847bc..0d5c27465 100644 --- a/embassy-stm32/src/tsc/mod.rs +++ b/embassy-stm32/src/tsc/mod.rs @@ -80,7 +80,7 @@ pub mod config; pub mod pin_groups; /// Definitions and implementations for individual TSC I/O pins. -pub mod tsc_io_pin; +pub mod io_pin; /// Structures and implementations for TSC acquisition banks. pub mod acquisition_banks; @@ -100,9 +100,9 @@ pub use acquisition_banks::*; pub use config::*; use embassy_sync::waitqueue::AtomicWaker; pub use errors::*; +pub use io_pin::*; pub use pin_groups::*; pub use tsc::*; -pub use tsc_io_pin::*; pub use types::*; use crate::rcc::RccPeripheral; diff --git a/embassy-stm32/src/tsc/pin_groups.rs b/embassy-stm32/src/tsc/pin_groups.rs index b15890d6f..1f3aafa35 100644 --- a/embassy-stm32/src/tsc/pin_groups.rs +++ b/embassy-stm32/src/tsc/pin_groups.rs @@ -4,7 +4,7 @@ use core::ops::BitOr; use embassy_hal_internal::{into_ref, PeripheralRef}; use super::errors::GroupError; -use super::tsc_io_pin::*; +use super::io_pin::*; use super::Instance; use crate::gpio::{AfType, AnyPin, OutputType, Speed}; use crate::Peripheral; @@ -22,14 +22,14 @@ pub enum PinType { /// Pin struct that maintains usage #[allow(missing_docs)] -pub struct TscPin<'d, T, Group> { +pub struct Pin<'d, T, Group> { _pin: PeripheralRef<'d, AnyPin>, role: PinType, - tsc_io_pin: TscIOPin, + tsc_io_pin: IOPin, phantom: PhantomData<(T, Group)>, } -impl<'d, T, Group> TscPin<'d, T, Group> { +impl<'d, T, Group> Pin<'d, T, Group> { /// Returns the role of this TSC pin. /// /// The role indicates whether this pin is configured as a channel, @@ -47,8 +47,8 @@ impl<'d, T, Group> TscPin<'d, T, Group> { /// which includes information about the pin's group and position within that group. /// /// # Returns - /// The `TscIOPin` representing this pin's TSC-specific configuration. - pub fn tsc_io_pin(&self) -> TscIOPin { + /// The `IOPin` representing this pin's TSC-specific configuration. + pub fn tsc_io_pin(&self) -> IOPin { self.tsc_io_pin } } @@ -71,10 +71,10 @@ impl<'d, T, Group> TscPin<'d, T, Group> { /// - No more than one shield pin is allowed across all groups. #[allow(missing_docs)] pub struct PinGroup<'d, T, Group> { - pin1: Option>, - pin2: Option>, - pin3: Option>, - pin4: Option>, + pin1: Option>, + pin2: Option>, + pin3: Option>, + pin4: Option>, } impl<'d, T, G> Default for PinGroup<'d, T, G> { @@ -92,7 +92,7 @@ impl<'d, T, G> Default for PinGroup<'d, T, G> { /// /// This module contains marker types and traits that represent different roles /// a TSC pin can have, such as channel, sample, or shield. -pub mod tsc_pin_roles { +pub mod pin_roles { use super::{OutputType, PinType}; /// Marker type for a TSC channel pin. @@ -162,10 +162,10 @@ pub struct PinGroupWithRoles< 'd, T: Instance, G, - R1 = tsc_pin_roles::Channel, - R2 = tsc_pin_roles::Channel, - R3 = tsc_pin_roles::Channel, - R4 = tsc_pin_roles::Channel, + R1 = pin_roles::Channel, + R2 = pin_roles::Channel, + R3 = pin_roles::Channel, + R4 = pin_roles::Channel, > { /// The underlying pin group without role information. pub pin_group: PinGroup<'d, T, G>, @@ -230,38 +230,38 @@ impl<'d, T: Instance, G> PinGroup<'d, T, G> { } /// Returns a reference to the first pin in the group, if configured. - pub fn pin1(&self) -> Option<&TscPin<'d, T, G>> { + pub fn pin1(&self) -> Option<&Pin<'d, T, G>> { self.pin1.as_ref() } /// Returns a reference to the second pin in the group, if configured. - pub fn pin2(&self) -> Option<&TscPin<'d, T, G>> { + pub fn pin2(&self) -> Option<&Pin<'d, T, G>> { self.pin2.as_ref() } /// Returns a reference to the third pin in the group, if configured. - pub fn pin3(&self) -> Option<&TscPin<'d, T, G>> { + pub fn pin3(&self) -> Option<&Pin<'d, T, G>> { self.pin3.as_ref() } /// Returns a reference to the fourth pin in the group, if configured. - pub fn pin4(&self) -> Option<&TscPin<'d, T, G>> { + pub fn pin4(&self) -> Option<&Pin<'d, T, G>> { self.pin4.as_ref() } - fn sample_pins(&self) -> impl Iterator + '_ { + fn sample_pins(&self) -> impl Iterator + '_ { self.pins_filtered(PinType::Sample) } - fn shield_pins(&self) -> impl Iterator + '_ { + fn shield_pins(&self) -> impl Iterator + '_ { self.pins_filtered(PinType::Shield) } - fn channel_pins(&self) -> impl Iterator + '_ { + fn channel_pins(&self) -> impl Iterator + '_ { self.pins_filtered(PinType::Channel) } - fn pins_filtered(&self, pin_type: PinType) -> impl Iterator + '_ { + fn pins_filtered(&self, pin_type: PinType) -> impl Iterator + '_ { self.pins().into_iter().filter_map(move |pin| { pin.as_ref() .and_then(|p| if p.role == pin_type { Some(p.tsc_io_pin) } else { None }) @@ -280,11 +280,11 @@ impl<'d, T: Instance, G> PinGroup<'d, T, G> { self.sample_pins().fold(0, u32::bitor) } - fn pins(&self) -> [&Option>; 4] { + fn pins(&self) -> [&Option>; 4] { [&self.pin1, &self.pin2, &self.pin3, &self.pin4] } - fn pins_mut(&mut self) -> [&mut Option>; 4] { + fn pins_mut(&mut self) -> [&mut Option>; 4] { [&mut self.pin1, &mut self.pin2, &mut self.pin3, &mut self.pin4] } } @@ -317,132 +317,132 @@ macro_rules! TSC_V3_GUARD { }}; } -macro_rules! trait_to_tsc_io_pin { +macro_rules! trait_to_io_pin { (G1IO1Pin) => { - TscIOPin::Group1Io1 + IOPin::Group1Io1 }; (G1IO2Pin) => { - TscIOPin::Group1Io2 + IOPin::Group1Io2 }; (G1IO3Pin) => { - TscIOPin::Group1Io3 + IOPin::Group1Io3 }; (G1IO4Pin) => { - TscIOPin::Group1Io4 + IOPin::Group1Io4 }; (G2IO1Pin) => { - TscIOPin::Group2Io1 + IOPin::Group2Io1 }; (G2IO2Pin) => { - TscIOPin::Group2Io2 + IOPin::Group2Io2 }; (G2IO3Pin) => { - TscIOPin::Group2Io3 + IOPin::Group2Io3 }; (G2IO4Pin) => { - TscIOPin::Group2Io4 + IOPin::Group2Io4 }; (G3IO1Pin) => { - TscIOPin::Group3Io1 + IOPin::Group3Io1 }; (G3IO2Pin) => { - TscIOPin::Group3Io2 + IOPin::Group3Io2 }; (G3IO3Pin) => { - TscIOPin::Group3Io3 + IOPin::Group3Io3 }; (G3IO4Pin) => { - TscIOPin::Group3Io4 + IOPin::Group3Io4 }; (G4IO1Pin) => { - TscIOPin::Group4Io1 + IOPin::Group4Io1 }; (G4IO2Pin) => { - TscIOPin::Group4Io2 + IOPin::Group4Io2 }; (G4IO3Pin) => { - TscIOPin::Group4Io3 + IOPin::Group4Io3 }; (G4IO4Pin) => { - TscIOPin::Group4Io4 + IOPin::Group4Io4 }; (G5IO1Pin) => { - TscIOPin::Group5Io1 + IOPin::Group5Io1 }; (G5IO2Pin) => { - TscIOPin::Group5Io2 + IOPin::Group5Io2 }; (G5IO3Pin) => { - TscIOPin::Group5Io3 + IOPin::Group5Io3 }; (G5IO4Pin) => { - TscIOPin::Group5Io4 + IOPin::Group5Io4 }; (G6IO1Pin) => { - TscIOPin::Group6Io1 + IOPin::Group6Io1 }; (G6IO2Pin) => { - TscIOPin::Group6Io2 + IOPin::Group6Io2 }; (G6IO3Pin) => { - TscIOPin::Group6Io3 + IOPin::Group6Io3 }; (G6IO4Pin) => { - TscIOPin::Group6Io4 + IOPin::Group6Io4 }; (G7IO1Pin) => { - TSC_V2_V3_GUARD!(TscIOPin::Group7Io1) + TSC_V2_V3_GUARD!(IOPin::Group7Io1) }; (G7IO2Pin) => { - TSC_V2_V3_GUARD!(TscIOPin::Group7Io2) + TSC_V2_V3_GUARD!(IOPin::Group7Io2) }; (G7IO3Pin) => { - TSC_V2_V3_GUARD!(TscIOPin::Group7Io3) + TSC_V2_V3_GUARD!(IOPin::Group7Io3) }; (G7IO4Pin) => { - TSC_V2_V3_GUARD!(TscIOPin::Group7Io4) + TSC_V2_V3_GUARD!(IOPin::Group7Io4) }; (G8IO1Pin) => { - TSC_V3_GUARD!(TscIOPin::Group8Io1) + TSC_V3_GUARD!(IOPin::Group8Io1) }; (G8IO2Pin) => { - TSC_V3_GUARD!(TscIOPin::Group8Io2) + TSC_V3_GUARD!(IOPin::Group8Io2) }; (G8IO3Pin) => { - TSC_V3_GUARD!(TscIOPin::Group8Io3) + TSC_V3_GUARD!(IOPin::Group8Io3) }; (G8IO4Pin) => { - TSC_V3_GUARD!(TscIOPin::Group8Io4) + TSC_V3_GUARD!(IOPin::Group8Io4) }; } macro_rules! impl_set_io { ($method:ident, $group:ident, $trait:ident, $index:expr) => { #[doc = concat!("Create a new pin1 for ", stringify!($group), " TSC group instance.")] - pub fn $method( + pub fn $method( &mut self, pin: impl Peripheral

> + 'd, - ) -> TscIOPinWithRole<$group, Role> { + ) -> IOPinWithRole<$group, Role> { into_ref!(pin); critical_section::with(|_| { pin.set_low(); pin.set_as_af(pin.af_num(), AfType::output(Role::output_type(), Speed::VeryHigh)); - let tsc_io_pin = trait_to_tsc_io_pin!($trait); - let new_pin = TscPin { + let tsc_io_pin = trait_to_io_pin!($trait); + let new_pin = Pin { _pin: pin.map_into(), role: Role::pin_type(), tsc_io_pin, phantom: PhantomData, }; *self.pin_group.pins_mut()[$index] = Some(new_pin); - TscIOPinWithRole { + IOPinWithRole { pin: tsc_io_pin, phantom: PhantomData, } @@ -453,14 +453,8 @@ macro_rules! impl_set_io { macro_rules! group_impl { ($group:ident, $trait1:ident, $trait2:ident, $trait3:ident, $trait4:ident) => { - impl< - 'd, - T: Instance, - R1: tsc_pin_roles::Role, - R2: tsc_pin_roles::Role, - R3: tsc_pin_roles::Role, - R4: tsc_pin_roles::Role, - > PinGroupWithRoles<'d, T, $group, R1, R2, R3, R4> + impl<'d, T: Instance, R1: pin_roles::Role, R2: pin_roles::Role, R3: pin_roles::Role, R4: pin_roles::Role> + PinGroupWithRoles<'d, T, $group, R1, R2, R3, R4> { impl_set_io!(set_io1, $group, $trait1, 0); impl_set_io!(set_io2, $group, $trait2, 1); diff --git a/embassy-stm32/src/tsc/tsc.rs b/embassy-stm32/src/tsc/tsc.rs index 58f9d9d2e..17d2da82f 100644 --- a/embassy-stm32/src/tsc/tsc.rs +++ b/embassy-stm32/src/tsc/tsc.rs @@ -8,8 +8,8 @@ use embassy_hal_internal::{into_ref, PeripheralRef}; use super::acquisition_banks::*; use super::config::*; use super::errors::*; +use super::io_pin::*; use super::pin_groups::*; -use super::tsc_io_pin::*; use super::types::*; use super::{Instance, InterruptHandler, TSC_NUM_GROUPS}; use crate::interrupt::typelevel::Interrupt; @@ -20,7 +20,7 @@ use crate::{interrupt, rcc, Peripheral}; /// /// These masks are used during the initial configuration of the TSC peripheral /// and for validating pin types during operations like creating acquisition banks. -struct TscIOMasks { +struct IOMasks { /// Mask representing all configured channel IOs channel_ios: u32, /// Mask representing all configured shield IOs @@ -35,19 +35,19 @@ pub struct Tsc<'d, T: Instance, K: PeriMode> { _pin_groups: PinGroups<'d, T>, state: State, config: Config, - masks: TscIOMasks, + masks: IOMasks, _kind: PhantomData, } impl<'d, T: Instance, K: PeriMode> Tsc<'d, T, K> { // Helper method to check if a pin is a channel pin - fn is_channel_pin(&self, pin: TscIOPin) -> bool { + fn is_channel_pin(&self, pin: IOPin) -> bool { (self.masks.channel_ios & pin) != 0 } - /// Get the status of all groups involved in a TscAcquisitionBank - pub fn get_acquisition_bank_status(&self, bank: &TscAcquisitionBank) -> TscAcquisitionBankStatus { - let mut bank_status = TscAcquisitionBankStatus::default(); + /// Get the status of all groups involved in a AcquisitionBank + pub fn get_acquisition_bank_status(&self, bank: &AcquisitionBank) -> AcquisitionBankStatus { + let mut bank_status = AcquisitionBankStatus::default(); for pin in bank.pins_iterator() { let group = pin.group(); let group_status = self.group_get_status(group); @@ -57,13 +57,13 @@ impl<'d, T: Instance, K: PeriMode> Tsc<'d, T, K> { bank_status } - /// Get the values for all channels involved in a TscAcquisitionBank - pub fn get_acquisition_bank_values(&self, bank: &TscAcquisitionBank) -> TscAcquisitionBankReadings { - let mut bank_readings = TscAcquisitionBankReadings::default(); + /// Get the values for all channels involved in a AcquisitionBank + pub fn get_acquisition_bank_values(&self, bank: &AcquisitionBank) -> AcquisitionBankReadings { + let mut bank_readings = AcquisitionBankReadings::default(); for pin in bank.pins_iterator() { let group = pin.group(); let value = self.group_get_value(group); - let reading = TscChannelReading { + let reading = ChannelReading { sensor_value: value, tsc_pin: pin, }; @@ -75,7 +75,7 @@ impl<'d, T: Instance, K: PeriMode> Tsc<'d, T, K> { /// Creates a new TSC acquisition bank from the provided pin configuration. /// - /// This method creates a `TscAcquisitionBank` that can be used for efficient, + /// This method creates a `AcquisitionBank` that can be used for efficient, /// repeated TSC acquisitions. It automatically generates the appropriate mask /// for the provided pins. /// @@ -87,16 +87,16 @@ impl<'d, T: Instance, K: PeriMode> Tsc<'d, T, K> { /// * `acquisition_bank_pins` - The pin configuration for the acquisition bank. /// /// # Returns - /// A new `TscAcquisitionBank` instance. + /// A new `AcquisitionBank` instance. /// /// # Example /// /// ``` /// let tsc = // ... initialize TSC - /// let tsc_sensor1: TscIOPinWithRole = ...; - /// let tsc_sensor2: TscIOPinWithRole = ...; + /// let tsc_sensor1: tsc::IOPinWithRole = ...; + /// let tsc_sensor2: tsc::IOPinWithRole = ...; /// - /// let bank = tsc.create_acquisition_bank(TscAcquisitionBankPins { + /// let bank = tsc.create_acquisition_bank(AcquisitionBankPins { /// g1_pin: Some(tsc_sensor1), /// g2_pin: Some(tsc_sensor2), /// ..Default::default() @@ -107,10 +107,10 @@ impl<'d, T: Instance, K: PeriMode> Tsc<'d, T, K> { /// tsc.start(); /// // ... perform acquisition ... /// ``` - pub fn create_acquisition_bank(&self, acquisition_bank_pins: TscAcquisitionBankPins) -> TscAcquisitionBank { + pub fn create_acquisition_bank(&self, acquisition_bank_pins: AcquisitionBankPins) -> AcquisitionBank { let bank_mask = acquisition_bank_pins.iter().fold(0u32, BitOr::bitor); - TscAcquisitionBank { + AcquisitionBank { pins: acquisition_bank_pins, mask: bank_mask, } @@ -118,7 +118,7 @@ impl<'d, T: Instance, K: PeriMode> Tsc<'d, T, K> { fn make_channels_mask(&self, channels: Itt) -> Result where - Itt: IntoIterator, + Itt: IntoIterator, { let mut group_mask = 0u32; let mut channel_mask = 0u32; @@ -144,7 +144,7 @@ impl<'d, T: Instance, K: PeriMode> Tsc<'d, T, K> { /// Sets the active channels for the next TSC acquisition. /// /// This is a low-level method that directly sets the channel mask. For most use cases, - /// consider using `set_active_channels_bank` with a `TscAcquisitionBank` instead, which + /// consider using `set_active_channels_bank` with a `AcquisitionBank` instead, which /// provides a higher-level interface and additional safety checks. /// /// This method configures which sensor channels will be read during the next @@ -167,9 +167,9 @@ impl<'d, T: Instance, K: PeriMode> Tsc<'d, T, K> { T::regs().ioccr().write(|w| w.0 = mask | self.masks.shield_ios); } - /// Convenience method for setting active channels directly from a slice of TscIOPin. + /// Convenience method for setting active channels directly from a slice of tsc::IOPin. /// This method performs safety checks but is less efficient for repeated use. - pub fn set_active_channels(&mut self, channels: &[TscIOPin]) -> Result<(), AcquisitionBankError> { + pub fn set_active_channels(&mut self, channels: &[IOPin]) -> Result<(), AcquisitionBankError> { let mask = self.make_channels_mask(channels.iter().cloned())?; self.set_active_channels_mask(mask); Ok(()) @@ -178,21 +178,21 @@ impl<'d, T: Instance, K: PeriMode> Tsc<'d, T, K> { /// Sets the active channels for the next TSC acquisition using a pre-configured acquisition bank. /// /// This method efficiently configures the TSC peripheral to read the channels specified - /// in the provided `TscAcquisitionBank`. It's the recommended way to set up + /// in the provided `AcquisitionBank`. It's the recommended way to set up /// channel configurations for acquisition, especially when using the same set of channels repeatedly. /// /// # Arguments /// - /// * `bank` - A reference to a `TscAcquisitionBank` containing the pre-configured + /// * `bank` - A reference to a `AcquisitionBank` containing the pre-configured /// TSC channel mask. /// /// # Example /// /// ``` - /// let tsc_sensor1: TscIOPinWithRole = ...; - /// let tsc_sensor2: TscIOPinWithRole = ...; + /// let tsc_sensor1: tsc::IOPinWithRole = ...; + /// let tsc_sensor2: tsc::IOPinWithRole = ...; /// let mut touch_controller: Tsc<'_, TSC, Async> = ...; - /// let bank = touch_controller.create_acquisition_bank(TscAcquisitionBankPins { + /// let bank = touch_controller.create_acquisition_bank(AcquisitionBankPins { /// g1_pin: Some(tsc_sensor1), /// g2_pin: Some(tsc_sensor2), /// ..Default::default() @@ -204,7 +204,7 @@ impl<'d, T: Instance, K: PeriMode> Tsc<'d, T, K> { /// ``` /// /// This method should be called before starting a new acquisition with the `start()` method. - pub fn set_active_channels_bank(&mut self, bank: &TscAcquisitionBank) { + pub fn set_active_channels_bank(&mut self, bank: &AcquisitionBank) { self.set_active_channels_mask(bank.mask) } @@ -227,7 +227,7 @@ impl<'d, T: Instance, K: PeriMode> Tsc<'d, T, K> { pin_groups.check()?; - let masks = TscIOMasks { + let masks = IOMasks { channel_ios: pin_groups.make_channel_ios_mask(), shield_ios: pin_groups.make_shield_ios_mask(), sampling_ios: pin_groups.make_sample_ios_mask(), diff --git a/embassy-stm32/src/tsc/tsc_io_pin.rs b/embassy-stm32/src/tsc/tsc_io_pin.rs deleted file mode 100644 index 38b27d0b3..000000000 --- a/embassy-stm32/src/tsc/tsc_io_pin.rs +++ /dev/null @@ -1,200 +0,0 @@ -use core::marker::PhantomData; -use core::ops::{BitAnd, BitOr, BitOrAssign}; - -use super::tsc_pin_roles; -use super::types::Group; - -/// Pin defines -#[allow(missing_docs)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -#[derive(PartialEq, Clone, Copy, Debug)] -pub enum TscIOPin { - Group1Io1, - Group1Io2, - Group1Io3, - Group1Io4, - Group2Io1, - Group2Io2, - Group2Io3, - Group2Io4, - Group3Io1, - Group3Io2, - Group3Io3, - Group3Io4, - Group4Io1, - Group4Io2, - Group4Io3, - Group4Io4, - Group5Io1, - Group5Io2, - Group5Io3, - Group5Io4, - Group6Io1, - Group6Io2, - Group6Io3, - Group6Io4, - #[cfg(any(tsc_v2, tsc_v3))] - Group7Io1, - #[cfg(any(tsc_v2, tsc_v3))] - Group7Io2, - #[cfg(any(tsc_v2, tsc_v3))] - Group7Io3, - #[cfg(any(tsc_v2, tsc_v3))] - Group7Io4, - #[cfg(tsc_v3)] - Group8Io1, - #[cfg(tsc_v3)] - Group8Io2, - #[cfg(tsc_v3)] - Group8Io3, - #[cfg(tsc_v3)] - Group8Io4, -} - -/// Represents a TSC I/O pin with associated group and role information. -/// -/// This type combines a `TscIOPin` with phantom type parameters to statically -/// encode the pin's group and role. This allows for type-safe operations -/// on TSC pins within their specific contexts. -/// -/// - `Group`: A type parameter representing the TSC group (e.g., `G1`, `G2`). -/// - `Role`: A type parameter representing the pin's role (e.g., `Channel`, `Sample`). -#[derive(Clone, Copy, Debug)] -pub struct TscIOPinWithRole { - /// The underlying TSC I/O pin. - pub pin: TscIOPin, - pub(super) phantom: PhantomData<(Group, Role)>, -} - -impl TscIOPinWithRole { - pub(super) fn get_pin(wrapped_pin: TscIOPinWithRole) -> TscIOPin { - wrapped_pin.pin - } -} - -impl TscIOPin { - /// Maps this TscIOPin to the Group it belongs to. - /// - /// This method provides a convenient way to determine which Group - /// a specific TSC I/O pin is associated with. - pub const fn group(&self) -> Group { - match self { - TscIOPin::Group1Io1 | TscIOPin::Group1Io2 | TscIOPin::Group1Io3 | TscIOPin::Group1Io4 => Group::One, - TscIOPin::Group2Io1 | TscIOPin::Group2Io2 | TscIOPin::Group2Io3 | TscIOPin::Group2Io4 => Group::Two, - TscIOPin::Group3Io1 | TscIOPin::Group3Io2 | TscIOPin::Group3Io3 | TscIOPin::Group3Io4 => Group::Three, - TscIOPin::Group4Io1 | TscIOPin::Group4Io2 | TscIOPin::Group4Io3 | TscIOPin::Group4Io4 => Group::Four, - TscIOPin::Group5Io1 | TscIOPin::Group5Io2 | TscIOPin::Group5Io3 | TscIOPin::Group5Io4 => Group::Five, - TscIOPin::Group6Io1 | TscIOPin::Group6Io2 | TscIOPin::Group6Io3 | TscIOPin::Group6Io4 => Group::Six, - #[cfg(any(tsc_v2, tsc_v3))] - TscIOPin::Group7Io1 | TscIOPin::Group7Io2 | TscIOPin::Group7Io3 | TscIOPin::Group7Io4 => Group::Seven, - #[cfg(tsc_v3)] - TscIOPin::Group8Io1 | TscIOPin::Group8Io2 | TscIOPin::Group8Io3 | TscIOPin::Group8Io4 => Group::Eight, - } - } - - /// Returns the `Group` associated with the given `TscIOPin`. - pub fn get_group(pin: TscIOPin) -> Group { - pin.group() - } -} - -impl BitOr for u32 { - type Output = u32; - fn bitor(self, rhs: TscIOPin) -> Self::Output { - let rhs: u32 = rhs.into(); - self | rhs - } -} - -impl BitOr for TscIOPin { - type Output = u32; - fn bitor(self, rhs: u32) -> Self::Output { - let val: u32 = self.into(); - val | rhs - } -} - -impl BitOr for TscIOPin { - type Output = u32; - fn bitor(self, rhs: Self) -> Self::Output { - let val: u32 = self.into(); - let rhs: u32 = rhs.into(); - val | rhs - } -} - -impl BitOrAssign for u32 { - fn bitor_assign(&mut self, rhs: TscIOPin) { - let rhs: u32 = rhs.into(); - *self |= rhs; - } -} - -impl BitAnd for u32 { - type Output = u32; - fn bitand(self, rhs: TscIOPin) -> Self::Output { - let rhs: u32 = rhs.into(); - self & rhs - } -} - -impl BitAnd for TscIOPin { - type Output = u32; - fn bitand(self, rhs: u32) -> Self::Output { - let val: u32 = self.into(); - val & rhs - } -} - -impl TscIOPin { - const fn to_u32(self) -> u32 { - match self { - TscIOPin::Group1Io1 => 0x00000001, - TscIOPin::Group1Io2 => 0x00000002, - TscIOPin::Group1Io3 => 0x00000004, - TscIOPin::Group1Io4 => 0x00000008, - TscIOPin::Group2Io1 => 0x00000010, - TscIOPin::Group2Io2 => 0x00000020, - TscIOPin::Group2Io3 => 0x00000040, - TscIOPin::Group2Io4 => 0x00000080, - TscIOPin::Group3Io1 => 0x00000100, - TscIOPin::Group3Io2 => 0x00000200, - TscIOPin::Group3Io3 => 0x00000400, - TscIOPin::Group3Io4 => 0x00000800, - TscIOPin::Group4Io1 => 0x00001000, - TscIOPin::Group4Io2 => 0x00002000, - TscIOPin::Group4Io3 => 0x00004000, - TscIOPin::Group4Io4 => 0x00008000, - TscIOPin::Group5Io1 => 0x00010000, - TscIOPin::Group5Io2 => 0x00020000, - TscIOPin::Group5Io3 => 0x00040000, - TscIOPin::Group5Io4 => 0x00080000, - TscIOPin::Group6Io1 => 0x00100000, - TscIOPin::Group6Io2 => 0x00200000, - TscIOPin::Group6Io3 => 0x00400000, - TscIOPin::Group6Io4 => 0x00800000, - #[cfg(any(tsc_v2, tsc_v3))] - TscIOPin::Group7Io1 => 0x01000000, - #[cfg(any(tsc_v2, tsc_v3))] - TscIOPin::Group7Io2 => 0x02000000, - #[cfg(any(tsc_v2, tsc_v3))] - TscIOPin::Group7Io3 => 0x04000000, - #[cfg(any(tsc_v2, tsc_v3))] - TscIOPin::Group7Io4 => 0x08000000, - #[cfg(tsc_v3)] - TscIOPin::Group8Io1 => 0x10000000, - #[cfg(tsc_v3)] - TscIOPin::Group8Io2 => 0x20000000, - #[cfg(tsc_v3)] - TscIOPin::Group8Io3 => 0x40000000, - #[cfg(tsc_v3)] - TscIOPin::Group8Io4 => 0x80000000, - } - } -} - -impl Into for TscIOPin { - fn into(self) -> u32 { - self.to_u32() - } -} diff --git a/examples/stm32f3/src/bin/tsc_blocking.rs b/examples/stm32f3/src/bin/tsc_blocking.rs index fa7f718e6..2c33838e5 100644 --- a/examples/stm32f3/src/bin/tsc_blocking.rs +++ b/examples/stm32f3/src/bin/tsc_blocking.rs @@ -64,9 +64,9 @@ async fn main(_spawner: embassy_executor::Spawner) { let mut g: PinGroupWithRoles = PinGroupWithRoles::default(); // D68 on the STM32F303ZE nucleo-board - g.set_io2::(context.PA10); + g.set_io2::(context.PA10); // D69 on the STM32F303ZE nucleo-board - let tsc_sensor = g.set_io1::(context.PA9); + let tsc_sensor = g.set_io1::(context.PA9); let pin_groups: PinGroups = PinGroups { g4: Some(g.pin_group), @@ -119,7 +119,7 @@ const MAX_GROUP_STATUS_READ_ATTEMPTS: usize = 10; // attempt to read group status and delay when still ongoing async fn read_touch_value( touch_controller: &mut tsc::Tsc<'_, peripherals::TSC, mode::Blocking>, - sensor_pin: TscIOPin, + sensor_pin: tsc::IOPin, ) -> Option { for _ in 0..MAX_GROUP_STATUS_READ_ATTEMPTS { match touch_controller.group_get_status(sensor_pin.group()) { diff --git a/examples/stm32l0/src/bin/tsc_async.rs b/examples/stm32l0/src/bin/tsc_async.rs index cebe9712f..dae351c2e 100644 --- a/examples/stm32l0/src/bin/tsc_async.rs +++ b/examples/stm32l0/src/bin/tsc_async.rs @@ -58,8 +58,8 @@ async fn main(_spawner: embassy_executor::Spawner) { let context = embassy_stm32::init(device_config); let mut pin_group: PinGroupWithRoles = PinGroupWithRoles::default(); - pin_group.set_io1::(context.PA0); - let sensor = pin_group.set_io2::(context.PA1); + pin_group.set_io1::(context.PA0); + let sensor = pin_group.set_io2::(context.PA1); let tsc_conf = Config { ct_pulse_high_length: ChargeTransferPulseCycle::_4, diff --git a/examples/stm32l0/src/bin/tsc_blocking.rs b/examples/stm32l0/src/bin/tsc_blocking.rs index 65203925c..e1f24639b 100644 --- a/examples/stm32l0/src/bin/tsc_blocking.rs +++ b/examples/stm32l0/src/bin/tsc_blocking.rs @@ -69,8 +69,8 @@ async fn main(_spawner: embassy_executor::Spawner) { }; let mut g1: PinGroupWithRoles = PinGroupWithRoles::default(); - g1.set_io1::(context.PA0); - let tsc_sensor = g1.set_io2::(context.PA1); + g1.set_io1::(context.PA0); + let tsc_sensor = g1.set_io2::(context.PA1); let pin_groups: PinGroups = PinGroups { g1: Some(g1.pin_group), @@ -123,7 +123,7 @@ const MAX_GROUP_STATUS_READ_ATTEMPTS: usize = 10; // attempt to read group status and delay when still ongoing async fn read_touch_value( touch_controller: &mut tsc::Tsc<'_, peripherals::TSC, mode::Blocking>, - sensor_pin: TscIOPin, + sensor_pin: tsc::IOPin, ) -> Option { for _ in 0..MAX_GROUP_STATUS_READ_ATTEMPTS { match touch_controller.group_get_status(sensor_pin.group()) { diff --git a/examples/stm32l0/src/bin/tsc_multipin.rs b/examples/stm32l0/src/bin/tsc_multipin.rs index 85feb50b0..bf75a5657 100644 --- a/examples/stm32l0/src/bin/tsc_multipin.rs +++ b/examples/stm32l0/src/bin/tsc_multipin.rs @@ -78,7 +78,7 @@ const SENSOR_THRESHOLD: u16 = 35; async fn acquire_sensors( touch_controller: &mut Tsc<'static, peripherals::TSC, mode::Async>, - tsc_acquisition_bank: &TscAcquisitionBank, + tsc_acquisition_bank: &AcquisitionBank, ) { touch_controller.set_active_channels_mask(tsc_acquisition_bank.mask()); touch_controller.start(); @@ -95,11 +95,11 @@ async fn main(_spawner: embassy_executor::Spawner) { // ---------- initial configuration of TSC ---------- let mut pin_group1: PinGroupWithRoles = PinGroupWithRoles::default(); - pin_group1.set_io1::(context.PA0); + pin_group1.set_io1::(context.PA0); let tsc_sensor0 = pin_group1.set_io2(context.PA1); let mut pin_group5: PinGroupWithRoles = PinGroupWithRoles::default(); - pin_group5.set_io1::(context.PB3); + pin_group5.set_io1::(context.PB3); let tsc_sensor1 = pin_group5.set_io2(context.PB4); let tsc_sensor2 = pin_group5.set_io3(context.PB6); @@ -128,14 +128,14 @@ async fn main(_spawner: embassy_executor::Spawner) { // ---------- setting up acquisition banks ---------- // sensor0 and sensor1 in this example belong to different TSC-groups, // therefore we can acquire and read them both in one go. - let bank1 = touch_controller.create_acquisition_bank(TscAcquisitionBankPins { + let bank1 = touch_controller.create_acquisition_bank(AcquisitionBankPins { g1_pin: Some(tsc_sensor0), g5_pin: Some(tsc_sensor1), ..Default::default() }); // `sensor1` and `sensor2` belongs to the same TSC-group, therefore we must make sure to // acquire them one at the time. Therefore, we organize them into different acquisition banks. - let bank2 = touch_controller.create_acquisition_bank(TscAcquisitionBankPins { + let bank2 = touch_controller.create_acquisition_bank(AcquisitionBankPins { g5_pin: Some(tsc_sensor2), ..Default::default() }); diff --git a/examples/stm32l4/src/bin/tsc_async.rs b/examples/stm32l4/src/bin/tsc_async.rs index ada2c468f..b9a059e2e 100644 --- a/examples/stm32l4/src/bin/tsc_async.rs +++ b/examples/stm32l4/src/bin/tsc_async.rs @@ -50,9 +50,9 @@ async fn main(_spawner: embassy_executor::Spawner) { let mut pin_group: PinGroupWithRoles = PinGroupWithRoles::default(); // D25 - pin_group.set_io1::(context.PB4); + pin_group.set_io1::(context.PB4); // D21 - let tsc_sensor = pin_group.set_io2::(context.PB5); + let tsc_sensor = pin_group.set_io2::(context.PB5); let pin_groups: PinGroups = PinGroups { g2: Some(pin_group.pin_group), diff --git a/examples/stm32l4/src/bin/tsc_blocking.rs b/examples/stm32l4/src/bin/tsc_blocking.rs index 76aba55ba..12084f8e2 100644 --- a/examples/stm32l4/src/bin/tsc_blocking.rs +++ b/examples/stm32l4/src/bin/tsc_blocking.rs @@ -74,9 +74,9 @@ async fn main(_spawner: embassy_executor::Spawner) { let mut g2: PinGroupWithRoles = PinGroupWithRoles::default(); // D25 - g2.set_io1::(context.PB4); + g2.set_io1::(context.PB4); // D21 - let tsc_sensor = g2.set_io2::(context.PB5); + let tsc_sensor = g2.set_io2::(context.PB5); let pin_groups: PinGroups = PinGroups { g2: Some(g2.pin_group), @@ -128,7 +128,7 @@ const MAX_GROUP_STATUS_READ_ATTEMPTS: usize = 10; // attempt to read group status and delay when still ongoing async fn read_touch_value( touch_controller: &mut tsc::Tsc<'_, peripherals::TSC, mode::Blocking>, - sensor_pin: TscIOPin, + sensor_pin: tsc::IOPin, ) -> Option { for _ in 0..MAX_GROUP_STATUS_READ_ATTEMPTS { match touch_controller.group_get_status(sensor_pin.group()) { diff --git a/examples/stm32l4/src/bin/tsc_multipin.rs b/examples/stm32l4/src/bin/tsc_multipin.rs index f26a6f4eb..2fadbe16a 100644 --- a/examples/stm32l4/src/bin/tsc_multipin.rs +++ b/examples/stm32l4/src/bin/tsc_multipin.rs @@ -74,7 +74,7 @@ const SENSOR_THRESHOLD: u16 = 20; async fn acquire_sensors( touch_controller: &mut Tsc<'static, peripherals::TSC, mode::Async>, - tsc_acquisition_bank: &TscAcquisitionBank, + tsc_acquisition_bank: &AcquisitionBank, ) { touch_controller.set_active_channels_mask(tsc_acquisition_bank.mask()); touch_controller.start(); @@ -91,11 +91,11 @@ async fn main(_spawner: embassy_executor::Spawner) { // ---------- initial configuration of TSC ---------- let mut g1: PinGroupWithRoles = PinGroupWithRoles::default(); - g1.set_io1::(context.PB12); - let sensor0 = g1.set_io2::(context.PB13); + g1.set_io1::(context.PB12); + let sensor0 = g1.set_io2::(context.PB13); let mut g2: PinGroupWithRoles = PinGroupWithRoles::default(); - g2.set_io1::(context.PB4); + g2.set_io1::(context.PB4); let sensor1 = g2.set_io2(context.PB5); let sensor2 = g2.set_io3(context.PB6); @@ -124,14 +124,14 @@ async fn main(_spawner: embassy_executor::Spawner) { // ---------- setting up acquisition banks ---------- // sensor0 and sensor1 belong to different TSC-groups, therefore we can acquire and // read them both in one go. - let bank1 = touch_controller.create_acquisition_bank(TscAcquisitionBankPins { + let bank1 = touch_controller.create_acquisition_bank(AcquisitionBankPins { g1_pin: Some(sensor0), g2_pin: Some(sensor1), ..Default::default() }); // `sensor1` and `sensor2` belongs to the same TSC-group, therefore we must make sure to // acquire them one at the time. We do this by organizing them into different acquisition banks. - let bank2 = touch_controller.create_acquisition_bank(TscAcquisitionBankPins { + let bank2 = touch_controller.create_acquisition_bank(AcquisitionBankPins { g2_pin: Some(sensor2), ..Default::default() }); diff --git a/examples/stm32u5/src/bin/tsc.rs b/examples/stm32u5/src/bin/tsc.rs index 800486665..a85acc4c7 100644 --- a/examples/stm32u5/src/bin/tsc.rs +++ b/examples/stm32u5/src/bin/tsc.rs @@ -36,15 +36,15 @@ async fn main(_spawner: embassy_executor::Spawner) { }; let mut g1: PinGroupWithRoles = PinGroupWithRoles::default(); - g1.set_io2::(context.PB13); - g1.set_io3::(context.PB14); + g1.set_io2::(context.PB13); + g1.set_io3::(context.PB14); let mut g2: PinGroupWithRoles = PinGroupWithRoles::default(); - g2.set_io1::(context.PB4); + g2.set_io1::(context.PB4); let sensor0 = g2.set_io2(context.PB5); let mut g7: PinGroupWithRoles = PinGroupWithRoles::default(); - g7.set_io2::(context.PE3); + g7.set_io2::(context.PE3); let sensor1 = g7.set_io3(context.PE4); let pin_groups: PinGroups = PinGroups { @@ -56,7 +56,7 @@ async fn main(_spawner: embassy_executor::Spawner) { let mut touch_controller = tsc::Tsc::new_async(context.TSC, pin_groups, config, Irqs).unwrap(); - let acquisition_bank = touch_controller.create_acquisition_bank(TscAcquisitionBankPins { + let acquisition_bank = touch_controller.create_acquisition_bank(AcquisitionBankPins { g2_pin: Some(sensor0), g7_pin: Some(sensor1), ..Default::default() From efbe7fb8e8ac77eaad2787bb0ea981b1e0f875c0 Mon Sep 17 00:00:00 2001 From: michel Date: Fri, 22 Nov 2024 16:48:18 +0100 Subject: [PATCH 0412/1217] stm32 tsc examples: minor corrections --- examples/stm32l0/src/bin/tsc_multipin.rs | 8 ++++---- examples/stm32l4/src/bin/tsc_multipin.rs | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/stm32l0/src/bin/tsc_multipin.rs b/examples/stm32l0/src/bin/tsc_multipin.rs index bf75a5657..6343de141 100644 --- a/examples/stm32l0/src/bin/tsc_multipin.rs +++ b/examples/stm32l0/src/bin/tsc_multipin.rs @@ -9,7 +9,7 @@ // // This example demonstrates how to: // 1. Configure multiple channel pins within a single TSC group -// 2. Use the set_active_channels method to switch between different channels +// 2. Use the set_active_channels_bank method to switch between sets of different channels (acquisition banks) // 3. Read and interpret touch values from multiple channels in the same group // // Suggested physical setup on STM32L073RZ Nucleo board: @@ -29,7 +29,7 @@ // - PA0 as sampling capacitor, TSC group 1 IO1 (label A0) // - PA1 as channel, TSC group 1 IO2 (label A1) // - PB3 as sampling capacitor, TSC group 5 IO1 (label D3) -// - PB4 as channel, TSC group 5 IO2 (label D3) +// - PB4 as channel, TSC group 5 IO2 (label D10) // - PB6 as channel, TSC group 5 IO3 (label D5) // // The pins have been chosen to make it easy to simply add capacitors directly onto the board and @@ -80,7 +80,7 @@ async fn acquire_sensors( touch_controller: &mut Tsc<'static, peripherals::TSC, mode::Async>, tsc_acquisition_bank: &AcquisitionBank, ) { - touch_controller.set_active_channels_mask(tsc_acquisition_bank.mask()); + touch_controller.set_active_channels_bank(tsc_acquisition_bank); touch_controller.start(); touch_controller.pend_for_acquisition().await; touch_controller.discharge_io(true); @@ -156,7 +156,7 @@ async fn main(_spawner: embassy_executor::Spawner) { acquire_sensors(&mut touch_controller, &bank1).await; let readings1 = touch_controller.get_acquisition_bank_values(&bank1); acquire_sensors(&mut touch_controller, &bank2).await; - let readings2 = touch_controller.get_acquisition_bank_values(&bank1); + let readings2 = touch_controller.get_acquisition_bank_values(&bank2); let mut touched_sensors_count = 0; for reading in readings1.iter() { diff --git a/examples/stm32l4/src/bin/tsc_multipin.rs b/examples/stm32l4/src/bin/tsc_multipin.rs index 2fadbe16a..8fec5ddc4 100644 --- a/examples/stm32l4/src/bin/tsc_multipin.rs +++ b/examples/stm32l4/src/bin/tsc_multipin.rs @@ -12,7 +12,7 @@ // ## This example demonstrates how to: // // 1. Configure multiple channel pins within a single TSC group -// 2. Use the set_active_channels method to switch between different channels +// 2. Use the set_active_channels_bank method to switch between sets of different channels (acquisition banks) // 3. Read and interpret touch values from multiple channels in the same group // // ## Suggested physical setup on STM32L4R5ZI-P board: @@ -76,7 +76,7 @@ async fn acquire_sensors( touch_controller: &mut Tsc<'static, peripherals::TSC, mode::Async>, tsc_acquisition_bank: &AcquisitionBank, ) { - touch_controller.set_active_channels_mask(tsc_acquisition_bank.mask()); + touch_controller.set_active_channels_bank(tsc_acquisition_bank); touch_controller.start(); touch_controller.pend_for_acquisition().await; touch_controller.discharge_io(true); From dcd6284996c501b2d376f5c1d4af6fc5a0f00521 Mon Sep 17 00:00:00 2001 From: michel Date: Fri, 22 Nov 2024 16:49:06 +0100 Subject: [PATCH 0413/1217] stm32 tsc: added multipin example for stm32f3 --- examples/stm32f3/src/bin/tsc_multipin.rs | 204 +++++++++++++++++++++++ 1 file changed, 204 insertions(+) create mode 100644 examples/stm32f3/src/bin/tsc_multipin.rs diff --git a/examples/stm32f3/src/bin/tsc_multipin.rs b/examples/stm32f3/src/bin/tsc_multipin.rs new file mode 100644 index 000000000..c524c3760 --- /dev/null +++ b/examples/stm32f3/src/bin/tsc_multipin.rs @@ -0,0 +1,204 @@ +// Example of TSC (Touch Sensing Controller) using multiple pins from the same tsc-group. +// +// What is special about using multiple TSC pins as sensor channels from the same TSC group, +// is that only one TSC pin for each TSC group can be acquired and read at the time. +// To control which channel pins are acquired and read, we must write a mask before initiating an +// acquisition. To help manage and abstract all this business away, we can organize our channel +// pins into acquisition banks. Each acquisition bank can contain exactly one channel pin per TSC +// group and it will contain the relevant mask. +// +// This example demonstrates how to: +// 1. Configure multiple channel pins within a single TSC group +// 2. Use the set_active_channels_bank method to switch between sets of different channels (acquisition banks) +// 3. Read and interpret touch values from multiple channels in the same group +// +// Suggested physical setup on STM32F303ZE Nucleo board: +// - Connect a 1000pF capacitor between pin PA10 and GND. This is the sampling capacitor for TSC +// group 4. +// - Connect one end of a 1K resistor to pin PA9 and leave the other end loose. +// The loose end will act as a touch sensor. +// +// - Connect a 1000pF capacitor between pin PA7 and GND. This is the sampling capacitor for TSC +// group 2. +// - Connect one end of another 1K resistor to pin PA6 and leave the other end loose. +// The loose end will act as a touch sensor. +// - Connect one end of another 1K resistor to pin PA5 and leave the other end loose. +// The loose end will act as a touch sensor. +// +// The example uses pins from two TSC groups. +// - PA10 as sampling capacitor, TSC group 4 IO2 +// - PA9 as channel, TSC group 4 IO1 +// - PA7 as sampling capacitor, TSC group 2 IO4 +// - PA6 as channel, TSC group 2 IO3 +// - PA5 as channel, TSC group 2 IO2 +// +// The pins have been chosen to make it easy to simply add capacitors directly onto the board and +// connect one leg to GND, and to easily add resistors to the board with no special connectors, +// breadboards, special wires or soldering required. All you need is the capacitors and resistors. +// +// The program reads the designated channel pins and adjusts the LED blinking +// pattern based on which sensor(s) are touched: +// - No touch: LED off +// - one sensor touched: Slow blinking +// - two sensors touched: Fast blinking +// - three sensors touched: LED constantly on +// +// ## Troubleshooting: +// +// - If touch is not detected, try adjusting the SENSOR_THRESHOLD value (currently set to 20). +// - Experiment with different values for ct_pulse_high_length, ct_pulse_low_length, pulse_generator_prescaler, max_count_value, and discharge_delay to optimize sensitivity. +// - Be aware that for some boards there will be overlapping concerns between some pins, for +// example UART connection for the programmer to the MCU and a TSC pin. No errors or warning will +// be emitted if you try to use such a pin for TSC, but you will get strange sensor readings. +// +// Note: Configuration values and sampling capacitor values have been determined experimentally. Optimal values may vary based on your specific hardware setup. Refer to the official STM32 datasheet and user manuals for more information on pin configurations and TSC functionality. + +#![no_std] +#![no_main] + +use defmt::*; +use embassy_stm32::gpio::{Level, Output, Speed}; +use embassy_stm32::tsc::{self, *}; +use embassy_stm32::{mode, peripherals}; +use embassy_time::Timer; +use {defmt_rtt as _, panic_probe as _}; + +const SENSOR_THRESHOLD: u16 = 10; + +async fn acquire_sensors( + touch_controller: &mut Tsc<'static, peripherals::TSC, mode::Blocking>, + tsc_acquisition_bank: &AcquisitionBank, +) { + touch_controller.set_active_channels_bank(tsc_acquisition_bank); + touch_controller.start(); + touch_controller.poll_for_acquisition(); + touch_controller.discharge_io(true); + let discharge_delay = 5; // ms + Timer::after_millis(discharge_delay).await; +} + +#[embassy_executor::main] +async fn main(_spawner: embassy_executor::Spawner) { + let device_config = embassy_stm32::Config::default(); + let context = embassy_stm32::init(device_config); + + // ---------- initial configuration of TSC ---------- + // + let mut pin_group4: PinGroupWithRoles = PinGroupWithRoles::default(); + // D68 on the STM32F303ZE nucleo-board + pin_group4.set_io2::(context.PA10); + // D69 on the STM32F303ZE nucleo-board + let tsc_sensor0 = pin_group4.set_io1(context.PA9); + + let mut pin_group2: PinGroupWithRoles = PinGroupWithRoles::default(); + // D11 on the STM32F303ZE nucleo-board + pin_group2.set_io4::(context.PA7); + // D12 on the STM32F303ZE nucleo-board + let tsc_sensor1 = pin_group2.set_io3(context.PA6); + // D13 on the STM32F303ZE nucleo-board + let tsc_sensor2 = pin_group2.set_io2(context.PA5); + + let config = Config { + ct_pulse_high_length: ChargeTransferPulseCycle::_4, + ct_pulse_low_length: ChargeTransferPulseCycle::_4, + spread_spectrum: false, + spread_spectrum_deviation: SSDeviation::new(2).unwrap(), + spread_spectrum_prescaler: false, + pulse_generator_prescaler: PGPrescalerDivider::_16, + max_count_value: MaxCount::_255, + io_default_mode: false, + synchro_pin_polarity: false, + acquisition_mode: false, + max_count_interrupt: false, + }; + + let pin_groups: PinGroups = PinGroups { + g4: Some(pin_group4.pin_group), + g2: Some(pin_group2.pin_group), + ..Default::default() + }; + + let mut touch_controller = tsc::Tsc::new_blocking(context.TSC, pin_groups, config).unwrap(); + + // ---------- setting up acquisition banks ---------- + // sensor0 and sensor1 in this example belong to different TSC-groups, + // therefore we can acquire and read them both in one go. + let bank1 = touch_controller.create_acquisition_bank(AcquisitionBankPins { + g4_pin: Some(tsc_sensor0), + g2_pin: Some(tsc_sensor1), + ..Default::default() + }); + // `sensor1` and `sensor2` belongs to the same TSC-group, therefore we must make sure to + // acquire them one at the time. Therefore, we organize them into different acquisition banks. + let bank2 = touch_controller.create_acquisition_bank(AcquisitionBankPins { + g2_pin: Some(tsc_sensor2), + ..Default::default() + }); + + // Check if TSC is ready + if touch_controller.get_state() != State::Ready { + crate::panic!("TSC not ready!"); + } + + info!("TSC initialized successfully"); + + // LED2 on the STM32F303ZE nucleo-board + let mut led = Output::new(context.PB7, Level::High, Speed::Low); + + let mut led_state = false; + + loop { + acquire_sensors(&mut touch_controller, &bank1).await; + let readings1 = touch_controller.get_acquisition_bank_values(&bank1); + acquire_sensors(&mut touch_controller, &bank2).await; + let readings2 = touch_controller.get_acquisition_bank_values(&bank2); + + let mut touched_sensors_count = 0; + for reading in readings1.iter() { + info!("{}", reading); + if reading.sensor_value < SENSOR_THRESHOLD { + touched_sensors_count += 1; + } + } + for reading in readings2.iter() { + info!("{}", reading); + if reading.sensor_value < SENSOR_THRESHOLD { + touched_sensors_count += 1; + } + } + + match touched_sensors_count { + 0 => { + // No sensors touched, turn off the LED + led.set_low(); + led_state = false; + } + 1 => { + // One sensor touched, blink slowly + led_state = !led_state; + if led_state { + led.set_high(); + } else { + led.set_low(); + } + Timer::after_millis(200).await; + } + 2 => { + // Two sensors touched, blink faster + led_state = !led_state; + if led_state { + led.set_high(); + } else { + led.set_low(); + } + Timer::after_millis(50).await; + } + 3 => { + // All three sensors touched, LED constantly on + led.set_high(); + led_state = true; + } + _ => crate::unreachable!(), // This case should never occur with 3 sensors + } + } +} From d0b1819aa52666a4fca37211ddab82b01eea84ce Mon Sep 17 00:00:00 2001 From: sawyer bristol Date: Fri, 29 Nov 2024 20:29:43 -0700 Subject: [PATCH 0414/1217] custom bcd usb version --- embassy-usb/src/builder.rs | 6 ++++++ embassy-usb/src/descriptor.rs | 24 ++++++++++++------------ 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/embassy-usb/src/builder.rs b/embassy-usb/src/builder.rs index e1bf8041f..c7d83e710 100644 --- a/embassy-usb/src/builder.rs +++ b/embassy-usb/src/builder.rs @@ -15,6 +15,11 @@ pub struct Config<'a> { pub(crate) vendor_id: u16, pub(crate) product_id: u16, + /// Device BCD USB version. + /// + /// Default: `0x02` ("2.1") + pub bcd_usb: u16, + /// Device class code assigned by USB.org. Set to `0xff` for vendor-specific /// devices that do not conform to any class. /// @@ -108,6 +113,7 @@ impl<'a> Config<'a> { vendor_id: vid, product_id: pid, device_release: 0x0010, + bcd_usb: 0x02, manufacturer: None, product: None, serial_number: None, diff --git a/embassy-usb/src/descriptor.rs b/embassy-usb/src/descriptor.rs index 06ebe0481..8824a0355 100644 --- a/embassy-usb/src/descriptor.rs +++ b/embassy-usb/src/descriptor.rs @@ -326,11 +326,11 @@ pub(crate) fn device_descriptor(config: &Config) -> [u8; 18] { 18, // bLength 0x01, // bDescriptorType 0x10, - 0x02, // bcdUSB 2.1 - config.device_class, // bDeviceClass - config.device_sub_class, // bDeviceSubClass - config.device_protocol, // bDeviceProtocol - config.max_packet_size_0, // bMaxPacketSize0 + (config.bcd_usb >> 8) as u8, // bcdUSB + config.device_class, // bDeviceClass + config.device_sub_class, // bDeviceSubClass + config.device_protocol, // bDeviceProtocol + config.max_packet_size_0, // bMaxPacketSize0 config.vendor_id as u8, (config.vendor_id >> 8) as u8, // idVendor config.product_id as u8, @@ -353,13 +353,13 @@ pub(crate) fn device_qualifier_descriptor(config: &Config) -> [u8; 10] { 10, // bLength 0x06, // bDescriptorType 0x10, - 0x02, // bcdUSB 2.1 - config.device_class, // bDeviceClass - config.device_sub_class, // bDeviceSubClass - config.device_protocol, // bDeviceProtocol - config.max_packet_size_0, // bMaxPacketSize0 - 1, // bNumConfigurations - 0, // Reserved + (config.bcd_usb >> 8) as u8, // bcdUSB + config.device_class, // bDeviceClass + config.device_sub_class, // bDeviceSubClass + config.device_protocol, // bDeviceProtocol + config.max_packet_size_0, // bMaxPacketSize0 + 1, // bNumConfigurations + 0, // Reserved ] } From fdb8ee2e8a70fc078cbd2a4419c919f9fd361d56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Sat, 30 Nov 2024 10:50:57 +0100 Subject: [PATCH 0415/1217] RTC: Trigger expired alarms --- embassy-stm32/src/time_driver.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs index 88b6c48bb..8cf74ef6c 100644 --- a/embassy-stm32/src/time_driver.rs +++ b/embassy-stm32/src/time_driver.rs @@ -414,7 +414,10 @@ impl RtcDriver { let alarm_handle = unsafe { AlarmHandle::new(i as u8) }; let alarm = self.get_alarm(cs, alarm_handle); - self.set_alarm(alarm_handle, alarm.timestamp.get()); + if !self.set_alarm(alarm_handle, alarm.timestamp.get()) { + // If the alarm timestamp has passed, we need to trigger it + self.trigger_alarm(i, cs); + } } } From efee03744e0c82c3b6b4419e072129aad3dae841 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Sat, 30 Nov 2024 11:07:20 +0100 Subject: [PATCH 0416/1217] Only recompute allocated alarms --- embassy-stm32/src/time_driver.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs index 8cf74ef6c..00aa3cfa4 100644 --- a/embassy-stm32/src/time_driver.rs +++ b/embassy-stm32/src/time_driver.rs @@ -410,7 +410,7 @@ impl RtcDriver { regs_gp16().cnt().write(|w| w.set_cnt(cnt as u16)); // Now, recompute all alarms - for i in 0..ALARM_COUNT { + for i in 0..self.alarm_count.load(Ordering::Relaxed) as usize { let alarm_handle = unsafe { AlarmHandle::new(i as u8) }; let alarm = self.get_alarm(cs, alarm_handle); From 7d15ec921a279682c4e0b8a9eb5176e541f99b17 Mon Sep 17 00:00:00 2001 From: Derek Hageman Date: Sun, 1 Dec 2024 09:30:23 -0700 Subject: [PATCH 0417/1217] stm32/usart: Implement data bit selection Implement data bit size selection and add 7-bit mode. --- embassy-stm32/src/usart/mod.rs | 85 +++++++++++++++++++++++++--------- 1 file changed, 63 insertions(+), 22 deletions(-) diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index 8152fc560..d2fb85ee3 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -91,6 +91,8 @@ unsafe fn on_interrupt(r: Regs, s: &'static State) { #[cfg_attr(feature = "defmt", derive(defmt::Format))] /// Number of data bits pub enum DataBits { + /// 7 Data Bits + DataBits7, /// 8 Data Bits DataBits8, /// 9 Data Bits @@ -134,6 +136,8 @@ pub enum ConfigError { BaudrateTooHigh, /// Rx or Tx not enabled RxOrTxNotEnabled, + /// Data bits and parity combination not supported + DataParityNotSupported, } #[non_exhaustive] @@ -1617,31 +1621,66 @@ fn configure( w.set_re(enable_rx); } - // configure word size - // if using odd or even parity it must be configured to 9bits - w.set_m0(if config.parity != Parity::ParityNone { - trace!("USART: m0: vals::M0::BIT9"); - vals::M0::BIT9 - } else { - trace!("USART: m0: vals::M0::BIT8"); - vals::M0::BIT8 - }); - // configure parity - w.set_pce(config.parity != Parity::ParityNone); - w.set_ps(match config.parity { - Parity::ParityOdd => { - trace!("USART: set_ps: vals::Ps::ODD"); - vals::Ps::ODD + // configure word size and parity, since the parity bit is inserted into the MSB position, + // it increases the effective word size + match (config.parity, config.data_bits) { + (Parity::ParityNone, DataBits::DataBits8) => { + trace!("USART: m0: 8 data bits, no parity"); + w.set_m0(vals::M0::BIT8); + #[cfg(any(usart_v3, usart_v4))] + w.set_m1(vals::M1::M0); + w.set_pce(false); } - Parity::ParityEven => { - trace!("USART: set_ps: vals::Ps::EVEN"); - vals::Ps::EVEN + (Parity::ParityNone, DataBits::DataBits9) => { + trace!("USART: m0: 9 data bits, no parity"); + w.set_m0(vals::M0::BIT9); + #[cfg(any(usart_v3, usart_v4))] + w.set_m1(vals::M1::M0); + w.set_pce(false); + } + #[cfg(any(usart_v3, usart_v4))] + (Parity::ParityNone, DataBits::DataBits7) => { + trace!("USART: m0: 7 data bits, no parity"); + w.set_m0(vals::M0::BIT8); + w.set_m1(vals::M1::BIT7); + w.set_pce(false); + } + (Parity::ParityEven, DataBits::DataBits8) => { + trace!("USART: m0: 8 data bits, even parity"); + w.set_m0(vals::M0::BIT9); + #[cfg(any(usart_v3, usart_v4))] + w.set_m1(vals::M1::M0); + w.set_pce(true); + w.set_ps(vals::Ps::EVEN); + } + (Parity::ParityEven, DataBits::DataBits7) => { + trace!("USART: m0: 7 data bits, even parity"); + w.set_m0(vals::M0::BIT8); + #[cfg(any(usart_v3, usart_v4))] + w.set_m1(vals::M1::M0); + w.set_pce(true); + w.set_ps(vals::Ps::EVEN); + } + (Parity::ParityOdd, DataBits::DataBits8) => { + trace!("USART: m0: 8 data bits, odd parity"); + w.set_m0(vals::M0::BIT9); + #[cfg(any(usart_v3, usart_v4))] + w.set_m1(vals::M1::M0); + w.set_pce(true); + w.set_ps(vals::Ps::ODD); + } + (Parity::ParityOdd, DataBits::DataBits7) => { + trace!("USART: m0: 7 data bits, odd parity"); + w.set_m0(vals::M0::BIT8); + #[cfg(any(usart_v3, usart_v4))] + w.set_m1(vals::M1::M0); + w.set_pce(true); + w.set_ps(vals::Ps::ODD); } _ => { - trace!("USART: set_ps: vals::Ps::EVEN"); - vals::Ps::EVEN + return Err(ConfigError::DataParityNotSupported); } - }); + } #[cfg(not(usart_v1))] w.set_over8(vals::Over8::from_bits(over8 as _)); #[cfg(usart_v4)] @@ -1649,7 +1688,9 @@ fn configure( trace!("USART: set_fifoen: true (usart_v4)"); w.set_fifoen(true); } - }); + + Ok(()) + })?; Ok(()) } From 18020d672d20d19fa0191a002413457fcf5c4182 Mon Sep 17 00:00:00 2001 From: decaday Date: Mon, 2 Dec 2024 16:51:50 +0800 Subject: [PATCH 0418/1217] fix: error message for multiple time-driver-xxx cargo features --- embassy-stm32/build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 348d48b9b..f92d8b8ba 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -195,7 +195,7 @@ fn main() { .to_ascii_lowercase(), ), Err(GetOneError::None) => None, - Err(GetOneError::Multiple) => panic!("Multiple stm32xx Cargo features enabled"), + Err(GetOneError::Multiple) => panic!("Multiple time-driver-xxx Cargo features enabled"), }; let time_driver_singleton = match time_driver.as_ref().map(|x| x.as_ref()) { From ed1f44e58bb38fa1c490f0094400b673bd4bccc3 Mon Sep 17 00:00:00 2001 From: Gerhard de Clercq <11624490+Gerharddc@users.noreply.github.com> Date: Mon, 2 Dec 2024 11:04:17 +0100 Subject: [PATCH 0419/1217] embassy-dfu-usb: Improve debuggability This commit adds logging to embassy-dfu-usb which helps with debugging issues such as https://github.com/embassy-rs/embassy/issues/3536. It also cleans up a few repeated code blocks and avoid re-initialising the local buffer for every iteration. --- embassy-usb-dfu/Cargo.toml | 2 +- embassy-usb-dfu/src/consts.rs | 41 +++++++++--------- embassy-usb-dfu/src/dfu.rs | 78 ++++++++++++++++++++++------------- 3 files changed, 70 insertions(+), 51 deletions(-) diff --git a/embassy-usb-dfu/Cargo.toml b/embassy-usb-dfu/Cargo.toml index 16da468bd..763c9600d 100644 --- a/embassy-usb-dfu/Cargo.toml +++ b/embassy-usb-dfu/Cargo.toml @@ -42,4 +42,4 @@ esp32c3-hal = { version = "0.13.0", optional = true, default-features = false } [features] dfu = [] application = [] -defmt = ["dep:defmt"] +defmt = ["dep:defmt", "embassy-boot/defmt", "embassy-usb/defmt"] diff --git a/embassy-usb-dfu/src/consts.rs b/embassy-usb-dfu/src/consts.rs index f8a056e5c..190b5ad5a 100644 --- a/embassy-usb-dfu/src/consts.rs +++ b/embassy-usb-dfu/src/consts.rs @@ -7,30 +7,29 @@ pub(crate) const DFU_PROTOCOL_DFU: u8 = 0x02; pub(crate) const DFU_PROTOCOL_RT: u8 = 0x01; pub(crate) const DESC_DFU_FUNCTIONAL: u8 = 0x21; -#[cfg(feature = "defmt")] -defmt::bitflags! { - pub struct DfuAttributes: u8 { - const WILL_DETACH = 0b0000_1000; - const MANIFESTATION_TOLERANT = 0b0000_0100; - const CAN_UPLOAD = 0b0000_0010; - const CAN_DOWNLOAD = 0b0000_0001; - } +macro_rules! define_dfu_attributes { + ($macro:path) => { + $macro! { + /// Attributes supported by the DFU controller. + pub struct DfuAttributes: u8 { + /// Generate WillDetache sequence on bus. + const WILL_DETACH = 0b0000_1000; + /// Device can communicate during manifestation phase. + const MANIFESTATION_TOLERANT = 0b0000_0100; + /// Capable of upload. + const CAN_UPLOAD = 0b0000_0010; + /// Capable of download. + const CAN_DOWNLOAD = 0b0000_0001; + } + } + }; } +#[cfg(feature = "defmt")] +define_dfu_attributes!(defmt::bitflags); + #[cfg(not(feature = "defmt"))] -bitflags::bitflags! { - /// Attributes supported by the DFU controller. - pub struct DfuAttributes: u8 { - /// Generate WillDetache sequence on bus. - const WILL_DETACH = 0b0000_1000; - /// Device can communicate during manifestation phase. - const MANIFESTATION_TOLERANT = 0b0000_0100; - /// Capable of upload. - const CAN_UPLOAD = 0b0000_0010; - /// Capable of download. - const CAN_DOWNLOAD = 0b0000_0001; - } -} +define_dfu_attributes!(bitflags::bitflags); #[derive(Copy, Clone, PartialEq, Eq)] #[repr(u8)] diff --git a/embassy-usb-dfu/src/dfu.rs b/embassy-usb-dfu/src/dfu.rs index e99aa70c3..abd929a9e 100644 --- a/embassy-usb-dfu/src/dfu.rs +++ b/embassy-usb-dfu/src/dfu.rs @@ -1,6 +1,6 @@ use core::marker::PhantomData; -use embassy_boot::{AlignedBuffer, BlockingFirmwareUpdater}; +use embassy_boot::{AlignedBuffer, BlockingFirmwareUpdater, FirmwareUpdaterError}; use embassy_usb::control::{InResponse, OutResponse, Recipient, RequestType}; use embassy_usb::driver::Driver; use embassy_usb::{Builder, Handler}; @@ -19,6 +19,7 @@ pub struct Control<'d, DFU: NorFlash, STATE: NorFlash, RST: Reset, const BLOCK_S state: State, status: Status, offset: usize, + buf: AlignedBuffer, _rst: PhantomData, } @@ -31,6 +32,7 @@ impl<'d, DFU: NorFlash, STATE: NorFlash, RST: Reset, const BLOCK_SIZE: usize> Co state: State::DfuIdle, status: Status::Ok, offset: 0, + buf: AlignedBuffer([0; BLOCK_SIZE]), _rst: PhantomData, } } @@ -42,6 +44,20 @@ impl<'d, DFU: NorFlash, STATE: NorFlash, RST: Reset, const BLOCK_SIZE: usize> Co } } +impl From for Status { + fn from(e: FirmwareUpdaterError) -> Self { + match e { + FirmwareUpdaterError::Flash(e) => match e { + NorFlashErrorKind::NotAligned => Status::ErrWrite, + NorFlashErrorKind::OutOfBounds => Status::ErrAddress, + _ => Status::ErrUnknown, + }, + FirmwareUpdaterError::Signature(_) => Status::ErrVerify, + FirmwareUpdaterError::BadState => Status::ErrUnknown, + } + } +} + impl<'d, DFU: NorFlash, STATE: NorFlash, RST: Reset, const BLOCK_SIZE: usize> Handler for Control<'d, DFU, STATE, RST, BLOCK_SIZE> { @@ -51,65 +67,67 @@ impl<'d, DFU: NorFlash, STATE: NorFlash, RST: Reset, const BLOCK_SIZE: usize> Ha data: &[u8], ) -> Option { if (req.request_type, req.recipient) != (RequestType::Class, Recipient::Interface) { + debug!("Unknown out request: {:?}", req); return None; } match Request::try_from(req.request) { Ok(Request::Abort) => { + info!("Abort requested"); self.reset_state(); Some(OutResponse::Accepted) } Ok(Request::Dnload) if self.attrs.contains(DfuAttributes::CAN_DOWNLOAD) => { if req.value == 0 { + info!("Download starting"); self.state = State::Download; self.offset = 0; } - let mut buf = AlignedBuffer([0; BLOCK_SIZE]); - buf.as_mut()[..data.len()].copy_from_slice(data); + if self.state != State::Download { + error!("Unexpected DNLOAD while chip is waiting for a GETSTATUS"); + self.status = Status::ErrUnknown; + self.state = State::Error; + return Some(OutResponse::Rejected); + } + + if data.len() > BLOCK_SIZE { + error!("USB data len exceeded block size"); + self.status = Status::ErrUnknown; + self.state = State::Error; + return Some(OutResponse::Rejected); + } + + debug!("Copying {} bytes to buffer", data.len()); + self.buf.as_mut()[..data.len()].copy_from_slice(data); + + let final_transfer = req.length == 0; + if final_transfer { + debug!("Receiving final transfer"); - if req.length == 0 { match self.updater.mark_updated() { Ok(_) => { self.status = Status::Ok; self.state = State::ManifestSync; + info!("Update complete"); } Err(e) => { + error!("Error completing update: {}", e); self.state = State::Error; - match e { - embassy_boot::FirmwareUpdaterError::Flash(e) => match e { - NorFlashErrorKind::NotAligned => self.status = Status::ErrWrite, - NorFlashErrorKind::OutOfBounds => self.status = Status::ErrAddress, - _ => self.status = Status::ErrUnknown, - }, - embassy_boot::FirmwareUpdaterError::Signature(_) => self.status = Status::ErrVerify, - embassy_boot::FirmwareUpdaterError::BadState => self.status = Status::ErrUnknown, - } + self.status = e.into(); } } } else { - if self.state != State::Download { - // Unexpected DNLOAD while chip is waiting for a GETSTATUS - self.status = Status::ErrUnknown; - self.state = State::Error; - return Some(OutResponse::Rejected); - } - match self.updater.write_firmware(self.offset, buf.as_ref()) { + debug!("Writing {} bytes at {}", data.len(), self.offset); + match self.updater.write_firmware(self.offset, self.buf.as_ref()) { Ok(_) => { self.status = Status::Ok; self.state = State::DlSync; self.offset += data.len(); } Err(e) => { + error!("Error writing firmware: {:?}", e); self.state = State::Error; - match e { - embassy_boot::FirmwareUpdaterError::Flash(e) => match e { - NorFlashErrorKind::NotAligned => self.status = Status::ErrWrite, - NorFlashErrorKind::OutOfBounds => self.status = Status::ErrAddress, - _ => self.status = Status::ErrUnknown, - }, - embassy_boot::FirmwareUpdaterError::Signature(_) => self.status = Status::ErrVerify, - embassy_boot::FirmwareUpdaterError::BadState => self.status = Status::ErrUnknown, - } + self.status = e.into(); } } } @@ -118,6 +136,7 @@ impl<'d, DFU: NorFlash, STATE: NorFlash, RST: Reset, const BLOCK_SIZE: usize> Ha } Ok(Request::Detach) => Some(OutResponse::Accepted), // Device is already in DFU mode Ok(Request::ClrStatus) => { + info!("Clear status requested"); self.reset_state(); Some(OutResponse::Accepted) } @@ -131,6 +150,7 @@ impl<'d, DFU: NorFlash, STATE: NorFlash, RST: Reset, const BLOCK_SIZE: usize> Ha buf: &'a mut [u8], ) -> Option> { if (req.request_type, req.recipient) != (RequestType::Class, Recipient::Interface) { + debug!("Unknown in request: {:?}", req); return None; } match Request::try_from(req.request) { From f25830a5b67caad4a89eeed2cd602ac12198f6c5 Mon Sep 17 00:00:00 2001 From: sawyer bristol Date: Mon, 2 Dec 2024 15:44:01 -0700 Subject: [PATCH 0420/1217] bcd default to 2.1 --- embassy-usb/src/builder.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-usb/src/builder.rs b/embassy-usb/src/builder.rs index c7d83e710..28a449a9f 100644 --- a/embassy-usb/src/builder.rs +++ b/embassy-usb/src/builder.rs @@ -17,7 +17,7 @@ pub struct Config<'a> { /// Device BCD USB version. /// - /// Default: `0x02` ("2.1") + /// Default: `0x0210` ("2.1") pub bcd_usb: u16, /// Device class code assigned by USB.org. Set to `0xff` for vendor-specific @@ -113,7 +113,7 @@ impl<'a> Config<'a> { vendor_id: vid, product_id: pid, device_release: 0x0010, - bcd_usb: 0x02, + bcd_usb: 0x0210, manufacturer: None, product: None, serial_number: None, From 8068f7092efcc8f42fa2031d3977dcade74981d2 Mon Sep 17 00:00:00 2001 From: sawyer bristol Date: Mon, 2 Dec 2024 15:44:29 -0700 Subject: [PATCH 0421/1217] fix bug and allow bcd to be .0 --- embassy-usb/src/descriptor.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-usb/src/descriptor.rs b/embassy-usb/src/descriptor.rs index 8824a0355..09ce50951 100644 --- a/embassy-usb/src/descriptor.rs +++ b/embassy-usb/src/descriptor.rs @@ -325,7 +325,7 @@ pub(crate) fn device_descriptor(config: &Config) -> [u8; 18] { [ 18, // bLength 0x01, // bDescriptorType - 0x10, + config.bcd_usb as u8, (config.bcd_usb >> 8) as u8, // bcdUSB config.device_class, // bDeviceClass config.device_sub_class, // bDeviceSubClass From 75382336164c8284196eb1fad057050ba735a72d Mon Sep 17 00:00:00 2001 From: rafael Date: Sat, 9 Nov 2024 17:19:06 +0100 Subject: [PATCH 0422/1217] correct rp pwm dutycycle examples: desired frequency --- examples/rp/src/bin/pwm.rs | 12 ++++++++---- examples/rp23/src/bin/pwm.rs | 10 +++++++--- examples/rp23/src/bin/pwm_tb6612fng_motor_driver.rs | 11 +++++++---- 3 files changed, 22 insertions(+), 11 deletions(-) diff --git a/examples/rp/src/bin/pwm.rs b/examples/rp/src/bin/pwm.rs index 791b88b5b..06b9313f2 100644 --- a/examples/rp/src/bin/pwm.rs +++ b/examples/rp/src/bin/pwm.rs @@ -48,11 +48,15 @@ async fn pwm_set_dutycycle(slice2: PWM_SLICE2, pin4: PIN_4) { // If we aim for a specific frequency, here is how we can calculate the top value. // The top value sets the period of the PWM cycle, so a counter goes from 0 to top and then wraps around to 0. // Every such wraparound is one PWM cycle. So here is how we get 25KHz: + let desired_freq_hz = 25_000; + let clock_freq_hz = embassy_rp::clocks::clk_sys_freq(); + let divider = 16u8; + let period = (clock_freq_hz / (desired_freq_hz * divider as u32)) as u16 - 1; + let mut c = Config::default(); - let pwm_freq = 25_000; // Hz, our desired frequency - let clock_freq = embassy_rp::clocks::clk_sys_freq(); - c.top = (clock_freq / pwm_freq) as u16 - 1; - + c.top = period; + c.divider = divider.into(); + let mut pwm = Pwm::new_output_a(slice2, pin4, c.clone()); loop { diff --git a/examples/rp23/src/bin/pwm.rs b/examples/rp23/src/bin/pwm.rs index 5a4457158..ed3c94f15 100644 --- a/examples/rp23/src/bin/pwm.rs +++ b/examples/rp23/src/bin/pwm.rs @@ -53,10 +53,14 @@ async fn pwm_set_dutycycle(slice2: PWM_SLICE2, pin4: PIN_4) { // If we aim for a specific frequency, here is how we can calculate the top value. // The top value sets the period of the PWM cycle, so a counter goes from 0 to top and then wraps around to 0. // Every such wraparound is one PWM cycle. So here is how we get 25KHz: + let desired_freq_hz = 25_000; + let clock_freq_hz = embassy_rp::clocks::clk_sys_freq(); + let divider = 16u8; + let period = (clock_freq_hz / (desired_freq_hz * divider as u32)) as u16 - 1; + let mut c = Config::default(); - let pwm_freq = 25_000; // Hz, our desired frequency - let clock_freq = embassy_rp::clocks::clk_sys_freq(); - c.top = (clock_freq / pwm_freq) as u16 - 1; + c.top = period; + c.divider = divider.into(); let mut pwm = Pwm::new_output_a(slice2, pin4, c.clone()); diff --git a/examples/rp23/src/bin/pwm_tb6612fng_motor_driver.rs b/examples/rp23/src/bin/pwm_tb6612fng_motor_driver.rs index 3fad2928c..0682888e8 100644 --- a/examples/rp23/src/bin/pwm_tb6612fng_motor_driver.rs +++ b/examples/rp23/src/bin/pwm_tb6612fng_motor_driver.rs @@ -40,10 +40,11 @@ async fn main(_spawner: Spawner) { let s = split_resources!(p); let r = s.motor; - // we want a PWM frequency of 1KHz, especially cheaper motors do not respond well to higher frequencies - let pwm_freq = 1_000; // Hz, our desired frequency - let clock_freq = embassy_rp::clocks::clk_sys_freq(); - let period = (clock_freq / pwm_freq) as u16 - 1; + // we want a PWM frequency of 10KHz, especially cheaper motors do not respond well to higher frequencies + let desired_freq_hz = 10_000; + let clock_freq_hz = embassy_rp::clocks::clk_sys_freq(); + let divider = 16u8; + let period = (clock_freq_hz / (desired_freq_hz * divider as u32)) as u16 - 1; // we need a standby output and two motors to construct a full TB6612FNG @@ -55,6 +56,7 @@ async fn main(_spawner: Spawner) { let left_bckw = gpio::Output::new(r.left_backward_pin, gpio::Level::Low); let mut left_speed = pwm::Config::default(); left_speed.top = period; + left_speed.divider = divider.into(); let left_pwm = pwm::Pwm::new_output_a(r.left_slice, r.left_pwm_pin, left_speed); let left_motor = Motor::new(left_fwd, left_bckw, left_pwm).unwrap(); @@ -63,6 +65,7 @@ async fn main(_spawner: Spawner) { let right_bckw = gpio::Output::new(r.right_backward_pin, gpio::Level::Low); let mut right_speed = pwm::Config::default(); right_speed.top = period; + right_speed.divider = divider.into(); let right_pwm = pwm::Pwm::new_output_b(r.right_slice, r.right_pwm_pin, right_speed); let right_motor = Motor::new(right_fwd, right_bckw, right_pwm).unwrap(); From ccf2e0c528a85518e9d64456d9dfde9e951ef613 Mon Sep 17 00:00:00 2001 From: rafael Date: Sat, 9 Nov 2024 17:37:24 +0100 Subject: [PATCH 0423/1217] formatting --- examples/rp/src/bin/pwm.rs | 8 ++++---- examples/rp23/src/bin/pwm.rs | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/rp/src/bin/pwm.rs b/examples/rp/src/bin/pwm.rs index 06b9313f2..cf6531994 100644 --- a/examples/rp/src/bin/pwm.rs +++ b/examples/rp/src/bin/pwm.rs @@ -9,7 +9,7 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_rp::peripherals::{PIN_25, PIN_4, PWM_SLICE2, PWM_SLICE4}; +use embassy_rp::peripherals::{PIN_4, PIN_25, PWM_SLICE2, PWM_SLICE4}; use embassy_rp::pwm::{Config, Pwm, SetDutyCycle}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; @@ -48,15 +48,15 @@ async fn pwm_set_dutycycle(slice2: PWM_SLICE2, pin4: PIN_4) { // If we aim for a specific frequency, here is how we can calculate the top value. // The top value sets the period of the PWM cycle, so a counter goes from 0 to top and then wraps around to 0. // Every such wraparound is one PWM cycle. So here is how we get 25KHz: - let desired_freq_hz = 25_000; + let desired_freq_hz = 25_000; let clock_freq_hz = embassy_rp::clocks::clk_sys_freq(); let divider = 16u8; let period = (clock_freq_hz / (desired_freq_hz * divider as u32)) as u16 - 1; - + let mut c = Config::default(); c.top = period; c.divider = divider.into(); - + let mut pwm = Pwm::new_output_a(slice2, pin4, c.clone()); loop { diff --git a/examples/rp23/src/bin/pwm.rs b/examples/rp23/src/bin/pwm.rs index ed3c94f15..bd3c287ad 100644 --- a/examples/rp23/src/bin/pwm.rs +++ b/examples/rp23/src/bin/pwm.rs @@ -10,7 +10,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_rp::block::ImageDef; -use embassy_rp::peripherals::{PIN_25, PIN_4, PWM_SLICE2, PWM_SLICE4}; +use embassy_rp::peripherals::{PIN_4, PIN_25, PWM_SLICE2, PWM_SLICE4}; use embassy_rp::pwm::{Config, Pwm, SetDutyCycle}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; From ed10b9de7b0292a23036d3144146cff8137caf4f Mon Sep 17 00:00:00 2001 From: rafael Date: Sat, 9 Nov 2024 17:39:21 +0100 Subject: [PATCH 0424/1217] formatting --- examples/rp/src/bin/pwm.rs | 2 +- examples/rp23/src/bin/pwm.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/rp/src/bin/pwm.rs b/examples/rp/src/bin/pwm.rs index cf6531994..2f5f94870 100644 --- a/examples/rp/src/bin/pwm.rs +++ b/examples/rp/src/bin/pwm.rs @@ -9,7 +9,7 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_rp::peripherals::{PIN_4, PIN_25, PWM_SLICE2, PWM_SLICE4}; +use embassy_rp::peripherals::{PIN_25, PIN_4, PWM_SLICE2, PWM_SLICE4}; use embassy_rp::pwm::{Config, Pwm, SetDutyCycle}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/rp23/src/bin/pwm.rs b/examples/rp23/src/bin/pwm.rs index bd3c287ad..ed3c94f15 100644 --- a/examples/rp23/src/bin/pwm.rs +++ b/examples/rp23/src/bin/pwm.rs @@ -10,7 +10,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_rp::block::ImageDef; -use embassy_rp::peripherals::{PIN_4, PIN_25, PWM_SLICE2, PWM_SLICE4}; +use embassy_rp::peripherals::{PIN_25, PIN_4, PWM_SLICE2, PWM_SLICE4}; use embassy_rp::pwm::{Config, Pwm, SetDutyCycle}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; From 34899491e56db35a1b7e045a7854d10c0ca05457 Mon Sep 17 00:00:00 2001 From: sawyer bristol Date: Mon, 2 Dec 2024 15:57:58 -0700 Subject: [PATCH 0425/1217] add named bcd versions --- embassy-usb/src/builder.rs | 11 +++++++++-- embassy-usb/src/descriptor.rs | 24 ++++++++++++------------ 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/embassy-usb/src/builder.rs b/embassy-usb/src/builder.rs index 28a449a9f..8d6d06a6b 100644 --- a/embassy-usb/src/builder.rs +++ b/embassy-usb/src/builder.rs @@ -7,6 +7,13 @@ use crate::msos::{DeviceLevelDescriptor, FunctionLevelDescriptor, MsOsDescriptor use crate::types::{InterfaceNumber, StringIndex}; use crate::{Handler, Interface, UsbDevice, MAX_INTERFACE_COUNT, STRING_INDEX_CUSTOM_START}; +#[derive(Debug, Copy, Clone)] +/// Allows Configuring the Bcd USB version below 2.1 +pub enum BcdUsbVersion { + Two = 0x0200, + TwoOne = 0x0210, +} + #[derive(Debug, Copy, Clone)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[non_exhaustive] @@ -18,7 +25,7 @@ pub struct Config<'a> { /// Device BCD USB version. /// /// Default: `0x0210` ("2.1") - pub bcd_usb: u16, + pub bcd_usb: BcdUsbVersion, /// Device class code assigned by USB.org. Set to `0xff` for vendor-specific /// devices that do not conform to any class. @@ -113,7 +120,7 @@ impl<'a> Config<'a> { vendor_id: vid, product_id: pid, device_release: 0x0010, - bcd_usb: 0x0210, + bcd_usb: BcdUsbVersion::TwoOne, manufacturer: None, product: None, serial_number: None, diff --git a/embassy-usb/src/descriptor.rs b/embassy-usb/src/descriptor.rs index 09ce50951..51cd2b39a 100644 --- a/embassy-usb/src/descriptor.rs +++ b/embassy-usb/src/descriptor.rs @@ -326,11 +326,11 @@ pub(crate) fn device_descriptor(config: &Config) -> [u8; 18] { 18, // bLength 0x01, // bDescriptorType config.bcd_usb as u8, - (config.bcd_usb >> 8) as u8, // bcdUSB - config.device_class, // bDeviceClass - config.device_sub_class, // bDeviceSubClass - config.device_protocol, // bDeviceProtocol - config.max_packet_size_0, // bMaxPacketSize0 + (config.bcd_usb as u16 >> 8) as u8, // bcdUSB + config.device_class, // bDeviceClass + config.device_sub_class, // bDeviceSubClass + config.device_protocol, // bDeviceProtocol + config.max_packet_size_0, // bMaxPacketSize0 config.vendor_id as u8, (config.vendor_id >> 8) as u8, // idVendor config.product_id as u8, @@ -353,13 +353,13 @@ pub(crate) fn device_qualifier_descriptor(config: &Config) -> [u8; 10] { 10, // bLength 0x06, // bDescriptorType 0x10, - (config.bcd_usb >> 8) as u8, // bcdUSB - config.device_class, // bDeviceClass - config.device_sub_class, // bDeviceSubClass - config.device_protocol, // bDeviceProtocol - config.max_packet_size_0, // bMaxPacketSize0 - 1, // bNumConfigurations - 0, // Reserved + (config.bcd_usb as u16 >> 8) as u8, // bcdUSB + config.device_class, // bDeviceClass + config.device_sub_class, // bDeviceSubClass + config.device_protocol, // bDeviceProtocol + config.max_packet_size_0, // bMaxPacketSize0 + 1, // bNumConfigurations + 0, // Reserved ] } From 4d9ee16f3c25241337a4ec730ed3079f7ded19bc Mon Sep 17 00:00:00 2001 From: sawyer bristol Date: Mon, 2 Dec 2024 15:58:39 -0700 Subject: [PATCH 0426/1217] fix device_qualifier_descriptor with custom bcd version --- embassy-usb/src/descriptor.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-usb/src/descriptor.rs b/embassy-usb/src/descriptor.rs index 51cd2b39a..e9a6fd79a 100644 --- a/embassy-usb/src/descriptor.rs +++ b/embassy-usb/src/descriptor.rs @@ -352,7 +352,7 @@ pub(crate) fn device_qualifier_descriptor(config: &Config) -> [u8; 10] { [ 10, // bLength 0x06, // bDescriptorType - 0x10, + config.bcd_usb as u8, (config.bcd_usb as u16 >> 8) as u8, // bcdUSB config.device_class, // bDeviceClass config.device_sub_class, // bDeviceSubClass From 180d816e00a9575da95682782da25409eb7deb68 Mon Sep 17 00:00:00 2001 From: sawyer bristol Date: Mon, 2 Dec 2024 16:03:38 -0700 Subject: [PATCH 0427/1217] add fmt --- embassy-usb/src/builder.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/embassy-usb/src/builder.rs b/embassy-usb/src/builder.rs index 8d6d06a6b..9e5aa0574 100644 --- a/embassy-usb/src/builder.rs +++ b/embassy-usb/src/builder.rs @@ -8,6 +8,8 @@ use crate::types::{InterfaceNumber, StringIndex}; use crate::{Handler, Interface, UsbDevice, MAX_INTERFACE_COUNT, STRING_INDEX_CUSTOM_START}; #[derive(Debug, Copy, Clone)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[non_exhaustive] /// Allows Configuring the Bcd USB version below 2.1 pub enum BcdUsbVersion { Two = 0x0200, From fe2c82e98cfe843eeb01196e3fc19fac61b6e6bf Mon Sep 17 00:00:00 2001 From: sawyer bristol Date: Mon, 2 Dec 2024 16:07:10 -0700 Subject: [PATCH 0428/1217] rename BcdUsbVersion -> UsbVersion --- embassy-usb/src/builder.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/embassy-usb/src/builder.rs b/embassy-usb/src/builder.rs index 9e5aa0574..6c42b07dc 100644 --- a/embassy-usb/src/builder.rs +++ b/embassy-usb/src/builder.rs @@ -11,7 +11,7 @@ use crate::{Handler, Interface, UsbDevice, MAX_INTERFACE_COUNT, STRING_INDEX_CUS #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[non_exhaustive] /// Allows Configuring the Bcd USB version below 2.1 -pub enum BcdUsbVersion { +pub enum UsbVersion { Two = 0x0200, TwoOne = 0x0210, } @@ -27,7 +27,7 @@ pub struct Config<'a> { /// Device BCD USB version. /// /// Default: `0x0210` ("2.1") - pub bcd_usb: BcdUsbVersion, + pub bcd_usb: UsbVersion, /// Device class code assigned by USB.org. Set to `0xff` for vendor-specific /// devices that do not conform to any class. @@ -122,7 +122,7 @@ impl<'a> Config<'a> { vendor_id: vid, product_id: pid, device_release: 0x0010, - bcd_usb: BcdUsbVersion::TwoOne, + bcd_usb: UsbVersion::TwoOne, manufacturer: None, product: None, serial_number: None, From dcf228e4487982b2aef577eb914d80fcb2ecbdc3 Mon Sep 17 00:00:00 2001 From: dstric-aqueduct <96876452+dstric-aqueduct@users.noreply.github.com> Date: Tue, 15 Oct 2024 11:48:54 -0400 Subject: [PATCH 0429/1217] Add `set_config` method to RP SPI driver Add a `set_config` method to `Spi` to allow reconfiguring SPI mode after creation. The existing implementation of the `embassy-embedded-hal` trait `SetConfig` is changed to use the new method. Existing uses of `SetConfig` trait may need to explicitly call the trait method to maintain current return type. --- embassy-rp/src/spi.rs | 52 +++++++++++++++++++----------- examples/rp23/src/bin/spi_sdmmc.rs | 2 +- 2 files changed, 35 insertions(+), 19 deletions(-) diff --git a/embassy-rp/src/spi.rs b/embassy-rp/src/spi.rs index a8f4e72c7..c48b5c54f 100644 --- a/embassy-rp/src/spi.rs +++ b/embassy-rp/src/spi.rs @@ -84,16 +84,9 @@ impl<'d, T: Instance, M: Mode> Spi<'d, T, M> { ) -> Self { into_ref!(inner); - let p = inner.regs(); - let (presc, postdiv) = calc_prescs(config.frequency); + Self::apply_config(&inner, &config); - p.cpsr().write(|w| w.set_cpsdvsr(presc)); - p.cr0().write(|w| { - w.set_dss(0b0111); // 8bit - w.set_spo(config.polarity == Polarity::IdleHigh); - w.set_sph(config.phase == Phase::CaptureOnSecondTransition); - w.set_scr(postdiv); - }); + let p = inner.regs(); // Always enable DREQ signals -- harmless if DMA is not listening p.dmacr().write(|reg| { @@ -164,6 +157,23 @@ impl<'d, T: Instance, M: Mode> Spi<'d, T, M> { } } + /// Private function to apply SPI configuration (phase, polarity, frequency) settings. + /// + /// Driver should be disabled before making changes and reenabled after the modifications + /// are applied. + fn apply_config(inner: &PeripheralRef<'d, T>, config: &Config) { + let p = inner.regs(); + let (presc, postdiv) = calc_prescs(config.frequency); + + p.cpsr().write(|w| w.set_cpsdvsr(presc)); + p.cr0().write(|w| { + w.set_dss(0b0111); // 8bit + w.set_spo(config.polarity == Polarity::IdleHigh); + w.set_sph(config.phase == Phase::CaptureOnSecondTransition); + w.set_scr(postdiv); + }); + } + /// Write data to SPI blocking execution until done. pub fn blocking_write(&mut self, data: &[u8]) -> Result<(), Error> { let p = self.inner.regs(); @@ -244,6 +254,20 @@ impl<'d, T: Instance, M: Mode> Spi<'d, T, M> { // enable p.cr1().write(|w| w.set_sse(true)); } + + /// Set SPI config. + pub fn set_config(&mut self, config: &Config) { + let p = self.inner.regs(); + + // disable + p.cr1().write(|w| w.set_sse(false)); + + // change stuff + Self::apply_config(&self.inner, config); + + // enable + p.cr1().write(|w| w.set_sse(true)); + } } impl<'d, T: Instance> Spi<'d, T, Blocking> { @@ -697,15 +721,7 @@ impl<'d, T: Instance, M: Mode> SetConfig for Spi<'d, T, M> { type Config = Config; type ConfigError = (); fn set_config(&mut self, config: &Self::Config) -> Result<(), ()> { - let p = self.inner.regs(); - let (presc, postdiv) = calc_prescs(config.frequency); - p.cpsr().write(|w| w.set_cpsdvsr(presc)); - p.cr0().write(|w| { - w.set_dss(0b0111); // 8bit - w.set_spo(config.polarity == Polarity::IdleHigh); - w.set_sph(config.phase == Phase::CaptureOnSecondTransition); - w.set_scr(postdiv); - }); + self.set_config(config); Ok(()) } diff --git a/examples/rp23/src/bin/spi_sdmmc.rs b/examples/rp23/src/bin/spi_sdmmc.rs index aa6b44ffa..cfc38dfd9 100644 --- a/examples/rp23/src/bin/spi_sdmmc.rs +++ b/examples/rp23/src/bin/spi_sdmmc.rs @@ -56,7 +56,7 @@ async fn main(_spawner: Spawner) { // Now that the card is initialized, the SPI clock can go faster let mut config = spi::Config::default(); config.frequency = 16_000_000; - sdcard.spi(|dev| dev.bus_mut().set_config(&config)).ok(); + sdcard.spi(|dev| SetConfig::set_config(dev.bus_mut(), &config)).ok(); // Now let's look for volumes (also known as partitions) on our block device. // To do this we need a Volume Manager. It will take ownership of the block device. From 0138bc5dd8d0c49c86b01668b0af8a2e8dca699c Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 3 Dec 2024 00:31:36 +0100 Subject: [PATCH 0430/1217] examples/rp: update sdmmc. --- examples/rp/src/bin/spi_sdmmc.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/examples/rp/src/bin/spi_sdmmc.rs b/examples/rp/src/bin/spi_sdmmc.rs index 4cbc82f7b..a60850d0f 100644 --- a/examples/rp/src/bin/spi_sdmmc.rs +++ b/examples/rp/src/bin/spi_sdmmc.rs @@ -7,7 +7,6 @@ #![no_main] use defmt::*; -use embassy_embedded_hal::SetConfig; use embassy_executor::Spawner; use embassy_rp::spi::Spi; use embassy_rp::{gpio, spi}; @@ -51,7 +50,7 @@ async fn main(_spawner: Spawner) { // Now that the card is initialized, the SPI clock can go faster let mut config = spi::Config::default(); config.frequency = 16_000_000; - sdcard.spi(|dev| dev.bus_mut().set_config(&config)).ok(); + sdcard.spi(|dev| dev.bus_mut().set_config(&config)); // Now let's look for volumes (also known as partitions) on our block device. // To do this we need a Volume Manager. It will take ownership of the block device. From 6494429a20f6d32e9afdd82417392bcfafc73687 Mon Sep 17 00:00:00 2001 From: Enmanuel Parache Date: Wed, 6 Nov 2024 17:02:39 -0400 Subject: [PATCH 0431/1217] stm32/usart: Changing baud rate --- embassy-stm32/src/usart/mod.rs | 149 +++++++++++++++++++++++++++--- examples/stm32l1/src/bin/usart.rs | 37 ++++++++ 2 files changed, 171 insertions(+), 15 deletions(-) create mode 100644 examples/stm32l1/src/bin/usart.rs diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index d2fb85ee3..b5db672f2 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -539,6 +539,12 @@ impl<'d, M: Mode> UartTx<'d, M> { pub fn send_break(&self) { send_break(&self.info.regs); } + + /// Set baudrate + pub fn set_baudrate(&self, baudrate: u32) -> Result<(), ConfigError> + { + set_baudrate(self.info, self.kernel_clock, baudrate) + } } /// Wait until transmission complete @@ -1014,6 +1020,12 @@ impl<'d, M: Mode> UartRx<'d, M> { } Ok(()) } + + /// Set baudrate + pub fn set_baudrate(&self, baudrate: u32) -> Result<(), ConfigError> + { + set_baudrate(self.info, self.kernel_clock, baudrate) + } } impl<'d, M: Mode> Drop for UartTx<'d, M> { @@ -1455,6 +1467,14 @@ impl<'d, M: Mode> Uart<'d, M> { pub fn send_break(&self) { self.tx.send_break(); } + + /// Set baudrate + pub fn set_baudrate(&self, baudrate: u32) -> Result<(), ConfigError> + { + self.tx.set_baudrate(baudrate)?; + self.rx.set_baudrate(baudrate)?; + Ok(()) + } } fn reconfigure(info: &Info, kernel_clock: Hertz, config: &Config) -> Result<(), ConfigError> { @@ -1470,6 +1490,120 @@ fn reconfigure(info: &Info, kernel_clock: Hertz, config: &Config) -> Result<(), Ok(()) } +fn calculate_brr(baud: u32, pclk: u32, presc: u32, mul: u32) -> u32 { + // The calculation to be done to get the BRR is `mul * pclk / presc / baud` + // To do this in 32-bit only we can't multiply `mul` and `pclk` + let clock = pclk / presc; + + // The mul is applied as the last operation to prevent overflow + let brr = clock / baud * mul; + + // The BRR calculation will be a bit off because of integer rounding. + // Because we multiplied our inaccuracy with mul, our rounding now needs to be in proportion to mul. + let rounding = ((clock % baud) * mul + (baud / 2)) / baud; + + brr + rounding +} + +fn set_baudrate(info: &Info, kernel_clock: Hertz, baudrate: u32) -> Result<(), ConfigError> { + info.interrupt.disable(); + + set_usart_baudrate(info, kernel_clock, baudrate)?; + + info.interrupt.unpend(); + unsafe { info.interrupt.enable() }; + + Ok(()) +} + +fn set_usart_baudrate(info: &Info, kernel_clock: Hertz, baudrate: u32) -> Result<(), ConfigError> { + let r = info.regs; + let kind = info.kind; + + #[cfg(not(usart_v4))] + static DIVS: [(u16, ()); 1] = [(1, ())]; + + #[cfg(usart_v4)] + static DIVS: [(u16, vals::Presc); 12] = [ + (1, vals::Presc::DIV1), + (2, vals::Presc::DIV2), + (4, vals::Presc::DIV4), + (6, vals::Presc::DIV6), + (8, vals::Presc::DIV8), + (10, vals::Presc::DIV10), + (12, vals::Presc::DIV12), + (16, vals::Presc::DIV16), + (32, vals::Presc::DIV32), + (64, vals::Presc::DIV64), + (128, vals::Presc::DIV128), + (256, vals::Presc::DIV256), + ]; + + let (mul, brr_min, brr_max) = match kind { + #[cfg(any(usart_v3, usart_v4))] + Kind::Lpuart => { + trace!("USART: Kind::Lpuart"); + (256, 0x300, 0x10_0000) + } + Kind::Uart => { + trace!("USART: Kind::Uart"); + (1, 0x10, 0x1_0000) + } + }; + + r.cr1().modify(|w| { + // disable uart + w.set_ue(false); + }); + + let mut found_brr = None; + for &(presc, _presc_val) in &DIVS { + let brr = calculate_brr(baudrate, kernel_clock.0, presc as u32, mul); + trace!( + "USART: presc={}, div=0x{:08x} (mantissa = {}, fraction = {})", + presc, + brr, + brr >> 4, + brr & 0x0F + ); + + if brr < brr_min { + #[cfg(not(usart_v1))] + if brr * 2 >= brr_min && kind == Kind::Uart && !cfg!(usart_v1) { + r.brr().write_value(regs::Brr(((brr << 1) & !0xF) | (brr & 0x07))); + #[cfg(usart_v4)] + r.presc().write(|w| w.set_prescaler(_presc_val)); + found_brr = Some(brr); + break; + } + return Err(ConfigError::BaudrateTooHigh); + } + + if brr < brr_max { + r.brr().write_value(regs::Brr(brr)); + #[cfg(usart_v4)] + r.presc().write(|w| w.set_prescaler(_presc_val)); + found_brr = Some(brr); + break; + } + } + + let brr = found_brr.ok_or(ConfigError::BaudrateTooLow)?; + + trace!( + "Desired baudrate: {}, actual baudrate: {}", + baudrate, + kernel_clock.0 / brr * mul + ); + + r.cr1().modify(|w| { + // enable uart + w.set_ue(true); + }); + + Ok(()) +} + fn configure( info: &Info, kernel_clock: Hertz, @@ -1515,21 +1649,6 @@ fn configure( } }; - fn calculate_brr(baud: u32, pclk: u32, presc: u32, mul: u32) -> u32 { - // The calculation to be done to get the BRR is `mul * pclk / presc / baud` - // To do this in 32-bit only we can't multiply `mul` and `pclk` - let clock = pclk / presc; - - // The mul is applied as the last operation to prevent overflow - let brr = clock / baud * mul; - - // The BRR calculation will be a bit off because of integer rounding. - // Because we multiplied our inaccuracy with mul, our rounding now needs to be in proportion to mul. - let rounding = ((clock % baud) * mul + (baud / 2)) / baud; - - brr + rounding - } - // UART must be disabled during configuration. r.cr1().modify(|w| { w.set_ue(false); diff --git a/examples/stm32l1/src/bin/usart.rs b/examples/stm32l1/src/bin/usart.rs new file mode 100644 index 000000000..dba79b8b4 --- /dev/null +++ b/examples/stm32l1/src/bin/usart.rs @@ -0,0 +1,37 @@ +#![no_std] +#![no_main] + +use cortex_m_rt::entry; +use defmt::*; +use embassy_stm32::usart::{Config, Uart}; +use embassy_stm32::{bind_interrupts, peripherals, usart}; +use {defmt_rtt as _, panic_probe as _}; + +bind_interrupts!(struct Irqs { + USART2 => usart::InterruptHandler; +}); + +#[entry] +fn main() -> ! { + info!("Hello World!"); + + let p = embassy_stm32::init(Default::default()); + + let config = Config::default(); + let mut usart = Uart::new_blocking(p.USART2, p.PA3, p.PA2, config).unwrap(); + let desired_baudrate = 9600; // Default is 115200 and 9600 is used as example + + match usart.set_baudrate(desired_baudrate) { + Ok(_) => info!("Baud rate set to {}", desired_baudrate), + Err(err) => error!("Error setting baudrate to {}: {}", desired_baudrate, err), + } + + unwrap!(usart.blocking_write(b"Hello Embassy World!\r\n")); + info!("wrote Hello, starting echo"); + + let mut buf = [0u8; 1]; + loop { + unwrap!(usart.blocking_read(&mut buf)); + unwrap!(usart.blocking_write(&buf)); + } +} From def2601558dcc075fc9ee7dc13b5ab5e55fcb96e Mon Sep 17 00:00:00 2001 From: Enmanuel Parache Date: Wed, 6 Nov 2024 17:23:55 -0400 Subject: [PATCH 0432/1217] rustfmt --- embassy-stm32/src/usart/mod.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index b5db672f2..dc73de0c7 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -541,8 +541,7 @@ impl<'d, M: Mode> UartTx<'d, M> { } /// Set baudrate - pub fn set_baudrate(&self, baudrate: u32) -> Result<(), ConfigError> - { + pub fn set_baudrate(&self, baudrate: u32) -> Result<(), ConfigError> { set_baudrate(self.info, self.kernel_clock, baudrate) } } @@ -1022,8 +1021,7 @@ impl<'d, M: Mode> UartRx<'d, M> { } /// Set baudrate - pub fn set_baudrate(&self, baudrate: u32) -> Result<(), ConfigError> - { + pub fn set_baudrate(&self, baudrate: u32) -> Result<(), ConfigError> { set_baudrate(self.info, self.kernel_clock, baudrate) } } @@ -1469,8 +1467,7 @@ impl<'d, M: Mode> Uart<'d, M> { } /// Set baudrate - pub fn set_baudrate(&self, baudrate: u32) -> Result<(), ConfigError> - { + pub fn set_baudrate(&self, baudrate: u32) -> Result<(), ConfigError> { self.tx.set_baudrate(baudrate)?; self.rx.set_baudrate(baudrate)?; Ok(()) From 63298e2f7c5c31eecdf0f734e85e94ad5e423bcb Mon Sep 17 00:00:00 2001 From: Enmanuel Parache Date: Thu, 7 Nov 2024 14:43:27 -0400 Subject: [PATCH 0433/1217] Reduced code duplication --- embassy-stm32/src/usart/mod.rs | 183 ++++++++++++--------------------- 1 file changed, 63 insertions(+), 120 deletions(-) diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index dc73de0c7..6bde827b9 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -1513,10 +1513,12 @@ fn set_baudrate(info: &Info, kernel_clock: Hertz, baudrate: u32) -> Result<(), C Ok(()) } -fn set_usart_baudrate(info: &Info, kernel_clock: Hertz, baudrate: u32) -> Result<(), ConfigError> { - let r = info.regs; - let kind = info.kind; - +fn find_and_set_brr( + r: stm32_metapac::usart::Usart, + kind: Kind, + kernel_clock: Hertz, + baudrate: u32, +) -> Result { #[cfg(not(usart_v4))] static DIVS: [(u16, ()); 1] = [(1, ())]; @@ -1548,12 +1550,8 @@ fn set_usart_baudrate(info: &Info, kernel_clock: Hertz, baudrate: u32) -> Result } }; - r.cr1().modify(|w| { - // disable uart - w.set_ue(false); - }); - let mut found_brr = None; + let mut over8 = false; for &(presc, _presc_val) in &DIVS { let brr = calculate_brr(baudrate, kernel_clock.0, presc as u32, mul); trace!( @@ -1564,106 +1562,6 @@ fn set_usart_baudrate(info: &Info, kernel_clock: Hertz, baudrate: u32) -> Result brr & 0x0F ); - if brr < brr_min { - #[cfg(not(usart_v1))] - if brr * 2 >= brr_min && kind == Kind::Uart && !cfg!(usart_v1) { - r.brr().write_value(regs::Brr(((brr << 1) & !0xF) | (brr & 0x07))); - #[cfg(usart_v4)] - r.presc().write(|w| w.set_prescaler(_presc_val)); - found_brr = Some(brr); - break; - } - return Err(ConfigError::BaudrateTooHigh); - } - - if brr < brr_max { - r.brr().write_value(regs::Brr(brr)); - #[cfg(usart_v4)] - r.presc().write(|w| w.set_prescaler(_presc_val)); - found_brr = Some(brr); - break; - } - } - - let brr = found_brr.ok_or(ConfigError::BaudrateTooLow)?; - - trace!( - "Desired baudrate: {}, actual baudrate: {}", - baudrate, - kernel_clock.0 / brr * mul - ); - - r.cr1().modify(|w| { - // enable uart - w.set_ue(true); - }); - - Ok(()) -} - -fn configure( - info: &Info, - kernel_clock: Hertz, - config: &Config, - enable_rx: bool, - enable_tx: bool, -) -> Result<(), ConfigError> { - let r = info.regs; - let kind = info.kind; - - if !enable_rx && !enable_tx { - return Err(ConfigError::RxOrTxNotEnabled); - } - - #[cfg(not(usart_v4))] - static DIVS: [(u16, ()); 1] = [(1, ())]; - - #[cfg(usart_v4)] - static DIVS: [(u16, vals::Presc); 12] = [ - (1, vals::Presc::DIV1), - (2, vals::Presc::DIV2), - (4, vals::Presc::DIV4), - (6, vals::Presc::DIV6), - (8, vals::Presc::DIV8), - (10, vals::Presc::DIV10), - (12, vals::Presc::DIV12), - (16, vals::Presc::DIV16), - (32, vals::Presc::DIV32), - (64, vals::Presc::DIV64), - (128, vals::Presc::DIV128), - (256, vals::Presc::DIV256), - ]; - - let (mul, brr_min, brr_max) = match kind { - #[cfg(any(usart_v3, usart_v4))] - Kind::Lpuart => { - trace!("USART: Kind::Lpuart"); - (256, 0x300, 0x10_0000) - } - Kind::Uart => { - trace!("USART: Kind::Uart"); - (1, 0x10, 0x1_0000) - } - }; - - // UART must be disabled during configuration. - r.cr1().modify(|w| { - w.set_ue(false); - }); - - #[cfg(not(usart_v1))] - let mut over8 = false; - let mut found_brr = None; - for &(presc, _presc_val) in &DIVS { - let brr = calculate_brr(config.baudrate, kernel_clock.0, presc as u32, mul); - trace!( - "USART: presc={}, div=0x{:08x} (mantissa = {}, fraction = {})", - presc, - brr, - brr >> 4, - brr & 0x0F - ); - if brr < brr_min { #[cfg(not(usart_v1))] if brr * 2 >= brr_min && kind == Kind::Uart && !cfg!(usart_v1) { @@ -1686,18 +1584,63 @@ fn configure( } } - let brr = found_brr.ok_or(ConfigError::BaudrateTooLow)?; + match found_brr { + Some(brr) => { + #[cfg(not(usart_v1))] + let oversampling = if over8 { "8 bit" } else { "16 bit" }; + #[cfg(usart_v1)] + let oversampling = "default"; + trace!( + "Using {} oversampling, desired baudrate: {}, actual baudrate: {}", + oversampling, + baudrate, + kernel_clock.0 / brr * mul + ); + Ok(over8) + } + None => Err(ConfigError::BaudrateTooLow), + } +} - #[cfg(not(usart_v1))] - let oversampling = if over8 { "8 bit" } else { "16 bit" }; - #[cfg(usart_v1)] - let oversampling = "default"; - trace!( - "Using {} oversampling, desired baudrate: {}, actual baudrate: {}", - oversampling, - config.baudrate, - kernel_clock.0 / brr * mul - ); +fn set_usart_baudrate(info: &Info, kernel_clock: Hertz, baudrate: u32) -> Result<(), ConfigError> { + let r = info.regs; + r.cr1().modify(|w| { + // disable uart + w.set_ue(false); + }); + let over8 = find_and_set_brr(r, info.kind, kernel_clock, baudrate)?; + + r.cr1().modify(|w| { + // enable uart + w.set_ue(true); + + #[cfg(not(usart_v1))] + w.set_over8(vals::Over8::from_bits(over8 as _)); + }); + + Ok(()) +} + +fn configure( + info: &Info, + kernel_clock: Hertz, + config: &Config, + enable_rx: bool, + enable_tx: bool, +) -> Result<(), ConfigError> { + let r = info.regs; + let kind = info.kind; + + if !enable_rx && !enable_tx { + return Err(ConfigError::RxOrTxNotEnabled); + } + + // UART must be disabled during configuration. + r.cr1().modify(|w| { + w.set_ue(false); + }); + + let over8 = find_and_set_brr(r, kind, kernel_clock, config.baudrate)?; r.cr2().write(|w| { w.set_stop(match config.stop_bits { From 32a1b232cb74e61edc98aa5f499e58a1b13d055b Mon Sep 17 00:00:00 2001 From: Enmanuel Parache Date: Thu, 7 Nov 2024 15:24:23 -0400 Subject: [PATCH 0434/1217] Fixed build error --- embassy-stm32/src/usart/mod.rs | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index 6bde827b9..2d801e6bf 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -1513,12 +1513,7 @@ fn set_baudrate(info: &Info, kernel_clock: Hertz, baudrate: u32) -> Result<(), C Ok(()) } -fn find_and_set_brr( - r: stm32_metapac::usart::Usart, - kind: Kind, - kernel_clock: Hertz, - baudrate: u32, -) -> Result { +fn find_and_set_brr(r: Regs, kind: Kind, kernel_clock: Hertz, baudrate: u32) -> Result { #[cfg(not(usart_v4))] static DIVS: [(u16, ()); 1] = [(1, ())]; @@ -1551,7 +1546,11 @@ fn find_and_set_brr( }; let mut found_brr = None; + #[cfg(not(usart_v1))] let mut over8 = false; + #[cfg(usart_v1)] + let over8 = false; + for &(presc, _presc_val) in &DIVS { let brr = calculate_brr(baudrate, kernel_clock.0, presc as u32, mul); trace!( @@ -1608,7 +1607,11 @@ fn set_usart_baudrate(info: &Info, kernel_clock: Hertz, baudrate: u32) -> Result // disable uart w.set_ue(false); }); + + #[cfg(not(usart_v1))] let over8 = find_and_set_brr(r, info.kind, kernel_clock, baudrate)?; + #[cfg(usart_v1)] + let _over8 = find_and_set_brr(r, info.kind, kernel_clock, baudrate)?; r.cr1().modify(|w| { // enable uart @@ -1640,7 +1643,10 @@ fn configure( w.set_ue(false); }); + #[cfg(not(usart_v1))] let over8 = find_and_set_brr(r, kind, kernel_clock, config.baudrate)?; + #[cfg(usart_v1)] + let _over8 = find_and_set_brr(r, kind, kernel_clock, config.baudrate)?; r.cr2().write(|w| { w.set_stop(match config.stop_bits { From 8d2fbf0e143c99c0f10b204e5efbaa81749decbf Mon Sep 17 00:00:00 2001 From: Enmanuel Parache Date: Sat, 9 Nov 2024 12:38:02 -0400 Subject: [PATCH 0435/1217] Extend set_baudrate implementation to Buffered and RingBuffered structs --- embassy-stm32/src/usart/buffered.rs | 21 +++++++++++++++++++-- embassy-stm32/src/usart/ringbuffered.rs | 9 ++++++++- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs index f7b2bf4b4..814be2858 100644 --- a/embassy-stm32/src/usart/buffered.rs +++ b/embassy-stm32/src/usart/buffered.rs @@ -12,8 +12,8 @@ use embassy_sync::waitqueue::AtomicWaker; #[cfg(not(any(usart_v1, usart_v2)))] use super::DePin; use super::{ - clear_interrupt_flags, configure, rdr, reconfigure, send_break, sr, tdr, Config, ConfigError, CtsPin, Error, Info, - Instance, Regs, RtsPin, RxPin, TxPin, + clear_interrupt_flags, configure, rdr, reconfigure, send_break, set_baudrate, sr, tdr, Config, ConfigError, CtsPin, + Error, Info, Instance, Regs, RtsPin, RxPin, TxPin, }; use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed}; use crate::interrupt::{self, InterruptExt}; @@ -441,6 +441,13 @@ impl<'d> BufferedUart<'d> { pub fn send_break(&self) { self.tx.send_break() } + + /// Set baudrate + pub fn set_baudrate(&self, baudrate: u32) -> Result<(), ConfigError> { + self.tx.set_baudrate(baudrate)?; + self.rx.set_baudrate(baudrate)?; + Ok(()) + } } impl<'d> BufferedUartRx<'d> { @@ -535,6 +542,11 @@ impl<'d> BufferedUartRx<'d> { Ok(()) } + + /// Set baudrate + pub fn set_baudrate(&self, baudrate: u32) -> Result<(), ConfigError> { + set_baudrate(self.info, self.kernel_clock, baudrate) + } } impl<'d> BufferedUartTx<'d> { @@ -625,6 +637,11 @@ impl<'d> BufferedUartTx<'d> { pub fn send_break(&self) { send_break(&self.info.regs); } + + /// Set baudrate + pub fn set_baudrate(&self, baudrate: u32) -> Result<(), ConfigError> { + set_baudrate(self.info, self.kernel_clock, baudrate) + } } impl<'d> Drop for BufferedUartRx<'d> { diff --git a/embassy-stm32/src/usart/ringbuffered.rs b/embassy-stm32/src/usart/ringbuffered.rs index a791ac2a9..560ce4e8f 100644 --- a/embassy-stm32/src/usart/ringbuffered.rs +++ b/embassy-stm32/src/usart/ringbuffered.rs @@ -8,7 +8,9 @@ use embassy_hal_internal::PeripheralRef; use embedded_io_async::ReadReady; use futures_util::future::{select, Either}; -use super::{clear_interrupt_flags, rdr, reconfigure, sr, Config, ConfigError, Error, Info, State, UartRx}; +use super::{ + clear_interrupt_flags, rdr, reconfigure, set_baudrate, sr, Config, ConfigError, Error, Info, State, UartRx, +}; use crate::dma::ReadableRingBuffer; use crate::gpio::{AnyPin, SealedPin as _}; use crate::mode::Async; @@ -213,6 +215,11 @@ impl<'d> RingBufferedUartRx<'d> { Either::Right(((), _)) => Ok(()), } } + + /// Set baudrate + pub fn set_baudrate(&self, baudrate: u32) -> Result<(), ConfigError> { + set_baudrate(self.info, self.kernel_clock, baudrate) + } } impl Drop for RingBufferedUartRx<'_> { From 52ac74982d412a80409858e9b10479812d71cb82 Mon Sep 17 00:00:00 2001 From: Michael de Silva Date: Thu, 30 May 2024 23:41:07 +0530 Subject: [PATCH 0436/1217] Remove code that isn't used by the example --- examples/rp/src/bin/wifi_scan.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/examples/rp/src/bin/wifi_scan.rs b/examples/rp/src/bin/wifi_scan.rs index 434f0074c..2ef899080 100644 --- a/examples/rp/src/bin/wifi_scan.rs +++ b/examples/rp/src/bin/wifi_scan.rs @@ -26,11 +26,6 @@ async fn cyw43_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'stat runner.run().await } -#[embassy_executor::task] -async fn net_task(mut runner: embassy_net::Runner<'static, cyw43::NetDriver<'static>>) -> ! { - runner.run().await -} - #[embassy_executor::main] async fn main(spawner: Spawner) { info!("Hello World!"); From 1f9e678066fec147f724cf5635102d795acd8031 Mon Sep 17 00:00:00 2001 From: sawyer bristol Date: Mon, 2 Dec 2024 19:41:50 -0700 Subject: [PATCH 0437/1217] forgot to expose UsbVersion --- embassy-usb/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-usb/src/lib.rs b/embassy-usb/src/lib.rs index a5478ca0e..93dd6b4d2 100644 --- a/embassy-usb/src/lib.rs +++ b/embassy-usb/src/lib.rs @@ -23,7 +23,7 @@ mod config { use embassy_futures::select::{select, Either}; use heapless::Vec; -pub use crate::builder::{Builder, Config, FunctionBuilder, InterfaceAltBuilder, InterfaceBuilder}; +pub use crate::builder::{Builder, Config, FunctionBuilder, InterfaceAltBuilder, InterfaceBuilder, UsbVersion}; use crate::config::{MAX_HANDLER_COUNT, MAX_INTERFACE_COUNT}; use crate::control::{InResponse, OutResponse, Recipient, Request, RequestType}; use crate::descriptor::{descriptor_type, lang_id}; From 6065bc63021224b5d3650ad204b387eb622fd8c6 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Tue, 3 Dec 2024 15:13:22 +0100 Subject: [PATCH 0438/1217] Free tx buffer on ipc send failure --- embassy-net-nrf91/src/lib.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/embassy-net-nrf91/src/lib.rs b/embassy-net-nrf91/src/lib.rs index 80d08f7f5..110d0ff24 100644 --- a/embassy-net-nrf91/src/lib.rs +++ b/embassy-net-nrf91/src/lib.rs @@ -507,6 +507,7 @@ impl StateInner { if data.is_empty() { msg.data = ptr::null_mut(); msg.data_len = 0; + self.send_message_raw(msg) } else { assert!(data.len() <= TX_BUF_SIZE); let buf_idx = self.find_free_tx_buf().ok_or(NoFreeBufs)?; @@ -517,10 +518,15 @@ impl StateInner { self.tx_buf_used[buf_idx] = true; fence(Ordering::SeqCst); // synchronize copy_nonoverlapping (non-volatile) with volatile writes below. + if let Err(e) = self.send_message_raw(msg) { + msg.data = ptr::null_mut(); + msg.data_len = 0; + self.tx_buf_used[buf_idx] = false; + Err(e) + } else { + Ok(()) + } } - - // TODO free data buf if send_message_raw fails. - self.send_message_raw(msg) } fn send_message_raw(&mut self, msg: &Message) -> Result<(), NoFreeBufs> { From 0b7f9d84befa3ebf0f04bd0036b0fe9a222f7ecf Mon Sep 17 00:00:00 2001 From: sawyer bristol Date: Tue, 3 Dec 2024 09:54:15 -0700 Subject: [PATCH 0439/1217] add docs for usb version variants --- embassy-usb/src/builder.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/embassy-usb/src/builder.rs b/embassy-usb/src/builder.rs index 6c42b07dc..008a10f72 100644 --- a/embassy-usb/src/builder.rs +++ b/embassy-usb/src/builder.rs @@ -12,7 +12,9 @@ use crate::{Handler, Interface, UsbDevice, MAX_INTERFACE_COUNT, STRING_INDEX_CUS #[non_exhaustive] /// Allows Configuring the Bcd USB version below 2.1 pub enum UsbVersion { + /// Usb version 2.0 Two = 0x0200, + /// Usb version 2.1 TwoOne = 0x0210, } From aa1bd827ca36f88baa116c2bf5c2cb3c74e6b026 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Wed, 4 Dec 2024 14:24:18 +0100 Subject: [PATCH 0440/1217] Wait for tx buffers to be available for request fn --- embassy-net-nrf91/src/lib.rs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/embassy-net-nrf91/src/lib.rs b/embassy-net-nrf91/src/lib.rs index 110d0ff24..d8878f147 100644 --- a/embassy-net-nrf91/src/lib.rs +++ b/embassy-net-nrf91/src/lib.rs @@ -209,6 +209,7 @@ async fn new_internal<'a>( tx_seq_no: 0, tx_buf_used: [false; TX_BUF_COUNT], + tx_waker: WakerRegistration::new(), trace_chans: Vec::new(), trace_check: PointerChecker { @@ -311,6 +312,7 @@ struct StateInner { tx_seq_no: u16, tx_buf_used: [bool; TX_BUF_COUNT], + tx_waker: WakerRegistration, trace_chans: Vec, trace_check: PointerChecker, @@ -522,6 +524,7 @@ impl StateInner { msg.data = ptr::null_mut(); msg.data_len = 0; self.tx_buf_used[buf_idx] = false; + self.tx_waker.wake(); Err(e) } else { Ok(()) @@ -586,6 +589,7 @@ impl StateInner { ); } self.tx_buf_used[idx] = false; + self.tx_waker.wake(); } fn handle_data(&mut self, msg: &Message, ch: &mut ch::Runner) { @@ -761,10 +765,22 @@ impl<'a> Control<'a> { state.next_req_serial = state.next_req_serial.wrapping_add(1); } + drop(state); // don't borrow state across awaits. + msg.param[0..4].copy_from_slice(&req_serial.to_le_bytes()); - unwrap!(state.send_message(msg, req_data)); + + poll_fn(|cx| { + let mut state = self.state.borrow_mut(); + state.tx_waker.register(cx.waker()); + match state.send_message(msg, req_data) { + Ok(_) => Poll::Ready(()), + Err(NoFreeBufs) => Poll::Pending, + } + }) + .await; // Setup the pending request state. + let mut state = self.state.borrow_mut(); let (req_slot_idx, req_slot) = state .requests .iter_mut() From a5ab19276e5b421de4ca034121909a6e7257a5d4 Mon Sep 17 00:00:00 2001 From: Badr Bouslikhin Date: Thu, 5 Dec 2024 18:12:31 +0100 Subject: [PATCH 0441/1217] docs: document softdevice/embassy-boot-nrf integration --- embassy-boot-nrf/README.md | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/embassy-boot-nrf/README.md b/embassy-boot-nrf/README.md index f0d87e18c..b77cf80bd 100644 --- a/embassy-boot-nrf/README.md +++ b/embassy-boot-nrf/README.md @@ -6,6 +6,25 @@ An adaptation of `embassy-boot` for nRF. ## Features -* Load applications with or without the softdevice. -* Configure bootloader partitions based on linker script. -* Using watchdog timer to detect application failure. +- Load applications with or without the softdevice. +- Configure bootloader partitions based on linker script. +- Using watchdog timer to detect application failure. + +## Working with a SoftDevice + +When a SoftDevice is present, it handles starting the bootloader and the application as needed. + +The SoftDevice architecture supports the bootloader via a configurable base address, referred to as `BOOTLOADERADDR`, in the application flash region. This address can be specified either: + +1. At the `MBR_BOOTLOADER_ADDR` location in flash memory (defined in `nrf_mbr.h`), or +2. In the `UICR.NRFFW[0]` register. + +The `UICR.NRFFW[0]` register is used only if `MBR_BOOTLOADER_ADDR` has its default value of `0xFFFFFFFF`. This bootloader relies on the latter approach. + +In the `memory.x` linker script, there is a section `.uicr_bootloader_start_address` (origin `0x10001014`, length `0x4`) that stores the `BOOTLOADERADDR` value. +Ensure that `__bootloader_start` is set to the origin address of the bootloader partition. + +When a bootloader is present, the SoftDevice forwards interrupts to it and executes the bootloader reset handler, defined in the bootloader's vector table at `BOOTLOADERADDR`. + +Once the bootloader loads the application, the SoftDevice initiates the Application Reset Handler, defined in the application’s vector table at APP_CODE_BASE hardcoded in the SoftDevice. +The active partition's origin **must** match the `APP_CODE_BASE` value hardcoded within the SoftDevice. This value can be found in the release notes for each SoftDevice version. From 75a21e5045c3d770c69737df1b586e668ba5b1b1 Mon Sep 17 00:00:00 2001 From: Badr Bouslikhin Date: Thu, 5 Dec 2024 18:39:54 +0100 Subject: [PATCH 0442/1217] docs: add an faq on bootloader failures --- docs/pages/faq.adoc | 46 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/docs/pages/faq.adoc b/docs/pages/faq.adoc index d4f49bfc1..3e32563cc 100644 --- a/docs/pages/faq.adoc +++ b/docs/pages/faq.adoc @@ -385,3 +385,49 @@ async fn idle() { loop { embassy_futures::yield_now().await; } } ---- + +== Why is my bootloader restarting in loop? + +== Troubleshooting Bootloader Restart Loops + +If your bootloader restarts in a loop, there could be multiple reasons. Here are some things to check: + +=== Validate the `memory.x` File +The bootloader performs critical checks when creating partitions using the addresses defined in `memory.x`. Ensure the following assertions hold true: + +[source,rust] +---- +const { + core::assert!(Self::PAGE_SIZE % ACTIVE::WRITE_SIZE as u32 == 0); + core::assert!(Self::PAGE_SIZE % ACTIVE::ERASE_SIZE as u32 == 0); + core::assert!(Self::PAGE_SIZE % DFU::WRITE_SIZE as u32 == 0); + core::assert!(Self::PAGE_SIZE % DFU::ERASE_SIZE as u32 == 0); +} + +// Ensure enough progress pages to store copy progress +assert_eq!(0, Self::PAGE_SIZE % aligned_buf.len() as u32); +assert!(aligned_buf.len() >= STATE::WRITE_SIZE); +assert_eq!(0, aligned_buf.len() % ACTIVE::WRITE_SIZE); +assert_eq!(0, aligned_buf.len() % DFU::WRITE_SIZE); +---- + +If any of these assertions fail, the bootloader will likely restart in a loop. This failure might not log any messages (e.g., when using `defmt`). Confirm that your `memory.x` file and flash memory align with these requirements. + +=== Handling Panic Logging +Some panic errors might log messages, but certain microcontrollers reset before the message is fully printed. To ensure panic messages are logged, add a delay using no-operation (NOP) instructions before the reset: + +[source,rust] +---- +#[panic_handler] +fn panic(_info: &core::panic::PanicInfo) -> ! { + for _ in 0..10_000_000 { + cortex_m::asm::nop(); + } + cortex_m::asm::udf(); +} +---- + +=== Feed the watchdog + + +Some `embassy-boot` implementations (like `embassy-boot-nrf` and `embassy-boot-rp`) rely on a watchdog timer to detect application failure. The bootloader will restart if your application code does not properly feed the watchdog timer. Make sure to feed it correctly. From 78b536e74ba158917946ee9516924f1966f20ecd Mon Sep 17 00:00:00 2001 From: Badr Bouslikhin Date: Thu, 5 Dec 2024 18:47:33 +0100 Subject: [PATCH 0443/1217] docs: improve stm32 embassy-usb-dfu example --- .../boot/bootloader/stm32wb-dfu/README.md | 32 +++++++++++++++++-- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/examples/boot/bootloader/stm32wb-dfu/README.md b/examples/boot/bootloader/stm32wb-dfu/README.md index d5c6ea57c..3c5f268a0 100644 --- a/examples/boot/bootloader/stm32wb-dfu/README.md +++ b/examples/boot/bootloader/stm32wb-dfu/README.md @@ -1,11 +1,37 @@ # Bootloader for STM32 -The bootloader uses `embassy-boot` to interact with the flash. +This bootloader implementation uses `embassy-boot` and `embassy-usb-dfu` to manage firmware updates and interact with the flash memory on STM32WB55 devices. -# Usage +## Prerequisites -Flash the bootloader +- Rust toolchain with `cargo` installed +- `cargo-flash` for flashing the bootloader +- `dfu-util` for firmware updates +- `cargo-binutils` for binary generation + +## Usage + +### 1. Flash the Bootloader + +First, flash the bootloader to your device: ``` cargo flash --features embassy-stm32/stm32wb55rg --release --chip STM32WB55RGVx ``` + +### 2. Build and Flash Application + +Generate your application binary and flash it using DFU: + +``` +cargo objcopy --release -- -O binary fw.bin +dfu-util -d c0de:cafe -w -D fw.bin +``` + +## Troubleshooting + +- Make sure your device is in DFU mode before flashing +- Verify the USB VID:PID matches your device (c0de:cafe) +- Check USB connections if the device is not detected +- Make sure the transfer size option of `dfu-util` matches the bootloader configuration. By default, `dfu-util` will use the transfer size reported by the device, but you can override it with the `-t` option if needed. +- Make sure `control_buf` size is larger than or equal to the `usb_dfu` `BLOCK_SIZE` parameter (in this example, both are set to 4096 bytes). From 03082a9cdf65bbb675b47fc6b4ea657939fcf01b Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Fri, 6 Dec 2024 11:29:55 +0100 Subject: [PATCH 0444/1217] nrf/nfct: set correct frame delay timing. This makes it work both with and without trace logging, before it would only work with. --- embassy-nrf/src/nfct.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/embassy-nrf/src/nfct.rs b/embassy-nrf/src/nfct.rs index 2756c7952..a79cc5840 100644 --- a/embassy-nrf/src/nfct.rs +++ b/embassy-nrf/src/nfct.rs @@ -215,6 +215,12 @@ impl<'d> NfcT<'d> { r.framedelaymode().write(|w| { w.set_framedelaymode(vals::Framedelaymode::WINDOW_GRID); }); + r.framedelaymin().write(|w| { + w.set_framedelaymin(1152); + }); + r.framedelaymax().write(|w| { + w.set_framedelaymax(0xFFFF); // max + }); info!("waiting for field"); poll_fn(|cx| { @@ -259,12 +265,6 @@ impl<'d> NfcT<'d> { continue; } - // TODO: add support for "window" frame delay, which is technically - // needed to be compliant with iso14443-4 - r.framedelaymode().write(|w| { - w.set_framedelaymode(vals::Framedelaymode::FREE_RUN); - }); - // disable autocoll #[cfg(not(feature = "nrf52832"))] r.autocolresconfig().write(|w| w.0 = 0b11u32); From 0225221f8bfe71723f8673d9e316e9ab7d180782 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Fri, 6 Dec 2024 11:30:33 +0100 Subject: [PATCH 0445/1217] nrf/nfct: use the right error register for rx and tx. --- embassy-nrf/src/nfct.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/embassy-nrf/src/nfct.rs b/embassy-nrf/src/nfct.rs index a79cc5840..85866063a 100644 --- a/embassy-nrf/src/nfct.rs +++ b/embassy-nrf/src/nfct.rs @@ -328,7 +328,9 @@ impl<'d> NfcT<'d> { if r.events_error().read() != 0 { trace!("Got error?"); - warn!("errors: {:08x}", r.errorstatus().read().0); + let errs = r.errorstatus().read(); + r.errorstatus().write(|w| w.0 = 0xFFFF_FFFF); + trace!("errors: {:08x}", errs.0); r.events_error().write_value(0); return Poll::Ready(Err(Error::RxError)); } @@ -382,7 +384,9 @@ impl<'d> NfcT<'d> { if r.events_rxerror().read() != 0 { trace!("RXerror got in recv frame, should be back in idle state"); r.events_rxerror().write_value(0); - warn!("errors: {:08x}", r.errorstatus().read().0); + let errs = r.framestatus().rx().read(); + r.framestatus().rx().write(|w| w.0 = 0xFFFF_FFFF); + trace!("errors: {:08x}", errs.0); return Poll::Ready(Err(Error::RxError)); } From 306099f9d522e941c5297d9335fd239b732bbf41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Fri, 6 Dec 2024 13:23:06 +0100 Subject: [PATCH 0446/1217] Prepare embassy-usb-synopsys-otg 0.2.0 --- embassy-stm32/Cargo.toml | 2 +- embassy-usb-synopsys-otg/CHANGELOG.md | 25 +++++++++++++++++++++++++ embassy-usb-synopsys-otg/Cargo.toml | 2 +- embassy-usb-synopsys-otg/README.md | 4 ++-- 4 files changed, 29 insertions(+), 4 deletions(-) create mode 100644 embassy-usb-synopsys-otg/CHANGELOG.md diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 09b7f805a..607e90739 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -50,7 +50,7 @@ embassy-hal-internal = {version = "0.2.0", path = "../embassy-hal-internal", fea embassy-embedded-hal = {version = "0.2.0", path = "../embassy-embedded-hal", default-features = false } embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver" } embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver" } -embassy-usb-synopsys-otg = {version = "0.1.0", path = "../embassy-usb-synopsys-otg" } +embassy-usb-synopsys-otg = {version = "0.2.0", path = "../embassy-usb-synopsys-otg" } embassy-executor = { version = "0.6.3", path = "../embassy-executor", optional = true } embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } diff --git a/embassy-usb-synopsys-otg/CHANGELOG.md b/embassy-usb-synopsys-otg/CHANGELOG.md new file mode 100644 index 000000000..293363d9a --- /dev/null +++ b/embassy-usb-synopsys-otg/CHANGELOG.md @@ -0,0 +1,25 @@ +# Changelog for embassy-usb-synopsys-otg + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## Unreleased + +## 0.2.0 - 2024-12-06 + +- Fix corruption in CONTROL OUT transfers (and remove `quirk_setup_late_cnak`) +- Fix build with `defmt` enabled +- Add USBPHYC clock configuration for H7RS series +- Add support for ISO endpoints +- Add support for a full-speed ULPI mode +- Add OTG core DMA address registers +- Ensure endpoint allocation fails when `endpoint_count < MAX_EP_COUNT`. +- New configuration option: `xcvrdly` (transceiver delay). +- `EpState` now implements `Send` and `Sync`. +- The default value of `vbus_detection` is now `false`. + +## 0.1.0 - 2024-04-30 + +Initial release. diff --git a/embassy-usb-synopsys-otg/Cargo.toml b/embassy-usb-synopsys-otg/Cargo.toml index d621577bf..7a9143ef9 100644 --- a/embassy-usb-synopsys-otg/Cargo.toml +++ b/embassy-usb-synopsys-otg/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "embassy-usb-synopsys-otg" -version = "0.1.0" +version = "0.2.0" edition = "2021" license = "MIT OR Apache-2.0" description = "`embassy-usb-driver` implementation for Synopsys OTG USB controllers" diff --git a/embassy-usb-synopsys-otg/README.md b/embassy-usb-synopsys-otg/README.md index 5354f07bf..ba3c8116a 100644 --- a/embassy-usb-synopsys-otg/README.md +++ b/embassy-usb-synopsys-otg/README.md @@ -1,6 +1,6 @@ # Embassy USB driver for the Synopsys USB OTG core -This crate implements [`embassy-usb-driver`](https://crates.io/crates/embassy-usb-driver) for Synopsys USB OTG devices. +This crate implements [`embassy-usb-driver`](https://crates.io/crates/embassy-usb-driver) for Synopsys USB OTG devices. It contains the "core" of the driver that is common across all chips using the Synopsys OTG IP, but it doesn't contain chip-specific initialization such @@ -12,5 +12,5 @@ List of HALs integrating this driver: - [`embassy-stm32`](https://crates.io/crates/embassy-stm32), for STMicroelectronics STM32 chips. - [`esp-hal`](https://crates.io/crates/esp-hal), for Espressif ESP32 chips. -If you wish to integrate this crate into your device's HAL, you will need to add the +If you wish to integrate this crate into your device's HAL, you will need to add the device-specific initialization. See the above crates for examples on how to do it. \ No newline at end of file From 1bb6e455bd8de70a6132dfea19811e7cbecba479 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Fri, 6 Dec 2024 15:47:21 +0100 Subject: [PATCH 0447/1217] Keep track of raw fd used for net data --- embassy-net-nrf91/src/lib.rs | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/embassy-net-nrf91/src/lib.rs b/embassy-net-nrf91/src/lib.rs index d8878f147..3abe2c766 100644 --- a/embassy-net-nrf91/src/lib.rs +++ b/embassy-net-nrf91/src/lib.rs @@ -198,6 +198,7 @@ async fn new_internal<'a>( cb, requests: [const { None }; REQ_COUNT], next_req_serial: 0x12345678, + net_fd: None, rx_control_list: ptr::null_mut(), rx_data_list: ptr::null_mut(), @@ -305,6 +306,8 @@ struct StateInner { requests: [Option; REQ_COUNT], next_req_serial: u32, + net_fd: Option, + rx_control_list: *mut List, rx_data_list: *mut List, rx_seq_no: u16, @@ -885,6 +888,8 @@ impl<'a> Control<'a> { assert_eq!(status, 0); assert_eq!(msg.param_len, 16); let fd = u32::from_le_bytes(msg.param[12..16].try_into().unwrap()); + self.state.borrow_mut().net_fd.replace(fd); + trace!("got FD: {}", fd); fd } @@ -924,16 +929,17 @@ impl<'a> Runner<'a> { state.poll(&mut self.trace_writer, &mut self.ch); if let Poll::Ready(buf) = self.ch.poll_tx_buf(cx) { - let fd = 128u32; // TODO unhardcode - let mut msg: Message = unsafe { mem::zeroed() }; - msg.channel = 2; // data - msg.id = 0x7006_0004; // IP send - msg.param_len = 12; - msg.param[4..8].copy_from_slice(&fd.to_le_bytes()); - if let Err(e) = state.send_message(&mut msg, buf) { - warn!("tx failed: {:?}", e); + if let Some(fd) = state.net_fd { + let mut msg: Message = unsafe { mem::zeroed() }; + msg.channel = 2; // data + msg.id = 0x7006_0004; // IP send + msg.param_len = 12; + msg.param[4..8].copy_from_slice(&fd.to_le_bytes()); + if let Err(e) = state.send_message(&mut msg, buf) { + warn!("tx failed: {:?}", e); + } + self.ch.tx_done(); } - self.ch.tx_done(); } Poll::Pending From 0bec981882d5dda657a54f46afd3cfac054cd00f Mon Sep 17 00:00:00 2001 From: David Lawrence Date: Fri, 6 Dec 2024 11:07:38 -0500 Subject: [PATCH 0448/1217] STM32: bump to latest stm32-metapac HRTIM driver is updated per https://github.com/embassy-rs/stm32-data/pull/544 --- embassy-stm32/Cargo.toml | 4 ++-- embassy-stm32/src/hrtim/mod.rs | 22 ++++------------------ examples/stm32f334/src/bin/pwm.rs | 4 ++-- 3 files changed, 8 insertions(+), 22 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 607e90739..8b4e7c929 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -72,7 +72,7 @@ rand_core = "0.6.3" sdio-host = "0.5.0" critical-section = "1.1" #stm32-metapac = { version = "15" } -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-ab0ec4c19f81854189bab8215544ccd1256e1045" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-ddb0e7abab14bf3e1399875767b8834442382988" } vcell = "0.1.3" nb = "1.0.0" @@ -101,7 +101,7 @@ proc-macro2 = "1.0.36" quote = "1.0.15" #stm32-metapac = { version = "15", default-features = false, features = ["metadata"]} -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-ab0ec4c19f81854189bab8215544ccd1256e1045", default-features = false, features = ["metadata"] } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-ddb0e7abab14bf3e1399875767b8834442382988", default-features = false, features = ["metadata"] } [features] default = ["rt"] diff --git a/embassy-stm32/src/hrtim/mod.rs b/embassy-stm32/src/hrtim/mod.rs index 13343fc2a..d9b7c16fb 100644 --- a/embassy-stm32/src/hrtim/mod.rs +++ b/embassy-stm32/src/hrtim/mod.rs @@ -236,8 +236,6 @@ pub struct BridgeConverter> { impl> BridgeConverter { /// Create a new HRTIM bridge converter driver. pub fn new(_channel: C, frequency: Hertz) -> Self { - use crate::pac::hrtim::vals::{Activeeffect, Inactiveeffect}; - T::set_channel_frequency(C::raw(), frequency); // Always enable preload @@ -258,28 +256,16 @@ impl> BridgeConverter { // Therefore, software-implemented dead time must be used when setting the duty cycles // Set output 1 to active on a period event - T::regs() - .tim(C::raw()) - .setr(0) - .modify(|w| w.set_per(Activeeffect::SETACTIVE)); + T::regs().tim(C::raw()).setr(0).modify(|w| w.set_per(true)); // Set output 1 to inactive on a compare 1 event - T::regs() - .tim(C::raw()) - .rstr(0) - .modify(|w| w.set_cmp(0, Inactiveeffect::SETINACTIVE)); + T::regs().tim(C::raw()).rstr(0).modify(|w| w.set_cmp(0, true)); // Set output 2 to active on a compare 2 event - T::regs() - .tim(C::raw()) - .setr(1) - .modify(|w| w.set_cmp(1, Activeeffect::SETACTIVE)); + T::regs().tim(C::raw()).setr(1).modify(|w| w.set_cmp(1, true)); // Set output 2 to inactive on a compare 3 event - T::regs() - .tim(C::raw()) - .rstr(1) - .modify(|w| w.set_cmp(2, Inactiveeffect::SETINACTIVE)); + T::regs().tim(C::raw()).rstr(1).modify(|w| w.set_cmp(2, true)); Self { timer: PhantomData, diff --git a/examples/stm32f334/src/bin/pwm.rs b/examples/stm32f334/src/bin/pwm.rs index e6d1a6c02..2b0686121 100644 --- a/examples/stm32f334/src/bin/pwm.rs +++ b/examples/stm32f334/src/bin/pwm.rs @@ -57,14 +57,14 @@ async fn main(_spawner: Spawner) { // embassy_stm32::pac::HRTIM1 // .tim(0) // .setr(0) - // .modify(|w| w.set_sst(Activeeffect::SETACTIVE)); + // .modify(|w| w.set_sst(true)); // // Timer::after_millis(500).await; // // embassy_stm32::pac::HRTIM1 // .tim(0) // .rstr(0) - // .modify(|w| w.set_srt(Inactiveeffect::SETINACTIVE)); + // .modify(|w| w.set_srt(true)); let max_duty = buck_converter.get_max_compare_value(); From e7ca6a131d50991a0cb244b652df279e972c78dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Sat, 7 Dec 2024 18:20:09 +0100 Subject: [PATCH 0449/1217] Shrink task arena of tests --- tests/nrf/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/nrf/Cargo.toml b/tests/nrf/Cargo.toml index f91ab8b06..0d82f9866 100644 --- a/tests/nrf/Cargo.toml +++ b/tests/nrf/Cargo.toml @@ -9,7 +9,7 @@ teleprobe-meta = "1" embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt", ] } -embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "task-arena-size-16384", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "time-driver-rtc1", "gpiote", "unstable-pac"] } embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } From b7a58a6d69e0d14385bdc872721afac047edd8a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Sat, 7 Dec 2024 21:02:23 +0100 Subject: [PATCH 0450/1217] Keep 52840's task arena unchanged --- tests/nrf/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/nrf/Cargo.toml b/tests/nrf/Cargo.toml index 0d82f9866..766318998 100644 --- a/tests/nrf/Cargo.toml +++ b/tests/nrf/Cargo.toml @@ -33,7 +33,7 @@ portable-atomic = { version = "1.6.0" } nrf51422 = ["embassy-nrf/nrf51", "portable-atomic/unsafe-assume-single-core"] nrf52832 = ["embassy-nrf/nrf52832", "easydma"] nrf52833 = ["embassy-nrf/nrf52833", "easydma", "two-uarts"] -nrf52840 = ["embassy-nrf/nrf52840", "easydma", "two-uarts"] +nrf52840 = ["embassy-nrf/nrf52840", "easydma", "two-uarts", "embassy-executor/task-arena-size-16384"] nrf5340 = ["embassy-nrf/nrf5340-app-s", "easydma", "two-uarts"] nrf9160 = ["embassy-nrf/nrf9160-s", "easydma", "two-uarts"] From d1df927c03d837a50f49d349060e8e7b3aa511b9 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sat, 7 Dec 2024 22:03:23 +0100 Subject: [PATCH 0451/1217] nrf/nfct: actually fix frame timing. Now it works both with android and iOS, and both with and without logs. --- embassy-nrf/src/nfct.rs | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/embassy-nrf/src/nfct.rs b/embassy-nrf/src/nfct.rs index 85866063a..cbd3920ee 100644 --- a/embassy-nrf/src/nfct.rs +++ b/embassy-nrf/src/nfct.rs @@ -212,15 +212,13 @@ impl<'d> NfcT<'d> { #[cfg(not(feature = "nrf52832"))] r.autocolresconfig().write(|w| w.0 = 0b10); + // framedelaymax=4096 is needed to make it work with phones from + // a certain company named after some fruit. + r.framedelaymin().write(|w| w.set_framedelaymin(1152)); + r.framedelaymax().write(|w| w.set_framedelaymax(4096)); r.framedelaymode().write(|w| { w.set_framedelaymode(vals::Framedelaymode::WINDOW_GRID); }); - r.framedelaymin().write(|w| { - w.set_framedelaymin(1152); - }); - r.framedelaymax().write(|w| { - w.set_framedelaymax(0xFFFF); // max - }); info!("waiting for field"); poll_fn(|cx| { @@ -269,6 +267,17 @@ impl<'d> NfcT<'d> { #[cfg(not(feature = "nrf52832"))] r.autocolresconfig().write(|w| w.0 = 0b11u32); + // once anticoll is done, set framedelaymax to the maximum possible. + // this gives the firmware as much time as possible to reply. + // higher layer still has to reply faster than the FWT it specifies in the iso14443-4 ATS, + // but that's not our concern. + // + // nrf52832 field is 16bit instead of 20bit. this seems to force a too short timeout, maybe it's a SVD bug? + #[cfg(not(feature = "nrf52832"))] + r.framedelaymax().write(|w| w.set_framedelaymax(0xF_FFFF)); + #[cfg(feature = "nrf52832")] + r.framedelaymax().write(|w| w.set_framedelaymax(0xFFFF)); + return; } } From e2e5d0f16b946303c53be549b72a5cdc082827fe Mon Sep 17 00:00:00 2001 From: Tommy Gilligan <7865781+tommy-gilligan@users.noreply.github.com> Date: Sun, 8 Dec 2024 11:52:42 +1100 Subject: [PATCH 0452/1217] rp23: port usb_hid_keyboard example from rp --- examples/rp23/src/bin/usb_hid_keyboard.rs | 193 ++++++++++++++++++++++ 1 file changed, 193 insertions(+) create mode 100644 examples/rp23/src/bin/usb_hid_keyboard.rs diff --git a/examples/rp23/src/bin/usb_hid_keyboard.rs b/examples/rp23/src/bin/usb_hid_keyboard.rs new file mode 100644 index 000000000..29be85a49 --- /dev/null +++ b/examples/rp23/src/bin/usb_hid_keyboard.rs @@ -0,0 +1,193 @@ +#![no_std] +#![no_main] + +use core::sync::atomic::{AtomicBool, Ordering}; + +use defmt::*; +use embassy_executor::Spawner; +use embassy_futures::join::join; +use embassy_rp::bind_interrupts; +use embassy_rp::gpio::{Input, Pull}; +use embassy_rp::block::ImageDef; +use embassy_rp::peripherals::USB; +use embassy_rp::usb::{Driver as UsbDriver, InterruptHandler}; +use embassy_usb::class::hid::{HidReaderWriter, ReportId, RequestHandler, State as HidState}; +use embassy_usb::control::OutResponse; +use embassy_usb::{Builder, Config, Handler}; +use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor}; +use {defmt_rtt as _, panic_probe as _}; + +#[link_section = ".start_block"] +#[used] +pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); + +bind_interrupts!(struct Irqs { + USBCTRL_IRQ => InterruptHandler; +}); + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_rp::init(Default::default()); + // Create the driver, from the HAL. + let driver = UsbDriver::new(p.USB, Irqs); + + // Create embassy-usb Config + let mut config = Config::new(0xc0de, 0xcafe); + config.manufacturer = Some("Embassy"); + config.product = Some("HID keyboard example"); + config.serial_number = Some("12345678"); + config.max_power = 100; + config.max_packet_size_0 = 64; + + // Create embassy-usb DeviceBuilder using the driver and config. + // It needs some buffers for building the descriptors. + let mut config_descriptor = [0; 256]; + let mut bos_descriptor = [0; 256]; + // You can also add a Microsoft OS descriptor. + let mut msos_descriptor = [0; 256]; + let mut control_buf = [0; 64]; + let mut request_handler = MyRequestHandler {}; + let mut device_handler = MyDeviceHandler::new(); + + let mut state = HidState::new(); + + let mut builder = Builder::new( + driver, + config, + &mut config_descriptor, + &mut bos_descriptor, + &mut msos_descriptor, + &mut control_buf, + ); + + builder.handler(&mut device_handler); + + // Create classes on the builder. + let config = embassy_usb::class::hid::Config { + report_descriptor: KeyboardReport::desc(), + request_handler: None, + poll_ms: 60, + max_packet_size: 64, + }; + let hid = HidReaderWriter::<_, 1, 8>::new(&mut builder, &mut state, config); + + // Build the builder. + let mut usb = builder.build(); + + // Run the USB device. + let usb_fut = usb.run(); + + // Set up the signal pin that will be used to trigger the keyboard. + let mut signal_pin = Input::new(p.PIN_16, Pull::None); + + // Enable the schmitt trigger to slightly debounce. + signal_pin.set_schmitt(true); + + let (reader, mut writer) = hid.split(); + + // Do stuff with the class! + let in_fut = async { + loop { + info!("Waiting for HIGH on pin 16"); + signal_pin.wait_for_high().await; + info!("HIGH DETECTED"); + // Create a report with the A key pressed. (no shift modifier) + let report = KeyboardReport { + keycodes: [4, 0, 0, 0, 0, 0], + leds: 0, + modifier: 0, + reserved: 0, + }; + // Send the report. + match writer.write_serialize(&report).await { + Ok(()) => {} + Err(e) => warn!("Failed to send report: {:?}", e), + }; + signal_pin.wait_for_low().await; + info!("LOW DETECTED"); + let report = KeyboardReport { + keycodes: [0, 0, 0, 0, 0, 0], + leds: 0, + modifier: 0, + reserved: 0, + }; + match writer.write_serialize(&report).await { + Ok(()) => {} + Err(e) => warn!("Failed to send report: {:?}", e), + }; + } + }; + + let out_fut = async { + reader.run(false, &mut request_handler).await; + }; + + // Run everything concurrently. + // If we had made everything `'static` above instead, we could do this using separate tasks instead. + join(usb_fut, join(in_fut, out_fut)).await; +} + +struct MyRequestHandler {} + +impl RequestHandler for MyRequestHandler { + fn get_report(&mut self, id: ReportId, _buf: &mut [u8]) -> Option { + info!("Get report for {:?}", id); + None + } + + fn set_report(&mut self, id: ReportId, data: &[u8]) -> OutResponse { + info!("Set report for {:?}: {=[u8]}", id, data); + OutResponse::Accepted + } + + fn set_idle_ms(&mut self, id: Option, dur: u32) { + info!("Set idle rate for {:?} to {:?}", id, dur); + } + + fn get_idle_ms(&mut self, id: Option) -> Option { + info!("Get idle rate for {:?}", id); + None + } +} + +struct MyDeviceHandler { + configured: AtomicBool, +} + +impl MyDeviceHandler { + fn new() -> Self { + MyDeviceHandler { + configured: AtomicBool::new(false), + } + } +} + +impl Handler for MyDeviceHandler { + fn enabled(&mut self, enabled: bool) { + self.configured.store(false, Ordering::Relaxed); + if enabled { + info!("Device enabled"); + } else { + info!("Device disabled"); + } + } + + fn reset(&mut self) { + self.configured.store(false, Ordering::Relaxed); + info!("Bus reset, the Vbus current limit is 100mA"); + } + + fn addressed(&mut self, addr: u8) { + self.configured.store(false, Ordering::Relaxed); + info!("USB address set to: {}", addr); + } + + fn configured(&mut self, configured: bool) { + self.configured.store(configured, Ordering::Relaxed); + if configured { + info!("Device configured, it may now draw up to the configured current limit from Vbus.") + } else { + info!("Device is no longer configured, the Vbus current limit is 100mA."); + } + } +} From f0be2fdce4856888bd412fe9475ae55e05cf20a2 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Mon, 9 Dec 2024 15:16:03 +0100 Subject: [PATCH 0453/1217] Extend tracing api to support executor id and end task Allow applications to provide a trace implementation that only needs to implement APIs used by the embassy executor, and provide more context in the event of multiple executors being used. --- embassy-executor/Cargo.toml | 6 ++- embassy-executor/src/raw/mod.rs | 52 +++++------------- embassy-executor/src/raw/trace.rs | 90 +++++++++++++++++++++++++++++++ 3 files changed, 107 insertions(+), 41 deletions(-) create mode 100644 embassy-executor/src/raw/trace.rs diff --git a/embassy-executor/Cargo.toml b/embassy-executor/Cargo.toml index 7c930b658..0a5360e5d 100644 --- a/embassy-executor/Cargo.toml +++ b/embassy-executor/Cargo.toml @@ -31,7 +31,7 @@ features = ["defmt", "arch-cortex-m", "executor-thread", "executor-interrupt"] [dependencies] defmt = { version = "0.3", optional = true } log = { version = "0.4.14", optional = true } -rtos-trace = { version = "0.1.2", optional = true } +rtos-trace = { version = "0.1.3", optional = true } embassy-executor-macros = { version = "0.6.2", path = "../embassy-executor-macros" } embassy-time-driver = { version = "0.1.0", path = "../embassy-time-driver", optional = true } @@ -91,6 +91,10 @@ arch-spin = ["_arch"] executor-thread = [] ## Enable the interrupt-mode executor (available in Cortex-M only) executor-interrupt = [] +## Enable tracing support (adds some overhead) +trace = [] +## Enable support for rtos-trace framework +rtos-trace = ["dep:rtos-trace", "trace"] #! ### Task Arena Size #! Sets the [task arena](#task-arena) size. Necessary if you’re not using `nightly`. diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs index ebabee1ba..3f93eae6f 100644 --- a/embassy-executor/src/raw/mod.rs +++ b/embassy-executor/src/raw/mod.rs @@ -18,6 +18,8 @@ mod state; #[cfg(feature = "integrated-timers")] mod timer_queue; +#[cfg(feature = "trace")] +mod trace; pub(crate) mod util; #[cfg_attr(feature = "turbowakers", path = "waker_turbo.rs")] mod waker; @@ -31,8 +33,6 @@ use core::task::{Context, Poll}; #[cfg(feature = "integrated-timers")] use embassy_time_driver::AlarmHandle; -#[cfg(feature = "rtos-trace")] -use rtos_trace::trace; use self::run_queue::{RunQueue, RunQueueItem}; use self::state::State; @@ -352,8 +352,8 @@ impl SyncExecutor { /// - `task` must NOT be already enqueued (in this executor or another one). #[inline(always)] unsafe fn enqueue(&self, task: TaskRef) { - #[cfg(feature = "rtos-trace")] - trace::task_ready_begin(task.as_ptr() as u32); + #[cfg(feature = "trace")] + trace::task_ready_begin(self, &task); if self.run_queue.enqueue(task) { self.pender.pend(); @@ -369,8 +369,8 @@ impl SyncExecutor { pub(super) unsafe fn spawn(&'static self, task: TaskRef) { task.header().executor.set(Some(self)); - #[cfg(feature = "rtos-trace")] - trace::task_new(task.as_ptr() as u32); + #[cfg(feature = "trace")] + trace::task_new(self, &task); self.enqueue(task); } @@ -400,14 +400,14 @@ impl SyncExecutor { return; } - #[cfg(feature = "rtos-trace")] - trace::task_exec_begin(p.as_ptr() as u32); + #[cfg(feature = "trace")] + trace::task_exec_begin(self, &p); // Run the task task.poll_fn.get().unwrap_unchecked()(p); - #[cfg(feature = "rtos-trace")] - trace::task_exec_end(); + #[cfg(feature = "trace")] + trace::task_exec_end(self, &p); // Enqueue or update into timer_queue #[cfg(feature = "integrated-timers")] @@ -430,8 +430,8 @@ impl SyncExecutor { } } - #[cfg(feature = "rtos-trace")] - trace::system_idle(); + #[cfg(feature = "trace")] + trace::executor_idle(self) } } @@ -593,31 +593,3 @@ impl embassy_time_queue_driver::TimerQueue for TimerQueue { #[cfg(feature = "integrated-timers")] embassy_time_queue_driver::timer_queue_impl!(static TIMER_QUEUE: TimerQueue = TimerQueue); - -#[cfg(all(feature = "rtos-trace", feature = "integrated-timers"))] -const fn gcd(a: u64, b: u64) -> u64 { - if b == 0 { - a - } else { - gcd(b, a % b) - } -} - -#[cfg(feature = "rtos-trace")] -impl rtos_trace::RtosTraceOSCallbacks for Executor { - fn task_list() { - // We don't know what tasks exist, so we can't send them. - } - #[cfg(feature = "integrated-timers")] - fn time() -> u64 { - const GCD_1M: u64 = gcd(embassy_time_driver::TICK_HZ, 1_000_000); - embassy_time_driver::now() * (1_000_000 / GCD_1M) / (embassy_time_driver::TICK_HZ / GCD_1M) - } - #[cfg(not(feature = "integrated-timers"))] - fn time() -> u64 { - 0 - } -} - -#[cfg(feature = "rtos-trace")] -rtos_trace::global_os_callbacks! {Executor} diff --git a/embassy-executor/src/raw/trace.rs b/embassy-executor/src/raw/trace.rs new file mode 100644 index 000000000..c7bcf9c11 --- /dev/null +++ b/embassy-executor/src/raw/trace.rs @@ -0,0 +1,90 @@ +#![allow(unused)] +use crate::raw::{SyncExecutor, TaskRef}; + +#[cfg(not(feature = "rtos-trace"))] +extern "Rust" { + fn _embassy_trace_task_new(executor_id: u32, task_id: u32); + fn _embassy_trace_task_exec_begin(executor_id: u32, task_id: u32); + fn _embassy_trace_task_exec_end(excutor_id: u32, task_id: u32); + fn _embassy_trace_task_ready_begin(executor_id: u32, task_id: u32); + fn _embassy_trace_executor_idle(executor_id: u32); +} + +#[inline] +pub(crate) fn task_new(executor: &SyncExecutor, task: &TaskRef) { + #[cfg(not(feature = "rtos-trace"))] + unsafe { + _embassy_trace_task_new(executor as *const _ as u32, task.as_ptr() as u32) + } + + #[cfg(feature = "rtos-trace")] + rtos_trace::trace::task_new(task.as_ptr() as u32); +} + +#[inline] +pub(crate) fn task_ready_begin(executor: &SyncExecutor, task: &TaskRef) { + #[cfg(not(feature = "rtos-trace"))] + unsafe { + _embassy_trace_task_ready_begin(executor as *const _ as u32, task.as_ptr() as u32) + } + #[cfg(feature = "rtos-trace")] + rtos_trace::trace::task_ready_begin(task.as_ptr() as u32); +} + +#[inline] +pub(crate) fn task_exec_begin(executor: &SyncExecutor, task: &TaskRef) { + #[cfg(not(feature = "rtos-trace"))] + unsafe { + _embassy_trace_task_exec_begin(executor as *const _ as u32, task.as_ptr() as u32) + } + #[cfg(feature = "rtos-trace")] + rtos_trace::trace::task_exec_begin(task.as_ptr() as u32); +} + +#[inline] +pub(crate) fn task_exec_end(executor: &SyncExecutor, task: &TaskRef) { + #[cfg(not(feature = "rtos-trace"))] + unsafe { + _embassy_trace_task_exec_end(executor as *const _ as u32, task.as_ptr() as u32) + } + #[cfg(feature = "rtos-trace")] + rtos_trace::trace::task_exec_end(); +} + +#[inline] +pub(crate) fn executor_idle(executor: &SyncExecutor) { + #[cfg(not(feature = "rtos-trace"))] + unsafe { + _embassy_trace_executor_idle(executor as *const _ as u32) + } + #[cfg(feature = "rtos-trace")] + rtos_trace::trace::system_idle(); +} + +#[cfg(all(feature = "rtos-trace", feature = "integrated-timers"))] +const fn gcd(a: u64, b: u64) -> u64 { + if b == 0 { + a + } else { + gcd(b, a % b) + } +} + +#[cfg(feature = "rtos-trace")] +impl rtos_trace::RtosTraceOSCallbacks for crate::raw::SyncExecutor { + fn task_list() { + // We don't know what tasks exist, so we can't send them. + } + #[cfg(feature = "integrated-timers")] + fn time() -> u64 { + const GCD_1M: u64 = gcd(embassy_time_driver::TICK_HZ, 1_000_000); + embassy_time_driver::now() * (1_000_000 / GCD_1M) / (embassy_time_driver::TICK_HZ / GCD_1M) + } + #[cfg(not(feature = "integrated-timers"))] + fn time() -> u64 { + 0 + } +} + +#[cfg(feature = "rtos-trace")] +rtos_trace::global_os_callbacks! {SyncExecutor} From 30ba7b85df4329ab22588628907bceac89318051 Mon Sep 17 00:00:00 2001 From: Tommy Gilligan <7865781+tommy-gilligan@users.noreply.github.com> Date: Tue, 10 Dec 2024 06:27:22 +1100 Subject: [PATCH 0454/1217] cargo +nightly fmt --- examples/rp23/src/bin/usb_hid_keyboard.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/rp23/src/bin/usb_hid_keyboard.rs b/examples/rp23/src/bin/usb_hid_keyboard.rs index 29be85a49..ec1e88746 100644 --- a/examples/rp23/src/bin/usb_hid_keyboard.rs +++ b/examples/rp23/src/bin/usb_hid_keyboard.rs @@ -7,8 +7,8 @@ use defmt::*; use embassy_executor::Spawner; use embassy_futures::join::join; use embassy_rp::bind_interrupts; -use embassy_rp::gpio::{Input, Pull}; use embassy_rp::block::ImageDef; +use embassy_rp::gpio::{Input, Pull}; use embassy_rp::peripherals::USB; use embassy_rp::usb::{Driver as UsbDriver, InterruptHandler}; use embassy_usb::class::hid::{HidReaderWriter, ReportId, RequestHandler, State as HidState}; From 0b9cdd86ab398ddbc96f6859c6a33f55c788fbc6 Mon Sep 17 00:00:00 2001 From: Gerhard de Clercq <11624490+Gerharddc@users.noreply.github.com> Date: Tue, 10 Dec 2024 09:21:37 +0100 Subject: [PATCH 0455/1217] embassy-usb-dfu: use correct function descriptors This should allow things to work properly even when IADs are used. --- embassy-usb-dfu/src/dfu.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-usb-dfu/src/dfu.rs b/embassy-usb-dfu/src/dfu.rs index abd929a9e..c23286cf5 100644 --- a/embassy-usb-dfu/src/dfu.rs +++ b/embassy-usb-dfu/src/dfu.rs @@ -189,7 +189,7 @@ pub fn usb_dfu<'d, D: Driver<'d>, DFU: NorFlash, STATE: NorFlash, RST: Reset, co builder: &mut Builder<'d, D>, handler: &'d mut Control<'d, DFU, STATE, RST, BLOCK_SIZE>, ) { - let mut func = builder.function(0x00, 0x00, 0x00); + let mut func = builder.function(USB_CLASS_APPN_SPEC, APPN_SPEC_SUBCLASS_DFU, DFU_PROTOCOL_DFU); let mut iface = func.interface(); let mut alt = iface.alt_setting(USB_CLASS_APPN_SPEC, APPN_SPEC_SUBCLASS_DFU, DFU_PROTOCOL_DFU, None); alt.descriptor( From 5963a10d4d541ef93e42ccfe339aa9aa343f2914 Mon Sep 17 00:00:00 2001 From: Gerhard de Clercq <11624490+Gerharddc@users.noreply.github.com> Date: Tue, 10 Dec 2024 09:31:47 +0100 Subject: [PATCH 0456/1217] stm32wb-dfu: add MSOS headers The USB DFU example now shows how to automatically get the WinUSB driver assigned. --- .../boot/bootloader/stm32wb-dfu/src/main.rs | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/examples/boot/bootloader/stm32wb-dfu/src/main.rs b/examples/boot/bootloader/stm32wb-dfu/src/main.rs index 093b39f9d..b09d53cf0 100644 --- a/examples/boot/bootloader/stm32wb-dfu/src/main.rs +++ b/examples/boot/bootloader/stm32wb-dfu/src/main.rs @@ -12,7 +12,7 @@ use embassy_stm32::rcc::WPAN_DEFAULT; use embassy_stm32::usb::Driver; use embassy_stm32::{bind_interrupts, peripherals, usb}; use embassy_sync::blocking_mutex::Mutex; -use embassy_usb::Builder; +use embassy_usb::{msos, Builder}; use embassy_usb_dfu::consts::DfuAttributes; use embassy_usb_dfu::{usb_dfu, Control, ResetImmediate}; @@ -20,6 +20,9 @@ bind_interrupts!(struct Irqs { USB_LP => usb::InterruptHandler; }); +// This is a randomly generated GUID to allow clients on Windows to find our device +const DEVICE_INTERFACE_GUIDS: &[&str] = &["{EAA9A5DC-30BA-44BC-9232-606CDC875321}"]; + #[entry] fn main() -> ! { let mut config = embassy_stm32::Config::default(); @@ -62,6 +65,18 @@ fn main() -> ! { &mut control_buf, ); + // We add MSOS headers so that the device automatically gets assigned the WinUSB driver on Windows. + // Otherwise users need to do this manually using a tool like Zadig. + // + // It seems it is important for the DFU class that these headers be on the Device level. + // + builder.msos_descriptor(msos::windows_version::WIN8_1, 2); + builder.msos_feature(msos::CompatibleIdFeatureDescriptor::new("WINUSB", "")); + builder.msos_feature(msos::RegistryPropertyFeatureDescriptor::new( + "DeviceInterfaceGUIDs", + msos::PropertyData::RegMultiSz(DEVICE_INTERFACE_GUIDS), + )); + usb_dfu::<_, _, _, ResetImmediate, 4096>(&mut builder, &mut state); let mut dev = builder.build(); From 501d3942e8b6b04fd1cb4c14728ba4c2e118d8b5 Mon Sep 17 00:00:00 2001 From: Dave Marples Date: Thu, 5 Dec 2024 16:35:56 +0000 Subject: [PATCH 0457/1217] Add support for stm32u595/5a5 OTG_HS in client mode --- embassy-stm32/src/usb/mod.rs | 20 ++++ embassy-stm32/src/usb/otg.rs | 32 ++++-- examples/stm32u5/src/bin/usb_hs_serial.rs | 129 ++++++++++++++++++++++ 3 files changed, 174 insertions(+), 7 deletions(-) create mode 100644 examples/stm32u5/src/bin/usb_hs_serial.rs diff --git a/embassy-stm32/src/usb/mod.rs b/embassy-stm32/src/usb/mod.rs index a473285bf..9737b9b3f 100644 --- a/embassy-stm32/src/usb/mod.rs +++ b/embassy-stm32/src/usb/mod.rs @@ -26,6 +26,7 @@ fn common_init() { // Clock might not be exact 48Mhz due to rounding errors in PLL calculation, or if the user // has tight clock restrictions due to something else (like audio). #[cfg(not(stm32h7rs))] + #[cfg(not(all(stm32u5, peri_usb_otg_hs)))] if freq.0.abs_diff(48_000_000) > 120_000 { panic!( "USB clock should be 48Mhz but is {} Hz. Please double-check your RCC settings.", @@ -33,6 +34,15 @@ fn common_init() { ) } + // For OTG-HS on STM32U5 only the 32MHz clock is fast enough (Table 762, Sect 73.14.4) + #[cfg(all(stm32u5, peri_usb_otg_hs))] + if freq.0.abs_diff(32_000_000) > 120_000 { + panic!( + "USB clock should be 32Mhz but is {} Hz. Please double-check your RCC settings.", + freq.0 + ) + } + #[cfg(any(stm32l4, stm32l5, stm32wb, stm32u0))] critical_section::with(|_| crate::pac::PWR.cr2().modify(|w| w.set_usv(true))); @@ -90,6 +100,16 @@ fn common_init() { // Wait for USB power to stabilize while !crate::pac::PWR.svmsr().read().vddusbrdy() {} + + // Now set up transceiver power if it's a OTG-HS + #[cfg(peri_usb_otg_hs)] + { + crate::pac::PWR.vosr().modify(|w| { + w.set_usbpwren(true); + w.set_usbboosten(true); + }); + while !crate::pac::PWR.vosr().read().usbboostrdy() {} + } } T::Interrupt::unpend(); diff --git a/embassy-stm32/src/usb/otg.rs b/embassy-stm32/src/usb/otg.rs index 6ca28b156..d1b38a558 100644 --- a/embassy-stm32/src/usb/otg.rs +++ b/embassy-stm32/src/usb/otg.rs @@ -26,7 +26,6 @@ impl interrupt::typelevel::Handler for InterruptHandl unsafe fn on_interrupt() { let r = T::regs(); let state = T::state(); - on_interrupt_impl(r, state, T::ENDPOINT_COUNT); } } @@ -103,15 +102,18 @@ impl<'d, T: Instance> Driver<'d, T> { pub fn new_hs( _peri: impl Peripheral

+ 'd, _irq: impl interrupt::typelevel::Binding> + 'd, - dp: impl Peripheral

> + 'd, - dm: impl Peripheral

> + 'd, + _dp: impl Peripheral

> + 'd, + _dm: impl Peripheral

> + 'd, ep_out_buffer: &'d mut [u8], config: Config, ) -> Self { - into_ref!(dp, dm); - - dp.set_as_af(dp.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh)); - dm.set_as_af(dm.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh)); + // For STM32U5 High speed pins need to be left in analog mode + #[cfg(not(all(stm32u5, peri_usb_otg_hs)))] + { + into_ref!(_dp, _dm); + _dp.set_as_af(_dp.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh)); + _dm.set_as_af(_dm.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh)); + } let instance = OtgInstance { regs: T::regs(), @@ -311,6 +313,22 @@ impl<'d, T: Instance> Bus<'d, T> { }); }); + #[cfg(all(stm32u5, peri_usb_otg_hs))] + { + // Only the 32MHz clock is suitable here, which the magic number represents + crate::pac::SYSCFG.otghsphycr().modify(|w| { + w.set_clksel(11); + w.set_en(true); + }); + + critical_section::with(|_| { + crate::pac::RCC.ahb2enr1().modify(|w| { + w.set_usb_otg_hsen(true); + w.set_usb_otg_hs_phyen(true); + }); + }); + } + let r = T::regs(); let core_id = r.cid().read().0; trace!("Core id {:08x}", core_id); diff --git a/examples/stm32u5/src/bin/usb_hs_serial.rs b/examples/stm32u5/src/bin/usb_hs_serial.rs new file mode 100644 index 000000000..5549e2cbb --- /dev/null +++ b/examples/stm32u5/src/bin/usb_hs_serial.rs @@ -0,0 +1,129 @@ +#![no_std] +#![no_main] + +use defmt::{panic, *}; +use defmt_rtt as _; // global logger +use embassy_executor::Spawner; +use embassy_futures::join::join; +use embassy_stm32::usb::{Driver, Instance}; +use embassy_stm32::{bind_interrupts, peripherals, usb, Config}; +use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; +use embassy_usb::driver::EndpointError; +use embassy_usb::Builder; +use panic_probe as _; + +bind_interrupts!(struct Irqs { + OTG_HS => usb::InterruptHandler; +}); + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + info!("Hello World!"); + + let mut config = Config::default(); + { + use embassy_stm32::rcc::*; + use embassy_stm32::time::Hertz; + config.rcc.hse = Some(Hse { + freq: Hertz(16_000_000), + mode: HseMode::Oscillator, + }); + config.rcc.pll1 = Some(Pll { + source: PllSource::HSE, + prediv: PllPreDiv::DIV2, // HSE / 2 = 8MHz + mul: PllMul::MUL60, // 8MHz * 60 = 480MHz + divr: Some(PllDiv::DIV3), // 480MHz / 3 = 160MHz (sys_ck) + divq: Some(PllDiv::DIV10), // 480MHz / 10 = 48MHz (USB) + divp: Some(PllDiv::DIV15), // 480MHz / 15 = 32MHz (USBOTG) + }); + config.rcc.mux.otghssel = mux::Otghssel::PLL1_P; + config.rcc.voltage_range = VoltageScale::RANGE1; + config.rcc.sys = Sysclk::PLL1_R; + } + + let p = embassy_stm32::init(config); + + // Create the driver, from the HAL. + let mut ep_out_buffer = [0u8; 256]; + let mut config = embassy_stm32::usb::Config::default(); + // Do not enable vbus_detection. This is a safe default that works in all boards. + // However, if your USB device is self-powered (can stay powered on if USB is unplugged), you need + // to enable vbus_detection to comply with the USB spec. If you enable it, the board + // has to support it or USB won't work at all. See docs on `vbus_detection` for details. + config.vbus_detection = false; + let driver = Driver::new_hs(p.USB_OTG_HS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); + + // Create embassy-usb Config + let mut config = embassy_usb::Config::new(0xc0de, 0xcafe); + config.manufacturer = Some("Embassy"); + config.product = Some("USB-serial example"); + config.serial_number = Some("12345678"); + + // Required for windows compatibility. + // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help + config.device_class = 0xEF; + config.device_sub_class = 0x02; + config.device_protocol = 0x01; + config.composite_with_iads = true; + + // Create embassy-usb DeviceBuilder using the driver and config. + // It needs some buffers for building the descriptors. + let mut config_descriptor = [0; 256]; + let mut bos_descriptor = [0; 256]; + let mut control_buf = [0; 64]; + + let mut state = State::new(); + + let mut builder = Builder::new( + driver, + config, + &mut config_descriptor, + &mut bos_descriptor, + &mut [], // no msos descriptors + &mut control_buf, + ); + + // Create classes on the builder. + let mut class = CdcAcmClass::new(&mut builder, &mut state, 64); + + // Build the builder. + let mut usb = builder.build(); + + // Run the USB device. + let usb_fut = usb.run(); + + // Do stuff with the class! + let echo_fut = async { + loop { + class.wait_connection().await; + info!("Connected"); + let _ = echo(&mut class).await; + info!("Disconnected"); + } + }; + + // Run everything concurrently. + // If we had made everything `'static` above instead, we could do this using separate tasks instead. + join(usb_fut, echo_fut).await; +} + +struct Disconnected {} + +impl From for Disconnected { + fn from(val: EndpointError) -> Self { + match val { + EndpointError::BufferOverflow => panic!("Buffer overflow"), + EndpointError::Disabled => Disconnected {}, + } + } +} + +async fn echo<'d, T: Instance + 'd>(class: &mut CdcAcmClass<'d, Driver<'d, T>>) -> Result<(), Disconnected> { + let mut buf = [0; 64]; + loop { + let n = class.read_packet(&mut buf).await?; + let data = &buf[..n]; + info!("data: {:x}", data); + class.write_packet(data).await?; + } +} From a0e056a629c166b38c536c68afbf852819f10143 Mon Sep 17 00:00:00 2001 From: Marvin Drees Date: Fri, 6 Dec 2024 16:22:08 +0100 Subject: [PATCH 0458/1217] Update STM32U5 OTG HS clock handling Signed-off-by: Marvin Drees --- embassy-stm32/src/rcc/u5.rs | 29 +++++++++++++++++++++++++++++ embassy-stm32/src/usb/mod.rs | 14 ++------------ embassy-stm32/src/usb/otg.rs | 2 -- 3 files changed, 31 insertions(+), 14 deletions(-) diff --git a/embassy-stm32/src/rcc/u5.rs b/embassy-stm32/src/rcc/u5.rs index af99c77bc..dc77dc540 100644 --- a/embassy-stm32/src/rcc/u5.rs +++ b/embassy-stm32/src/rcc/u5.rs @@ -1,9 +1,13 @@ pub use crate::pac::pwr::vals::Vos as VoltageScale; +#[cfg(all(peri_usb_otg_hs))] +pub use crate::pac::rcc::vals::Otghssel; pub use crate::pac::rcc::vals::{ Hpre as AHBPrescaler, Msirange, Msirange as MSIRange, Plldiv as PllDiv, Pllm as PllPreDiv, Plln as PllMul, Pllsrc as PllSource, Ppre as APBPrescaler, Sw as Sysclk, }; use crate::pac::rcc::vals::{Hseext, Msirgsel, Pllmboost, Pllrge}; +#[cfg(all(peri_usb_otg_hs))] +pub use crate::pac::{syscfg::vals::Usbrefcksel, SYSCFG}; use crate::pac::{FLASH, PWR, RCC}; use crate::rcc::LSI_FREQ; use crate::time::Hertz; @@ -295,6 +299,31 @@ pub(crate) unsafe fn init(config: Config) { let rtc = config.ls.init(); + #[cfg(all(stm32u5, peri_usb_otg_hs))] + let usb_refck = match config.mux.otghssel { + Otghssel::HSE => hse, + Otghssel::HSE_DIV_2 => hse.map(|hse_val| hse_val / 2u8), + Otghssel::PLL1_P => pll1.p, + Otghssel::PLL1_P_DIV_2 => pll1.p.map(|pll1p_val| pll1p_val / 2u8), + }; + #[cfg(all(stm32u5, peri_usb_otg_hs))] + let usb_refck_sel = match usb_refck { + Some(clk_val) => match clk_val { + Hertz(16_000_000) => Usbrefcksel::MHZ16, + Hertz(19_200_000) => Usbrefcksel::MHZ19_2, + Hertz(20_000_000) => Usbrefcksel::MHZ20, + Hertz(24_000_000) => Usbrefcksel::MHZ24, + Hertz(26_000_000) => Usbrefcksel::MHZ26, + Hertz(32_000_000) => Usbrefcksel::MHZ32, + _ => panic!("cannot select OTG_HS reference clock with source frequency of {} Hz, must be one of 16, 19.2, 20, 24, 26, 32 MHz", clk_val), + }, + None => Usbrefcksel::MHZ24, + }; + #[cfg(all(stm32u5, peri_usb_otg_hs))] + SYSCFG.otghsphycr().modify(|w| { + w.set_clksel(usb_refck_sel); + }); + let lse = config.ls.lse.map(|l| l.frequency); let lsi = config.ls.lsi.then_some(LSI_FREQ); diff --git a/embassy-stm32/src/usb/mod.rs b/embassy-stm32/src/usb/mod.rs index 9737b9b3f..ae5963420 100644 --- a/embassy-stm32/src/usb/mod.rs +++ b/embassy-stm32/src/usb/mod.rs @@ -15,7 +15,7 @@ fn common_init() { let freq = T::frequency(); // On the H7RS, the USBPHYC embeds a PLL accepting one of the input frequencies listed below and providing 48MHz to OTG_FS and 60MHz to OTG_HS internally - #[cfg(stm32h7rs)] + #[cfg(any(stm32h7rs, all(stm32u5, peri_usb_otg_hs)))] if ![16_000_000, 19_200_000, 20_000_000, 24_000_000, 26_000_000, 32_000_000].contains(&freq.0) { panic!( "USB clock should be one of 16, 19.2, 20, 24, 26, 32Mhz but is {} Hz. Please double-check your RCC settings.", @@ -25,8 +25,7 @@ fn common_init() { // Check frequency is within the 0.25% tolerance allowed by the spec. // Clock might not be exact 48Mhz due to rounding errors in PLL calculation, or if the user // has tight clock restrictions due to something else (like audio). - #[cfg(not(stm32h7rs))] - #[cfg(not(all(stm32u5, peri_usb_otg_hs)))] + #[cfg(not(any(stm32h7rs, all(stm32u5, peri_usb_otg_hs))))] if freq.0.abs_diff(48_000_000) > 120_000 { panic!( "USB clock should be 48Mhz but is {} Hz. Please double-check your RCC settings.", @@ -34,15 +33,6 @@ fn common_init() { ) } - // For OTG-HS on STM32U5 only the 32MHz clock is fast enough (Table 762, Sect 73.14.4) - #[cfg(all(stm32u5, peri_usb_otg_hs))] - if freq.0.abs_diff(32_000_000) > 120_000 { - panic!( - "USB clock should be 32Mhz but is {} Hz. Please double-check your RCC settings.", - freq.0 - ) - } - #[cfg(any(stm32l4, stm32l5, stm32wb, stm32u0))] critical_section::with(|_| crate::pac::PWR.cr2().modify(|w| w.set_usv(true))); diff --git a/embassy-stm32/src/usb/otg.rs b/embassy-stm32/src/usb/otg.rs index d1b38a558..d3c7978e4 100644 --- a/embassy-stm32/src/usb/otg.rs +++ b/embassy-stm32/src/usb/otg.rs @@ -315,9 +315,7 @@ impl<'d, T: Instance> Bus<'d, T> { #[cfg(all(stm32u5, peri_usb_otg_hs))] { - // Only the 32MHz clock is suitable here, which the magic number represents crate::pac::SYSCFG.otghsphycr().modify(|w| { - w.set_clksel(11); w.set_en(true); }); From 1e2cbeae68d12a37ff73292294bb96c9282476bd Mon Sep 17 00:00:00 2001 From: ROMemories <152802150+ROMemories@users.noreply.github.com> Date: Tue, 10 Dec 2024 14:17:53 +0100 Subject: [PATCH 0459/1217] fix(embassy-net): make the `Config` constructors `const` --- embassy-net/src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/embassy-net/src/lib.rs b/embassy-net/src/lib.rs index ec7f10fdd..831e01d44 100644 --- a/embassy-net/src/lib.rs +++ b/embassy-net/src/lib.rs @@ -180,7 +180,7 @@ pub struct Config { impl Config { /// IPv4 configuration with static addressing. #[cfg(feature = "proto-ipv4")] - pub fn ipv4_static(config: StaticConfigV4) -> Self { + pub const fn ipv4_static(config: StaticConfigV4) -> Self { Self { ipv4: ConfigV4::Static(config), #[cfg(feature = "proto-ipv6")] @@ -190,7 +190,7 @@ impl Config { /// IPv6 configuration with static addressing. #[cfg(feature = "proto-ipv6")] - pub fn ipv6_static(config: StaticConfigV6) -> Self { + pub const fn ipv6_static(config: StaticConfigV6) -> Self { Self { #[cfg(feature = "proto-ipv4")] ipv4: ConfigV4::None, @@ -206,7 +206,7 @@ impl Config { /// let _cfg = Config::dhcpv4(Default::default()); /// ``` #[cfg(feature = "dhcpv4")] - pub fn dhcpv4(config: DhcpConfig) -> Self { + pub const fn dhcpv4(config: DhcpConfig) -> Self { Self { ipv4: ConfigV4::Dhcp(config), #[cfg(feature = "proto-ipv6")] From cfe6bc172404131cb03c3078cc6d91b1dd5a8014 Mon Sep 17 00:00:00 2001 From: Gabrael Levine Date: Tue, 10 Dec 2024 11:06:28 -0800 Subject: [PATCH 0460/1217] Add missing opamp external outputs for STM32G4 --- embassy-stm32/src/opamp.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/embassy-stm32/src/opamp.rs b/embassy-stm32/src/opamp.rs index c86c18e22..d1c53a740 100644 --- a/embassy-stm32/src/opamp.rs +++ b/embassy-stm32/src/opamp.rs @@ -251,10 +251,12 @@ foreach_peripheral!( impl_opamp_external_output!(OPAMP2, ADC2, 3); }; (opamp, OPAMP3) => { + impl_opamp_external_output!(OPAMP3, ADC1, 12); impl_opamp_external_output!(OPAMP3, ADC3, 1); }; // OPAMP4 only in STM32G4 Cat 3 devices (opamp, OPAMP4) => { + impl_opamp_external_output!(OPAMP4, ADC1, 11); impl_opamp_external_output!(OPAMP4, ADC4, 3); }; // OPAMP5 only in STM32G4 Cat 3 devices @@ -264,6 +266,7 @@ foreach_peripheral!( // OPAMP6 only in STM32G4 Cat 3/4 devices (opamp, OPAMP6) => { impl_opamp_external_output!(OPAMP6, ADC1, 14); + impl_opamp_external_output!(OPAMP6, ADC2, 14); }; ); From 5a5495aac43d75610735f2ca80fb6c8e8f31ed71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Tue, 26 Nov 2024 23:54:21 +0100 Subject: [PATCH 0461/1217] Refactor integrated-timers --- .github/ci/test.sh | 2 +- ci-xtensa.sh | 4 +- ci.sh | 4 +- embassy-executor/Cargo.toml | 2 +- embassy-executor/src/arch/avr.rs | 4 - embassy-executor/src/arch/cortex_m.rs | 6 - embassy-executor/src/arch/riscv32.rs | 4 - embassy-executor/src/arch/spin.rs | 4 - embassy-executor/src/arch/std.rs | 4 - embassy-executor/src/arch/wasm.rs | 4 - embassy-executor/src/raw/mod.rs | 135 ++----- embassy-executor/src/raw/timer_queue.rs | 89 +++-- embassy-executor/src/raw/util.rs | 5 + embassy-executor/tests/test.rs | 3 - embassy-nrf/Cargo.toml | 3 +- embassy-nrf/src/time_driver.rs | 117 ++---- embassy-rp/Cargo.toml | 3 +- embassy-rp/src/time_driver.rs | 130 ++----- embassy-stm32/Cargo.toml | 4 +- embassy-stm32/src/low_power.rs | 3 - embassy-stm32/src/time_driver.rs | 154 +++----- embassy-time-driver/src/lib.rs | 135 +------ embassy-time-queue-driver/Cargo.toml | 33 ++ embassy-time-queue-driver/src/lib.rs | 136 ++++++- .../src/queue_generic.rs | 146 ++++++++ embassy-time/Cargo.toml | 24 -- embassy-time/src/driver_mock.rs | 85 ++--- embassy-time/src/driver_std.rs | 119 ++---- embassy-time/src/driver_wasm.rs | 80 ++-- embassy-time/src/lib.rs | 2 - embassy-time/src/queue_generic.rs | 346 ------------------ examples/nrf52840-rtic/Cargo.toml | 3 +- 32 files changed, 611 insertions(+), 1182 deletions(-) create mode 100644 embassy-time-queue-driver/src/queue_generic.rs delete mode 100644 embassy-time/src/queue_generic.rs diff --git a/.github/ci/test.sh b/.github/ci/test.sh index 0fe088bfe..285f3f29e 100755 --- a/.github/ci/test.sh +++ b/.github/ci/test.sh @@ -17,7 +17,7 @@ cargo test --manifest-path ./embassy-futures/Cargo.toml cargo test --manifest-path ./embassy-sync/Cargo.toml cargo test --manifest-path ./embassy-embedded-hal/Cargo.toml cargo test --manifest-path ./embassy-hal-internal/Cargo.toml -cargo test --manifest-path ./embassy-time/Cargo.toml --features generic-queue,mock-driver +cargo test --manifest-path ./embassy-time/Cargo.toml --features mock-driver cargo test --manifest-path ./embassy-time-driver/Cargo.toml cargo test --manifest-path ./embassy-boot/Cargo.toml diff --git a/ci-xtensa.sh b/ci-xtensa.sh index 32d362def..2cac7444c 100755 --- a/ci-xtensa.sh +++ b/ci-xtensa.sh @@ -24,7 +24,9 @@ cargo batch \ --- build --release --manifest-path embassy-executor/Cargo.toml --target xtensa-esp32-none-elf --features arch-spin,executor-thread \ --- build --release --manifest-path embassy-executor/Cargo.toml --target xtensa-esp32-none-elf --features arch-spin,executor-thread,integrated-timers \ --- build --release --manifest-path embassy-sync/Cargo.toml --target xtensa-esp32s2-none-elf --features defmt \ - --- build --release --manifest-path embassy-time/Cargo.toml --target xtensa-esp32s2-none-elf --features defmt,defmt-timestamp-uptime,generic-queue-8,mock-driver \ + --- build --release --manifest-path embassy-time/Cargo.toml --target xtensa-esp32s2-none-elf --features defmt,defmt-timestamp-uptime,mock-driver \ + --- build --release --manifest-path embassy-time-queue-driver/Cargo.toml --target xtensa-esp32s2-none-elf --features integrated-timers \ + --- build --release --manifest-path embassy-time-queue-driver/Cargo.toml --target xtensa-esp32s2-none-elf --features generic-queue-8 \ --- build --release --manifest-path embassy-net/Cargo.toml --target xtensa-esp32-none-elf --features defmt,tcp,udp,dns,proto-ipv4,medium-ethernet,packet-trace \ --- build --release --manifest-path embassy-net/Cargo.toml --target xtensa-esp32-none-elf --features defmt,tcp,udp,dns,proto-ipv4,multicast,medium-ethernet \ --- build --release --manifest-path embassy-net/Cargo.toml --target xtensa-esp32-none-elf --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet \ diff --git a/ci.sh b/ci.sh index 307e268c4..71b862632 100755 --- a/ci.sh +++ b/ci.sh @@ -45,7 +45,9 @@ cargo batch \ --- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features arch-riscv32,executor-thread \ --- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features arch-riscv32,executor-thread,integrated-timers \ --- build --release --manifest-path embassy-sync/Cargo.toml --target thumbv6m-none-eabi --features defmt \ - --- build --release --manifest-path embassy-time/Cargo.toml --target thumbv6m-none-eabi --features defmt,defmt-timestamp-uptime,generic-queue-8,mock-driver \ + --- build --release --manifest-path embassy-time/Cargo.toml --target thumbv6m-none-eabi --features defmt,defmt-timestamp-uptime,mock-driver \ + --- build --release --manifest-path embassy-time-queue-driver/Cargo.toml --target thumbv6m-none-eabi --features integrated-timers \ + --- build --release --manifest-path embassy-time-queue-driver/Cargo.toml --target thumbv6m-none-eabi --features generic-queue-8 \ --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,medium-ethernet,packet-trace \ --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,multicast,medium-ethernet \ --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet \ diff --git a/embassy-executor/Cargo.toml b/embassy-executor/Cargo.toml index 0a5360e5d..862d25b59 100644 --- a/embassy-executor/Cargo.toml +++ b/embassy-executor/Cargo.toml @@ -68,7 +68,7 @@ nightly = ["embassy-executor-macros/nightly"] turbowakers = [] ## Use the executor-integrated `embassy-time` timer queue. -integrated-timers = ["dep:embassy-time-driver", "dep:embassy-time-queue-driver"] +integrated-timers = ["dep:embassy-time-driver"] #! ### Architecture _arch = [] # some arch was picked diff --git a/embassy-executor/src/arch/avr.rs b/embassy-executor/src/arch/avr.rs index 7f9ed4421..70085d04d 100644 --- a/embassy-executor/src/arch/avr.rs +++ b/embassy-executor/src/arch/avr.rs @@ -53,10 +53,6 @@ mod thread { /// /// This function never returns. pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! { - unsafe { - self.inner.initialize(); - } - init(self.inner.spawner()); loop { diff --git a/embassy-executor/src/arch/cortex_m.rs b/embassy-executor/src/arch/cortex_m.rs index 0c2af88a6..5c517e0a2 100644 --- a/embassy-executor/src/arch/cortex_m.rs +++ b/embassy-executor/src/arch/cortex_m.rs @@ -98,9 +98,6 @@ mod thread { /// /// This function never returns. pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! { - unsafe { - self.inner.initialize(); - } init(self.inner.spawner()); loop { @@ -210,9 +207,6 @@ mod interrupt { } let executor = unsafe { (&*self.executor.get()).assume_init_ref() }; - unsafe { - executor.initialize(); - } unsafe { NVIC::unmask(irq) } diff --git a/embassy-executor/src/arch/riscv32.rs b/embassy-executor/src/arch/riscv32.rs index 715e5f3cf..01e63a9fd 100644 --- a/embassy-executor/src/arch/riscv32.rs +++ b/embassy-executor/src/arch/riscv32.rs @@ -54,10 +54,6 @@ mod thread { /// /// This function never returns. pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! { - unsafe { - self.inner.initialize(); - } - init(self.inner.spawner()); loop { diff --git a/embassy-executor/src/arch/spin.rs b/embassy-executor/src/arch/spin.rs index 54c7458b3..340023620 100644 --- a/embassy-executor/src/arch/spin.rs +++ b/embassy-executor/src/arch/spin.rs @@ -48,10 +48,6 @@ mod thread { /// /// This function never returns. pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! { - unsafe { - self.inner.initialize(); - } - init(self.inner.spawner()); loop { diff --git a/embassy-executor/src/arch/std.rs b/embassy-executor/src/arch/std.rs index 948c7711b..b02b15988 100644 --- a/embassy-executor/src/arch/std.rs +++ b/embassy-executor/src/arch/std.rs @@ -55,10 +55,6 @@ mod thread { /// /// This function never returns. pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! { - unsafe { - self.inner.initialize(); - } - init(self.inner.spawner()); loop { diff --git a/embassy-executor/src/arch/wasm.rs b/embassy-executor/src/arch/wasm.rs index 35025f11f..f9d0f935c 100644 --- a/embassy-executor/src/arch/wasm.rs +++ b/embassy-executor/src/arch/wasm.rs @@ -70,10 +70,6 @@ mod thread { /// - a `static mut` (unsafe) /// - a local variable in a function you know never returns (like `fn main() -> !`), upgrading its lifetime with `transmute`. (unsafe) pub fn start(&'static mut self, init: impl FnOnce(Spawner)) { - unsafe { - self.inner.initialize(); - } - unsafe { let executor = &self.inner; let future = Closure::new(move |_| { diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs index 3f93eae6f..80bd49bad 100644 --- a/embassy-executor/src/raw/mod.rs +++ b/embassy-executor/src/raw/mod.rs @@ -17,7 +17,7 @@ mod run_queue; mod state; #[cfg(feature = "integrated-timers")] -mod timer_queue; +pub mod timer_queue; #[cfg(feature = "trace")] mod trace; pub(crate) mod util; @@ -31,9 +31,6 @@ use core::pin::Pin; use core::ptr::NonNull; use core::task::{Context, Poll}; -#[cfg(feature = "integrated-timers")] -use embassy_time_driver::AlarmHandle; - use self::run_queue::{RunQueue, RunQueueItem}; use self::state::State; use self::util::{SyncUnsafeCell, UninitCell}; @@ -47,8 +44,7 @@ pub(crate) struct TaskHeader { pub(crate) executor: SyncUnsafeCell>, poll_fn: SyncUnsafeCell>, - #[cfg(feature = "integrated-timers")] - pub(crate) expires_at: SyncUnsafeCell, + /// Integrated timer queue storage. This field should not be accessed outside of the timer queue. #[cfg(feature = "integrated-timers")] pub(crate) timer_queue_item: timer_queue::TimerQueueItem, } @@ -80,6 +76,12 @@ impl TaskRef { unsafe { self.ptr.as_ref() } } + /// Returns a reference to the executor that the task is currently running on. + #[cfg(feature = "integrated-timers")] + pub unsafe fn executor(self) -> Option<&'static Executor> { + self.header().executor.get().map(|e| Executor::wrap(e)) + } + /// The returned pointer is valid for the entire TaskStorage. pub(crate) fn as_ptr(self) -> *const TaskHeader { self.ptr.as_ptr() @@ -120,8 +122,6 @@ impl TaskStorage { // Note: this is lazily initialized so that a static `TaskStorage` will go in `.bss` poll_fn: SyncUnsafeCell::new(None), - #[cfg(feature = "integrated-timers")] - expires_at: SyncUnsafeCell::new(0), #[cfg(feature = "integrated-timers")] timer_queue_item: timer_queue::TimerQueueItem::new(), }, @@ -160,9 +160,6 @@ impl TaskStorage { Poll::Ready(_) => { this.future.drop_in_place(); this.raw.state.despawn(); - - #[cfg(feature = "integrated-timers")] - this.raw.expires_at.set(u64::MAX); } Poll::Pending => {} } @@ -316,34 +313,16 @@ impl Pender { pub(crate) struct SyncExecutor { run_queue: RunQueue, pender: Pender, - - #[cfg(feature = "integrated-timers")] - pub(crate) timer_queue: timer_queue::TimerQueue, - #[cfg(feature = "integrated-timers")] - alarm: AlarmHandle, } impl SyncExecutor { pub(crate) fn new(pender: Pender) -> Self { - #[cfg(feature = "integrated-timers")] - let alarm = unsafe { unwrap!(embassy_time_driver::allocate_alarm()) }; - Self { run_queue: RunQueue::new(), pender, - - #[cfg(feature = "integrated-timers")] - timer_queue: timer_queue::TimerQueue::new(), - #[cfg(feature = "integrated-timers")] - alarm, } } - pub(crate) unsafe fn initialize(&'static self) { - #[cfg(feature = "integrated-timers")] - embassy_time_driver::set_alarm_callback(self.alarm, Self::alarm_callback, self as *const _ as *mut ()); - } - /// Enqueue a task in the task queue /// /// # Safety @@ -360,12 +339,6 @@ impl SyncExecutor { } } - #[cfg(feature = "integrated-timers")] - fn alarm_callback(ctx: *mut ()) { - let this: &Self = unsafe { &*(ctx as *const Self) }; - this.pender.pend(); - } - pub(super) unsafe fn spawn(&'static self, task: TaskRef) { task.header().executor.set(Some(self)); @@ -379,56 +352,27 @@ impl SyncExecutor { /// /// Same as [`Executor::poll`], plus you must only call this on the thread this executor was created. pub(crate) unsafe fn poll(&'static self) { - #[allow(clippy::never_loop)] - loop { - #[cfg(feature = "integrated-timers")] - self.timer_queue - .dequeue_expired(embassy_time_driver::now(), wake_task_no_pend); + self.run_queue.dequeue_all(|p| { + let task = p.header(); - self.run_queue.dequeue_all(|p| { - let task = p.header(); - - #[cfg(feature = "integrated-timers")] - task.expires_at.set(u64::MAX); - - if !task.state.run_dequeue() { - // If task is not running, ignore it. This can happen in the following scenario: - // - Task gets dequeued, poll starts - // - While task is being polled, it gets woken. It gets placed in the queue. - // - Task poll finishes, returning done=true - // - RUNNING bit is cleared, but the task is already in the queue. - return; - } - - #[cfg(feature = "trace")] - trace::task_exec_begin(self, &p); - - // Run the task - task.poll_fn.get().unwrap_unchecked()(p); - - #[cfg(feature = "trace")] - trace::task_exec_end(self, &p); - - // Enqueue or update into timer_queue - #[cfg(feature = "integrated-timers")] - self.timer_queue.update(p); - }); - - #[cfg(feature = "integrated-timers")] - { - // If this is already in the past, set_alarm might return false - // In that case do another poll loop iteration. - let next_expiration = self.timer_queue.next_expiration(); - if embassy_time_driver::set_alarm(self.alarm, next_expiration) { - break; - } + if !task.state.run_dequeue() { + // If task is not running, ignore it. This can happen in the following scenario: + // - Task gets dequeued, poll starts + // - While task is being polled, it gets woken. It gets placed in the queue. + // - Task poll finishes, returning done=true + // - RUNNING bit is cleared, but the task is already in the queue. + return; } - #[cfg(not(feature = "integrated-timers"))] - { - break; - } - } + #[cfg(feature = "trace")] + trace::task_exec_begin(self, &p); + + // Run the task + task.poll_fn.get().unwrap_unchecked()(p); + + #[cfg(feature = "trace")] + trace::task_exec_end(self, &p); + }); #[cfg(feature = "trace")] trace::executor_idle(self) @@ -494,15 +438,6 @@ impl Executor { } } - /// Initializes the executor. - /// - /// # Safety - /// - /// This function must be called once before any other method is called. - pub unsafe fn initialize(&'static self) { - self.inner.initialize(); - } - /// Spawn a task in this executor. /// /// # Safety @@ -575,21 +510,3 @@ pub fn wake_task_no_pend(task: TaskRef) { } } } - -#[cfg(feature = "integrated-timers")] -struct TimerQueue; - -#[cfg(feature = "integrated-timers")] -impl embassy_time_queue_driver::TimerQueue for TimerQueue { - fn schedule_wake(&'static self, at: u64, waker: &core::task::Waker) { - let task = waker::task_from_waker(waker); - let task = task.header(); - unsafe { - let expires_at = task.expires_at.get(); - task.expires_at.set(expires_at.min(at)); - } - } -} - -#[cfg(feature = "integrated-timers")] -embassy_time_queue_driver::timer_queue_impl!(static TIMER_QUEUE: TimerQueue = TimerQueue); diff --git a/embassy-executor/src/raw/timer_queue.rs b/embassy-executor/src/raw/timer_queue.rs index 94a5f340b..953bf014f 100644 --- a/embassy-executor/src/raw/timer_queue.rs +++ b/embassy-executor/src/raw/timer_queue.rs @@ -1,75 +1,100 @@ +//! Timer queue operations. use core::cmp::min; +use super::util::SyncUnsafeCell; use super::TaskRef; -use crate::raw::util::SyncUnsafeCell; pub(crate) struct TimerQueueItem { next: SyncUnsafeCell>, + expires_at: SyncUnsafeCell, } impl TimerQueueItem { pub const fn new() -> Self { Self { next: SyncUnsafeCell::new(None), + expires_at: SyncUnsafeCell::new(0), } } } -pub(crate) struct TimerQueue { +/// A timer queue, with items integrated into tasks. +pub struct TimerQueue { head: SyncUnsafeCell>, } impl TimerQueue { + /// Creates a new timer queue. pub const fn new() -> Self { Self { head: SyncUnsafeCell::new(None), } } - pub(crate) unsafe fn update(&self, p: TaskRef) { - let task = p.header(); - if task.expires_at.get() != u64::MAX { + /// Schedules a task to run at a specific time. + /// + /// If this function returns `true`, the called should find the next expiration time and set + /// a new alarm for that time. + pub fn schedule_wake(&mut self, at: u64, p: TaskRef) -> bool { + unsafe { + let task = p.header(); + let item = &task.timer_queue_item; if task.state.timer_enqueue() { - task.timer_queue_item.next.set(self.head.get()); - self.head.set(Some(p)); + // If not in the queue, add it and update. + let prev = self.head.replace(Some(p)); + item.next.set(prev); + } else if at <= item.expires_at.get() { + // If expiration is sooner than previously set, update. + } else { + // Task does not need to be updated. + return false; } + + item.expires_at.set(at); + true } } - pub(crate) unsafe fn next_expiration(&self) -> u64 { - let mut res = u64::MAX; - self.retain(|p| { - let task = p.header(); - let expires = task.expires_at.get(); - res = min(res, expires); - expires != u64::MAX - }); - res - } + /// Dequeues expired timers and returns the next alarm time. + /// + /// The provided callback will be called for each expired task. Tasks that never expire + /// will be removed, but the callback will not be called. + pub fn next_expiration(&mut self, now: u64) -> u64 { + let mut next_expiration = u64::MAX; - pub(crate) unsafe fn dequeue_expired(&self, now: u64, on_task: impl Fn(TaskRef)) { self.retain(|p| { let task = p.header(); - if task.expires_at.get() <= now { - on_task(p); + let item = &task.timer_queue_item; + let expires = unsafe { item.expires_at.get() }; + + if expires <= now { + // Timer expired, process task. + super::wake_task(p); false } else { - true + // Timer didn't yet expire, or never expires. + next_expiration = min(next_expiration, expires); + expires != u64::MAX } }); + + next_expiration } - pub(crate) unsafe fn retain(&self, mut f: impl FnMut(TaskRef) -> bool) { - let mut prev = &self.head; - while let Some(p) = prev.get() { - let task = p.header(); - if f(p) { - // Skip to next - prev = &task.timer_queue_item.next; - } else { - // Remove it - prev.set(task.timer_queue_item.next.get()); - task.state.timer_dequeue(); + fn retain(&self, mut f: impl FnMut(TaskRef) -> bool) { + unsafe { + let mut prev = &self.head; + while let Some(p) = prev.get() { + let task = p.header(); + let item = &task.timer_queue_item; + if f(p) { + // Skip to next + prev = &item.next; + } else { + // Remove it + prev.set(item.next.get()); + task.state.timer_dequeue(); + } } } } diff --git a/embassy-executor/src/raw/util.rs b/embassy-executor/src/raw/util.rs index c46085e45..e2633658a 100644 --- a/embassy-executor/src/raw/util.rs +++ b/embassy-executor/src/raw/util.rs @@ -54,4 +54,9 @@ impl SyncUnsafeCell { { *self.value.get() } + + #[cfg(feature = "integrated-timers")] + pub unsafe fn replace(&self, value: T) -> T { + core::mem::replace(&mut *self.value.get(), value) + } } diff --git a/embassy-executor/tests/test.rs b/embassy-executor/tests/test.rs index 8054bf7eb..0ce1f1891 100644 --- a/embassy-executor/tests/test.rs +++ b/embassy-executor/tests/test.rs @@ -40,9 +40,6 @@ fn setup() -> (&'static Executor, Trace) { let trace = Trace::new(); let context = Box::leak(Box::new(trace.clone())) as *mut _ as *mut (); let executor = &*Box::leak(Box::new(Executor::new(context))); - unsafe { - executor.initialize(); - } (executor, trace) } diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml index 9da050a22..48f80bb5e 100644 --- a/embassy-nrf/Cargo.toml +++ b/embassy-nrf/Cargo.toml @@ -119,7 +119,7 @@ _nrf52 = ["_ppi"] _nrf51 = ["_ppi"] _nrf91 = [] -_time-driver = ["dep:embassy-time-driver", "embassy-time-driver?/tick-hz-32_768"] +_time-driver = ["dep:embassy-time-driver", "embassy-time-driver?/tick-hz-32_768", "dep:embassy-time-queue-driver"] # trustzone state. _s = [] @@ -135,6 +135,7 @@ _nrf52832_anomaly_109 = [] [dependencies] embassy-time-driver = { version = "0.1", path = "../embassy-time-driver", optional = true } +embassy-time-queue-driver = { version = "0.1", path = "../embassy-time-queue-driver", optional = true } embassy-time = { version = "0.3.2", path = "../embassy-time", optional = true } embassy-sync = { version = "0.6.1", path = "../embassy-sync" } embassy-hal-internal = {version = "0.2.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-3"] } diff --git a/embassy-nrf/src/time_driver.rs b/embassy-nrf/src/time_driver.rs index 9ba38ec1b..f8b3c4bbc 100644 --- a/embassy-nrf/src/time_driver.rs +++ b/embassy-nrf/src/time_driver.rs @@ -1,11 +1,11 @@ use core::cell::Cell; -use core::sync::atomic::{compiler_fence, AtomicU32, AtomicU8, Ordering}; -use core::{mem, ptr}; +use core::sync::atomic::{compiler_fence, AtomicU32, Ordering}; use critical_section::CriticalSection; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::blocking_mutex::CriticalSectionMutex as Mutex; -use embassy_time_driver::{AlarmHandle, Driver}; +use embassy_time_driver::Driver; +use embassy_time_queue_driver::GlobalTimerQueue; use crate::interrupt::InterruptExt; use crate::{interrupt, pac}; @@ -94,11 +94,6 @@ mod test { struct AlarmState { timestamp: Cell, - - // This is really a Option<(fn(*mut ()), *mut ())> - // but fn pointers aren't allowed in const yet - callback: Cell<*const ()>, - ctx: Cell<*mut ()>, } unsafe impl Send for AlarmState {} @@ -107,26 +102,20 @@ impl AlarmState { const fn new() -> Self { Self { timestamp: Cell::new(u64::MAX), - callback: Cell::new(ptr::null()), - ctx: Cell::new(ptr::null_mut()), } } } -const ALARM_COUNT: usize = 3; - struct RtcDriver { /// Number of 2^23 periods elapsed since boot. period: AtomicU32, - alarm_count: AtomicU8, /// Timestamp at which to fire alarm. u64::MAX if no alarm is scheduled. - alarms: Mutex<[AlarmState; ALARM_COUNT]>, + alarms: Mutex, } embassy_time_driver::time_driver_impl!(static DRIVER: RtcDriver = RtcDriver { period: AtomicU32::new(0), - alarm_count: AtomicU8::new(0), - alarms: Mutex::const_new(CriticalSectionRawMutex::new(), [const {AlarmState::new()}; ALARM_COUNT]), + alarms: Mutex::const_new(CriticalSectionRawMutex::new(), AlarmState::new()), }); impl RtcDriver { @@ -169,13 +158,12 @@ impl RtcDriver { self.next_period(); } - for n in 0..ALARM_COUNT { - if r.events_compare(n).read() == 1 { - r.events_compare(n).write_value(0); - critical_section::with(|cs| { - self.trigger_alarm(n, cs); - }) - } + let n = 0; + if r.events_compare(n).read() == 1 { + r.events_compare(n).write_value(0); + critical_section::with(|cs| { + self.trigger_alarm(cs); + }); } } @@ -186,75 +174,33 @@ impl RtcDriver { self.period.store(period, Ordering::Relaxed); let t = (period as u64) << 23; - for n in 0..ALARM_COUNT { - let alarm = &self.alarms.borrow(cs)[n]; - let at = alarm.timestamp.get(); + let n = 0; + let alarm = &self.alarms.borrow(cs); + let at = alarm.timestamp.get(); - if at < t + 0xc00000 { - // just enable it. `set_alarm` has already set the correct CC val. - r.intenset().write(|w| w.0 = compare_n(n)); - } + if at < t + 0xc00000 { + // just enable it. `set_alarm` has already set the correct CC val. + r.intenset().write(|w| w.0 = compare_n(n)); } }) } - fn get_alarm<'a>(&'a self, cs: CriticalSection<'a>, alarm: AlarmHandle) -> &'a AlarmState { - // safety: we're allowed to assume the AlarmState is created by us, and - // we never create one that's out of bounds. - unsafe { self.alarms.borrow(cs).get_unchecked(alarm.id() as usize) } - } - - fn trigger_alarm(&self, n: usize, cs: CriticalSection) { + fn trigger_alarm(&self, cs: CriticalSection) { + let n = 0; let r = rtc(); r.intenclr().write(|w| w.0 = compare_n(n)); - let alarm = &self.alarms.borrow(cs)[n]; + let alarm = &self.alarms.borrow(cs); alarm.timestamp.set(u64::MAX); // Call after clearing alarm, so the callback can set another alarm. - - // safety: - // - we can ignore the possiblity of `f` being unset (null) because of the safety contract of `allocate_alarm`. - // - other than that we only store valid function pointers into alarm.callback - let f: fn(*mut ()) = unsafe { mem::transmute(alarm.callback.get()) }; - f(alarm.ctx.get()); - } -} - -impl Driver for RtcDriver { - fn now(&self) -> u64 { - // `period` MUST be read before `counter`, see comment at the top for details. - let period = self.period.load(Ordering::Relaxed); - compiler_fence(Ordering::Acquire); - let counter = rtc().counter().read().0; - calc_now(period, counter) + TIMER_QUEUE_DRIVER.dispatch(); } - unsafe fn allocate_alarm(&self) -> Option { - critical_section::with(|_| { - let id = self.alarm_count.load(Ordering::Relaxed); - if id < ALARM_COUNT as u8 { - self.alarm_count.store(id + 1, Ordering::Relaxed); - Some(AlarmHandle::new(id)) - } else { - None - } - }) - } - - fn set_alarm_callback(&self, alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()) { + fn set_alarm(&self, timestamp: u64) -> bool { critical_section::with(|cs| { - let alarm = self.get_alarm(cs, alarm); - - alarm.callback.set(callback as *const ()); - alarm.ctx.set(ctx); - }) - } - - fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) -> bool { - critical_section::with(|cs| { - let n = alarm.id() as _; - let alarm = self.get_alarm(cs, alarm); + let n = 0; + let alarm = &self.alarms.borrow(cs); alarm.timestamp.set(timestamp); let r = rtc(); @@ -304,6 +250,16 @@ impl Driver for RtcDriver { } } +impl Driver for RtcDriver { + fn now(&self) -> u64 { + // `period` MUST be read before `counter`, see comment at the top for details. + let period = self.period.load(Ordering::Relaxed); + compiler_fence(Ordering::Acquire); + let counter = rtc().counter().read().0; + calc_now(period, counter) + } +} + #[cfg(feature = "_nrf54l")] #[cfg(feature = "rt")] #[interrupt] @@ -321,3 +277,8 @@ fn RTC1() { pub(crate) fn init(irq_prio: crate::interrupt::Priority) { DRIVER.init(irq_prio) } + +embassy_time_queue_driver::timer_queue_impl!( + static TIMER_QUEUE_DRIVER: GlobalTimerQueue + = GlobalTimerQueue::new(|next_expiration| DRIVER.set_alarm(next_expiration)) +); diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index 3809f1894..94de82fa9 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml @@ -40,7 +40,7 @@ critical-section-impl = ["critical-section/restore-state-u8"] unstable-pac = [] ## Enable the timer for use with `embassy-time` with a 1MHz tick rate. -time-driver = ["dep:embassy-time-driver", "embassy-time-driver?/tick-hz-1_000_000"] +time-driver = ["dep:embassy-time-driver", "embassy-time-driver?/tick-hz-1_000_000", "dep:embassy-time-queue-driver"] ## Enable ROM function cache. This will store the address of a ROM function when first used, improving performance of subsequent calls. rom-func-cache = [] @@ -110,6 +110,7 @@ binary-info = ["rt", "dep:rp-binary-info", "rp-binary-info?/binary-info"] [dependencies] embassy-sync = { version = "0.6.1", path = "../embassy-sync" } embassy-time-driver = { version = "0.1", path = "../embassy-time-driver", optional = true } +embassy-time-queue-driver = { version = "0.1", path = "../embassy-time-queue-driver", optional = true } embassy-time = { version = "0.3.2", path = "../embassy-time" } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } embassy-hal-internal = {version = "0.2.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-2"] } diff --git a/embassy-rp/src/time_driver.rs b/embassy-rp/src/time_driver.rs index 40fc71bb1..17ae5fff3 100644 --- a/embassy-rp/src/time_driver.rs +++ b/embassy-rp/src/time_driver.rs @@ -1,11 +1,10 @@ //! Timer driver. use core::cell::Cell; -use atomic_polyfill::{AtomicU8, Ordering}; -use critical_section::CriticalSection; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::blocking_mutex::Mutex; -use embassy_time_driver::{AlarmHandle, Driver}; +use embassy_time_driver::Driver; +use embassy_time_queue_driver::GlobalTimerQueue; #[cfg(feature = "rp2040")] use pac::TIMER; #[cfg(feature = "_rp235x")] @@ -16,23 +15,17 @@ use crate::{interrupt, pac}; struct AlarmState { timestamp: Cell, - callback: Cell>, } unsafe impl Send for AlarmState {} -const ALARM_COUNT: usize = 4; - struct TimerDriver { - alarms: Mutex, - next_alarm: AtomicU8, + alarms: Mutex, } embassy_time_driver::time_driver_impl!(static DRIVER: TimerDriver = TimerDriver{ - alarms: Mutex::const_new(CriticalSectionRawMutex::new(), [const{AlarmState { + alarms: Mutex::const_new(CriticalSectionRawMutex::new(), AlarmState { timestamp: Cell::new(0), - callback: Cell::new(None), - }}; ALARM_COUNT]), - next_alarm: AtomicU8::new(0), + }), }); impl Driver for TimerDriver { @@ -46,34 +39,13 @@ impl Driver for TimerDriver { } } } +} - unsafe fn allocate_alarm(&self) -> Option { - let id = self.next_alarm.fetch_update(Ordering::AcqRel, Ordering::Acquire, |x| { - if x < ALARM_COUNT as u8 { - Some(x + 1) - } else { - None - } - }); - - match id { - Ok(id) => Some(AlarmHandle::new(id)), - Err(_) => None, - } - } - - fn set_alarm_callback(&self, alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()) { - let n = alarm.id() as usize; +impl TimerDriver { + fn set_alarm(&self, timestamp: u64) -> bool { + let n = 0; critical_section::with(|cs| { - let alarm = &self.alarms.borrow(cs)[n]; - alarm.callback.set(Some((callback, ctx))); - }) - } - - fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) -> bool { - let n = alarm.id() as usize; - critical_section::with(|cs| { - let alarm = &self.alarms.borrow(cs)[n]; + let alarm = &self.alarms.borrow(cs); alarm.timestamp.set(timestamp); // Arm it. @@ -96,15 +68,14 @@ impl Driver for TimerDriver { } }) } -} -impl TimerDriver { - fn check_alarm(&self, n: usize) { + fn check_alarm(&self) { + let n = 0; critical_section::with(|cs| { - let alarm = &self.alarms.borrow(cs)[n]; + let alarm = &self.alarms.borrow(cs); let timestamp = alarm.timestamp.get(); if timestamp <= self.now() { - self.trigger_alarm(n, cs) + self.trigger_alarm() } else { // Not elapsed, arm it again. // This can happen if it was set more than 2^32 us in the future. @@ -116,17 +87,8 @@ impl TimerDriver { TIMER.intr().write(|w| w.set_alarm(n, true)); } - fn trigger_alarm(&self, n: usize, cs: CriticalSection) { - // disarm - TIMER.armed().write(|w| w.set_armed(1 << n)); - - let alarm = &self.alarms.borrow(cs)[n]; - alarm.timestamp.set(u64::MAX); - - // Call after clearing alarm, so the callback can set another alarm. - if let Some((f, ctx)) = alarm.callback.get() { - f(ctx); - } + fn trigger_alarm(&self) { + TIMER_QUEUE_DRIVER.dispatch(); } } @@ -134,79 +96,37 @@ impl TimerDriver { pub unsafe fn init() { // init alarms critical_section::with(|cs| { - let alarms = DRIVER.alarms.borrow(cs); - for a in alarms { - a.timestamp.set(u64::MAX); - } + let alarm = DRIVER.alarms.borrow(cs); + alarm.timestamp.set(u64::MAX); }); - // enable all irqs + // enable irq TIMER.inte().write(|w| { w.set_alarm(0, true); - w.set_alarm(1, true); - w.set_alarm(2, true); - w.set_alarm(3, true); }); #[cfg(feature = "rp2040")] { interrupt::TIMER_IRQ_0.enable(); - interrupt::TIMER_IRQ_1.enable(); - interrupt::TIMER_IRQ_2.enable(); - interrupt::TIMER_IRQ_3.enable(); } #[cfg(feature = "_rp235x")] { interrupt::TIMER0_IRQ_0.enable(); - interrupt::TIMER0_IRQ_1.enable(); - interrupt::TIMER0_IRQ_2.enable(); - interrupt::TIMER0_IRQ_3.enable(); } } #[cfg(all(feature = "rt", feature = "rp2040"))] #[interrupt] fn TIMER_IRQ_0() { - DRIVER.check_alarm(0) -} - -#[cfg(all(feature = "rt", feature = "rp2040"))] -#[interrupt] -fn TIMER_IRQ_1() { - DRIVER.check_alarm(1) -} - -#[cfg(all(feature = "rt", feature = "rp2040"))] -#[interrupt] -fn TIMER_IRQ_2() { - DRIVER.check_alarm(2) -} - -#[cfg(all(feature = "rt", feature = "rp2040"))] -#[interrupt] -fn TIMER_IRQ_3() { - DRIVER.check_alarm(3) + DRIVER.check_alarm() } #[cfg(all(feature = "rt", feature = "_rp235x"))] #[interrupt] fn TIMER0_IRQ_0() { - DRIVER.check_alarm(0) + DRIVER.check_alarm() } -#[cfg(all(feature = "rt", feature = "_rp235x"))] -#[interrupt] -fn TIMER0_IRQ_1() { - DRIVER.check_alarm(1) -} - -#[cfg(all(feature = "rt", feature = "_rp235x"))] -#[interrupt] -fn TIMER0_IRQ_2() { - DRIVER.check_alarm(2) -} - -#[cfg(all(feature = "rt", feature = "_rp235x"))] -#[interrupt] -fn TIMER0_IRQ_3() { - DRIVER.check_alarm(3) -} +embassy_time_queue_driver::timer_queue_impl!( + static TIMER_QUEUE_DRIVER: GlobalTimerQueue + = GlobalTimerQueue::new(|next_expiration| DRIVER.set_alarm(next_expiration)) +); diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 8b4e7c929..82030f99f 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -45,6 +45,7 @@ rustdoc-args = ["--cfg", "docsrs"] embassy-sync = { version = "0.6.1", path = "../embassy-sync" } embassy-time = { version = "0.3.2", path = "../embassy-time", optional = true } embassy-time-driver = { version = "0.1", path = "../embassy-time-driver", optional = true } +embassy-time-queue-driver = { version = "0.1", path = "../embassy-time-queue-driver", optional = true } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } embassy-hal-internal = {version = "0.2.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-4"] } embassy-embedded-hal = {version = "0.2.0", path = "../embassy-embedded-hal", default-features = false } @@ -125,6 +126,7 @@ defmt = [ exti = [] low-power = [ "dep:embassy-executor", "embassy-executor?/arch-cortex-m", "time" ] low-power-debug-with-sleep = [] +integrated-timers = ["dep:embassy-executor", "_time-driver"] ## Automatically generate `memory.x` file using [`stm32-metapac`](https://docs.rs/stm32-metapac/) memory-x = ["stm32-metapac/memory-x"] @@ -149,7 +151,7 @@ time = ["dep:embassy-time", "embassy-embedded-hal/time"] # Features starting with `_` are for internal use only. They're not intended # to be enabled by other crates, and are not covered by semver guarantees. -_time-driver = ["dep:embassy-time-driver", "time"] +_time-driver = ["dep:embassy-time-driver", "time", "dep:embassy-time-queue-driver"] ## Use any time driver time-driver-any = ["_time-driver"] diff --git a/embassy-stm32/src/low_power.rs b/embassy-stm32/src/low_power.rs index 0b87bd95a..7734365f1 100644 --- a/embassy-stm32/src/low_power.rs +++ b/embassy-stm32/src/low_power.rs @@ -256,9 +256,6 @@ impl Executor { /// This function never returns. pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! { let executor = unsafe { EXECUTOR.as_mut().unwrap() }; - unsafe { - executor.inner.initialize(); - } init(executor.inner.spawner()); loop { diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs index 00aa3cfa4..290f857ad 100644 --- a/embassy-stm32/src/time_driver.rs +++ b/embassy-stm32/src/time_driver.rs @@ -1,13 +1,13 @@ #![allow(non_snake_case)] use core::cell::Cell; -use core::sync::atomic::{compiler_fence, AtomicU32, AtomicU8, Ordering}; -use core::{mem, ptr}; +use core::sync::atomic::{compiler_fence, AtomicU32, Ordering}; use critical_section::CriticalSection; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::blocking_mutex::Mutex; -use embassy_time_driver::{AlarmHandle, Driver, TICK_HZ}; +use embassy_time_driver::{Driver, TICK_HZ}; +use embassy_time_queue_driver::GlobalTimerQueue; use stm32_metapac::timer::{regs, TimGp16}; use crate::interrupt::typelevel::Interrupt; @@ -24,18 +24,6 @@ use crate::{interrupt, peripherals}; // additional CC capabilities to provide timer alarms to embassy-time. embassy-time requires AT LEAST // one alarm to be allocatable, which means timers that only have CC1, such as TIM16/TIM17, are not // candidates for use as an embassy-time driver provider. (a.k.a 1CH and 1CH_CMP are not, others are good.) -// -// The values of ALARM_COUNT below are not the TOTAL CC registers available, but rather the number -// available after reserving CC1 for regular time keeping. For example, TIM2 has four CC registers: -// CC1, CC2, CC3, and CC4, so it can provide ALARM_COUNT = 3. - -cfg_if::cfg_if! { - if #[cfg(any(time_driver_tim9, time_driver_tim12, time_driver_tim15, time_driver_tim21, time_driver_tim22))] { - const ALARM_COUNT: usize = 1; - } else { - const ALARM_COUNT: usize = 3; - } -} #[cfg(time_driver_tim1)] type T = peripherals::TIM1; @@ -208,11 +196,6 @@ fn calc_now(period: u32, counter: u16) -> u64 { struct AlarmState { timestamp: Cell, - - // This is really a Option<(fn(*mut ()), *mut ())> - // but fn pointers aren't allowed in const yet - callback: Cell<*const ()>, - ctx: Cell<*mut ()>, } unsafe impl Send for AlarmState {} @@ -221,8 +204,6 @@ impl AlarmState { const fn new() -> Self { Self { timestamp: Cell::new(u64::MAX), - callback: Cell::new(ptr::null()), - ctx: Cell::new(ptr::null_mut()), } } } @@ -230,17 +211,14 @@ impl AlarmState { pub(crate) struct RtcDriver { /// Number of 2^15 periods elapsed since boot. period: AtomicU32, - alarm_count: AtomicU8, - /// Timestamp at which to fire alarm. u64::MAX if no alarm is scheduled. - alarms: Mutex, + alarm: Mutex, #[cfg(feature = "low-power")] rtc: Mutex>>, } embassy_time_driver::time_driver_impl!(static DRIVER: RtcDriver = RtcDriver { period: AtomicU32::new(0), - alarm_count: AtomicU8::new(0), - alarms: Mutex::const_new(CriticalSectionRawMutex::new(), [const{AlarmState::new()}; ALARM_COUNT]), + alarm: Mutex::const_new(CriticalSectionRawMutex::new(), AlarmState::new()), #[cfg(feature = "low-power")] rtc: Mutex::const_new(CriticalSectionRawMutex::new(), Cell::new(None)), }); @@ -289,7 +267,7 @@ impl RtcDriver { let r = regs_gp16(); // XXX: reduce the size of this critical section ? - critical_section::with(|cs| { + critical_section::with(|_cs| { let sr = r.sr().read(); let dier = r.dier().read(); @@ -308,10 +286,9 @@ impl RtcDriver { self.next_period(); } - for n in 0..ALARM_COUNT { - if sr.ccif(n + 1) && dier.ccie(n + 1) { - self.trigger_alarm(n, cs); - } + let n = 0; + if sr.ccif(n + 1) && dier.ccie(n + 1) { + self.trigger_alarm(); } }) } @@ -326,36 +303,20 @@ impl RtcDriver { critical_section::with(move |cs| { r.dier().modify(move |w| { - for n in 0..ALARM_COUNT { - let alarm = &self.alarms.borrow(cs)[n]; - let at = alarm.timestamp.get(); + let n = 0; + let alarm = self.alarm.borrow(cs); + let at = alarm.timestamp.get(); - if at < t + 0xc000 { - // just enable it. `set_alarm` has already set the correct CCR val. - w.set_ccie(n + 1, true); - } + if at < t + 0xc000 { + // just enable it. `set_alarm` has already set the correct CCR val. + w.set_ccie(n + 1, true); } }) }) } - fn get_alarm<'a>(&'a self, cs: CriticalSection<'a>, alarm: AlarmHandle) -> &'a AlarmState { - // safety: we're allowed to assume the AlarmState is created by us, and - // we never create one that's out of bounds. - unsafe { self.alarms.borrow(cs).get_unchecked(alarm.id() as usize) } - } - - fn trigger_alarm(&self, n: usize, cs: CriticalSection) { - let alarm = &self.alarms.borrow(cs)[n]; - alarm.timestamp.set(u64::MAX); - - // Call after clearing alarm, so the callback can set another alarm. - - // safety: - // - we can ignore the possibility of `f` being unset (null) because of the safety contract of `allocate_alarm`. - // - other than that we only store valid function pointers into alarm.callback - let f: fn(*mut ()) = unsafe { mem::transmute(alarm.callback.get()) }; - f(alarm.ctx.get()); + fn trigger_alarm(&self) { + TIMER_QUEUE_DRIVER.dispatch(); } /* @@ -367,14 +328,7 @@ impl RtcDriver { fn time_until_next_alarm(&self, cs: CriticalSection) -> embassy_time::Duration { let now = self.now() + 32; - embassy_time::Duration::from_ticks( - self.alarms - .borrow(cs) - .iter() - .map(|alarm: &AlarmState| alarm.timestamp.get().saturating_sub(now)) - .min() - .unwrap_or(u64::MAX), - ) + embassy_time::Duration::from_ticks(self.alarm.borrow(cs).timestamp.get().saturating_sub(now)) } #[cfg(feature = "low-power")] @@ -409,15 +363,12 @@ impl RtcDriver { self.period.store(period, Ordering::SeqCst); regs_gp16().cnt().write(|w| w.set_cnt(cnt as u16)); - // Now, recompute all alarms - for i in 0..self.alarm_count.load(Ordering::Relaxed) as usize { - let alarm_handle = unsafe { AlarmHandle::new(i as u8) }; - let alarm = self.get_alarm(cs, alarm_handle); + // Now, recompute alarm + let alarm = self.alarm.borrow(cs); - if !self.set_alarm(alarm_handle, alarm.timestamp.get()) { - // If the alarm timestamp has passed, we need to trigger it - self.trigger_alarm(i, cs); - } + if !self.set_alarm(alarm.timestamp.get()) { + // If the alarm timestamp has passed, we need to trigger it + self.trigger_alarm(); } } @@ -489,46 +440,13 @@ impl RtcDriver { regs_gp16().cr1().modify(|w| w.set_cen(true)); }) } -} -impl Driver for RtcDriver { - fn now(&self) -> u64 { - let r = regs_gp16(); - - let period = self.period.load(Ordering::Relaxed); - compiler_fence(Ordering::Acquire); - let counter = r.cnt().read().cnt(); - calc_now(period, counter) - } - - unsafe fn allocate_alarm(&self) -> Option { - critical_section::with(|_| { - let id = self.alarm_count.load(Ordering::Relaxed); - if id < ALARM_COUNT as u8 { - self.alarm_count.store(id + 1, Ordering::Relaxed); - Some(AlarmHandle::new(id)) - } else { - None - } - }) - } - - fn set_alarm_callback(&self, alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()) { - critical_section::with(|cs| { - let alarm = self.get_alarm(cs, alarm); - - alarm.callback.set(callback as *const ()); - alarm.ctx.set(ctx); - }) - } - - fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) -> bool { + fn set_alarm(&self, timestamp: u64) -> bool { critical_section::with(|cs| { let r = regs_gp16(); - let n = alarm.id() as usize; - let alarm = self.get_alarm(cs, alarm); - alarm.timestamp.set(timestamp); + let n = 0; + self.alarm.borrow(cs).timestamp.set(timestamp); let t = self.now(); if timestamp <= t { @@ -536,7 +454,7 @@ impl Driver for RtcDriver { // Disarm the alarm and return `false` to indicate that. r.dier().modify(|w| w.set_ccie(n + 1, false)); - alarm.timestamp.set(u64::MAX); + self.alarm.borrow(cs).timestamp.set(u64::MAX); return false; } @@ -558,7 +476,7 @@ impl Driver for RtcDriver { // It is the caller's responsibility to handle this ambiguity. r.dier().modify(|w| w.set_ccie(n + 1, false)); - alarm.timestamp.set(u64::MAX); + self.alarm.borrow(cs).timestamp.set(u64::MAX); return false; } @@ -569,6 +487,17 @@ impl Driver for RtcDriver { } } +impl Driver for RtcDriver { + fn now(&self) -> u64 { + let r = regs_gp16(); + + let period = self.period.load(Ordering::Relaxed); + compiler_fence(Ordering::Acquire); + let counter = r.cnt().read().cnt(); + calc_now(period, counter) + } +} + #[cfg(feature = "low-power")] pub(crate) fn get_driver() -> &'static RtcDriver { &DRIVER @@ -577,3 +506,8 @@ pub(crate) fn get_driver() -> &'static RtcDriver { pub(crate) fn init(cs: CriticalSection) { DRIVER.init(cs) } + +embassy_time_queue_driver::timer_queue_impl!( + static TIMER_QUEUE_DRIVER: GlobalTimerQueue + = GlobalTimerQueue::new(|next_expiration| DRIVER.set_alarm(next_expiration)) +); diff --git a/embassy-time-driver/src/lib.rs b/embassy-time-driver/src/lib.rs index 12f40b9b9..ffb363cd7 100644 --- a/embassy-time-driver/src/lib.rs +++ b/embassy-time-driver/src/lib.rs @@ -21,8 +21,8 @@ //! //! Instead of the usual "trait + generic params" approach, calls from embassy to the driver are done via `extern` functions. //! -//! `embassy` internally defines the driver functions as `extern "Rust" { fn _embassy_time_now() -> u64; }` and calls them. -//! The driver crate defines the functions as `#[no_mangle] fn _embassy_time_now() -> u64`. The linker will resolve the +//! `embassy` internally defines the driver function as `extern "Rust" { fn _embassy_time_now() -> u64; }` and calls it. +//! The driver crate defines the function as `#[no_mangle] fn _embassy_time_now() -> u64`. The linker will resolve the //! calls from the `embassy` crate to call into the driver crate. //! //! If there is none or multiple drivers in the crate tree, linking will fail. @@ -38,7 +38,7 @@ //! # Example //! //! ``` -//! use embassy_time_driver::{Driver, AlarmHandle}; +//! use embassy_time_driver::Driver; //! //! struct MyDriver{} // not public! //! @@ -46,15 +46,6 @@ //! fn now(&self) -> u64 { //! todo!() //! } -//! unsafe fn allocate_alarm(&self) -> Option { -//! todo!() -//! } -//! fn set_alarm_callback(&self, alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()) { -//! todo!() -//! } -//! fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) -> bool { -//! todo!() -//! } //! } //! //! embassy_time_driver::time_driver_impl!(static DRIVER: MyDriver = MyDriver{}); @@ -70,28 +61,6 @@ mod tick; /// This value is specified by the [`tick-*` Cargo features](crate#tick-rate) pub const TICK_HZ: u64 = tick::TICK_HZ; -/// Alarm handle, assigned by the driver. -#[derive(Clone, Copy)] -pub struct AlarmHandle { - id: u8, -} - -impl AlarmHandle { - /// Create an AlarmHandle - /// - /// Safety: May only be called by the current global Driver impl. - /// The impl is allowed to rely on the fact that all `AlarmHandle` instances - /// are created by itself in unsafe code (e.g. indexing operations) - pub unsafe fn new(id: u8) -> Self { - Self { id } - } - - /// Get the ID of the AlarmHandle. - pub fn id(&self) -> u8 { - self.id - } -} - /// Time driver pub trait Driver: Send + Sync + 'static { /// Return the current timestamp in ticks. @@ -105,76 +74,10 @@ pub trait Driver: Send + Sync + 'static { /// you MUST extend them to 64-bit, for example by counting overflows in software, /// or chaining multiple timers together. fn now(&self) -> u64; - - /// Try allocating an alarm handle. Returns None if no alarms left. - /// Initially the alarm has no callback set, and a null `ctx` pointer. - /// - /// The allocated alarm is a reusable resource and can be used multiple times. - /// Once the alarm has fired, it remains allocated and can be set again without needing - /// to be reallocated. - /// - /// # Safety - /// It is UB to make the alarm fire before setting a callback. - unsafe fn allocate_alarm(&self) -> Option; - - /// Set the callback function to be called when the alarm triggers. - /// The callback may be called from any context (interrupt or thread mode). - /// - /// The callback is maintained after the alarm has fired. Callers do not need - /// to set a callback again before setting another alarm, unless they want to - /// change the callback function or context. - fn set_alarm_callback(&self, alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()); - - /// Set an alarm at the given timestamp. - /// - /// ## Behavior - /// - /// If `timestamp` is in the future, `set_alarm` schedules calling the callback function - /// at that time, and returns `true`. - /// - /// If `timestamp` is in the past, `set_alarm` has two allowed behaviors. Implementations can pick whether to: - /// - /// - Schedule calling the callback function "immediately", as if the requested timestamp was "now+epsilon" and return `true`, or - /// - Not schedule the callback, and return `false`. - /// - /// Callers must ensure to behave correctly with either behavior. - /// - /// When callback is called, it is guaranteed that `now()` will return a value greater than or equal to `timestamp`. - /// - /// ## Reentrancy - /// - /// Calling the callback from `set_alarm` synchronously is not allowed. If the implementation chooses the first option above, - /// it must still call the callback from another context (i.e. an interrupt handler or background thread), it's not allowed - /// to call it synchronously in the context `set_alarm` is running. - /// - /// The reason for the above is callers are explicitly permitted to do both of: - /// - Lock a mutex in the alarm callback. - /// - Call `set_alarm` while having that mutex locked. - /// - /// If `set_alarm` called the callback synchronously, it'd cause a deadlock or panic because it'd cause the - /// mutex to be locked twice reentrantly in the same context. - /// - /// ## Overwriting alarms - /// - /// Only one alarm can be active at a time for each `AlarmHandle`. This overwrites any previously-set alarm if any. - /// - /// ## Unsetting the alarm - /// - /// There is no `unset_alarm` API. Instead, callers can call `set_alarm` with `timestamp` set to `u64::MAX`. - /// - /// This allows for more efficient implementations, since they don't need to distinguish between the "alarm set" and - /// "alarm not set" cases, thanks to the fact "Alarm set for u64::MAX" is effectively equivalent for "alarm not set". - /// - /// This means implementations need to be careful to avoid timestamp overflows. The recommendation is to make `timestamp` - /// be in the same units as hardware ticks to avoid any conversions, which makes avoiding overflow easier. - fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) -> bool; } extern "Rust" { fn _embassy_time_now() -> u64; - fn _embassy_time_allocate_alarm() -> Option; - fn _embassy_time_set_alarm_callback(alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()); - fn _embassy_time_set_alarm(alarm: AlarmHandle, timestamp: u64) -> bool; } /// See [`Driver::now`] @@ -182,23 +85,6 @@ pub fn now() -> u64 { unsafe { _embassy_time_now() } } -/// See [`Driver::allocate_alarm`] -/// -/// Safety: it is UB to make the alarm fire before setting a callback. -pub unsafe fn allocate_alarm() -> Option { - _embassy_time_allocate_alarm() -} - -/// See [`Driver::set_alarm_callback`] -pub fn set_alarm_callback(alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()) { - unsafe { _embassy_time_set_alarm_callback(alarm, callback, ctx) } -} - -/// See [`Driver::set_alarm`] -pub fn set_alarm(alarm: AlarmHandle, timestamp: u64) -> bool { - unsafe { _embassy_time_set_alarm(alarm, timestamp) } -} - /// Set the time Driver implementation. /// /// See the module documentation for an example. @@ -211,20 +97,5 @@ macro_rules! time_driver_impl { fn _embassy_time_now() -> u64 { <$t as $crate::Driver>::now(&$name) } - - #[no_mangle] - unsafe fn _embassy_time_allocate_alarm() -> Option<$crate::AlarmHandle> { - <$t as $crate::Driver>::allocate_alarm(&$name) - } - - #[no_mangle] - fn _embassy_time_set_alarm_callback(alarm: $crate::AlarmHandle, callback: fn(*mut ()), ctx: *mut ()) { - <$t as $crate::Driver>::set_alarm_callback(&$name, alarm, callback, ctx) - } - - #[no_mangle] - fn _embassy_time_set_alarm(alarm: $crate::AlarmHandle, timestamp: u64) -> bool { - <$t as $crate::Driver>::set_alarm(&$name, alarm, timestamp) - } }; } diff --git a/embassy-time-queue-driver/Cargo.toml b/embassy-time-queue-driver/Cargo.toml index 9ce9d79bb..599041a3f 100644 --- a/embassy-time-queue-driver/Cargo.toml +++ b/embassy-time-queue-driver/Cargo.toml @@ -20,6 +20,39 @@ categories = [ # This is especially common when mixing crates from crates.io and git. links = "embassy-time-queue" +[dependencies] +critical-section = "1.2.0" +heapless = "0.8" +embassy-executor = { version = "0.6.3", path = "../embassy-executor", optional = true } +embassy-time-driver = { version = "0.1.0", path = "../embassy-time-driver" } + +[features] +#! ### Generic Queue + +## Use the executor-integrated `embassy-time` timer queue. The timer items are stored inside +## the task headers, so you do not need to set a capacity for the queue. +## To use this you must have a time driver provided. +## +## If this feature is not enabled, a generic queue is available with a configurable capacity. +integrated-timers = ["embassy-executor/integrated-timers"] + +#! The following features set how many timers are used for the generic queue. At most one +#! `generic-queue-*` feature can be enabled. If none is enabled, a default of 64 timers is used. +#! +#! When using embassy-time from libraries, you should *not* enable any `generic-queue-*` feature, to allow the +#! end user to pick. + +## Generic Queue with 8 timers +generic-queue-8 = [] +## Generic Queue with 16 timers +generic-queue-16 = [] +## Generic Queue with 32 timers +generic-queue-32 = [] +## Generic Queue with 64 timers +generic-queue-64 = [] +## Generic Queue with 128 timers +generic-queue-128 = [] + [package.metadata.embassy_docs] src_base = "https://github.com/embassy-rs/embassy/blob/embassy-time-queue-driver-v$VERSION/embassy-time-queue-driver/src/" src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-time-queue-driver/src/" diff --git a/embassy-time-queue-driver/src/lib.rs b/embassy-time-queue-driver/src/lib.rs index 50736e8c7..c5e989854 100644 --- a/embassy-time-queue-driver/src/lib.rs +++ b/embassy-time-queue-driver/src/lib.rs @@ -6,7 +6,29 @@ //! //! - Define a struct `MyTimerQueue` //! - Implement [`TimerQueue`] for it -//! - Register it as the global timer queue with [`timer_queue_impl`](crate::timer_queue_impl). +//! - Register it as the global timer queue with [`timer_queue_impl`]. +//! - Ensure that you process the timer queue when `schedule_wake` is due. This usually involves +//! waking expired tasks, finding the next expiration time and setting an alarm. +//! +//! If a single global timer queue is sufficient for you, you can use the +//! [`GlobalTimerQueue`] type, which is a wrapper around a global timer queue +//! protected by a critical section. +//! +//! ``` +//! use embassy_time_queue_driver::GlobalTimerQueue; +//! embassy_time_queue_driver::timer_queue_impl!( +//! static TIMER_QUEUE_DRIVER: GlobalTimerQueue +//! = GlobalTimerQueue::new(|next_expiration| todo!("Set an alarm")) +//! ); +//! ``` +//! +//! You can also use the `queue_generic` or the `embassy_executor::raw::timer_queue` modules to +//! implement your own timer queue. These modules contain queue implementations which you can wrap +//! and tailor to your needs. +//! +//! If you are providing an embassy-executor implementation besides a timer queue, you can choose to +//! expose the `integrated-timers` feature in your implementation. This feature stores timer items +//! in the tasks themselves, so you don't need a fixed-size queue or dynamic memory allocation. //! //! ## Example //! @@ -14,7 +36,7 @@ //! use core::task::Waker; //! //! use embassy_time::Instant; -//! use embassy_time::queue::{TimerQueue}; +//! use embassy_time::queue::TimerQueue; //! //! struct MyTimerQueue{}; // not public! //! @@ -26,11 +48,18 @@ //! //! embassy_time_queue_driver::timer_queue_impl!(static QUEUE: MyTimerQueue = MyTimerQueue{}); //! ``` + +pub mod queue_generic; + +use core::cell::RefCell; use core::task::Waker; +use critical_section::Mutex; + /// Timer queue pub trait TimerQueue { /// Schedules a waker in the queue to be awoken at moment `at`. + /// /// If this moment is in the past, the waker might be awoken immediately. fn schedule_wake(&'static self, at: u64, waker: &Waker); } @@ -58,3 +87,106 @@ macro_rules! timer_queue_impl { } }; } + +#[cfg(feature = "integrated-timers")] +type InnerQueue = embassy_executor::raw::timer_queue::TimerQueue; + +#[cfg(not(feature = "integrated-timers"))] +type InnerQueue = queue_generic::Queue; + +/// A timer queue implementation that can be used as a global timer queue. +/// +/// This implementation is not thread-safe, and should be protected by a mutex of some sort. +pub struct GenericTimerQueue bool> { + queue: InnerQueue, + set_alarm: F, +} + +impl bool> GenericTimerQueue { + /// Creates a new timer queue. + /// + /// `set_alarm` is a function that should set the next alarm time. The function should + /// return `true` if the alarm was set, and `false` if the alarm was in the past. + pub const fn new(set_alarm: F) -> Self { + Self { + queue: InnerQueue::new(), + set_alarm, + } + } + + /// Schedules a task to run at a specific time, and returns whether any changes were made. + pub fn schedule_wake(&mut self, at: u64, waker: &core::task::Waker) { + #[cfg(feature = "integrated-timers")] + let waker = embassy_executor::raw::task_from_waker(waker); + + if self.queue.schedule_wake(at, waker) { + self.dispatch() + } + } + + /// Dequeues expired timers and returns the next alarm time. + pub fn next_expiration(&mut self, now: u64) -> u64 { + self.queue.next_expiration(now) + } + + /// Handle the alarm. + /// + /// Call this function when the next alarm is due. + pub fn dispatch(&mut self) { + let mut next_expiration = self.next_expiration(embassy_time_driver::now()); + + while !(self.set_alarm)(next_expiration) { + // next_expiration is in the past, dequeue and find a new expiration + next_expiration = self.next_expiration(next_expiration); + } + } +} + +/// A [`GenericTimerQueue`] protected by a critical section. Directly useable as a [`TimerQueue`]. +pub struct GlobalTimerQueue { + inner: Mutex bool>>>, +} + +impl GlobalTimerQueue { + /// Creates a new timer queue. + /// + /// `set_alarm` is a function that should set the next alarm time. The function should + /// return `true` if the alarm was set, and `false` if the alarm was in the past. + pub const fn new(set_alarm: fn(u64) -> bool) -> Self { + Self { + inner: Mutex::new(RefCell::new(GenericTimerQueue::new(set_alarm))), + } + } + + /// Schedules a task to run at a specific time, and returns whether any changes were made. + pub fn schedule_wake(&self, at: u64, waker: &core::task::Waker) { + critical_section::with(|cs| { + let mut inner = self.inner.borrow_ref_mut(cs); + inner.schedule_wake(at, waker); + }); + } + + /// Dequeues expired timers and returns the next alarm time. + pub fn next_expiration(&self, now: u64) -> u64 { + critical_section::with(|cs| { + let mut inner = self.inner.borrow_ref_mut(cs); + inner.next_expiration(now) + }) + } + + /// Handle the alarm. + /// + /// Call this function when the next alarm is due. + pub fn dispatch(&self) { + critical_section::with(|cs| { + let mut inner = self.inner.borrow_ref_mut(cs); + inner.dispatch() + }) + } +} + +impl TimerQueue for GlobalTimerQueue { + fn schedule_wake(&'static self, at: u64, waker: &Waker) { + GlobalTimerQueue::schedule_wake(self, at, waker) + } +} diff --git a/embassy-time-queue-driver/src/queue_generic.rs b/embassy-time-queue-driver/src/queue_generic.rs new file mode 100644 index 000000000..232035bc6 --- /dev/null +++ b/embassy-time-queue-driver/src/queue_generic.rs @@ -0,0 +1,146 @@ +//! Generic timer queue implementations. +//! +//! Time queue drivers may use this to simplify their implementation. + +use core::cmp::{min, Ordering}; +use core::task::Waker; + +use heapless::Vec; + +#[derive(Debug)] +struct Timer { + at: u64, + waker: Waker, +} + +impl PartialEq for Timer { + fn eq(&self, other: &Self) -> bool { + self.at == other.at + } +} + +impl Eq for Timer {} + +impl PartialOrd for Timer { + fn partial_cmp(&self, other: &Self) -> Option { + self.at.partial_cmp(&other.at) + } +} + +impl Ord for Timer { + fn cmp(&self, other: &Self) -> Ordering { + self.at.cmp(&other.at) + } +} + +/// A timer queue with a pre-determined capacity. +pub struct ConstGenericQueue { + queue: Vec, +} + +impl ConstGenericQueue { + /// Creates a new timer queue. + pub const fn new() -> Self { + Self { queue: Vec::new() } + } + + /// Schedules a task to run at a specific time, and returns whether any changes were made. + /// + /// If this function returns `true`, the called should find the next expiration time and set + /// a new alarm for that time. + pub fn schedule_wake(&mut self, at: u64, waker: &Waker) -> bool { + self.queue + .iter_mut() + .find(|timer| timer.waker.will_wake(waker)) + .map(|timer| { + if timer.at > at { + timer.at = at; + true + } else { + false + } + }) + .unwrap_or_else(|| { + let mut timer = Timer { + waker: waker.clone(), + at, + }; + + loop { + match self.queue.push(timer) { + Ok(()) => break, + Err(e) => timer = e, + } + + self.queue.pop().unwrap().waker.wake(); + } + + true + }) + } + + /// Dequeues expired timers and returns the next alarm time. + pub fn next_expiration(&mut self, now: u64) -> u64 { + let mut next_alarm = u64::MAX; + + let mut i = 0; + while i < self.queue.len() { + let timer = &self.queue[i]; + if timer.at <= now { + let timer = self.queue.swap_remove(i); + timer.waker.wake(); + } else { + next_alarm = min(next_alarm, timer.at); + i += 1; + } + } + + next_alarm + } +} + +#[cfg(feature = "generic-queue-8")] +const QUEUE_SIZE: usize = 8; +#[cfg(feature = "generic-queue-16")] +const QUEUE_SIZE: usize = 16; +#[cfg(feature = "generic-queue-32")] +const QUEUE_SIZE: usize = 32; +#[cfg(feature = "generic-queue-64")] +const QUEUE_SIZE: usize = 64; +#[cfg(feature = "generic-queue-128")] +const QUEUE_SIZE: usize = 128; +#[cfg(not(any( + feature = "generic-queue-8", + feature = "generic-queue-16", + feature = "generic-queue-32", + feature = "generic-queue-64", + feature = "generic-queue-128" +)))] +const QUEUE_SIZE: usize = 64; + +/// A timer queue with a pre-determined capacity. +pub struct Queue { + queue: ConstGenericQueue, +} + +impl Queue { + /// Creates a new timer queue. + pub const fn new() -> Self { + Self { + queue: ConstGenericQueue::new(), + } + } + + /// Schedules a task to run at a specific time, and returns whether any changes were made. + /// + /// If this function returns `true`, the called should find the next expiration time and set + /// a new alarm for that time. + pub fn schedule_wake(&mut self, at: u64, waker: &Waker) -> bool { + self.queue.schedule_wake(at, waker) + } + + /// Dequeues expired timers and returns the next alarm time. + pub fn next_expiration(&mut self, now: u64) -> u64 { + self.queue.next_expiration(now) + } +} diff --git a/embassy-time/Cargo.toml b/embassy-time/Cargo.toml index 8c7de9840..e3074119f 100644 --- a/embassy-time/Cargo.toml +++ b/embassy-time/Cargo.toml @@ -42,29 +42,6 @@ defmt-timestamp-uptime-tus = ["defmt"] ## Create a `MockDriver` that can be manually advanced for testing purposes. mock-driver = ["tick-hz-1_000_000"] -#! ### Generic Queue - -## Create a global, generic queue that can be used with any executor. -## To use this you must have a time driver provided. -generic-queue = [] - -#! The following features set how many timers are used for the generic queue. At most one -#! `generic-queue-*` feature can be enabled. If none is enabled, a default of 64 timers is used. -#! -#! When using embassy-time from libraries, you should *not* enable any `generic-queue-*` feature, to allow the -#! end user to pick. - -## Generic Queue with 8 timers -generic-queue-8 = ["generic-queue"] -## Generic Queue with 16 timers -generic-queue-16 = ["generic-queue"] -## Generic Queue with 32 timers -generic-queue-32 = ["generic-queue"] -## Generic Queue with 64 timers -generic-queue-64 = ["generic-queue"] -## Generic Queue with 128 timers -generic-queue-128 = ["generic-queue"] - #! ### Tick Rate #! #! At most 1 `tick-*` feature can be enabled. If none is enabled, a default of 1MHz is used. @@ -419,7 +396,6 @@ embedded-hal-async = { version = "1.0" } futures-util = { version = "0.3.17", default-features = false } critical-section = "1.1" cfg-if = "1.0.0" -heapless = "0.8" document-features = "0.2.7" diff --git a/embassy-time/src/driver_mock.rs b/embassy-time/src/driver_mock.rs index 8587f9172..829eb0437 100644 --- a/embassy-time/src/driver_mock.rs +++ b/embassy-time/src/driver_mock.rs @@ -1,7 +1,7 @@ use core::cell::RefCell; use critical_section::Mutex as CsMutex; -use embassy_time_driver::{AlarmHandle, Driver}; +use embassy_time_driver::Driver; use crate::{Duration, Instant}; @@ -60,15 +60,13 @@ impl MockDriver { let now = inner.now.as_ticks(); - inner - .alarm - .as_mut() - .filter(|alarm| alarm.timestamp <= now) - .map(|alarm| { - alarm.timestamp = u64::MAX; + if inner.alarm.timestamp <= now { + inner.alarm.timestamp = u64::MAX; - (alarm.callback, alarm.ctx) - }) + Some((inner.alarm.callback, inner.alarm.ctx)) + } else { + None + } }) }; @@ -76,68 +74,48 @@ impl MockDriver { (callback)(ctx); } } -} -impl Driver for MockDriver { - fn now(&self) -> u64 { - critical_section::with(|cs| self.0.borrow_ref(cs).now).as_ticks() - } - - unsafe fn allocate_alarm(&self) -> Option { + /// Configures a callback to be called when the alarm fires. + pub fn set_alarm_callback(&self, callback: fn(*mut ()), ctx: *mut ()) { critical_section::with(|cs| { let mut inner = self.0.borrow_ref_mut(cs); - if inner.alarm.is_some() { - None - } else { - inner.alarm.replace(AlarmState::new()); - - Some(AlarmHandle::new(0)) - } - }) - } - - fn set_alarm_callback(&self, _alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()) { - critical_section::with(|cs| { - let mut inner = self.0.borrow_ref_mut(cs); - - let Some(alarm) = inner.alarm.as_mut() else { - panic!("Alarm not allocated"); - }; - - alarm.callback = callback; - alarm.ctx = ctx; + inner.alarm.callback = callback; + inner.alarm.ctx = ctx; }); } - fn set_alarm(&self, _alarm: AlarmHandle, timestamp: u64) -> bool { + /// Sets the alarm to fire at the specified timestamp. + pub fn set_alarm(&self, timestamp: u64) -> bool { critical_section::with(|cs| { let mut inner = self.0.borrow_ref_mut(cs); if timestamp <= inner.now.as_ticks() { false } else { - let Some(alarm) = inner.alarm.as_mut() else { - panic!("Alarm not allocated"); - }; - - alarm.timestamp = timestamp; + inner.alarm.timestamp = timestamp; true } }) } } +impl Driver for MockDriver { + fn now(&self) -> u64 { + critical_section::with(|cs| self.0.borrow_ref(cs).now).as_ticks() + } +} + struct InnerMockDriver { now: Instant, - alarm: Option, + alarm: AlarmState, } impl InnerMockDriver { const fn new() -> Self { Self { now: Instant::from_ticks(0), - alarm: None, + alarm: AlarmState::new(), } } } @@ -189,8 +167,7 @@ mod tests { setup(); let driver = MockDriver::get(); - let alarm = unsafe { AlarmHandle::new(0) }; - assert_eq!(false, driver.set_alarm(alarm, driver.now())); + assert_eq!(false, driver.set_alarm(driver.now())); } #[test] @@ -199,23 +176,11 @@ mod tests { setup(); let driver = MockDriver::get(); - let alarm = unsafe { driver.allocate_alarm() }.expect("No alarms available"); static mut CALLBACK_CALLED: bool = false; - let ctx = &mut () as *mut (); - driver.set_alarm_callback(alarm, |_| unsafe { CALLBACK_CALLED = true }, ctx); - driver.set_alarm(alarm, driver.now() + 1); + driver.set_alarm_callback(|_| unsafe { CALLBACK_CALLED = true }, core::ptr::null_mut()); + driver.set_alarm(driver.now() + 1); assert_eq!(false, unsafe { CALLBACK_CALLED }); driver.advance(Duration::from_secs(1)); assert_eq!(true, unsafe { CALLBACK_CALLED }); } - - #[test] - #[serial] - fn test_allocate_alarm() { - setup(); - - let driver = MockDriver::get(); - assert!(unsafe { driver.allocate_alarm() }.is_some()); - assert!(unsafe { driver.allocate_alarm() }.is_none()); - } } diff --git a/embassy-time/src/driver_std.rs b/embassy-time/src/driver_std.rs index cbef7aae1..45467f09b 100644 --- a/embassy-time/src/driver_std.rs +++ b/embassy-time/src/driver_std.rs @@ -1,53 +1,38 @@ -use core::sync::atomic::{AtomicU8, Ordering}; use std::cell::{RefCell, UnsafeCell}; use std::mem::MaybeUninit; use std::sync::{Condvar, Mutex, Once}; use std::time::{Duration as StdDuration, Instant as StdInstant}; -use std::{mem, ptr, thread}; +use std::{ptr, thread}; use critical_section::Mutex as CsMutex; -use embassy_time_driver::{AlarmHandle, Driver}; - -const ALARM_COUNT: usize = 4; +use embassy_time_driver::Driver; +use embassy_time_queue_driver::GlobalTimerQueue; struct AlarmState { timestamp: u64, - - // This is really a Option<(fn(*mut ()), *mut ())> - // but fn pointers aren't allowed in const yet - callback: *const (), - ctx: *mut (), } unsafe impl Send for AlarmState {} impl AlarmState { const fn new() -> Self { - Self { - timestamp: u64::MAX, - callback: ptr::null(), - ctx: ptr::null_mut(), - } + Self { timestamp: u64::MAX } } } struct TimeDriver { - alarm_count: AtomicU8, - once: Once, - // The STD Driver implementation requires the alarms' mutex to be reentrant, which the STD Mutex isn't + // The STD Driver implementation requires the alarm's mutex to be reentrant, which the STD Mutex isn't // Fortunately, mutexes based on the `critical-section` crate are reentrant, because the critical sections // themselves are reentrant - alarms: UninitCell>>, + alarm: UninitCell>>, zero_instant: UninitCell, signaler: UninitCell, } embassy_time_driver::time_driver_impl!(static DRIVER: TimeDriver = TimeDriver { - alarm_count: AtomicU8::new(0), - once: Once::new(), - alarms: UninitCell::uninit(), + alarm: UninitCell::uninit(), zero_instant: UninitCell::uninit(), signaler: UninitCell::uninit(), }); @@ -55,8 +40,8 @@ embassy_time_driver::time_driver_impl!(static DRIVER: TimeDriver = TimeDriver { impl TimeDriver { fn init(&self) { self.once.call_once(|| unsafe { - self.alarms - .write(CsMutex::new(RefCell::new([const { AlarmState::new() }; ALARM_COUNT]))); + self.alarm + .write(CsMutex::new(RefCell::new(const { AlarmState::new() }))); self.zero_instant.write(StdInstant::now()); self.signaler.write(Signaler::new()); @@ -70,36 +55,13 @@ impl TimeDriver { let now = DRIVER.now(); let next_alarm = critical_section::with(|cs| { - let alarms = unsafe { DRIVER.alarms.as_ref() }.borrow(cs); - loop { - let pending = alarms - .borrow_mut() - .iter_mut() - .find(|alarm| alarm.timestamp <= now) - .map(|alarm| { - alarm.timestamp = u64::MAX; + let mut alarm = unsafe { DRIVER.alarm.as_ref() }.borrow_ref_mut(cs); + if alarm.timestamp <= now { + alarm.timestamp = u64::MAX; - (alarm.callback, alarm.ctx) - }); - - if let Some((callback, ctx)) = pending { - // safety: - // - we can ignore the possiblity of `f` being unset (null) because of the safety contract of `allocate_alarm`. - // - other than that we only store valid function pointers into alarm.callback - let f: fn(*mut ()) = unsafe { mem::transmute(callback) }; - f(ctx); - } else { - // No alarm due - break; - } + TIMER_QUEUE_DRIVER.dispatch(); } - - alarms - .borrow() - .iter() - .map(|alarm| alarm.timestamp) - .min() - .unwrap_or(u64::MAX) + alarm.timestamp }); // Ensure we don't overflow @@ -110,6 +72,17 @@ impl TimeDriver { unsafe { DRIVER.signaler.as_ref() }.wait_until(until); } } + + fn set_alarm(&self, timestamp: u64) -> bool { + self.init(); + critical_section::with(|cs| { + let mut alarm = unsafe { self.alarm.as_ref() }.borrow_ref_mut(cs); + alarm.timestamp = timestamp; + unsafe { self.signaler.as_ref() }.signal(); + }); + + true + } } impl Driver for TimeDriver { @@ -119,43 +92,6 @@ impl Driver for TimeDriver { let zero = unsafe { self.zero_instant.read() }; StdInstant::now().duration_since(zero).as_micros() as u64 } - - unsafe fn allocate_alarm(&self) -> Option { - let id = self.alarm_count.fetch_update(Ordering::AcqRel, Ordering::Acquire, |x| { - if x < ALARM_COUNT as u8 { - Some(x + 1) - } else { - None - } - }); - - match id { - Ok(id) => Some(AlarmHandle::new(id)), - Err(_) => None, - } - } - - fn set_alarm_callback(&self, alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()) { - self.init(); - critical_section::with(|cs| { - let mut alarms = unsafe { self.alarms.as_ref() }.borrow_ref_mut(cs); - let alarm = &mut alarms[alarm.id() as usize]; - alarm.callback = callback as *const (); - alarm.ctx = ctx; - }); - } - - fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) -> bool { - self.init(); - critical_section::with(|cs| { - let mut alarms = unsafe { self.alarms.as_ref() }.borrow_ref_mut(cs); - let alarm = &mut alarms[alarm.id() as usize]; - alarm.timestamp = timestamp; - unsafe { self.signaler.as_ref() }.signal(); - }); - - true - } } struct Signaler { @@ -228,3 +164,8 @@ impl UninitCell { ptr::read(self.as_mut_ptr()) } } + +embassy_time_queue_driver::timer_queue_impl!( + static TIMER_QUEUE_DRIVER: GlobalTimerQueue + = GlobalTimerQueue::new(|next_expiration| DRIVER.set_alarm(next_expiration)) +); diff --git a/embassy-time/src/driver_wasm.rs b/embassy-time/src/driver_wasm.rs index d65629e49..dcc935fde 100644 --- a/embassy-time/src/driver_wasm.rs +++ b/embassy-time/src/driver_wasm.rs @@ -1,28 +1,22 @@ -use core::sync::atomic::{AtomicU8, Ordering}; use std::cell::UnsafeCell; use std::mem::MaybeUninit; use std::ptr; use std::sync::{Mutex, Once}; -use embassy_time_driver::{AlarmHandle, Driver}; +use embassy_time_driver::Driver; +use embassy_time_queue_driver::GlobalTimerQueue; use wasm_bindgen::prelude::*; use wasm_timer::Instant as StdInstant; -const ALARM_COUNT: usize = 4; - struct AlarmState { token: Option, - closure: Option>, } unsafe impl Send for AlarmState {} impl AlarmState { const fn new() -> Self { - Self { - token: None, - closure: None, - } + Self { token: None } } } @@ -33,66 +27,32 @@ extern "C" { } struct TimeDriver { - alarm_count: AtomicU8, - once: Once, - alarms: UninitCell>, + alarm: UninitCell>, zero_instant: UninitCell, + closure: UninitCell>, } embassy_time_driver::time_driver_impl!(static DRIVER: TimeDriver = TimeDriver { - alarm_count: AtomicU8::new(0), once: Once::new(), - alarms: UninitCell::uninit(), + alarm: UninitCell::uninit(), zero_instant: UninitCell::uninit(), + closure: UninitCell::uninit() }); impl TimeDriver { fn init(&self) { self.once.call_once(|| unsafe { - self.alarms - .write(Mutex::new([const { AlarmState::new() }; ALARM_COUNT])); + self.alarm.write(Mutex::new(const { AlarmState::new() })); self.zero_instant.write(StdInstant::now()); + self.closure + .write(Closure::new(Box::new(|| TIMER_QUEUE_DRIVER.dispatch()))); }); } -} -impl Driver for TimeDriver { - fn now(&self) -> u64 { + fn set_alarm(&self, timestamp: u64) -> bool { self.init(); - - let zero = unsafe { self.zero_instant.read() }; - StdInstant::now().duration_since(zero).as_micros() as u64 - } - - unsafe fn allocate_alarm(&self) -> Option { - let id = self.alarm_count.fetch_update(Ordering::AcqRel, Ordering::Acquire, |x| { - if x < ALARM_COUNT as u8 { - Some(x + 1) - } else { - None - } - }); - - match id { - Ok(id) => Some(AlarmHandle::new(id)), - Err(_) => None, - } - } - - fn set_alarm_callback(&self, alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()) { - self.init(); - let mut alarms = unsafe { self.alarms.as_ref() }.lock().unwrap(); - let alarm = &mut alarms[alarm.id() as usize]; - alarm.closure.replace(Closure::new(move || { - callback(ctx); - })); - } - - fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) -> bool { - self.init(); - let mut alarms = unsafe { self.alarms.as_ref() }.lock().unwrap(); - let alarm = &mut alarms[alarm.id() as usize]; + let mut alarm = unsafe { self.alarm.as_ref() }.lock().unwrap(); if let Some(token) = alarm.token { clearTimeout(token); } @@ -102,13 +62,22 @@ impl Driver for TimeDriver { false } else { let timeout = (timestamp - now) as u32; - alarm.token = Some(setTimeout(alarm.closure.as_ref().unwrap(), timeout / 1000)); + alarm.token = Some(setTimeout(unsafe { self.closure.as_ref() }, timeout / 1000)); true } } } +impl Driver for TimeDriver { + fn now(&self) -> u64 { + self.init(); + + let zero = unsafe { self.zero_instant.read() }; + StdInstant::now().duration_since(zero).as_micros() as u64 + } +} + pub(crate) struct UninitCell(MaybeUninit>); unsafe impl Send for UninitCell {} unsafe impl Sync for UninitCell {} @@ -139,3 +108,8 @@ impl UninitCell { ptr::read(self.as_mut_ptr()) } } + +embassy_time_queue_driver::timer_queue_impl!( + static TIMER_QUEUE_DRIVER: GlobalTimerQueue + = GlobalTimerQueue::new(|next_expiration| DRIVER.set_alarm(next_expiration)) +); diff --git a/embassy-time/src/lib.rs b/embassy-time/src/lib.rs index 8d0648ce5..80a359413 100644 --- a/embassy-time/src/lib.rs +++ b/embassy-time/src/lib.rs @@ -25,8 +25,6 @@ pub use driver_mock::MockDriver; mod driver_std; #[cfg(feature = "wasm")] mod driver_wasm; -#[cfg(feature = "generic-queue")] -mod queue_generic; pub use delay::{block_for, Delay}; pub use duration::Duration; diff --git a/embassy-time/src/queue_generic.rs b/embassy-time/src/queue_generic.rs deleted file mode 100644 index 0068edae8..000000000 --- a/embassy-time/src/queue_generic.rs +++ /dev/null @@ -1,346 +0,0 @@ -use core::cell::RefCell; -use core::cmp::{min, Ordering}; -use core::task::Waker; - -use critical_section::Mutex; -use embassy_time_driver::{allocate_alarm, set_alarm, set_alarm_callback, AlarmHandle}; -use embassy_time_queue_driver::TimerQueue; -use heapless::Vec; - -use crate::Instant; - -#[cfg(feature = "generic-queue-8")] -const QUEUE_SIZE: usize = 8; -#[cfg(feature = "generic-queue-16")] -const QUEUE_SIZE: usize = 16; -#[cfg(feature = "generic-queue-32")] -const QUEUE_SIZE: usize = 32; -#[cfg(feature = "generic-queue-64")] -const QUEUE_SIZE: usize = 64; -#[cfg(feature = "generic-queue-128")] -const QUEUE_SIZE: usize = 128; -#[cfg(not(any( - feature = "generic-queue-8", - feature = "generic-queue-16", - feature = "generic-queue-32", - feature = "generic-queue-64", - feature = "generic-queue-128" -)))] -const QUEUE_SIZE: usize = 64; - -#[derive(Debug)] -struct Timer { - at: Instant, - waker: Waker, -} - -impl PartialEq for Timer { - fn eq(&self, other: &Self) -> bool { - self.at == other.at - } -} - -impl Eq for Timer {} - -impl PartialOrd for Timer { - fn partial_cmp(&self, other: &Self) -> Option { - self.at.partial_cmp(&other.at) - } -} - -impl Ord for Timer { - fn cmp(&self, other: &Self) -> Ordering { - self.at.cmp(&other.at) - } -} - -struct InnerQueue { - queue: Vec, - alarm: AlarmHandle, -} - -impl InnerQueue { - fn schedule_wake(&mut self, at: Instant, waker: &Waker) { - self.queue - .iter_mut() - .find(|timer| timer.waker.will_wake(waker)) - .map(|timer| { - timer.at = min(timer.at, at); - }) - .unwrap_or_else(|| { - let mut timer = Timer { - waker: waker.clone(), - at, - }; - - loop { - match self.queue.push(timer) { - Ok(()) => break, - Err(e) => timer = e, - } - - self.queue.pop().unwrap().waker.wake(); - } - }); - - // Don't wait for the alarm callback to trigger and directly - // dispatch all timers that are already due - // - // Then update the alarm if necessary - self.dispatch(); - } - - fn dispatch(&mut self) { - loop { - let now = Instant::now(); - - let mut next_alarm = Instant::MAX; - - let mut i = 0; - while i < self.queue.len() { - let timer = &self.queue[i]; - if timer.at <= now { - let timer = self.queue.swap_remove(i); - timer.waker.wake(); - } else { - next_alarm = min(next_alarm, timer.at); - i += 1; - } - } - - if self.update_alarm(next_alarm) { - break; - } - } - } - - fn update_alarm(&mut self, next_alarm: Instant) -> bool { - if next_alarm == Instant::MAX { - true - } else { - set_alarm(self.alarm, next_alarm.as_ticks()) - } - } - - fn handle_alarm(&mut self) { - self.dispatch(); - } -} - -struct Queue { - inner: Mutex>>, -} - -impl Queue { - const fn new() -> Self { - Self { - inner: Mutex::new(RefCell::new(None)), - } - } - - fn schedule_wake(&'static self, at: Instant, waker: &Waker) { - critical_section::with(|cs| { - let mut inner = self.inner.borrow_ref_mut(cs); - - inner - .get_or_insert_with(|| { - let handle = unsafe { allocate_alarm() }.unwrap(); - set_alarm_callback(handle, Self::handle_alarm_callback, self as *const _ as _); - InnerQueue { - queue: Vec::new(), - alarm: handle, - } - }) - .schedule_wake(at, waker) - }); - } - - fn handle_alarm(&self) { - critical_section::with(|cs| self.inner.borrow_ref_mut(cs).as_mut().unwrap().handle_alarm()) - } - - fn handle_alarm_callback(ctx: *mut ()) { - unsafe { (ctx as *const Self).as_ref().unwrap() }.handle_alarm(); - } -} - -impl TimerQueue for Queue { - fn schedule_wake(&'static self, at: u64, waker: &Waker) { - Queue::schedule_wake(self, Instant::from_ticks(at), waker); - } -} - -embassy_time_queue_driver::timer_queue_impl!(static QUEUE: Queue = Queue::new()); - -#[cfg(test)] -#[cfg(feature = "mock-driver")] -mod tests { - use core::sync::atomic::{AtomicBool, Ordering}; - use core::task::Waker; - use std::sync::Arc; - use std::task::Wake; - - use serial_test::serial; - - use crate::driver_mock::MockDriver; - use crate::queue_generic::QUEUE; - use crate::{Duration, Instant}; - - struct TestWaker { - pub awoken: AtomicBool, - } - - impl Wake for TestWaker { - fn wake(self: Arc) { - self.awoken.store(true, Ordering::Relaxed); - } - - fn wake_by_ref(self: &Arc) { - self.awoken.store(true, Ordering::Relaxed); - } - } - - fn test_waker() -> (Arc, Waker) { - let arc = Arc::new(TestWaker { - awoken: AtomicBool::new(false), - }); - let waker = Waker::from(arc.clone()); - - (arc, waker) - } - - fn setup() { - MockDriver::get().reset(); - critical_section::with(|cs| *QUEUE.inner.borrow_ref_mut(cs) = None); - } - - fn queue_len() -> usize { - critical_section::with(|cs| { - QUEUE - .inner - .borrow_ref(cs) - .as_ref() - .map(|inner| inner.queue.iter().count()) - .unwrap_or(0) - }) - } - - #[test] - #[serial] - fn test_schedule() { - setup(); - - assert_eq!(queue_len(), 0); - - let (flag, waker) = test_waker(); - - QUEUE.schedule_wake(Instant::from_secs(1), &waker); - - assert!(!flag.awoken.load(Ordering::Relaxed)); - assert_eq!(queue_len(), 1); - } - - #[test] - #[serial] - fn test_schedule_same() { - setup(); - - let (_flag, waker) = test_waker(); - - QUEUE.schedule_wake(Instant::from_secs(1), &waker); - - assert_eq!(queue_len(), 1); - - QUEUE.schedule_wake(Instant::from_secs(1), &waker); - - assert_eq!(queue_len(), 1); - - QUEUE.schedule_wake(Instant::from_secs(100), &waker); - - assert_eq!(queue_len(), 1); - - let (_flag2, waker2) = test_waker(); - - QUEUE.schedule_wake(Instant::from_secs(100), &waker2); - - assert_eq!(queue_len(), 2); - } - - #[test] - #[serial] - fn test_trigger() { - setup(); - - let (flag, waker) = test_waker(); - - QUEUE.schedule_wake(Instant::from_secs(100), &waker); - - assert!(!flag.awoken.load(Ordering::Relaxed)); - - MockDriver::get().advance(Duration::from_secs(99)); - - assert!(!flag.awoken.load(Ordering::Relaxed)); - - assert_eq!(queue_len(), 1); - - MockDriver::get().advance(Duration::from_secs(1)); - - assert!(flag.awoken.load(Ordering::Relaxed)); - - assert_eq!(queue_len(), 0); - } - - #[test] - #[serial] - fn test_immediate_trigger() { - setup(); - - let (flag, waker) = test_waker(); - - QUEUE.schedule_wake(Instant::from_secs(100), &waker); - - MockDriver::get().advance(Duration::from_secs(50)); - - let (flag2, waker2) = test_waker(); - - QUEUE.schedule_wake(Instant::from_secs(40), &waker2); - - assert!(!flag.awoken.load(Ordering::Relaxed)); - assert!(flag2.awoken.load(Ordering::Relaxed)); - assert_eq!(queue_len(), 1); - } - - #[test] - #[serial] - fn test_queue_overflow() { - setup(); - - for i in 1..super::QUEUE_SIZE { - let (flag, waker) = test_waker(); - - QUEUE.schedule_wake(Instant::from_secs(310), &waker); - - assert_eq!(queue_len(), i); - assert!(!flag.awoken.load(Ordering::Relaxed)); - } - - let (flag, waker) = test_waker(); - - QUEUE.schedule_wake(Instant::from_secs(300), &waker); - - assert_eq!(queue_len(), super::QUEUE_SIZE); - assert!(!flag.awoken.load(Ordering::Relaxed)); - - let (flag2, waker2) = test_waker(); - - QUEUE.schedule_wake(Instant::from_secs(305), &waker2); - - assert_eq!(queue_len(), super::QUEUE_SIZE); - assert!(flag.awoken.load(Ordering::Relaxed)); - - let (_flag3, waker3) = test_waker(); - QUEUE.schedule_wake(Instant::from_secs(320), &waker3); - assert_eq!(queue_len(), super::QUEUE_SIZE); - assert!(flag2.awoken.load(Ordering::Relaxed)); - } -} diff --git a/examples/nrf52840-rtic/Cargo.toml b/examples/nrf52840-rtic/Cargo.toml index 290b2fdb1..326355dd6 100644 --- a/examples/nrf52840-rtic/Cargo.toml +++ b/examples/nrf52840-rtic/Cargo.toml @@ -9,7 +9,8 @@ rtic = { version = "2", features = ["thumbv7-backend"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } -embassy-time = { version = "0.3.2", path = "../../embassy-time", features = [ "defmt", "defmt-timestamp-uptime", "generic-queue"] } +embassy-time = { version = "0.3.2", path = "../../embassy-time", features = [ "defmt", "defmt-timestamp-uptime"] } +embassy-time-queue-driver = { version = "0.1.0", path = "../../embassy-time-queue-driver" } embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = [ "defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } defmt = "0.3" From 6cc8709ecc9e8f71a13ec62b42be52bc8adf2c7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Sun, 8 Dec 2024 20:05:37 +0100 Subject: [PATCH 0462/1217] Changelog --- embassy-executor/CHANGELOG.md | 5 ++++- embassy-time-driver/CHANGELOG.md | 14 ++++++++++++++ embassy-time-queue-driver/CHANGELOG.md | 16 ++++++++++++++++ embassy-time/CHANGELOG.md | 5 ++++- 4 files changed, 38 insertions(+), 2 deletions(-) create mode 100644 embassy-time-driver/CHANGELOG.md create mode 100644 embassy-time-queue-driver/CHANGELOG.md diff --git a/embassy-executor/CHANGELOG.md b/embassy-executor/CHANGELOG.md index 00b1bef28..1aef57a70 100644 --- a/embassy-executor/CHANGELOG.md +++ b/embassy-executor/CHANGELOG.md @@ -7,7 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased -- `raw::Executor` now has an `fn initialize` that must be called once before starting to poll it. +- embassy-executor no longer provides an `embassy-time-queue-driver` implementation +- Added `TaskRef::executor` to obtain a reference to a task's executor +- integrated-timers are no longer processed when polling the executor. +- `raw::timer_queue::TimerQueue` is now public. ## 0.6.3 - 2024-11-12 diff --git a/embassy-time-driver/CHANGELOG.md b/embassy-time-driver/CHANGELOG.md new file mode 100644 index 000000000..ebc37b6f4 --- /dev/null +++ b/embassy-time-driver/CHANGELOG.md @@ -0,0 +1,14 @@ +# Changelog for embassy-time-queue-driver + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## Unreleased + +- The `allocate_alarm`, `set_alarm_callback`, `set_alarm` functions have been removed. + +## 0.1.0 - 2024-01-11 + +Initial release diff --git a/embassy-time-queue-driver/CHANGELOG.md b/embassy-time-queue-driver/CHANGELOG.md new file mode 100644 index 000000000..3b2aa8695 --- /dev/null +++ b/embassy-time-queue-driver/CHANGELOG.md @@ -0,0 +1,16 @@ +# Changelog for embassy-time-queue-driver + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## Unreleased + +- Added `integrated-timers` and `generic-queue-N` features +- Added `queue_generic` module which contains `Queue` (configured via the `generic-queue-N` features) and `ConstGenericQueue`. +- Added `GenericTimerQueue` and `GlobalTimerQueue` structs that can be used to implement timer queues. + +## 0.1.0 - 2024-01-11 + +Initial release diff --git a/embassy-time/CHANGELOG.md b/embassy-time/CHANGELOG.md index 3b4d93387..a6acb1ad6 100644 --- a/embassy-time/CHANGELOG.md +++ b/embassy-time/CHANGELOG.md @@ -7,10 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +- The `generic-queue` and related features have been removed (moved to embassy-time-queue-driver) +- embassy-time no longer provides an `embassy-time-queue-driver` implementation + ## 0.3.2 - 2024-08-05 - Implement with_timeout()/with_deadline() method style call on Future -- Add collapse_debuginfo to fmt.rs macros. +- Add collapse_debuginfo to fmt.rs macros. ## 0.3.1 - 2024-01-11 From 12f58fbcfd3f10b43795936127a890c6a0f8f280 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Sun, 8 Dec 2024 23:04:43 +0100 Subject: [PATCH 0463/1217] Remove TIMER_QUEUED state --- embassy-executor/src/raw/state_atomics.rs | 18 ---------------- embassy-executor/src/raw/state_atomics_arm.rs | 19 ++--------------- .../src/raw/state_critical_section.rs | 21 ------------------- embassy-executor/src/raw/timer_queue.rs | 4 ++-- 4 files changed, 4 insertions(+), 58 deletions(-) diff --git a/embassy-executor/src/raw/state_atomics.rs b/embassy-executor/src/raw/state_atomics.rs index e1279ac0b..e4127897e 100644 --- a/embassy-executor/src/raw/state_atomics.rs +++ b/embassy-executor/src/raw/state_atomics.rs @@ -4,9 +4,6 @@ use core::sync::atomic::{AtomicU32, Ordering}; pub(crate) const STATE_SPAWNED: u32 = 1 << 0; /// Task is in the executor run queue pub(crate) const STATE_RUN_QUEUED: u32 = 1 << 1; -/// Task is in the executor timer queue -#[cfg(feature = "integrated-timers")] -pub(crate) const STATE_TIMER_QUEUED: u32 = 1 << 2; pub(crate) struct State { state: AtomicU32, @@ -55,19 +52,4 @@ impl State { let state = self.state.fetch_and(!STATE_RUN_QUEUED, Ordering::AcqRel); state & STATE_SPAWNED != 0 } - - /// Mark the task as timer-queued. Return whether it was newly queued (i.e. not queued before) - #[cfg(feature = "integrated-timers")] - #[inline(always)] - pub fn timer_enqueue(&self) -> bool { - let old_state = self.state.fetch_or(STATE_TIMER_QUEUED, Ordering::AcqRel); - old_state & STATE_TIMER_QUEUED == 0 - } - - /// Unmark the task as timer-queued. - #[cfg(feature = "integrated-timers")] - #[inline(always)] - pub fn timer_dequeue(&self) { - self.state.fetch_and(!STATE_TIMER_QUEUED, Ordering::AcqRel); - } } diff --git a/embassy-executor/src/raw/state_atomics_arm.rs b/embassy-executor/src/raw/state_atomics_arm.rs index e4dfe5093..b673c7359 100644 --- a/embassy-executor/src/raw/state_atomics_arm.rs +++ b/embassy-executor/src/raw/state_atomics_arm.rs @@ -11,9 +11,8 @@ pub(crate) struct State { spawned: AtomicBool, /// Task is in the executor run queue run_queued: AtomicBool, - /// Task is in the executor timer queue - timer_queued: AtomicBool, pad: AtomicBool, + pad2: AtomicBool, } impl State { @@ -21,8 +20,8 @@ impl State { Self { spawned: AtomicBool::new(false), run_queued: AtomicBool::new(false), - timer_queued: AtomicBool::new(false), pad: AtomicBool::new(false), + pad2: AtomicBool::new(false), } } @@ -86,18 +85,4 @@ impl State { self.run_queued.store(false, Ordering::Relaxed); r } - - /// Mark the task as timer-queued. Return whether it was newly queued (i.e. not queued before) - #[cfg(feature = "integrated-timers")] - #[inline(always)] - pub fn timer_enqueue(&self) -> bool { - !self.timer_queued.swap(true, Ordering::Relaxed) - } - - /// Unmark the task as timer-queued. - #[cfg(feature = "integrated-timers")] - #[inline(always)] - pub fn timer_dequeue(&self) { - self.timer_queued.store(false, Ordering::Relaxed); - } } diff --git a/embassy-executor/src/raw/state_critical_section.rs b/embassy-executor/src/raw/state_critical_section.rs index c3cc1b0b7..b92eed006 100644 --- a/embassy-executor/src/raw/state_critical_section.rs +++ b/embassy-executor/src/raw/state_critical_section.rs @@ -6,9 +6,6 @@ use critical_section::Mutex; pub(crate) const STATE_SPAWNED: u32 = 1 << 0; /// Task is in the executor run queue pub(crate) const STATE_RUN_QUEUED: u32 = 1 << 1; -/// Task is in the executor timer queue -#[cfg(feature = "integrated-timers")] -pub(crate) const STATE_TIMER_QUEUED: u32 = 1 << 2; pub(crate) struct State { state: Mutex>, @@ -72,22 +69,4 @@ impl State { ok }) } - - /// Mark the task as timer-queued. Return whether it was newly queued (i.e. not queued before) - #[cfg(feature = "integrated-timers")] - #[inline(always)] - pub fn timer_enqueue(&self) -> bool { - self.update(|s| { - let ok = *s & STATE_TIMER_QUEUED == 0; - *s |= STATE_TIMER_QUEUED; - ok - }) - } - - /// Unmark the task as timer-queued. - #[cfg(feature = "integrated-timers")] - #[inline(always)] - pub fn timer_dequeue(&self) { - self.update(|s| *s &= !STATE_TIMER_QUEUED); - } } diff --git a/embassy-executor/src/raw/timer_queue.rs b/embassy-executor/src/raw/timer_queue.rs index 953bf014f..513397090 100644 --- a/embassy-executor/src/raw/timer_queue.rs +++ b/embassy-executor/src/raw/timer_queue.rs @@ -39,7 +39,7 @@ impl TimerQueue { unsafe { let task = p.header(); let item = &task.timer_queue_item; - if task.state.timer_enqueue() { + if item.next.get().is_none() { // If not in the queue, add it and update. let prev = self.head.replace(Some(p)); item.next.set(prev); @@ -93,7 +93,7 @@ impl TimerQueue { } else { // Remove it prev.set(item.next.get()); - task.state.timer_dequeue(); + item.next.set(None); } } } From dc18ee29a0f93ce34892731ee0580a3e9e3f2298 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Sun, 8 Dec 2024 23:07:35 +0100 Subject: [PATCH 0464/1217] Do not access task header --- embassy-executor/src/raw/mod.rs | 6 ++++++ embassy-executor/src/raw/timer_queue.rs | 14 ++++++-------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs index 80bd49bad..f9c6509f1 100644 --- a/embassy-executor/src/raw/mod.rs +++ b/embassy-executor/src/raw/mod.rs @@ -82,6 +82,12 @@ impl TaskRef { self.header().executor.get().map(|e| Executor::wrap(e)) } + /// Returns a reference to the timer queue item. + #[cfg(feature = "integrated-timers")] + pub fn timer_queue_item(&self) -> &'static timer_queue::TimerQueueItem { + &self.header().timer_queue_item + } + /// The returned pointer is valid for the entire TaskStorage. pub(crate) fn as_ptr(self) -> *const TaskHeader { self.ptr.as_ptr() diff --git a/embassy-executor/src/raw/timer_queue.rs b/embassy-executor/src/raw/timer_queue.rs index 513397090..e0a22f4d4 100644 --- a/embassy-executor/src/raw/timer_queue.rs +++ b/embassy-executor/src/raw/timer_queue.rs @@ -4,13 +4,14 @@ use core::cmp::min; use super::util::SyncUnsafeCell; use super::TaskRef; -pub(crate) struct TimerQueueItem { +/// An item in the timer queue. +pub struct TimerQueueItem { next: SyncUnsafeCell>, expires_at: SyncUnsafeCell, } impl TimerQueueItem { - pub const fn new() -> Self { + pub(crate) const fn new() -> Self { Self { next: SyncUnsafeCell::new(None), expires_at: SyncUnsafeCell::new(0), @@ -37,8 +38,7 @@ impl TimerQueue { /// a new alarm for that time. pub fn schedule_wake(&mut self, at: u64, p: TaskRef) -> bool { unsafe { - let task = p.header(); - let item = &task.timer_queue_item; + let item = p.timer_queue_item(); if item.next.get().is_none() { // If not in the queue, add it and update. let prev = self.head.replace(Some(p)); @@ -63,8 +63,7 @@ impl TimerQueue { let mut next_expiration = u64::MAX; self.retain(|p| { - let task = p.header(); - let item = &task.timer_queue_item; + let item = p.timer_queue_item(); let expires = unsafe { item.expires_at.get() }; if expires <= now { @@ -85,8 +84,7 @@ impl TimerQueue { unsafe { let mut prev = &self.head; while let Some(p) = prev.get() { - let task = p.header(); - let item = &task.timer_queue_item; + let item = p.timer_queue_item(); if f(p) { // Skip to next prev = &item.next; From d45ea43892198484b5f6dcea4c351dc11d226cc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Sun, 8 Dec 2024 23:21:53 +0100 Subject: [PATCH 0465/1217] Move integrated timer queue into time-queue-driver --- embassy-executor/CHANGELOG.md | 1 - embassy-executor/src/raw/timer_queue.rs | 96 +++---------------- embassy-executor/src/raw/util.rs | 5 - embassy-time-queue-driver/src/lib.rs | 11 ++- .../src/queue_integrated.rs | 78 +++++++++++++++ 5 files changed, 96 insertions(+), 95 deletions(-) create mode 100644 embassy-time-queue-driver/src/queue_integrated.rs diff --git a/embassy-executor/CHANGELOG.md b/embassy-executor/CHANGELOG.md index 1aef57a70..068156210 100644 --- a/embassy-executor/CHANGELOG.md +++ b/embassy-executor/CHANGELOG.md @@ -10,7 +10,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - embassy-executor no longer provides an `embassy-time-queue-driver` implementation - Added `TaskRef::executor` to obtain a reference to a task's executor - integrated-timers are no longer processed when polling the executor. -- `raw::timer_queue::TimerQueue` is now public. ## 0.6.3 - 2024-11-12 diff --git a/embassy-executor/src/raw/timer_queue.rs b/embassy-executor/src/raw/timer_queue.rs index e0a22f4d4..46e346c1b 100644 --- a/embassy-executor/src/raw/timer_queue.rs +++ b/embassy-executor/src/raw/timer_queue.rs @@ -1,99 +1,25 @@ //! Timer queue operations. -use core::cmp::min; -use super::util::SyncUnsafeCell; +use core::cell::Cell; + use super::TaskRef; /// An item in the timer queue. pub struct TimerQueueItem { - next: SyncUnsafeCell>, - expires_at: SyncUnsafeCell, + /// The next item in the queue. + pub next: Cell>, + + /// The time at which this item expires. + pub expires_at: Cell, } +unsafe impl Sync for TimerQueueItem {} + impl TimerQueueItem { pub(crate) const fn new() -> Self { Self { - next: SyncUnsafeCell::new(None), - expires_at: SyncUnsafeCell::new(0), - } - } -} - -/// A timer queue, with items integrated into tasks. -pub struct TimerQueue { - head: SyncUnsafeCell>, -} - -impl TimerQueue { - /// Creates a new timer queue. - pub const fn new() -> Self { - Self { - head: SyncUnsafeCell::new(None), - } - } - - /// Schedules a task to run at a specific time. - /// - /// If this function returns `true`, the called should find the next expiration time and set - /// a new alarm for that time. - pub fn schedule_wake(&mut self, at: u64, p: TaskRef) -> bool { - unsafe { - let item = p.timer_queue_item(); - if item.next.get().is_none() { - // If not in the queue, add it and update. - let prev = self.head.replace(Some(p)); - item.next.set(prev); - } else if at <= item.expires_at.get() { - // If expiration is sooner than previously set, update. - } else { - // Task does not need to be updated. - return false; - } - - item.expires_at.set(at); - true - } - } - - /// Dequeues expired timers and returns the next alarm time. - /// - /// The provided callback will be called for each expired task. Tasks that never expire - /// will be removed, but the callback will not be called. - pub fn next_expiration(&mut self, now: u64) -> u64 { - let mut next_expiration = u64::MAX; - - self.retain(|p| { - let item = p.timer_queue_item(); - let expires = unsafe { item.expires_at.get() }; - - if expires <= now { - // Timer expired, process task. - super::wake_task(p); - false - } else { - // Timer didn't yet expire, or never expires. - next_expiration = min(next_expiration, expires); - expires != u64::MAX - } - }); - - next_expiration - } - - fn retain(&self, mut f: impl FnMut(TaskRef) -> bool) { - unsafe { - let mut prev = &self.head; - while let Some(p) = prev.get() { - let item = p.timer_queue_item(); - if f(p) { - // Skip to next - prev = &item.next; - } else { - // Remove it - prev.set(item.next.get()); - item.next.set(None); - } - } + next: Cell::new(None), + expires_at: Cell::new(0), } } } diff --git a/embassy-executor/src/raw/util.rs b/embassy-executor/src/raw/util.rs index e2633658a..c46085e45 100644 --- a/embassy-executor/src/raw/util.rs +++ b/embassy-executor/src/raw/util.rs @@ -54,9 +54,4 @@ impl SyncUnsafeCell { { *self.value.get() } - - #[cfg(feature = "integrated-timers")] - pub unsafe fn replace(&self, value: T) -> T { - core::mem::replace(&mut *self.value.get(), value) - } } diff --git a/embassy-time-queue-driver/src/lib.rs b/embassy-time-queue-driver/src/lib.rs index c5e989854..0c78921ed 100644 --- a/embassy-time-queue-driver/src/lib.rs +++ b/embassy-time-queue-driver/src/lib.rs @@ -22,9 +22,9 @@ //! ); //! ``` //! -//! You can also use the `queue_generic` or the `embassy_executor::raw::timer_queue` modules to -//! implement your own timer queue. These modules contain queue implementations which you can wrap -//! and tailor to your needs. +//! You can also use the `queue_generic` or the `queue_integrated` modules to implement your own +//! timer queue. These modules contain queue implementations which you can wrap and tailor to +//! your needs. //! //! If you are providing an embassy-executor implementation besides a timer queue, you can choose to //! expose the `integrated-timers` feature in your implementation. This feature stores timer items @@ -49,7 +49,10 @@ //! embassy_time_queue_driver::timer_queue_impl!(static QUEUE: MyTimerQueue = MyTimerQueue{}); //! ``` +#[cfg(not(feature = "integrated-timers"))] pub mod queue_generic; +#[cfg(feature = "integrated-timers")] +pub mod queue_integrated; use core::cell::RefCell; use core::task::Waker; @@ -89,7 +92,7 @@ macro_rules! timer_queue_impl { } #[cfg(feature = "integrated-timers")] -type InnerQueue = embassy_executor::raw::timer_queue::TimerQueue; +type InnerQueue = queue_integrated::TimerQueue; #[cfg(not(feature = "integrated-timers"))] type InnerQueue = queue_generic::Queue; diff --git a/embassy-time-queue-driver/src/queue_integrated.rs b/embassy-time-queue-driver/src/queue_integrated.rs new file mode 100644 index 000000000..cb0f79356 --- /dev/null +++ b/embassy-time-queue-driver/src/queue_integrated.rs @@ -0,0 +1,78 @@ +//! Timer queue operations. +use core::cell::Cell; +use core::cmp::min; + +use embassy_executor::raw::TaskRef; + +/// A timer queue, with items integrated into tasks. +pub struct TimerQueue { + head: Cell>, +} + +impl TimerQueue { + /// Creates a new timer queue. + pub const fn new() -> Self { + Self { head: Cell::new(None) } + } + + /// Schedules a task to run at a specific time. + /// + /// If this function returns `true`, the called should find the next expiration time and set + /// a new alarm for that time. + pub fn schedule_wake(&mut self, at: u64, p: TaskRef) -> bool { + let item = p.timer_queue_item(); + if item.next.get().is_none() { + // If not in the queue, add it and update. + let prev = self.head.replace(Some(p)); + item.next.set(prev); + } else if at <= item.expires_at.get() { + // If expiration is sooner than previously set, update. + } else { + // Task does not need to be updated. + return false; + } + + item.expires_at.set(at); + true + } + + /// Dequeues expired timers and returns the next alarm time. + /// + /// The provided callback will be called for each expired task. Tasks that never expire + /// will be removed, but the callback will not be called. + pub fn next_expiration(&mut self, now: u64) -> u64 { + let mut next_expiration = u64::MAX; + + self.retain(|p| { + let item = p.timer_queue_item(); + let expires = item.expires_at.get(); + + if expires <= now { + // Timer expired, process task. + embassy_executor::raw::wake_task(p); + false + } else { + // Timer didn't yet expire, or never expires. + next_expiration = min(next_expiration, expires); + expires != u64::MAX + } + }); + + next_expiration + } + + fn retain(&self, mut f: impl FnMut(TaskRef) -> bool) { + let mut prev = &self.head; + while let Some(p) = prev.get() { + let item = p.timer_queue_item(); + if f(p) { + // Skip to next + prev = &item.next; + } else { + // Remove it + prev.set(item.next.get()); + item.next.set(None); + } + } + } +} From df5a399125aea0014a1629d01ef1559b5ae04af9 Mon Sep 17 00:00:00 2001 From: Alessandro Gasbarroni Date: Tue, 10 Dec 2024 10:40:24 +0100 Subject: [PATCH 0466/1217] nrf: Add RESET operations helpers for the nrf5340 --- embassy-nrf/src/lib.rs | 3 ++ embassy-nrf/src/reset.rs | 82 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+) create mode 100644 embassy-nrf/src/reset.rs diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index 7c5dd7c83..e7ec4eb9d 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs @@ -126,6 +126,9 @@ pub mod qspi; #[cfg(not(any(feature = "_nrf91", feature = "_nrf5340-app")))] pub mod radio; #[cfg(not(feature = "_nrf54l"))] // TODO +#[cfg(feature = "_nrf5340")] +pub mod reset; +#[cfg(not(feature = "_nrf54l"))] // TODO #[cfg(not(any(feature = "_nrf5340-app", feature = "_nrf91")))] pub mod rng; #[cfg(not(feature = "_nrf54l"))] // TODO diff --git a/embassy-nrf/src/reset.rs b/embassy-nrf/src/reset.rs new file mode 100644 index 000000000..a33d8f31f --- /dev/null +++ b/embassy-nrf/src/reset.rs @@ -0,0 +1,82 @@ +//! Reset + +#![macro_use] + +use bitflags::bitflags; +use nrf_pac::reset::regs::Resetreas; +#[cfg(not(feature = "_nrf5340-net"))] +use nrf_pac::reset::vals::Forceoff; + +use crate::chip::pac::RESET; + +bitflags! { + #[derive(Debug, Copy, Clone, PartialEq)] + /// Bitflag representation of the `RESETREAS` register + pub struct ResetReason: u32 { + /// Reset Pin + const RESETPIN = 1; + /// Application watchdog timer 0 + const DOG0 = 1 << 1; + /// Application CTRL-AP + const CTRLAP = 1 << 2; + /// Application soft reset + const SREQ = 1 << 3; + /// Application CPU lockup + const LOCKUP = 1 << 4; + /// Wakeup from System OFF when wakeup is triggered by DETECT signal from GPIO + const OFF = 1 << 5; + /// Wakeup from System OFF when wakeup is triggered by ANADETECT signal from LPCOMP + const LPCOMP = 1 << 6; + /// Wakeup from System OFF when wakeup is triggered by entering the Debug Interface mode + const DIF = 1 << 7; + /// Network soft reset + #[cfg(feature = "_nrf5340-net")] + const LSREQ = 1 << 16; + /// Network CPU lockup + #[cfg(feature = "_nrf5340-net")] + const LLOCKUP = 1 << 17; + /// Network watchdog timer + #[cfg(feature = "_nrf5340-net")] + const LDOG = 1 << 18; + /// Force-OFF reset from application core + #[cfg(feature = "_nrf5340-net")] + const MFORCEOFF = 1 << 23; + /// Wakeup from System OFF mode due to NFC field being detected + const NFC = 1 << 24; + /// Application watchdog timer 1 + const DOG1 = 1 << 25; + /// Wakeup from System OFF mode due to VBUS rising into valid range + const VBUS = 1 << 26; + /// Network CTRL-AP + #[cfg(feature = "_nrf5340-net")] + const LCTRLAP = 1 << 27; + } +} + +/// Reads the bitflag of the reset reasons +pub fn read_reasons() -> ResetReason { + ResetReason::from_bits_retain(RESET.resetreas().read().0) +} + +/// Resets the reset reasons +pub fn clear_reasons() { + RESET.resetreas().write(|w| *w = Resetreas(ResetReason::all().bits())); +} + +/// Returns if the network core is held in reset +#[cfg(not(feature = "_nrf5340-net"))] +pub fn network_core_held() -> bool { + RESET.network().forceoff().read().forceoff() == Forceoff::HOLD +} + +/// Releases the network core from the FORCEOFF state +#[cfg(not(feature = "_nrf5340-net"))] +pub fn release_network_core() { + RESET.network().forceoff().write(|w| w.set_forceoff(Forceoff::RELEASE)); +} + +/// Holds the network core in the FORCEOFF state +#[cfg(not(feature = "_nrf5340-net"))] +pub fn hold_network_core() { + RESET.network().forceoff().write(|w| w.set_forceoff(Forceoff::HOLD)); +} From 415db448c7c476f8c2d81e157437657868d10158 Mon Sep 17 00:00:00 2001 From: Alexander Walter Date: Fri, 13 Dec 2024 19:38:30 +0100 Subject: [PATCH 0467/1217] Added system off and wake-on-field --- embassy-nrf/src/lib.rs | 3 +++ embassy-nrf/src/power.rs | 13 +++++++++++++ 2 files changed, 16 insertions(+) create mode 100644 embassy-nrf/src/power.rs diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index e7ec4eb9d..b6283c7f5 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs @@ -107,6 +107,9 @@ pub mod nvmc; ))] pub mod pdm; #[cfg(not(feature = "_nrf54l"))] // TODO +#[cfg(feature = "nrf52840")] +pub mod power; +#[cfg(not(feature = "_nrf54l"))] // TODO pub mod ppi; #[cfg(not(feature = "_nrf54l"))] // TODO #[cfg(not(any( diff --git a/embassy-nrf/src/power.rs b/embassy-nrf/src/power.rs new file mode 100644 index 000000000..440028380 --- /dev/null +++ b/embassy-nrf/src/power.rs @@ -0,0 +1,13 @@ +//! Power + +use crate::chip::pac::{NFCT, POWER}; + +/// Puts the MCU into "System Off" mode with a power usage 0f 0.4 uA +pub fn set_system_off() { + POWER.systemoff().write(|w| w.set_systemoff(true)); +} + +/// Wake the system if there if an NFC field close to the nrf52840's antenna +pub fn wake_on_nfc_sense() { + NFCT.tasks_sense().write_value(0x01); +} From ec96395d084d5edc8be25ddaea8547e2ebd447a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Mon, 9 Dec 2024 08:43:57 +0100 Subject: [PATCH 0468/1217] Prevent task from respawning while in the timer queue --- embassy-executor/src/raw/mod.rs | 36 ++++++++++++++++- embassy-executor/src/raw/state_atomics.rs | 36 +++++++++++++++++ embassy-executor/src/raw/state_atomics_arm.rs | 40 ++++++++++++++++++- .../src/raw/state_critical_section.rs | 29 ++++++++++++++ embassy-executor/src/raw/timer_queue.rs | 15 ++++++- embassy-time-queue-driver/src/lib.rs | 14 +++++++ .../src/queue_integrated.rs | 20 +++++++--- 7 files changed, 181 insertions(+), 9 deletions(-) diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs index f9c6509f1..14d689900 100644 --- a/embassy-executor/src/raw/mod.rs +++ b/embassy-executor/src/raw/mod.rs @@ -50,7 +50,7 @@ pub(crate) struct TaskHeader { } /// This is essentially a `&'static TaskStorage` where the type of the future has been erased. -#[derive(Clone, Copy)] +#[derive(Clone, Copy, PartialEq)] pub struct TaskRef { ptr: NonNull, } @@ -72,6 +72,16 @@ impl TaskRef { } } + /// # Safety + /// + /// The result of this function must only be compared + /// for equality, or stored, but not used. + pub const unsafe fn dangling() -> Self { + Self { + ptr: NonNull::dangling(), + } + } + pub(crate) fn header(self) -> &'static TaskHeader { unsafe { self.ptr.as_ref() } } @@ -88,6 +98,30 @@ impl TaskRef { &self.header().timer_queue_item } + /// Mark the task as timer-queued. Return whether it was newly queued (i.e. not queued before) + /// + /// Entering this state prevents the task from being respawned while in a timer queue. + /// + /// Safety: + /// + /// This functions should only be called by the timer queue implementation, before + /// enqueueing the timer item. + #[cfg(feature = "integrated-timers")] + pub unsafe fn timer_enqueue(&self) -> timer_queue::TimerEnqueueOperation { + self.header().state.timer_enqueue() + } + + /// Unmark the task as timer-queued. + /// + /// Safety: + /// + /// This functions should only be called by the timer queue implementation, after the task has + /// been removed from the timer queue. + #[cfg(feature = "integrated-timers")] + pub unsafe fn timer_dequeue(&self) { + self.header().state.timer_dequeue() + } + /// The returned pointer is valid for the entire TaskStorage. pub(crate) fn as_ptr(self) -> *const TaskHeader { self.ptr.as_ptr() diff --git a/embassy-executor/src/raw/state_atomics.rs b/embassy-executor/src/raw/state_atomics.rs index e4127897e..d03c61ade 100644 --- a/embassy-executor/src/raw/state_atomics.rs +++ b/embassy-executor/src/raw/state_atomics.rs @@ -1,9 +1,15 @@ use core::sync::atomic::{AtomicU32, Ordering}; +#[cfg(feature = "integrated-timers")] +use super::timer_queue::TimerEnqueueOperation; + /// Task is spawned (has a future) pub(crate) const STATE_SPAWNED: u32 = 1 << 0; /// Task is in the executor run queue pub(crate) const STATE_RUN_QUEUED: u32 = 1 << 1; +/// Task is in the executor timer queue +#[cfg(feature = "integrated-timers")] +pub(crate) const STATE_TIMER_QUEUED: u32 = 1 << 2; pub(crate) struct State { state: AtomicU32, @@ -52,4 +58,34 @@ impl State { let state = self.state.fetch_and(!STATE_RUN_QUEUED, Ordering::AcqRel); state & STATE_SPAWNED != 0 } + + /// Mark the task as timer-queued. Return whether it can be enqueued. + #[cfg(feature = "integrated-timers")] + #[inline(always)] + pub fn timer_enqueue(&self) -> TimerEnqueueOperation { + if self + .state + .fetch_update(Ordering::SeqCst, Ordering::SeqCst, |state| { + // If not started, ignore it + if state & STATE_SPAWNED == 0 { + None + } else { + // Mark it as enqueued + Some(state | STATE_TIMER_QUEUED) + } + }) + .is_ok() + { + TimerEnqueueOperation::Enqueue + } else { + TimerEnqueueOperation::Ignore + } + } + + /// Unmark the task as timer-queued. + #[cfg(feature = "integrated-timers")] + #[inline(always)] + pub fn timer_dequeue(&self) { + self.state.fetch_and(!STATE_TIMER_QUEUED, Ordering::Relaxed); + } } diff --git a/embassy-executor/src/raw/state_atomics_arm.rs b/embassy-executor/src/raw/state_atomics_arm.rs index b673c7359..f6f2e8f08 100644 --- a/embassy-executor/src/raw/state_atomics_arm.rs +++ b/embassy-executor/src/raw/state_atomics_arm.rs @@ -1,9 +1,14 @@ use core::arch::asm; use core::sync::atomic::{compiler_fence, AtomicBool, AtomicU32, Ordering}; +#[cfg(feature = "integrated-timers")] +use super::timer_queue::TimerEnqueueOperation; + // Must be kept in sync with the layout of `State`! pub(crate) const STATE_SPAWNED: u32 = 1 << 0; pub(crate) const STATE_RUN_QUEUED: u32 = 1 << 8; +#[cfg(feature = "integrated-timers")] +pub(crate) const STATE_TIMER_QUEUED: u32 = 1 << 16; #[repr(C, align(4))] pub(crate) struct State { @@ -11,8 +16,9 @@ pub(crate) struct State { spawned: AtomicBool, /// Task is in the executor run queue run_queued: AtomicBool, + /// Task is in the executor timer queue + timer_queued: AtomicBool, pad: AtomicBool, - pad2: AtomicBool, } impl State { @@ -20,8 +26,8 @@ impl State { Self { spawned: AtomicBool::new(false), run_queued: AtomicBool::new(false), + timer_queued: AtomicBool::new(false), pad: AtomicBool::new(false), - pad2: AtomicBool::new(false), } } @@ -85,4 +91,34 @@ impl State { self.run_queued.store(false, Ordering::Relaxed); r } + + /// Mark the task as timer-queued. Return whether it can be enqueued. + #[cfg(feature = "integrated-timers")] + #[inline(always)] + pub fn timer_enqueue(&self) -> TimerEnqueueOperation { + if self + .as_u32() + .fetch_update(Ordering::SeqCst, Ordering::SeqCst, |state| { + // If not started, ignore it + if state & STATE_SPAWNED == 0 { + None + } else { + // Mark it as enqueued + Some(state | STATE_TIMER_QUEUED) + } + }) + .is_ok() + { + TimerEnqueueOperation::Enqueue + } else { + TimerEnqueueOperation::Ignore + } + } + + /// Unmark the task as timer-queued. + #[cfg(feature = "integrated-timers")] + #[inline(always)] + pub fn timer_dequeue(&self) { + self.timer_queued.store(false, Ordering::Relaxed); + } } diff --git a/embassy-executor/src/raw/state_critical_section.rs b/embassy-executor/src/raw/state_critical_section.rs index b92eed006..c0ec2f530 100644 --- a/embassy-executor/src/raw/state_critical_section.rs +++ b/embassy-executor/src/raw/state_critical_section.rs @@ -2,10 +2,16 @@ use core::cell::Cell; use critical_section::Mutex; +#[cfg(feature = "integrated-timers")] +use super::timer_queue::TimerEnqueueOperation; + /// Task is spawned (has a future) pub(crate) const STATE_SPAWNED: u32 = 1 << 0; /// Task is in the executor run queue pub(crate) const STATE_RUN_QUEUED: u32 = 1 << 1; +/// Task is in the executor timer queue +#[cfg(feature = "integrated-timers")] +pub(crate) const STATE_TIMER_QUEUED: u32 = 1 << 2; pub(crate) struct State { state: Mutex>, @@ -69,4 +75,27 @@ impl State { ok }) } + + /// Mark the task as timer-queued. Return whether it can be enqueued. + #[cfg(feature = "integrated-timers")] + #[inline(always)] + pub fn timer_enqueue(&self) -> TimerEnqueueOperation { + self.update(|s| { + // FIXME: we need to split SPAWNED into two phases, to prevent enqueueing a task that is + // just being spawned, because its executor pointer may still be changing. + if *s & STATE_SPAWNED == STATE_SPAWNED { + *s |= STATE_TIMER_QUEUED; + TimerEnqueueOperation::Enqueue + } else { + TimerEnqueueOperation::Ignore + } + }) + } + + /// Unmark the task as timer-queued. + #[cfg(feature = "integrated-timers")] + #[inline(always)] + pub fn timer_dequeue(&self) { + self.update(|s| *s &= !STATE_TIMER_QUEUED); + } } diff --git a/embassy-executor/src/raw/timer_queue.rs b/embassy-executor/src/raw/timer_queue.rs index 46e346c1b..c36708401 100644 --- a/embassy-executor/src/raw/timer_queue.rs +++ b/embassy-executor/src/raw/timer_queue.rs @@ -7,6 +7,9 @@ use super::TaskRef; /// An item in the timer queue. pub struct TimerQueueItem { /// The next item in the queue. + /// + /// If this field contains `Some`, the item is in the queue. The last item in the queue has a + /// value of `Some(dangling_pointer)` pub next: Cell>, /// The time at which this item expires. @@ -19,7 +22,17 @@ impl TimerQueueItem { pub(crate) const fn new() -> Self { Self { next: Cell::new(None), - expires_at: Cell::new(0), + expires_at: Cell::new(u64::MAX), } } } + +/// The operation to perform after `timer_enqueue` is called. +#[derive(Debug, Copy, Clone, PartialEq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum TimerEnqueueOperation { + /// Enqueue the task. + Enqueue, + /// Update the task's expiration time. + Ignore, +} diff --git a/embassy-time-queue-driver/src/lib.rs b/embassy-time-queue-driver/src/lib.rs index 0c78921ed..2d5fd449a 100644 --- a/embassy-time-queue-driver/src/lib.rs +++ b/embassy-time-queue-driver/src/lib.rs @@ -73,6 +73,20 @@ extern "Rust" { /// Schedule the given waker to be woken at `at`. pub fn schedule_wake(at: u64, waker: &Waker) { + #[cfg(feature = "integrated-timers")] + { + use embassy_executor::raw::task_from_waker; + use embassy_executor::raw::timer_queue::TimerEnqueueOperation; + // The very first thing we must do, before we even access the timer queue, is to + // mark the task a TIMER_QUEUED. This ensures that the task that is being scheduled + // can not be respawn while we are accessing the timer queue. + let task = task_from_waker(waker); + if unsafe { task.timer_enqueue() } == TimerEnqueueOperation::Ignore { + // We are not allowed to enqueue the task in the timer queue. This is because the + // task is not spawned, and so it makes no sense to schedule it. + return; + } + } unsafe { _embassy_time_schedule_wake(at, waker) } } diff --git a/embassy-time-queue-driver/src/queue_integrated.rs b/embassy-time-queue-driver/src/queue_integrated.rs index cb0f79356..b905c00c3 100644 --- a/embassy-time-queue-driver/src/queue_integrated.rs +++ b/embassy-time-queue-driver/src/queue_integrated.rs @@ -24,16 +24,21 @@ impl TimerQueue { if item.next.get().is_none() { // If not in the queue, add it and update. let prev = self.head.replace(Some(p)); - item.next.set(prev); + item.next.set(if prev.is_none() { + Some(unsafe { TaskRef::dangling() }) + } else { + prev + }); + item.expires_at.set(at); + true } else if at <= item.expires_at.get() { // If expiration is sooner than previously set, update. + item.expires_at.set(at); + true } else { // Task does not need to be updated. - return false; + false } - - item.expires_at.set(at); - true } /// Dequeues expired timers and returns the next alarm time. @@ -64,6 +69,10 @@ impl TimerQueue { fn retain(&self, mut f: impl FnMut(TaskRef) -> bool) { let mut prev = &self.head; while let Some(p) = prev.get() { + if unsafe { p == TaskRef::dangling() } { + // prev was the last item, stop + break; + } let item = p.timer_queue_item(); if f(p) { // Skip to next @@ -72,6 +81,7 @@ impl TimerQueue { // Remove it prev.set(item.next.get()); item.next.set(None); + unsafe { p.timer_dequeue() }; } } } From b268b1795fed58544c166c41842ce0d66328aa3e Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sun, 8 Dec 2024 23:27:32 +0100 Subject: [PATCH 0469/1217] Merge time-driver and time-queue-driver traits, make HALs own and handle the queue. --- .github/ci/test.sh | 2 +- embassy-nrf/src/time_driver.rs | 109 ++++++------ embassy-rp/src/time_driver.rs | 72 ++++---- embassy-stm32/src/time_driver.rs | 104 ++++++----- embassy-time-driver/src/lib.rs | 17 ++ embassy-time-queue-driver/src/lib.rs | 140 ++------------- .../src/queue_integrated.rs | 12 +- embassy-time/Cargo.toml | 1 - embassy-time/src/driver_mock.rs | 113 ++++-------- embassy-time/src/driver_std.rs | 163 ++++++------------ embassy-time/src/driver_wasm.rs | 112 ++++++------ 11 files changed, 328 insertions(+), 517 deletions(-) diff --git a/.github/ci/test.sh b/.github/ci/test.sh index 285f3f29e..0fd6820d2 100755 --- a/.github/ci/test.sh +++ b/.github/ci/test.sh @@ -17,7 +17,7 @@ cargo test --manifest-path ./embassy-futures/Cargo.toml cargo test --manifest-path ./embassy-sync/Cargo.toml cargo test --manifest-path ./embassy-embedded-hal/Cargo.toml cargo test --manifest-path ./embassy-hal-internal/Cargo.toml -cargo test --manifest-path ./embassy-time/Cargo.toml --features mock-driver +cargo test --manifest-path ./embassy-time/Cargo.toml --features mock-driver,embassy-time-queue-driver/generic-queue-8 cargo test --manifest-path ./embassy-time-driver/Cargo.toml cargo test --manifest-path ./embassy-boot/Cargo.toml diff --git a/embassy-nrf/src/time_driver.rs b/embassy-nrf/src/time_driver.rs index f8b3c4bbc..a27fae9a8 100644 --- a/embassy-nrf/src/time_driver.rs +++ b/embassy-nrf/src/time_driver.rs @@ -1,11 +1,11 @@ -use core::cell::Cell; +use core::cell::{Cell, RefCell}; use core::sync::atomic::{compiler_fence, AtomicU32, Ordering}; use critical_section::CriticalSection; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::blocking_mutex::CriticalSectionMutex as Mutex; use embassy_time_driver::Driver; -use embassy_time_queue_driver::GlobalTimerQueue; +use embassy_time_queue_driver::Queue; use crate::interrupt::InterruptExt; use crate::{interrupt, pac}; @@ -111,11 +111,13 @@ struct RtcDriver { period: AtomicU32, /// Timestamp at which to fire alarm. u64::MAX if no alarm is scheduled. alarms: Mutex, + queue: Mutex>, } embassy_time_driver::time_driver_impl!(static DRIVER: RtcDriver = RtcDriver { period: AtomicU32::new(0), alarms: Mutex::const_new(CriticalSectionRawMutex::new(), AlarmState::new()), + queue: Mutex::new(RefCell::new(Queue::new())), }); impl RtcDriver { @@ -194,59 +196,60 @@ impl RtcDriver { alarm.timestamp.set(u64::MAX); // Call after clearing alarm, so the callback can set another alarm. - TIMER_QUEUE_DRIVER.dispatch(); + let mut next = self.queue.borrow(cs).borrow_mut().next_expiration(self.now()); + while !self.set_alarm(cs, next) { + next = self.queue.borrow(cs).borrow_mut().next_expiration(self.now()); + } } - fn set_alarm(&self, timestamp: u64) -> bool { - critical_section::with(|cs| { - let n = 0; - let alarm = &self.alarms.borrow(cs); - alarm.timestamp.set(timestamp); + fn set_alarm(&self, cs: CriticalSection, timestamp: u64) -> bool { + let n = 0; + let alarm = &self.alarms.borrow(cs); + alarm.timestamp.set(timestamp); - let r = rtc(); + let r = rtc(); - let t = self.now(); - if timestamp <= t { - // If alarm timestamp has passed the alarm will not fire. - // Disarm the alarm and return `false` to indicate that. - r.intenclr().write(|w| w.0 = compare_n(n)); + let t = self.now(); + if timestamp <= t { + // If alarm timestamp has passed the alarm will not fire. + // Disarm the alarm and return `false` to indicate that. + r.intenclr().write(|w| w.0 = compare_n(n)); - alarm.timestamp.set(u64::MAX); + alarm.timestamp.set(u64::MAX); - return false; - } + return false; + } - // If it hasn't triggered yet, setup it in the compare channel. + // If it hasn't triggered yet, setup it in the compare channel. - // Write the CC value regardless of whether we're going to enable it now or not. - // This way, when we enable it later, the right value is already set. + // Write the CC value regardless of whether we're going to enable it now or not. + // This way, when we enable it later, the right value is already set. - // nrf52 docs say: - // If the COUNTER is N, writing N or N+1 to a CC register may not trigger a COMPARE event. - // To workaround this, we never write a timestamp smaller than N+3. - // N+2 is not safe because rtc can tick from N to N+1 between calling now() and writing cc. - // - // It is impossible for rtc to tick more than once because - // - this code takes less time than 1 tick - // - it runs with interrupts disabled so nothing else can preempt it. - // - // This means that an alarm can be delayed for up to 2 ticks (from t+1 to t+3), but this is allowed - // by the Alarm trait contract. What's not allowed is triggering alarms *before* their scheduled time, - // and we don't do that here. - let safe_timestamp = timestamp.max(t + 3); - r.cc(n).write(|w| w.set_compare(safe_timestamp as u32 & 0xFFFFFF)); + // nrf52 docs say: + // If the COUNTER is N, writing N or N+1 to a CC register may not trigger a COMPARE event. + // To workaround this, we never write a timestamp smaller than N+3. + // N+2 is not safe because rtc can tick from N to N+1 between calling now() and writing cc. + // + // It is impossible for rtc to tick more than once because + // - this code takes less time than 1 tick + // - it runs with interrupts disabled so nothing else can preempt it. + // + // This means that an alarm can be delayed for up to 2 ticks (from t+1 to t+3), but this is allowed + // by the Alarm trait contract. What's not allowed is triggering alarms *before* their scheduled time, + // and we don't do that here. + let safe_timestamp = timestamp.max(t + 3); + r.cc(n).write(|w| w.set_compare(safe_timestamp as u32 & 0xFFFFFF)); - let diff = timestamp - t; - if diff < 0xc00000 { - r.intenset().write(|w| w.0 = compare_n(n)); - } else { - // If it's too far in the future, don't setup the compare channel yet. - // It will be setup later by `next_period`. - r.intenclr().write(|w| w.0 = compare_n(n)); - } + let diff = timestamp - t; + if diff < 0xc00000 { + r.intenset().write(|w| w.0 = compare_n(n)); + } else { + // If it's too far in the future, don't setup the compare channel yet. + // It will be setup later by `next_period`. + r.intenclr().write(|w| w.0 = compare_n(n)); + } - true - }) + true } } @@ -258,6 +261,19 @@ impl Driver for RtcDriver { let counter = rtc().counter().read().0; calc_now(period, counter) } + + fn schedule_wake(&self, at: u64, waker: &core::task::Waker) { + critical_section::with(|cs| { + let mut queue = self.queue.borrow(cs).borrow_mut(); + + if queue.schedule_wake(at, waker) { + let mut next = queue.next_expiration(self.now()); + while !self.set_alarm(cs, next) { + next = queue.next_expiration(self.now()); + } + } + }) + } } #[cfg(feature = "_nrf54l")] @@ -277,8 +293,3 @@ fn RTC1() { pub(crate) fn init(irq_prio: crate::interrupt::Priority) { DRIVER.init(irq_prio) } - -embassy_time_queue_driver::timer_queue_impl!( - static TIMER_QUEUE_DRIVER: GlobalTimerQueue - = GlobalTimerQueue::new(|next_expiration| DRIVER.set_alarm(next_expiration)) -); diff --git a/embassy-rp/src/time_driver.rs b/embassy-rp/src/time_driver.rs index 17ae5fff3..a0eaec10e 100644 --- a/embassy-rp/src/time_driver.rs +++ b/embassy-rp/src/time_driver.rs @@ -1,10 +1,11 @@ //! Timer driver. -use core::cell::Cell; +use core::cell::{Cell, RefCell}; +use critical_section::CriticalSection; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::blocking_mutex::Mutex; use embassy_time_driver::Driver; -use embassy_time_queue_driver::GlobalTimerQueue; +use embassy_time_queue_driver::Queue; #[cfg(feature = "rp2040")] use pac::TIMER; #[cfg(feature = "_rp235x")] @@ -20,12 +21,14 @@ unsafe impl Send for AlarmState {} struct TimerDriver { alarms: Mutex, + queue: Mutex>, } embassy_time_driver::time_driver_impl!(static DRIVER: TimerDriver = TimerDriver{ alarms: Mutex::const_new(CriticalSectionRawMutex::new(), AlarmState { timestamp: Cell::new(0), }), + queue: Mutex::new(RefCell::new(Queue::new())) }); impl Driver for TimerDriver { @@ -39,34 +42,45 @@ impl Driver for TimerDriver { } } } + + fn schedule_wake(&self, at: u64, waker: &core::task::Waker) { + critical_section::with(|cs| { + let mut queue = self.queue.borrow(cs).borrow_mut(); + + if queue.schedule_wake(at, waker) { + let mut next = queue.next_expiration(self.now()); + while !self.set_alarm(cs, next) { + next = queue.next_expiration(self.now()); + } + } + }) + } } impl TimerDriver { - fn set_alarm(&self, timestamp: u64) -> bool { + fn set_alarm(&self, cs: CriticalSection, timestamp: u64) -> bool { let n = 0; - critical_section::with(|cs| { - let alarm = &self.alarms.borrow(cs); - alarm.timestamp.set(timestamp); + let alarm = &self.alarms.borrow(cs); + alarm.timestamp.set(timestamp); - // Arm it. - // Note that we're not checking the high bits at all. This means the irq may fire early - // if the alarm is more than 72 minutes (2^32 us) in the future. This is OK, since on irq fire - // it is checked if the alarm time has passed. - TIMER.alarm(n).write_value(timestamp as u32); + // Arm it. + // Note that we're not checking the high bits at all. This means the irq may fire early + // if the alarm is more than 72 minutes (2^32 us) in the future. This is OK, since on irq fire + // it is checked if the alarm time has passed. + TIMER.alarm(n).write_value(timestamp as u32); - let now = self.now(); - if timestamp <= now { - // If alarm timestamp has passed the alarm will not fire. - // Disarm the alarm and return `false` to indicate that. - TIMER.armed().write(|w| w.set_armed(1 << n)); + let now = self.now(); + if timestamp <= now { + // If alarm timestamp has passed the alarm will not fire. + // Disarm the alarm and return `false` to indicate that. + TIMER.armed().write(|w| w.set_armed(1 << n)); - alarm.timestamp.set(u64::MAX); + alarm.timestamp.set(u64::MAX); - false - } else { - true - } - }) + false + } else { + true + } } fn check_alarm(&self) { @@ -75,7 +89,7 @@ impl TimerDriver { let alarm = &self.alarms.borrow(cs); let timestamp = alarm.timestamp.get(); if timestamp <= self.now() { - self.trigger_alarm() + self.trigger_alarm(cs) } else { // Not elapsed, arm it again. // This can happen if it was set more than 2^32 us in the future. @@ -87,8 +101,11 @@ impl TimerDriver { TIMER.intr().write(|w| w.set_alarm(n, true)); } - fn trigger_alarm(&self) { - TIMER_QUEUE_DRIVER.dispatch(); + fn trigger_alarm(&self, cs: CriticalSection) { + let mut next = self.queue.borrow(cs).borrow_mut().next_expiration(self.now()); + while !self.set_alarm(cs, next) { + next = self.queue.borrow(cs).borrow_mut().next_expiration(self.now()); + } } } @@ -125,8 +142,3 @@ fn TIMER_IRQ_0() { fn TIMER0_IRQ_0() { DRIVER.check_alarm() } - -embassy_time_queue_driver::timer_queue_impl!( - static TIMER_QUEUE_DRIVER: GlobalTimerQueue - = GlobalTimerQueue::new(|next_expiration| DRIVER.set_alarm(next_expiration)) -); diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs index 290f857ad..a4c333d82 100644 --- a/embassy-stm32/src/time_driver.rs +++ b/embassy-stm32/src/time_driver.rs @@ -1,13 +1,13 @@ #![allow(non_snake_case)] -use core::cell::Cell; +use core::cell::{Cell, RefCell}; use core::sync::atomic::{compiler_fence, AtomicU32, Ordering}; use critical_section::CriticalSection; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::blocking_mutex::Mutex; use embassy_time_driver::{Driver, TICK_HZ}; -use embassy_time_queue_driver::GlobalTimerQueue; +use embassy_time_queue_driver::Queue; use stm32_metapac::timer::{regs, TimGp16}; use crate::interrupt::typelevel::Interrupt; @@ -214,6 +214,7 @@ pub(crate) struct RtcDriver { alarm: Mutex, #[cfg(feature = "low-power")] rtc: Mutex>>, + queue: Mutex>, } embassy_time_driver::time_driver_impl!(static DRIVER: RtcDriver = RtcDriver { @@ -221,6 +222,7 @@ embassy_time_driver::time_driver_impl!(static DRIVER: RtcDriver = RtcDriver { alarm: Mutex::const_new(CriticalSectionRawMutex::new(), AlarmState::new()), #[cfg(feature = "low-power")] rtc: Mutex::const_new(CriticalSectionRawMutex::new(), Cell::new(None)), + queue: Mutex::new(RefCell::new(Queue::new())) }); impl RtcDriver { @@ -266,8 +268,7 @@ impl RtcDriver { fn on_interrupt(&self) { let r = regs_gp16(); - // XXX: reduce the size of this critical section ? - critical_section::with(|_cs| { + critical_section::with(|cs| { let sr = r.sr().read(); let dier = r.dier().read(); @@ -288,7 +289,7 @@ impl RtcDriver { let n = 0; if sr.ccif(n + 1) && dier.ccie(n + 1) { - self.trigger_alarm(); + self.trigger_alarm(cs); } }) } @@ -315,8 +316,11 @@ impl RtcDriver { }) } - fn trigger_alarm(&self) { - TIMER_QUEUE_DRIVER.dispatch(); + fn trigger_alarm(&self, cs: CriticalSection) { + let mut next = self.queue.borrow(cs).borrow_mut().next_expiration(self.now()); + while !self.set_alarm(cs, next) { + next = self.queue.borrow(cs).borrow_mut().next_expiration(self.now()); + } } /* @@ -366,9 +370,9 @@ impl RtcDriver { // Now, recompute alarm let alarm = self.alarm.borrow(cs); - if !self.set_alarm(alarm.timestamp.get()) { + if !self.set_alarm(cs, alarm.timestamp.get()) { // If the alarm timestamp has passed, we need to trigger it - self.trigger_alarm(); + self.trigger_alarm(cs); } } @@ -441,49 +445,47 @@ impl RtcDriver { }) } - fn set_alarm(&self, timestamp: u64) -> bool { - critical_section::with(|cs| { - let r = regs_gp16(); + fn set_alarm(&self, cs: CriticalSection, timestamp: u64) -> bool { + let r = regs_gp16(); - let n = 0; - self.alarm.borrow(cs).timestamp.set(timestamp); + let n = 0; + self.alarm.borrow(cs).timestamp.set(timestamp); - let t = self.now(); - if timestamp <= t { - // If alarm timestamp has passed the alarm will not fire. - // Disarm the alarm and return `false` to indicate that. - r.dier().modify(|w| w.set_ccie(n + 1, false)); + let t = self.now(); + if timestamp <= t { + // If alarm timestamp has passed the alarm will not fire. + // Disarm the alarm and return `false` to indicate that. + r.dier().modify(|w| w.set_ccie(n + 1, false)); - self.alarm.borrow(cs).timestamp.set(u64::MAX); + self.alarm.borrow(cs).timestamp.set(u64::MAX); - return false; - } + return false; + } - // Write the CCR value regardless of whether we're going to enable it now or not. - // This way, when we enable it later, the right value is already set. - r.ccr(n + 1).write(|w| w.set_ccr(timestamp as u16)); + // Write the CCR value regardless of whether we're going to enable it now or not. + // This way, when we enable it later, the right value is already set. + r.ccr(n + 1).write(|w| w.set_ccr(timestamp as u16)); - // Enable it if it'll happen soon. Otherwise, `next_period` will enable it. - let diff = timestamp - t; - r.dier().modify(|w| w.set_ccie(n + 1, diff < 0xc000)); + // Enable it if it'll happen soon. Otherwise, `next_period` will enable it. + let diff = timestamp - t; + r.dier().modify(|w| w.set_ccie(n + 1, diff < 0xc000)); - // Reevaluate if the alarm timestamp is still in the future - let t = self.now(); - if timestamp <= t { - // If alarm timestamp has passed since we set it, we have a race condition and - // the alarm may or may not have fired. - // Disarm the alarm and return `false` to indicate that. - // It is the caller's responsibility to handle this ambiguity. - r.dier().modify(|w| w.set_ccie(n + 1, false)); + // Reevaluate if the alarm timestamp is still in the future + let t = self.now(); + if timestamp <= t { + // If alarm timestamp has passed since we set it, we have a race condition and + // the alarm may or may not have fired. + // Disarm the alarm and return `false` to indicate that. + // It is the caller's responsibility to handle this ambiguity. + r.dier().modify(|w| w.set_ccie(n + 1, false)); - self.alarm.borrow(cs).timestamp.set(u64::MAX); + self.alarm.borrow(cs).timestamp.set(u64::MAX); - return false; - } + return false; + } - // We're confident the alarm will ring in the future. - true - }) + // We're confident the alarm will ring in the future. + true } } @@ -496,6 +498,19 @@ impl Driver for RtcDriver { let counter = r.cnt().read().cnt(); calc_now(period, counter) } + + fn schedule_wake(&self, at: u64, waker: &core::task::Waker) { + critical_section::with(|cs| { + let mut queue = self.queue.borrow(cs).borrow_mut(); + + if queue.schedule_wake(at, waker) { + let mut next = queue.next_expiration(self.now()); + while !self.set_alarm(cs, next) { + next = queue.next_expiration(self.now()); + } + } + }) + } } #[cfg(feature = "low-power")] @@ -506,8 +521,3 @@ pub(crate) fn get_driver() -> &'static RtcDriver { pub(crate) fn init(cs: CriticalSection) { DRIVER.init(cs) } - -embassy_time_queue_driver::timer_queue_impl!( - static TIMER_QUEUE_DRIVER: GlobalTimerQueue - = GlobalTimerQueue::new(|next_expiration| DRIVER.set_alarm(next_expiration)) -); diff --git a/embassy-time-driver/src/lib.rs b/embassy-time-driver/src/lib.rs index ffb363cd7..090969d8c 100644 --- a/embassy-time-driver/src/lib.rs +++ b/embassy-time-driver/src/lib.rs @@ -38,6 +38,8 @@ //! # Example //! //! ``` +//! use core::task::Waker; +//! //! use embassy_time_driver::Driver; //! //! struct MyDriver{} // not public! @@ -46,6 +48,10 @@ //! fn now(&self) -> u64 { //! todo!() //! } +//! +//! fn schedule_wake(&self, at: u64, waker: &Waker) { +//! todo!() +//! } //! } //! //! embassy_time_driver::time_driver_impl!(static DRIVER: MyDriver = MyDriver{}); @@ -54,6 +60,8 @@ //! ## Feature flags #![doc = document_features::document_features!(feature_label = r#"{feature}"#)] +use core::task::Waker; + mod tick; /// Ticks per second of the global timebase. @@ -74,6 +82,10 @@ pub trait Driver: Send + Sync + 'static { /// you MUST extend them to 64-bit, for example by counting overflows in software, /// or chaining multiple timers together. fn now(&self) -> u64; + + /// Schedules a waker to be awoken at moment `at`. + /// If this moment is in the past, the waker might be awoken immediately. + fn schedule_wake(&self, at: u64, waker: &Waker); } extern "Rust" { @@ -97,5 +109,10 @@ macro_rules! time_driver_impl { fn _embassy_time_now() -> u64 { <$t as $crate::Driver>::now(&$name) } + + #[no_mangle] + fn _embassy_time_schedule_wake(at: u64, waker: &core::task::Waker) { + <$t as $crate::Driver>::schedule_wake(&$name, at, waker); + } }; } diff --git a/embassy-time-queue-driver/src/lib.rs b/embassy-time-queue-driver/src/lib.rs index 2d5fd449a..ed490a0ef 100644 --- a/embassy-time-queue-driver/src/lib.rs +++ b/embassy-time-queue-driver/src/lib.rs @@ -49,23 +49,18 @@ //! embassy_time_queue_driver::timer_queue_impl!(static QUEUE: MyTimerQueue = MyTimerQueue{}); //! ``` +use core::task::Waker; + #[cfg(not(feature = "integrated-timers"))] pub mod queue_generic; #[cfg(feature = "integrated-timers")] pub mod queue_integrated; -use core::cell::RefCell; -use core::task::Waker; +#[cfg(feature = "integrated-timers")] +pub use queue_integrated::Queue; -use critical_section::Mutex; - -/// Timer queue -pub trait TimerQueue { - /// Schedules a waker in the queue to be awoken at moment `at`. - /// - /// If this moment is in the past, the waker might be awoken immediately. - fn schedule_wake(&'static self, at: u64, waker: &Waker); -} +#[cfg(not(feature = "integrated-timers"))] +pub use queue_generic::Queue; extern "Rust" { fn _embassy_time_schedule_wake(at: u64, waker: &Waker); @@ -73,7 +68,10 @@ extern "Rust" { /// Schedule the given waker to be woken at `at`. pub fn schedule_wake(at: u64, waker: &Waker) { - #[cfg(feature = "integrated-timers")] + // This function is not implemented in embassy-time-driver because it needs access to executor + // internals. The function updates task state, then delegates to the implementation provided + // by the time driver. + #[cfg(not(feature = "_generic-queue"))] { use embassy_executor::raw::task_from_waker; use embassy_executor::raw::timer_queue::TimerEnqueueOperation; @@ -89,121 +87,3 @@ pub fn schedule_wake(at: u64, waker: &Waker) { } unsafe { _embassy_time_schedule_wake(at, waker) } } - -/// Set the TimerQueue implementation. -/// -/// See the module documentation for an example. -#[macro_export] -macro_rules! timer_queue_impl { - (static $name:ident: $t: ty = $val:expr) => { - static $name: $t = $val; - - #[no_mangle] - fn _embassy_time_schedule_wake(at: u64, waker: &core::task::Waker) { - <$t as $crate::TimerQueue>::schedule_wake(&$name, at, waker); - } - }; -} - -#[cfg(feature = "integrated-timers")] -type InnerQueue = queue_integrated::TimerQueue; - -#[cfg(not(feature = "integrated-timers"))] -type InnerQueue = queue_generic::Queue; - -/// A timer queue implementation that can be used as a global timer queue. -/// -/// This implementation is not thread-safe, and should be protected by a mutex of some sort. -pub struct GenericTimerQueue bool> { - queue: InnerQueue, - set_alarm: F, -} - -impl bool> GenericTimerQueue { - /// Creates a new timer queue. - /// - /// `set_alarm` is a function that should set the next alarm time. The function should - /// return `true` if the alarm was set, and `false` if the alarm was in the past. - pub const fn new(set_alarm: F) -> Self { - Self { - queue: InnerQueue::new(), - set_alarm, - } - } - - /// Schedules a task to run at a specific time, and returns whether any changes were made. - pub fn schedule_wake(&mut self, at: u64, waker: &core::task::Waker) { - #[cfg(feature = "integrated-timers")] - let waker = embassy_executor::raw::task_from_waker(waker); - - if self.queue.schedule_wake(at, waker) { - self.dispatch() - } - } - - /// Dequeues expired timers and returns the next alarm time. - pub fn next_expiration(&mut self, now: u64) -> u64 { - self.queue.next_expiration(now) - } - - /// Handle the alarm. - /// - /// Call this function when the next alarm is due. - pub fn dispatch(&mut self) { - let mut next_expiration = self.next_expiration(embassy_time_driver::now()); - - while !(self.set_alarm)(next_expiration) { - // next_expiration is in the past, dequeue and find a new expiration - next_expiration = self.next_expiration(next_expiration); - } - } -} - -/// A [`GenericTimerQueue`] protected by a critical section. Directly useable as a [`TimerQueue`]. -pub struct GlobalTimerQueue { - inner: Mutex bool>>>, -} - -impl GlobalTimerQueue { - /// Creates a new timer queue. - /// - /// `set_alarm` is a function that should set the next alarm time. The function should - /// return `true` if the alarm was set, and `false` if the alarm was in the past. - pub const fn new(set_alarm: fn(u64) -> bool) -> Self { - Self { - inner: Mutex::new(RefCell::new(GenericTimerQueue::new(set_alarm))), - } - } - - /// Schedules a task to run at a specific time, and returns whether any changes were made. - pub fn schedule_wake(&self, at: u64, waker: &core::task::Waker) { - critical_section::with(|cs| { - let mut inner = self.inner.borrow_ref_mut(cs); - inner.schedule_wake(at, waker); - }); - } - - /// Dequeues expired timers and returns the next alarm time. - pub fn next_expiration(&self, now: u64) -> u64 { - critical_section::with(|cs| { - let mut inner = self.inner.borrow_ref_mut(cs); - inner.next_expiration(now) - }) - } - - /// Handle the alarm. - /// - /// Call this function when the next alarm is due. - pub fn dispatch(&self) { - critical_section::with(|cs| { - let mut inner = self.inner.borrow_ref_mut(cs); - inner.dispatch() - }) - } -} - -impl TimerQueue for GlobalTimerQueue { - fn schedule_wake(&'static self, at: u64, waker: &Waker) { - GlobalTimerQueue::schedule_wake(self, at, waker) - } -} diff --git a/embassy-time-queue-driver/src/queue_integrated.rs b/embassy-time-queue-driver/src/queue_integrated.rs index b905c00c3..6bb4c0c1a 100644 --- a/embassy-time-queue-driver/src/queue_integrated.rs +++ b/embassy-time-queue-driver/src/queue_integrated.rs @@ -1,15 +1,16 @@ //! Timer queue operations. use core::cell::Cell; use core::cmp::min; +use core::task::Waker; use embassy_executor::raw::TaskRef; /// A timer queue, with items integrated into tasks. -pub struct TimerQueue { +pub struct Queue { head: Cell>, } -impl TimerQueue { +impl Queue { /// Creates a new timer queue. pub const fn new() -> Self { Self { head: Cell::new(None) } @@ -19,11 +20,12 @@ impl TimerQueue { /// /// If this function returns `true`, the called should find the next expiration time and set /// a new alarm for that time. - pub fn schedule_wake(&mut self, at: u64, p: TaskRef) -> bool { - let item = p.timer_queue_item(); + pub fn schedule_wake(&mut self, at: u64, waker: &Waker) -> bool { + let task = embassy_executor::raw::task_from_waker(waker); + let item = task.timer_queue_item(); if item.next.get().is_none() { // If not in the queue, add it and update. - let prev = self.head.replace(Some(p)); + let prev = self.head.replace(Some(task)); item.next.set(if prev.is_none() { Some(unsafe { TaskRef::dangling() }) } else { diff --git a/embassy-time/Cargo.toml b/embassy-time/Cargo.toml index e3074119f..9959e2863 100644 --- a/embassy-time/Cargo.toml +++ b/embassy-time/Cargo.toml @@ -384,7 +384,6 @@ tick-hz-5_242_880_000 = ["embassy-time-driver/tick-hz-5_242_880_000"] [dependencies] embassy-time-driver = { version = "0.1.0", path = "../embassy-time-driver" } -embassy-time-queue-driver = { version = "0.1.0", path = "../embassy-time-queue-driver" } defmt = { version = "0.3", optional = true } log = { version = "0.4.14", optional = true } diff --git a/embassy-time/src/driver_mock.rs b/embassy-time/src/driver_mock.rs index 829eb0437..138d60499 100644 --- a/embassy-time/src/driver_mock.rs +++ b/embassy-time/src/driver_mock.rs @@ -1,7 +1,9 @@ use core::cell::RefCell; +use core::task::Waker; use critical_section::Mutex as CsMutex; use embassy_time_driver::Driver; +use embassy_time_queue_driver::Queue; use crate::{Duration, Instant}; @@ -52,50 +54,12 @@ impl MockDriver { /// Advances the time by the specified [`Duration`]. /// Calling any alarm callbacks that are due. pub fn advance(&self, duration: Duration) { - let notify = { - critical_section::with(|cs| { - let mut inner = self.0.borrow_ref_mut(cs); - - inner.now += duration; - - let now = inner.now.as_ticks(); - - if inner.alarm.timestamp <= now { - inner.alarm.timestamp = u64::MAX; - - Some((inner.alarm.callback, inner.alarm.ctx)) - } else { - None - } - }) - }; - - if let Some((callback, ctx)) = notify { - (callback)(ctx); - } - } - - /// Configures a callback to be called when the alarm fires. - pub fn set_alarm_callback(&self, callback: fn(*mut ()), ctx: *mut ()) { critical_section::with(|cs| { - let mut inner = self.0.borrow_ref_mut(cs); + let inner = &mut *self.0.borrow_ref_mut(cs); - inner.alarm.callback = callback; - inner.alarm.ctx = ctx; - }); - } - - /// Sets the alarm to fire at the specified timestamp. - pub fn set_alarm(&self, timestamp: u64) -> bool { - critical_section::with(|cs| { - let mut inner = self.0.borrow_ref_mut(cs); - - if timestamp <= inner.now.as_ticks() { - false - } else { - inner.alarm.timestamp = timestamp; - true - } + inner.now += duration; + // wake expired tasks. + inner.queue.next_expiration(inner.now.as_ticks()); }) } } @@ -104,44 +68,38 @@ impl Driver for MockDriver { fn now(&self) -> u64 { critical_section::with(|cs| self.0.borrow_ref(cs).now).as_ticks() } + + fn schedule_wake(&self, at: u64, waker: &Waker) { + critical_section::with(|cs| { + let inner = &mut *self.0.borrow_ref_mut(cs); + // enqueue it + inner.queue.schedule_wake(at, waker); + // wake it if it's in the past. + inner.queue.next_expiration(inner.now.as_ticks()); + }) + } } struct InnerMockDriver { now: Instant, - alarm: AlarmState, + queue: Queue, } impl InnerMockDriver { const fn new() -> Self { Self { now: Instant::from_ticks(0), - alarm: AlarmState::new(), + queue: Queue::new(), } } } -struct AlarmState { - timestamp: u64, - callback: fn(*mut ()), - ctx: *mut (), -} - -impl AlarmState { - const fn new() -> Self { - Self { - timestamp: u64::MAX, - callback: Self::noop, - ctx: core::ptr::null_mut(), - } - } - - fn noop(_ctx: *mut ()) {} -} - -unsafe impl Send for AlarmState {} - #[cfg(test)] mod tests { + use core::sync::atomic::{AtomicBool, Ordering}; + use std::sync::Arc; + use std::task::Wake; + use serial_test::serial; use super::*; @@ -163,24 +121,25 @@ mod tests { #[test] #[serial] - fn test_set_alarm_not_in_future() { + fn test_schedule_wake() { setup(); - let driver = MockDriver::get(); - assert_eq!(false, driver.set_alarm(driver.now())); - } + static CALLBACK_CALLED: AtomicBool = AtomicBool::new(false); - #[test] - #[serial] - fn test_alarm() { - setup(); + struct MockWaker; + + impl Wake for MockWaker { + fn wake(self: Arc) { + CALLBACK_CALLED.store(true, Ordering::Relaxed); + } + } + let waker = Arc::new(MockWaker).into(); let driver = MockDriver::get(); - static mut CALLBACK_CALLED: bool = false; - driver.set_alarm_callback(|_| unsafe { CALLBACK_CALLED = true }, core::ptr::null_mut()); - driver.set_alarm(driver.now() + 1); - assert_eq!(false, unsafe { CALLBACK_CALLED }); + + driver.schedule_wake(driver.now() + 1, &waker); + assert_eq!(false, CALLBACK_CALLED.load(Ordering::Relaxed)); driver.advance(Duration::from_secs(1)); - assert_eq!(true, unsafe { CALLBACK_CALLED }); + assert_eq!(true, CALLBACK_CALLED.load(Ordering::Relaxed)); } } diff --git a/embassy-time/src/driver_std.rs b/embassy-time/src/driver_std.rs index 45467f09b..35888fddd 100644 --- a/embassy-time/src/driver_std.rs +++ b/embassy-time/src/driver_std.rs @@ -1,97 +1,67 @@ -use std::cell::{RefCell, UnsafeCell}; -use std::mem::MaybeUninit; -use std::sync::{Condvar, Mutex, Once}; +use std::sync::{Condvar, Mutex}; +use std::thread; use std::time::{Duration as StdDuration, Instant as StdInstant}; -use std::{ptr, thread}; -use critical_section::Mutex as CsMutex; use embassy_time_driver::Driver; -use embassy_time_queue_driver::GlobalTimerQueue; - -struct AlarmState { - timestamp: u64, -} - -unsafe impl Send for AlarmState {} - -impl AlarmState { - const fn new() -> Self { - Self { timestamp: u64::MAX } - } -} +use embassy_time_queue_driver::Queue; struct TimeDriver { - once: Once, - // The STD Driver implementation requires the alarm's mutex to be reentrant, which the STD Mutex isn't - // Fortunately, mutexes based on the `critical-section` crate are reentrant, because the critical sections - // themselves are reentrant - alarm: UninitCell>>, - zero_instant: UninitCell, - signaler: UninitCell, + signaler: Signaler, + inner: Mutex, +} + +struct Inner { + zero_instant: Option, + queue: Queue, } embassy_time_driver::time_driver_impl!(static DRIVER: TimeDriver = TimeDriver { - once: Once::new(), - alarm: UninitCell::uninit(), - zero_instant: UninitCell::uninit(), - signaler: UninitCell::uninit(), + inner: Mutex::new(Inner{ + zero_instant: None, + queue: Queue::new(), + }), + signaler: Signaler::new(), }); -impl TimeDriver { - fn init(&self) { - self.once.call_once(|| unsafe { - self.alarm - .write(CsMutex::new(RefCell::new(const { AlarmState::new() }))); - self.zero_instant.write(StdInstant::now()); - self.signaler.write(Signaler::new()); - - thread::spawn(Self::alarm_thread); - }); - } - - fn alarm_thread() { - let zero = unsafe { DRIVER.zero_instant.read() }; - loop { - let now = DRIVER.now(); - - let next_alarm = critical_section::with(|cs| { - let mut alarm = unsafe { DRIVER.alarm.as_ref() }.borrow_ref_mut(cs); - if alarm.timestamp <= now { - alarm.timestamp = u64::MAX; - - TIMER_QUEUE_DRIVER.dispatch(); - } - alarm.timestamp - }); - - // Ensure we don't overflow - let until = zero - .checked_add(StdDuration::from_micros(next_alarm)) - .unwrap_or_else(|| StdInstant::now() + StdDuration::from_secs(1)); - - unsafe { DRIVER.signaler.as_ref() }.wait_until(until); - } - } - - fn set_alarm(&self, timestamp: u64) -> bool { - self.init(); - critical_section::with(|cs| { - let mut alarm = unsafe { self.alarm.as_ref() }.borrow_ref_mut(cs); - alarm.timestamp = timestamp; - unsafe { self.signaler.as_ref() }.signal(); - }); - - true +impl Inner { + fn init(&mut self) -> StdInstant { + *self.zero_instant.get_or_insert_with(|| { + thread::spawn(alarm_thread); + StdInstant::now() + }) } } impl Driver for TimeDriver { fn now(&self) -> u64 { - self.init(); - - let zero = unsafe { self.zero_instant.read() }; + let mut inner = self.inner.lock().unwrap(); + let zero = inner.init(); StdInstant::now().duration_since(zero).as_micros() as u64 } + + fn schedule_wake(&self, at: u64, waker: &core::task::Waker) { + let mut inner = self.inner.lock().unwrap(); + inner.init(); + if inner.queue.schedule_wake(at, waker) { + self.signaler.signal(); + } + } +} + +fn alarm_thread() { + let zero = DRIVER.inner.lock().unwrap().zero_instant.unwrap(); + loop { + let now = DRIVER.now(); + + let next_alarm = DRIVER.inner.lock().unwrap().queue.next_expiration(now); + + // Ensure we don't overflow + let until = zero + .checked_add(StdDuration::from_micros(next_alarm)) + .unwrap_or_else(|| StdInstant::now() + StdDuration::from_secs(1)); + + DRIVER.signaler.wait_until(until); + } } struct Signaler { @@ -100,7 +70,7 @@ struct Signaler { } impl Signaler { - fn new() -> Self { + const fn new() -> Self { Self { mutex: Mutex::new(false), condvar: Condvar::new(), @@ -132,40 +102,3 @@ impl Signaler { self.condvar.notify_one(); } } - -pub(crate) struct UninitCell(MaybeUninit>); -unsafe impl Send for UninitCell {} -unsafe impl Sync for UninitCell {} - -impl UninitCell { - pub const fn uninit() -> Self { - Self(MaybeUninit::uninit()) - } - - pub unsafe fn as_ptr(&self) -> *const T { - (*self.0.as_ptr()).get() - } - - pub unsafe fn as_mut_ptr(&self) -> *mut T { - (*self.0.as_ptr()).get() - } - - pub unsafe fn as_ref(&self) -> &T { - &*self.as_ptr() - } - - pub unsafe fn write(&self, val: T) { - ptr::write(self.as_mut_ptr(), val) - } -} - -impl UninitCell { - pub unsafe fn read(&self) -> T { - ptr::read(self.as_mut_ptr()) - } -} - -embassy_time_queue_driver::timer_queue_impl!( - static TIMER_QUEUE_DRIVER: GlobalTimerQueue - = GlobalTimerQueue::new(|next_expiration| DRIVER.set_alarm(next_expiration)) -); diff --git a/embassy-time/src/driver_wasm.rs b/embassy-time/src/driver_wasm.rs index dcc935fde..bcdd1670b 100644 --- a/embassy-time/src/driver_wasm.rs +++ b/embassy-time/src/driver_wasm.rs @@ -1,10 +1,7 @@ -use std::cell::UnsafeCell; -use std::mem::MaybeUninit; -use std::ptr; -use std::sync::{Mutex, Once}; +use std::sync::Mutex; use embassy_time_driver::Driver; -use embassy_time_queue_driver::GlobalTimerQueue; +use embassy_time_queue_driver::Queue; use wasm_bindgen::prelude::*; use wasm_timer::Instant as StdInstant; @@ -12,8 +9,6 @@ struct AlarmState { token: Option, } -unsafe impl Send for AlarmState {} - impl AlarmState { const fn new() -> Self { Self { token: None } @@ -27,33 +22,38 @@ extern "C" { } struct TimeDriver { - once: Once, - alarm: UninitCell>, - zero_instant: UninitCell, - closure: UninitCell>, + inner: Mutex, } +struct Inner { + alarm: AlarmState, + zero_instant: Option, + queue: Queue, + closure: Option>, +} + +unsafe impl Send for Inner {} + embassy_time_driver::time_driver_impl!(static DRIVER: TimeDriver = TimeDriver { - once: Once::new(), - alarm: UninitCell::uninit(), - zero_instant: UninitCell::uninit(), - closure: UninitCell::uninit() + inner: Mutex::new(Inner{ + zero_instant: None, + queue: Queue::new(), + alarm: AlarmState::new(), + closure: None, + }), }); -impl TimeDriver { - fn init(&self) { - self.once.call_once(|| unsafe { - self.alarm.write(Mutex::new(const { AlarmState::new() })); - self.zero_instant.write(StdInstant::now()); - self.closure - .write(Closure::new(Box::new(|| TIMER_QUEUE_DRIVER.dispatch()))); - }); +impl Inner { + fn init(&mut self) -> StdInstant { + *self.zero_instant.get_or_insert_with(StdInstant::now) } - fn set_alarm(&self, timestamp: u64) -> bool { - self.init(); - let mut alarm = unsafe { self.alarm.as_ref() }.lock().unwrap(); - if let Some(token) = alarm.token { + fn now(&mut self) -> u64 { + StdInstant::now().duration_since(self.zero_instant.unwrap()).as_micros() as u64 + } + + fn set_alarm(&mut self, timestamp: u64) -> bool { + if let Some(token) = self.alarm.token { clearTimeout(token); } @@ -62,7 +62,8 @@ impl TimeDriver { false } else { let timeout = (timestamp - now) as u32; - alarm.token = Some(setTimeout(unsafe { self.closure.as_ref() }, timeout / 1000)); + let closure = self.closure.get_or_insert_with(|| Closure::new(dispatch)); + self.alarm.token = Some(setTimeout(closure, timeout / 1000)); true } @@ -71,45 +72,32 @@ impl TimeDriver { impl Driver for TimeDriver { fn now(&self) -> u64 { - self.init(); - - let zero = unsafe { self.zero_instant.read() }; + let mut inner = self.inner.lock().unwrap(); + let zero = inner.init(); StdInstant::now().duration_since(zero).as_micros() as u64 } -} -pub(crate) struct UninitCell(MaybeUninit>); -unsafe impl Send for UninitCell {} -unsafe impl Sync for UninitCell {} - -impl UninitCell { - pub const fn uninit() -> Self { - Self(MaybeUninit::uninit()) - } - unsafe fn as_ptr(&self) -> *const T { - (*self.0.as_ptr()).get() - } - - pub unsafe fn as_mut_ptr(&self) -> *mut T { - (*self.0.as_ptr()).get() - } - - pub unsafe fn as_ref(&self) -> &T { - &*self.as_ptr() - } - - pub unsafe fn write(&self, val: T) { - ptr::write(self.as_mut_ptr(), val) + fn schedule_wake(&self, at: u64, waker: &core::task::Waker) { + let mut inner = self.inner.lock().unwrap(); + inner.init(); + if inner.queue.schedule_wake(at, waker) { + let now = inner.now(); + let mut next = inner.queue.next_expiration(now); + while !inner.set_alarm(next) { + let now = inner.now(); + next = inner.queue.next_expiration(now); + } + } } } -impl UninitCell { - pub unsafe fn read(&self) -> T { - ptr::read(self.as_mut_ptr()) +fn dispatch() { + let inner = &mut *DRIVER.inner.lock().unwrap(); + + let now = inner.now(); + let mut next = inner.queue.next_expiration(now); + while !inner.set_alarm(next) { + let now = inner.now(); + next = inner.queue.next_expiration(now); } } - -embassy_time_queue_driver::timer_queue_impl!( - static TIMER_QUEUE_DRIVER: GlobalTimerQueue - = GlobalTimerQueue::new(|next_expiration| DRIVER.set_alarm(next_expiration)) -); From 6f08c62d5ddcbeba01e098e11b9bc4ed1dfa7cc2 Mon Sep 17 00:00:00 2001 From: Alexander Walter Date: Sat, 14 Dec 2024 00:11:32 +0100 Subject: [PATCH 0470/1217] Add nrf9160 --- embassy-nrf/src/lib.rs | 2 +- embassy-nrf/src/power.rs | 15 +++++++++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index b6283c7f5..ec5e9f864 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs @@ -107,7 +107,7 @@ pub mod nvmc; ))] pub mod pdm; #[cfg(not(feature = "_nrf54l"))] // TODO -#[cfg(feature = "nrf52840")] +#[cfg(any(feature = "nrf52840", feature = "nrf9160-s", feature = "nrf9160-ns"))] pub mod power; #[cfg(not(feature = "_nrf54l"))] // TODO pub mod ppi; diff --git a/embassy-nrf/src/power.rs b/embassy-nrf/src/power.rs index 440028380..66dfbae65 100644 --- a/embassy-nrf/src/power.rs +++ b/embassy-nrf/src/power.rs @@ -1,13 +1,24 @@ //! Power -use crate::chip::pac::{NFCT, POWER}; +#[cfg(feature = "nrf52840")] +use crate::chip::pac::NFCT; -/// Puts the MCU into "System Off" mode with a power usage 0f 0.4 uA +#[cfg(feature = "nrf52840")] +use crate::chip::pac::POWER; + +#[cfg(any(feature = "nrf9160-s", feature = "nrf9160-ns"))] +use crate::chip::pac::REGULATORS; + +/// Puts the MCU into "System Off" mode with minimal power usage pub fn set_system_off() { + #[cfg(feature = "nrf52840")] POWER.systemoff().write(|w| w.set_systemoff(true)); + #[cfg(any(feature = "nrf9160-s", feature = "nrf9160-ns"))] + REGULATORS.systemoff().write(|w| w.set_systemoff(true)); } /// Wake the system if there if an NFC field close to the nrf52840's antenna +#[cfg(feature = "nrf52840")] pub fn wake_on_nfc_sense() { NFCT.tasks_sense().write_value(0x01); } From be1ed104e47e16eca1ec4e403db9ae02da5c9e27 Mon Sep 17 00:00:00 2001 From: Alexander Walter Date: Sat, 14 Dec 2024 00:57:55 +0100 Subject: [PATCH 0471/1217] Add trait embedded_io_async to uarte --- embassy-nrf/src/uarte.rs | 57 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/embassy-nrf/src/uarte.rs b/embassy-nrf/src/uarte.rs index 2a59d029d..378325749 100644 --- a/embassy-nrf/src/uarte.rs +++ b/embassy-nrf/src/uarte.rs @@ -1047,3 +1047,60 @@ mod eh02 { } } } + +mod _embedded_io { + use super::*; + + impl embedded_io_async::Error for Error { + fn kind(&self) -> embedded_io_async::ErrorKind { + match *self { + Error::BufferTooLong => embedded_io_async::ErrorKind::InvalidInput, + Error::BufferNotInRAM => embedded_io_async::ErrorKind::Unsupported, + Error::Framing => embedded_io_async::ErrorKind::InvalidData, + Error::Parity => embedded_io_async::ErrorKind::InvalidData, + Error::Overrun => embedded_io_async::ErrorKind::OutOfMemory, + Error::Break => embedded_io_async::ErrorKind::ConnectionAborted, + } + } + } + + impl<'d, U: Instance> embedded_io_async::ErrorType for Uarte<'d, U> { + type Error = Error; + } + + impl<'d, U: Instance> embedded_io_async::ErrorType for UarteRx<'d, U> { + type Error = Error; + } + + impl<'d, U: Instance> embedded_io_async::ErrorType for UarteTx<'d, U> { + type Error = Error; + } + + impl<'d, U: Instance> embedded_io_async::Read for Uarte<'d, U> { + async fn read(&mut self, buf: &mut [u8]) -> Result { + self.read(buf).await?; + Ok(buf.len()) + } + } + + impl<'d: 'd, U: Instance> embedded_io_async::Read for UarteRx<'d, U> { + async fn read(&mut self, buf: &mut [u8]) -> Result { + self.read(buf).await?; + Ok(buf.len()) + } + } + + impl<'d, U: Instance> embedded_io_async::Write for Uarte<'d, U> { + async fn write(&mut self, buf: &[u8]) -> Result { + self.write(buf).await?; + Ok(buf.len()) + } + } + + impl<'d: 'd, U: Instance> embedded_io_async::Write for UarteTx<'d, U> { + async fn write(&mut self, buf: &[u8]) -> Result { + self.write(buf).await?; + Ok(buf.len()) + } + } +} From c4f6509cf28e1a8c2401a67f771dd8b959ae7c49 Mon Sep 17 00:00:00 2001 From: Alexander Walter Date: Sat, 14 Dec 2024 01:02:35 +0100 Subject: [PATCH 0472/1217] rustfmt --- embassy-nrf/src/power.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/embassy-nrf/src/power.rs b/embassy-nrf/src/power.rs index 66dfbae65..ab6460625 100644 --- a/embassy-nrf/src/power.rs +++ b/embassy-nrf/src/power.rs @@ -2,10 +2,8 @@ #[cfg(feature = "nrf52840")] use crate::chip::pac::NFCT; - #[cfg(feature = "nrf52840")] use crate::chip::pac::POWER; - #[cfg(any(feature = "nrf9160-s", feature = "nrf9160-ns"))] use crate::chip::pac::REGULATORS; From 854d1f3743e8759095bbcd25fb0d73884562ee9d Mon Sep 17 00:00:00 2001 From: vinsynth <1.5vhunt@gmail.com> Date: Sat, 14 Dec 2024 00:32:47 -0500 Subject: [PATCH 0473/1217] add sysclk frequency argument to PioI2Out::new --- embassy-rp/src/pio_programs/i2s.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/embassy-rp/src/pio_programs/i2s.rs b/embassy-rp/src/pio_programs/i2s.rs index e3f1f89d4..8989afb4c 100644 --- a/embassy-rp/src/pio_programs/i2s.rs +++ b/embassy-rp/src/pio_programs/i2s.rs @@ -51,6 +51,7 @@ impl<'a, P: Instance, const S: usize> PioI2sOut<'a, P, S> { data_pin: impl PioPin, bit_clock_pin: impl PioPin, lr_clock_pin: impl PioPin, + sysclk_frequency: u32, sample_rate: u32, bit_depth: u32, channels: u32, @@ -67,7 +68,7 @@ impl<'a, P: Instance, const S: usize> PioI2sOut<'a, P, S> { cfg.use_program(&program.prg, &[&bit_clock_pin, &left_right_clock_pin]); cfg.set_out_pins(&[&data_pin]); let clock_frequency = sample_rate * bit_depth * channels; - cfg.clock_divider = (125_000_000. / clock_frequency as f64 / 2.).to_fixed(); + cfg.clock_divider = (sysclk_frequency as f64 / clock_frequency as f64 / 2.).to_fixed(); cfg.shift_out = ShiftConfig { threshold: 32, direction: ShiftDirection::Left, From 3b5993cf48c0a1a5f88f5d0f771df16ceb4de3fb Mon Sep 17 00:00:00 2001 From: Alexander Walter Date: Sat, 14 Dec 2024 15:40:08 +0100 Subject: [PATCH 0474/1217] Move wake on sense to nfct --- embassy-nrf/src/nfct.rs | 7 ++++++- embassy-nrf/src/power.rs | 6 ------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/embassy-nrf/src/nfct.rs b/embassy-nrf/src/nfct.rs index cbd3920ee..06cb0916c 100644 --- a/embassy-nrf/src/nfct.rs +++ b/embassy-nrf/src/nfct.rs @@ -18,7 +18,7 @@ use embassy_sync::waitqueue::AtomicWaker; pub use vals::{Bitframesdd as SddPat, Discardmode as DiscardMode}; use crate::interrupt::InterruptExt; -use crate::pac::nfct::vals; +use crate::pac::{nfct::vals, NFCT}; use crate::peripherals::NFCT; use crate::util::slice_in_ram; use crate::{interrupt, pac, Peripheral}; @@ -420,3 +420,8 @@ impl<'d> NfcT<'d> { Ok(n) } } + +/// Wake the system if there if an NFC field close to the antenna +pub fn wake_on_nfc_sense() { + NFCT.tasks_sense().write_value(0x01); +} diff --git a/embassy-nrf/src/power.rs b/embassy-nrf/src/power.rs index ab6460625..730efe094 100644 --- a/embassy-nrf/src/power.rs +++ b/embassy-nrf/src/power.rs @@ -14,9 +14,3 @@ pub fn set_system_off() { #[cfg(any(feature = "nrf9160-s", feature = "nrf9160-ns"))] REGULATORS.systemoff().write(|w| w.set_systemoff(true)); } - -/// Wake the system if there if an NFC field close to the nrf52840's antenna -#[cfg(feature = "nrf52840")] -pub fn wake_on_nfc_sense() { - NFCT.tasks_sense().write_value(0x01); -} From f5ead85377ab78d8f463df4f1e358770ff3eca5b Mon Sep 17 00:00:00 2001 From: Alexander Walter Date: Sat, 14 Dec 2024 15:41:31 +0100 Subject: [PATCH 0475/1217] Just impl Write --- embassy-nrf/src/uarte.rs | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/embassy-nrf/src/uarte.rs b/embassy-nrf/src/uarte.rs index 378325749..ebb4dd941 100644 --- a/embassy-nrf/src/uarte.rs +++ b/embassy-nrf/src/uarte.rs @@ -1068,28 +1068,10 @@ mod _embedded_io { type Error = Error; } - impl<'d, U: Instance> embedded_io_async::ErrorType for UarteRx<'d, U> { - type Error = Error; - } - impl<'d, U: Instance> embedded_io_async::ErrorType for UarteTx<'d, U> { type Error = Error; } - impl<'d, U: Instance> embedded_io_async::Read for Uarte<'d, U> { - async fn read(&mut self, buf: &mut [u8]) -> Result { - self.read(buf).await?; - Ok(buf.len()) - } - } - - impl<'d: 'd, U: Instance> embedded_io_async::Read for UarteRx<'d, U> { - async fn read(&mut self, buf: &mut [u8]) -> Result { - self.read(buf).await?; - Ok(buf.len()) - } - } - impl<'d, U: Instance> embedded_io_async::Write for Uarte<'d, U> { async fn write(&mut self, buf: &[u8]) -> Result { self.write(buf).await?; From ea374a47368fb917e6a89b0bc567a225778f4f9f Mon Sep 17 00:00:00 2001 From: Alexander Walter Date: Sat, 14 Dec 2024 15:48:18 +0100 Subject: [PATCH 0476/1217] Fix rustfm and warning --- embassy-nrf/src/nfct.rs | 3 ++- embassy-nrf/src/power.rs | 2 -- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/embassy-nrf/src/nfct.rs b/embassy-nrf/src/nfct.rs index 06cb0916c..8b4b6dfe0 100644 --- a/embassy-nrf/src/nfct.rs +++ b/embassy-nrf/src/nfct.rs @@ -18,7 +18,8 @@ use embassy_sync::waitqueue::AtomicWaker; pub use vals::{Bitframesdd as SddPat, Discardmode as DiscardMode}; use crate::interrupt::InterruptExt; -use crate::pac::{nfct::vals, NFCT}; +use crate::pac::nfct::vals; +use crate::pac::NFCT; use crate::peripherals::NFCT; use crate::util::slice_in_ram; use crate::{interrupt, pac, Peripheral}; diff --git a/embassy-nrf/src/power.rs b/embassy-nrf/src/power.rs index 730efe094..f93bf8f49 100644 --- a/embassy-nrf/src/power.rs +++ b/embassy-nrf/src/power.rs @@ -1,7 +1,5 @@ //! Power -#[cfg(feature = "nrf52840")] -use crate::chip::pac::NFCT; #[cfg(feature = "nrf52840")] use crate::chip::pac::POWER; #[cfg(any(feature = "nrf9160-s", feature = "nrf9160-ns"))] From ffbef9316d523724d050f32e800668a56e534657 Mon Sep 17 00:00:00 2001 From: vinsynth <1.5vhunt@gmail.com> Date: Sat, 14 Dec 2024 11:02:18 -0500 Subject: [PATCH 0477/1217] i2s frequency relative to sysclk --- embassy-rp/src/pio_programs/i2s.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/embassy-rp/src/pio_programs/i2s.rs b/embassy-rp/src/pio_programs/i2s.rs index 8989afb4c..87fb2e19f 100644 --- a/embassy-rp/src/pio_programs/i2s.rs +++ b/embassy-rp/src/pio_programs/i2s.rs @@ -51,7 +51,6 @@ impl<'a, P: Instance, const S: usize> PioI2sOut<'a, P, S> { data_pin: impl PioPin, bit_clock_pin: impl PioPin, lr_clock_pin: impl PioPin, - sysclk_frequency: u32, sample_rate: u32, bit_depth: u32, channels: u32, @@ -68,7 +67,7 @@ impl<'a, P: Instance, const S: usize> PioI2sOut<'a, P, S> { cfg.use_program(&program.prg, &[&bit_clock_pin, &left_right_clock_pin]); cfg.set_out_pins(&[&data_pin]); let clock_frequency = sample_rate * bit_depth * channels; - cfg.clock_divider = (sysclk_frequency as f64 / clock_frequency as f64 / 2.).to_fixed(); + cfg.clock_divider = (crate::clocks::clk_sys_freq() as f64 / clock_frequency as f64 / 2.).to_fixed(); cfg.shift_out = ShiftConfig { threshold: 32, direction: ShiftDirection::Left, From 1152148081c7c80e42d67d9517ae75b628ecf38b Mon Sep 17 00:00:00 2001 From: Alexander van Saase Date: Sat, 14 Dec 2024 22:33:24 +0100 Subject: [PATCH 0478/1217] Add is_x() methods for all EitherN enum variants --- embassy-futures/src/select.rs | 110 ++++++++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) diff --git a/embassy-futures/src/select.rs b/embassy-futures/src/select.rs index bb175253b..014fee5d2 100644 --- a/embassy-futures/src/select.rs +++ b/embassy-futures/src/select.rs @@ -14,6 +14,18 @@ pub enum Either { Second(B), } +impl Either { + /// Did the first future complete first? + pub fn is_first(&self) -> bool { + matches!(self, Either::First(_)) + } + + /// Did the second future complete first? + pub fn is_second(&self) -> bool { + matches!(self, Either::Second(_)) + } +} + /// Wait for one of two futures to complete. /// /// This function returns a new future which polls all the futures. @@ -73,6 +85,23 @@ pub enum Either3 { Third(C), } +impl Either3 { + /// Did the first future complete first? + pub fn is_first(&self) -> bool { + matches!(self, Either3::First(_)) + } + + /// Did the second future complete first? + pub fn is_second(&self) -> bool { + matches!(self, Either3::Second(_)) + } + + /// Did the third future complete first? + pub fn is_third(&self) -> bool { + matches!(self, Either3::Third(_)) + } +} + /// Same as [`select`], but with more futures. pub fn select3(a: A, b: B, c: C) -> Select3 where @@ -134,6 +163,28 @@ pub enum Either4 { Fourth(D), } +impl Either4 { + /// Did the first future complete first? + pub fn is_first(&self) -> bool { + matches!(self, Either4::First(_)) + } + + /// Did the second future complete first? + pub fn is_second(&self) -> bool { + matches!(self, Either4::Second(_)) + } + + /// Did the third future complete first? + pub fn is_third(&self) -> bool { + matches!(self, Either4::Third(_)) + } + + /// Did the fourth future complete first? + pub fn is_fourth(&self) -> bool { + matches!(self, Either4::Fourth(_)) + } +} + /// Same as [`select`], but with more futures. pub fn select4(a: A, b: B, c: C, d: D) -> Select4 where @@ -204,6 +255,33 @@ pub enum Either5 { Fifth(E), } +impl Either5 { + /// Did the first future complete first? + pub fn is_first(&self) -> bool { + matches!(self, Either5::First(_)) + } + + /// Did the second future complete first? + pub fn is_second(&self) -> bool { + matches!(self, Either5::Second(_)) + } + + /// Did the third future complete first? + pub fn is_third(&self) -> bool { + matches!(self, Either5::Third(_)) + } + + /// Did the fourth future complete first? + pub fn is_fourth(&self) -> bool { + matches!(self, Either5::Fourth(_)) + } + + /// Did the fifth future complete first? + pub fn is_fifth(&self) -> bool { + matches!(self, Either5::Fifth(_)) + } +} + /// Same as [`select`], but with more futures. pub fn select5(a: A, b: B, c: C, d: D, e: E) -> Select5 where @@ -283,6 +361,38 @@ pub enum Either6 { Sixth(F), } +impl Either6 { + /// Did the first future complete first? + pub fn is_first(&self) -> bool { + matches!(self, Either6::First(_)) + } + + /// Did the second future complete first? + pub fn is_second(&self) -> bool { + matches!(self, Either6::Second(_)) + } + + /// Did the third future complete first? + pub fn is_third(&self) -> bool { + matches!(self, Either6::Third(_)) + } + + /// Did the fourth future complete first? + pub fn is_fourth(&self) -> bool { + matches!(self, Either6::Fourth(_)) + } + + /// Did the fifth future complete first? + pub fn is_fifth(&self) -> bool { + matches!(self, Either6::Fifth(_)) + } + + /// Did the sixth future complete first? + pub fn is_sixth(&self) -> bool { + matches!(self, Either6::Sixth(_)) + } +} + /// Same as [`select`], but with more futures. pub fn select6(a: A, b: B, c: C, d: D, e: E, f: F) -> Select6 where From 4b31639dcacd23ce24d9a33d3a491c8d58ca9cfd Mon Sep 17 00:00:00 2001 From: Fabian Wolter Date: Sat, 14 Dec 2024 23:32:08 +0100 Subject: [PATCH 0479/1217] STM32F0 fix using HSI48 as SYSCLK on devices with CRS Fixes #3651 --- embassy-stm32/src/rcc/f013.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/embassy-stm32/src/rcc/f013.rs b/embassy-stm32/src/rcc/f013.rs index c915f1b16..a38ca955e 100644 --- a/embassy-stm32/src/rcc/f013.rs +++ b/embassy-stm32/src/rcc/f013.rs @@ -229,6 +229,9 @@ pub(crate) unsafe fn init(config: Config) { Sysclk::HSI => unwrap!(hsi), Sysclk::HSE => unwrap!(hse), Sysclk::PLL1_P => unwrap!(pll), + #[cfg(crs)] + Sysclk::HSI48 => unwrap!(hsi48), + #[cfg(not(crs))] _ => unreachable!(), }; From 2f2e2c6031a1abaecdac5ed2febe109e647fe6fd Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 9 Dec 2024 00:28:14 +0100 Subject: [PATCH 0480/1217] Make `integrated-timers` the default, remove Cargo feature. --- ci-nightly.sh | 9 +----- ci-xtensa.sh | 13 ++++----- ci.sh | 11 ++----- docs/examples/basic/Cargo.toml | 2 +- docs/pages/new_project.adoc | 4 +-- embassy-executor/Cargo.toml | 6 +--- embassy-executor/src/raw/mod.rs | 7 ----- embassy-executor/src/raw/state_atomics.rs | 4 --- embassy-executor/src/raw/state_atomics_arm.rs | 4 --- .../src/raw/state_critical_section.rs | 4 --- embassy-executor/src/raw/trace.rs | 22 +++++--------- embassy-stm32/Cargo.toml | 1 - embassy-time-queue-driver/Cargo.toml | 29 ++++++++++--------- embassy-time-queue-driver/src/lib.rs | 11 ++++--- embassy-time/Cargo.toml | 1 + examples/boot/application/nrf/Cargo.toml | 2 +- examples/boot/application/rp/Cargo.toml | 2 +- examples/boot/application/stm32f3/Cargo.toml | 2 +- examples/boot/application/stm32f7/Cargo.toml | 2 +- examples/boot/application/stm32h7/Cargo.toml | 2 +- examples/boot/application/stm32l0/Cargo.toml | 2 +- examples/boot/application/stm32l1/Cargo.toml | 2 +- examples/boot/application/stm32l4/Cargo.toml | 2 +- .../boot/application/stm32wb-dfu/Cargo.toml | 2 +- examples/boot/application/stm32wl/Cargo.toml | 2 +- examples/nrf-rtos-trace/Cargo.toml | 2 +- examples/nrf51/Cargo.toml | 2 +- examples/nrf52810/Cargo.toml | 2 +- examples/nrf52840-rtic/Cargo.toml | 2 +- examples/nrf52840/Cargo.toml | 2 +- examples/nrf5340/Cargo.toml | 2 +- examples/nrf54l15/Cargo.toml | 2 +- examples/nrf9151/ns/Cargo.toml | 2 +- examples/nrf9151/s/Cargo.toml | 2 +- examples/nrf9160/Cargo.toml | 2 +- examples/rp/Cargo.toml | 2 +- examples/rp23/Cargo.toml | 2 +- examples/std/Cargo.toml | 2 +- examples/stm32c0/Cargo.toml | 2 +- examples/stm32f0/Cargo.toml | 2 +- examples/stm32f1/Cargo.toml | 2 +- examples/stm32f2/Cargo.toml | 2 +- examples/stm32f3/Cargo.toml | 2 +- examples/stm32f334/Cargo.toml | 2 +- examples/stm32f4/Cargo.toml | 2 +- examples/stm32f469/Cargo.toml | 2 +- examples/stm32f7/Cargo.toml | 2 +- examples/stm32g0/Cargo.toml | 2 +- examples/stm32g4/Cargo.toml | 2 +- examples/stm32h5/Cargo.toml | 2 +- examples/stm32h7/Cargo.toml | 2 +- examples/stm32h723/Cargo.toml | 2 +- examples/stm32h735/Cargo.toml | 2 +- examples/stm32h755cm4/Cargo.toml | 2 +- examples/stm32h755cm7/Cargo.toml | 2 +- examples/stm32h7b0/Cargo.toml | 2 +- examples/stm32h7rs/Cargo.toml | 2 +- examples/stm32l0/Cargo.toml | 2 +- examples/stm32l1/Cargo.toml | 2 +- examples/stm32l4/Cargo.toml | 2 +- examples/stm32l5/Cargo.toml | 2 +- examples/stm32u0/Cargo.toml | 2 +- examples/stm32u5/Cargo.toml | 2 +- examples/stm32wb/Cargo.toml | 2 +- examples/stm32wba/Cargo.toml | 2 +- examples/stm32wl/Cargo.toml | 2 +- examples/wasm/Cargo.toml | 2 +- tests/nrf/Cargo.toml | 2 +- tests/rp/Cargo.toml | 2 +- tests/stm32/Cargo.toml | 2 +- 70 files changed, 96 insertions(+), 142 deletions(-) diff --git a/ci-nightly.sh b/ci-nightly.sh index bdb364f53..1b69cc18e 100755 --- a/ci-nightly.sh +++ b/ci-nightly.sh @@ -13,20 +13,13 @@ cargo batch \ --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,log \ --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,defmt \ --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv6m-none-eabi --features nightly,defmt \ - --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv6m-none-eabi --features nightly,defmt,arch-cortex-m,executor-thread,executor-interrupt,integrated-timers \ + --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv6m-none-eabi --features nightly,defmt,arch-cortex-m,executor-thread,executor-interrupt \ --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m \ - --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,integrated-timers \ --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,executor-thread \ - --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,executor-thread,integrated-timers \ --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,executor-interrupt \ - --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,executor-interrupt,integrated-timers \ --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,executor-thread,executor-interrupt \ - --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,executor-thread,executor-interrupt,integrated-timers \ --- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features nightly,arch-riscv32 \ - --- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features nightly,arch-riscv32,integrated-timers \ --- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features nightly,arch-riscv32,executor-thread \ - --- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features nightly,arch-riscv32,executor-thread,integrated-timers \ --- build --release --manifest-path examples/nrf52840-rtic/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/nrf52840-rtic \ cargo build --release --manifest-path embassy-executor/Cargo.toml --target avr-unknown-gnu-atmega328 -Z build-std=core,alloc --features nightly,arch-avr,avr-device/atmega328p -cargo build --release --manifest-path embassy-executor/Cargo.toml --target avr-unknown-gnu-atmega328 -Z build-std=core,alloc --features nightly,arch-avr,integrated-timers,avr-device/atmega328p diff --git a/ci-xtensa.sh b/ci-xtensa.sh index 2cac7444c..056e85d48 100755 --- a/ci-xtensa.sh +++ b/ci-xtensa.sh @@ -14,18 +14,15 @@ cargo batch \ --- build --release --manifest-path embassy-executor/Cargo.toml --target xtensa-esp32-none-elf --features log \ --- build --release --manifest-path embassy-executor/Cargo.toml --target xtensa-esp32-none-elf --features defmt \ --- build --release --manifest-path embassy-executor/Cargo.toml --target xtensa-esp32s2-none-elf --features defmt \ - --- build --release --manifest-path embassy-executor/Cargo.toml --target xtensa-esp32-none-elf --features defmt,arch-spin,executor-thread,integrated-timers \ - --- build --release --manifest-path embassy-executor/Cargo.toml --target xtensa-esp32s2-none-elf --features defmt,arch-spin,executor-thread,integrated-timers \ - --- build --release --manifest-path embassy-executor/Cargo.toml --target xtensa-esp32s3-none-elf --features defmt,arch-spin,executor-thread,integrated-timers \ + --- build --release --manifest-path embassy-executor/Cargo.toml --target xtensa-esp32-none-elf --features defmt,arch-spin,executor-thread \ + --- build --release --manifest-path embassy-executor/Cargo.toml --target xtensa-esp32s2-none-elf --features defmt,arch-spin,executor-thread \ + --- build --release --manifest-path embassy-executor/Cargo.toml --target xtensa-esp32s3-none-elf --features defmt,arch-spin,executor-thread \ --- build --release --manifest-path embassy-executor/Cargo.toml --target xtensa-esp32-none-elf --features arch-spin \ - --- build --release --manifest-path embassy-executor/Cargo.toml --target xtensa-esp32-none-elf --features arch-spin,integrated-timers \ --- build --release --manifest-path embassy-executor/Cargo.toml --target xtensa-esp32-none-elf --features arch-spin,rtos-trace \ - --- build --release --manifest-path embassy-executor/Cargo.toml --target xtensa-esp32-none-elf --features arch-spin,integrated-timers,rtos-trace \ --- build --release --manifest-path embassy-executor/Cargo.toml --target xtensa-esp32-none-elf --features arch-spin,executor-thread \ - --- build --release --manifest-path embassy-executor/Cargo.toml --target xtensa-esp32-none-elf --features arch-spin,executor-thread,integrated-timers \ --- build --release --manifest-path embassy-sync/Cargo.toml --target xtensa-esp32s2-none-elf --features defmt \ --- build --release --manifest-path embassy-time/Cargo.toml --target xtensa-esp32s2-none-elf --features defmt,defmt-timestamp-uptime,mock-driver \ - --- build --release --manifest-path embassy-time-queue-driver/Cargo.toml --target xtensa-esp32s2-none-elf --features integrated-timers \ + --- build --release --manifest-path embassy-time-queue-driver/Cargo.toml --target xtensa-esp32s2-none-elf \ --- build --release --manifest-path embassy-time-queue-driver/Cargo.toml --target xtensa-esp32s2-none-elf --features generic-queue-8 \ --- build --release --manifest-path embassy-net/Cargo.toml --target xtensa-esp32-none-elf --features defmt,tcp,udp,dns,proto-ipv4,medium-ethernet,packet-trace \ --- build --release --manifest-path embassy-net/Cargo.toml --target xtensa-esp32-none-elf --features defmt,tcp,udp,dns,proto-ipv4,multicast,medium-ethernet \ @@ -38,4 +35,4 @@ cargo batch \ --- build --release --manifest-path embassy-net/Cargo.toml --target xtensa-esp32-none-elf --features defmt,tcp,udp,dns,proto-ipv4,proto-ipv6,medium-ethernet \ --- build --release --manifest-path embassy-net/Cargo.toml --target xtensa-esp32-none-elf --features defmt,tcp,udp,dns,proto-ipv4,proto-ipv6,medium-ip \ --- build --release --manifest-path embassy-net/Cargo.toml --target xtensa-esp32-none-elf --features defmt,tcp,udp,dns,proto-ipv4,proto-ipv6,medium-ip,medium-ethernet \ - --- build --release --manifest-path embassy-net/Cargo.toml --target xtensa-esp32-none-elf --features defmt,tcp,udp,dns,proto-ipv4,proto-ipv6,medium-ip,medium-ethernet,medium-ieee802154 \ \ No newline at end of file + --- build --release --manifest-path embassy-net/Cargo.toml --target xtensa-esp32-none-elf --features defmt,tcp,udp,dns,proto-ipv4,proto-ipv6,medium-ip,medium-ethernet,medium-ieee802154 \ diff --git a/ci.sh b/ci.sh index 71b862632..cb3a2f3f7 100755 --- a/ci.sh +++ b/ci.sh @@ -29,24 +29,17 @@ cargo batch \ --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features log \ --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features defmt \ --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv6m-none-eabi --features defmt \ - --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv6m-none-eabi --features defmt,arch-cortex-m,executor-thread,executor-interrupt,integrated-timers \ + --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv6m-none-eabi --features defmt,arch-cortex-m,executor-thread,executor-interrupt \ --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m \ - --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,integrated-timers \ --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,rtos-trace \ - --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,integrated-timers,rtos-trace \ --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,executor-thread \ - --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,executor-thread,integrated-timers \ --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,executor-interrupt \ - --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,executor-interrupt,integrated-timers \ --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,executor-thread,executor-interrupt \ - --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,executor-thread,executor-interrupt,integrated-timers \ --- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features arch-riscv32 \ - --- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features arch-riscv32,integrated-timers \ --- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features arch-riscv32,executor-thread \ - --- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features arch-riscv32,executor-thread,integrated-timers \ --- build --release --manifest-path embassy-sync/Cargo.toml --target thumbv6m-none-eabi --features defmt \ --- build --release --manifest-path embassy-time/Cargo.toml --target thumbv6m-none-eabi --features defmt,defmt-timestamp-uptime,mock-driver \ - --- build --release --manifest-path embassy-time-queue-driver/Cargo.toml --target thumbv6m-none-eabi --features integrated-timers \ + --- build --release --manifest-path embassy-time-queue-driver/Cargo.toml --target thumbv6m-none-eabi \ --- build --release --manifest-path embassy-time-queue-driver/Cargo.toml --target thumbv6m-none-eabi --features generic-queue-8 \ --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,medium-ethernet,packet-trace \ --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,multicast,medium-ethernet \ diff --git a/docs/examples/basic/Cargo.toml b/docs/examples/basic/Cargo.toml index d46431b9a..daf83873d 100644 --- a/docs/examples/basic/Cargo.toml +++ b/docs/examples/basic/Cargo.toml @@ -6,7 +6,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-executor = { version = "0.6.3", path = "../../../embassy-executor", features = ["defmt", "integrated-timers", "arch-cortex-m", "executor-thread"] } +embassy-executor = { version = "0.6.3", path = "../../../embassy-executor", features = ["defmt", "arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.3.2", path = "../../../embassy-time", features = ["defmt"] } embassy-nrf = { version = "0.2.0", path = "../../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote"] } diff --git a/docs/pages/new_project.adoc b/docs/pages/new_project.adoc index f8dd848be..63340016b 100644 --- a/docs/pages/new_project.adoc +++ b/docs/pages/new_project.adoc @@ -80,7 +80,7 @@ At the time of writing, embassy is already published to crates.io. Therefore, de ---- [dependencies] embassy-stm32 = { version = "0.1.0", features = ["defmt", "time-driver-any", "stm32g474re", "memory-x", "unstable-pac", "exti"] } -embassy-executor = { version = "0.6.3", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.3", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.3.2", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } ---- @@ -100,7 +100,7 @@ An example Cargo.toml file might look as follows: ---- [dependencies] embassy-stm32 = {version = "0.1.0", features = ["defmt", "time-driver-any", "stm32g474re", "memory-x", "unstable-pac", "exti"]} -embassy-executor = { version = "0.3.3", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.3.3", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.2", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } [patch.crates-io] diff --git a/embassy-executor/Cargo.toml b/embassy-executor/Cargo.toml index 862d25b59..60fe7087a 100644 --- a/embassy-executor/Cargo.toml +++ b/embassy-executor/Cargo.toml @@ -35,7 +35,6 @@ rtos-trace = { version = "0.1.3", optional = true } embassy-executor-macros = { version = "0.6.2", path = "../embassy-executor-macros" } embassy-time-driver = { version = "0.1.0", path = "../embassy-time-driver", optional = true } -embassy-time-queue-driver = { version = "0.1.0", path = "../embassy-time-queue-driver", optional = true } critical-section = "1.1" document-features = "0.2.7" @@ -67,9 +66,6 @@ nightly = ["embassy-executor-macros/nightly"] # See: https://github.com/embassy-rs/embassy/pull/1263 turbowakers = [] -## Use the executor-integrated `embassy-time` timer queue. -integrated-timers = ["dep:embassy-time-driver"] - #! ### Architecture _arch = [] # some arch was picked ## std @@ -94,7 +90,7 @@ executor-interrupt = [] ## Enable tracing support (adds some overhead) trace = [] ## Enable support for rtos-trace framework -rtos-trace = ["dep:rtos-trace", "trace"] +rtos-trace = ["dep:rtos-trace", "trace", "dep:embassy-time-driver"] #! ### Task Arena Size #! Sets the [task arena](#task-arena) size. Necessary if you’re not using `nightly`. diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs index 14d689900..2feaab155 100644 --- a/embassy-executor/src/raw/mod.rs +++ b/embassy-executor/src/raw/mod.rs @@ -16,7 +16,6 @@ mod run_queue; #[cfg_attr(not(target_has_atomic = "8"), path = "state_critical_section.rs")] mod state; -#[cfg(feature = "integrated-timers")] pub mod timer_queue; #[cfg(feature = "trace")] mod trace; @@ -45,7 +44,6 @@ pub(crate) struct TaskHeader { poll_fn: SyncUnsafeCell>, /// Integrated timer queue storage. This field should not be accessed outside of the timer queue. - #[cfg(feature = "integrated-timers")] pub(crate) timer_queue_item: timer_queue::TimerQueueItem, } @@ -87,13 +85,11 @@ impl TaskRef { } /// Returns a reference to the executor that the task is currently running on. - #[cfg(feature = "integrated-timers")] pub unsafe fn executor(self) -> Option<&'static Executor> { self.header().executor.get().map(|e| Executor::wrap(e)) } /// Returns a reference to the timer queue item. - #[cfg(feature = "integrated-timers")] pub fn timer_queue_item(&self) -> &'static timer_queue::TimerQueueItem { &self.header().timer_queue_item } @@ -106,7 +102,6 @@ impl TaskRef { /// /// This functions should only be called by the timer queue implementation, before /// enqueueing the timer item. - #[cfg(feature = "integrated-timers")] pub unsafe fn timer_enqueue(&self) -> timer_queue::TimerEnqueueOperation { self.header().state.timer_enqueue() } @@ -117,7 +112,6 @@ impl TaskRef { /// /// This functions should only be called by the timer queue implementation, after the task has /// been removed from the timer queue. - #[cfg(feature = "integrated-timers")] pub unsafe fn timer_dequeue(&self) { self.header().state.timer_dequeue() } @@ -162,7 +156,6 @@ impl TaskStorage { // Note: this is lazily initialized so that a static `TaskStorage` will go in `.bss` poll_fn: SyncUnsafeCell::new(None), - #[cfg(feature = "integrated-timers")] timer_queue_item: timer_queue::TimerQueueItem::new(), }, future: UninitCell::uninit(), diff --git a/embassy-executor/src/raw/state_atomics.rs b/embassy-executor/src/raw/state_atomics.rs index d03c61ade..15eb9a368 100644 --- a/embassy-executor/src/raw/state_atomics.rs +++ b/embassy-executor/src/raw/state_atomics.rs @@ -1,6 +1,5 @@ use core::sync::atomic::{AtomicU32, Ordering}; -#[cfg(feature = "integrated-timers")] use super::timer_queue::TimerEnqueueOperation; /// Task is spawned (has a future) @@ -8,7 +7,6 @@ pub(crate) const STATE_SPAWNED: u32 = 1 << 0; /// Task is in the executor run queue pub(crate) const STATE_RUN_QUEUED: u32 = 1 << 1; /// Task is in the executor timer queue -#[cfg(feature = "integrated-timers")] pub(crate) const STATE_TIMER_QUEUED: u32 = 1 << 2; pub(crate) struct State { @@ -60,7 +58,6 @@ impl State { } /// Mark the task as timer-queued. Return whether it can be enqueued. - #[cfg(feature = "integrated-timers")] #[inline(always)] pub fn timer_enqueue(&self) -> TimerEnqueueOperation { if self @@ -83,7 +80,6 @@ impl State { } /// Unmark the task as timer-queued. - #[cfg(feature = "integrated-timers")] #[inline(always)] pub fn timer_dequeue(&self) { self.state.fetch_and(!STATE_TIMER_QUEUED, Ordering::Relaxed); diff --git a/embassy-executor/src/raw/state_atomics_arm.rs b/embassy-executor/src/raw/state_atomics_arm.rs index f6f2e8f08..7a152e8c0 100644 --- a/embassy-executor/src/raw/state_atomics_arm.rs +++ b/embassy-executor/src/raw/state_atomics_arm.rs @@ -1,13 +1,11 @@ use core::arch::asm; use core::sync::atomic::{compiler_fence, AtomicBool, AtomicU32, Ordering}; -#[cfg(feature = "integrated-timers")] use super::timer_queue::TimerEnqueueOperation; // Must be kept in sync with the layout of `State`! pub(crate) const STATE_SPAWNED: u32 = 1 << 0; pub(crate) const STATE_RUN_QUEUED: u32 = 1 << 8; -#[cfg(feature = "integrated-timers")] pub(crate) const STATE_TIMER_QUEUED: u32 = 1 << 16; #[repr(C, align(4))] @@ -93,7 +91,6 @@ impl State { } /// Mark the task as timer-queued. Return whether it can be enqueued. - #[cfg(feature = "integrated-timers")] #[inline(always)] pub fn timer_enqueue(&self) -> TimerEnqueueOperation { if self @@ -116,7 +113,6 @@ impl State { } /// Unmark the task as timer-queued. - #[cfg(feature = "integrated-timers")] #[inline(always)] pub fn timer_dequeue(&self) { self.timer_queued.store(false, Ordering::Relaxed); diff --git a/embassy-executor/src/raw/state_critical_section.rs b/embassy-executor/src/raw/state_critical_section.rs index c0ec2f530..367162ba2 100644 --- a/embassy-executor/src/raw/state_critical_section.rs +++ b/embassy-executor/src/raw/state_critical_section.rs @@ -2,7 +2,6 @@ use core::cell::Cell; use critical_section::Mutex; -#[cfg(feature = "integrated-timers")] use super::timer_queue::TimerEnqueueOperation; /// Task is spawned (has a future) @@ -10,7 +9,6 @@ pub(crate) const STATE_SPAWNED: u32 = 1 << 0; /// Task is in the executor run queue pub(crate) const STATE_RUN_QUEUED: u32 = 1 << 1; /// Task is in the executor timer queue -#[cfg(feature = "integrated-timers")] pub(crate) const STATE_TIMER_QUEUED: u32 = 1 << 2; pub(crate) struct State { @@ -77,7 +75,6 @@ impl State { } /// Mark the task as timer-queued. Return whether it can be enqueued. - #[cfg(feature = "integrated-timers")] #[inline(always)] pub fn timer_enqueue(&self) -> TimerEnqueueOperation { self.update(|s| { @@ -93,7 +90,6 @@ impl State { } /// Unmark the task as timer-queued. - #[cfg(feature = "integrated-timers")] #[inline(always)] pub fn timer_dequeue(&self) { self.update(|s| *s &= !STATE_TIMER_QUEUED); diff --git a/embassy-executor/src/raw/trace.rs b/embassy-executor/src/raw/trace.rs index c7bcf9c11..b34387b58 100644 --- a/embassy-executor/src/raw/trace.rs +++ b/embassy-executor/src/raw/trace.rs @@ -61,29 +61,23 @@ pub(crate) fn executor_idle(executor: &SyncExecutor) { rtos_trace::trace::system_idle(); } -#[cfg(all(feature = "rtos-trace", feature = "integrated-timers"))] -const fn gcd(a: u64, b: u64) -> u64 { - if b == 0 { - a - } else { - gcd(b, a % b) - } -} - #[cfg(feature = "rtos-trace")] impl rtos_trace::RtosTraceOSCallbacks for crate::raw::SyncExecutor { fn task_list() { // We don't know what tasks exist, so we can't send them. } - #[cfg(feature = "integrated-timers")] fn time() -> u64 { + const fn gcd(a: u64, b: u64) -> u64 { + if b == 0 { + a + } else { + gcd(b, a % b) + } + } + const GCD_1M: u64 = gcd(embassy_time_driver::TICK_HZ, 1_000_000); embassy_time_driver::now() * (1_000_000 / GCD_1M) / (embassy_time_driver::TICK_HZ / GCD_1M) } - #[cfg(not(feature = "integrated-timers"))] - fn time() -> u64 { - 0 - } } #[cfg(feature = "rtos-trace")] diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 82030f99f..47e9e8bb9 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -126,7 +126,6 @@ defmt = [ exti = [] low-power = [ "dep:embassy-executor", "embassy-executor?/arch-cortex-m", "time" ] low-power-debug-with-sleep = [] -integrated-timers = ["dep:embassy-executor", "_time-driver"] ## Automatically generate `memory.x` file using [`stm32-metapac`](https://docs.rs/stm32-metapac/) memory-x = ["stm32-metapac/memory-x"] diff --git a/embassy-time-queue-driver/Cargo.toml b/embassy-time-queue-driver/Cargo.toml index 599041a3f..7a10e29b4 100644 --- a/embassy-time-queue-driver/Cargo.toml +++ b/embassy-time-queue-driver/Cargo.toml @@ -23,35 +23,36 @@ links = "embassy-time-queue" [dependencies] critical-section = "1.2.0" heapless = "0.8" -embassy-executor = { version = "0.6.3", path = "../embassy-executor", optional = true } +embassy-executor = { version = "0.6.3", path = "../embassy-executor" } embassy-time-driver = { version = "0.1.0", path = "../embassy-time-driver" } [features] #! ### Generic Queue -## Use the executor-integrated `embassy-time` timer queue. The timer items are stored inside -## the task headers, so you do not need to set a capacity for the queue. -## To use this you must have a time driver provided. -## -## If this feature is not enabled, a generic queue is available with a configurable capacity. -integrated-timers = ["embassy-executor/integrated-timers"] - -#! The following features set how many timers are used for the generic queue. At most one +#! By default this crate uses a timer queue implementation that is faster but depends on `embassy-executor`. +#! It will panic if you try to await any timer when using another executor. +#! +#! Alternatively, you can choose to use a "generic" timer queue implementation that works on any executor. +#! To enable it, enable any of the features below. +#! +#! The features also set how many timers are used for the generic queue. At most one #! `generic-queue-*` feature can be enabled. If none is enabled, a default of 64 timers is used. #! #! When using embassy-time from libraries, you should *not* enable any `generic-queue-*` feature, to allow the #! end user to pick. ## Generic Queue with 8 timers -generic-queue-8 = [] +generic-queue-8 = ["_generic-queue"] ## Generic Queue with 16 timers -generic-queue-16 = [] +generic-queue-16 = ["_generic-queue"] ## Generic Queue with 32 timers -generic-queue-32 = [] +generic-queue-32 = ["_generic-queue"] ## Generic Queue with 64 timers -generic-queue-64 = [] +generic-queue-64 = ["_generic-queue"] ## Generic Queue with 128 timers -generic-queue-128 = [] +generic-queue-128 = ["_generic-queue"] + +_generic-queue = [] [package.metadata.embassy_docs] src_base = "https://github.com/embassy-rs/embassy/blob/embassy-time-queue-driver-v$VERSION/embassy-time-queue-driver/src/" diff --git a/embassy-time-queue-driver/src/lib.rs b/embassy-time-queue-driver/src/lib.rs index ed490a0ef..46dd646ca 100644 --- a/embassy-time-queue-driver/src/lib.rs +++ b/embassy-time-queue-driver/src/lib.rs @@ -51,16 +51,15 @@ use core::task::Waker; -#[cfg(not(feature = "integrated-timers"))] +#[cfg(feature = "_generic-queue")] pub mod queue_generic; -#[cfg(feature = "integrated-timers")] +#[cfg(not(feature = "_generic-queue"))] pub mod queue_integrated; -#[cfg(feature = "integrated-timers")] -pub use queue_integrated::Queue; - -#[cfg(not(feature = "integrated-timers"))] +#[cfg(feature = "_generic-queue")] pub use queue_generic::Queue; +#[cfg(not(feature = "_generic-queue"))] +pub use queue_integrated::Queue; extern "Rust" { fn _embassy_time_schedule_wake(at: u64, waker: &Waker); diff --git a/embassy-time/Cargo.toml b/embassy-time/Cargo.toml index 9959e2863..e3074119f 100644 --- a/embassy-time/Cargo.toml +++ b/embassy-time/Cargo.toml @@ -384,6 +384,7 @@ tick-hz-5_242_880_000 = ["embassy-time-driver/tick-hz-5_242_880_000"] [dependencies] embassy-time-driver = { version = "0.1.0", path = "../embassy-time-driver" } +embassy-time-queue-driver = { version = "0.1.0", path = "../embassy-time-queue-driver" } defmt = { version = "0.3", optional = true } log = { version = "0.4.14", optional = true } diff --git a/examples/boot/application/nrf/Cargo.toml b/examples/boot/application/nrf/Cargo.toml index 046571e05..45ad341fc 100644 --- a/examples/boot/application/nrf/Cargo.toml +++ b/examples/boot/application/nrf/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.6.3", path = "../../../../embassy-executor", features = ["task-arena-size-16384", "arch-cortex-m", "executor-thread", "integrated-timers", "arch-cortex-m", "executor-thread"] } +embassy-executor = { version = "0.6.3", path = "../../../../embassy-executor", features = ["task-arena-size-16384", "arch-cortex-m", "executor-thread", "arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [] } embassy-nrf = { version = "0.2.0", path = "../../../../embassy-nrf", features = ["time-driver-rtc1", "gpiote", ] } embassy-boot = { version = "0.3.0", path = "../../../../embassy-boot", features = [] } diff --git a/examples/boot/application/rp/Cargo.toml b/examples/boot/application/rp/Cargo.toml index f859ddbc6..ec99f2605 100644 --- a/examples/boot/application/rp/Cargo.toml +++ b/examples/boot/application/rp/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.6.3", path = "../../../../embassy-executor", features = ["task-arena-size-16384", "arch-cortex-m", "executor-thread", "integrated-timers", "arch-cortex-m", "executor-thread"] } +embassy-executor = { version = "0.6.3", path = "../../../../embassy-executor", features = ["task-arena-size-16384", "arch-cortex-m", "executor-thread", "arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [] } embassy-rp = { version = "0.2.0", path = "../../../../embassy-rp", features = ["time-driver", "rp2040"] } embassy-boot-rp = { version = "0.3.0", path = "../../../../embassy-boot-rp", features = [] } diff --git a/examples/boot/application/stm32f3/Cargo.toml b/examples/boot/application/stm32f3/Cargo.toml index d5b26d698..d2138db87 100644 --- a/examples/boot/application/stm32f3/Cargo.toml +++ b/examples/boot/application/stm32f3/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.6.3", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32f303re", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32" } diff --git a/examples/boot/application/stm32f7/Cargo.toml b/examples/boot/application/stm32f7/Cargo.toml index d13692aa8..b86c66f5d 100644 --- a/examples/boot/application/stm32f7/Cargo.toml +++ b/examples/boot/application/stm32f7/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.6.3", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32f767zi", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } diff --git a/examples/boot/application/stm32h7/Cargo.toml b/examples/boot/application/stm32h7/Cargo.toml index a2de827aa..e2e2fe711 100644 --- a/examples/boot/application/stm32h7/Cargo.toml +++ b/examples/boot/application/stm32h7/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.6.3", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32h743zi", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } diff --git a/examples/boot/application/stm32l0/Cargo.toml b/examples/boot/application/stm32l0/Cargo.toml index ddfddf652..7e9c52ffa 100644 --- a/examples/boot/application/stm32l0/Cargo.toml +++ b/examples/boot/application/stm32l0/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.6.3", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l072cz", "time-driver-any", "exti", "memory-x"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } diff --git a/examples/boot/application/stm32l1/Cargo.toml b/examples/boot/application/stm32l1/Cargo.toml index 4780c20f4..42353a24c 100644 --- a/examples/boot/application/stm32l1/Cargo.toml +++ b/examples/boot/application/stm32l1/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.6.3", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l151cb-a", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } diff --git a/examples/boot/application/stm32l4/Cargo.toml b/examples/boot/application/stm32l4/Cargo.toml index 0a31d6b62..cf0b0242a 100644 --- a/examples/boot/application/stm32l4/Cargo.toml +++ b/examples/boot/application/stm32l4/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.6.3", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l475vg", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } diff --git a/examples/boot/application/stm32wb-dfu/Cargo.toml b/examples/boot/application/stm32wb-dfu/Cargo.toml index 67f6bde11..ea2879fb5 100644 --- a/examples/boot/application/stm32wb-dfu/Cargo.toml +++ b/examples/boot/application/stm32wb-dfu/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.6.3", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32wb55rg", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } diff --git a/examples/boot/application/stm32wl/Cargo.toml b/examples/boot/application/stm32wl/Cargo.toml index da27d4601..6417b8430 100644 --- a/examples/boot/application/stm32wl/Cargo.toml +++ b/examples/boot/application/stm32wl/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.6.3", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32wl55jc-cm4", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } diff --git a/examples/nrf-rtos-trace/Cargo.toml b/examples/nrf-rtos-trace/Cargo.toml index 449056409..6d13d668a 100644 --- a/examples/nrf-rtos-trace/Cargo.toml +++ b/examples/nrf-rtos-trace/Cargo.toml @@ -16,7 +16,7 @@ log = [ [dependencies] embassy-sync = { version = "0.6.1", path = "../../embassy-sync" } -embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "rtos-trace", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "rtos-trace"] } embassy-time = { version = "0.3.2", path = "../../embassy-time" } embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] } diff --git a/examples/nrf51/Cargo.toml b/examples/nrf51/Cargo.toml index 05e702773..8d995cfd8 100644 --- a/examples/nrf51/Cargo.toml +++ b/examples/nrf51/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-4096", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-4096", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf51", "gpiote", "time-driver-rtc1", "unstable-pac", "time", "rt"] } diff --git a/examples/nrf52810/Cargo.toml b/examples/nrf52810/Cargo.toml index b0b73417b..fa2a27aaa 100644 --- a/examples/nrf52810/Cargo.toml +++ b/examples/nrf52810/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf52810", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } diff --git a/examples/nrf52840-rtic/Cargo.toml b/examples/nrf52840-rtic/Cargo.toml index 326355dd6..6b15b24da 100644 --- a/examples/nrf52840-rtic/Cargo.toml +++ b/examples/nrf52840-rtic/Cargo.toml @@ -10,7 +10,7 @@ rtic = { version = "2", features = ["thumbv7-backend"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = [ "defmt", "defmt-timestamp-uptime"] } -embassy-time-queue-driver = { version = "0.1.0", path = "../../embassy-time-queue-driver" } +embassy-time-queue-driver = { version = "0.1.0", path = "../../embassy-time-queue-driver", features = ["generic-queue-8"] } embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = [ "defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } defmt = "0.3" diff --git a/examples/nrf52840/Cargo.toml b/examples/nrf52840/Cargo.toml index 701911a30..fa29d52b9 100644 --- a/examples/nrf52840/Cargo.toml +++ b/examples/nrf52840/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } diff --git a/examples/nrf5340/Cargo.toml b/examples/nrf5340/Cargo.toml index 13442405d..1792b277c 100644 --- a/examples/nrf5340/Cargo.toml +++ b/examples/nrf5340/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf5340-app-s", "time-driver-rtc1", "gpiote", "unstable-pac"] } embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } diff --git a/examples/nrf54l15/Cargo.toml b/examples/nrf54l15/Cargo.toml index 6d11269f7..7288ef6af 100644 --- a/examples/nrf54l15/Cargo.toml +++ b/examples/nrf54l15/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf54l15-app-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } diff --git a/examples/nrf9151/ns/Cargo.toml b/examples/nrf9151/ns/Cargo.toml index 96bf6700d..0353cf598 100644 --- a/examples/nrf9151/ns/Cargo.toml +++ b/examples/nrf9151/ns/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-executor = { version = "0.6.3", path = "../../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.3.2", path = "../../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.2.0", path = "../../../embassy-nrf", features = ["defmt", "nrf9120-ns", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } diff --git a/examples/nrf9151/s/Cargo.toml b/examples/nrf9151/s/Cargo.toml index f7adf259d..5d2302574 100644 --- a/examples/nrf9151/s/Cargo.toml +++ b/examples/nrf9151/s/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-executor = { version = "0.6.3", path = "../../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.3.2", path = "../../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.2.0", path = "../../../embassy-nrf", features = ["defmt", "nrf9120-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } diff --git a/examples/nrf9160/Cargo.toml b/examples/nrf9160/Cargo.toml index 3b404c730..b52cd4af0 100644 --- a/examples/nrf9160/Cargo.toml +++ b/examples/nrf9160/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf9160-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } embassy-net-nrf91 = { version = "0.1.0", path = "../../embassy-net-nrf91", features = ["defmt"] } diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index 2dce1676a..ce812b2e0 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal", features = ["defmt"] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-98304", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-98304", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-rp = { version = "0.2.0", path = "../../embassy-rp", features = ["defmt", "unstable-pac", "time-driver", "critical-section-impl", "rp2040"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/rp23/Cargo.toml b/examples/rp23/Cargo.toml index 2fcad247d..72eef222d 100644 --- a/examples/rp23/Cargo.toml +++ b/examples/rp23/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal", features = ["defmt"] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-98304", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-98304", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-rp = { version = "0.2.0", path = "../../embassy-rp", features = ["defmt", "unstable-pac", "time-driver", "critical-section-impl", "rp235xa", "binary-info"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/std/Cargo.toml b/examples/std/Cargo.toml index 77948515a..e43fd77c8 100644 --- a/examples/std/Cargo.toml +++ b/examples/std/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["log"] } -embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-std", "executor-thread", "log", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-std", "executor-thread", "log"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["log", "std", ] } embassy-net = { version = "0.5.0", path = "../../embassy-net", features=[ "std", "log", "medium-ethernet", "medium-ip", "tcp", "udp", "dns", "dhcpv4", "proto-ipv6"] } embassy-net-tuntap = { version = "0.1.0", path = "../../embassy-net-tuntap" } diff --git a/examples/stm32c0/Cargo.toml b/examples/stm32c0/Cargo.toml index 895e668da..5ac3018e1 100644 --- a/examples/stm32c0/Cargo.toml +++ b/examples/stm32c0/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32c031c6 to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32c031c6", "memory-x", "unstable-pac", "exti"] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } defmt = "0.3" diff --git a/examples/stm32f0/Cargo.toml b/examples/stm32f0/Cargo.toml index 056f8470d..af3ef7abb 100644 --- a/examples/stm32f0/Cargo.toml +++ b/examples/stm32f0/Cargo.toml @@ -13,7 +13,7 @@ defmt = "0.3" defmt-rtt = "0.4" panic-probe = { version = "0.3", features = ["print-defmt"] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } static_cell = "2" portable-atomic = { version = "1.5", features = ["unsafe-assume-single-core"] } diff --git a/examples/stm32f1/Cargo.toml b/examples/stm32f1/Cargo.toml index c081333d7..538e95dfb 100644 --- a/examples/stm32f1/Cargo.toml +++ b/examples/stm32f1/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32f103c8 to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f103c8", "unstable-pac", "memory-x", "time-driver-any" ] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32f2/Cargo.toml b/examples/stm32f2/Cargo.toml index f7993497c..48d524b90 100644 --- a/examples/stm32f2/Cargo.toml +++ b/examples/stm32f2/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32f207zg to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f207zg", "unstable-pac", "memory-x", "time-driver-any", "exti"] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } defmt = "0.3" diff --git a/examples/stm32f3/Cargo.toml b/examples/stm32f3/Cargo.toml index a7b8935a9..66fb34223 100644 --- a/examples/stm32f3/Cargo.toml +++ b/examples/stm32f3/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32f303ze to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f303ze", "unstable-pac", "memory-x", "time-driver-tim2", "exti"] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32f334/Cargo.toml b/examples/stm32f334/Cargo.toml index ed8348772..c6b311fa5 100644 --- a/examples/stm32f334/Cargo.toml +++ b/examples/stm32f334/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f334r8", "unstable-pac", "memory-x", "time-driver-any", "exti"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/stm32f4/Cargo.toml b/examples/stm32f4/Cargo.toml index 2a0b7c507..4f0629fc6 100644 --- a/examples/stm32f4/Cargo.toml +++ b/examples/stm32f4/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32f429zi to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32f429zi", "unstable-pac", "memory-x", "time-driver-tim4", "exti", "chrono"] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt" ] } embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", ] } diff --git a/examples/stm32f469/Cargo.toml b/examples/stm32f469/Cargo.toml index 382f7e485..a80409801 100644 --- a/examples/stm32f469/Cargo.toml +++ b/examples/stm32f469/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Specific examples only for stm32f469 embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32f469ni", "unstable-pac", "memory-x", "time-driver-any", "exti", "chrono"] } -embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } defmt = "0.3" diff --git a/examples/stm32f7/Cargo.toml b/examples/stm32f7/Cargo.toml index 480694dca..520b8bc42 100644 --- a/examples/stm32f7/Cargo.toml +++ b/examples/stm32f7/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32f777zi to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32f777zi", "memory-x", "unstable-pac", "time-driver-any", "exti"] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } embedded-io-async = { version = "0.6.1" } diff --git a/examples/stm32g0/Cargo.toml b/examples/stm32g0/Cargo.toml index 66cac1885..3d11610ce 100644 --- a/examples/stm32g0/Cargo.toml +++ b/examples/stm32g0/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32g0b1re to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32g0b1re", "memory-x", "unstable-pac", "exti"] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", default-features = false, features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32g4/Cargo.toml b/examples/stm32g4/Cargo.toml index 36bef4787..87fa2c53a 100644 --- a/examples/stm32g4/Cargo.toml +++ b/examples/stm32g4/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32g491re to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32g491re", "memory-x", "unstable-pac", "exti"] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32h5/Cargo.toml b/examples/stm32h5/Cargo.toml index 1a5791c83..516d491e5 100644 --- a/examples/stm32h5/Cargo.toml +++ b/examples/stm32h5/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32h563zi to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h563zi", "memory-x", "time-driver-any", "exti", "unstable-pac", "low-power"] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/stm32h7/Cargo.toml b/examples/stm32h7/Cargo.toml index b90a6a455..68a0c3d88 100644 --- a/examples/stm32h7/Cargo.toml +++ b/examples/stm32h7/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h743bi", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } -embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/stm32h723/Cargo.toml b/examples/stm32h723/Cargo.toml index 6e3f0dd03..82f3cb9c2 100644 --- a/examples/stm32h723/Cargo.toml +++ b/examples/stm32h723/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32h723zg to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h723zg", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32h735/Cargo.toml b/examples/stm32h735/Cargo.toml index a9c66ec48..a517b9727 100644 --- a/examples/stm32h735/Cargo.toml +++ b/examples/stm32h735/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h735ig", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } -embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32h755cm4/Cargo.toml b/examples/stm32h755cm4/Cargo.toml index 455dee98b..1d4d3eb85 100644 --- a/examples/stm32h755cm4/Cargo.toml +++ b/examples/stm32h755cm4/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h755zi-cm4", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } -embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/stm32h755cm7/Cargo.toml b/examples/stm32h755cm7/Cargo.toml index 4d6167ab2..76c88c806 100644 --- a/examples/stm32h755cm7/Cargo.toml +++ b/examples/stm32h755cm7/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h755zi-cm7", "time-driver-tim3", "exti", "memory-x", "unstable-pac", "chrono"] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } -embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/stm32h7b0/Cargo.toml b/examples/stm32h7b0/Cargo.toml index 41f0fb5ca..aba398fa5 100644 --- a/examples/stm32h7b0/Cargo.toml +++ b/examples/stm32h7b0/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h7b0vb", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } -embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/stm32h7rs/Cargo.toml b/examples/stm32h7rs/Cargo.toml index 24065dbce..1d957e2cc 100644 --- a/examples/stm32h7rs/Cargo.toml +++ b/examples/stm32h7rs/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32h743bi to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h7s3l8", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/stm32l0/Cargo.toml b/examples/stm32l0/Cargo.toml index 9d234804a..5cc312a50 100644 --- a/examples/stm32l0/Cargo.toml +++ b/examples/stm32l0/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32l072cz to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32l073rz", "unstable-pac", "time-driver-any", "exti", "memory-x"] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } defmt = "0.3" diff --git a/examples/stm32l1/Cargo.toml b/examples/stm32l1/Cargo.toml index 33e4f96e5..31b6785fa 100644 --- a/examples/stm32l1/Cargo.toml +++ b/examples/stm32l1/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32l151cb-a", "time-driver-any", "memory-x"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/stm32l4/Cargo.toml b/examples/stm32l4/Cargo.toml index 512bb8064..3fde18ecd 100644 --- a/examples/stm32l4/Cargo.toml +++ b/examples/stm32l4/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32l4s5vi to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32l4r5zi", "memory-x", "time-driver-any", "exti", "chrono"] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768", ] } embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/stm32l5/Cargo.toml b/examples/stm32l5/Cargo.toml index e09311f9d..2b8a2c064 100644 --- a/examples/stm32l5/Cargo.toml +++ b/examples/stm32l5/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32l552ze to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32l552ze", "time-driver-any", "exti", "memory-x", "low-power"] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } diff --git a/examples/stm32u0/Cargo.toml b/examples/stm32u0/Cargo.toml index fef695c82..11953acfc 100644 --- a/examples/stm32u0/Cargo.toml +++ b/examples/stm32u0/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32u083rc to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32u083rc", "memory-x", "unstable-pac", "exti", "chrono"] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", default-features = false, features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32u5/Cargo.toml b/examples/stm32u5/Cargo.toml index 528429f4c..68a17ce43 100644 --- a/examples/stm32u5/Cargo.toml +++ b/examples/stm32u5/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32u5g9zj to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "unstable-pac", "stm32u5g9zj", "time-driver-any", "memory-x" ] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32wb/Cargo.toml b/examples/stm32wb/Cargo.toml index 400c7b20c..ecc72397b 100644 --- a/examples/stm32wb/Cargo.toml +++ b/examples/stm32wb/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32wb55rg", "time-driver-any", "memory-x", "exti"] } embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", features = ["defmt", "stm32wb55rg"] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", ], optional=true } diff --git a/examples/stm32wba/Cargo.toml b/examples/stm32wba/Cargo.toml index 9e4251ce1..7735dfdde 100644 --- a/examples/stm32wba/Cargo.toml +++ b/examples/stm32wba/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32wba52cg", "time-driver-any", "memory-x", "exti"] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", ], optional=true } diff --git a/examples/stm32wl/Cargo.toml b/examples/stm32wl/Cargo.toml index 6507fd1eb..0182745e5 100644 --- a/examples/stm32wl/Cargo.toml +++ b/examples/stm32wl/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32wl55jc-cm4 to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32wl55jc-cm4", "time-driver-any", "memory-x", "unstable-pac", "exti", "chrono"] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-4096", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-4096", "arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } diff --git a/examples/wasm/Cargo.toml b/examples/wasm/Cargo.toml index 5e4d352b5..f5dcdc0a2 100644 --- a/examples/wasm/Cargo.toml +++ b/examples/wasm/Cargo.toml @@ -9,7 +9,7 @@ crate-type = ["cdylib"] [dependencies] embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["log"] } -embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-wasm", "executor-thread", "log", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-wasm", "executor-thread", "log"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["log", "wasm", ] } wasm-logger = "0.2.0" diff --git a/tests/nrf/Cargo.toml b/tests/nrf/Cargo.toml index 766318998..7af3d0649 100644 --- a/tests/nrf/Cargo.toml +++ b/tests/nrf/Cargo.toml @@ -9,7 +9,7 @@ teleprobe-meta = "1" embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt", ] } -embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "time-driver-rtc1", "gpiote", "unstable-pac"] } embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } diff --git a/tests/rp/Cargo.toml b/tests/rp/Cargo.toml index 7fb791578..8cd40418a 100644 --- a/tests/rp/Cargo.toml +++ b/tests/rp/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" teleprobe-meta = "1.1" embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", ] } embassy-rp = { version = "0.2.0", path = "../../embassy-rp", features = [ "defmt", "unstable-pac", "time-driver", "critical-section-impl", "intrinsics", "rom-v2-intrinsics", "run-from-ram", "rp2040"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml index 599f7c702..5ae6878cc 100644 --- a/tests/stm32/Cargo.toml +++ b/tests/stm32/Cargo.toml @@ -60,7 +60,7 @@ cm0 = ["portable-atomic/unsafe-assume-single-core"] teleprobe-meta = "1" embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "tick-hz-131_072", "defmt-timestamp-uptime"] } embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "memory-x", "time-driver-any"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } From 5c4983236c2e68b6ba2ce325ed77ec39466fc3b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Fri, 13 Dec 2024 21:45:52 +0100 Subject: [PATCH 0481/1217] Make sure an exited task does not get stuck in a timer queue --- embassy-executor/src/raw/mod.rs | 14 ++++++++++++++ embassy-executor/tests/test.rs | 4 ++++ 2 files changed, 18 insertions(+) diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs index 2feaab155..b825fa6c2 100644 --- a/embassy-executor/src/raw/mod.rs +++ b/embassy-executor/src/raw/mod.rs @@ -192,7 +192,17 @@ impl TaskStorage { match future.poll(&mut cx) { Poll::Ready(_) => { this.future.drop_in_place(); + + // Mark this task to be timer queued, to prevent re-queueing it. + this.raw.state.timer_enqueue(); + + // Now mark the task as not spawned, so that + // - it can be spawned again once it has been removed from the timer queue + // - it can not be timer-queued again this.raw.state.despawn(); + + // Schedule the task by hand in the past, so it runs immediately. + unsafe { _embassy_time_schedule_wake(0, &waker) } } Poll::Pending => {} } @@ -211,6 +221,10 @@ impl TaskStorage { } } +extern "Rust" { + fn _embassy_time_schedule_wake(at: u64, waker: &core::task::Waker); +} + /// An uninitialized [`TaskStorage`]. pub struct AvailableTask { task: &'static TaskStorage, diff --git a/embassy-executor/tests/test.rs b/embassy-executor/tests/test.rs index 0ce1f1891..992ab3da9 100644 --- a/embassy-executor/tests/test.rs +++ b/embassy-executor/tests/test.rs @@ -150,3 +150,7 @@ fn executor_task_cfg_args() { let (_, _, _) = (a, b, c); } } + +// We need this for the test to compile, even though we don't want to use timers at the moment. +#[no_mangle] +fn _embassy_time_schedule_wake(_at: u64, _waker: &core::task::Waker) {} From e861344b179b3e955ac47f1985b7f97fdfb93892 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Sun, 15 Dec 2024 17:44:42 +0100 Subject: [PATCH 0482/1217] Fix comments and tweak task exit --- embassy-executor/src/raw/mod.rs | 21 +++++++++++++++------ embassy-executor/src/raw/timer_queue.rs | 5 +++-- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs index b825fa6c2..7da14468d 100644 --- a/embassy-executor/src/raw/mod.rs +++ b/embassy-executor/src/raw/mod.rs @@ -94,13 +94,14 @@ impl TaskRef { &self.header().timer_queue_item } - /// Mark the task as timer-queued. Return whether it was newly queued (i.e. not queued before) + /// Mark the task as timer-queued. Return whether it should be actually enqueued + /// using `_embassy_time_schedule_wake`. /// /// Entering this state prevents the task from being respawned while in a timer queue. /// /// Safety: /// - /// This functions should only be called by the timer queue implementation, before + /// This functions should only be called by the timer queue driver, before /// enqueueing the timer item. pub unsafe fn timer_enqueue(&self) -> timer_queue::TimerEnqueueOperation { self.header().state.timer_enqueue() @@ -193,16 +194,24 @@ impl TaskStorage { Poll::Ready(_) => { this.future.drop_in_place(); - // Mark this task to be timer queued, to prevent re-queueing it. - this.raw.state.timer_enqueue(); + // Mark this task to be timer queued. + // We're splitting the enqueue in two parts, so that we can change task state + // to something that prevent re-queueing. + let op = this.raw.state.timer_enqueue(); // Now mark the task as not spawned, so that // - it can be spawned again once it has been removed from the timer queue // - it can not be timer-queued again + // We must do this before scheduling the wake, to prevent the task from being + // dequeued by the time driver while it's still SPAWNED. this.raw.state.despawn(); - // Schedule the task by hand in the past, so it runs immediately. - unsafe { _embassy_time_schedule_wake(0, &waker) } + // Now let's finish enqueueing. While we shouldn't get an `Ignore` here, it's + // better to be safe. + if op == timer_queue::TimerEnqueueOperation::Enqueue { + // Schedule the task in the past, so it gets dequeued ASAP. + unsafe { _embassy_time_schedule_wake(0, &waker) } + } } Poll::Pending => {} } diff --git a/embassy-executor/src/raw/timer_queue.rs b/embassy-executor/src/raw/timer_queue.rs index c36708401..cd9a73822 100644 --- a/embassy-executor/src/raw/timer_queue.rs +++ b/embassy-executor/src/raw/timer_queue.rs @@ -30,9 +30,10 @@ impl TimerQueueItem { /// The operation to perform after `timer_enqueue` is called. #[derive(Debug, Copy, Clone, PartialEq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[must_use] pub enum TimerEnqueueOperation { - /// Enqueue the task. + /// Enqueue the task (or update its expiration time). Enqueue, - /// Update the task's expiration time. + /// The task must not be enqueued in the timer queue. Ignore, } From 0492dba5368e7cb22ede2d41d26d4d0431ba2252 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Sun, 15 Dec 2024 19:24:49 +0100 Subject: [PATCH 0483/1217] Update documentation and changelogs --- embassy-time-driver/CHANGELOG.md | 3 +- embassy-time-driver/src/lib.rs | 79 +++++++++++++++++++------- embassy-time-queue-driver/CHANGELOG.md | 5 +- embassy-time-queue-driver/src/lib.rs | 49 ++-------------- 4 files changed, 69 insertions(+), 67 deletions(-) diff --git a/embassy-time-driver/CHANGELOG.md b/embassy-time-driver/CHANGELOG.md index ebc37b6f4..2af1dc736 100644 --- a/embassy-time-driver/CHANGELOG.md +++ b/embassy-time-driver/CHANGELOG.md @@ -1,4 +1,4 @@ -# Changelog for embassy-time-queue-driver +# Changelog for embassy-time-driver All notable changes to this project will be documented in this file. @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased - The `allocate_alarm`, `set_alarm_callback`, `set_alarm` functions have been removed. +- `schedule_wake` has been added to the `Driver` trait. ## 0.1.0 - 2024-01-11 diff --git a/embassy-time-driver/src/lib.rs b/embassy-time-driver/src/lib.rs index 090969d8c..57a9f7587 100644 --- a/embassy-time-driver/src/lib.rs +++ b/embassy-time-driver/src/lib.rs @@ -17,25 +17,7 @@ //! Otherwise, don’t enable any `tick-hz-*` feature to let the user configure the tick rate themselves by //! enabling a feature on `embassy-time`. //! -//! # Linkage details -//! -//! Instead of the usual "trait + generic params" approach, calls from embassy to the driver are done via `extern` functions. -//! -//! `embassy` internally defines the driver function as `extern "Rust" { fn _embassy_time_now() -> u64; }` and calls it. -//! The driver crate defines the function as `#[no_mangle] fn _embassy_time_now() -> u64`. The linker will resolve the -//! calls from the `embassy` crate to call into the driver crate. -//! -//! If there is none or multiple drivers in the crate tree, linking will fail. -//! -//! This method has a few key advantages for something as foundational as timekeeping: -//! -//! - The time driver is available everywhere easily, without having to thread the implementation -//! through generic parameters. This is especially helpful for libraries. -//! - It means comparing `Instant`s will always make sense: if there were multiple drivers -//! active, one could compare an `Instant` from driver A to an `Instant` from driver B, which -//! would yield incorrect results. -//! -//! # Example +//! ### Example //! //! ``` //! use core::task::Waker; @@ -56,6 +38,65 @@ //! //! embassy_time_driver::time_driver_impl!(static DRIVER: MyDriver = MyDriver{}); //! ``` +//! +//! ## Implementing the timer queue +//! +//! The simplest (but suboptimal) way to implement a timer queue is to define a single queue in the +//! time driver. Declare a field protected by an appropriate mutex (e.g. `critical_section::Mutex`). +//! +//! Then, you'll need to adapt the `schedule_wake` method to use this queue. +//! +//! ```ignore +//! use core::cell::RefCell; +//! use core::task::Waker; +//! +//! use embassy_time_queue_driver::Queue; +//! use embassy_time_driver::Driver; +//! +//! struct MyDriver { +//! timer_queue: critical_section::Mutex>, +//! } +//! +//! impl MyDriver { +//! fn set_alarm(&self, cs: &CriticalSection, at: u64) -> bool { +//! todo!() +//! } +//! } +//! +//! impl Driver for MyDriver { +//! // fn now(&self) -> u64 { ... } +//! +//! fn schedule_wake(&self, at: u64, waker: &Waker) { +//! critical_section::with(|cs| { +//! let mut queue = self.queue.borrow(cs).borrow_mut(); +//! if queue.schedule_wake(at, waker) { +//! let mut next = queue.next_expiration(self.now()); +//! while !self.set_alarm(cs, next) { +//! next = queue.next_expiration(self.now()); +//! } +//! } +//! }); +//! } +//! } +//! ``` +//! +//! # Linkage details +//! +//! Instead of the usual "trait + generic params" approach, calls from embassy to the driver are done via `extern` functions. +//! +//! `embassy` internally defines the driver function as `extern "Rust" { fn _embassy_time_now() -> u64; }` and calls it. +//! The driver crate defines the function as `#[no_mangle] fn _embassy_time_now() -> u64`. The linker will resolve the +//! calls from the `embassy` crate to call into the driver crate. +//! +//! If there is none or multiple drivers in the crate tree, linking will fail. +//! +//! This method has a few key advantages for something as foundational as timekeeping: +//! +//! - The time driver is available everywhere easily, without having to thread the implementation +//! through generic parameters. This is especially helpful for libraries. +//! - It means comparing `Instant`s will always make sense: if there were multiple drivers +//! active, one could compare an `Instant` from driver A to an `Instant` from driver B, which +//! would yield incorrect results. //! ## Feature flags #![doc = document_features::document_features!(feature_label = r#"{feature}"#)] diff --git a/embassy-time-queue-driver/CHANGELOG.md b/embassy-time-queue-driver/CHANGELOG.md index 3b2aa8695..a99f250ed 100644 --- a/embassy-time-queue-driver/CHANGELOG.md +++ b/embassy-time-queue-driver/CHANGELOG.md @@ -7,9 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased -- Added `integrated-timers` and `generic-queue-N` features -- Added `queue_generic` module which contains `Queue` (configured via the `generic-queue-N` features) and `ConstGenericQueue`. -- Added `GenericTimerQueue` and `GlobalTimerQueue` structs that can be used to implement timer queues. +- Added `generic-queue-N` features. +- Added `embassy_time_queue_driver::Queue` struct which uses integrated or a generic storage (configured using `generic-queue-N`). ## 0.1.0 - 2024-01-11 diff --git a/embassy-time-queue-driver/src/lib.rs b/embassy-time-queue-driver/src/lib.rs index 46dd646ca..d8b01df3b 100644 --- a/embassy-time-queue-driver/src/lib.rs +++ b/embassy-time-queue-driver/src/lib.rs @@ -2,52 +2,13 @@ #![doc = include_str!("../README.md")] #![warn(missing_docs)] -//! ## Implementing a timer queue +//! This crate is an implementation detail of `embassy-time-driver`. //! -//! - Define a struct `MyTimerQueue` -//! - Implement [`TimerQueue`] for it -//! - Register it as the global timer queue with [`timer_queue_impl`]. -//! - Ensure that you process the timer queue when `schedule_wake` is due. This usually involves -//! waking expired tasks, finding the next expiration time and setting an alarm. +//! As a HAL user, you should only depend on this crate if your application does not use +//! `embassy-executor` and your HAL does not configure a generic queue by itself. //! -//! If a single global timer queue is sufficient for you, you can use the -//! [`GlobalTimerQueue`] type, which is a wrapper around a global timer queue -//! protected by a critical section. -//! -//! ``` -//! use embassy_time_queue_driver::GlobalTimerQueue; -//! embassy_time_queue_driver::timer_queue_impl!( -//! static TIMER_QUEUE_DRIVER: GlobalTimerQueue -//! = GlobalTimerQueue::new(|next_expiration| todo!("Set an alarm")) -//! ); -//! ``` -//! -//! You can also use the `queue_generic` or the `queue_integrated` modules to implement your own -//! timer queue. These modules contain queue implementations which you can wrap and tailor to -//! your needs. -//! -//! If you are providing an embassy-executor implementation besides a timer queue, you can choose to -//! expose the `integrated-timers` feature in your implementation. This feature stores timer items -//! in the tasks themselves, so you don't need a fixed-size queue or dynamic memory allocation. -//! -//! ## Example -//! -//! ``` -//! use core::task::Waker; -//! -//! use embassy_time::Instant; -//! use embassy_time::queue::TimerQueue; -//! -//! struct MyTimerQueue{}; // not public! -//! -//! impl TimerQueue for MyTimerQueue { -//! fn schedule_wake(&'static self, at: u64, waker: &Waker) { -//! todo!() -//! } -//! } -//! -//! embassy_time_queue_driver::timer_queue_impl!(static QUEUE: MyTimerQueue = MyTimerQueue{}); -//! ``` +//! As a HAL implementer, you need to depend on this crate if you want to implement a time driver, +//! but how you should do so is documented in [`embassy_time_driver`]. use core::task::Waker; From e77ac50248639e299f93b1820e73c9df9ceb09e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Sun, 15 Dec 2024 20:27:08 +0100 Subject: [PATCH 0484/1217] Remove critical_section dependency --- embassy-time-queue-driver/Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/embassy-time-queue-driver/Cargo.toml b/embassy-time-queue-driver/Cargo.toml index 7a10e29b4..208b64668 100644 --- a/embassy-time-queue-driver/Cargo.toml +++ b/embassy-time-queue-driver/Cargo.toml @@ -21,7 +21,6 @@ categories = [ links = "embassy-time-queue" [dependencies] -critical-section = "1.2.0" heapless = "0.8" embassy-executor = { version = "0.6.3", path = "../embassy-executor" } embassy-time-driver = { version = "0.1.0", path = "../embassy-time-driver" } From 4df4ffbbd49729cde38a3a4a73cdafd208372a53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Sun, 15 Dec 2024 20:28:12 +0100 Subject: [PATCH 0485/1217] Remove time-driver dependency --- embassy-time-queue-driver/Cargo.toml | 1 - embassy-time-queue-driver/src/lib.rs | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/embassy-time-queue-driver/Cargo.toml b/embassy-time-queue-driver/Cargo.toml index 208b64668..a104f5c39 100644 --- a/embassy-time-queue-driver/Cargo.toml +++ b/embassy-time-queue-driver/Cargo.toml @@ -23,7 +23,6 @@ links = "embassy-time-queue" [dependencies] heapless = "0.8" embassy-executor = { version = "0.6.3", path = "../embassy-executor" } -embassy-time-driver = { version = "0.1.0", path = "../embassy-time-driver" } [features] #! ### Generic Queue diff --git a/embassy-time-queue-driver/src/lib.rs b/embassy-time-queue-driver/src/lib.rs index d8b01df3b..97c81a124 100644 --- a/embassy-time-queue-driver/src/lib.rs +++ b/embassy-time-queue-driver/src/lib.rs @@ -8,7 +8,7 @@ //! `embassy-executor` and your HAL does not configure a generic queue by itself. //! //! As a HAL implementer, you need to depend on this crate if you want to implement a time driver, -//! but how you should do so is documented in [`embassy_time_driver`]. +//! but how you should do so is documented in `embassy-time-driver`. use core::task::Waker; From a10290b28e41922b0f53aafbcc82c49ee3f4e22f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Mon, 16 Dec 2024 09:15:15 +0100 Subject: [PATCH 0486/1217] Zero-inizialize expires_at --- embassy-executor/src/raw/timer_queue.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-executor/src/raw/timer_queue.rs b/embassy-executor/src/raw/timer_queue.rs index cd9a73822..2ba0e00a9 100644 --- a/embassy-executor/src/raw/timer_queue.rs +++ b/embassy-executor/src/raw/timer_queue.rs @@ -22,7 +22,7 @@ impl TimerQueueItem { pub(crate) const fn new() -> Self { Self { next: Cell::new(None), - expires_at: Cell::new(u64::MAX), + expires_at: Cell::new(0), } } } From e1c00613288024623f7fde61f65c4c40c9a5381a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Mon, 16 Dec 2024 12:54:45 +0100 Subject: [PATCH 0487/1217] Disable failing test --- ci.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ci.sh b/ci.sh index cb3a2f3f7..6b523193c 100755 --- a/ci.sh +++ b/ci.sh @@ -302,6 +302,9 @@ rm out/tests/stm32wb55rg/wpan_ble # unstable, I think it's running out of RAM? rm out/tests/stm32f207zg/eth +# temporarily disabled, hard faults for unknown reasons +rm out/tests/stm32f207zg/usart_rx_ringbuffered + # doesn't work, gives "noise error", no idea why. usart_dma does pass. rm out/tests/stm32u5a5zj/usart From f389ba37219d842d7db0ab94cd421c69645a5757 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Fri, 13 Dec 2024 20:35:40 +0100 Subject: [PATCH 0488/1217] Only lock once to wake a task --- embassy-executor/src/raw/mod.rs | 20 +++++---- embassy-executor/src/raw/run_queue_atomics.rs | 2 +- .../src/raw/run_queue_critical_section.rs | 10 ++--- embassy-executor/src/raw/state_atomics.rs | 20 +++++++-- embassy-executor/src/raw/state_atomics_arm.rs | 19 +++++++-- .../src/raw/state_critical_section.rs | 42 +++++++++++-------- 6 files changed, 73 insertions(+), 40 deletions(-) diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs index 7da14468d..bcbd214a9 100644 --- a/embassy-executor/src/raw/mod.rs +++ b/embassy-executor/src/raw/mod.rs @@ -386,11 +386,11 @@ impl SyncExecutor { /// - `task` must be set up to run in this executor. /// - `task` must NOT be already enqueued (in this executor or another one). #[inline(always)] - unsafe fn enqueue(&self, task: TaskRef) { + unsafe fn enqueue(&self, task: TaskRef, l: state::Token) { #[cfg(feature = "trace")] trace::task_ready_begin(self, &task); - if self.run_queue.enqueue(task) { + if self.run_queue.enqueue(task, l) { self.pender.pend(); } } @@ -401,7 +401,9 @@ impl SyncExecutor { #[cfg(feature = "trace")] trace::task_new(self, &task); - self.enqueue(task); + state::locked(|l| { + self.enqueue(task, l); + }) } /// # Safety @@ -544,13 +546,13 @@ impl Executor { /// You can obtain a `TaskRef` from a `Waker` using [`task_from_waker`]. pub fn wake_task(task: TaskRef) { let header = task.header(); - if header.state.run_enqueue() { + header.state.run_enqueue(|l| { // We have just marked the task as scheduled, so enqueue it. unsafe { let executor = header.executor.get().unwrap_unchecked(); - executor.enqueue(task); + executor.enqueue(task, l); } - } + }); } /// Wake a task by `TaskRef` without calling pend. @@ -558,11 +560,11 @@ pub fn wake_task(task: TaskRef) { /// You can obtain a `TaskRef` from a `Waker` using [`task_from_waker`]. pub fn wake_task_no_pend(task: TaskRef) { let header = task.header(); - if header.state.run_enqueue() { + header.state.run_enqueue(|l| { // We have just marked the task as scheduled, so enqueue it. unsafe { let executor = header.executor.get().unwrap_unchecked(); - executor.run_queue.enqueue(task); + executor.run_queue.enqueue(task, l); } - } + }); } diff --git a/embassy-executor/src/raw/run_queue_atomics.rs b/embassy-executor/src/raw/run_queue_atomics.rs index 90907cfda..efdafdff0 100644 --- a/embassy-executor/src/raw/run_queue_atomics.rs +++ b/embassy-executor/src/raw/run_queue_atomics.rs @@ -45,7 +45,7 @@ impl RunQueue { /// /// `item` must NOT be already enqueued in any queue. #[inline(always)] - pub(crate) unsafe fn enqueue(&self, task: TaskRef) -> bool { + pub(crate) unsafe fn enqueue(&self, task: TaskRef, _: super::state::Token) -> bool { let mut was_empty = false; self.head diff --git a/embassy-executor/src/raw/run_queue_critical_section.rs b/embassy-executor/src/raw/run_queue_critical_section.rs index ba59c8f29..90f09e8c8 100644 --- a/embassy-executor/src/raw/run_queue_critical_section.rs +++ b/embassy-executor/src/raw/run_queue_critical_section.rs @@ -44,13 +44,11 @@ impl RunQueue { /// /// `item` must NOT be already enqueued in any queue. #[inline(always)] - pub(crate) unsafe fn enqueue(&self, task: TaskRef) -> bool { - critical_section::with(|cs| { - let prev = self.head.borrow(cs).replace(Some(task)); - task.header().run_queue_item.next.borrow(cs).set(prev); + pub(crate) unsafe fn enqueue(&self, task: TaskRef, cs: CriticalSection<'_>) -> bool { + let prev = self.head.borrow(cs).replace(Some(task)); + task.header().run_queue_item.next.borrow(cs).set(prev); - prev.is_none() - }) + prev.is_none() } /// Empty the queue, then call `on_task` for each task that was in the queue. diff --git a/embassy-executor/src/raw/state_atomics.rs b/embassy-executor/src/raw/state_atomics.rs index 15eb9a368..abfe94486 100644 --- a/embassy-executor/src/raw/state_atomics.rs +++ b/embassy-executor/src/raw/state_atomics.rs @@ -2,6 +2,15 @@ use core::sync::atomic::{AtomicU32, Ordering}; use super::timer_queue::TimerEnqueueOperation; +pub(crate) struct Token(()); + +/// Creates a token and passes it to the closure. +/// +/// This is a no-op replacement for `CriticalSection::with` because we don't need any locking. +pub(crate) fn locked(f: impl FnOnce(Token)) { + f(Token(())); +} + /// Task is spawned (has a future) pub(crate) const STATE_SPAWNED: u32 = 1 << 0; /// Task is in the executor run queue @@ -34,10 +43,12 @@ impl State { self.state.fetch_and(!STATE_SPAWNED, Ordering::AcqRel); } - /// Mark the task as run-queued if it's spawned and isn't already run-queued. Return true on success. + /// Mark the task as run-queued if it's spawned and isn't already run-queued. Run the given + /// function if the task was successfully marked. #[inline(always)] - pub fn run_enqueue(&self) -> bool { - self.state + pub fn run_enqueue(&self, f: impl FnOnce(Token)) { + if self + .state .fetch_update(Ordering::SeqCst, Ordering::SeqCst, |state| { // If already scheduled, or if not started, if (state & STATE_RUN_QUEUED != 0) || (state & STATE_SPAWNED == 0) { @@ -48,6 +59,9 @@ impl State { } }) .is_ok() + { + locked(f); + } } /// Unmark the task as run-queued. Return whether the task is spawned. diff --git a/embassy-executor/src/raw/state_atomics_arm.rs b/embassy-executor/src/raw/state_atomics_arm.rs index 7a152e8c0..f0f014652 100644 --- a/embassy-executor/src/raw/state_atomics_arm.rs +++ b/embassy-executor/src/raw/state_atomics_arm.rs @@ -3,6 +3,15 @@ use core::sync::atomic::{compiler_fence, AtomicBool, AtomicU32, Ordering}; use super::timer_queue::TimerEnqueueOperation; +pub(crate) struct Token(()); + +/// Creates a token and passes it to the closure. +/// +/// This is a no-op replacement for `CriticalSection::with` because we don't need any locking. +pub(crate) fn locked(f: impl FnOnce(Token)) { + f(Token(())); +} + // Must be kept in sync with the layout of `State`! pub(crate) const STATE_SPAWNED: u32 = 1 << 0; pub(crate) const STATE_RUN_QUEUED: u32 = 1 << 8; @@ -57,9 +66,10 @@ impl State { self.spawned.store(false, Ordering::Relaxed); } - /// Mark the task as run-queued if it's spawned and isn't already run-queued. Return true on success. + /// Mark the task as run-queued if it's spawned and isn't already run-queued. Run the given + /// function if the task was successfully marked. #[inline(always)] - pub fn run_enqueue(&self) -> bool { + pub fn run_enqueue(&self, f: impl FnOnce(Token)) { unsafe { loop { let state: u32; @@ -67,14 +77,15 @@ impl State { if (state & STATE_RUN_QUEUED != 0) || (state & STATE_SPAWNED == 0) { asm!("clrex", options(nomem, nostack)); - return false; + return; } let outcome: usize; let new_state = state | STATE_RUN_QUEUED; asm!("strex {}, {}, [{}]", out(reg) outcome, in(reg) new_state, in(reg) self, options(nostack)); if outcome == 0 { - return true; + locked(f); + return; } } } diff --git a/embassy-executor/src/raw/state_critical_section.rs b/embassy-executor/src/raw/state_critical_section.rs index 367162ba2..8e570b33c 100644 --- a/embassy-executor/src/raw/state_critical_section.rs +++ b/embassy-executor/src/raw/state_critical_section.rs @@ -1,6 +1,7 @@ use core::cell::Cell; -use critical_section::Mutex; +pub(crate) use critical_section::{with as locked, CriticalSection as Token}; +use critical_section::{CriticalSection, Mutex}; use super::timer_queue::TimerEnqueueOperation; @@ -23,13 +24,15 @@ impl State { } fn update(&self, f: impl FnOnce(&mut u32) -> R) -> R { - critical_section::with(|cs| { - let s = self.state.borrow(cs); - let mut val = s.get(); - let r = f(&mut val); - s.set(val); - r - }) + critical_section::with(|cs| self.update_with_cs(cs, f)) + } + + fn update_with_cs(&self, cs: CriticalSection<'_>, f: impl FnOnce(&mut u32) -> R) -> R { + let s = self.state.borrow(cs); + let mut val = s.get(); + let r = f(&mut val); + s.set(val); + r } /// If task is idle, mark it as spawned + run_queued and return true. @@ -51,17 +54,22 @@ impl State { self.update(|s| *s &= !STATE_SPAWNED); } - /// Mark the task as run-queued if it's spawned and isn't already run-queued. Return true on success. + /// Mark the task as run-queued if it's spawned and isn't already run-queued. Run the given + /// function if the task was successfully marked. #[inline(always)] - pub fn run_enqueue(&self) -> bool { - self.update(|s| { - if (*s & STATE_RUN_QUEUED != 0) || (*s & STATE_SPAWNED == 0) { - false - } else { - *s |= STATE_RUN_QUEUED; - true + pub fn run_enqueue(&self, f: impl FnOnce(Token)) { + critical_section::with(|cs| { + if self.update_with_cs(cs, |s| { + if (*s & STATE_RUN_QUEUED != 0) || (*s & STATE_SPAWNED == 0) { + false + } else { + *s |= STATE_RUN_QUEUED; + true + } + }) { + f(cs); } - }) + }); } /// Unmark the task as run-queued. Return whether the task is spawned. From b44ef5ccb40d6b778e623e6e68a234c2e0615d25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Mon, 16 Dec 2024 15:56:55 +0100 Subject: [PATCH 0489/1217] Fix racy access of TaskHeader::executor --- embassy-executor/src/raw/mod.rs | 70 +++++++++++++++++-- embassy-executor/src/raw/state_atomics.rs | 5 +- embassy-executor/src/raw/state_atomics_arm.rs | 5 +- embassy-executor/src/spawner.rs | 8 ++- 4 files changed, 75 insertions(+), 13 deletions(-) diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs index bcbd214a9..808a78389 100644 --- a/embassy-executor/src/raw/mod.rs +++ b/embassy-executor/src/raw/mod.rs @@ -14,7 +14,58 @@ mod run_queue; #[cfg_attr(all(cortex_m, target_has_atomic = "8"), path = "state_atomics_arm.rs")] #[cfg_attr(all(not(cortex_m), target_has_atomic = "8"), path = "state_atomics.rs")] #[cfg_attr(not(target_has_atomic = "8"), path = "state_critical_section.rs")] -mod state; +pub(crate) mod state; + +#[cfg(target_has_atomic = "ptr")] +mod owner { + use core::sync::atomic::{AtomicPtr, Ordering}; + + use super::{state::Token, SyncExecutor}; + + pub(crate) struct ExecutorRef(AtomicPtr); + + impl ExecutorRef { + pub const fn new() -> Self { + Self(AtomicPtr::new(core::ptr::null_mut())) + } + + pub fn set(&self, executor: Option<&'static SyncExecutor>, _: Token) { + let ptr = executor.map(|e| e as *const SyncExecutor).unwrap_or(core::ptr::null()); + self.0.store(ptr.cast_mut(), Ordering::Release); + } + + pub fn get(&self, _: Token) -> *const SyncExecutor { + self.0.load(Ordering::Acquire).cast_const() + } + } +} +#[cfg(not(target_has_atomic = "ptr"))] +mod owner { + use super::{state::Token, SyncExecutor}; + use core::cell::Cell; + + use critical_section::Mutex; + + pub(crate) struct ExecutorRef(Mutex>); + + unsafe impl Send for ExecutorRef {} + unsafe impl Sync for ExecutorRef {} + + impl ExecutorRef { + pub const fn new() -> Self { + Self(Mutex::new(Cell::new(core::ptr::null()))) + } + + pub fn set(&self, executor: Option<&'static SyncExecutor>, cs: Token) { + let ptr = executor.map(|e| e as *const SyncExecutor).unwrap_or(core::ptr::null()); + self.0.borrow(cs).set(ptr); + } + + pub fn get(&self, cs: Token) -> *const SyncExecutor { + self.0.borrow(cs).get() + } + } +} pub mod timer_queue; #[cfg(feature = "trace")] @@ -30,6 +81,8 @@ use core::pin::Pin; use core::ptr::NonNull; use core::task::{Context, Poll}; +use crate::raw::owner::ExecutorRef; + use self::run_queue::{RunQueue, RunQueueItem}; use self::state::State; use self::util::{SyncUnsafeCell, UninitCell}; @@ -40,7 +93,7 @@ use super::SpawnToken; pub(crate) struct TaskHeader { pub(crate) state: State, pub(crate) run_queue_item: RunQueueItem, - pub(crate) executor: SyncUnsafeCell>, + pub(crate) executor: ExecutorRef, poll_fn: SyncUnsafeCell>, /// Integrated timer queue storage. This field should not be accessed outside of the timer queue. @@ -86,7 +139,8 @@ impl TaskRef { /// Returns a reference to the executor that the task is currently running on. pub unsafe fn executor(self) -> Option<&'static Executor> { - self.header().executor.get().map(|e| Executor::wrap(e)) + let executor = state::locked(|token| self.header().executor.get(token)); + executor.as_ref().map(|e| Executor::wrap(e)) } /// Returns a reference to the timer queue item. @@ -153,7 +207,7 @@ impl TaskStorage { raw: TaskHeader { state: State::new(), run_queue_item: RunQueueItem::new(), - executor: SyncUnsafeCell::new(None), + executor: ExecutorRef::new(), // Note: this is lazily initialized so that a static `TaskStorage` will go in `.bss` poll_fn: SyncUnsafeCell::new(None), @@ -396,7 +450,9 @@ impl SyncExecutor { } pub(super) unsafe fn spawn(&'static self, task: TaskRef) { - task.header().executor.set(Some(self)); + state::locked(|l| { + task.header().executor.set(Some(self), l); + }); #[cfg(feature = "trace")] trace::task_new(self, &task); @@ -549,7 +605,7 @@ pub fn wake_task(task: TaskRef) { header.state.run_enqueue(|l| { // We have just marked the task as scheduled, so enqueue it. unsafe { - let executor = header.executor.get().unwrap_unchecked(); + let executor = header.executor.get(l).as_ref().unwrap_unchecked(); executor.enqueue(task, l); } }); @@ -563,7 +619,7 @@ pub fn wake_task_no_pend(task: TaskRef) { header.state.run_enqueue(|l| { // We have just marked the task as scheduled, so enqueue it. unsafe { - let executor = header.executor.get().unwrap_unchecked(); + let executor = header.executor.get(l).as_ref().unwrap_unchecked(); executor.run_queue.enqueue(task, l); } }); diff --git a/embassy-executor/src/raw/state_atomics.rs b/embassy-executor/src/raw/state_atomics.rs index abfe94486..d7350464f 100644 --- a/embassy-executor/src/raw/state_atomics.rs +++ b/embassy-executor/src/raw/state_atomics.rs @@ -2,13 +2,14 @@ use core::sync::atomic::{AtomicU32, Ordering}; use super::timer_queue::TimerEnqueueOperation; +#[derive(Clone, Copy)] pub(crate) struct Token(()); /// Creates a token and passes it to the closure. /// /// This is a no-op replacement for `CriticalSection::with` because we don't need any locking. -pub(crate) fn locked(f: impl FnOnce(Token)) { - f(Token(())); +pub(crate) fn locked(f: impl FnOnce(Token) -> R) -> R { + f(Token(())) } /// Task is spawned (has a future) diff --git a/embassy-executor/src/raw/state_atomics_arm.rs b/embassy-executor/src/raw/state_atomics_arm.rs index f0f014652..c1e8f69ab 100644 --- a/embassy-executor/src/raw/state_atomics_arm.rs +++ b/embassy-executor/src/raw/state_atomics_arm.rs @@ -3,13 +3,14 @@ use core::sync::atomic::{compiler_fence, AtomicBool, AtomicU32, Ordering}; use super::timer_queue::TimerEnqueueOperation; +#[derive(Clone, Copy)] pub(crate) struct Token(()); /// Creates a token and passes it to the closure. /// /// This is a no-op replacement for `CriticalSection::with` because we don't need any locking. -pub(crate) fn locked(f: impl FnOnce(Token)) { - f(Token(())); +pub(crate) fn locked(f: impl FnOnce(Token) -> R) -> R { + f(Token(())) } // Must be kept in sync with the layout of `State`! diff --git a/embassy-executor/src/spawner.rs b/embassy-executor/src/spawner.rs index 271606244..bc243bee7 100644 --- a/embassy-executor/src/spawner.rs +++ b/embassy-executor/src/spawner.rs @@ -92,7 +92,9 @@ impl Spawner { pub async fn for_current_executor() -> Self { poll_fn(|cx| { let task = raw::task_from_waker(cx.waker()); - let executor = unsafe { task.header().executor.get().unwrap_unchecked() }; + let executor = raw::state::locked(|l| { + unsafe { task.header().executor.get(l).as_ref().unwrap_unchecked() } + }); let executor = unsafe { raw::Executor::wrap(executor) }; Poll::Ready(Self::new(executor)) }) @@ -164,7 +166,9 @@ impl SendSpawner { pub async fn for_current_executor() -> Self { poll_fn(|cx| { let task = raw::task_from_waker(cx.waker()); - let executor = unsafe { task.header().executor.get().unwrap_unchecked() }; + let executor = raw::state::locked(|l| { + unsafe { task.header().executor.get(l).as_ref().unwrap_unchecked() } + }); Poll::Ready(Self::new(executor)) }) .await From 87280463b24ce4d50b655aa526ab034b0dc2ad61 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 28 Nov 2024 17:59:45 +0100 Subject: [PATCH 0490/1217] Update to Rust 1.83 --- rust-toolchain.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 69a964040..704d2e3a2 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,5 +1,5 @@ [toolchain] -channel = "1.82" +channel = "1.83" components = [ "rust-src", "rustfmt", "llvm-tools" ] targets = [ "thumbv7em-none-eabi", From 2846647c94d75b433232c959655b88558c560767 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 16 Dec 2024 16:09:01 +0100 Subject: [PATCH 0491/1217] Remove use of static mut. --- examples/stm32f4/src/bin/usb_uac_speaker.rs | 19 +++++++++++-------- examples/stm32h5/src/bin/usb_uac_speaker.rs | 19 +++++++++++-------- 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/examples/stm32f4/src/bin/usb_uac_speaker.rs b/examples/stm32f4/src/bin/usb_uac_speaker.rs index 8d83afd1a..e22e07e63 100644 --- a/examples/stm32f4/src/bin/usb_uac_speaker.rs +++ b/examples/stm32f4/src/bin/usb_uac_speaker.rs @@ -1,7 +1,7 @@ #![no_std] #![no_main] -use core::cell::RefCell; +use core::cell::{Cell, RefCell}; use defmt::{panic, *}; use embassy_executor::Spawner; @@ -217,8 +217,8 @@ async fn usb_control_task(control_monitor: speaker::ControlMonitor<'static>) { /// This gives an (ideal) counter value of 336.000 for every update of the `FEEDBACK_SIGNAL`. #[interrupt] fn TIM2() { - static mut LAST_TICKS: u32 = 0; - static mut FRAME_COUNT: usize = 0; + static LAST_TICKS: Mutex> = Mutex::new(Cell::new(0)); + static FRAME_COUNT: Mutex> = Mutex::new(Cell::new(0)); critical_section::with(|cs| { // Read timer counter. @@ -230,11 +230,14 @@ fn TIM2() { if status.ccif(CHANNEL_INDEX) { let ticks = timer.ccr(CHANNEL_INDEX).read(); - *FRAME_COUNT += 1; - if *FRAME_COUNT >= FEEDBACK_REFRESH_PERIOD.frame_count() { - *FRAME_COUNT = 0; - FEEDBACK_SIGNAL.signal(ticks.wrapping_sub(*LAST_TICKS)); - *LAST_TICKS = ticks; + let frame_count = FRAME_COUNT.borrow(cs); + let last_ticks = LAST_TICKS.borrow(cs); + + frame_count.set(frame_count.get() + 1); + if frame_count.get() >= FEEDBACK_REFRESH_PERIOD.frame_count() { + frame_count.set(0); + FEEDBACK_SIGNAL.signal(ticks.wrapping_sub(last_ticks.get())); + last_ticks.set(ticks); } }; diff --git a/examples/stm32h5/src/bin/usb_uac_speaker.rs b/examples/stm32h5/src/bin/usb_uac_speaker.rs index 4fd4ccbbd..8c24fa916 100644 --- a/examples/stm32h5/src/bin/usb_uac_speaker.rs +++ b/examples/stm32h5/src/bin/usb_uac_speaker.rs @@ -1,7 +1,7 @@ #![no_std] #![no_main] -use core::cell::RefCell; +use core::cell::{Cell, RefCell}; use defmt::{panic, *}; use embassy_executor::Spawner; @@ -212,8 +212,8 @@ async fn usb_control_task(control_monitor: speaker::ControlMonitor<'static>) { /// This gives an (ideal) counter value of 336.000 for every update of the `FEEDBACK_SIGNAL`. #[interrupt] fn TIM5() { - static mut LAST_TICKS: u32 = 0; - static mut FRAME_COUNT: usize = 0; + static LAST_TICKS: Mutex> = Mutex::new(Cell::new(0)); + static FRAME_COUNT: Mutex> = Mutex::new(Cell::new(0)); critical_section::with(|cs| { // Read timer counter. @@ -225,11 +225,14 @@ fn TIM5() { if status.ccif(CHANNEL_INDEX) { let ticks = timer.ccr(CHANNEL_INDEX).read(); - *FRAME_COUNT += 1; - if *FRAME_COUNT >= FEEDBACK_REFRESH_PERIOD.frame_count() { - *FRAME_COUNT = 0; - FEEDBACK_SIGNAL.signal(ticks.wrapping_sub(*LAST_TICKS)); - *LAST_TICKS = ticks; + let frame_count = FRAME_COUNT.borrow(cs); + let last_ticks = LAST_TICKS.borrow(cs); + + frame_count.set(frame_count.get() + 1); + if frame_count.get() >= FEEDBACK_REFRESH_PERIOD.frame_count() { + frame_count.set(0); + FEEDBACK_SIGNAL.signal(ticks.wrapping_sub(last_ticks.get())); + last_ticks.set(ticks); } }; From b47a631abf0c200c3b29b8e4ec199421835a0525 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Mon, 16 Dec 2024 17:24:17 +0100 Subject: [PATCH 0492/1217] Rely on atomic load-store on all targets --- embassy-executor/src/raw/mod.rs | 72 +++++---------------------------- embassy-executor/src/spawner.rs | 21 +++++++--- 2 files changed, 25 insertions(+), 68 deletions(-) diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs index 808a78389..5a476213b 100644 --- a/embassy-executor/src/raw/mod.rs +++ b/embassy-executor/src/raw/mod.rs @@ -14,58 +14,7 @@ mod run_queue; #[cfg_attr(all(cortex_m, target_has_atomic = "8"), path = "state_atomics_arm.rs")] #[cfg_attr(all(not(cortex_m), target_has_atomic = "8"), path = "state_atomics.rs")] #[cfg_attr(not(target_has_atomic = "8"), path = "state_critical_section.rs")] -pub(crate) mod state; - -#[cfg(target_has_atomic = "ptr")] -mod owner { - use core::sync::atomic::{AtomicPtr, Ordering}; - - use super::{state::Token, SyncExecutor}; - - pub(crate) struct ExecutorRef(AtomicPtr); - - impl ExecutorRef { - pub const fn new() -> Self { - Self(AtomicPtr::new(core::ptr::null_mut())) - } - - pub fn set(&self, executor: Option<&'static SyncExecutor>, _: Token) { - let ptr = executor.map(|e| e as *const SyncExecutor).unwrap_or(core::ptr::null()); - self.0.store(ptr.cast_mut(), Ordering::Release); - } - - pub fn get(&self, _: Token) -> *const SyncExecutor { - self.0.load(Ordering::Acquire).cast_const() - } - } -} -#[cfg(not(target_has_atomic = "ptr"))] -mod owner { - use super::{state::Token, SyncExecutor}; - use core::cell::Cell; - - use critical_section::Mutex; - - pub(crate) struct ExecutorRef(Mutex>); - - unsafe impl Send for ExecutorRef {} - unsafe impl Sync for ExecutorRef {} - - impl ExecutorRef { - pub const fn new() -> Self { - Self(Mutex::new(Cell::new(core::ptr::null()))) - } - - pub fn set(&self, executor: Option<&'static SyncExecutor>, cs: Token) { - let ptr = executor.map(|e| e as *const SyncExecutor).unwrap_or(core::ptr::null()); - self.0.borrow(cs).set(ptr); - } - - pub fn get(&self, cs: Token) -> *const SyncExecutor { - self.0.borrow(cs).get() - } - } -} +mod state; pub mod timer_queue; #[cfg(feature = "trace")] @@ -79,10 +28,9 @@ use core::marker::PhantomData; use core::mem; use core::pin::Pin; use core::ptr::NonNull; +use core::sync::atomic::{AtomicPtr, Ordering}; use core::task::{Context, Poll}; -use crate::raw::owner::ExecutorRef; - use self::run_queue::{RunQueue, RunQueueItem}; use self::state::State; use self::util::{SyncUnsafeCell, UninitCell}; @@ -93,7 +41,7 @@ use super::SpawnToken; pub(crate) struct TaskHeader { pub(crate) state: State, pub(crate) run_queue_item: RunQueueItem, - pub(crate) executor: ExecutorRef, + pub(crate) executor: AtomicPtr, poll_fn: SyncUnsafeCell>, /// Integrated timer queue storage. This field should not be accessed outside of the timer queue. @@ -139,7 +87,7 @@ impl TaskRef { /// Returns a reference to the executor that the task is currently running on. pub unsafe fn executor(self) -> Option<&'static Executor> { - let executor = state::locked(|token| self.header().executor.get(token)); + let executor = self.header().executor.load(Ordering::Relaxed); executor.as_ref().map(|e| Executor::wrap(e)) } @@ -207,7 +155,7 @@ impl TaskStorage { raw: TaskHeader { state: State::new(), run_queue_item: RunQueueItem::new(), - executor: ExecutorRef::new(), + executor: AtomicPtr::new(core::ptr::null_mut()), // Note: this is lazily initialized so that a static `TaskStorage` will go in `.bss` poll_fn: SyncUnsafeCell::new(None), @@ -450,9 +398,9 @@ impl SyncExecutor { } pub(super) unsafe fn spawn(&'static self, task: TaskRef) { - state::locked(|l| { - task.header().executor.set(Some(self), l); - }); + task.header() + .executor + .store((self as *const Self).cast_mut(), Ordering::Relaxed); #[cfg(feature = "trace")] trace::task_new(self, &task); @@ -605,7 +553,7 @@ pub fn wake_task(task: TaskRef) { header.state.run_enqueue(|l| { // We have just marked the task as scheduled, so enqueue it. unsafe { - let executor = header.executor.get(l).as_ref().unwrap_unchecked(); + let executor = header.executor.load(Ordering::Relaxed).as_ref().unwrap_unchecked(); executor.enqueue(task, l); } }); @@ -619,7 +567,7 @@ pub fn wake_task_no_pend(task: TaskRef) { header.state.run_enqueue(|l| { // We have just marked the task as scheduled, so enqueue it. unsafe { - let executor = header.executor.get(l).as_ref().unwrap_unchecked(); + let executor = header.executor.load(Ordering::Relaxed).as_ref().unwrap_unchecked(); executor.run_queue.enqueue(task, l); } }); diff --git a/embassy-executor/src/spawner.rs b/embassy-executor/src/spawner.rs index bc243bee7..16347ad71 100644 --- a/embassy-executor/src/spawner.rs +++ b/embassy-executor/src/spawner.rs @@ -1,6 +1,7 @@ use core::future::poll_fn; use core::marker::PhantomData; use core::mem; +use core::sync::atomic::Ordering; use core::task::Poll; use super::raw; @@ -92,9 +93,13 @@ impl Spawner { pub async fn for_current_executor() -> Self { poll_fn(|cx| { let task = raw::task_from_waker(cx.waker()); - let executor = raw::state::locked(|l| { - unsafe { task.header().executor.get(l).as_ref().unwrap_unchecked() } - }); + let executor = unsafe { + task.header() + .executor + .load(Ordering::Relaxed) + .as_ref() + .unwrap_unchecked() + }; let executor = unsafe { raw::Executor::wrap(executor) }; Poll::Ready(Self::new(executor)) }) @@ -166,9 +171,13 @@ impl SendSpawner { pub async fn for_current_executor() -> Self { poll_fn(|cx| { let task = raw::task_from_waker(cx.waker()); - let executor = raw::state::locked(|l| { - unsafe { task.header().executor.get(l).as_ref().unwrap_unchecked() } - }); + let executor = unsafe { + task.header() + .executor + .load(Ordering::Relaxed) + .as_ref() + .unwrap_unchecked() + }; Poll::Ready(Self::new(executor)) }) .await From 3c121e5425e0a1901c459d27e3e5929f86d0a206 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Mon, 16 Dec 2024 18:08:19 +0100 Subject: [PATCH 0493/1217] Remove special handling of integrated timer queue --- embassy-executor/src/raw/mod.rs | 22 ---------------------- embassy-time-driver/src/lib.rs | 6 ++++++ embassy-time-queue-driver/src/lib.rs | 28 ---------------------------- embassy-time/Cargo.toml | 8 ++++---- embassy-time/src/timer.rs | 6 +++--- 5 files changed, 13 insertions(+), 57 deletions(-) diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs index 5a476213b..997db6756 100644 --- a/embassy-executor/src/raw/mod.rs +++ b/embassy-executor/src/raw/mod.rs @@ -195,25 +195,7 @@ impl TaskStorage { match future.poll(&mut cx) { Poll::Ready(_) => { this.future.drop_in_place(); - - // Mark this task to be timer queued. - // We're splitting the enqueue in two parts, so that we can change task state - // to something that prevent re-queueing. - let op = this.raw.state.timer_enqueue(); - - // Now mark the task as not spawned, so that - // - it can be spawned again once it has been removed from the timer queue - // - it can not be timer-queued again - // We must do this before scheduling the wake, to prevent the task from being - // dequeued by the time driver while it's still SPAWNED. this.raw.state.despawn(); - - // Now let's finish enqueueing. While we shouldn't get an `Ignore` here, it's - // better to be safe. - if op == timer_queue::TimerEnqueueOperation::Enqueue { - // Schedule the task in the past, so it gets dequeued ASAP. - unsafe { _embassy_time_schedule_wake(0, &waker) } - } } Poll::Pending => {} } @@ -232,10 +214,6 @@ impl TaskStorage { } } -extern "Rust" { - fn _embassy_time_schedule_wake(at: u64, waker: &core::task::Waker); -} - /// An uninitialized [`TaskStorage`]. pub struct AvailableTask { task: &'static TaskStorage, diff --git a/embassy-time-driver/src/lib.rs b/embassy-time-driver/src/lib.rs index 57a9f7587..c776fbdf8 100644 --- a/embassy-time-driver/src/lib.rs +++ b/embassy-time-driver/src/lib.rs @@ -131,6 +131,7 @@ pub trait Driver: Send + Sync + 'static { extern "Rust" { fn _embassy_time_now() -> u64; + fn _embassy_time_schedule_wake(at: u64, waker: &Waker); } /// See [`Driver::now`] @@ -138,6 +139,11 @@ pub fn now() -> u64 { unsafe { _embassy_time_now() } } +/// Schedule the given waker to be woken at `at`. +pub fn schedule_wake(at: u64, waker: &Waker) { + unsafe { _embassy_time_schedule_wake(at, waker) } +} + /// Set the time Driver implementation. /// /// See the module documentation for an example. diff --git a/embassy-time-queue-driver/src/lib.rs b/embassy-time-queue-driver/src/lib.rs index 97c81a124..333b6124d 100644 --- a/embassy-time-queue-driver/src/lib.rs +++ b/embassy-time-queue-driver/src/lib.rs @@ -10,8 +10,6 @@ //! As a HAL implementer, you need to depend on this crate if you want to implement a time driver, //! but how you should do so is documented in `embassy-time-driver`. -use core::task::Waker; - #[cfg(feature = "_generic-queue")] pub mod queue_generic; #[cfg(not(feature = "_generic-queue"))] @@ -21,29 +19,3 @@ pub mod queue_integrated; pub use queue_generic::Queue; #[cfg(not(feature = "_generic-queue"))] pub use queue_integrated::Queue; - -extern "Rust" { - fn _embassy_time_schedule_wake(at: u64, waker: &Waker); -} - -/// Schedule the given waker to be woken at `at`. -pub fn schedule_wake(at: u64, waker: &Waker) { - // This function is not implemented in embassy-time-driver because it needs access to executor - // internals. The function updates task state, then delegates to the implementation provided - // by the time driver. - #[cfg(not(feature = "_generic-queue"))] - { - use embassy_executor::raw::task_from_waker; - use embassy_executor::raw::timer_queue::TimerEnqueueOperation; - // The very first thing we must do, before we even access the timer queue, is to - // mark the task a TIMER_QUEUED. This ensures that the task that is being scheduled - // can not be respawn while we are accessing the timer queue. - let task = task_from_waker(waker); - if unsafe { task.timer_enqueue() } == TimerEnqueueOperation::Ignore { - // We are not allowed to enqueue the task in the timer queue. This is because the - // task is not spawned, and so it makes no sense to schedule it. - return; - } - } - unsafe { _embassy_time_schedule_wake(at, waker) } -} diff --git a/embassy-time/Cargo.toml b/embassy-time/Cargo.toml index e3074119f..4f4ea0b14 100644 --- a/embassy-time/Cargo.toml +++ b/embassy-time/Cargo.toml @@ -24,8 +24,8 @@ target = "x86_64-unknown-linux-gnu" features = ["defmt", "std"] [features] -std = ["tick-hz-1_000_000", "critical-section/std"] -wasm = ["dep:wasm-bindgen", "dep:js-sys", "dep:wasm-timer", "tick-hz-1_000_000"] +std = ["tick-hz-1_000_000", "critical-section/std", "dep:embassy-time-queue-driver"] +wasm = ["dep:wasm-bindgen", "dep:js-sys", "dep:wasm-timer", "tick-hz-1_000_000", "dep:embassy-time-queue-driver"] ## Display the time since startup next to defmt log messages. ## At most 1 `defmt-timestamp-uptime-*` feature can be used. @@ -40,7 +40,7 @@ defmt-timestamp-uptime-tms = ["defmt"] defmt-timestamp-uptime-tus = ["defmt"] ## Create a `MockDriver` that can be manually advanced for testing purposes. -mock-driver = ["tick-hz-1_000_000"] +mock-driver = ["tick-hz-1_000_000", "dep:embassy-time-queue-driver"] #! ### Tick Rate #! @@ -384,7 +384,7 @@ tick-hz-5_242_880_000 = ["embassy-time-driver/tick-hz-5_242_880_000"] [dependencies] embassy-time-driver = { version = "0.1.0", path = "../embassy-time-driver" } -embassy-time-queue-driver = { version = "0.1.0", path = "../embassy-time-queue-driver" } +embassy-time-queue-driver = { version = "0.1.0", path = "../embassy-time-queue-driver", optional = true} defmt = { version = "0.3", optional = true } log = { version = "0.4.14", optional = true } diff --git a/embassy-time/src/timer.rs b/embassy-time/src/timer.rs index 4d7194b20..295ddbd9b 100644 --- a/embassy-time/src/timer.rs +++ b/embassy-time/src/timer.rs @@ -157,7 +157,7 @@ impl Future for Timer { if self.yielded_once && self.expires_at <= Instant::now() { Poll::Ready(()) } else { - embassy_time_queue_driver::schedule_wake(self.expires_at.as_ticks(), cx.waker()); + embassy_time_driver::schedule_wake(self.expires_at.as_ticks(), cx.waker()); self.yielded_once = true; Poll::Pending } @@ -238,7 +238,7 @@ impl Ticker { self.expires_at += dur; Poll::Ready(()) } else { - embassy_time_queue_driver::schedule_wake(self.expires_at.as_ticks(), cx.waker()); + embassy_time_driver::schedule_wake(self.expires_at.as_ticks(), cx.waker()); Poll::Pending } }) @@ -255,7 +255,7 @@ impl Stream for Ticker { self.expires_at += dur; Poll::Ready(Some(())) } else { - embassy_time_queue_driver::schedule_wake(self.expires_at.as_ticks(), cx.waker()); + embassy_time_driver::schedule_wake(self.expires_at.as_ticks(), cx.waker()); Poll::Pending } } From c9f32b7e3667f29c4ab15d4dbab37acdb471d0ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Mon, 16 Dec 2024 18:51:09 +0100 Subject: [PATCH 0494/1217] Attach payload to TimerQueueItem --- embassy-executor/Cargo.toml | 16 +++++++++ embassy-executor/src/raw/timer_queue.rs | 45 +++++++++++++++++++++++++ 2 files changed, 61 insertions(+) diff --git a/embassy-executor/Cargo.toml b/embassy-executor/Cargo.toml index 60fe7087a..2a64b9c83 100644 --- a/embassy-executor/Cargo.toml +++ b/embassy-executor/Cargo.toml @@ -92,6 +92,22 @@ trace = [] ## Enable support for rtos-trace framework rtos-trace = ["dep:rtos-trace", "trace", "dep:embassy-time-driver"] +#! ### Timer Item Payload Size +#! Sets the size of the payload for timer items, allowing integrated timer implementors to store +#! additional data in the timer item. The payload field will be aligned to this value as well. +#! If these features are not defined, the timer item will contain no payload field. + +_timer-item-payload = [] # A size was picked + +## 1 bytes +timer-item-payload-size-1 = ["_timer-item-payload"] +## 2 bytes +timer-item-payload-size-2 = ["_timer-item-payload"] +## 4 bytes +timer-item-payload-size-4 = ["_timer-item-payload"] +## 8 bytes +timer-item-payload-size-8 = ["_timer-item-payload"] + #! ### Task Arena Size #! Sets the [task arena](#task-arena) size. Necessary if you’re not using `nightly`. #! diff --git a/embassy-executor/src/raw/timer_queue.rs b/embassy-executor/src/raw/timer_queue.rs index 2ba0e00a9..c4dba18ff 100644 --- a/embassy-executor/src/raw/timer_queue.rs +++ b/embassy-executor/src/raw/timer_queue.rs @@ -4,6 +4,45 @@ use core::cell::Cell; use super::TaskRef; +#[cfg(feature = "_timer-item-payload")] +macro_rules! define_opaque { + ($size:tt) => { + /// An opaque data type. + #[repr(align($size))] + pub struct OpaqueData { + data: [u8; $size], + } + + impl OpaqueData { + const fn new() -> Self { + Self { data: [0; $size] } + } + + /// Access the data as a reference to a type `T`. + /// + /// Safety: + /// + /// The caller must ensure that the size of the type `T` is less than, or equal to + /// the size of the payload, and must ensure that the alignment of the type `T` is + /// less than, or equal to the alignment of the payload. + /// + /// The type must be valid when zero-initialized. + pub unsafe fn as_ref(&self) -> &T { + &*(self.data.as_ptr() as *const T) + } + } + }; +} + +#[cfg(feature = "timer-item-payload-size-1")] +define_opaque!(1); +#[cfg(feature = "timer-item-payload-size-2")] +define_opaque!(2); +#[cfg(feature = "timer-item-payload-size-4")] +define_opaque!(4); +#[cfg(feature = "timer-item-payload-size-8")] +define_opaque!(8); + /// An item in the timer queue. pub struct TimerQueueItem { /// The next item in the queue. @@ -14,6 +53,10 @@ pub struct TimerQueueItem { /// The time at which this item expires. pub expires_at: Cell, + + /// Some implementation-defined, zero-initialized piece of data. + #[cfg(feature = "_timer-item-payload")] + pub payload: OpaqueData, } unsafe impl Sync for TimerQueueItem {} @@ -23,6 +66,8 @@ impl TimerQueueItem { Self { next: Cell::new(None), expires_at: Cell::new(0), + #[cfg(feature = "_timer-item-payload")] + payload: OpaqueData::new(), } } } From fbd0fe06bde7949d3374d10e540291493e088314 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Mon, 16 Dec 2024 18:56:42 +0100 Subject: [PATCH 0495/1217] Remove special handling of integrated timer items --- embassy-executor/src/raw/mod.rs | 23 ------------------- embassy-executor/src/raw/timer_queue.rs | 11 --------- .../src/queue_integrated.rs | 1 - 3 files changed, 35 deletions(-) diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs index 997db6756..bdd5ff5ae 100644 --- a/embassy-executor/src/raw/mod.rs +++ b/embassy-executor/src/raw/mod.rs @@ -96,29 +96,6 @@ impl TaskRef { &self.header().timer_queue_item } - /// Mark the task as timer-queued. Return whether it should be actually enqueued - /// using `_embassy_time_schedule_wake`. - /// - /// Entering this state prevents the task from being respawned while in a timer queue. - /// - /// Safety: - /// - /// This functions should only be called by the timer queue driver, before - /// enqueueing the timer item. - pub unsafe fn timer_enqueue(&self) -> timer_queue::TimerEnqueueOperation { - self.header().state.timer_enqueue() - } - - /// Unmark the task as timer-queued. - /// - /// Safety: - /// - /// This functions should only be called by the timer queue implementation, after the task has - /// been removed from the timer queue. - pub unsafe fn timer_dequeue(&self) { - self.header().state.timer_dequeue() - } - /// The returned pointer is valid for the entire TaskStorage. pub(crate) fn as_ptr(self) -> *const TaskHeader { self.ptr.as_ptr() diff --git a/embassy-executor/src/raw/timer_queue.rs b/embassy-executor/src/raw/timer_queue.rs index c4dba18ff..e52453be4 100644 --- a/embassy-executor/src/raw/timer_queue.rs +++ b/embassy-executor/src/raw/timer_queue.rs @@ -71,14 +71,3 @@ impl TimerQueueItem { } } } - -/// The operation to perform after `timer_enqueue` is called. -#[derive(Debug, Copy, Clone, PartialEq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -#[must_use] -pub enum TimerEnqueueOperation { - /// Enqueue the task (or update its expiration time). - Enqueue, - /// The task must not be enqueued in the timer queue. - Ignore, -} diff --git a/embassy-time-queue-driver/src/queue_integrated.rs b/embassy-time-queue-driver/src/queue_integrated.rs index 6bb4c0c1a..246cf1d63 100644 --- a/embassy-time-queue-driver/src/queue_integrated.rs +++ b/embassy-time-queue-driver/src/queue_integrated.rs @@ -83,7 +83,6 @@ impl Queue { // Remove it prev.set(item.next.get()); item.next.set(None); - unsafe { p.timer_dequeue() }; } } } From 71812d0c9ba3c0c9f8689299f825ebc1318db938 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Mon, 16 Dec 2024 18:59:00 +0100 Subject: [PATCH 0496/1217] Changelog --- embassy-executor/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/embassy-executor/CHANGELOG.md b/embassy-executor/CHANGELOG.md index 068156210..59ea88d0c 100644 --- a/embassy-executor/CHANGELOG.md +++ b/embassy-executor/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - embassy-executor no longer provides an `embassy-time-queue-driver` implementation - Added `TaskRef::executor` to obtain a reference to a task's executor - integrated-timers are no longer processed when polling the executor. +- Added the option to store data in timer queue items ## 0.6.3 - 2024-11-12 From a8617429e4c3177a3e7c31b20ee36a2dfe6b6430 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Mon, 16 Dec 2024 19:00:01 +0100 Subject: [PATCH 0497/1217] Add note --- embassy-time-driver/src/lib.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/embassy-time-driver/src/lib.rs b/embassy-time-driver/src/lib.rs index c776fbdf8..9f2795a01 100644 --- a/embassy-time-driver/src/lib.rs +++ b/embassy-time-driver/src/lib.rs @@ -46,6 +46,9 @@ //! //! Then, you'll need to adapt the `schedule_wake` method to use this queue. //! +//! Note that if you are using multiple queues, you will need to ensure that a single timer +//! queue item is only ever enqueued into a single queue at a time. +//! //! ```ignore //! use core::cell::RefCell; //! use core::task::Waker; From c90d048ecb611908f5696b4f57d689bdb254aee6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Mon, 16 Dec 2024 19:03:00 +0100 Subject: [PATCH 0498/1217] Remove TIMER_QUEUED --- embassy-executor/src/raw/state_atomics.rs | 32 ----------------- embassy-executor/src/raw/state_atomics_arm.rs | 36 ++----------------- .../src/raw/state_critical_section.rs | 25 ------------- 3 files changed, 2 insertions(+), 91 deletions(-) diff --git a/embassy-executor/src/raw/state_atomics.rs b/embassy-executor/src/raw/state_atomics.rs index d7350464f..6f5266bda 100644 --- a/embassy-executor/src/raw/state_atomics.rs +++ b/embassy-executor/src/raw/state_atomics.rs @@ -1,7 +1,5 @@ use core::sync::atomic::{AtomicU32, Ordering}; -use super::timer_queue::TimerEnqueueOperation; - #[derive(Clone, Copy)] pub(crate) struct Token(()); @@ -16,8 +14,6 @@ pub(crate) fn locked(f: impl FnOnce(Token) -> R) -> R { pub(crate) const STATE_SPAWNED: u32 = 1 << 0; /// Task is in the executor run queue pub(crate) const STATE_RUN_QUEUED: u32 = 1 << 1; -/// Task is in the executor timer queue -pub(crate) const STATE_TIMER_QUEUED: u32 = 1 << 2; pub(crate) struct State { state: AtomicU32, @@ -71,32 +67,4 @@ impl State { let state = self.state.fetch_and(!STATE_RUN_QUEUED, Ordering::AcqRel); state & STATE_SPAWNED != 0 } - - /// Mark the task as timer-queued. Return whether it can be enqueued. - #[inline(always)] - pub fn timer_enqueue(&self) -> TimerEnqueueOperation { - if self - .state - .fetch_update(Ordering::SeqCst, Ordering::SeqCst, |state| { - // If not started, ignore it - if state & STATE_SPAWNED == 0 { - None - } else { - // Mark it as enqueued - Some(state | STATE_TIMER_QUEUED) - } - }) - .is_ok() - { - TimerEnqueueOperation::Enqueue - } else { - TimerEnqueueOperation::Ignore - } - } - - /// Unmark the task as timer-queued. - #[inline(always)] - pub fn timer_dequeue(&self) { - self.state.fetch_and(!STATE_TIMER_QUEUED, Ordering::Relaxed); - } } diff --git a/embassy-executor/src/raw/state_atomics_arm.rs b/embassy-executor/src/raw/state_atomics_arm.rs index c1e8f69ab..4896b33c5 100644 --- a/embassy-executor/src/raw/state_atomics_arm.rs +++ b/embassy-executor/src/raw/state_atomics_arm.rs @@ -1,8 +1,6 @@ use core::arch::asm; use core::sync::atomic::{compiler_fence, AtomicBool, AtomicU32, Ordering}; -use super::timer_queue::TimerEnqueueOperation; - #[derive(Clone, Copy)] pub(crate) struct Token(()); @@ -16,7 +14,6 @@ pub(crate) fn locked(f: impl FnOnce(Token) -> R) -> R { // Must be kept in sync with the layout of `State`! pub(crate) const STATE_SPAWNED: u32 = 1 << 0; pub(crate) const STATE_RUN_QUEUED: u32 = 1 << 8; -pub(crate) const STATE_TIMER_QUEUED: u32 = 1 << 16; #[repr(C, align(4))] pub(crate) struct State { @@ -24,9 +21,8 @@ pub(crate) struct State { spawned: AtomicBool, /// Task is in the executor run queue run_queued: AtomicBool, - /// Task is in the executor timer queue - timer_queued: AtomicBool, pad: AtomicBool, + pad2: AtomicBool, } impl State { @@ -34,8 +30,8 @@ impl State { Self { spawned: AtomicBool::new(false), run_queued: AtomicBool::new(false), - timer_queued: AtomicBool::new(false), pad: AtomicBool::new(false), + pad2: AtomicBool::new(false), } } @@ -101,32 +97,4 @@ impl State { self.run_queued.store(false, Ordering::Relaxed); r } - - /// Mark the task as timer-queued. Return whether it can be enqueued. - #[inline(always)] - pub fn timer_enqueue(&self) -> TimerEnqueueOperation { - if self - .as_u32() - .fetch_update(Ordering::SeqCst, Ordering::SeqCst, |state| { - // If not started, ignore it - if state & STATE_SPAWNED == 0 { - None - } else { - // Mark it as enqueued - Some(state | STATE_TIMER_QUEUED) - } - }) - .is_ok() - { - TimerEnqueueOperation::Enqueue - } else { - TimerEnqueueOperation::Ignore - } - } - - /// Unmark the task as timer-queued. - #[inline(always)] - pub fn timer_dequeue(&self) { - self.timer_queued.store(false, Ordering::Relaxed); - } } diff --git a/embassy-executor/src/raw/state_critical_section.rs b/embassy-executor/src/raw/state_critical_section.rs index 8e570b33c..29b10f6e3 100644 --- a/embassy-executor/src/raw/state_critical_section.rs +++ b/embassy-executor/src/raw/state_critical_section.rs @@ -3,14 +3,10 @@ use core::cell::Cell; pub(crate) use critical_section::{with as locked, CriticalSection as Token}; use critical_section::{CriticalSection, Mutex}; -use super::timer_queue::TimerEnqueueOperation; - /// Task is spawned (has a future) pub(crate) const STATE_SPAWNED: u32 = 1 << 0; /// Task is in the executor run queue pub(crate) const STATE_RUN_QUEUED: u32 = 1 << 1; -/// Task is in the executor timer queue -pub(crate) const STATE_TIMER_QUEUED: u32 = 1 << 2; pub(crate) struct State { state: Mutex>, @@ -81,25 +77,4 @@ impl State { ok }) } - - /// Mark the task as timer-queued. Return whether it can be enqueued. - #[inline(always)] - pub fn timer_enqueue(&self) -> TimerEnqueueOperation { - self.update(|s| { - // FIXME: we need to split SPAWNED into two phases, to prevent enqueueing a task that is - // just being spawned, because its executor pointer may still be changing. - if *s & STATE_SPAWNED == STATE_SPAWNED { - *s |= STATE_TIMER_QUEUED; - TimerEnqueueOperation::Enqueue - } else { - TimerEnqueueOperation::Ignore - } - }) - } - - /// Unmark the task as timer-queued. - #[inline(always)] - pub fn timer_dequeue(&self) { - self.update(|s| *s &= !STATE_TIMER_QUEUED); - } } From c3c571e01ef902ccd2c3b176a4bc6ee3547d5da7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Mon, 16 Dec 2024 20:17:43 +0100 Subject: [PATCH 0499/1217] Remove test implementation of schedule_wake --- embassy-executor/tests/test.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/embassy-executor/tests/test.rs b/embassy-executor/tests/test.rs index 992ab3da9..0ce1f1891 100644 --- a/embassy-executor/tests/test.rs +++ b/embassy-executor/tests/test.rs @@ -150,7 +150,3 @@ fn executor_task_cfg_args() { let (_, _, _) = (a, b, c); } } - -// We need this for the test to compile, even though we don't want to use timers at the moment. -#[no_mangle] -fn _embassy_time_schedule_wake(_at: u64, _waker: &core::task::Waker) {} From fc25fca00b48630073575d14bcc713912d0b0104 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 17 Dec 2024 13:06:31 +0100 Subject: [PATCH 0500/1217] Remove WakerHack for good. Now that 1.83 xtensa is out, we can remove it unconditionally. --- embassy-executor/src/raw/waker.rs | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/embassy-executor/src/raw/waker.rs b/embassy-executor/src/raw/waker.rs index 9c70f995a..b7d57c314 100644 --- a/embassy-executor/src/raw/waker.rs +++ b/embassy-executor/src/raw/waker.rs @@ -32,22 +32,11 @@ pub(crate) unsafe fn from_task(p: TaskRef) -> Waker { /// /// Panics if the waker is not created by the Embassy executor. pub fn task_from_waker(waker: &Waker) -> TaskRef { - struct WakerHack { - data: *const (), - vtable: &'static RawWakerVTable, - } - - // safety: OK because WakerHack has the same layout as Waker. - // This is not really guaranteed because the structs are `repr(Rust)`, it is - // indeed the case in the current implementation. - // TODO use waker_getters when stable. https://github.com/rust-lang/rust/issues/96992 - let hack: &WakerHack = unsafe { core::mem::transmute(waker) }; - // make sure to compare vtable addresses. Doing `==` on the references // will compare the contents, which is slower. - if hack.vtable as *const _ != &VTABLE as *const _ { + if waker.vtable() as *const _ != &VTABLE as *const _ { panic!("Found waker not created by the Embassy executor. `embassy_time::Timer` only works with the Embassy executor.") } // safety: our wakers are always created with `TaskRef::as_ptr` - unsafe { TaskRef::from_ptr(hack.data as *const TaskHeader) } + unsafe { TaskRef::from_ptr(waker.data() as *const TaskHeader) } } From 7eac184af0b6bf88c43158b9a791d7c169d5bb3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Mon, 9 Dec 2024 17:11:47 +0100 Subject: [PATCH 0501/1217] Document task states and state transitions --- embassy-executor/src/raw/mod.rs | 38 +++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs index bdd5ff5ae..0ac569946 100644 --- a/embassy-executor/src/raw/mod.rs +++ b/embassy-executor/src/raw/mod.rs @@ -38,6 +38,44 @@ pub use self::waker::task_from_waker; use super::SpawnToken; /// Raw task header for use in task pointers. +/// +/// A task can be in one of the following states: +/// +/// - Not spawned: the task is ready to spawn. +/// - `SPAWNED`: the task is currently spawned and may be running. +/// - `RUN_ENQUEUED`: the task is enqueued to be polled. Note that the task may be `!SPAWNED`. +/// In this case, the `RUN_ENQUEUED` state will be cleared when the task is next polled, without +/// polling the task's future. +/// +/// A task's complete life cycle is as follows: +/// +/// ```text +/// ┌────────────┠┌────────────────────────┠+/// ┌─►│Not spawned │◄─6┤Not spawned|Run enqueued│ +/// │ │ │ │ │ +/// │ └─────┬──────┘ └──────▲─────────────────┘ +/// │ 1 │ +/// │ │ ┌────────────┘ +/// │ │ 5 +/// │ ┌─────▼────┴─────────┠+/// │ │Spawned|Run enqueued│ +/// │ │ │ +/// │ └─────┬▲─────────────┘ +/// │ 2│ +/// │ │3 +/// │ ┌─────▼┴─────┠+/// └─4┤ Spawned │ +/// │ │ +/// └────────────┘ +/// ``` +/// +/// Transitions: +/// - 1: Task is spawned - `AvailableTask::claim -> Executor::spawn` +/// - 2: During poll - `RunQueue::dequeue_all -> State::run_dequeue` +/// - 3: Task wakes itself, waker wakes task - `Waker::wake -> wake_task -> State::run_enqueue` +/// - 4: Task exits - `TaskStorage::poll -> Poll::Ready` +/// - 5: A run-queued task exits - `TaskStorage::poll -> Poll::Ready` +/// - 6: Task is dequeued and then ignored via `State::run_dequeue` pub(crate) struct TaskHeader { pub(crate) state: State, pub(crate) run_queue_item: RunQueueItem, From c6ca46c82529e014aaceb218ad88978c50f0db07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Tue, 26 Nov 2024 00:20:34 +0100 Subject: [PATCH 0502/1217] Set RUN_QUEUED unconditionally --- embassy-executor/Cargo.toml | 1 + embassy-executor/src/raw/mod.rs | 3 +- embassy-executor/src/raw/state_atomics.rs | 15 +- embassy-executor/src/raw/state_atomics_arm.rs | 2 +- .../src/raw/state_critical_section.rs | 9 +- embassy-executor/tests/test.rs | 133 ++++++++++++++++++ 6 files changed, 142 insertions(+), 21 deletions(-) diff --git a/embassy-executor/Cargo.toml b/embassy-executor/Cargo.toml index 2a64b9c83..5effaca65 100644 --- a/embassy-executor/Cargo.toml +++ b/embassy-executor/Cargo.toml @@ -55,6 +55,7 @@ avr-device = { version = "0.5.3", optional = true } [dev-dependencies] critical-section = { version = "1.1", features = ["std"] } trybuild = "1.0" +embassy-sync = { path = "../embassy-sync" } [features] diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs index 0ac569946..6503b556f 100644 --- a/embassy-executor/src/raw/mod.rs +++ b/embassy-executor/src/raw/mod.rs @@ -52,7 +52,7 @@ use super::SpawnToken; /// ```text /// ┌────────────┠┌────────────────────────┠/// ┌─►│Not spawned │◄─6┤Not spawned|Run enqueued│ -/// │ │ │ │ │ +/// │ │ ├7─►│ │ /// │ └─────┬──────┘ └──────▲─────────────────┘ /// │ 1 │ /// │ │ ┌────────────┘ @@ -76,6 +76,7 @@ use super::SpawnToken; /// - 4: Task exits - `TaskStorage::poll -> Poll::Ready` /// - 5: A run-queued task exits - `TaskStorage::poll -> Poll::Ready` /// - 6: Task is dequeued and then ignored via `State::run_dequeue` +/// - 7: A task is waken when it is not spawned - `wake_task -> State::run_enqueue` pub(crate) struct TaskHeader { pub(crate) state: State, pub(crate) run_queue_item: RunQueueItem, diff --git a/embassy-executor/src/raw/state_atomics.rs b/embassy-executor/src/raw/state_atomics.rs index 6f5266bda..bdd317b53 100644 --- a/embassy-executor/src/raw/state_atomics.rs +++ b/embassy-executor/src/raw/state_atomics.rs @@ -44,19 +44,8 @@ impl State { /// function if the task was successfully marked. #[inline(always)] pub fn run_enqueue(&self, f: impl FnOnce(Token)) { - if self - .state - .fetch_update(Ordering::SeqCst, Ordering::SeqCst, |state| { - // If already scheduled, or if not started, - if (state & STATE_RUN_QUEUED != 0) || (state & STATE_SPAWNED == 0) { - None - } else { - // Mark it as scheduled - Some(state | STATE_RUN_QUEUED) - } - }) - .is_ok() - { + let prev = self.state.fetch_or(STATE_RUN_QUEUED, Ordering::AcqRel); + if prev & STATE_RUN_QUEUED == 0 { locked(f); } } diff --git a/embassy-executor/src/raw/state_atomics_arm.rs b/embassy-executor/src/raw/state_atomics_arm.rs index 4896b33c5..06bf24343 100644 --- a/embassy-executor/src/raw/state_atomics_arm.rs +++ b/embassy-executor/src/raw/state_atomics_arm.rs @@ -72,7 +72,7 @@ impl State { let state: u32; asm!("ldrex {}, [{}]", out(reg) state, in(reg) self, options(nostack)); - if (state & STATE_RUN_QUEUED != 0) || (state & STATE_SPAWNED == 0) { + if state & STATE_RUN_QUEUED != 0 { asm!("clrex", options(nomem, nostack)); return; } diff --git a/embassy-executor/src/raw/state_critical_section.rs b/embassy-executor/src/raw/state_critical_section.rs index 29b10f6e3..4733af278 100644 --- a/embassy-executor/src/raw/state_critical_section.rs +++ b/embassy-executor/src/raw/state_critical_section.rs @@ -56,12 +56,9 @@ impl State { pub fn run_enqueue(&self, f: impl FnOnce(Token)) { critical_section::with(|cs| { if self.update_with_cs(cs, |s| { - if (*s & STATE_RUN_QUEUED != 0) || (*s & STATE_SPAWNED == 0) { - false - } else { - *s |= STATE_RUN_QUEUED; - true - } + let ok = *s & STATE_RUN_QUEUED == 0; + *s |= STATE_RUN_QUEUED; + ok }) { f(cs); } diff --git a/embassy-executor/tests/test.rs b/embassy-executor/tests/test.rs index 0ce1f1891..78c49c071 100644 --- a/embassy-executor/tests/test.rs +++ b/embassy-executor/tests/test.rs @@ -137,6 +137,139 @@ fn executor_task_self_wake_twice() { ) } +#[test] +fn waking_after_completion_does_not_poll() { + use embassy_sync::waitqueue::AtomicWaker; + + #[task] + async fn task1(trace: Trace, waker: &'static AtomicWaker) { + poll_fn(|cx| { + trace.push("poll task1"); + waker.register(cx.waker()); + Poll::Ready(()) + }) + .await + } + + let waker = Box::leak(Box::new(AtomicWaker::new())); + + let (executor, trace) = setup(); + executor.spawner().spawn(task1(trace.clone(), waker)).unwrap(); + + unsafe { executor.poll() }; + waker.wake(); + unsafe { executor.poll() }; + + // Exited task may be waken but is not polled + waker.wake(); + waker.wake(); + unsafe { executor.poll() }; // Clears running status + + // Can respawn waken-but-dead task + executor.spawner().spawn(task1(trace.clone(), waker)).unwrap(); + + unsafe { executor.poll() }; + + assert_eq!( + trace.get(), + &[ + "pend", // spawning a task pends the executor + "poll task1", // + "pend", // manual wake, gets cleared by poll + "pend", // manual wake, single pend for two wakes + "pend", // respawning a task pends the executor + "poll task1", // + ] + ) +} + +#[test] +fn waking_with_old_waker_after_respawn() { + use embassy_sync::waitqueue::AtomicWaker; + + async fn yield_now(trace: Trace) { + let mut yielded = false; + poll_fn(|cx| { + if yielded { + Poll::Ready(()) + } else { + trace.push("yield_now"); + yielded = true; + cx.waker().wake_by_ref(); + Poll::Pending + } + }) + .await + } + + #[task] + async fn task1(trace: Trace, waker: &'static AtomicWaker) { + yield_now(trace.clone()).await; + poll_fn(|cx| { + trace.push("poll task1"); + waker.register(cx.waker()); + Poll::Ready(()) + }) + .await; + } + + let waker = Box::leak(Box::new(AtomicWaker::new())); + + let (executor, trace) = setup(); + executor.spawner().spawn(task1(trace.clone(), waker)).unwrap(); + + unsafe { executor.poll() }; + unsafe { executor.poll() }; // progress to registering the waker + waker.wake(); + unsafe { executor.poll() }; + // Task has exited + + assert_eq!( + trace.get(), + &[ + "pend", // spawning a task pends the executor + "yield_now", // + "pend", // yield_now wakes the task + "poll task1", // + "pend", // task self-wakes + ] + ); + + // Can respawn task on another executor + let (other_executor, other_trace) = setup(); + other_executor + .spawner() + .spawn(task1(other_trace.clone(), waker)) + .unwrap(); + + unsafe { other_executor.poll() }; // just run to the yield_now + waker.wake(); // trigger old waker registration + unsafe { executor.poll() }; + unsafe { other_executor.poll() }; + + // First executor's trace has not changed + assert_eq!( + trace.get(), + &[ + "pend", // spawning a task pends the executor + "yield_now", // + "pend", // yield_now wakes the task + "poll task1", // + "pend", // task self-wakes + ] + ); + + assert_eq!( + other_trace.get(), + &[ + "pend", // spawning a task pends the executor + "yield_now", // + "pend", // manual wake, gets cleared by poll + "poll task1", // + ] + ); +} + #[test] fn executor_task_cfg_args() { // simulate cfg'ing away argument c From 889b419fc40f252726dbdc8a67bc4d27aa5b81f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Tue, 17 Dec 2024 17:14:59 +0100 Subject: [PATCH 0503/1217] Simplify ARM run_enqueue --- embassy-executor/src/raw/state_atomics_arm.rs | 21 +++---------------- 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/embassy-executor/src/raw/state_atomics_arm.rs b/embassy-executor/src/raw/state_atomics_arm.rs index 06bf24343..cbda0d89d 100644 --- a/embassy-executor/src/raw/state_atomics_arm.rs +++ b/embassy-executor/src/raw/state_atomics_arm.rs @@ -1,4 +1,3 @@ -use core::arch::asm; use core::sync::atomic::{compiler_fence, AtomicBool, AtomicU32, Ordering}; #[derive(Clone, Copy)] @@ -67,24 +66,10 @@ impl State { /// function if the task was successfully marked. #[inline(always)] pub fn run_enqueue(&self, f: impl FnOnce(Token)) { - unsafe { - loop { - let state: u32; - asm!("ldrex {}, [{}]", out(reg) state, in(reg) self, options(nostack)); + let old = self.run_queued.swap(true, Ordering::AcqRel); - if state & STATE_RUN_QUEUED != 0 { - asm!("clrex", options(nomem, nostack)); - return; - } - - let outcome: usize; - let new_state = state | STATE_RUN_QUEUED; - asm!("strex {}, {}, [{}]", out(reg) outcome, in(reg) new_state, in(reg) self, options(nostack)); - if outcome == 0 { - locked(f); - return; - } - } + if !old { + locked(f); } } From edb8f21a741358f7c80b744f008f1e5acc77b429 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Sat, 7 Dec 2024 14:45:16 +0100 Subject: [PATCH 0504/1217] Take critical section instead of unsafe --- embassy-executor/src/raw/mod.rs | 9 --------- embassy-executor/src/raw/run_queue_atomics.rs | 11 ++++++++++- .../src/raw/run_queue_critical_section.rs | 16 ++++++++++++---- 3 files changed, 22 insertions(+), 14 deletions(-) diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs index 6503b556f..c79fdae60 100644 --- a/embassy-executor/src/raw/mod.rs +++ b/embassy-executor/src/raw/mod.rs @@ -411,15 +411,6 @@ impl SyncExecutor { self.run_queue.dequeue_all(|p| { let task = p.header(); - if !task.state.run_dequeue() { - // If task is not running, ignore it. This can happen in the following scenario: - // - Task gets dequeued, poll starts - // - While task is being polled, it gets woken. It gets placed in the queue. - // - Task poll finishes, returning done=true - // - RUNNING bit is cleared, but the task is already in the queue. - return; - } - #[cfg(feature = "trace")] trace::task_exec_begin(self, &p); diff --git a/embassy-executor/src/raw/run_queue_atomics.rs b/embassy-executor/src/raw/run_queue_atomics.rs index efdafdff0..aad90d767 100644 --- a/embassy-executor/src/raw/run_queue_atomics.rs +++ b/embassy-executor/src/raw/run_queue_atomics.rs @@ -81,7 +81,16 @@ impl RunQueue { // safety: there are no concurrent accesses to `next` next = unsafe { task.header().run_queue_item.next.get() }; - on_task(task); + let run_task = task.header().state.run_dequeue(); + + if run_task { + // If task is not running, ignore it. This can happen in the following scenario: + // - Task gets dequeued, poll starts + // - While task is being polled, it gets woken. It gets placed in the queue. + // - Task poll finishes, returning done=true + // - RUNNING bit is cleared, but the task is already in the queue. + on_task(task); + } } } } diff --git a/embassy-executor/src/raw/run_queue_critical_section.rs b/embassy-executor/src/raw/run_queue_critical_section.rs index 90f09e8c8..4f1b2855a 100644 --- a/embassy-executor/src/raw/run_queue_critical_section.rs +++ b/embassy-executor/src/raw/run_queue_critical_section.rs @@ -63,11 +63,19 @@ impl RunQueue { // If the task re-enqueues itself, the `next` pointer will get overwritten. // Therefore, first read the next pointer, and only then process the task. - // safety: we know if the task is enqueued, no one else will touch the `next` pointer. - let cs = unsafe { CriticalSection::new() }; - next = task.header().run_queue_item.next.borrow(cs).get(); + let run_task = critical_section::with(|cs| { + next = task.header().run_queue_item.next.borrow(cs).get(); + task.header().state.run_dequeue(cs) + }); - on_task(task); + if run_task { + // If task is not running, ignore it. This can happen in the following scenario: + // - Task gets dequeued, poll starts + // - While task is being polled, it gets woken. It gets placed in the queue. + // - Task poll finishes, returning done=true + // - RUNNING bit is cleared, but the task is already in the queue. + on_task(task); + } } } } From 8fd08b1e97533c7526bb4937770060d18bb37410 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Tue, 17 Dec 2024 18:05:48 +0100 Subject: [PATCH 0505/1217] Swap poll_fn to allow polling exited tasks --- embassy-executor/src/raw/mod.rs | 17 +++++++++++++++-- embassy-executor/src/raw/run_queue_atomics.rs | 12 ++---------- .../src/raw/run_queue_critical_section.rs | 13 +++---------- embassy-executor/src/raw/state_atomics.rs | 5 ++--- embassy-executor/src/raw/state_atomics_arm.rs | 4 +--- .../src/raw/state_critical_section.rs | 8 ++------ 6 files changed, 25 insertions(+), 34 deletions(-) diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs index c79fdae60..242e9c365 100644 --- a/embassy-executor/src/raw/mod.rs +++ b/embassy-executor/src/raw/mod.rs @@ -202,16 +202,29 @@ impl TaskStorage { } } + unsafe fn poll_to_despawn(p: TaskRef) { + // The task's future has already been dropped, we just mark it as `!SPAWNED`. + let this = &*p.as_ptr().cast::>(); + this.raw.state.despawn(); + } + unsafe fn poll(p: TaskRef) { - let this = &*(p.as_ptr() as *const TaskStorage); + let this = &*p.as_ptr().cast::>(); let future = Pin::new_unchecked(this.future.as_mut()); let waker = waker::from_task(p); let mut cx = Context::from_waker(&waker); match future.poll(&mut cx) { Poll::Ready(_) => { + waker.wake_by_ref(); + + // As the future has finished and this function will not be called + // again, we can safely drop the future here. this.future.drop_in_place(); - this.raw.state.despawn(); + + // We replace the poll_fn with a despawn function, so that the task is cleaned up + // when the executor polls it next. + this.raw.poll_fn.set(Some(Self::poll_to_despawn)); } Poll::Pending => {} } diff --git a/embassy-executor/src/raw/run_queue_atomics.rs b/embassy-executor/src/raw/run_queue_atomics.rs index aad90d767..ce511d79a 100644 --- a/embassy-executor/src/raw/run_queue_atomics.rs +++ b/embassy-executor/src/raw/run_queue_atomics.rs @@ -81,16 +81,8 @@ impl RunQueue { // safety: there are no concurrent accesses to `next` next = unsafe { task.header().run_queue_item.next.get() }; - let run_task = task.header().state.run_dequeue(); - - if run_task { - // If task is not running, ignore it. This can happen in the following scenario: - // - Task gets dequeued, poll starts - // - While task is being polled, it gets woken. It gets placed in the queue. - // - Task poll finishes, returning done=true - // - RUNNING bit is cleared, but the task is already in the queue. - on_task(task); - } + task.header().state.run_dequeue(); + on_task(task); } } } diff --git a/embassy-executor/src/raw/run_queue_critical_section.rs b/embassy-executor/src/raw/run_queue_critical_section.rs index 4f1b2855a..86c4085ed 100644 --- a/embassy-executor/src/raw/run_queue_critical_section.rs +++ b/embassy-executor/src/raw/run_queue_critical_section.rs @@ -63,19 +63,12 @@ impl RunQueue { // If the task re-enqueues itself, the `next` pointer will get overwritten. // Therefore, first read the next pointer, and only then process the task. - let run_task = critical_section::with(|cs| { + critical_section::with(|cs| { next = task.header().run_queue_item.next.borrow(cs).get(); - task.header().state.run_dequeue(cs) + task.header().state.run_dequeue(cs); }); - if run_task { - // If task is not running, ignore it. This can happen in the following scenario: - // - Task gets dequeued, poll starts - // - While task is being polled, it gets woken. It gets placed in the queue. - // - Task poll finishes, returning done=true - // - RUNNING bit is cleared, but the task is already in the queue. - on_task(task); - } + on_task(task); } } } diff --git a/embassy-executor/src/raw/state_atomics.rs b/embassy-executor/src/raw/state_atomics.rs index bdd317b53..b6576bfc2 100644 --- a/embassy-executor/src/raw/state_atomics.rs +++ b/embassy-executor/src/raw/state_atomics.rs @@ -52,8 +52,7 @@ impl State { /// Unmark the task as run-queued. Return whether the task is spawned. #[inline(always)] - pub fn run_dequeue(&self) -> bool { - let state = self.state.fetch_and(!STATE_RUN_QUEUED, Ordering::AcqRel); - state & STATE_SPAWNED != 0 + pub fn run_dequeue(&self) { + self.state.fetch_and(!STATE_RUN_QUEUED, Ordering::AcqRel); } } diff --git a/embassy-executor/src/raw/state_atomics_arm.rs b/embassy-executor/src/raw/state_atomics_arm.rs index cbda0d89d..b743dcc2c 100644 --- a/embassy-executor/src/raw/state_atomics_arm.rs +++ b/embassy-executor/src/raw/state_atomics_arm.rs @@ -75,11 +75,9 @@ impl State { /// Unmark the task as run-queued. Return whether the task is spawned. #[inline(always)] - pub fn run_dequeue(&self) -> bool { + pub fn run_dequeue(&self) { compiler_fence(Ordering::Release); - let r = self.spawned.load(Ordering::Relaxed); self.run_queued.store(false, Ordering::Relaxed); - r } } diff --git a/embassy-executor/src/raw/state_critical_section.rs b/embassy-executor/src/raw/state_critical_section.rs index 4733af278..6b627ff79 100644 --- a/embassy-executor/src/raw/state_critical_section.rs +++ b/embassy-executor/src/raw/state_critical_section.rs @@ -67,11 +67,7 @@ impl State { /// Unmark the task as run-queued. Return whether the task is spawned. #[inline(always)] - pub fn run_dequeue(&self) -> bool { - self.update(|s| { - let ok = *s & STATE_SPAWNED != 0; - *s &= !STATE_RUN_QUEUED; - ok - }) + pub fn run_dequeue(&self, cs: CriticalSection<'_>) { + self.update_with_cs(cs, |s| *s &= !STATE_RUN_QUEUED) } } From b51bd9ad040754728142df9991763b4672c31ecd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Tue, 17 Dec 2024 18:09:51 +0100 Subject: [PATCH 0506/1217] Update tests --- embassy-executor/tests/test.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/embassy-executor/tests/test.rs b/embassy-executor/tests/test.rs index 78c49c071..d8c5a6ae3 100644 --- a/embassy-executor/tests/test.rs +++ b/embassy-executor/tests/test.rs @@ -69,6 +69,7 @@ fn executor_task() { &[ "pend", // spawning a task pends the executor "poll task1", // poll only once. + "pend", // task is done, wakes itself to exit ] ) } @@ -179,6 +180,7 @@ fn waking_after_completion_does_not_poll() { "pend", // manual wake, single pend for two wakes "pend", // respawning a task pends the executor "poll task1", // + "pend", // task is done, wakes itself to exit ] ) } @@ -266,6 +268,7 @@ fn waking_with_old_waker_after_respawn() { "yield_now", // "pend", // manual wake, gets cleared by poll "poll task1", // + "pend", // task is done, wakes itself to exit ] ); } From 7d5fbe26c955bae4bd394d1092702bd81f849c9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Tue, 17 Dec 2024 18:17:36 +0100 Subject: [PATCH 0507/1217] Update state diagram --- embassy-executor/src/raw/mod.rs | 43 ++++++++++++++++----------------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs index 242e9c365..5df5ca9e1 100644 --- a/embassy-executor/src/raw/mod.rs +++ b/embassy-executor/src/raw/mod.rs @@ -50,33 +50,32 @@ use super::SpawnToken; /// A task's complete life cycle is as follows: /// /// ```text -/// ┌────────────┠┌────────────────────────┠-/// ┌─►│Not spawned │◄─6┤Not spawned|Run enqueued│ -/// │ │ ├7─►│ │ -/// │ └─────┬──────┘ └──────▲─────────────────┘ -/// │ 1 │ -/// │ │ ┌────────────┘ -/// │ │ 5 -/// │ ┌─────▼────┴─────────┠-/// │ │Spawned|Run enqueued│ -/// │ │ │ -/// │ └─────┬▲─────────────┘ -/// │ 2│ -/// │ │3 -/// │ ┌─────▼┴─────┠-/// └─4┤ Spawned │ -/// │ │ -/// └────────────┘ +/// ┌────────────┠┌────────────────────────┠+/// │Not spawned │◄─5┤Not spawned|Run enqueued│ +/// │ ├6─►│ │ +/// └─────┬──────┘ └──────▲─────────────────┘ +/// 1 │ +/// │ ┌────────────┘ +/// │ 4 +/// ┌─────▼────┴─────────┠+/// │Spawned|Run enqueued│ +/// │ │ +/// └─────┬▲─────────────┘ +/// 2│ +/// │3 +/// ┌─────▼┴─────┠+/// │ Spawned │ +/// │ │ +/// └────────────┘ /// ``` /// /// Transitions: /// - 1: Task is spawned - `AvailableTask::claim -> Executor::spawn` /// - 2: During poll - `RunQueue::dequeue_all -> State::run_dequeue` -/// - 3: Task wakes itself, waker wakes task - `Waker::wake -> wake_task -> State::run_enqueue` -/// - 4: Task exits - `TaskStorage::poll -> Poll::Ready` -/// - 5: A run-queued task exits - `TaskStorage::poll -> Poll::Ready` -/// - 6: Task is dequeued and then ignored via `State::run_dequeue` -/// - 7: A task is waken when it is not spawned - `wake_task -> State::run_enqueue` +/// - 3: Task wakes itself, waker wakes task, or task exits - `Waker::wake -> wake_task -> State::run_enqueue` +/// - 4: A run-queued task exits - `TaskStorage::poll -> Poll::Ready` +/// - 5: Task is dequeued. The task's future is not polled, because exiting the task replaces its `poll_fn`. +/// - 6: A task is waken when it is not spawned - `wake_task -> State::run_enqueue` pub(crate) struct TaskHeader { pub(crate) state: State, pub(crate) run_queue_item: RunQueueItem, From a011f487690465f8ae64fd74f4c51a8be3979890 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Tue, 17 Dec 2024 18:37:17 +0100 Subject: [PATCH 0508/1217] Make poll_to_despawn non-generic --- embassy-executor/src/raw/mod.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs index 5df5ca9e1..39d2d73ab 100644 --- a/embassy-executor/src/raw/mod.rs +++ b/embassy-executor/src/raw/mod.rs @@ -161,6 +161,12 @@ pub struct TaskStorage { future: UninitCell, // Valid if STATE_SPAWNED } +unsafe fn poll_to_despawn(p: TaskRef) { + // The task's future has already been dropped, we just mark it as `!SPAWNED`. + let this = p.header(); + this.state.despawn(); +} + impl TaskStorage { const NEW: Self = Self::new(); @@ -201,12 +207,6 @@ impl TaskStorage { } } - unsafe fn poll_to_despawn(p: TaskRef) { - // The task's future has already been dropped, we just mark it as `!SPAWNED`. - let this = &*p.as_ptr().cast::>(); - this.raw.state.despawn(); - } - unsafe fn poll(p: TaskRef) { let this = &*p.as_ptr().cast::>(); @@ -223,7 +223,7 @@ impl TaskStorage { // We replace the poll_fn with a despawn function, so that the task is cleaned up // when the executor polls it next. - this.raw.poll_fn.set(Some(Self::poll_to_despawn)); + this.raw.poll_fn.set(Some(poll_to_despawn)); } Poll::Pending => {} } From 2ca374fc9c0d0abe579716d1a7c2dc0724321ee7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Tue, 17 Dec 2024 18:46:32 +0100 Subject: [PATCH 0509/1217] Don't force a wake to despawn --- embassy-executor/src/raw/mod.rs | 6 ++++-- embassy-executor/tests/test.rs | 3 --- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs index 39d2d73ab..4a4ecf603 100644 --- a/embassy-executor/src/raw/mod.rs +++ b/embassy-executor/src/raw/mod.rs @@ -215,8 +215,6 @@ impl TaskStorage { let mut cx = Context::from_waker(&waker); match future.poll(&mut cx) { Poll::Ready(_) => { - waker.wake_by_ref(); - // As the future has finished and this function will not be called // again, we can safely drop the future here. this.future.drop_in_place(); @@ -224,6 +222,10 @@ impl TaskStorage { // We replace the poll_fn with a despawn function, so that the task is cleaned up // when the executor polls it next. this.raw.poll_fn.set(Some(poll_to_despawn)); + + // Make sure we despawn last, so that other threads can only spawn the task + // after we're done with it. + this.raw.state.despawn(); } Poll::Pending => {} } diff --git a/embassy-executor/tests/test.rs b/embassy-executor/tests/test.rs index d8c5a6ae3..78c49c071 100644 --- a/embassy-executor/tests/test.rs +++ b/embassy-executor/tests/test.rs @@ -69,7 +69,6 @@ fn executor_task() { &[ "pend", // spawning a task pends the executor "poll task1", // poll only once. - "pend", // task is done, wakes itself to exit ] ) } @@ -180,7 +179,6 @@ fn waking_after_completion_does_not_poll() { "pend", // manual wake, single pend for two wakes "pend", // respawning a task pends the executor "poll task1", // - "pend", // task is done, wakes itself to exit ] ) } @@ -268,7 +266,6 @@ fn waking_with_old_waker_after_respawn() { "yield_now", // "pend", // manual wake, gets cleared by poll "poll task1", // - "pend", // task is done, wakes itself to exit ] ); } From 76d8a896bbff612e3d2db27554891c71d28988af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Tue, 17 Dec 2024 18:51:22 +0100 Subject: [PATCH 0510/1217] Make poll_to_despawn a no_op --- embassy-executor/src/raw/mod.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs index 4a4ecf603..e38a2af66 100644 --- a/embassy-executor/src/raw/mod.rs +++ b/embassy-executor/src/raw/mod.rs @@ -161,10 +161,8 @@ pub struct TaskStorage { future: UninitCell, // Valid if STATE_SPAWNED } -unsafe fn poll_to_despawn(p: TaskRef) { - // The task's future has already been dropped, we just mark it as `!SPAWNED`. - let this = p.header(); - this.state.despawn(); +unsafe fn poll_exited(_p: TaskRef) { + // Nothing to do, the task is already !SPAWNED and dequeued. } impl TaskStorage { @@ -221,7 +219,7 @@ impl TaskStorage { // We replace the poll_fn with a despawn function, so that the task is cleaned up // when the executor polls it next. - this.raw.poll_fn.set(Some(poll_to_despawn)); + this.raw.poll_fn.set(Some(poll_exited)); // Make sure we despawn last, so that other threads can only spawn the task // after we're done with it. From b2e82684707e8675f61bba01e818947ba536d3c7 Mon Sep 17 00:00:00 2001 From: Piotr Esden-Tempski Date: Tue, 17 Dec 2024 14:45:52 -0800 Subject: [PATCH 0511/1217] stm32/(o|q)spi: command naming convention fix The naming convention is to prefix blocking functions with blocking. As both command implementations are blocking the async for the ospi implementation should also be dropped. --- embassy-stm32/src/ospi/mod.rs | 2 +- embassy-stm32/src/qspi/mod.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/ospi/mod.rs b/embassy-stm32/src/ospi/mod.rs index f8ef66216..38217a9a4 100644 --- a/embassy-stm32/src/ospi/mod.rs +++ b/embassy-stm32/src/ospi/mod.rs @@ -520,7 +520,7 @@ impl<'d, T: Instance, M: PeriMode> Ospi<'d, T, M> { } /// Function used to control or configure the target device without data transfer - pub async fn command(&mut self, command: &TransferConfig) -> Result<(), OspiError> { + pub fn blocking_command(&mut self, command: &TransferConfig) -> Result<(), OspiError> { // Wait for peripheral to be free while T::REGS.sr().read().busy() {} diff --git a/embassy-stm32/src/qspi/mod.rs b/embassy-stm32/src/qspi/mod.rs index 49836aa57..0c65d0556 100644 --- a/embassy-stm32/src/qspi/mod.rs +++ b/embassy-stm32/src/qspi/mod.rs @@ -148,7 +148,7 @@ impl<'d, T: Instance, M: PeriMode> Qspi<'d, T, M> { } /// Do a QSPI command. - pub fn command(&mut self, transaction: TransferConfig) { + pub fn blocking_command(&mut self, transaction: TransferConfig) { #[cfg(not(stm32h7))] T::REGS.cr().modify(|v| v.set_dmaen(false)); self.setup_transaction(QspiMode::IndirectWrite, &transaction, None); From bafcdedebe1b94a9eb35a397553ee9ecab237080 Mon Sep 17 00:00:00 2001 From: Piotr Esden-Tempski Date: Tue, 17 Dec 2024 14:56:45 -0800 Subject: [PATCH 0512/1217] Update (q|o)spi examples. --- examples/stm32f7/src/bin/qspi.rs | 4 ++-- examples/stm32h7b0/src/bin/ospi_memory_mapped.rs | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/stm32f7/src/bin/qspi.rs b/examples/stm32f7/src/bin/qspi.rs index 90d319b7a..bd3287964 100644 --- a/examples/stm32f7/src/bin/qspi.rs +++ b/examples/stm32f7/src/bin/qspi.rs @@ -72,7 +72,7 @@ impl FlashMemory { address: None, dummy: DummyCycles::_0, }; - self.qspi.command(transaction); + self.qspi.blocking_command(transaction); } pub fn reset_memory(&mut self) { @@ -143,7 +143,7 @@ impl FlashMemory { dummy: DummyCycles::_0, }; self.enable_write(); - self.qspi.command(transaction); + self.qspi.blocking_command(transaction); self.wait_write_finish(); } diff --git a/examples/stm32h7b0/src/bin/ospi_memory_mapped.rs b/examples/stm32h7b0/src/bin/ospi_memory_mapped.rs index 9c397e507..dffb740a9 100644 --- a/examples/stm32h7b0/src/bin/ospi_memory_mapped.rs +++ b/examples/stm32h7b0/src/bin/ospi_memory_mapped.rs @@ -223,7 +223,7 @@ impl FlashMemory { dummy: DummyCycles::_0, ..Default::default() }; - self.ospi.command(&transaction).await.unwrap(); + self.ospi.blocking_command(&transaction).unwrap(); } async fn exec_command(&mut self, cmd: u8) { @@ -238,7 +238,7 @@ impl FlashMemory { ..Default::default() }; // info!("Excuting command: {:x}", transaction.instruction); - self.ospi.command(&transaction).await.unwrap(); + self.ospi.blocking_command(&transaction).unwrap(); } pub async fn reset_memory(&mut self) { @@ -318,7 +318,7 @@ impl FlashMemory { ..Default::default() }; self.enable_write().await; - self.ospi.command(&transaction).await.unwrap(); + self.ospi.blocking_command(&transaction).unwrap(); self.wait_write_finish(); } From 8eeff8502d56612ce6fea55d01990a21e665ac43 Mon Sep 17 00:00:00 2001 From: klownfish Date: Wed, 18 Dec 2024 01:46:26 +0100 Subject: [PATCH 0513/1217] better u5 adc example --- examples/stm32u5/src/bin/adc.rs | 65 ++++++++++++++++++++++----------- 1 file changed, 43 insertions(+), 22 deletions(-) diff --git a/examples/stm32u5/src/bin/adc.rs b/examples/stm32u5/src/bin/adc.rs index f97facf9e..049b985cf 100644 --- a/examples/stm32u5/src/bin/adc.rs +++ b/examples/stm32u5/src/bin/adc.rs @@ -6,6 +6,7 @@ use defmt::{*}; use defmt_rtt as _; use embassy_stm32::adc; +use embassy_stm32::adc::AdcChannel; use embassy_stm32::adc::adc4; use panic_probe as _; @@ -33,37 +34,57 @@ async fn main(spawner: embassy_executor::Spawner) { } - let p = embassy_stm32::init(config); - info!("Hello World!"); + let mut p = embassy_stm32::init(config); let mut adc = adc::Adc::new(p.ADC1); - let mut adc_pin = p.PA3; + let mut adc_pin1 = p.PA3; // A0 on nucleo u5a5 + let mut adc_pin2 = p.PA2; // A1 on nucleo u5a5 adc.set_resolution(adc::Resolution::BITS14); adc.set_averaging(adc::Averaging::Samples1024); - adc.set_sample_time(adc::SampleTime::CYCLES1_5); - - let mut adc2 = adc::Adc::new(p.ADC2); - let mut adc_pin2 = p.PA5; - adc2.set_resolution(adc::Resolution::BITS14); - adc2.set_averaging(adc::Averaging::Samples1024); - adc2.set_sample_time(adc::SampleTime::CYCLES1_5); + adc.set_sample_time(adc::SampleTime::CYCLES160_5); + let max = adc::resolution_to_max_count(adc::Resolution::BITS14); let mut adc4 = adc4::Adc4::new(p.ADC4); - let mut adc_pin4 = p.PD11; + let mut adc4_pin1 = p.PD11; + let mut adc4_pin2 = p.PC0; adc4.set_resolution(adc4::Resolution::BITS12); adc4.set_averaging(adc4::Averaging::Samples256); adc4.set_sample_time(adc4::SampleTime::CYCLES1_5); + let max4 = adc4::resolution_to_max_count(adc4::Resolution::BITS12); - loop { - embassy_time::Timer::after_millis(100).await; - let raw :u16 = adc.blocking_read(&mut adc_pin); - let max = adc::resolution_to_max_count(adc::Resolution::BITS14); - let volt: f32 = 3.3 * raw as f32 / max as f32; - info!("Read ADC1 {}", volt); + let raw: u16 = adc.blocking_read(&mut adc_pin1); + let volt: f32 = 3.3 * raw as f32 / max as f32; + info!("Read 1 pin 1 {}", volt); + + let raw: u16 = adc.blocking_read(&mut adc_pin2); + let volt: f32 = 3.3 * raw as f32 / max as f32; + info!("Read 1 pin 2 {}", volt); + + let raw4: u16 = adc4.blocking_read(&mut adc4_pin1); + let volt4: f32 = 3.3 * raw4 as f32 / max4 as f32; + info!("Read 4 pin 1 {}", volt4); + + let raw4: u16 = adc4.blocking_read(&mut adc4_pin2); + let volt4: f32 = 3.3 * raw4 as f32 / max4 as f32; + info!("Read 4 pin 2 {}", volt4); + + let mut degraded1 = adc_pin1.degrade_adc(); + let mut degraded2 = adc_pin2.degrade_adc(); + let mut measurements = [0u16; 2]; + + adc.read( + &mut p.GPDMA1_CH0, + [ + (&mut degraded2, adc::SampleTime::CYCLES160_5), + (&mut degraded1, adc::SampleTime::CYCLES160_5), + ] + .into_iter(), + &mut measurements, + ).await; + let volt1: f32 = 3.3 * measurements[1] as f32 / max as f32; + let volt2: f32 = 3.3 * measurements[0] as f32 / max as f32; + + info!("Async read 1 pin 1 {}", volt1); + info!("Async read 1 pin 2 {}", volt2); - let raw4 :u16 = adc4.blocking_read(&mut adc_pin4); - let max4 = adc4::resolution_to_max_count(adc4::Resolution::BITS12); - let volt4: f32 = 3.3 * raw4 as f32 / max4 as f32; - info!("Read ADC4 {}", volt4); - } } \ No newline at end of file From 8678911028a591d72fd1d8418407b5885ed4c417 Mon Sep 17 00:00:00 2001 From: klownfish Date: Wed, 18 Dec 2024 01:46:53 +0100 Subject: [PATCH 0514/1217] fix adc for u5 --- embassy-stm32/src/adc/v4.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/src/adc/v4.rs b/embassy-stm32/src/adc/v4.rs index d73bdb226..96dae25bd 100644 --- a/embassy-stm32/src/adc/v4.rs +++ b/embassy-stm32/src/adc/v4.rs @@ -463,7 +463,7 @@ impl<'d, T: Instance> Adc<'d, T> { Self::set_channel_sample_time(channel, sample_time); - #[cfg(stm32h7)] + #[cfg(any(stm32h7, stm32u5))] { T::regs().cfgr2().modify(|w| w.set_lshift(0)); T::regs() From b912dc197d91d9b4d40c81e59589cba234b53888 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Wed, 18 Dec 2024 11:54:11 +0100 Subject: [PATCH 0515/1217] Force use 1.83 for Xtensa --- .github/ci/build-xtensa.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ci/build-xtensa.sh b/.github/ci/build-xtensa.sh index a13391c82..88357a041 100755 --- a/.github/ci/build-xtensa.sh +++ b/.github/ci/build-xtensa.sh @@ -13,7 +13,7 @@ export CARGO_TARGET_DIR=/ci/cache/target export CARGO_NET_GIT_FETCH_WITH_CLI=true cargo install espup -/ci/cache/cargo/bin/espup install +/ci/cache/cargo/bin/espup install --toolchain-version 1.83.0.1 # Restore lockfiles if [ -f /ci/cache/lockfiles.tar ]; then From f25c729d2858b9f367bb5c52d84540f7b267c05b Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 19 Dec 2024 16:51:58 +0100 Subject: [PATCH 0516/1217] update nightly. --- rust-toolchain-nightly.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain-nightly.toml b/rust-toolchain-nightly.toml index d0c92e655..6efd98956 100644 --- a/rust-toolchain-nightly.toml +++ b/rust-toolchain-nightly.toml @@ -1,5 +1,5 @@ [toolchain] -channel = "nightly-2024-11-04" +channel = "nightly-2024-12-10" components = [ "rust-src", "rustfmt", "llvm-tools", "miri" ] targets = [ "thumbv7em-none-eabi", From 8d98844312eb87539c9e2de2492b8508c2d1c01f Mon Sep 17 00:00:00 2001 From: Anatol Ulrich Date: Thu, 19 Dec 2024 18:35:42 +0100 Subject: [PATCH 0517/1217] embassy-stm32: make SPI slew rate/speed configurable and change default to `Medium` --- embassy-stm32/src/gpio.rs | 15 +++++++++++++++ embassy-stm32/src/spi/mod.rs | 33 ++++++++++++++++++++++++--------- 2 files changed, 39 insertions(+), 9 deletions(-) diff --git a/embassy-stm32/src/gpio.rs b/embassy-stm32/src/gpio.rs index 87519f51e..6283a91bf 100644 --- a/embassy-stm32/src/gpio.rs +++ b/embassy-stm32/src/gpio.rs @@ -658,6 +658,16 @@ fn set_as_af(pin_port: u8, af_num: u8, af_type: AfType) { r.moder().modify(|w| w.set_moder(n, vals::Moder::ALTERNATE)); } +#[inline(never)] +#[cfg(gpio_v2)] +fn set_speed(pin_port: u8, speed: Speed) { + let pin = unsafe { AnyPin::steal(pin_port) }; + let r = pin.block(); + let n = pin._pin() as usize; + + r.ospeedr().modify(|w| w.set_ospeedr(n, speed.to_ospeedr())); +} + #[inline(never)] fn set_as_analog(pin_port: u8) { let pin = unsafe { AnyPin::steal(pin_port) }; @@ -738,6 +748,11 @@ pub(crate) trait SealedPin { set_as_af(self.pin_port(), af_num, af_type) } + #[inline] + fn set_speed(&self, speed: Speed) { + set_speed(self.pin_port(), speed) + } + #[inline] fn set_as_analog(&self) { set_as_analog(self.pin_port()); diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs index a65b0cc64..12653b08b 100644 --- a/embassy-stm32/src/spi/mod.rs +++ b/embassy-stm32/src/spi/mod.rs @@ -10,7 +10,7 @@ use embassy_hal_internal::PeripheralRef; pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; use crate::dma::{word, ChannelAndRequest}; -use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed}; +use crate::gpio::{AfType, AnyPin, OutputType, Pin, Pull, SealedPin as _, Speed}; use crate::mode::{Async, Blocking, Mode as PeriMode}; use crate::pac::spi::{regs, vals, Spi as Regs}; use crate::rcc::{RccInfo, SealedRccPeripheral}; @@ -55,6 +55,9 @@ pub struct Config { /// There are some ICs that require a pull-up on the MISO pin for some applications. /// If you are unsure, you probably don't need this. pub miso_pull: Pull, + /// signal rise/fall speed (slew rate) - defaults to `Medium`. + /// Increase for high SPI speeds. Change to `Low` to reduce ringing. + pub rise_fall_speed: Speed, } impl Default for Config { @@ -64,6 +67,7 @@ impl Default for Config { bit_order: BitOrder::MsbFirst, frequency: Hertz(1_000_000), miso_pull: Pull::None, + rise_fall_speed: Speed::VeryHigh, } } } @@ -92,14 +96,14 @@ impl Config { #[cfg(gpio_v1)] fn sck_af(&self) -> AfType { - AfType::output(OutputType::PushPull, Speed::VeryHigh) + AfType::output(OutputType::PushPull, self.rise_fall_speed) } #[cfg(gpio_v2)] fn sck_af(&self) -> AfType { AfType::output_pull( OutputType::PushPull, - Speed::VeryHigh, + self.rise_fall_speed, match self.mode.polarity { Polarity::IdleLow => Pull::Down, Polarity::IdleHigh => Pull::Up, @@ -118,6 +122,7 @@ pub struct Spi<'d, M: PeriMode> { rx_dma: Option>, _phantom: PhantomData, current_word_size: word_impl::Config, + rise_fall_speed: Speed, } impl<'d, M: PeriMode> Spi<'d, M> { @@ -140,6 +145,7 @@ impl<'d, M: PeriMode> Spi<'d, M> { rx_dma, current_word_size: ::CONFIG, _phantom: PhantomData, + rise_fall_speed: config.rise_fall_speed, }; this.enable_and_init(config); this @@ -243,6 +249,14 @@ impl<'d, M: PeriMode> Spi<'d, M> { let br = compute_baud_rate(self.kernel_clock, config.frequency); + self.rise_fall_speed = config.rise_fall_speed; + if let Some(sck) = self.sck.as_ref() { + sck.set_speed(config.rise_fall_speed); + } + if let Some(mosi) = self.mosi.as_ref() { + mosi.set_speed(config.rise_fall_speed); + } + #[cfg(any(spi_v1, spi_f1, spi_v2))] self.info.regs.cr1().modify(|w| { w.set_cpha(cpha); @@ -308,6 +322,7 @@ impl<'d, M: PeriMode> Spi<'d, M> { bit_order, frequency, miso_pull, + rise_fall_speed: self.rise_fall_speed, } } @@ -441,7 +456,7 @@ impl<'d> Spi<'d, Blocking> { Self::new_inner( peri, new_pin!(sck, config.sck_af()), - new_pin!(mosi, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + new_pin!(mosi, AfType::output(OutputType::PushPull, config.rise_fall_speed)), new_pin!(miso, AfType::input(config.miso_pull)), None, None, @@ -477,7 +492,7 @@ impl<'d> Spi<'d, Blocking> { Self::new_inner( peri, new_pin!(sck, config.sck_af()), - new_pin!(mosi, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + new_pin!(mosi, AfType::output(OutputType::PushPull, config.rise_fall_speed)), None, None, None, @@ -496,7 +511,7 @@ impl<'d> Spi<'d, Blocking> { Self::new_inner( peri, None, - new_pin!(mosi, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + new_pin!(mosi, AfType::output(OutputType::PushPull, config.rise_fall_speed)), None, None, None, @@ -519,7 +534,7 @@ impl<'d> Spi<'d, Async> { Self::new_inner( peri, new_pin!(sck, config.sck_af()), - new_pin!(mosi, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + new_pin!(mosi, AfType::output(OutputType::PushPull, config.rise_fall_speed)), new_pin!(miso, AfType::input(config.miso_pull)), new_dma!(tx_dma), new_dma!(rx_dma), @@ -561,7 +576,7 @@ impl<'d> Spi<'d, Async> { Self::new_inner( peri, new_pin!(sck, config.sck_af()), - new_pin!(mosi, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + new_pin!(mosi, AfType::output(OutputType::PushPull, config.rise_fall_speed)), None, new_dma!(tx_dma), None, @@ -581,7 +596,7 @@ impl<'d> Spi<'d, Async> { Self::new_inner( peri, None, - new_pin!(mosi, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + new_pin!(mosi, AfType::output(OutputType::PushPull, config.rise_fall_speed)), None, new_dma!(tx_dma), None, From 26fe834c098a40d9e8a3f8853c5d06181a09f6da Mon Sep 17 00:00:00 2001 From: Anatol Ulrich Date: Thu, 19 Dec 2024 18:48:07 +0100 Subject: [PATCH 0518/1217] fix imports --- embassy-stm32/src/spi/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs index 12653b08b..2d8bf6209 100644 --- a/embassy-stm32/src/spi/mod.rs +++ b/embassy-stm32/src/spi/mod.rs @@ -10,7 +10,7 @@ use embassy_hal_internal::PeripheralRef; pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; use crate::dma::{word, ChannelAndRequest}; -use crate::gpio::{AfType, AnyPin, OutputType, Pin, Pull, SealedPin as _, Speed}; +use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed}; use crate::mode::{Async, Blocking, Mode as PeriMode}; use crate::pac::spi::{regs, vals, Spi as Regs}; use crate::rcc::{RccInfo, SealedRccPeripheral}; From d91b8c6394dbec23d3b1f6f7d0dfa5b1553acce4 Mon Sep 17 00:00:00 2001 From: Anatol Ulrich Date: Thu, 19 Dec 2024 18:52:27 +0100 Subject: [PATCH 0519/1217] consistently cfg-gate `set_speed` --- embassy-stm32/src/gpio.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/embassy-stm32/src/gpio.rs b/embassy-stm32/src/gpio.rs index 6283a91bf..c047f84ae 100644 --- a/embassy-stm32/src/gpio.rs +++ b/embassy-stm32/src/gpio.rs @@ -749,6 +749,7 @@ pub(crate) trait SealedPin { } #[inline] + #[cfg(gpio_v2)] fn set_speed(&self, speed: Speed) { set_speed(self.pin_port(), speed) } From 7743c8fb9a678a216af7a1ab30123922fb1af811 Mon Sep 17 00:00:00 2001 From: Anatol Ulrich Date: Thu, 19 Dec 2024 19:16:38 +0100 Subject: [PATCH 0520/1217] more cfg gating --- embassy-stm32/src/spi/mod.rs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs index 2d8bf6209..bf8284233 100644 --- a/embassy-stm32/src/spi/mod.rs +++ b/embassy-stm32/src/spi/mod.rs @@ -249,12 +249,15 @@ impl<'d, M: PeriMode> Spi<'d, M> { let br = compute_baud_rate(self.kernel_clock, config.frequency); - self.rise_fall_speed = config.rise_fall_speed; - if let Some(sck) = self.sck.as_ref() { - sck.set_speed(config.rise_fall_speed); - } - if let Some(mosi) = self.mosi.as_ref() { - mosi.set_speed(config.rise_fall_speed); + #[cfg(gpio_v2)] + { + self.rise_fall_speed = config.rise_fall_speed; + if let Some(sck) = self.sck.as_ref() { + sck.set_speed(config.rise_fall_speed); + } + if let Some(mosi) = self.mosi.as_ref() { + mosi.set_speed(config.rise_fall_speed); + } } #[cfg(any(spi_v1, spi_f1, spi_v2))] From 5c4133c70e58cc50fa9d7322630304132d095bcb Mon Sep 17 00:00:00 2001 From: korbin Date: Sat, 21 Dec 2024 09:00:46 -0700 Subject: [PATCH 0521/1217] expose rp bootloader state like stm32 --- embassy-boot-rp/src/lib.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/embassy-boot-rp/src/lib.rs b/embassy-boot-rp/src/lib.rs index 3e1731f5e..6ec33a580 100644 --- a/embassy-boot-rp/src/lib.rs +++ b/embassy-boot-rp/src/lib.rs @@ -14,7 +14,10 @@ use embassy_time::Duration; use embedded_storage::nor_flash::{ErrorType, NorFlash, ReadNorFlash}; /// A bootloader for RP2040 devices. -pub struct BootLoader; +pub struct BootLoader { + /// The reported state of the bootloader after preparing for boot + pub state: State, +} impl BootLoader { /// Inspect the bootloader state and perform actions required before booting, such as swapping firmware @@ -36,8 +39,8 @@ impl BootLoader { ) -> Result { let mut aligned_buf = AlignedBuffer([0; BUFFER_SIZE]); let mut boot = embassy_boot::BootLoader::new(config); - let _state = boot.prepare_boot(aligned_buf.as_mut())?; - Ok(Self) + let state = boot.prepare_boot(aligned_buf.as_mut())?; + Ok(Self { state }) } /// Boots the application. From abb42206f2e888fb1ad0eae05b17edfedcb101ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Sun, 22 Dec 2024 00:52:54 +0100 Subject: [PATCH 0522/1217] Add generic-queue-* features back to embassy-time --- embassy-time-queue-driver/Cargo.toml | 2 +- embassy-time-queue-driver/src/lib.rs | 3 +-- embassy-time/CHANGELOG.md | 1 - embassy-time/Cargo.toml | 25 +++++++++++++++++++++++++ 4 files changed, 27 insertions(+), 4 deletions(-) diff --git a/embassy-time-queue-driver/Cargo.toml b/embassy-time-queue-driver/Cargo.toml index a104f5c39..7fa91bb0c 100644 --- a/embassy-time-queue-driver/Cargo.toml +++ b/embassy-time-queue-driver/Cargo.toml @@ -36,7 +36,7 @@ embassy-executor = { version = "0.6.3", path = "../embassy-executor" } #! The features also set how many timers are used for the generic queue. At most one #! `generic-queue-*` feature can be enabled. If none is enabled, a default of 64 timers is used. #! -#! When using embassy-time from libraries, you should *not* enable any `generic-queue-*` feature, to allow the +#! When using embassy-time-queue-driver from libraries, you should *not* enable any `generic-queue-*` feature, to allow the #! end user to pick. ## Generic Queue with 8 timers diff --git a/embassy-time-queue-driver/src/lib.rs b/embassy-time-queue-driver/src/lib.rs index 333b6124d..72453f0ea 100644 --- a/embassy-time-queue-driver/src/lib.rs +++ b/embassy-time-queue-driver/src/lib.rs @@ -4,8 +4,7 @@ //! This crate is an implementation detail of `embassy-time-driver`. //! -//! As a HAL user, you should only depend on this crate if your application does not use -//! `embassy-executor` and your HAL does not configure a generic queue by itself. +//! As a HAL user, you should not need to depend on this crate directly. //! //! As a HAL implementer, you need to depend on this crate if you want to implement a time driver, //! but how you should do so is documented in `embassy-time-driver`. diff --git a/embassy-time/CHANGELOG.md b/embassy-time/CHANGELOG.md index a6acb1ad6..0026fbd08 100644 --- a/embassy-time/CHANGELOG.md +++ b/embassy-time/CHANGELOG.md @@ -7,7 +7,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased -- The `generic-queue` and related features have been removed (moved to embassy-time-queue-driver) - embassy-time no longer provides an `embassy-time-queue-driver` implementation ## 0.3.2 - 2024-08-05 diff --git a/embassy-time/Cargo.toml b/embassy-time/Cargo.toml index 4f4ea0b14..eeac7dc29 100644 --- a/embassy-time/Cargo.toml +++ b/embassy-time/Cargo.toml @@ -42,6 +42,31 @@ defmt-timestamp-uptime-tus = ["defmt"] ## Create a `MockDriver` that can be manually advanced for testing purposes. mock-driver = ["tick-hz-1_000_000", "dep:embassy-time-queue-driver"] +#! ### Generic Queue + +#! By default embassy-time uses a timer queue implementation that is faster but depends on `embassy-executor`. +#! It will panic if you try to await any timer when using another executor. +#! +#! Alternatively, you can choose to use a "generic" timer queue implementation that works on any executor. +#! To enable it, enable any of the features below. +#! +#! The features also set how many timers are used for the generic queue. At most one +#! `generic-queue-*` feature can be enabled. If none is enabled, a default of 64 timers is used. +#! +#! When using embassy-time from libraries, you should *not* enable any `generic-queue-*` feature, to allow the +#! end user to pick. + +## Generic Queue with 8 timers +generic-queue-8 = ["embassy-time-queue-driver/generic-queue-8"] +## Generic Queue with 16 timers +generic-queue-16 = ["embassy-time-queue-driver/generic-queue-16"] +## Generic Queue with 32 timers +generic-queue-32 = ["embassy-time-queue-driver/generic-queue-32"] +## Generic Queue with 64 timers +generic-queue-64 = ["embassy-time-queue-driver/generic-queue-64"] +## Generic Queue with 128 timers +generic-queue-128 = ["embassy-time-queue-driver/generic-queue-128"] + #! ### Tick Rate #! #! At most 1 `tick-*` feature can be enabled. If none is enabled, a default of 1MHz is used. From b35b45e151e324d5b64c54f3443bf714ef367551 Mon Sep 17 00:00:00 2001 From: elagil Date: Sun, 22 Dec 2024 15:06:42 +0100 Subject: [PATCH 0523/1217] feat: stm32h5 UCPD example --- embassy-stm32/src/ucpd.rs | 40 +++++++++++++ examples/stm32h5/src/bin/usb_c_pd.rs | 90 ++++++++++++++++++++++++++++ 2 files changed, 130 insertions(+) create mode 100644 examples/stm32h5/src/bin/usb_c_pd.rs diff --git a/embassy-stm32/src/ucpd.rs b/embassy-stm32/src/ucpd.rs index ee0a2c7c1..ac31f46a4 100644 --- a/embassy-stm32/src/ucpd.rs +++ b/embassy-stm32/src/ucpd.rs @@ -175,6 +175,21 @@ impl<'d, T: Instance> Ucpd<'d, T> { w.set_ucpden(true); }); + r.cfgr2().write(|w| { + w.set_rxafilten(true); + }); + + // Software trim according to RM0481, p. 2650 + #[cfg(stm32h5)] + { + let trim_rd_cc1 = unsafe { *(0x4002_242C as *const u32) & 0xF }; + let trim_rd_cc2 = unsafe { ((*(0x4002_242C as *const u32)) >> 8) & 0xF }; + + r.cfgr3().write(|w| { + w.set_trim_cc1_rd(trim_rd_cc1 as u8); + w.set_trim_cc2_rd(trim_rd_cc2 as u8); + }); + } Self { cc_phy: CcPhy { _lifetime: PhantomData }, } @@ -278,6 +293,31 @@ impl<'d, T: Instance> CcPhy<'d, T> { }); }); + // Software trim according to RM0481, p. 2668 + #[cfg(stm32h5)] + T::REGS.cfgr3().modify(|w| match cc_pull { + CcPull::Source1_5A => { + #[cfg(stm32h5)] + { + let trim_1a5_cc1 = unsafe { *(0x08FF_F844 as *const u32) & 0xF }; + let trim_1a5_cc2 = unsafe { ((*(0x08FF_F844 as *const u32)) >> 16) & 0xF }; + + w.set_trim_cc1_rp(trim_1a5_cc1 as u8); + w.set_trim_cc2_rp(trim_1a5_cc2 as u8); + }; + } + _ => { + #[cfg(stm32h5)] + { + let trim_3a0_cc1 = unsafe { (*(0x4002_242C as *const u32) >> 4) & 0xF }; + let trim_3a0_cc2 = unsafe { ((*(0x4002_242C as *const u32)) >> 12) & 0xF }; + + w.set_trim_cc1_rp(trim_3a0_cc1 as u8); + w.set_trim_cc2_rp(trim_3a0_cc2 as u8); + }; + } + }); + // Disable dead-battery pull-down resistors which are enabled by default on boot. critical_section::with(|cs| { init( diff --git a/examples/stm32h5/src/bin/usb_c_pd.rs b/examples/stm32h5/src/bin/usb_c_pd.rs new file mode 100644 index 000000000..3bf3ab258 --- /dev/null +++ b/examples/stm32h5/src/bin/usb_c_pd.rs @@ -0,0 +1,90 @@ +#![no_std] +#![no_main] + +use defmt::{error, info, Format}; +use embassy_executor::Spawner; +use embassy_stm32::gpio::Output; +use embassy_stm32::ucpd::{self, CcPhy, CcPull, CcSel, CcVState, Ucpd}; +use embassy_stm32::{bind_interrupts, peripherals, Config}; +use embassy_time::{with_timeout, Duration}; +use {defmt_rtt as _, panic_probe as _}; + +bind_interrupts!(struct Irqs { + UCPD1 => ucpd::InterruptHandler; +}); + +#[derive(Debug, Format)] +enum CableOrientation { + Normal, + Flipped, + DebugAccessoryMode, +} + +// Returns true when the cable +async fn wait_attached(cc_phy: &mut CcPhy<'_, T>) -> CableOrientation { + loop { + let (cc1, cc2) = cc_phy.vstate(); + if cc1 == CcVState::LOWEST && cc2 == CcVState::LOWEST { + // Detached, wait until attached by monitoring the CC lines. + cc_phy.wait_for_vstate_change().await; + continue; + } + + // Attached, wait for CC lines to be stable for tCCDebounce (100..200ms). + if with_timeout(Duration::from_millis(100), cc_phy.wait_for_vstate_change()) + .await + .is_ok() + { + // State has changed, restart detection procedure. + continue; + }; + + // State was stable for the complete debounce period, check orientation. + return match (cc1, cc2) { + (_, CcVState::LOWEST) => CableOrientation::Normal, // CC1 connected + (CcVState::LOWEST, _) => CableOrientation::Flipped, // CC2 connected + _ => CableOrientation::DebugAccessoryMode, // Both connected (special cable) + }; + } +} + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let config = Config::default(); + let p = embassy_stm32::init(config); + + info!("Hello World!"); + + // This pin controls the dead-battery mode on the attached TCPP01-M12. + // If low, TCPP01-M12 disconnects CC lines and presents dead-battery resistance on CC lines, thus set high. + let _tcpp01_m12_ndb = Output::new(p.PA9, embassy_stm32::gpio::Level::High, embassy_stm32::gpio::Speed::Low); + + let mut ucpd = Ucpd::new(p.UCPD1, Irqs {}, p.PB13, p.PB14, Default::default()); + ucpd.cc_phy().set_pull(CcPull::Sink); + + info!("Waiting for USB connection..."); + let cable_orientation = wait_attached(ucpd.cc_phy()).await; + info!("USB cable connected, orientation: {}", cable_orientation); + + let cc_sel = match cable_orientation { + CableOrientation::Normal => { + info!("Starting PD communication on CC1 pin"); + CcSel::CC1 + } + CableOrientation::Flipped => { + info!("Starting PD communication on CC2 pin"); + CcSel::CC2 + } + CableOrientation::DebugAccessoryMode => panic!("No PD communication in DAM"), + }; + let (_cc_phy, mut pd_phy) = ucpd.split_pd_phy(p.GPDMA1_CH0, p.GPDMA1_CH1, cc_sel); + + loop { + // Enough space for the longest non-extended data message. + let mut buf = [0_u8; 30]; + match pd_phy.receive(buf.as_mut()).await { + Ok(n) => info!("USB PD RX: {=[u8]:?}", &buf[..n]), + Err(e) => error!("USB PD RX: {}", e), + } + } +} From c9cd46bdf5eef502f35deadd606aa154207c1d33 Mon Sep 17 00:00:00 2001 From: elagil Date: Sun, 22 Dec 2024 15:06:42 +0100 Subject: [PATCH 0524/1217] fix: h5-only rx filter --- embassy-stm32/src/ucpd.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/embassy-stm32/src/ucpd.rs b/embassy-stm32/src/ucpd.rs index ac31f46a4..2cfdcb415 100644 --- a/embassy-stm32/src/ucpd.rs +++ b/embassy-stm32/src/ucpd.rs @@ -175,6 +175,7 @@ impl<'d, T: Instance> Ucpd<'d, T> { w.set_ucpden(true); }); + #[cfg(stm32h5)] r.cfgr2().write(|w| { w.set_rxafilten(true); }); @@ -190,6 +191,7 @@ impl<'d, T: Instance> Ucpd<'d, T> { w.set_trim_cc2_rd(trim_rd_cc2 as u8); }); } + Self { cc_phy: CcPhy { _lifetime: PhantomData }, } From c08411f32ffd075b33dcab36e4612df30d08b2fa Mon Sep 17 00:00:00 2001 From: elagil Date: Sun, 22 Dec 2024 15:06:42 +0100 Subject: [PATCH 0525/1217] fix: docstrings --- embassy-stm32/src/ucpd.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/ucpd.rs b/embassy-stm32/src/ucpd.rs index 2cfdcb415..403d54f4b 100644 --- a/embassy-stm32/src/ucpd.rs +++ b/embassy-stm32/src/ucpd.rs @@ -180,7 +180,7 @@ impl<'d, T: Instance> Ucpd<'d, T> { w.set_rxafilten(true); }); - // Software trim according to RM0481, p. 2650 + // Software trim according to RM0481, p. 2650/2668 #[cfg(stm32h5)] { let trim_rd_cc1 = unsafe { *(0x4002_242C as *const u32) & 0xF }; @@ -295,7 +295,7 @@ impl<'d, T: Instance> CcPhy<'d, T> { }); }); - // Software trim according to RM0481, p. 2668 + // Software trim according to RM0481, p. 2650/2668 #[cfg(stm32h5)] T::REGS.cfgr3().modify(|w| match cc_pull { CcPull::Source1_5A => { From b6e70c8eb32353d9c437ee614f6728c9fd9158b6 Mon Sep 17 00:00:00 2001 From: elagil Date: Sun, 22 Dec 2024 15:06:42 +0100 Subject: [PATCH 0526/1217] fix: add docstring for target platform --- examples/stm32h5/src/bin/usb_c_pd.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples/stm32h5/src/bin/usb_c_pd.rs b/examples/stm32h5/src/bin/usb_c_pd.rs index 3bf3ab258..00cb3b3da 100644 --- a/examples/stm32h5/src/bin/usb_c_pd.rs +++ b/examples/stm32h5/src/bin/usb_c_pd.rs @@ -1,3 +1,5 @@ +//! This example targets the NUCLEO-H563ZI platform. +//! USB-C CC lines are protected by a TCPP01-M12 chipset. #![no_std] #![no_main] From 2ec81419fa7ca1d1d4c797c1d416c1f226aefb33 Mon Sep 17 00:00:00 2001 From: Daniel Trnka Date: Sat, 21 Dec 2024 22:01:36 +0100 Subject: [PATCH 0527/1217] stm32/usart: configurable readback in half-duplex mode --- embassy-stm32/src/usart/mod.rs | 54 +++++++++++++++++++++++++++------- 1 file changed, 44 insertions(+), 10 deletions(-) diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index 2d801e6bf..98b5c9cfe 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -125,6 +125,33 @@ pub enum StopBits { STOP1P5, } +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +/// Enables or disables receiver so written data are read back in half-duplex mode +pub enum HalfDuplexReadback { + /// Disables receiver so written data are not read back + NoReadback, + /// Enables receiver so written data are read back + Readback, +} + +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +/// Duplex mode +pub enum Duplex { + /// Full duplex + Full, + /// Half duplex with possibility to read back written data + Half(HalfDuplexReadback), +} + +impl Duplex { + /// Returns true if half-duplex + fn is_half(&self) -> bool { + matches!(self, Duplex::Half(_)) + } +} + #[non_exhaustive] #[derive(Clone, Copy, PartialEq, Eq, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -181,7 +208,7 @@ pub struct Config { pub rx_pull: Pull, // private: set by new_half_duplex, not by the user. - half_duplex: bool, + duplex: Duplex, } impl Config { @@ -220,7 +247,7 @@ impl Default for Config { #[cfg(any(usart_v3, usart_v4))] invert_rx: false, rx_pull: Pull::None, - half_duplex: false, + duplex: Duplex::Full, } } } @@ -308,6 +335,7 @@ pub struct UartTx<'d, M: Mode> { cts: Option>, de: Option>, tx_dma: Option>, + duplex: Duplex, _phantom: PhantomData, } @@ -413,7 +441,7 @@ impl<'d> UartTx<'d, Async> { let mut cr1 = r.cr1().read(); if r.cr3().read().hdsel() && !cr1.te() { cr1.set_te(true); - cr1.set_re(false); + cr1.set_re(self.duplex == Duplex::Half(HalfDuplexReadback::Readback)); r.cr1().write_value(cr1); } @@ -485,6 +513,7 @@ impl<'d, M: Mode> UartTx<'d, M> { cts, de: None, tx_dma, + duplex: config.duplex, _phantom: PhantomData, }; this.enable_and_configure(&config)?; @@ -519,7 +548,7 @@ impl<'d, M: Mode> UartTx<'d, M> { let mut cr1 = r.cr1().read(); if r.cr3().read().hdsel() && !cr1.te() { cr1.set_te(true); - cr1.set_re(false); + cr1.set_re(self.duplex == Duplex::Half(HalfDuplexReadback::Readback)); r.cr1().write_value(cr1); } @@ -1149,13 +1178,14 @@ impl<'d> Uart<'d, Async> { tx_dma: impl Peripheral

> + 'd, rx_dma: impl Peripheral

> + 'd, mut config: Config, + readback: HalfDuplexReadback, half_duplex: HalfDuplexConfig, ) -> Result { #[cfg(not(any(usart_v1, usart_v2)))] { config.swap_rx_tx = false; } - config.half_duplex = true; + config.duplex = Duplex::Half(readback); Self::new_inner( peri, @@ -1188,10 +1218,11 @@ impl<'d> Uart<'d, Async> { tx_dma: impl Peripheral

> + 'd, rx_dma: impl Peripheral

> + 'd, mut config: Config, + readback: HalfDuplexReadback, half_duplex: HalfDuplexConfig, ) -> Result { config.swap_rx_tx = true; - config.half_duplex = true; + config.duplex = Duplex::Half(readback); Self::new_inner( peri, @@ -1307,13 +1338,14 @@ impl<'d> Uart<'d, Blocking> { peri: impl Peripheral

+ 'd, tx: impl Peripheral

> + 'd, mut config: Config, + readback: HalfDuplexReadback, half_duplex: HalfDuplexConfig, ) -> Result { #[cfg(not(any(usart_v1, usart_v2)))] { config.swap_rx_tx = false; } - config.half_duplex = true; + config.duplex = Duplex::Half(readback); Self::new_inner( peri, @@ -1343,10 +1375,11 @@ impl<'d> Uart<'d, Blocking> { peri: impl Peripheral

+ 'd, rx: impl Peripheral

> + 'd, mut config: Config, + readback: HalfDuplexReadback, half_duplex: HalfDuplexConfig, ) -> Result { config.swap_rx_tx = true; - config.half_duplex = true; + config.duplex = Duplex::Half(readback); Self::new_inner( peri, @@ -1388,6 +1421,7 @@ impl<'d, M: Mode> Uart<'d, M> { cts, de, tx_dma, + duplex: config.duplex, }, rx: UartRx { _phantom: PhantomData, @@ -1667,14 +1701,14 @@ fn configure( r.cr3().modify(|w| { #[cfg(not(usart_v1))] w.set_onebit(config.assume_noise_free); - w.set_hdsel(config.half_duplex); + w.set_hdsel(config.duplex.is_half()); }); r.cr1().write(|w| { // enable uart w.set_ue(true); - if config.half_duplex { + if config.duplex.is_half() { // The te and re bits will be set by write, read and flush methods. // Receiver should be enabled by default for Half-Duplex. w.set_te(false); From 7b7ac1bd3ea2eb4897b8fcab706da968188bb700 Mon Sep 17 00:00:00 2001 From: Daniel Trnka Date: Sun, 22 Dec 2024 12:53:05 +0100 Subject: [PATCH 0528/1217] stm32/usart: disabling receiver before write in half-duplex moved to a new function --- embassy-stm32/src/usart/mod.rs | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index 98b5c9cfe..48cc4f6d6 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -437,13 +437,7 @@ impl<'d> UartTx<'d, Async> { pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> { let r = self.info.regs; - // Enable Transmitter and disable Receiver for Half-Duplex mode - let mut cr1 = r.cr1().read(); - if r.cr3().read().hdsel() && !cr1.te() { - cr1.set_te(true); - cr1.set_re(self.duplex == Duplex::Half(HalfDuplexReadback::Readback)); - r.cr1().write_value(cr1); - } + half_duplex_set_rx_tx_before_write(&r, self.duplex == Duplex::Half(HalfDuplexReadback::Readback)); let ch = self.tx_dma.as_mut().unwrap(); r.cr3().modify(|reg| { @@ -544,13 +538,7 @@ impl<'d, M: Mode> UartTx<'d, M> { pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> { let r = self.info.regs; - // Enable Transmitter and disable Receiver for Half-Duplex mode - let mut cr1 = r.cr1().read(); - if r.cr3().read().hdsel() && !cr1.te() { - cr1.set_te(true); - cr1.set_re(self.duplex == Duplex::Half(HalfDuplexReadback::Readback)); - r.cr1().write_value(cr1); - } + half_duplex_set_rx_tx_before_write(&r, self.duplex == Duplex::Half(HalfDuplexReadback::Readback)); for &b in buffer { while !sr(r).read().txe() {} @@ -629,6 +617,17 @@ pub fn send_break(regs: &Regs) { regs.rqr().write(|w| w.set_sbkrq(true)); } +/// Enable Transmitter and disable Receiver for Half-Duplex mode +/// In case of readback, keep Receiver enabled +fn half_duplex_set_rx_tx_before_write(r: &Regs, enable_readback: bool) { + let mut cr1 = r.cr1().read(); + if r.cr3().read().hdsel() && !cr1.te() { + cr1.set_te(true); + cr1.set_re(enable_readback); + r.cr1().write_value(cr1); + } +} + impl<'d> UartRx<'d, Async> { /// Create a new rx-only UART with no hardware flow control. /// From a7983668da2947f7846f0abc4736708539aedc42 Mon Sep 17 00:00:00 2001 From: Daniel Trnka Date: Sat, 21 Dec 2024 13:29:00 +0100 Subject: [PATCH 0529/1217] stm32/usart: half-duplex support for buffered usart --- embassy-stm32/src/usart/buffered.rs | 100 +++++++++++++++++++++++++++- 1 file changed, 98 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs index 814be2858..7bbe01a00 100644 --- a/embassy-stm32/src/usart/buffered.rs +++ b/embassy-stm32/src/usart/buffered.rs @@ -12,8 +12,9 @@ use embassy_sync::waitqueue::AtomicWaker; #[cfg(not(any(usart_v1, usart_v2)))] use super::DePin; use super::{ - clear_interrupt_flags, configure, rdr, reconfigure, send_break, set_baudrate, sr, tdr, Config, ConfigError, CtsPin, - Error, Info, Instance, Regs, RtsPin, RxPin, TxPin, + clear_interrupt_flags, configure, half_duplex_set_rx_tx_before_write, rdr, reconfigure, send_break, set_baudrate, + sr, tdr, Config, ConfigError, CtsPin, Duplex, Error, HalfDuplexConfig, HalfDuplexReadback, Info, Instance, Regs, + RtsPin, RxPin, TxPin, }; use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed}; use crate::interrupt::{self, InterruptExt}; @@ -108,6 +109,8 @@ unsafe fn on_interrupt(r: Regs, state: &'static State) { }); } + half_duplex_set_rx_tx_before_write(&r, state.half_duplex_readback.load(Ordering::Relaxed)); + tdr(r).write_volatile(buf[0].into()); tx_reader.pop_done(1); } else { @@ -126,6 +129,7 @@ pub(super) struct State { tx_buf: RingBuffer, tx_done: AtomicBool, tx_rx_refcount: AtomicU8, + half_duplex_readback: AtomicBool, } impl State { @@ -137,6 +141,7 @@ impl State { tx_waker: AtomicWaker::new(), tx_done: AtomicBool::new(true), tx_rx_refcount: AtomicU8::new(0), + half_duplex_readback: AtomicBool::new(false), } } } @@ -321,6 +326,84 @@ impl<'d> BufferedUart<'d> { ) } + /// Create a single-wire half-duplex Uart transceiver on a single Tx pin. + /// + /// See [`new_half_duplex_on_rx`][`Self::new_half_duplex_on_rx`] if you would prefer to use an Rx pin + /// (when it is available for your chip). There is no functional difference between these methods, as both + /// allow bidirectional communication. + /// + /// The TX pin is always released when no data is transmitted. Thus, it acts as a standard + /// I/O in idle or in reception. It means that the I/O must be configured so that TX is + /// configured as alternate function open-drain with an external pull-up + /// Apart from this, the communication protocol is similar to normal USART mode. Any conflict + /// on the line must be managed by software (for instance by using a centralized arbiter). + #[doc(alias("HDSEL"))] + pub fn new_half_duplex( + peri: impl Peripheral

+ 'd, + tx: impl Peripheral

> + 'd, + _irq: impl interrupt::typelevel::Binding> + 'd, + tx_buffer: &'d mut [u8], + rx_buffer: &'d mut [u8], + mut config: Config, + readback: HalfDuplexReadback, + half_duplex: HalfDuplexConfig, + ) -> Result { + #[cfg(not(any(usart_v1, usart_v2)))] + { + config.swap_rx_tx = false; + } + config.duplex = Duplex::Half(readback); + + Self::new_inner( + peri, + None, + new_pin!(tx, half_duplex.af_type()), + None, + None, + None, + tx_buffer, + rx_buffer, + config, + ) + } + + /// Create a single-wire half-duplex Uart transceiver on a single Rx pin. + /// + /// See [`new_half_duplex`][`Self::new_half_duplex`] if you would prefer to use an Tx pin. + /// There is no functional difference between these methods, as both allow bidirectional communication. + /// + /// The pin is always released when no data is transmitted. Thus, it acts as a standard + /// I/O in idle or in reception. + /// Apart from this, the communication protocol is similar to normal USART mode. Any conflict + /// on the line must be managed by software (for instance by using a centralized arbiter). + #[cfg(not(any(usart_v1, usart_v2)))] + #[doc(alias("HDSEL"))] + pub fn new_half_duplex_on_rx( + peri: impl Peripheral

+ 'd, + rx: impl Peripheral

> + 'd, + _irq: impl interrupt::typelevel::Binding> + 'd, + tx_buffer: &'d mut [u8], + rx_buffer: &'d mut [u8], + mut config: Config, + readback: HalfDuplexReadback, + half_duplex: HalfDuplexConfig, + ) -> Result { + config.swap_rx_tx = true; + config.duplex = Duplex::Half(readback); + + Self::new_inner( + peri, + new_pin!(rx, half_duplex.af_type()), + None, + None, + None, + None, + tx_buffer, + rx_buffer, + config, + ) + } + fn new_inner( _peri: impl Peripheral

+ 'd, rx: Option>, @@ -336,6 +419,11 @@ impl<'d> BufferedUart<'d> { let state = T::buffered_state(); let kernel_clock = T::frequency(); + state.half_duplex_readback.store( + config.duplex == Duplex::Half(HalfDuplexReadback::Readback), + Ordering::Relaxed, + ); + let mut this = Self { rx: BufferedUartRx { info, @@ -381,12 +469,20 @@ impl<'d> BufferedUart<'d> { w.set_ctse(self.tx.cts.is_some()); #[cfg(not(any(usart_v1, usart_v2)))] w.set_dem(self.tx.de.is_some()); + w.set_hdsel(config.duplex.is_half()); }); configure(info, self.rx.kernel_clock, &config, true, true)?; info.regs.cr1().modify(|w| { w.set_rxneie(true); w.set_idleie(true); + + if config.duplex.is_half() { + // The te and re bits will be set by write, read and flush methods. + // Receiver should be enabled by default for Half-Duplex. + w.set_te(false); + w.set_re(true); + } }); info.interrupt.unpend(); From 7070f5364eb903c6c6b0b28348a582f5a9e1f89e Mon Sep 17 00:00:00 2001 From: Daniel Trnka Date: Sun, 22 Dec 2024 17:37:20 +0100 Subject: [PATCH 0530/1217] examples/stm32g0: added ds18b20 temperature sensor on 1-wire bus --- examples/stm32g0/src/bin/onewire_ds18b20.rs | 271 ++++++++++++++++++++ 1 file changed, 271 insertions(+) create mode 100644 examples/stm32g0/src/bin/onewire_ds18b20.rs diff --git a/examples/stm32g0/src/bin/onewire_ds18b20.rs b/examples/stm32g0/src/bin/onewire_ds18b20.rs new file mode 100644 index 000000000..f85cc4ff8 --- /dev/null +++ b/examples/stm32g0/src/bin/onewire_ds18b20.rs @@ -0,0 +1,271 @@ +//! This examples shows how you can use buffered or DMA UART to read a DS18B20 temperature sensor on 1-Wire bus. +//! Connect 5k pull-up resistor between PA9 and 3.3V. +#![no_std] +#![no_main] + +use cortex_m::singleton; +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::mode::Async; +use embassy_stm32::usart::{ + BufferedUartRx, BufferedUartTx, Config, ConfigError, HalfDuplexConfig, RingBufferedUartRx, UartTx, +}; +use embassy_stm32::{bind_interrupts, peripherals, usart}; +use embassy_time::{Duration, Timer}; +use {defmt_rtt as _, panic_probe as _}; + +/// Create onewire bus using DMA USART +fn create_onewire(p: embassy_stm32::Peripherals) -> OneWire, RingBufferedUartRx<'static>> { + use embassy_stm32::usart::Uart; + bind_interrupts!(struct Irqs { + USART1 => usart::InterruptHandler; + }); + + let usart = Uart::new_half_duplex( + p.USART1, + p.PA9, + Irqs, + p.DMA1_CH1, + p.DMA1_CH2, + Config::default(), + // Enable readback so we can read sensor pulling data low while transmission is in progress + usart::HalfDuplexReadback::Readback, + HalfDuplexConfig::OpenDrainExternal, + ) + .unwrap(); + + const BUFFER_SIZE: usize = 16; + let (tx, rx) = usart.split(); + let rx_buf: &mut [u8; BUFFER_SIZE] = singleton!(TX_BUF: [u8; BUFFER_SIZE] = [0; BUFFER_SIZE]).unwrap(); + let rx = rx.into_ring_buffered(rx_buf); + OneWire::new(tx, rx) +} + +/* +/// Create onewire bus using buffered USART +fn create_onewire(p: embassy_stm32::Peripherals) -> OneWire, BufferedUartRx<'static>> { + use embassy_stm32::usart::BufferedUart; + bind_interrupts!(struct Irqs { + USART1 => usart::BufferedInterruptHandler; + }); + + const BUFFER_SIZE: usize = 16; + let tx_buf: &mut [u8; BUFFER_SIZE] = singleton!(TX_BUF: [u8; BUFFER_SIZE] = [0; BUFFER_SIZE]).unwrap(); + let rx_buf: &mut [u8; BUFFER_SIZE] = singleton!(RX_BUF: [u8; BUFFER_SIZE] = [0; BUFFER_SIZE]).unwrap(); + let usart = BufferedUart::new_half_duplex( + p.USART1, + p.PA9, + Irqs, + tx_buf, + rx_buf, + Config::default(), + // Enable readback so we can read sensor pulling data low while transmission is in progress + usart::HalfDuplexReadback::Readback, + HalfDuplexConfig::OpenDrainExternal, + ) + .unwrap(); + let (tx, rx) = usart.split(); + OneWire::new(tx, rx) +} +*/ + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_stm32::init(Default::default()); + + let onewire = create_onewire(p); + let mut sensor = Ds18b20::new(onewire); + + loop { + // Start a new temperature measurement + sensor.start().await; + // Wait for the measurement to finish + Timer::after(Duration::from_secs(1)).await; + match sensor.temperature().await { + Ok(temp) => info!("temp = {:?} deg C", temp), + _ => error!("sensor error"), + } + Timer::after(Duration::from_secs(1)).await; + } +} + +pub trait SetBaudrate { + fn set_baudrate(&mut self, baudrate: u32) -> Result<(), ConfigError>; +} +impl SetBaudrate for BufferedUartTx<'_> { + fn set_baudrate(&mut self, baudrate: u32) -> Result<(), ConfigError> { + BufferedUartTx::set_baudrate(self, baudrate) + } +} +impl SetBaudrate for BufferedUartRx<'_> { + fn set_baudrate(&mut self, baudrate: u32) -> Result<(), ConfigError> { + BufferedUartRx::set_baudrate(self, baudrate) + } +} +impl SetBaudrate for RingBufferedUartRx<'_> { + fn set_baudrate(&mut self, baudrate: u32) -> Result<(), ConfigError> { + RingBufferedUartRx::set_baudrate(self, baudrate) + } +} +impl SetBaudrate for UartTx<'_, Async> { + fn set_baudrate(&mut self, baudrate: u32) -> Result<(), ConfigError> { + UartTx::set_baudrate(self, baudrate) + } +} + +/// Simplified OneWire bus driver +pub struct OneWire +where + TX: embedded_io_async::Write + SetBaudrate, + RX: embedded_io_async::Read + SetBaudrate, +{ + tx: TX, + rx: RX, +} + +impl OneWire +where + TX: embedded_io_async::Write + SetBaudrate, + RX: embedded_io_async::Read + SetBaudrate, +{ + // bitrate with one bit taking ~104 us + const RESET_BUADRATE: u32 = 9600; + // bitrate with one bit taking ~8.7 us + const BAUDRATE: u32 = 115200; + + // startbit + 8 low bits = 9 * 1/115200 = 78 us low pulse + const LOGIC_1_CHAR: u8 = 0xFF; + // startbit only = 1/115200 = 8.7 us low pulse + const LOGIC_0_CHAR: u8 = 0x00; + + // Address all devices on the bus + const COMMAND_SKIP_ROM: u8 = 0xCC; + + pub fn new(tx: TX, rx: RX) -> Self { + Self { tx, rx } + } + + fn set_baudrate(&mut self, baudrate: u32) -> Result<(), ConfigError> { + self.tx.set_baudrate(baudrate)?; + self.rx.set_baudrate(baudrate) + } + + /// Reset the bus by at least 480 us low pulse. + pub async fn reset(&mut self) { + // Switch to 9600 baudrate, so one bit takes ~104 us + self.set_baudrate(Self::RESET_BUADRATE).expect("set_baudrate failed"); + // Low USART start bit + 4x low bits = 5 * 104 us = 520 us low pulse + self.tx.write(&[0xF0]).await.expect("write failed"); + + // Read the value on the bus + let mut buffer = [0; 1]; + self.rx.read_exact(&mut buffer).await.expect("read failed"); + + // Switch back to 115200 baudrate, so one bit takes ~8.7 us + self.set_baudrate(Self::BAUDRATE).expect("set_baudrate failed"); + + // read and expect sensor pulled some high bits to low (device present) + if buffer[0] & 0xF != 0 || buffer[0] & 0xF0 == 0xF0 { + warn!("No device present"); + } + } + + /// Send byte and read response on the bus. + pub async fn write_read_byte(&mut self, byte: u8) -> u8 { + // One byte is sent as 8 UART characters + let mut tx = [0; 8]; + for (pos, char) in tx.iter_mut().enumerate() { + *char = if (byte >> pos) & 0x1 == 0x1 { + Self::LOGIC_1_CHAR + } else { + Self::LOGIC_0_CHAR + }; + } + self.tx.write_all(&tx).await.expect("write failed"); + + // Readback the value on the bus, sensors can pull logic 1 to 0 + let mut rx = [0; 8]; + self.rx.read_exact(&mut rx).await.expect("read failed"); + let mut bus_byte = 0; + for (pos, char) in rx.iter().enumerate() { + // if its 0xFF, sensor didnt pull the bus to low level + if *char == 0xFF { + bus_byte |= 1 << pos; + } + } + + bus_byte + } + + /// Read a byte from the bus. + pub async fn read_byte(&mut self) -> u8 { + self.write_read_byte(0xFF).await + } +} + +/// DS18B20 temperature sensor driver +pub struct Ds18b20 +where + TX: embedded_io_async::Write + SetBaudrate, + RX: embedded_io_async::Read + SetBaudrate, +{ + bus: OneWire, +} + +impl Ds18b20 +where + TX: embedded_io_async::Write + SetBaudrate, + RX: embedded_io_async::Read + SetBaudrate, +{ + /// Start a temperature conversion. + const FN_CONVERT_T: u8 = 0x44; + /// Read contents of the scratchpad containing the temperature. + const FN_READ_SCRATCHPAD: u8 = 0xBE; + + pub fn new(bus: OneWire) -> Self { + Self { bus } + } + + /// Start a new measurement. Allow at least 1000ms before getting `temperature`. + pub async fn start(&mut self) { + self.bus.reset().await; + self.bus.write_read_byte(OneWire::::COMMAND_SKIP_ROM).await; + self.bus.write_read_byte(Self::FN_CONVERT_T).await; + } + + /// Calculate CRC8 of the data + fn crc8(data: &[u8]) -> u8 { + let mut temp; + let mut data_byte; + let mut crc = 0; + for b in data { + data_byte = *b; + for _ in 0..8 { + temp = (crc ^ data_byte) & 0x01; + crc >>= 1; + if temp != 0 { + crc ^= 0x8C; + } + data_byte >>= 1; + } + } + crc + } + + /// Read the temperature. Ensure >1000ms has passed since `start` before calling this. + pub async fn temperature(&mut self) -> Result { + self.bus.reset().await; + self.bus.write_read_byte(OneWire::::COMMAND_SKIP_ROM).await; + self.bus.write_read_byte(Self::FN_READ_SCRATCHPAD).await; + + let mut data = [0; 9]; + for byte in data.iter_mut() { + *byte = self.bus.read_byte().await; + } + + match Self::crc8(&data) == 0 { + true => Ok(((data[1] as u16) << 8 | data[0] as u16) as f32 / 16.), + false => Err(()), + } + } +} From 9a238e6ad8aedf29b5f5af7308c7f5f50061242c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Wed, 18 Dec 2024 15:42:24 +0100 Subject: [PATCH 0531/1217] Prepare new embassy-time-*driver, embassy-executor, embassy-time --- cyw43/Cargo.toml | 2 +- docs/examples/basic/Cargo.toml | 4 ++-- embassy-boot-rp/Cargo.toml | 2 +- embassy-embedded-hal/Cargo.toml | 2 +- embassy-executor/CHANGELOG.md | 3 ++- embassy-executor/Cargo.toml | 4 ++-- embassy-net-adin1110/Cargo.toml | 2 +- embassy-net-enc28j60/Cargo.toml | 2 +- embassy-net-esp-hosted/Cargo.toml | 2 +- embassy-net-nrf91/Cargo.toml | 2 +- embassy-net-wiznet/Cargo.toml | 2 +- embassy-net/Cargo.toml | 2 +- embassy-nrf/Cargo.toml | 6 +++--- embassy-rp/Cargo.toml | 8 ++++---- embassy-stm32-wpan/Cargo.toml | 2 +- embassy-stm32/Cargo.toml | 8 ++++---- embassy-time-driver/CHANGELOG.md | 2 +- embassy-time-driver/Cargo.toml | 2 +- embassy-time-queue-driver/CHANGELOG.md | 2 +- embassy-time-queue-driver/Cargo.toml | 4 ++-- embassy-time/CHANGELOG.md | 2 +- embassy-time/Cargo.toml | 8 ++++---- embassy-usb-dfu/Cargo.toml | 2 +- examples/boot/application/nrf/Cargo.toml | 4 ++-- examples/boot/application/rp/Cargo.toml | 4 ++-- examples/boot/application/stm32f3/Cargo.toml | 4 ++-- examples/boot/application/stm32f7/Cargo.toml | 4 ++-- examples/boot/application/stm32h7/Cargo.toml | 4 ++-- examples/boot/application/stm32l0/Cargo.toml | 4 ++-- examples/boot/application/stm32l1/Cargo.toml | 4 ++-- examples/boot/application/stm32l4/Cargo.toml | 4 ++-- examples/boot/application/stm32wb-dfu/Cargo.toml | 4 ++-- examples/boot/application/stm32wl/Cargo.toml | 4 ++-- examples/lpc55s69/Cargo.toml | 4 ++-- examples/nrf-rtos-trace/Cargo.toml | 4 ++-- examples/nrf51/Cargo.toml | 4 ++-- examples/nrf52810/Cargo.toml | 4 ++-- examples/nrf52840-rtic/Cargo.toml | 4 ++-- examples/nrf52840/Cargo.toml | 4 ++-- examples/nrf5340/Cargo.toml | 4 ++-- examples/nrf54l15/Cargo.toml | 4 ++-- examples/nrf9151/ns/Cargo.toml | 4 ++-- examples/nrf9151/s/Cargo.toml | 4 ++-- examples/nrf9160/Cargo.toml | 4 ++-- examples/rp/Cargo.toml | 4 ++-- examples/rp23/Cargo.toml | 4 ++-- examples/std/Cargo.toml | 4 ++-- examples/stm32c0/Cargo.toml | 4 ++-- examples/stm32f0/Cargo.toml | 4 ++-- examples/stm32f1/Cargo.toml | 4 ++-- examples/stm32f2/Cargo.toml | 4 ++-- examples/stm32f3/Cargo.toml | 4 ++-- examples/stm32f334/Cargo.toml | 4 ++-- examples/stm32f4/Cargo.toml | 4 ++-- examples/stm32f469/Cargo.toml | 4 ++-- examples/stm32f7/Cargo.toml | 4 ++-- examples/stm32g0/Cargo.toml | 4 ++-- examples/stm32g4/Cargo.toml | 4 ++-- examples/stm32h5/Cargo.toml | 4 ++-- examples/stm32h7/Cargo.toml | 4 ++-- examples/stm32h723/Cargo.toml | 4 ++-- examples/stm32h735/Cargo.toml | 4 ++-- examples/stm32h755cm4/Cargo.toml | 4 ++-- examples/stm32h755cm7/Cargo.toml | 4 ++-- examples/stm32h7b0/Cargo.toml | 4 ++-- examples/stm32h7rs/Cargo.toml | 4 ++-- examples/stm32l0/Cargo.toml | 4 ++-- examples/stm32l1/Cargo.toml | 4 ++-- examples/stm32l4/Cargo.toml | 4 ++-- examples/stm32l5/Cargo.toml | 4 ++-- examples/stm32u0/Cargo.toml | 4 ++-- examples/stm32u5/Cargo.toml | 4 ++-- examples/stm32wb/Cargo.toml | 4 ++-- examples/stm32wba/Cargo.toml | 4 ++-- examples/stm32wl/Cargo.toml | 4 ++-- examples/wasm/Cargo.toml | 4 ++-- tests/nrf/Cargo.toml | 4 ++-- tests/perf-client/Cargo.toml | 2 +- tests/riscv32/Cargo.toml | 4 ++-- tests/rp/Cargo.toml | 4 ++-- tests/stm32/Cargo.toml | 4 ++-- 81 files changed, 153 insertions(+), 152 deletions(-) diff --git a/cyw43/Cargo.toml b/cyw43/Cargo.toml index 7c0260868..334e1f75e 100644 --- a/cyw43/Cargo.toml +++ b/cyw43/Cargo.toml @@ -18,7 +18,7 @@ bluetooth = ["dep:bt-hci", "dep:embedded-io-async"] firmware-logs = [] [dependencies] -embassy-time = { version = "0.3.2", path = "../embassy-time"} +embassy-time = { version = "0.4.0", path = "../embassy-time"} embassy-sync = { version = "0.6.1", path = "../embassy-sync"} embassy-futures = { version = "0.1.0", path = "../embassy-futures"} embassy-net-driver-channel = { version = "0.3.0", path = "../embassy-net-driver-channel"} diff --git a/docs/examples/basic/Cargo.toml b/docs/examples/basic/Cargo.toml index daf83873d..613fc2041 100644 --- a/docs/examples/basic/Cargo.toml +++ b/docs/examples/basic/Cargo.toml @@ -6,8 +6,8 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-executor = { version = "0.6.3", path = "../../../embassy-executor", features = ["defmt", "arch-cortex-m", "executor-thread"] } -embassy-time = { version = "0.3.2", path = "../../../embassy-time", features = ["defmt"] } +embassy-executor = { version = "0.7.0", path = "../../../embassy-executor", features = ["defmt", "arch-cortex-m", "executor-thread"] } +embassy-time = { version = "0.4.0", path = "../../../embassy-time", features = ["defmt"] } embassy-nrf = { version = "0.2.0", path = "../../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote"] } defmt = "0.3" diff --git a/embassy-boot-rp/Cargo.toml b/embassy-boot-rp/Cargo.toml index fa603047e..23994c171 100644 --- a/embassy-boot-rp/Cargo.toml +++ b/embassy-boot-rp/Cargo.toml @@ -27,7 +27,7 @@ log = { version = "0.4", optional = true } embassy-sync = { version = "0.6.1", path = "../embassy-sync" } embassy-rp = { version = "0.2.0", path = "../embassy-rp", default-features = false } embassy-boot = { version = "0.3.0", path = "../embassy-boot" } -embassy-time = { version = "0.3.2", path = "../embassy-time" } +embassy-time = { version = "0.4.0", path = "../embassy-time" } cortex-m = { version = "0.7.6" } cortex-m-rt = { version = "0.7" } diff --git a/embassy-embedded-hal/Cargo.toml b/embassy-embedded-hal/Cargo.toml index b7728c411..440d4b5fc 100644 --- a/embassy-embedded-hal/Cargo.toml +++ b/embassy-embedded-hal/Cargo.toml @@ -29,7 +29,7 @@ default = ["time"] [dependencies] embassy-futures = { version = "0.1.0", path = "../embassy-futures" } embassy-sync = { version = "0.6.1", path = "../embassy-sync" } -embassy-time = { version = "0.3.2", path = "../embassy-time", optional = true } +embassy-time = { version = "0.4.0", path = "../embassy-time", optional = true } embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = [ "unproven", ] } diff --git a/embassy-executor/CHANGELOG.md b/embassy-executor/CHANGELOG.md index 59ea88d0c..b45142802 100644 --- a/embassy-executor/CHANGELOG.md +++ b/embassy-executor/CHANGELOG.md @@ -5,12 +5,13 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## Unreleased +## 0.7.0 - 2024-12-18 - embassy-executor no longer provides an `embassy-time-queue-driver` implementation - Added `TaskRef::executor` to obtain a reference to a task's executor - integrated-timers are no longer processed when polling the executor. - Added the option to store data in timer queue items +- Added `timer-item-payload-size-X` features for time driver implementors ## 0.6.3 - 2024-11-12 diff --git a/embassy-executor/Cargo.toml b/embassy-executor/Cargo.toml index 5effaca65..d6f24ce84 100644 --- a/embassy-executor/Cargo.toml +++ b/embassy-executor/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "embassy-executor" -version = "0.6.3" +version = "0.7.0" edition = "2021" license = "MIT OR Apache-2.0" description = "async/await executor designed for embedded usage" @@ -34,7 +34,7 @@ log = { version = "0.4.14", optional = true } rtos-trace = { version = "0.1.3", optional = true } embassy-executor-macros = { version = "0.6.2", path = "../embassy-executor-macros" } -embassy-time-driver = { version = "0.1.0", path = "../embassy-time-driver", optional = true } +embassy-time-driver = { version = "0.2", path = "../embassy-time-driver", optional = true } critical-section = "1.1" document-features = "0.2.7" diff --git a/embassy-net-adin1110/Cargo.toml b/embassy-net-adin1110/Cargo.toml index 0b2a6744d..3c988a732 100644 --- a/embassy-net-adin1110/Cargo.toml +++ b/embassy-net-adin1110/Cargo.toml @@ -17,7 +17,7 @@ embedded-hal-1 = { package = "embedded-hal", version = "1.0" } embedded-hal-async = { version = "1.0" } embedded-hal-bus = { version = "0.1", features = ["async"] } embassy-net-driver-channel = { version = "0.3.0", path = "../embassy-net-driver-channel" } -embassy-time = { version = "0.3.2", path = "../embassy-time" } +embassy-time = { version = "0.4.0", path = "../embassy-time" } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } bitfield = "0.14.0" diff --git a/embassy-net-enc28j60/Cargo.toml b/embassy-net-enc28j60/Cargo.toml index cafced4b2..f3e66bbdb 100644 --- a/embassy-net-enc28j60/Cargo.toml +++ b/embassy-net-enc28j60/Cargo.toml @@ -13,7 +13,7 @@ documentation = "https://docs.embassy.dev/embassy-net-enc28j60" embedded-hal = { version = "1.0" } embedded-hal-async = { version = "1.0" } embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver" } -embassy-time = { version = "0.3.2", path = "../embassy-time" } +embassy-time = { version = "0.4.0", path = "../embassy-time" } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } defmt = { version = "0.3", optional = true } diff --git a/embassy-net-esp-hosted/Cargo.toml b/embassy-net-esp-hosted/Cargo.toml index d22ccb101..45534925d 100644 --- a/embassy-net-esp-hosted/Cargo.toml +++ b/embassy-net-esp-hosted/Cargo.toml @@ -17,7 +17,7 @@ log = [ "dep:log" ] defmt = { version = "0.3", optional = true } log = { version = "0.4.14", optional = true } -embassy-time = { version = "0.3.2", path = "../embassy-time" } +embassy-time = { version = "0.4.0", path = "../embassy-time" } embassy-sync = { version = "0.6.1", path = "../embassy-sync"} embassy-futures = { version = "0.1.0", path = "../embassy-futures"} embassy-net-driver-channel = { version = "0.3.0", path = "../embassy-net-driver-channel"} diff --git a/embassy-net-nrf91/Cargo.toml b/embassy-net-nrf91/Cargo.toml index f9e55c0b1..4e2f17ab2 100644 --- a/embassy-net-nrf91/Cargo.toml +++ b/embassy-net-nrf91/Cargo.toml @@ -20,7 +20,7 @@ log = { version = "0.4.14", optional = true } nrf-pac = { git = "https://github.com/embassy-rs/nrf-pac", rev = "52e3a757f06035c94291bfc42b0c03f71e4d677e" } cortex-m = "0.7.7" -embassy-time = { version = "0.3.1", path = "../embassy-time" } +embassy-time = { version = "0.4.0", path = "../embassy-time" } embassy-sync = { version = "0.6.1", path = "../embassy-sync"} embassy-futures = { version = "0.1.0", path = "../embassy-futures"} embassy-net-driver-channel = { version = "0.3.0", path = "../embassy-net-driver-channel"} diff --git a/embassy-net-wiznet/Cargo.toml b/embassy-net-wiznet/Cargo.toml index e7fb3f455..30c76d46e 100644 --- a/embassy-net-wiznet/Cargo.toml +++ b/embassy-net-wiznet/Cargo.toml @@ -13,7 +13,7 @@ documentation = "https://docs.embassy.dev/embassy-net-wiznet" embedded-hal = { version = "1.0" } embedded-hal-async = { version = "1.0" } embassy-net-driver-channel = { version = "0.3.0", path = "../embassy-net-driver-channel" } -embassy-time = { version = "0.3.2", path = "../embassy-time" } +embassy-time = { version = "0.4.0", path = "../embassy-time" } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } defmt = { version = "0.3", optional = true } diff --git a/embassy-net/Cargo.toml b/embassy-net/Cargo.toml index 1d79a2a07..a59327367 100644 --- a/embassy-net/Cargo.toml +++ b/embassy-net/Cargo.toml @@ -74,7 +74,7 @@ smoltcp = { version = "0.12.0", default-features = false, features = [ ] } embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver" } -embassy-time = { version = "0.3.2", path = "../embassy-time" } +embassy-time = { version = "0.4.0", path = "../embassy-time" } embassy-sync = { version = "0.6.1", path = "../embassy-sync" } embedded-io-async = { version = "0.6.1" } diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml index 48f80bb5e..a1248c1ca 100644 --- a/embassy-nrf/Cargo.toml +++ b/embassy-nrf/Cargo.toml @@ -134,9 +134,9 @@ _gpio-p2 = [] _nrf52832_anomaly_109 = [] [dependencies] -embassy-time-driver = { version = "0.1", path = "../embassy-time-driver", optional = true } -embassy-time-queue-driver = { version = "0.1", path = "../embassy-time-queue-driver", optional = true } -embassy-time = { version = "0.3.2", path = "../embassy-time", optional = true } +embassy-time-driver = { version = "0.2", path = "../embassy-time-driver", optional = true } +embassy-time-queue-driver = { version = "0.2", path = "../embassy-time-queue-driver", optional = true } +embassy-time = { version = "0.4.0", path = "../embassy-time", optional = true } embassy-sync = { version = "0.6.1", path = "../embassy-sync" } embassy-hal-internal = {version = "0.2.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-3"] } embassy-embedded-hal = {version = "0.2.0", path = "../embassy-embedded-hal" } diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index 94de82fa9..5e2e08f38 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml @@ -109,9 +109,9 @@ binary-info = ["rt", "dep:rp-binary-info", "rp-binary-info?/binary-info"] [dependencies] embassy-sync = { version = "0.6.1", path = "../embassy-sync" } -embassy-time-driver = { version = "0.1", path = "../embassy-time-driver", optional = true } -embassy-time-queue-driver = { version = "0.1", path = "../embassy-time-queue-driver", optional = true } -embassy-time = { version = "0.3.2", path = "../embassy-time" } +embassy-time-driver = { version = "0.2", path = "../embassy-time-driver", optional = true } +embassy-time-queue-driver = { version = "0.2", path = "../embassy-time-queue-driver", optional = true } +embassy-time = { version = "0.4.0", path = "../embassy-time" } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } embassy-hal-internal = {version = "0.2.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-2"] } embassy-embedded-hal = {version = "0.2.0", path = "../embassy-embedded-hal" } @@ -148,5 +148,5 @@ rp-binary-info = { version = "0.1.0", optional = true } smart-leds = "0.4.0" [dev-dependencies] -embassy-executor = { version = "0.6.3", path = "../embassy-executor", features = ["arch-std", "executor-thread"] } +embassy-executor = { version = "0.7.0", path = "../embassy-executor", features = ["arch-std", "executor-thread"] } static_cell = { version = "2" } diff --git a/embassy-stm32-wpan/Cargo.toml b/embassy-stm32-wpan/Cargo.toml index 7dd1bc677..552d80982 100644 --- a/embassy-stm32-wpan/Cargo.toml +++ b/embassy-stm32-wpan/Cargo.toml @@ -21,7 +21,7 @@ features = ["stm32wb55rg"] [dependencies] embassy-stm32 = { version = "0.1.0", path = "../embassy-stm32" } embassy-sync = { version = "0.6.1", path = "../embassy-sync" } -embassy-time = { version = "0.3.2", path = "../embassy-time", optional = true } +embassy-time = { version = "0.4.0", path = "../embassy-time", optional = true } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } embassy-hal-internal = { version = "0.2.0", path = "../embassy-hal-internal" } embassy-embedded-hal = { version = "0.2.0", path = "../embassy-embedded-hal" } diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 47e9e8bb9..527d2dd30 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -43,16 +43,16 @@ rustdoc-args = ["--cfg", "docsrs"] [dependencies] embassy-sync = { version = "0.6.1", path = "../embassy-sync" } -embassy-time = { version = "0.3.2", path = "../embassy-time", optional = true } -embassy-time-driver = { version = "0.1", path = "../embassy-time-driver", optional = true } -embassy-time-queue-driver = { version = "0.1", path = "../embassy-time-queue-driver", optional = true } +embassy-time = { version = "0.4.0", path = "../embassy-time", optional = true } +embassy-time-driver = { version = "0.2", path = "../embassy-time-driver", optional = true } +embassy-time-queue-driver = { version = "0.2", path = "../embassy-time-queue-driver", optional = true } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } embassy-hal-internal = {version = "0.2.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-4"] } embassy-embedded-hal = {version = "0.2.0", path = "../embassy-embedded-hal", default-features = false } embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver" } embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver" } embassy-usb-synopsys-otg = {version = "0.2.0", path = "../embassy-usb-synopsys-otg" } -embassy-executor = { version = "0.6.3", path = "../embassy-executor", optional = true } +embassy-executor = { version = "0.7.0", path = "../embassy-executor", optional = true } embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } embedded-hal-1 = { package = "embedded-hal", version = "1.0" } diff --git a/embassy-time-driver/CHANGELOG.md b/embassy-time-driver/CHANGELOG.md index 2af1dc736..7e9be8949 100644 --- a/embassy-time-driver/CHANGELOG.md +++ b/embassy-time-driver/CHANGELOG.md @@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## Unreleased +## 0.2.0 - 2024-12-18 - The `allocate_alarm`, `set_alarm_callback`, `set_alarm` functions have been removed. - `schedule_wake` has been added to the `Driver` trait. diff --git a/embassy-time-driver/Cargo.toml b/embassy-time-driver/Cargo.toml index d9f2e97df..2a1d5ee1d 100644 --- a/embassy-time-driver/Cargo.toml +++ b/embassy-time-driver/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "embassy-time-driver" -version = "0.1.0" +version = "0.2.0" edition = "2021" description = "Driver trait for embassy-time" repository = "https://github.com/embassy-rs/embassy" diff --git a/embassy-time-queue-driver/CHANGELOG.md b/embassy-time-queue-driver/CHANGELOG.md index a99f250ed..46d00c87d 100644 --- a/embassy-time-queue-driver/CHANGELOG.md +++ b/embassy-time-queue-driver/CHANGELOG.md @@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## Unreleased +## 0.2.0 - 2024-12-18 - Added `generic-queue-N` features. - Added `embassy_time_queue_driver::Queue` struct which uses integrated or a generic storage (configured using `generic-queue-N`). diff --git a/embassy-time-queue-driver/Cargo.toml b/embassy-time-queue-driver/Cargo.toml index 7fa91bb0c..990393cc0 100644 --- a/embassy-time-queue-driver/Cargo.toml +++ b/embassy-time-queue-driver/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "embassy-time-queue-driver" -version = "0.1.0" +version = "0.2.0" edition = "2021" description = "Timer queue driver trait for embassy-time" repository = "https://github.com/embassy-rs/embassy" @@ -22,7 +22,7 @@ links = "embassy-time-queue" [dependencies] heapless = "0.8" -embassy-executor = { version = "0.6.3", path = "../embassy-executor" } +embassy-executor = { version = "0.7.0", path = "../embassy-executor" } [features] #! ### Generic Queue diff --git a/embassy-time/CHANGELOG.md b/embassy-time/CHANGELOG.md index 0026fbd08..ec3219818 100644 --- a/embassy-time/CHANGELOG.md +++ b/embassy-time/CHANGELOG.md @@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## Unreleased +## 0.4.0 - 2024-12-18 - embassy-time no longer provides an `embassy-time-queue-driver` implementation diff --git a/embassy-time/Cargo.toml b/embassy-time/Cargo.toml index eeac7dc29..23317c6d3 100644 --- a/embassy-time/Cargo.toml +++ b/embassy-time/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "embassy-time" -version = "0.3.2" +version = "0.4.0" edition = "2021" description = "Instant and Duration for embedded no-std systems, with async timer support" repository = "https://github.com/embassy-rs/embassy" @@ -408,8 +408,8 @@ tick-hz-5_242_880_000 = ["embassy-time-driver/tick-hz-5_242_880_000"] #! [dependencies] -embassy-time-driver = { version = "0.1.0", path = "../embassy-time-driver" } -embassy-time-queue-driver = { version = "0.1.0", path = "../embassy-time-queue-driver", optional = true} +embassy-time-driver = { version = "0.2", path = "../embassy-time-driver" } +embassy-time-queue-driver = { version = "0.2", path = "../embassy-time-queue-driver", optional = true} defmt = { version = "0.3", optional = true } log = { version = "0.4.14", optional = true } @@ -432,4 +432,4 @@ wasm-timer = { version = "0.2.5", optional = true } [dev-dependencies] serial_test = "0.9" critical-section = { version = "1.1", features = ["std"] } -embassy-executor = { version = "0.6.3", path = "../embassy-executor" } +embassy-executor = { version = "0.7.0", path = "../embassy-executor" } diff --git a/embassy-usb-dfu/Cargo.toml b/embassy-usb-dfu/Cargo.toml index 763c9600d..baee0205e 100644 --- a/embassy-usb-dfu/Cargo.toml +++ b/embassy-usb-dfu/Cargo.toml @@ -34,7 +34,7 @@ cortex-m = { version = "0.7.7", features = ["inline-asm"], optional = true } embassy-boot = { version = "0.3.0", path = "../embassy-boot" } embassy-futures = { version = "0.1.1", path = "../embassy-futures" } embassy-sync = { version = "0.6.1", path = "../embassy-sync" } -embassy-time = { version = "0.3.2", path = "../embassy-time" } +embassy-time = { version = "0.4.0", path = "../embassy-time" } embassy-usb = { version = "0.3.0", path = "../embassy-usb", default-features = false } embedded-storage = { version = "0.3.1" } esp32c3-hal = { version = "0.13.0", optional = true, default-features = false } diff --git a/examples/boot/application/nrf/Cargo.toml b/examples/boot/application/nrf/Cargo.toml index 45ad341fc..bfe6532ad 100644 --- a/examples/boot/application/nrf/Cargo.toml +++ b/examples/boot/application/nrf/Cargo.toml @@ -6,8 +6,8 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.6.3", path = "../../../../embassy-executor", features = ["task-arena-size-16384", "arch-cortex-m", "executor-thread", "arch-cortex-m", "executor-thread"] } -embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [] } +embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["task-arena-size-16384", "arch-cortex-m", "executor-thread", "arch-cortex-m", "executor-thread"] } +embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [] } embassy-nrf = { version = "0.2.0", path = "../../../../embassy-nrf", features = ["time-driver-rtc1", "gpiote", ] } embassy-boot = { version = "0.3.0", path = "../../../../embassy-boot", features = [] } embassy-boot-nrf = { version = "0.3.0", path = "../../../../embassy-boot-nrf", features = [] } diff --git a/examples/boot/application/rp/Cargo.toml b/examples/boot/application/rp/Cargo.toml index ec99f2605..6217cf64b 100644 --- a/examples/boot/application/rp/Cargo.toml +++ b/examples/boot/application/rp/Cargo.toml @@ -6,8 +6,8 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.6.3", path = "../../../../embassy-executor", features = ["task-arena-size-16384", "arch-cortex-m", "executor-thread", "arch-cortex-m", "executor-thread"] } -embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [] } +embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["task-arena-size-16384", "arch-cortex-m", "executor-thread", "arch-cortex-m", "executor-thread"] } +embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [] } embassy-rp = { version = "0.2.0", path = "../../../../embassy-rp", features = ["time-driver", "rp2040"] } embassy-boot-rp = { version = "0.3.0", path = "../../../../embassy-boot-rp", features = [] } embassy-embedded-hal = { version = "0.2.0", path = "../../../../embassy-embedded-hal" } diff --git a/examples/boot/application/stm32f3/Cargo.toml b/examples/boot/application/stm32f3/Cargo.toml index d2138db87..68f65e384 100644 --- a/examples/boot/application/stm32f3/Cargo.toml +++ b/examples/boot/application/stm32f3/Cargo.toml @@ -6,8 +6,8 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.6.3", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread"] } -embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } +embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread"] } +embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32f303re", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32" } embassy-embedded-hal = { version = "0.2.0", path = "../../../../embassy-embedded-hal" } diff --git a/examples/boot/application/stm32f7/Cargo.toml b/examples/boot/application/stm32f7/Cargo.toml index b86c66f5d..90391af5c 100644 --- a/examples/boot/application/stm32f7/Cargo.toml +++ b/examples/boot/application/stm32f7/Cargo.toml @@ -6,8 +6,8 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.6.3", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread"] } -embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } +embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread"] } +embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32f767zi", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } embassy-embedded-hal = { version = "0.2.0", path = "../../../../embassy-embedded-hal" } diff --git a/examples/boot/application/stm32h7/Cargo.toml b/examples/boot/application/stm32h7/Cargo.toml index e2e2fe711..33e210d44 100644 --- a/examples/boot/application/stm32h7/Cargo.toml +++ b/examples/boot/application/stm32h7/Cargo.toml @@ -6,8 +6,8 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.6.3", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread"] } -embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } +embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread"] } +embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32h743zi", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } embassy-embedded-hal = { version = "0.2.0", path = "../../../../embassy-embedded-hal" } diff --git a/examples/boot/application/stm32l0/Cargo.toml b/examples/boot/application/stm32l0/Cargo.toml index 7e9c52ffa..f9402904f 100644 --- a/examples/boot/application/stm32l0/Cargo.toml +++ b/examples/boot/application/stm32l0/Cargo.toml @@ -6,8 +6,8 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.6.3", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread"] } -embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } +embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread"] } +embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l072cz", "time-driver-any", "exti", "memory-x"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } embassy-embedded-hal = { version = "0.2.0", path = "../../../../embassy-embedded-hal" } diff --git a/examples/boot/application/stm32l1/Cargo.toml b/examples/boot/application/stm32l1/Cargo.toml index 42353a24c..d02986850 100644 --- a/examples/boot/application/stm32l1/Cargo.toml +++ b/examples/boot/application/stm32l1/Cargo.toml @@ -6,8 +6,8 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.6.3", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread"] } -embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } +embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread"] } +embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l151cb-a", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } embassy-embedded-hal = { version = "0.2.0", path = "../../../../embassy-embedded-hal" } diff --git a/examples/boot/application/stm32l4/Cargo.toml b/examples/boot/application/stm32l4/Cargo.toml index cf0b0242a..fedfe2b33 100644 --- a/examples/boot/application/stm32l4/Cargo.toml +++ b/examples/boot/application/stm32l4/Cargo.toml @@ -6,8 +6,8 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.6.3", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread"] } -embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } +embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread"] } +embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l475vg", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } embassy-embedded-hal = { version = "0.2.0", path = "../../../../embassy-embedded-hal" } diff --git a/examples/boot/application/stm32wb-dfu/Cargo.toml b/examples/boot/application/stm32wb-dfu/Cargo.toml index ea2879fb5..ab359a948 100644 --- a/examples/boot/application/stm32wb-dfu/Cargo.toml +++ b/examples/boot/application/stm32wb-dfu/Cargo.toml @@ -6,8 +6,8 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.6.3", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread"] } -embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } +embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread"] } +embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32wb55rg", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } embassy-embedded-hal = { version = "0.2.0", path = "../../../../embassy-embedded-hal" } diff --git a/examples/boot/application/stm32wl/Cargo.toml b/examples/boot/application/stm32wl/Cargo.toml index 6417b8430..8e24fdcf1 100644 --- a/examples/boot/application/stm32wl/Cargo.toml +++ b/examples/boot/application/stm32wl/Cargo.toml @@ -6,8 +6,8 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.6.3", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread"] } -embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } +embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread"] } +embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32wl55jc-cm4", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } embassy-embedded-hal = { version = "0.2.0", path = "../../../../embassy-embedded-hal" } diff --git a/examples/lpc55s69/Cargo.toml b/examples/lpc55s69/Cargo.toml index 41a88f082..1c8d5f456 100644 --- a/examples/lpc55s69/Cargo.toml +++ b/examples/lpc55s69/Cargo.toml @@ -7,9 +7,9 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-nxp = { version = "0.1.0", path = "../../embassy-nxp", features = ["rt"] } -embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt"] } +embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt"] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } -embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt"] } +embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt"] } panic-halt = "0.2.0" cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } cortex-m-rt = {version = "0.7.0"} diff --git a/examples/nrf-rtos-trace/Cargo.toml b/examples/nrf-rtos-trace/Cargo.toml index 6d13d668a..0623b27ea 100644 --- a/examples/nrf-rtos-trace/Cargo.toml +++ b/examples/nrf-rtos-trace/Cargo.toml @@ -16,8 +16,8 @@ log = [ [dependencies] embassy-sync = { version = "0.6.1", path = "../../embassy-sync" } -embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "rtos-trace"] } -embassy-time = { version = "0.3.2", path = "../../embassy-time" } +embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "rtos-trace"] } +embassy-time = { version = "0.4.0", path = "../../embassy-time" } embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] } cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } diff --git a/examples/nrf51/Cargo.toml b/examples/nrf51/Cargo.toml index 8d995cfd8..492ebadd7 100644 --- a/examples/nrf51/Cargo.toml +++ b/examples/nrf51/Cargo.toml @@ -5,8 +5,8 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-4096", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } -embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } +embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-4096", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } +embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf51", "gpiote", "time-driver-rtc1", "unstable-pac", "time", "rt"] } defmt = "0.3" diff --git a/examples/nrf52810/Cargo.toml b/examples/nrf52810/Cargo.toml index fa2a27aaa..8cd3b83e3 100644 --- a/examples/nrf52810/Cargo.toml +++ b/examples/nrf52810/Cargo.toml @@ -7,8 +7,8 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } -embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } +embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } +embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf52810", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } defmt = "0.3" diff --git a/examples/nrf52840-rtic/Cargo.toml b/examples/nrf52840-rtic/Cargo.toml index 6b15b24da..f3c660103 100644 --- a/examples/nrf52840-rtic/Cargo.toml +++ b/examples/nrf52840-rtic/Cargo.toml @@ -9,8 +9,8 @@ rtic = { version = "2", features = ["thumbv7-backend"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } -embassy-time = { version = "0.3.2", path = "../../embassy-time", features = [ "defmt", "defmt-timestamp-uptime"] } -embassy-time-queue-driver = { version = "0.1.0", path = "../../embassy-time-queue-driver", features = ["generic-queue-8"] } +embassy-time = { version = "0.4.0", path = "../../embassy-time", features = [ "defmt", "defmt-timestamp-uptime"] } +embassy-time-queue-driver = { version = "0.2", path = "../../embassy-time-queue-driver", features = ["generic-queue-8"] } embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = [ "defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } defmt = "0.3" diff --git a/examples/nrf52840/Cargo.toml b/examples/nrf52840/Cargo.toml index fa29d52b9..7a4aa803b 100644 --- a/examples/nrf52840/Cargo.toml +++ b/examples/nrf52840/Cargo.toml @@ -7,8 +7,8 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } -embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } +embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } +embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/nrf5340/Cargo.toml b/examples/nrf5340/Cargo.toml index 1792b277c..b9d336db7 100644 --- a/examples/nrf5340/Cargo.toml +++ b/examples/nrf5340/Cargo.toml @@ -7,8 +7,8 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] } -embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } +embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] } +embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf5340-app-s", "time-driver-rtc1", "gpiote", "unstable-pac"] } embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/nrf54l15/Cargo.toml b/examples/nrf54l15/Cargo.toml index 7288ef6af..3f8f091ec 100644 --- a/examples/nrf54l15/Cargo.toml +++ b/examples/nrf54l15/Cargo.toml @@ -5,8 +5,8 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } -embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } +embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } +embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf54l15-app-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } defmt = "0.3" diff --git a/examples/nrf9151/ns/Cargo.toml b/examples/nrf9151/ns/Cargo.toml index 0353cf598..f32139d9e 100644 --- a/examples/nrf9151/ns/Cargo.toml +++ b/examples/nrf9151/ns/Cargo.toml @@ -5,8 +5,8 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-executor = { version = "0.6.3", path = "../../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } -embassy-time = { version = "0.3.2", path = "../../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } +embassy-executor = { version = "0.7.0", path = "../../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } +embassy-time = { version = "0.4.0", path = "../../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.2.0", path = "../../../embassy-nrf", features = ["defmt", "nrf9120-ns", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } defmt = "0.3" diff --git a/examples/nrf9151/s/Cargo.toml b/examples/nrf9151/s/Cargo.toml index 5d2302574..6ff5c4106 100644 --- a/examples/nrf9151/s/Cargo.toml +++ b/examples/nrf9151/s/Cargo.toml @@ -5,8 +5,8 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-executor = { version = "0.6.3", path = "../../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } -embassy-time = { version = "0.3.2", path = "../../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } +embassy-executor = { version = "0.7.0", path = "../../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } +embassy-time = { version = "0.4.0", path = "../../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.2.0", path = "../../../embassy-nrf", features = ["defmt", "nrf9120-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } defmt = "0.3" diff --git a/examples/nrf9160/Cargo.toml b/examples/nrf9160/Cargo.toml index b52cd4af0..885adb337 100644 --- a/examples/nrf9160/Cargo.toml +++ b/examples/nrf9160/Cargo.toml @@ -5,8 +5,8 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } -embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } +embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } +embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf9160-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } embassy-net-nrf91 = { version = "0.1.0", path = "../../embassy-net-nrf91", features = ["defmt"] } embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "proto-ipv4", "medium-ip"] } diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index ce812b2e0..c0606d444 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml @@ -8,8 +8,8 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal", features = ["defmt"] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-98304", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } -embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } +embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-98304", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } +embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-rp = { version = "0.2.0", path = "../../embassy-rp", features = ["defmt", "unstable-pac", "time-driver", "critical-section-impl", "rp2040"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "raw", "dhcpv4", "medium-ethernet", "dns", "proto-ipv4", "proto-ipv6", "multicast"] } diff --git a/examples/rp23/Cargo.toml b/examples/rp23/Cargo.toml index 72eef222d..252a2ec70 100644 --- a/examples/rp23/Cargo.toml +++ b/examples/rp23/Cargo.toml @@ -8,8 +8,8 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal", features = ["defmt"] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-98304", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } -embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } +embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-98304", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } +embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-rp = { version = "0.2.0", path = "../../embassy-rp", features = ["defmt", "unstable-pac", "time-driver", "critical-section-impl", "rp235xa", "binary-info"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "raw", "dhcpv4", "medium-ethernet", "dns"] } diff --git a/examples/std/Cargo.toml b/examples/std/Cargo.toml index e43fd77c8..0d1ab9f77 100644 --- a/examples/std/Cargo.toml +++ b/examples/std/Cargo.toml @@ -6,8 +6,8 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["log"] } -embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-std", "executor-thread", "log"] } -embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["log", "std", ] } +embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-std", "executor-thread", "log"] } +embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["log", "std", ] } embassy-net = { version = "0.5.0", path = "../../embassy-net", features=[ "std", "log", "medium-ethernet", "medium-ip", "tcp", "udp", "dns", "dhcpv4", "proto-ipv6"] } embassy-net-tuntap = { version = "0.1.0", path = "../../embassy-net-tuntap" } embassy-net-ppp = { version = "0.1.0", path = "../../embassy-net-ppp", features = ["log"]} diff --git a/examples/stm32c0/Cargo.toml b/examples/stm32c0/Cargo.toml index 5ac3018e1..21a6882ac 100644 --- a/examples/stm32c0/Cargo.toml +++ b/examples/stm32c0/Cargo.toml @@ -8,8 +8,8 @@ license = "MIT OR Apache-2.0" # Change stm32c031c6 to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32c031c6", "memory-x", "unstable-pac", "exti"] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } -embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } +embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } defmt = "0.3" defmt-rtt = "0.4" diff --git a/examples/stm32f0/Cargo.toml b/examples/stm32f0/Cargo.toml index af3ef7abb..9bfc9701d 100644 --- a/examples/stm32f0/Cargo.toml +++ b/examples/stm32f0/Cargo.toml @@ -13,8 +13,8 @@ defmt = "0.3" defmt-rtt = "0.4" panic-probe = { version = "0.3", features = ["print-defmt"] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } -embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } +embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } static_cell = "2" portable-atomic = { version = "1.5", features = ["unsafe-assume-single-core"] } diff --git a/examples/stm32f1/Cargo.toml b/examples/stm32f1/Cargo.toml index 538e95dfb..4211a07a7 100644 --- a/examples/stm32f1/Cargo.toml +++ b/examples/stm32f1/Cargo.toml @@ -8,8 +8,8 @@ license = "MIT OR Apache-2.0" # Change stm32f103c8 to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f103c8", "unstable-pac", "memory-x", "time-driver-any" ] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } -embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } +embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32f2/Cargo.toml b/examples/stm32f2/Cargo.toml index 48d524b90..8b53b2f90 100644 --- a/examples/stm32f2/Cargo.toml +++ b/examples/stm32f2/Cargo.toml @@ -8,8 +8,8 @@ license = "MIT OR Apache-2.0" # Change stm32f207zg to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f207zg", "unstable-pac", "memory-x", "time-driver-any", "exti"] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } -embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } +embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } defmt = "0.3" defmt-rtt = "0.4" diff --git a/examples/stm32f3/Cargo.toml b/examples/stm32f3/Cargo.toml index 66fb34223..60ec05f36 100644 --- a/examples/stm32f3/Cargo.toml +++ b/examples/stm32f3/Cargo.toml @@ -8,8 +8,8 @@ license = "MIT OR Apache-2.0" # Change stm32f303ze to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f303ze", "unstable-pac", "memory-x", "time-driver-tim2", "exti"] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } -embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } +embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32f334/Cargo.toml b/examples/stm32f334/Cargo.toml index c6b311fa5..02306c683 100644 --- a/examples/stm32f334/Cargo.toml +++ b/examples/stm32f334/Cargo.toml @@ -6,8 +6,8 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } -embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } +embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f334r8", "unstable-pac", "memory-x", "time-driver-any", "exti"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32f4/Cargo.toml b/examples/stm32f4/Cargo.toml index 4f0629fc6..8656dbc61 100644 --- a/examples/stm32f4/Cargo.toml +++ b/examples/stm32f4/Cargo.toml @@ -8,8 +8,8 @@ license = "MIT OR Apache-2.0" # Change stm32f429zi to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32f429zi", "unstable-pac", "memory-x", "time-driver-tim4", "exti", "chrono"] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } -embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } +embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt" ] } embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", ] } embassy-net-wiznet = { version = "0.1.0", path = "../../embassy-net-wiznet", features = ["defmt"] } diff --git a/examples/stm32f469/Cargo.toml b/examples/stm32f469/Cargo.toml index a80409801..01984f594 100644 --- a/examples/stm32f469/Cargo.toml +++ b/examples/stm32f469/Cargo.toml @@ -7,8 +7,8 @@ license = "MIT OR Apache-2.0" [dependencies] # Specific examples only for stm32f469 embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32f469ni", "unstable-pac", "memory-x", "time-driver-any", "exti", "chrono"] } -embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } -embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } +embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } defmt = "0.3" defmt-rtt = "0.4" diff --git a/examples/stm32f7/Cargo.toml b/examples/stm32f7/Cargo.toml index 520b8bc42..45e56b63f 100644 --- a/examples/stm32f7/Cargo.toml +++ b/examples/stm32f7/Cargo.toml @@ -8,8 +8,8 @@ license = "MIT OR Apache-2.0" # Change stm32f777zi to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32f777zi", "memory-x", "unstable-pac", "time-driver-any", "exti"] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] } -embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] } +embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } embedded-io-async = { version = "0.6.1" } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/stm32g0/Cargo.toml b/examples/stm32g0/Cargo.toml index 3d11610ce..4aa665d64 100644 --- a/examples/stm32g0/Cargo.toml +++ b/examples/stm32g0/Cargo.toml @@ -8,8 +8,8 @@ license = "MIT OR Apache-2.0" # Change stm32g0b1re to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32g0b1re", "memory-x", "unstable-pac", "exti"] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } -embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } +embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", default-features = false, features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32g4/Cargo.toml b/examples/stm32g4/Cargo.toml index 87fa2c53a..83974f1af 100644 --- a/examples/stm32g4/Cargo.toml +++ b/examples/stm32g4/Cargo.toml @@ -8,8 +8,8 @@ license = "MIT OR Apache-2.0" # Change stm32g491re to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32g491re", "memory-x", "unstable-pac", "exti"] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } -embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } +embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } usbd-hid = "0.8.1" diff --git a/examples/stm32h5/Cargo.toml b/examples/stm32h5/Cargo.toml index 516d491e5..7495b88ac 100644 --- a/examples/stm32h5/Cargo.toml +++ b/examples/stm32h5/Cargo.toml @@ -8,8 +8,8 @@ license = "MIT OR Apache-2.0" # Change stm32h563zi to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h563zi", "memory-x", "time-driver-any", "exti", "unstable-pac", "low-power"] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] } -embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] } +embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32h7/Cargo.toml b/examples/stm32h7/Cargo.toml index 68a0c3d88..3cefdcd31 100644 --- a/examples/stm32h7/Cargo.toml +++ b/examples/stm32h7/Cargo.toml @@ -9,8 +9,8 @@ license = "MIT OR Apache-2.0" embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h743bi", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } -embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } -embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } +embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32h723/Cargo.toml b/examples/stm32h723/Cargo.toml index 82f3cb9c2..95a9c4a3d 100644 --- a/examples/stm32h723/Cargo.toml +++ b/examples/stm32h723/Cargo.toml @@ -8,8 +8,8 @@ license = "MIT OR Apache-2.0" # Change stm32h723zg to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h723zg", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } -embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } +embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } defmt = "0.3" diff --git a/examples/stm32h735/Cargo.toml b/examples/stm32h735/Cargo.toml index a517b9727..021dff0e3 100644 --- a/examples/stm32h735/Cargo.toml +++ b/examples/stm32h735/Cargo.toml @@ -8,8 +8,8 @@ license = "MIT OR Apache-2.0" embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h735ig", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } -embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } -embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } +embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } defmt = "0.3" diff --git a/examples/stm32h755cm4/Cargo.toml b/examples/stm32h755cm4/Cargo.toml index 1d4d3eb85..f3fd5f894 100644 --- a/examples/stm32h755cm4/Cargo.toml +++ b/examples/stm32h755cm4/Cargo.toml @@ -9,8 +9,8 @@ license = "MIT OR Apache-2.0" embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h755zi-cm4", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } -embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } -embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } +embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32h755cm7/Cargo.toml b/examples/stm32h755cm7/Cargo.toml index 76c88c806..81c8eecc2 100644 --- a/examples/stm32h755cm7/Cargo.toml +++ b/examples/stm32h755cm7/Cargo.toml @@ -9,8 +9,8 @@ license = "MIT OR Apache-2.0" embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h755zi-cm7", "time-driver-tim3", "exti", "memory-x", "unstable-pac", "chrono"] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } -embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } -embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } +embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32h7b0/Cargo.toml b/examples/stm32h7b0/Cargo.toml index aba398fa5..660a340cf 100644 --- a/examples/stm32h7b0/Cargo.toml +++ b/examples/stm32h7b0/Cargo.toml @@ -8,8 +8,8 @@ license = "MIT OR Apache-2.0" embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h7b0vb", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } -embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } -embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } +embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32h7rs/Cargo.toml b/examples/stm32h7rs/Cargo.toml index 1d957e2cc..45bfde41c 100644 --- a/examples/stm32h7rs/Cargo.toml +++ b/examples/stm32h7rs/Cargo.toml @@ -8,8 +8,8 @@ license = "MIT OR Apache-2.0" # Change stm32h743bi to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h7s3l8", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } -embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } +embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32l0/Cargo.toml b/examples/stm32l0/Cargo.toml index 5cc312a50..3acc62e96 100644 --- a/examples/stm32l0/Cargo.toml +++ b/examples/stm32l0/Cargo.toml @@ -8,8 +8,8 @@ license = "MIT OR Apache-2.0" # Change stm32l072cz to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32l073rz", "unstable-pac", "time-driver-any", "exti", "memory-x"] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } -embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } +embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } defmt = "0.3" defmt-rtt = "0.4" diff --git a/examples/stm32l1/Cargo.toml b/examples/stm32l1/Cargo.toml index 31b6785fa..67a7dfbe8 100644 --- a/examples/stm32l1/Cargo.toml +++ b/examples/stm32l1/Cargo.toml @@ -6,8 +6,8 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } -embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } +embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32l151cb-a", "time-driver-any", "memory-x"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32l4/Cargo.toml b/examples/stm32l4/Cargo.toml index 3fde18ecd..7d08a18ed 100644 --- a/examples/stm32l4/Cargo.toml +++ b/examples/stm32l4/Cargo.toml @@ -8,8 +8,8 @@ license = "MIT OR Apache-2.0" # Change stm32l4s5vi to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32l4r5zi", "memory-x", "time-driver-any", "exti", "chrono"] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] } -embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768", ] } +embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] } +embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768", ] } embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embassy-net-adin1110 = { version = "0.2.0", path = "../../embassy-net-adin1110" } diff --git a/examples/stm32l5/Cargo.toml b/examples/stm32l5/Cargo.toml index 2b8a2c064..281dea430 100644 --- a/examples/stm32l5/Cargo.toml +++ b/examples/stm32l5/Cargo.toml @@ -8,8 +8,8 @@ license = "MIT OR Apache-2.0" # Change stm32l552ze to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32l552ze", "time-driver-any", "exti", "memory-x", "low-power"] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] } -embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] } +embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32u0/Cargo.toml b/examples/stm32u0/Cargo.toml index 11953acfc..1813881ba 100644 --- a/examples/stm32u0/Cargo.toml +++ b/examples/stm32u0/Cargo.toml @@ -8,8 +8,8 @@ license = "MIT OR Apache-2.0" # Change stm32u083rc to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32u083rc", "memory-x", "unstable-pac", "exti", "chrono"] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } -embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } +embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", default-features = false, features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32u5/Cargo.toml b/examples/stm32u5/Cargo.toml index 68a17ce43..f56ee024e 100644 --- a/examples/stm32u5/Cargo.toml +++ b/examples/stm32u5/Cargo.toml @@ -8,8 +8,8 @@ license = "MIT OR Apache-2.0" # Change stm32u5g9zj to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "unstable-pac", "stm32u5g9zj", "time-driver-any", "memory-x" ] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] } -embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] } +embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32wb/Cargo.toml b/examples/stm32wb/Cargo.toml index ecc72397b..1b8535d8a 100644 --- a/examples/stm32wb/Cargo.toml +++ b/examples/stm32wb/Cargo.toml @@ -9,8 +9,8 @@ license = "MIT OR Apache-2.0" embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32wb55rg", "time-driver-any", "memory-x", "exti"] } embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", features = ["defmt", "stm32wb55rg"] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] } -embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] } +embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", ], optional=true } defmt = "0.3" diff --git a/examples/stm32wba/Cargo.toml b/examples/stm32wba/Cargo.toml index 7735dfdde..126f47e42 100644 --- a/examples/stm32wba/Cargo.toml +++ b/examples/stm32wba/Cargo.toml @@ -7,8 +7,8 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32wba52cg", "time-driver-any", "memory-x", "exti"] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] } -embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] } +embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", ], optional=true } defmt = "0.3" diff --git a/examples/stm32wl/Cargo.toml b/examples/stm32wl/Cargo.toml index 0182745e5..7dbb40567 100644 --- a/examples/stm32wl/Cargo.toml +++ b/examples/stm32wl/Cargo.toml @@ -8,8 +8,8 @@ license = "MIT OR Apache-2.0" # Change stm32wl55jc-cm4 to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32wl55jc-cm4", "time-driver-any", "memory-x", "unstable-pac", "exti", "chrono"] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-4096", "arch-cortex-m", "executor-thread", "defmt"] } -embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-4096", "arch-cortex-m", "executor-thread", "defmt"] } +embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } defmt = "0.3" diff --git a/examples/wasm/Cargo.toml b/examples/wasm/Cargo.toml index f5dcdc0a2..8a97f4d25 100644 --- a/examples/wasm/Cargo.toml +++ b/examples/wasm/Cargo.toml @@ -9,8 +9,8 @@ crate-type = ["cdylib"] [dependencies] embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["log"] } -embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-wasm", "executor-thread", "log"] } -embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["log", "wasm", ] } +embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-wasm", "executor-thread", "log"] } +embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["log", "wasm", ] } wasm-logger = "0.2.0" wasm-bindgen = "0.2" diff --git a/tests/nrf/Cargo.toml b/tests/nrf/Cargo.toml index 7af3d0649..e0c5e90cf 100644 --- a/tests/nrf/Cargo.toml +++ b/tests/nrf/Cargo.toml @@ -9,8 +9,8 @@ teleprobe-meta = "1" embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt", ] } -embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } -embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } +embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } +embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "time-driver-rtc1", "gpiote", "unstable-pac"] } embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", ] } diff --git a/tests/perf-client/Cargo.toml b/tests/perf-client/Cargo.toml index 3bbc1b613..22137e2e7 100644 --- a/tests/perf-client/Cargo.toml +++ b/tests/perf-client/Cargo.toml @@ -5,6 +5,6 @@ edition = "2021" [dependencies] embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4"] } -embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", ] } +embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", ] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } defmt = "0.3.0" diff --git a/tests/riscv32/Cargo.toml b/tests/riscv32/Cargo.toml index e76e07d7c..51a113115 100644 --- a/tests/riscv32/Cargo.toml +++ b/tests/riscv32/Cargo.toml @@ -7,8 +7,8 @@ license = "MIT OR Apache-2.0" [dependencies] critical-section = { version = "1.1.1", features = ["restore-state-bool"] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync" } -embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-riscv32", "executor-thread"] } -embassy-time = { version = "0.3.2", path = "../../embassy-time" } +embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-riscv32", "executor-thread"] } +embassy-time = { version = "0.4.0", path = "../../embassy-time" } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } riscv-rt = "0.12.2" diff --git a/tests/rp/Cargo.toml b/tests/rp/Cargo.toml index 8cd40418a..d5aabc6ac 100644 --- a/tests/rp/Cargo.toml +++ b/tests/rp/Cargo.toml @@ -8,8 +8,8 @@ license = "MIT OR Apache-2.0" teleprobe-meta = "1.1" embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] } -embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", ] } +embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] } +embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", ] } embassy-rp = { version = "0.2.0", path = "../../embassy-rp", features = [ "defmt", "unstable-pac", "time-driver", "critical-section-impl", "intrinsics", "rom-v2-intrinsics", "run-from-ram", "rp2040"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "dhcpv4", "medium-ethernet"] } diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml index 5ae6878cc..afc96cb61 100644 --- a/tests/stm32/Cargo.toml +++ b/tests/stm32/Cargo.toml @@ -60,8 +60,8 @@ cm0 = ["portable-atomic/unsafe-assume-single-core"] teleprobe-meta = "1" embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } -embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "tick-hz-131_072", "defmt-timestamp-uptime"] } +embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } +embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "tick-hz-131_072", "defmt-timestamp-uptime"] } embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "memory-x", "time-driver-any"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", optional = true, features = ["defmt", "stm32wb55rg", "ble"] } From 1c485f18a2ee6147bf4cfd66789dc8e0c6e1466c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Wed, 18 Dec 2024 16:09:57 +0100 Subject: [PATCH 0532/1217] Remove bluetooth example and trouble dependencies --- examples/rp/Cargo.toml | 6 +- examples/rp/src/bin/bluetooth.rs | 150 ------------------------------- examples/rp23/Cargo.toml | 6 +- 3 files changed, 2 insertions(+), 160 deletions(-) delete mode 100644 examples/rp/src/bin/bluetooth.rs diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index c0606d444..bdd50707a 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml @@ -16,7 +16,7 @@ embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defm embassy-net-wiznet = { version = "0.1.0", path = "../../embassy-net-wiznet", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-usb-logger = { version = "0.2.0", path = "../../embassy-usb-logger" } -cyw43 = { version = "0.2.0", path = "../../cyw43", features = ["defmt", "firmware-logs", "bluetooth"] } +cyw43 = { version = "0.2.0", path = "../../cyw43", features = ["defmt", "firmware-logs"] } cyw43-pio = { version = "0.2.0", path = "../../cyw43-pio", features = ["defmt"] } defmt = "0.3" @@ -60,9 +60,6 @@ pio = "0.2.1" rand = { version = "0.8.5", default-features = false } embedded-sdmmc = "0.7.0" -bt-hci = { version = "0.1.0", default-features = false, features = ["defmt"] } -trouble-host = { version = "0.1.0", features = ["defmt", "gatt"] } - [profile.release] debug = 2 lto = true @@ -74,7 +71,6 @@ lto = true opt-level = "z" [patch.crates-io] -trouble-host = { git = "https://github.com/embassy-rs/trouble.git", rev = "4b8c0f499b34e46ca23a56e2d1640ede371722cf" } embassy-executor = { path = "../../embassy-executor" } embassy-sync = { path = "../../embassy-sync" } embassy-futures = { path = "../../embassy-futures" } diff --git a/examples/rp/src/bin/bluetooth.rs b/examples/rp/src/bin/bluetooth.rs deleted file mode 100644 index 7524e7929..000000000 --- a/examples/rp/src/bin/bluetooth.rs +++ /dev/null @@ -1,150 +0,0 @@ -//! This example test the RP Pico W on board LED. -//! -//! It does not work with the RP Pico board. See blinky.rs. - -#![no_std] -#![no_main] - -use bt_hci::controller::ExternalController; -use cyw43_pio::PioSpi; -use defmt::*; -use embassy_executor::Spawner; -use embassy_futures::join::join3; -use embassy_rp::bind_interrupts; -use embassy_rp::gpio::{Level, Output}; -use embassy_rp::peripherals::{DMA_CH0, PIO0}; -use embassy_rp::pio::{InterruptHandler, Pio}; -use embassy_sync::blocking_mutex::raw::NoopRawMutex; -use embassy_time::{Duration, Timer}; -use static_cell::StaticCell; -use trouble_host::advertise::{AdStructure, Advertisement, BR_EDR_NOT_SUPPORTED, LE_GENERAL_DISCOVERABLE}; -use trouble_host::attribute::{AttributeTable, CharacteristicProp, Service, Uuid}; -use trouble_host::gatt::GattEvent; -use trouble_host::{Address, BleHost, BleHostResources, PacketQos}; -use {defmt_rtt as _, embassy_time as _, panic_probe as _}; - -bind_interrupts!(struct Irqs { - PIO0_IRQ_0 => InterruptHandler; -}); - -#[embassy_executor::task] -async fn cyw43_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>) -> ! { - runner.run().await -} - -#[embassy_executor::main] -async fn main(spawner: Spawner) { - let p = embassy_rp::init(Default::default()); - let fw = include_bytes!("../../../../cyw43-firmware/43439A0.bin"); - let clm = include_bytes!("../../../../cyw43-firmware/43439A0_clm.bin"); - let btfw = include_bytes!("../../../../cyw43-firmware/43439A0_btfw.bin"); - - // To make flashing faster for development, you may want to flash the firmwares independently - // at hardcoded addresses, instead of baking them into the program with `include_bytes!`: - // probe-rs download 43439A0.bin --format bin --chip RP2040 --base-address 0x10100000 - // probe-rs download 43439A0_clm.bin --format bin --chip RP2040 --base-address 0x10140000 - // probe-rs download 43439A0_btfw.bin --format bin --chip RP2040 --base-address 0x10141400 - //let fw = unsafe { core::slice::from_raw_parts(0x10100000 as *const u8, 224190) }; - //let clm = unsafe { core::slice::from_raw_parts(0x10140000 as *const u8, 4752) }; - //let btfw = unsafe { core::slice::from_raw_parts(0x10141400 as *const u8, 6164) }; - - let pwr = Output::new(p.PIN_23, Level::Low); - let cs = Output::new(p.PIN_25, Level::High); - let mut pio = Pio::new(p.PIO0, Irqs); - let spi = PioSpi::new(&mut pio.common, pio.sm0, pio.irq0, cs, p.PIN_24, p.PIN_29, p.DMA_CH0); - - static STATE: StaticCell = StaticCell::new(); - let state = STATE.init(cyw43::State::new()); - let (_net_device, bt_device, mut control, runner) = cyw43::new_with_bluetooth(state, pwr, spi, fw, btfw).await; - unwrap!(spawner.spawn(cyw43_task(runner))); - control.init(clm).await; - - let controller: ExternalController<_, 10> = ExternalController::new(bt_device); - static HOST_RESOURCES: StaticCell> = StaticCell::new(); - let host_resources = HOST_RESOURCES.init(BleHostResources::new(PacketQos::None)); - - let mut ble: BleHost<'_, _> = BleHost::new(controller, host_resources); - - ble.set_random_address(Address::random([0xff, 0x9f, 0x1a, 0x05, 0xe4, 0xff])); - let mut table: AttributeTable<'_, NoopRawMutex, 10> = AttributeTable::new(); - - // Generic Access Service (mandatory) - let id = b"Pico W Bluetooth"; - let appearance = [0x80, 0x07]; - let mut bat_level = [0; 1]; - let handle = { - let mut svc = table.add_service(Service::new(0x1800)); - let _ = svc.add_characteristic_ro(0x2a00, id); - let _ = svc.add_characteristic_ro(0x2a01, &appearance[..]); - svc.build(); - - // Generic attribute service (mandatory) - table.add_service(Service::new(0x1801)); - - // Battery service - let mut svc = table.add_service(Service::new(0x180f)); - - svc.add_characteristic( - 0x2a19, - &[CharacteristicProp::Read, CharacteristicProp::Notify], - &mut bat_level, - ) - .build() - }; - - let mut adv_data = [0; 31]; - AdStructure::encode_slice( - &[ - AdStructure::Flags(LE_GENERAL_DISCOVERABLE | BR_EDR_NOT_SUPPORTED), - AdStructure::ServiceUuids16(&[Uuid::Uuid16([0x0f, 0x18])]), - AdStructure::CompleteLocalName(b"Pico W Bluetooth"), - ], - &mut adv_data[..], - ) - .unwrap(); - - let server = ble.gatt_server(&table); - - info!("Starting advertising and GATT service"); - let _ = join3( - ble.run(), - async { - loop { - match server.next().await { - Ok(GattEvent::Write { handle, connection: _ }) => { - let _ = table.get(handle, |value| { - info!("Write event. Value written: {:?}", value); - }); - } - Ok(GattEvent::Read { .. }) => { - info!("Read event"); - } - Err(e) => { - error!("Error processing GATT events: {:?}", e); - } - } - } - }, - async { - let mut advertiser = ble - .advertise( - &Default::default(), - Advertisement::ConnectableScannableUndirected { - adv_data: &adv_data[..], - scan_data: &[], - }, - ) - .await - .unwrap(); - let conn = advertiser.accept().await.unwrap(); - // Keep connection alive - let mut tick: u8 = 0; - loop { - Timer::after(Duration::from_secs(10)).await; - tick += 1; - server.notify(handle, &conn, &[tick]).await.unwrap(); - } - }, - ) - .await; -} diff --git a/examples/rp23/Cargo.toml b/examples/rp23/Cargo.toml index 252a2ec70..3afd2cddb 100644 --- a/examples/rp23/Cargo.toml +++ b/examples/rp23/Cargo.toml @@ -16,7 +16,7 @@ embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defm embassy-net-wiznet = { version = "0.1.0", path = "../../embassy-net-wiznet", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-usb-logger = { version = "0.2.0", path = "../../embassy-usb-logger" } -cyw43 = { version = "0.2.0", path = "../../cyw43", features = ["defmt", "firmware-logs", "bluetooth"] } +cyw43 = { version = "0.2.0", path = "../../cyw43", features = ["defmt", "firmware-logs"] } cyw43-pio = { version = "0.2.0", path = "../../cyw43-pio", features = ["defmt"] } defmt = "0.3" @@ -60,9 +60,6 @@ pio = "0.2.1" rand = { version = "0.8.5", default-features = false } embedded-sdmmc = "0.7.0" -bt-hci = { version = "0.1.0", default-features = false, features = ["defmt"] } -trouble-host = { version = "0.1.0", features = ["defmt", "gatt"] } - [profile.release] debug = 2 @@ -71,7 +68,6 @@ lto = true opt-level = "z" [patch.crates-io] -trouble-host = { git = "https://github.com/embassy-rs/trouble.git", rev = "4b8c0f499b34e46ca23a56e2d1640ede371722cf" } embassy-executor = { path = "../../embassy-executor" } embassy-sync = { path = "../../embassy-sync" } embassy-futures = { path = "../../embassy-futures" } From ab8ca3f126447edb3a9eb06aa6fd6cd394219c17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Fri, 20 Dec 2024 12:45:24 +0100 Subject: [PATCH 0533/1217] Rename ETQD, bump date --- .github/ci/doc.sh | 2 +- .github/ci/test.sh | 2 +- ci-xtensa.sh | 4 ++-- ci.sh | 4 ++-- docs/pages/faq.adoc | 6 +++--- embassy-executor/CHANGELOG.md | 2 +- embassy-nrf/Cargo.toml | 4 ++-- embassy-nrf/src/time_driver.rs | 2 +- embassy-rp/Cargo.toml | 4 ++-- embassy-rp/src/time_driver.rs | 2 +- embassy-stm32/Cargo.toml | 4 ++-- embassy-stm32/src/time_driver.rs | 2 +- embassy-time-driver/CHANGELOG.md | 2 +- embassy-time-driver/src/lib.rs | 2 +- embassy-time-queue-driver/README.md | 8 -------- .../CHANGELOG.md | 7 +------ .../Cargo.toml | 10 +++++----- embassy-time-queue-utils/README.md | 8 ++++++++ .../build.rs | 0 .../src/lib.rs | 7 ------- .../src/queue_generic.rs | 0 .../src/queue_integrated.rs | 0 embassy-time/CHANGELOG.md | 2 +- embassy-time/Cargo.toml | 18 +++++++++--------- embassy-time/src/driver_mock.rs | 2 +- embassy-time/src/driver_std.rs | 2 +- embassy-time/src/driver_wasm.rs | 2 +- examples/nrf52840-rtic/Cargo.toml | 2 +- 28 files changed, 49 insertions(+), 61 deletions(-) delete mode 100644 embassy-time-queue-driver/README.md rename {embassy-time-queue-driver => embassy-time-queue-utils}/CHANGELOG.md (54%) rename {embassy-time-queue-driver => embassy-time-queue-utils}/Cargo.toml (90%) create mode 100644 embassy-time-queue-utils/README.md rename {embassy-time-queue-driver => embassy-time-queue-utils}/build.rs (100%) rename {embassy-time-queue-driver => embassy-time-queue-utils}/src/lib.rs (51%) rename {embassy-time-queue-driver => embassy-time-queue-utils}/src/queue_generic.rs (100%) rename {embassy-time-queue-driver => embassy-time-queue-utils}/src/queue_integrated.rs (100%) diff --git a/.github/ci/doc.sh b/.github/ci/doc.sh index 47babe8f5..c92892406 100755 --- a/.github/ci/doc.sh +++ b/.github/ci/doc.sh @@ -32,7 +32,7 @@ docserver-builder -i ./embassy-stm32-wpan -o webroot/crates/embassy-stm32-wpan/g docserver-builder -i ./embassy-time -o webroot/crates/embassy-time/git.zup docserver-builder -i ./embassy-time-driver -o webroot/crates/embassy-time-driver/git.zup -docserver-builder -i ./embassy-time-queue-driver -o webroot/crates/embassy-time-queue-driver/git.zup +docserver-builder -i ./embassy-time-queue-utils -o webroot/crates/embassy-time-queue-utils/git.zup docserver-builder -i ./embassy-usb -o webroot/crates/embassy-usb/git.zup docserver-builder -i ./embassy-usb-dfu -o webroot/crates/embassy-usb-dfu/git.zup diff --git a/.github/ci/test.sh b/.github/ci/test.sh index 0fd6820d2..c78865e54 100755 --- a/.github/ci/test.sh +++ b/.github/ci/test.sh @@ -17,7 +17,7 @@ cargo test --manifest-path ./embassy-futures/Cargo.toml cargo test --manifest-path ./embassy-sync/Cargo.toml cargo test --manifest-path ./embassy-embedded-hal/Cargo.toml cargo test --manifest-path ./embassy-hal-internal/Cargo.toml -cargo test --manifest-path ./embassy-time/Cargo.toml --features mock-driver,embassy-time-queue-driver/generic-queue-8 +cargo test --manifest-path ./embassy-time/Cargo.toml --features mock-driver,embassy-time-queue-utils/generic-queue-8 cargo test --manifest-path ./embassy-time-driver/Cargo.toml cargo test --manifest-path ./embassy-boot/Cargo.toml diff --git a/ci-xtensa.sh b/ci-xtensa.sh index 056e85d48..6c9807e98 100755 --- a/ci-xtensa.sh +++ b/ci-xtensa.sh @@ -22,8 +22,8 @@ cargo batch \ --- build --release --manifest-path embassy-executor/Cargo.toml --target xtensa-esp32-none-elf --features arch-spin,executor-thread \ --- build --release --manifest-path embassy-sync/Cargo.toml --target xtensa-esp32s2-none-elf --features defmt \ --- build --release --manifest-path embassy-time/Cargo.toml --target xtensa-esp32s2-none-elf --features defmt,defmt-timestamp-uptime,mock-driver \ - --- build --release --manifest-path embassy-time-queue-driver/Cargo.toml --target xtensa-esp32s2-none-elf \ - --- build --release --manifest-path embassy-time-queue-driver/Cargo.toml --target xtensa-esp32s2-none-elf --features generic-queue-8 \ + --- build --release --manifest-path embassy-time-queue-utils/Cargo.toml --target xtensa-esp32s2-none-elf \ + --- build --release --manifest-path embassy-time-queue-utils/Cargo.toml --target xtensa-esp32s2-none-elf --features generic-queue-8 \ --- build --release --manifest-path embassy-net/Cargo.toml --target xtensa-esp32-none-elf --features defmt,tcp,udp,dns,proto-ipv4,medium-ethernet,packet-trace \ --- build --release --manifest-path embassy-net/Cargo.toml --target xtensa-esp32-none-elf --features defmt,tcp,udp,dns,proto-ipv4,multicast,medium-ethernet \ --- build --release --manifest-path embassy-net/Cargo.toml --target xtensa-esp32-none-elf --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet \ diff --git a/ci.sh b/ci.sh index 6b523193c..e7f1504aa 100755 --- a/ci.sh +++ b/ci.sh @@ -39,8 +39,8 @@ cargo batch \ --- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features arch-riscv32,executor-thread \ --- build --release --manifest-path embassy-sync/Cargo.toml --target thumbv6m-none-eabi --features defmt \ --- build --release --manifest-path embassy-time/Cargo.toml --target thumbv6m-none-eabi --features defmt,defmt-timestamp-uptime,mock-driver \ - --- build --release --manifest-path embassy-time-queue-driver/Cargo.toml --target thumbv6m-none-eabi \ - --- build --release --manifest-path embassy-time-queue-driver/Cargo.toml --target thumbv6m-none-eabi --features generic-queue-8 \ + --- build --release --manifest-path embassy-time-queue-utils/Cargo.toml --target thumbv6m-none-eabi \ + --- build --release --manifest-path embassy-time-queue-utils/Cargo.toml --target thumbv6m-none-eabi --features generic-queue-8 \ --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,medium-ethernet,packet-trace \ --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,multicast,medium-ethernet \ --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet \ diff --git a/docs/pages/faq.adoc b/docs/pages/faq.adoc index 3e32563cc..ed88515d0 100644 --- a/docs/pages/faq.adoc +++ b/docs/pages/faq.adoc @@ -140,9 +140,9 @@ Example: [source,toml] ---- [patch.crates-io] -embassy-time-queue-driver = { git = "https://github.com/embassy-rs/embassy.git", rev = "e5fdd35" } -embassy-time-driver = { git = "https://github.com/embassy-rs/embassy.git", rev = "e5fdd35" } -# embassy-time = { git = "https://github.com/embassy-rs/embassy.git", rev = "e5fdd35" } +embassy-time-queue-utils = { git = "https://github.com/embassy-rs/embassy.git", rev = "7f8af8a" } +embassy-time-driver = { git = "https://github.com/embassy-rs/embassy.git", rev = "7f8af8a" } +# embassy-time = { git = "https://github.com/embassy-rs/embassy.git", rev = "7f8af8a" } ---- Note that the git revision should match any other embassy patches or git dependencies that you are using! diff --git a/embassy-executor/CHANGELOG.md b/embassy-executor/CHANGELOG.md index b45142802..ee8003a54 100644 --- a/embassy-executor/CHANGELOG.md +++ b/embassy-executor/CHANGELOG.md @@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## 0.7.0 - 2024-12-18 +## 0.7.0 - 2024-12-22 - embassy-executor no longer provides an `embassy-time-queue-driver` implementation - Added `TaskRef::executor` to obtain a reference to a task's executor diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml index a1248c1ca..45666ade8 100644 --- a/embassy-nrf/Cargo.toml +++ b/embassy-nrf/Cargo.toml @@ -119,7 +119,7 @@ _nrf52 = ["_ppi"] _nrf51 = ["_ppi"] _nrf91 = [] -_time-driver = ["dep:embassy-time-driver", "embassy-time-driver?/tick-hz-32_768", "dep:embassy-time-queue-driver"] +_time-driver = ["dep:embassy-time-driver", "embassy-time-driver?/tick-hz-32_768", "dep:embassy-time-queue-utils"] # trustzone state. _s = [] @@ -135,7 +135,7 @@ _nrf52832_anomaly_109 = [] [dependencies] embassy-time-driver = { version = "0.2", path = "../embassy-time-driver", optional = true } -embassy-time-queue-driver = { version = "0.2", path = "../embassy-time-queue-driver", optional = true } +embassy-time-queue-utils = { version = "0.1", path = "../embassy-time-queue-utils", optional = true } embassy-time = { version = "0.4.0", path = "../embassy-time", optional = true } embassy-sync = { version = "0.6.1", path = "../embassy-sync" } embassy-hal-internal = {version = "0.2.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-3"] } diff --git a/embassy-nrf/src/time_driver.rs b/embassy-nrf/src/time_driver.rs index a27fae9a8..ade6fd2a1 100644 --- a/embassy-nrf/src/time_driver.rs +++ b/embassy-nrf/src/time_driver.rs @@ -5,7 +5,7 @@ use critical_section::CriticalSection; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::blocking_mutex::CriticalSectionMutex as Mutex; use embassy_time_driver::Driver; -use embassy_time_queue_driver::Queue; +use embassy_time_queue_utils::Queue; use crate::interrupt::InterruptExt; use crate::{interrupt, pac}; diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index 5e2e08f38..37d9d916f 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml @@ -40,7 +40,7 @@ critical-section-impl = ["critical-section/restore-state-u8"] unstable-pac = [] ## Enable the timer for use with `embassy-time` with a 1MHz tick rate. -time-driver = ["dep:embassy-time-driver", "embassy-time-driver?/tick-hz-1_000_000", "dep:embassy-time-queue-driver"] +time-driver = ["dep:embassy-time-driver", "embassy-time-driver?/tick-hz-1_000_000", "dep:embassy-time-queue-utils"] ## Enable ROM function cache. This will store the address of a ROM function when first used, improving performance of subsequent calls. rom-func-cache = [] @@ -110,7 +110,7 @@ binary-info = ["rt", "dep:rp-binary-info", "rp-binary-info?/binary-info"] [dependencies] embassy-sync = { version = "0.6.1", path = "../embassy-sync" } embassy-time-driver = { version = "0.2", path = "../embassy-time-driver", optional = true } -embassy-time-queue-driver = { version = "0.2", path = "../embassy-time-queue-driver", optional = true } +embassy-time-queue-utils = { version = "0.1", path = "../embassy-time-queue-utils", optional = true } embassy-time = { version = "0.4.0", path = "../embassy-time" } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } embassy-hal-internal = {version = "0.2.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-2"] } diff --git a/embassy-rp/src/time_driver.rs b/embassy-rp/src/time_driver.rs index a0eaec10e..aa5d564e7 100644 --- a/embassy-rp/src/time_driver.rs +++ b/embassy-rp/src/time_driver.rs @@ -5,7 +5,7 @@ use critical_section::CriticalSection; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::blocking_mutex::Mutex; use embassy_time_driver::Driver; -use embassy_time_queue_driver::Queue; +use embassy_time_queue_utils::Queue; #[cfg(feature = "rp2040")] use pac::TIMER; #[cfg(feature = "_rp235x")] diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 527d2dd30..ffd9a67e7 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -45,7 +45,7 @@ rustdoc-args = ["--cfg", "docsrs"] embassy-sync = { version = "0.6.1", path = "../embassy-sync" } embassy-time = { version = "0.4.0", path = "../embassy-time", optional = true } embassy-time-driver = { version = "0.2", path = "../embassy-time-driver", optional = true } -embassy-time-queue-driver = { version = "0.2", path = "../embassy-time-queue-driver", optional = true } +embassy-time-queue-utils = { version = "0.1", path = "../embassy-time-queue-utils", optional = true } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } embassy-hal-internal = {version = "0.2.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-4"] } embassy-embedded-hal = {version = "0.2.0", path = "../embassy-embedded-hal", default-features = false } @@ -150,7 +150,7 @@ time = ["dep:embassy-time", "embassy-embedded-hal/time"] # Features starting with `_` are for internal use only. They're not intended # to be enabled by other crates, and are not covered by semver guarantees. -_time-driver = ["dep:embassy-time-driver", "time", "dep:embassy-time-queue-driver"] +_time-driver = ["dep:embassy-time-driver", "time", "dep:embassy-time-queue-utils"] ## Use any time driver time-driver-any = ["_time-driver"] diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs index a4c333d82..fbe148359 100644 --- a/embassy-stm32/src/time_driver.rs +++ b/embassy-stm32/src/time_driver.rs @@ -7,7 +7,7 @@ use critical_section::CriticalSection; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::blocking_mutex::Mutex; use embassy_time_driver::{Driver, TICK_HZ}; -use embassy_time_queue_driver::Queue; +use embassy_time_queue_utils::Queue; use stm32_metapac::timer::{regs, TimGp16}; use crate::interrupt::typelevel::Interrupt; diff --git a/embassy-time-driver/CHANGELOG.md b/embassy-time-driver/CHANGELOG.md index 7e9be8949..30d56fd56 100644 --- a/embassy-time-driver/CHANGELOG.md +++ b/embassy-time-driver/CHANGELOG.md @@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## 0.2.0 - 2024-12-18 +## 0.2.0 - 2024-12-22 - The `allocate_alarm`, `set_alarm_callback`, `set_alarm` functions have been removed. - `schedule_wake` has been added to the `Driver` trait. diff --git a/embassy-time-driver/src/lib.rs b/embassy-time-driver/src/lib.rs index 9f2795a01..b77683a52 100644 --- a/embassy-time-driver/src/lib.rs +++ b/embassy-time-driver/src/lib.rs @@ -53,7 +53,7 @@ //! use core::cell::RefCell; //! use core::task::Waker; //! -//! use embassy_time_queue_driver::Queue; +//! use embassy_time_queue_utils::Queue; //! use embassy_time_driver::Driver; //! //! struct MyDriver { diff --git a/embassy-time-queue-driver/README.md b/embassy-time-queue-driver/README.md deleted file mode 100644 index b9fb12d94..000000000 --- a/embassy-time-queue-driver/README.md +++ /dev/null @@ -1,8 +0,0 @@ -# embassy-time-queue-driver - -This crate contains the driver trait used by the [`embassy-time`](https://crates.io/crates/embassy-time) timer queue. - -You should rarely need to use this crate directly. Only use it when implementing your own timer queue. - -There is two timer queue implementations, one in `embassy-time` enabled by the `generic-queue` feature, and -another in `embassy-executor` enabled by the `integrated-timers` feature. diff --git a/embassy-time-queue-driver/CHANGELOG.md b/embassy-time-queue-utils/CHANGELOG.md similarity index 54% rename from embassy-time-queue-driver/CHANGELOG.md rename to embassy-time-queue-utils/CHANGELOG.md index 46d00c87d..ae4714f62 100644 --- a/embassy-time-queue-driver/CHANGELOG.md +++ b/embassy-time-queue-utils/CHANGELOG.md @@ -1,15 +1,10 @@ -# Changelog for embassy-time-queue-driver +# Changelog for embassy-time-queue-utils All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## 0.2.0 - 2024-12-18 - -- Added `generic-queue-N` features. -- Added `embassy_time_queue_driver::Queue` struct which uses integrated or a generic storage (configured using `generic-queue-N`). - ## 0.1.0 - 2024-01-11 Initial release diff --git a/embassy-time-queue-driver/Cargo.toml b/embassy-time-queue-utils/Cargo.toml similarity index 90% rename from embassy-time-queue-driver/Cargo.toml rename to embassy-time-queue-utils/Cargo.toml index 990393cc0..48be12118 100644 --- a/embassy-time-queue-driver/Cargo.toml +++ b/embassy-time-queue-utils/Cargo.toml @@ -1,10 +1,10 @@ [package] -name = "embassy-time-queue-driver" -version = "0.2.0" +name = "embassy-time-queue-utils" +version = "0.1.0" edition = "2021" description = "Timer queue driver trait for embassy-time" repository = "https://github.com/embassy-rs/embassy" -documentation = "https://docs.embassy.dev/embassy-time-queue-driver" +documentation = "https://docs.embassy.dev/embassy-time-queue-utils" readme = "README.md" license = "MIT OR Apache-2.0" categories = [ @@ -53,6 +53,6 @@ generic-queue-128 = ["_generic-queue"] _generic-queue = [] [package.metadata.embassy_docs] -src_base = "https://github.com/embassy-rs/embassy/blob/embassy-time-queue-driver-v$VERSION/embassy-time-queue-driver/src/" -src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-time-queue-driver/src/" +src_base = "https://github.com/embassy-rs/embassy/blob/embassy-time-queue-utils-v$VERSION/embassy-time-queue-utils/src/" +src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-time-queue-utils/src/" target = "x86_64-unknown-linux-gnu" diff --git a/embassy-time-queue-utils/README.md b/embassy-time-queue-utils/README.md new file mode 100644 index 000000000..36461f1cb --- /dev/null +++ b/embassy-time-queue-utils/README.md @@ -0,0 +1,8 @@ +# embassy-time-queue-utils + +This crate contains timer queues to help implementing an [`embassy-time-driver`](https://crates.io/crates/embassy-time-driver). + +As a HAL user, you should not need to depend on this crate. + +As a HAL implementer, you need to depend on this crate if you want to implement a time driver, +but how you should do so is documented in `embassy-time-driver`. diff --git a/embassy-time-queue-driver/build.rs b/embassy-time-queue-utils/build.rs similarity index 100% rename from embassy-time-queue-driver/build.rs rename to embassy-time-queue-utils/build.rs diff --git a/embassy-time-queue-driver/src/lib.rs b/embassy-time-queue-utils/src/lib.rs similarity index 51% rename from embassy-time-queue-driver/src/lib.rs rename to embassy-time-queue-utils/src/lib.rs index 72453f0ea..a6f66913f 100644 --- a/embassy-time-queue-driver/src/lib.rs +++ b/embassy-time-queue-utils/src/lib.rs @@ -2,13 +2,6 @@ #![doc = include_str!("../README.md")] #![warn(missing_docs)] -//! This crate is an implementation detail of `embassy-time-driver`. -//! -//! As a HAL user, you should not need to depend on this crate directly. -//! -//! As a HAL implementer, you need to depend on this crate if you want to implement a time driver, -//! but how you should do so is documented in `embassy-time-driver`. - #[cfg(feature = "_generic-queue")] pub mod queue_generic; #[cfg(not(feature = "_generic-queue"))] diff --git a/embassy-time-queue-driver/src/queue_generic.rs b/embassy-time-queue-utils/src/queue_generic.rs similarity index 100% rename from embassy-time-queue-driver/src/queue_generic.rs rename to embassy-time-queue-utils/src/queue_generic.rs diff --git a/embassy-time-queue-driver/src/queue_integrated.rs b/embassy-time-queue-utils/src/queue_integrated.rs similarity index 100% rename from embassy-time-queue-driver/src/queue_integrated.rs rename to embassy-time-queue-utils/src/queue_integrated.rs diff --git a/embassy-time/CHANGELOG.md b/embassy-time/CHANGELOG.md index ec3219818..cd4c1afcb 100644 --- a/embassy-time/CHANGELOG.md +++ b/embassy-time/CHANGELOG.md @@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## 0.4.0 - 2024-12-18 +## 0.4.0 - 2024-12-22 - embassy-time no longer provides an `embassy-time-queue-driver` implementation diff --git a/embassy-time/Cargo.toml b/embassy-time/Cargo.toml index 23317c6d3..374b460c9 100644 --- a/embassy-time/Cargo.toml +++ b/embassy-time/Cargo.toml @@ -24,8 +24,8 @@ target = "x86_64-unknown-linux-gnu" features = ["defmt", "std"] [features] -std = ["tick-hz-1_000_000", "critical-section/std", "dep:embassy-time-queue-driver"] -wasm = ["dep:wasm-bindgen", "dep:js-sys", "dep:wasm-timer", "tick-hz-1_000_000", "dep:embassy-time-queue-driver"] +std = ["tick-hz-1_000_000", "critical-section/std", "dep:embassy-time-queue-utils"] +wasm = ["dep:wasm-bindgen", "dep:js-sys", "dep:wasm-timer", "tick-hz-1_000_000", "dep:embassy-time-queue-utils"] ## Display the time since startup next to defmt log messages. ## At most 1 `defmt-timestamp-uptime-*` feature can be used. @@ -40,7 +40,7 @@ defmt-timestamp-uptime-tms = ["defmt"] defmt-timestamp-uptime-tus = ["defmt"] ## Create a `MockDriver` that can be manually advanced for testing purposes. -mock-driver = ["tick-hz-1_000_000", "dep:embassy-time-queue-driver"] +mock-driver = ["tick-hz-1_000_000", "dep:embassy-time-queue-utils"] #! ### Generic Queue @@ -57,15 +57,15 @@ mock-driver = ["tick-hz-1_000_000", "dep:embassy-time-queue-driver"] #! end user to pick. ## Generic Queue with 8 timers -generic-queue-8 = ["embassy-time-queue-driver/generic-queue-8"] +generic-queue-8 = ["embassy-time-queue-utils/generic-queue-8"] ## Generic Queue with 16 timers -generic-queue-16 = ["embassy-time-queue-driver/generic-queue-16"] +generic-queue-16 = ["embassy-time-queue-utils/generic-queue-16"] ## Generic Queue with 32 timers -generic-queue-32 = ["embassy-time-queue-driver/generic-queue-32"] +generic-queue-32 = ["embassy-time-queue-utils/generic-queue-32"] ## Generic Queue with 64 timers -generic-queue-64 = ["embassy-time-queue-driver/generic-queue-64"] +generic-queue-64 = ["embassy-time-queue-utils/generic-queue-64"] ## Generic Queue with 128 timers -generic-queue-128 = ["embassy-time-queue-driver/generic-queue-128"] +generic-queue-128 = ["embassy-time-queue-utils/generic-queue-128"] #! ### Tick Rate #! @@ -409,7 +409,7 @@ tick-hz-5_242_880_000 = ["embassy-time-driver/tick-hz-5_242_880_000"] [dependencies] embassy-time-driver = { version = "0.2", path = "../embassy-time-driver" } -embassy-time-queue-driver = { version = "0.2", path = "../embassy-time-queue-driver", optional = true} +embassy-time-queue-utils = { version = "0.1", path = "../embassy-time-queue-utils", optional = true} defmt = { version = "0.3", optional = true } log = { version = "0.4.14", optional = true } diff --git a/embassy-time/src/driver_mock.rs b/embassy-time/src/driver_mock.rs index 138d60499..bb1961bf2 100644 --- a/embassy-time/src/driver_mock.rs +++ b/embassy-time/src/driver_mock.rs @@ -3,7 +3,7 @@ use core::task::Waker; use critical_section::Mutex as CsMutex; use embassy_time_driver::Driver; -use embassy_time_queue_driver::Queue; +use embassy_time_queue_utils::Queue; use crate::{Duration, Instant}; diff --git a/embassy-time/src/driver_std.rs b/embassy-time/src/driver_std.rs index 35888fddd..87d7ef7eb 100644 --- a/embassy-time/src/driver_std.rs +++ b/embassy-time/src/driver_std.rs @@ -3,7 +3,7 @@ use std::thread; use std::time::{Duration as StdDuration, Instant as StdInstant}; use embassy_time_driver::Driver; -use embassy_time_queue_driver::Queue; +use embassy_time_queue_utils::Queue; struct TimeDriver { signaler: Signaler, diff --git a/embassy-time/src/driver_wasm.rs b/embassy-time/src/driver_wasm.rs index bcdd1670b..e3207691a 100644 --- a/embassy-time/src/driver_wasm.rs +++ b/embassy-time/src/driver_wasm.rs @@ -1,7 +1,7 @@ use std::sync::Mutex; use embassy_time_driver::Driver; -use embassy_time_queue_driver::Queue; +use embassy_time_queue_utils::Queue; use wasm_bindgen::prelude::*; use wasm_timer::Instant as StdInstant; diff --git a/examples/nrf52840-rtic/Cargo.toml b/examples/nrf52840-rtic/Cargo.toml index f3c660103..00dfe9d80 100644 --- a/examples/nrf52840-rtic/Cargo.toml +++ b/examples/nrf52840-rtic/Cargo.toml @@ -10,7 +10,7 @@ rtic = { version = "2", features = ["thumbv7-backend"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = [ "defmt", "defmt-timestamp-uptime"] } -embassy-time-queue-driver = { version = "0.2", path = "../../embassy-time-queue-driver", features = ["generic-queue-8"] } +embassy-time-queue-utils = { version = "0.1", path = "../../embassy-time-queue-utils", features = ["generic-queue-8"] } embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = [ "defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } defmt = "0.3" From 4c7e1b05a0f363e6a3905e1d2743ff420adf9d4c Mon Sep 17 00:00:00 2001 From: wackazong Date: Mon, 23 Dec 2024 08:18:18 +0100 Subject: [PATCH 0534/1217] Impl core::err::Error for SpawnError --- embassy-executor/src/spawner.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/embassy-executor/src/spawner.rs b/embassy-executor/src/spawner.rs index 16347ad71..41320d4c3 100644 --- a/embassy-executor/src/spawner.rs +++ b/embassy-executor/src/spawner.rs @@ -62,6 +62,16 @@ pub enum SpawnError { Busy, } +impl core::fmt::Display for SpawnError { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + SpawnError::Busy => write!(f, "Busy"), + } + } +} + +impl core::error::Error for SpawnError {} + /// Handle to spawn tasks into an executor. /// /// This Spawner can spawn any task (Send and non-Send ones), but it can From 0f4b9c7451b0849857a4bf712194e847db9e5730 Mon Sep 17 00:00:00 2001 From: Eekle <96976531+Eekle@users.noreply.github.com> Date: Tue, 24 Dec 2024 12:53:06 +0100 Subject: [PATCH 0535/1217] Default USB to use composite_with_iads, which "just works" in most cases --- embassy-usb/src/builder.rs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/embassy-usb/src/builder.rs b/embassy-usb/src/builder.rs index 008a10f72..c19e13fe0 100644 --- a/embassy-usb/src/builder.rs +++ b/embassy-usb/src/builder.rs @@ -84,11 +84,14 @@ pub struct Config<'a> { /// Configures the device as a composite device with interface association descriptors. /// - /// If set to `true`, the following fields should have the given values: + /// If set to `true` (default), the following fields should have the given values: /// /// - `device_class` = `0xEF` /// - `device_sub_class` = `0x02` /// - `device_protocol` = `0x01` + /// + /// If set to `false`, those fields must be set correctly for the classes that will be + /// installed on the USB device. pub composite_with_iads: bool, /// Whether the device has its own power source. @@ -117,9 +120,9 @@ impl<'a> Config<'a> { /// Create default configuration with the provided vid and pid values. pub const fn new(vid: u16, pid: u16) -> Self { Self { - device_class: 0x00, - device_sub_class: 0x00, - device_protocol: 0x00, + device_class: 0xEF, + device_sub_class: 0x02, + device_protocol: 0x01, max_packet_size_0: 64, vendor_id: vid, product_id: pid, @@ -130,7 +133,7 @@ impl<'a> Config<'a> { serial_number: None, self_powered: false, supports_remote_wakeup: false, - composite_with_iads: false, + composite_with_iads: true, max_power: 100, } } From a3d35216d4649fbadd3e78fe240b736258b7befe Mon Sep 17 00:00:00 2001 From: Eekle <96976531+Eekle@users.noreply.github.com> Date: Tue, 24 Dec 2024 13:23:08 +0100 Subject: [PATCH 0536/1217] Remove manual settings of `composite_with_iads=true` --- embassy-usb-logger/src/lib.rs | 7 ------- examples/nrf52840/src/bin/usb_ethernet.rs | 6 ------ examples/nrf52840/src/bin/usb_serial.rs | 7 ------- examples/nrf52840/src/bin/usb_serial_multitask.rs | 7 ------- examples/nrf52840/src/bin/usb_serial_winusb.rs | 7 ------- examples/rp/src/bin/pio_uart.rs | 7 ------- examples/rp/src/bin/usb_ethernet.rs | 6 ------ examples/rp/src/bin/usb_midi.rs | 7 ------- examples/rp/src/bin/usb_raw.rs | 7 ------- examples/rp/src/bin/usb_raw_bulk.rs | 7 ------- examples/rp/src/bin/usb_serial.rs | 7 ------- examples/rp/src/bin/usb_serial_with_logger.rs | 7 ------- examples/rp23/src/bin/pio_uart.rs | 7 ------- examples/stm32f4/src/bin/usb_ethernet.rs | 6 ------ examples/stm32f4/src/bin/usb_hid_keyboard.rs | 7 ------- examples/stm32f4/src/bin/usb_hid_mouse.rs | 7 ------- examples/stm32f4/src/bin/usb_raw.rs | 7 ------- examples/stm32f4/src/bin/usb_serial.rs | 7 ------- examples/stm32f4/src/bin/usb_uac_speaker.rs | 7 ------- examples/stm32f7/src/bin/usb_serial.rs | 7 ------- examples/stm32g4/src/bin/usb_serial.rs | 5 ----- examples/stm32h5/src/bin/usb_serial.rs | 7 ------- examples/stm32h5/src/bin/usb_uac_speaker.rs | 7 ------- examples/stm32h7/src/bin/usb_serial.rs | 7 ------- examples/stm32h7rs/src/bin/usb_serial.rs | 6 ------ examples/stm32l1/src/bin/usb_serial.rs | 5 ----- examples/stm32l4/src/bin/usb_serial.rs | 7 ------- examples/stm32l5/src/bin/usb_ethernet.rs | 6 ------ examples/stm32u5/src/bin/usb_hs_serial.rs | 7 ------- examples/stm32u5/src/bin/usb_serial.rs | 7 ------- 30 files changed, 201 deletions(-) diff --git a/embassy-usb-logger/src/lib.rs b/embassy-usb-logger/src/lib.rs index 29c102f10..de25abce1 100644 --- a/embassy-usb-logger/src/lib.rs +++ b/embassy-usb-logger/src/lib.rs @@ -102,13 +102,6 @@ impl UsbLogger { config.max_power = 100; config.max_packet_size_0 = MAX_PACKET_SIZE; - // Required for windows compatiblity. - // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help - config.device_class = 0xEF; - config.device_sub_class = 0x02; - config.device_protocol = 0x01; - config.composite_with_iads = true; - let mut builder = Builder::new( driver, config, diff --git a/examples/nrf52840/src/bin/usb_ethernet.rs b/examples/nrf52840/src/bin/usb_ethernet.rs index 88314b749..49856012d 100644 --- a/examples/nrf52840/src/bin/usb_ethernet.rs +++ b/examples/nrf52840/src/bin/usb_ethernet.rs @@ -60,12 +60,6 @@ async fn main(spawner: Spawner) { config.max_power = 100; config.max_packet_size_0 = 64; - // Required for Windows support. - config.composite_with_iads = true; - config.device_class = 0xEF; - config.device_sub_class = 0x02; - config.device_protocol = 0x01; - // Create embassy-usb DeviceBuilder using the driver and config. static CONFIG_DESC: StaticCell<[u8; 256]> = StaticCell::new(); static BOS_DESC: StaticCell<[u8; 256]> = StaticCell::new(); diff --git a/examples/nrf52840/src/bin/usb_serial.rs b/examples/nrf52840/src/bin/usb_serial.rs index a534046d9..8d05df791 100644 --- a/examples/nrf52840/src/bin/usb_serial.rs +++ b/examples/nrf52840/src/bin/usb_serial.rs @@ -36,13 +36,6 @@ async fn main(_spawner: Spawner) { config.max_power = 100; config.max_packet_size_0 = 64; - // Required for windows compatibility. - // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help - config.device_class = 0xEF; - config.device_sub_class = 0x02; - config.device_protocol = 0x01; - config.composite_with_iads = true; - // Create embassy-usb DeviceBuilder using the driver and config. // It needs some buffers for building the descriptors. let mut config_descriptor = [0; 256]; diff --git a/examples/nrf52840/src/bin/usb_serial_multitask.rs b/examples/nrf52840/src/bin/usb_serial_multitask.rs index 32fc5e094..5e5b4de35 100644 --- a/examples/nrf52840/src/bin/usb_serial_multitask.rs +++ b/examples/nrf52840/src/bin/usb_serial_multitask.rs @@ -53,13 +53,6 @@ async fn main(spawner: Spawner) { config.max_power = 100; config.max_packet_size_0 = 64; - // Required for windows compatibility. - // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help - config.device_class = 0xEF; - config.device_sub_class = 0x02; - config.device_protocol = 0x01; - config.composite_with_iads = true; - static STATE: StaticCell = StaticCell::new(); let state = STATE.init(State::new()); diff --git a/examples/nrf52840/src/bin/usb_serial_winusb.rs b/examples/nrf52840/src/bin/usb_serial_winusb.rs index 0352f9c66..8a20ce673 100644 --- a/examples/nrf52840/src/bin/usb_serial_winusb.rs +++ b/examples/nrf52840/src/bin/usb_serial_winusb.rs @@ -41,13 +41,6 @@ async fn main(_spawner: Spawner) { config.max_power = 100; config.max_packet_size_0 = 64; - // Required for windows compatibility. - // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help - config.device_class = 0xEF; - config.device_sub_class = 0x02; - config.device_protocol = 0x01; - config.composite_with_iads = true; - // Create embassy-usb DeviceBuilder using the driver and config. // It needs some buffers for building the descriptors. let mut config_descriptor = [0; 256]; diff --git a/examples/rp/src/bin/pio_uart.rs b/examples/rp/src/bin/pio_uart.rs index aaf2a524f..485c65204 100644 --- a/examples/rp/src/bin/pio_uart.rs +++ b/examples/rp/src/bin/pio_uart.rs @@ -49,13 +49,6 @@ async fn main(_spawner: Spawner) { config.max_power = 100; config.max_packet_size_0 = 64; - // Required for windows compatibility. - // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help - config.device_class = 0xEF; - config.device_sub_class = 0x02; - config.device_protocol = 0x01; - config.composite_with_iads = true; - // Create embassy-usb DeviceBuilder using the driver and config. // It needs some buffers for building the descriptors. let mut config_descriptor = [0; 256]; diff --git a/examples/rp/src/bin/usb_ethernet.rs b/examples/rp/src/bin/usb_ethernet.rs index 9a15125d4..2add20bc6 100644 --- a/examples/rp/src/bin/usb_ethernet.rs +++ b/examples/rp/src/bin/usb_ethernet.rs @@ -60,12 +60,6 @@ async fn main(spawner: Spawner) { config.max_power = 100; config.max_packet_size_0 = 64; - // Required for Windows support. - config.composite_with_iads = true; - config.device_class = 0xEF; - config.device_sub_class = 0x02; - config.device_protocol = 0x01; - // Create embassy-usb DeviceBuilder using the driver and config. static CONFIG_DESC: StaticCell<[u8; 256]> = StaticCell::new(); static BOS_DESC: StaticCell<[u8; 256]> = StaticCell::new(); diff --git a/examples/rp/src/bin/usb_midi.rs b/examples/rp/src/bin/usb_midi.rs index 11db1b2e1..3b7910f8b 100644 --- a/examples/rp/src/bin/usb_midi.rs +++ b/examples/rp/src/bin/usb_midi.rs @@ -37,13 +37,6 @@ async fn main(_spawner: Spawner) { config.max_power = 100; config.max_packet_size_0 = 64; - // Required for windows compatibility. - // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help - config.device_class = 0xEF; - config.device_sub_class = 0x02; - config.device_protocol = 0x01; - config.composite_with_iads = true; - // Create embassy-usb DeviceBuilder using the driver and config. // It needs some buffers for building the descriptors. let mut config_descriptor = [0; 256]; diff --git a/examples/rp/src/bin/usb_raw.rs b/examples/rp/src/bin/usb_raw.rs index 97e7e0244..5974c04c0 100644 --- a/examples/rp/src/bin/usb_raw.rs +++ b/examples/rp/src/bin/usb_raw.rs @@ -84,13 +84,6 @@ async fn main(_spawner: Spawner) { config.max_power = 100; config.max_packet_size_0 = 64; - // // Required for windows compatibility. - // // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help - config.device_class = 0xEF; - config.device_sub_class = 0x02; - config.device_protocol = 0x01; - config.composite_with_iads = true; - // Create embassy-usb DeviceBuilder using the driver and config. // It needs some buffers for building the descriptors. let mut config_descriptor = [0; 256]; diff --git a/examples/rp/src/bin/usb_raw_bulk.rs b/examples/rp/src/bin/usb_raw_bulk.rs index 331c3da4c..103269791 100644 --- a/examples/rp/src/bin/usb_raw_bulk.rs +++ b/examples/rp/src/bin/usb_raw_bulk.rs @@ -62,13 +62,6 @@ async fn main(_spawner: Spawner) { config.max_power = 100; config.max_packet_size_0 = 64; - // // Required for windows compatibility. - // // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help - config.device_class = 0xEF; - config.device_sub_class = 0x02; - config.device_protocol = 0x01; - config.composite_with_iads = true; - // Create embassy-usb DeviceBuilder using the driver and config. // It needs some buffers for building the descriptors. let mut config_descriptor = [0; 256]; diff --git a/examples/rp/src/bin/usb_serial.rs b/examples/rp/src/bin/usb_serial.rs index 4a802994a..5e3f0f378 100644 --- a/examples/rp/src/bin/usb_serial.rs +++ b/examples/rp/src/bin/usb_serial.rs @@ -37,13 +37,6 @@ async fn main(spawner: Spawner) { config.serial_number = Some("12345678"); config.max_power = 100; config.max_packet_size_0 = 64; - - // Required for windows compatibility. - // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help - config.device_class = 0xEF; - config.device_sub_class = 0x02; - config.device_protocol = 0x01; - config.composite_with_iads = true; config }; diff --git a/examples/rp/src/bin/usb_serial_with_logger.rs b/examples/rp/src/bin/usb_serial_with_logger.rs index f9cfdef94..ea13a1e27 100644 --- a/examples/rp/src/bin/usb_serial_with_logger.rs +++ b/examples/rp/src/bin/usb_serial_with_logger.rs @@ -37,13 +37,6 @@ async fn main(_spawner: Spawner) { config.max_power = 100; config.max_packet_size_0 = 64; - // Required for windows compatibility. - // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help - config.device_class = 0xEF; - config.device_sub_class = 0x02; - config.device_protocol = 0x01; - config.composite_with_iads = true; - // Create embassy-usb DeviceBuilder using the driver and config. // It needs some buffers for building the descriptors. let mut config_descriptor = [0; 256]; diff --git a/examples/rp23/src/bin/pio_uart.rs b/examples/rp23/src/bin/pio_uart.rs index f8398c22a..672732c5b 100644 --- a/examples/rp23/src/bin/pio_uart.rs +++ b/examples/rp23/src/bin/pio_uart.rs @@ -52,13 +52,6 @@ async fn main(_spawner: Spawner) { config.max_power = 100; config.max_packet_size_0 = 64; - // Required for windows compatibility. - // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help - config.device_class = 0xEF; - config.device_sub_class = 0x02; - config.device_protocol = 0x01; - config.composite_with_iads = true; - // Create embassy-usb DeviceBuilder using the driver and config. // It needs some buffers for building the descriptors. let mut config_descriptor = [0; 256]; diff --git a/examples/stm32f4/src/bin/usb_ethernet.rs b/examples/stm32f4/src/bin/usb_ethernet.rs index a9504ec04..322cb90c7 100644 --- a/examples/stm32f4/src/bin/usb_ethernet.rs +++ b/examples/stm32f4/src/bin/usb_ethernet.rs @@ -93,12 +93,6 @@ async fn main(spawner: Spawner) { config.max_power = 100; config.max_packet_size_0 = 64; - // Required for Windows support. - config.composite_with_iads = true; - config.device_class = 0xEF; - config.device_sub_class = 0x02; - config.device_protocol = 0x01; - // Create embassy-usb DeviceBuilder using the driver and config. static CONFIG_DESC: StaticCell<[u8; 256]> = StaticCell::new(); static BOS_DESC: StaticCell<[u8; 256]> = StaticCell::new(); diff --git a/examples/stm32f4/src/bin/usb_hid_keyboard.rs b/examples/stm32f4/src/bin/usb_hid_keyboard.rs index 1270995c4..d6b4a9bc9 100644 --- a/examples/stm32f4/src/bin/usb_hid_keyboard.rs +++ b/examples/stm32f4/src/bin/usb_hid_keyboard.rs @@ -71,13 +71,6 @@ async fn main(_spawner: Spawner) { config.max_power = 100; config.max_packet_size_0 = 64; - // Required for windows compatibility. - // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help - config.device_class = 0xEF; - config.device_sub_class = 0x02; - config.device_protocol = 0x01; - config.composite_with_iads = true; - // Create embassy-usb DeviceBuilder using the driver and config. // It needs some buffers for building the descriptors. let mut config_descriptor = [0; 256]; diff --git a/examples/stm32f4/src/bin/usb_hid_mouse.rs b/examples/stm32f4/src/bin/usb_hid_mouse.rs index 45136f965..badb65e98 100644 --- a/examples/stm32f4/src/bin/usb_hid_mouse.rs +++ b/examples/stm32f4/src/bin/usb_hid_mouse.rs @@ -66,13 +66,6 @@ async fn main(_spawner: Spawner) { config.product = Some("HID mouse example"); config.serial_number = Some("12345678"); - // Required for windows compatibility. - // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help - config.device_class = 0xEF; - config.device_sub_class = 0x02; - config.device_protocol = 0x01; - config.composite_with_iads = true; - // Create embassy-usb DeviceBuilder using the driver and config. // It needs some buffers for building the descriptors. let mut config_descriptor = [0; 256]; diff --git a/examples/stm32f4/src/bin/usb_raw.rs b/examples/stm32f4/src/bin/usb_raw.rs index b2d706208..bbbcc082b 100644 --- a/examples/stm32f4/src/bin/usb_raw.rs +++ b/examples/stm32f4/src/bin/usb_raw.rs @@ -119,13 +119,6 @@ async fn main(_spawner: Spawner) { config.product = Some("USB-raw example"); config.serial_number = Some("12345678"); - // Required for windows compatibility. - // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help - config.device_class = 0xEF; - config.device_sub_class = 0x02; - config.device_protocol = 0x01; - config.composite_with_iads = true; - // Create embassy-usb DeviceBuilder using the driver and config. // It needs some buffers for building the descriptors. let mut config_descriptor = [0; 256]; diff --git a/examples/stm32f4/src/bin/usb_serial.rs b/examples/stm32f4/src/bin/usb_serial.rs index 328b5effe..e62b2d8d6 100644 --- a/examples/stm32f4/src/bin/usb_serial.rs +++ b/examples/stm32f4/src/bin/usb_serial.rs @@ -66,13 +66,6 @@ async fn main(_spawner: Spawner) { config.product = Some("USB-serial example"); config.serial_number = Some("12345678"); - // Required for windows compatibility. - // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help - config.device_class = 0xEF; - config.device_sub_class = 0x02; - config.device_protocol = 0x01; - config.composite_with_iads = true; - // Create embassy-usb DeviceBuilder using the driver and config. // It needs some buffers for building the descriptors. let mut config_descriptor = [0; 256]; diff --git a/examples/stm32f4/src/bin/usb_uac_speaker.rs b/examples/stm32f4/src/bin/usb_uac_speaker.rs index e22e07e63..654bec498 100644 --- a/examples/stm32f4/src/bin/usb_uac_speaker.rs +++ b/examples/stm32f4/src/bin/usb_uac_speaker.rs @@ -315,13 +315,6 @@ async fn main(spawner: Spawner) { config.product = Some("USB-audio-speaker example"); config.serial_number = Some("12345678"); - // Required for windows compatibility. - // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help - config.device_class = 0xEF; - config.device_sub_class = 0x02; - config.device_protocol = 0x01; - config.composite_with_iads = true; - let mut builder = embassy_usb::Builder::new( usb_driver, config, diff --git a/examples/stm32f7/src/bin/usb_serial.rs b/examples/stm32f7/src/bin/usb_serial.rs index 1906b28ed..349012888 100644 --- a/examples/stm32f7/src/bin/usb_serial.rs +++ b/examples/stm32f7/src/bin/usb_serial.rs @@ -66,13 +66,6 @@ async fn main(_spawner: Spawner) { config.product = Some("USB-serial example"); config.serial_number = Some("12345678"); - // Required for windows compatibility. - // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help - config.device_class = 0xEF; - config.device_sub_class = 0x02; - config.device_protocol = 0x01; - config.composite_with_iads = true; - // Create embassy-usb DeviceBuilder using the driver and config. // It needs some buffers for building the descriptors. let mut config_descriptor = [0; 256]; diff --git a/examples/stm32g4/src/bin/usb_serial.rs b/examples/stm32g4/src/bin/usb_serial.rs index ed2ac7fac..9f66f0c53 100644 --- a/examples/stm32g4/src/bin/usb_serial.rs +++ b/examples/stm32g4/src/bin/usb_serial.rs @@ -51,11 +51,6 @@ async fn main(_spawner: Spawner) { config.product = Some("USB-Serial Example"); config.serial_number = Some("123456"); - config.device_class = 0xEF; - config.device_sub_class = 0x02; - config.device_protocol = 0x01; - config.composite_with_iads = true; - let mut config_descriptor = [0; 256]; let mut bos_descriptor = [0; 256]; let mut control_buf = [0; 64]; diff --git a/examples/stm32h5/src/bin/usb_serial.rs b/examples/stm32h5/src/bin/usb_serial.rs index fbcbdb5f9..e8f536133 100644 --- a/examples/stm32h5/src/bin/usb_serial.rs +++ b/examples/stm32h5/src/bin/usb_serial.rs @@ -56,13 +56,6 @@ async fn main(_spawner: Spawner) { config.product = Some("USB-serial example"); config.serial_number = Some("12345678"); - // Required for windows compatibility. - // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help - config.device_class = 0xEF; - config.device_sub_class = 0x02; - config.device_protocol = 0x01; - config.composite_with_iads = true; - // Create embassy-usb DeviceBuilder using the driver and config. // It needs some buffers for building the descriptors. let mut config_descriptor = [0; 256]; diff --git a/examples/stm32h5/src/bin/usb_uac_speaker.rs b/examples/stm32h5/src/bin/usb_uac_speaker.rs index 8c24fa916..5d007261c 100644 --- a/examples/stm32h5/src/bin/usb_uac_speaker.rs +++ b/examples/stm32h5/src/bin/usb_uac_speaker.rs @@ -309,13 +309,6 @@ async fn main(spawner: Spawner) { config.product = Some("USB-audio-speaker example"); config.serial_number = Some("12345678"); - // Required for windows compatibility. - // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help - config.device_class = 0xEF; - config.device_sub_class = 0x02; - config.device_protocol = 0x01; - config.composite_with_iads = true; - let mut builder = embassy_usb::Builder::new( usb_driver, config, diff --git a/examples/stm32h7/src/bin/usb_serial.rs b/examples/stm32h7/src/bin/usb_serial.rs index 65ae597d4..50bb964da 100644 --- a/examples/stm32h7/src/bin/usb_serial.rs +++ b/examples/stm32h7/src/bin/usb_serial.rs @@ -67,13 +67,6 @@ async fn main(_spawner: Spawner) { config.product = Some("USB-serial example"); config.serial_number = Some("12345678"); - // Required for windows compatibility. - // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help - config.device_class = 0xEF; - config.device_sub_class = 0x02; - config.device_protocol = 0x01; - config.composite_with_iads = true; - // Create embassy-usb DeviceBuilder using the driver and config. // It needs some buffers for building the descriptors. let mut config_descriptor = [0; 256]; diff --git a/examples/stm32h7rs/src/bin/usb_serial.rs b/examples/stm32h7rs/src/bin/usb_serial.rs index 6773f7843..56a9884af 100644 --- a/examples/stm32h7rs/src/bin/usb_serial.rs +++ b/examples/stm32h7rs/src/bin/usb_serial.rs @@ -70,12 +70,6 @@ async fn main(_spawner: Spawner) { config.manufacturer = Some("Embassy"); config.product = Some("USB-serial example"); config.serial_number = Some("12345678"); - // Required for windows compatibility. - // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help - config.device_class = 0xEF; - config.device_sub_class = 0x02; - config.device_protocol = 0x01; - config.composite_with_iads = true; // Create embassy-usb DeviceBuilder using the driver and config. // It needs some buffers for building the descriptors. diff --git a/examples/stm32l1/src/bin/usb_serial.rs b/examples/stm32l1/src/bin/usb_serial.rs index 837f7fa57..a35f1d7a7 100644 --- a/examples/stm32l1/src/bin/usb_serial.rs +++ b/examples/stm32l1/src/bin/usb_serial.rs @@ -41,11 +41,6 @@ async fn main(_spawner: Spawner) { config.product = Some("USB-Serial Example"); config.serial_number = Some("123456"); - config.device_class = 0xEF; - config.device_sub_class = 0x02; - config.device_protocol = 0x01; - config.composite_with_iads = true; - let mut config_descriptor = [0; 256]; let mut bos_descriptor = [0; 256]; let mut control_buf = [0; 64]; diff --git a/examples/stm32l4/src/bin/usb_serial.rs b/examples/stm32l4/src/bin/usb_serial.rs index c3b1211d8..af90e297e 100644 --- a/examples/stm32l4/src/bin/usb_serial.rs +++ b/examples/stm32l4/src/bin/usb_serial.rs @@ -62,13 +62,6 @@ async fn main(_spawner: Spawner) { config.product = Some("USB-serial example"); config.serial_number = Some("12345678"); - // Required for windows compatibility. - // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help - config.device_class = 0xEF; - config.device_sub_class = 0x02; - config.device_protocol = 0x01; - config.composite_with_iads = true; - // Create embassy-usb DeviceBuilder using the driver and config. // It needs some buffers for building the descriptors. let mut config_descriptor = [0; 256]; diff --git a/examples/stm32l5/src/bin/usb_ethernet.rs b/examples/stm32l5/src/bin/usb_ethernet.rs index 095d50c73..809ec6ab1 100644 --- a/examples/stm32l5/src/bin/usb_ethernet.rs +++ b/examples/stm32l5/src/bin/usb_ethernet.rs @@ -72,12 +72,6 @@ async fn main(spawner: Spawner) { config.max_power = 100; config.max_packet_size_0 = 64; - // Required for Windows support. - config.composite_with_iads = true; - config.device_class = 0xEF; - config.device_sub_class = 0x02; - config.device_protocol = 0x01; - // Create embassy-usb DeviceBuilder using the driver and config. static CONFIG_DESC: StaticCell<[u8; 256]> = StaticCell::new(); static BOS_DESC: StaticCell<[u8; 256]> = StaticCell::new(); diff --git a/examples/stm32u5/src/bin/usb_hs_serial.rs b/examples/stm32u5/src/bin/usb_hs_serial.rs index 5549e2cbb..d37e7777b 100644 --- a/examples/stm32u5/src/bin/usb_hs_serial.rs +++ b/examples/stm32u5/src/bin/usb_hs_serial.rs @@ -59,13 +59,6 @@ async fn main(_spawner: Spawner) { config.product = Some("USB-serial example"); config.serial_number = Some("12345678"); - // Required for windows compatibility. - // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help - config.device_class = 0xEF; - config.device_sub_class = 0x02; - config.device_protocol = 0x01; - config.composite_with_iads = true; - // Create embassy-usb DeviceBuilder using the driver and config. // It needs some buffers for building the descriptors. let mut config_descriptor = [0; 256]; diff --git a/examples/stm32u5/src/bin/usb_serial.rs b/examples/stm32u5/src/bin/usb_serial.rs index 4bb1a6079..ff7f4e5be 100644 --- a/examples/stm32u5/src/bin/usb_serial.rs +++ b/examples/stm32u5/src/bin/usb_serial.rs @@ -56,13 +56,6 @@ async fn main(_spawner: Spawner) { config.product = Some("USB-serial example"); config.serial_number = Some("12345678"); - // Required for windows compatibility. - // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help - config.device_class = 0xEF; - config.device_sub_class = 0x02; - config.device_protocol = 0x01; - config.composite_with_iads = true; - // Create embassy-usb DeviceBuilder using the driver and config. // It needs some buffers for building the descriptors. let mut config_descriptor = [0; 256]; From cac700088231a8affd9595e31b9747a51ae64b6b Mon Sep 17 00:00:00 2001 From: Eekle <96976531+Eekle@users.noreply.github.com> Date: Tue, 24 Dec 2024 13:49:55 +0100 Subject: [PATCH 0537/1217] Update default docs for device class fields --- embassy-usb/src/builder.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/embassy-usb/src/builder.rs b/embassy-usb/src/builder.rs index c19e13fe0..9a21b9a3b 100644 --- a/embassy-usb/src/builder.rs +++ b/embassy-usb/src/builder.rs @@ -34,17 +34,20 @@ pub struct Config<'a> { /// Device class code assigned by USB.org. Set to `0xff` for vendor-specific /// devices that do not conform to any class. /// - /// Default: `0x00` (class code specified by interfaces) + /// Default: `0xEF` + /// See also: `composite_with_iads` pub device_class: u8, /// Device sub-class code. Depends on class. /// - /// Default: `0x00` + /// Default: `0x02` + /// See also: `composite_with_iads` pub device_sub_class: u8, /// Device protocol code. Depends on class and sub-class. /// - /// Default: `0x00` + /// Default: `0x01` + /// See also: `composite_with_iads` pub device_protocol: u8, /// Device release version in BCD. From 2a1620d6f762be56580ea497af137b18866857f7 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Wed, 25 Dec 2024 13:06:54 +0100 Subject: [PATCH 0538/1217] Remove useless std cargo features. --- embassy-embedded-hal/Cargo.toml | 5 ----- embassy-embedded-hal/src/lib.rs | 2 +- embassy-net/Cargo.toml | 3 --- embassy-net/src/lib.rs | 2 +- examples/std/Cargo.toml | 2 +- 5 files changed, 3 insertions(+), 11 deletions(-) diff --git a/embassy-embedded-hal/Cargo.toml b/embassy-embedded-hal/Cargo.toml index 440d4b5fc..0407bd5b6 100644 --- a/embassy-embedded-hal/Cargo.toml +++ b/embassy-embedded-hal/Cargo.toml @@ -15,14 +15,9 @@ categories = [ [package.metadata.embassy_docs] src_base = "https://github.com/embassy-rs/embassy/blob/embassy-embedded-hal-v$VERSION/embassy-embedded-hal/src/" src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-embedded-hal/src/" -features = ["std"] target = "x86_64-unknown-linux-gnu" -[package.metadata.docs.rs] -features = ["std"] - [features] -std = [] time = ["dep:embassy-time"] default = ["time"] diff --git a/embassy-embedded-hal/src/lib.rs b/embassy-embedded-hal/src/lib.rs index 99a2d93c7..1db4fe012 100644 --- a/embassy-embedded-hal/src/lib.rs +++ b/embassy-embedded-hal/src/lib.rs @@ -1,4 +1,4 @@ -#![cfg_attr(not(feature = "std"), no_std)] +#![no_std] #![allow(async_fn_in_trait)] #![warn(missing_docs)] #![doc = include_str!("../README.md")] diff --git a/embassy-net/Cargo.toml b/embassy-net/Cargo.toml index a59327367..a7f7ffad2 100644 --- a/embassy-net/Cargo.toml +++ b/embassy-net/Cargo.toml @@ -23,9 +23,6 @@ target = "thumbv7em-none-eabi" features = ["defmt", "tcp", "udp", "raw", "dns", "dhcpv4", "proto-ipv6", "medium-ethernet", "medium-ip", "medium-ieee802154", "multicast", "dhcpv4-hostname"] [features] -default = [] -std = [] - ## Enable defmt defmt = ["dep:defmt", "smoltcp/defmt", "embassy-net-driver/defmt", "heapless/defmt-03", "defmt?/ip_in_core"] diff --git a/embassy-net/src/lib.rs b/embassy-net/src/lib.rs index 831e01d44..47bd5191f 100644 --- a/embassy-net/src/lib.rs +++ b/embassy-net/src/lib.rs @@ -1,4 +1,4 @@ -#![cfg_attr(not(feature = "std"), no_std)] +#![no_std] #![allow(async_fn_in_trait)] #![warn(missing_docs)] #![doc = include_str!("../README.md")] diff --git a/examples/std/Cargo.toml b/examples/std/Cargo.toml index 0d1ab9f77..f67422f85 100644 --- a/examples/std/Cargo.toml +++ b/examples/std/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["log"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-std", "executor-thread", "log"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["log", "std", ] } -embassy-net = { version = "0.5.0", path = "../../embassy-net", features=[ "std", "log", "medium-ethernet", "medium-ip", "tcp", "udp", "dns", "dhcpv4", "proto-ipv6"] } +embassy-net = { version = "0.5.0", path = "../../embassy-net", features=[ "log", "medium-ethernet", "medium-ip", "tcp", "udp", "dns", "dhcpv4", "proto-ipv6"] } embassy-net-tuntap = { version = "0.1.0", path = "../../embassy-net-tuntap" } embassy-net-ppp = { version = "0.1.0", path = "../../embassy-net-ppp", features = ["log"]} embedded-io-async = { version = "0.6.1" } From 92a489b6a126913129bedc3f8a1407256b3590d7 Mon Sep 17 00:00:00 2001 From: Dion Dokter Date: Wed, 25 Dec 2024 22:50:19 +0100 Subject: [PATCH 0539/1217] Make SharedData repr C --- embassy-stm32/src/lib.rs | 39 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 39f3dfd61..3c7f96bb1 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -326,10 +326,11 @@ mod dual_core { /// ``` /// /// This static must be placed in the same position for both cores. How and where this is done is left to the user. + #[repr(C)] pub struct SharedData { init_flag: AtomicUsize, clocks: UnsafeCell>, - config: UnsafeCell>, + config: UnsafeCell>, } unsafe impl Sync for SharedData {} @@ -352,7 +353,7 @@ mod dual_core { rcc::set_freqs_ptr(shared_data.clocks.get()); let p = init_hw(config); - unsafe { *shared_data.config.get() }.write(config); + unsafe { *shared_data.config.get() }.write(config.into()); shared_data.init_flag.store(INIT_DONE_FLAG, Ordering::SeqCst); @@ -424,6 +425,40 @@ mod dual_core { Peripherals::take() } + + #[repr(C)] + #[derive(Clone, Copy)] + struct SharedConfig { + #[cfg(bdma)] + bdma_interrupt_priority: Priority, + #[cfg(dma)] + dma_interrupt_priority: Priority, + #[cfg(gpdma)] + gpdma_interrupt_priority: Priority, + } + + impl From for SharedConfig { + fn from(value: Config) -> Self { + let Config { + #[cfg(bdma)] + bdma_interrupt_priority, + #[cfg(dma)] + dma_interrupt_priority, + #[cfg(gpdma)] + gpdma_interrupt_priority, + .. + } = value; + + SharedConfig { + #[cfg(bdma)] + bdma_interrupt_priority, + #[cfg(dma)] + dma_interrupt_priority, + #[cfg(gpdma)] + gpdma_interrupt_priority, + } + } + } } #[cfg(feature = "_dual-core")] From 595ce48eb2be88a42ceb33865c337020a328a4dd Mon Sep 17 00:00:00 2001 From: Dion Dokter Date: Wed, 25 Dec 2024 22:54:48 +0100 Subject: [PATCH 0540/1217] Write the flag sooner with a known value --- embassy-stm32/src/lib.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 3c7f96bb1..857090303 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -350,6 +350,11 @@ mod dual_core { pub fn init_primary(config: Config, shared_data: &'static MaybeUninit) -> Peripherals { let shared_data = unsafe { shared_data.assume_init_ref() }; + // Write the flag as soon as possible. Reading this flag uninitialized in the `init_secondary` + // is maybe unsound? Unclear. If it is indeed unsound, writing it sooner doesn't fix it all, + // but improves the odds of it going right + shared_data.init_flag.store(0, Ordering::SeqCst); + rcc::set_freqs_ptr(shared_data.clocks.get()); let p = init_hw(config); From 19203c706f4b317a92bd47d946b32e3799ef9467 Mon Sep 17 00:00:00 2001 From: Dominik Boehi Date: Wed, 25 Dec 2024 16:47:16 +0100 Subject: [PATCH 0541/1217] nrf54l: Allow debug access from firmware sid3 This adds support for the --- embassy-nrf/src/lib.rs | 76 ++++++++++++++++++++++++---- examples/nrf54l15/.cargo/config.toml | 2 +- 2 files changed, 68 insertions(+), 10 deletions(-) diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index ec5e9f864..faef44d1b 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs @@ -507,7 +507,6 @@ pub fn init(config: config::Config) -> Peripherals { let mut needs_reset = false; // Setup debug protection. - #[cfg(not(feature = "_nrf54l"))] // TODO #[cfg(not(feature = "_nrf51"))] match config.debug { config::Debug::Allowed => { @@ -549,18 +548,77 @@ pub fn init(config: config::Config) -> Peripherals { } } + // TAMPC is only accessible for secure code + #[cfg(all(feature = "_nrf54l", feature = "_s"))] + { + use crate::pac::tampc::vals; + + // UICR cannot be written here, because it can only be written once after an erase all. + // The erase all value means that debug access is allowed if permitted by the firmware. + + // Write to TAMPC to permit debug access + // + // See https://docs.nordicsemi.com/bundle/ps_nrf54L15/page/debug.html#ariaid-title6 + + let p = pac::TAMPC; + + // Unlock dbgen + p.protect().domain(0).dbgen().ctrl().write(|w| { + w.set_key(vals::DomainDbgenCtrlKey::KEY); + w.set_writeprotection(vals::DomainDbgenCtrlWriteprotection::CLEAR); + }); + p.protect().domain(0).dbgen().ctrl().write(|w| { + w.set_key(vals::DomainDbgenCtrlKey::KEY); + w.set_value(vals::DomainDbgenCtrlValue::HIGH); + }); + + // Unlock niden + p.protect().domain(0).niden().ctrl().write(|w| { + w.set_key(vals::NidenCtrlKey::KEY); + w.set_writeprotection(vals::NidenCtrlWriteprotection::CLEAR); + }); + p.protect().domain(0).niden().ctrl().write(|w| { + w.set_key(vals::NidenCtrlKey::KEY); + w.set_value(vals::NidenCtrlValue::HIGH); + }); + + p.protect().domain(0).spiden().ctrl().write(|w| { + w.set_key(vals::SpidenCtrlKey::KEY); + w.set_writeprotection(vals::SpidenCtrlWriteprotection::CLEAR); + }); + p.protect().domain(0).spiden().ctrl().write(|w| { + w.set_key(vals::SpidenCtrlKey::KEY); + w.set_value(vals::SpidenCtrlValue::HIGH); + }); + + p.protect().domain(0).spniden().ctrl().write(|w| { + w.set_key(vals::SpnidenCtrlKey::KEY); + w.set_writeprotection(vals::SpnidenCtrlWriteprotection::CLEAR); + }); + p.protect().domain(0).spniden().ctrl().write(|w| { + w.set_key(vals::SpnidenCtrlKey::KEY); + w.set_value(vals::SpnidenCtrlValue::HIGH); + }); + } + // nothing to do on the nrf9160, debug is allowed by default. } - config::Debug::Disallowed => unsafe { - // UICR.APPROTECT = Enabled - let res = uicr_write(consts::UICR_APPROTECT, consts::APPROTECT_ENABLED); - needs_reset |= res == WriteResult::Written; - #[cfg(any(feature = "_nrf5340-app", feature = "_nrf91"))] - { - let res = uicr_write(consts::UICR_SECUREAPPROTECT, consts::APPROTECT_ENABLED); + config::Debug::Disallowed => { + // TODO: Handle nRF54L + // By default, debug access is not allowed if the firmware doesn't allow it. + // Code could be added here to disable debug access in UICR as well. + #[cfg(not(feature = "_nrf54l"))] + unsafe { + // UICR.APPROTECT = Enabled + let res = uicr_write(consts::UICR_APPROTECT, consts::APPROTECT_ENABLED); needs_reset |= res == WriteResult::Written; + #[cfg(any(feature = "_nrf5340-app", feature = "_nrf91"))] + { + let res = uicr_write(consts::UICR_SECUREAPPROTECT, consts::APPROTECT_ENABLED); + needs_reset |= res == WriteResult::Written; + } } - }, + } config::Debug::NotConfigured => {} } diff --git a/examples/nrf54l15/.cargo/config.toml b/examples/nrf54l15/.cargo/config.toml index 4a026ebbd..443bd7418 100644 --- a/examples/nrf54l15/.cargo/config.toml +++ b/examples/nrf54l15/.cargo/config.toml @@ -1,6 +1,6 @@ [target.'cfg(all(target_arch = "arm", target_os = "none"))'] # replace nRF82840_xxAA with your chip as listed in `probe-rs chip list` -runner = "../../sshprobe.sh" +runner = "probe-rs run --chip nrf54l15" [build] target = "thumbv8m.main-none-eabihf" From d1692494823c2be9423d74d446f555a879344a0c Mon Sep 17 00:00:00 2001 From: klownfish Date: Thu, 26 Dec 2024 22:26:01 +0100 Subject: [PATCH 0542/1217] update metapac version --- embassy-stm32/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 47e9e8bb9..1d96a6a61 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -73,7 +73,7 @@ rand_core = "0.6.3" sdio-host = "0.5.0" critical-section = "1.1" #stm32-metapac = { version = "15" } -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-ddb0e7abab14bf3e1399875767b8834442382988" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-392e41259ffc5ffbfd79169ee80451114fb367fe" } vcell = "0.1.3" nb = "1.0.0" @@ -102,7 +102,7 @@ proc-macro2 = "1.0.36" quote = "1.0.15" #stm32-metapac = { version = "15", default-features = false, features = ["metadata"]} -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-ddb0e7abab14bf3e1399875767b8834442382988", default-features = false, features = ["metadata"] } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-392e41259ffc5ffbfd79169ee80451114fb367fe", default-features = false, features = ["metadata"] } [features] default = ["rt"] From 4f4740eeb25e0db607a7f700e29efd313dd1942d Mon Sep 17 00:00:00 2001 From: klownfish Date: Fri, 27 Dec 2024 00:24:47 +0100 Subject: [PATCH 0543/1217] add async read for u5 ADC4 --- embassy-stm32/src/adc/u5_adc4.rs | 122 ++++++++++++++++++++++++++----- examples/stm32u5/src/bin/adc.rs | 100 ++++++++++++++++++------- 2 files changed, 177 insertions(+), 45 deletions(-) diff --git a/embassy-stm32/src/adc/u5_adc4.rs b/embassy-stm32/src/adc/u5_adc4.rs index 8d0c1abed..ddc1b58a2 100644 --- a/embassy-stm32/src/adc/u5_adc4.rs +++ b/embassy-stm32/src/adc/u5_adc4.rs @@ -4,13 +4,14 @@ pub use crate::pac::adc::vals::Adc4Presc as Presc; pub use crate::pac::adc::regs::Adc4Chselrmod0; #[allow(unused)] -use pac::adc::vals::{Adc4Exten, Adc4OversamplingRatio}; +use pac::adc::vals::{Adc4Exten, Adc4OversamplingRatio, Adc4Dmacfg}; use super::{ - blocking_delay_us, AdcChannel, SealedAdcChannel + blocking_delay_us, AdcChannel, SealedAdcChannel, AnyAdcChannel, RxDma4 }; use crate::time::Hertz; use crate::{pac, rcc, Peripheral}; +use crate::dma::Transfer; const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(55); @@ -182,6 +183,12 @@ pub struct Adc4<'d, T: Instance> { adc: crate::PeripheralRef<'d, T>, } +#[derive(Debug)] +pub enum Adc4Error { + InvalidSequence, + DMAError +} + impl<'d, T: Instance> Adc4<'d, T> { /// Create a new ADC driver. pub fn new(adc: impl Peripheral

+ 'd) -> Self { @@ -244,6 +251,7 @@ impl<'d, T: Instance> Adc4<'d, T> { // single conversion mode, software trigger T::regs().cfgr1().modify(|w| { w.set_cont(false); + w.set_discen(false); w.set_exten(Adc4Exten::DISABLED); }); @@ -336,8 +344,18 @@ impl<'d, T: Instance> Adc4<'d, T> { }) } - /// Perform a single conversion. - fn convert(&mut self) -> u16 { + /// Read an ADC channel. + pub fn blocking_read(&mut self, channel: &mut impl AdcChannel) -> u16{ + channel.setup(); + T::regs().cfgr1().modify(|reg| { + reg.set_chselrmod(false); + }); + + T::regs().chselrmod0().write_value(Adc4Chselrmod0(0_u32)); + T::regs().chselrmod0().modify(|w| { + w.set_chsel(channel.channel() as usize, true); + }); + T::regs().isr().modify(|reg| { reg.set_eos(true); reg.set_eoc(true); @@ -355,22 +373,92 @@ impl<'d, T: Instance> Adc4<'d, T> { T::regs().dr().read().0 as u16 } - /// Read an ADC channel. - pub fn blocking_read(&mut self, channel: &mut impl AdcChannel) -> u16 { - self.read_channel(channel) - } + /// Channels can not be repeated and must be in ascending order! + /// TODO: broken + pub async fn read( + &mut self, + rx_dma: &mut impl RxDma4, + sequence: impl ExactSizeIterator>, + readings: &mut [u16], + ) -> Result<(), Adc4Error> { + assert!(sequence.len() != 0, "Asynchronous read sequence cannot be empty"); + assert!( + sequence.len() == readings.len(), + "Sequence length must be equal to readings length" + ); - fn configure_channel(channel: &mut impl AdcChannel) { - channel.setup(); - T::regs().chselrmod0().write_value(Adc4Chselrmod0(0_u32)); - T::regs().chselrmod0().modify(|w| { - w.set_chsel(channel.channel() as usize, true); + // Ensure no conversions are ongoing + Self::cancel_conversions(); + + T::regs().isr().modify(|reg| { + reg.set_ovr(true); + reg.set_eos(true); + reg.set_eoc(true); }); + + T::regs().cfgr1().modify(|reg| { + reg.set_dmaen(true); + reg.set_dmacfg(Adc4Dmacfg::ONESHOT); + reg.set_chselrmod(false); + }); + + + let mut prev_channel: i16 = -1; + T::regs().chselrmod0().write_value(Adc4Chselrmod0(0_u32)); + for channel in sequence { + let channel_num = channel.channel; + if channel_num as i16 <= prev_channel { + return Err(Adc4Error::InvalidSequence); + }; + prev_channel = channel_num as i16; + + T::regs().chselrmod0().modify(|w| { + w.set_chsel(channel.channel as usize, true); + }); + }; + + let request = rx_dma.request(); + let transfer = unsafe { + Transfer::new_read( + rx_dma, + request, + T::regs().dr().as_ptr() as *mut u16, + readings, + Default::default(), + ) + }; + + // Start conversion + T::regs().cr().modify(|reg| { + reg.set_adstart(true); + }); + + // Wait for conversion sequence to finish. + transfer.await; + + blocking_delay_us(10); + + // Ensure conversions are finished. + Self::cancel_conversions(); + + // Reset configuration. + T::regs().cfgr1().modify(|reg| { + reg.set_dmaen(false); + }); + + if T::regs().isr().read().ovr() { + Err(Adc4Error::DMAError) + } else { + Ok(()) + } } - fn read_channel(&mut self, channel: &mut impl AdcChannel) -> u16 { - Self::configure_channel(channel); - let ret = self.convert(); - ret + fn cancel_conversions() { + if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() { + T::regs().cr().modify(|reg| { + reg.set_adstp(true); + }); + while T::regs().cr().read().adstart() {} + } } } \ No newline at end of file diff --git a/examples/stm32u5/src/bin/adc.rs b/examples/stm32u5/src/bin/adc.rs index 049b985cf..4632f2cd1 100644 --- a/examples/stm32u5/src/bin/adc.rs +++ b/examples/stm32u5/src/bin/adc.rs @@ -36,55 +36,99 @@ async fn main(spawner: embassy_executor::Spawner) { let mut p = embassy_stm32::init(config); - let mut adc = adc::Adc::new(p.ADC1); - let mut adc_pin1 = p.PA3; // A0 on nucleo u5a5 - let mut adc_pin2 = p.PA2; // A1 on nucleo u5a5 - adc.set_resolution(adc::Resolution::BITS14); - adc.set_averaging(adc::Averaging::Samples1024); - adc.set_sample_time(adc::SampleTime::CYCLES160_5); - let max = adc::resolution_to_max_count(adc::Resolution::BITS14); + // **** ADC1 init **** + let mut adc1 = adc::Adc::new(p.ADC1); + let mut adc1_pin1 = p.PA3; // A0 on nucleo u5a5 + let mut adc1_pin2 = p.PA2; // A1 + adc1.set_resolution(adc::Resolution::BITS14); + adc1.set_averaging(adc::Averaging::Samples1024); + adc1.set_sample_time(adc::SampleTime::CYCLES160_5); + let max1 = adc::resolution_to_max_count(adc::Resolution::BITS14); + // **** ADC2 init **** + let mut adc2 = adc::Adc::new(p.ADC2); + let mut adc2_pin1 = p.PC3; // A2 + let mut adc2_pin2 = p.PB0; // A3 + adc2.set_resolution(adc::Resolution::BITS14); + adc2.set_averaging(adc::Averaging::Samples1024); + adc2.set_sample_time(adc::SampleTime::CYCLES160_5); + let max2 = adc::resolution_to_max_count(adc::Resolution::BITS14); + + // **** ADC4 init **** let mut adc4 = adc4::Adc4::new(p.ADC4); - let mut adc4_pin1 = p.PD11; - let mut adc4_pin2 = p.PC0; + let mut adc4_pin1 = p.PC1; // A4 + let mut adc4_pin2 = p.PC0; // A5 adc4.set_resolution(adc4::Resolution::BITS12); adc4.set_averaging(adc4::Averaging::Samples256); adc4.set_sample_time(adc4::SampleTime::CYCLES1_5); let max4 = adc4::resolution_to_max_count(adc4::Resolution::BITS12); - let raw: u16 = adc.blocking_read(&mut adc_pin1); - let volt: f32 = 3.3 * raw as f32 / max as f32; - info!("Read 1 pin 1 {}", volt); + // **** ADC1 blocking read **** + let raw: u16 = adc1.blocking_read(&mut adc1_pin1); + let volt: f32 = 3.3 * raw as f32 / max1 as f32; + info!("Read adc1 pin 1 {}", volt); - let raw: u16 = adc.blocking_read(&mut adc_pin2); - let volt: f32 = 3.3 * raw as f32 / max as f32; - info!("Read 1 pin 2 {}", volt); + let raw: u16 = adc1.blocking_read(&mut adc1_pin2); + let volt: f32 = 3.3 * raw as f32 / max1 as f32; + info!("Read adc1 pin 2 {}", volt); - let raw4: u16 = adc4.blocking_read(&mut adc4_pin1); - let volt4: f32 = 3.3 * raw4 as f32 / max4 as f32; - info!("Read 4 pin 1 {}", volt4); + // **** ADC2 blocking read **** + let raw: u16 = adc2.blocking_read(&mut adc2_pin1); + let volt: f32 = 3.3 * raw as f32 / max2 as f32; + info!("Read adc2 pin 1 {}", volt); - let raw4: u16 = adc4.blocking_read(&mut adc4_pin2); - let volt4: f32 = 3.3 * raw4 as f32 / max4 as f32; - info!("Read 4 pin 2 {}", volt4); + let raw: u16 = adc2.blocking_read(&mut adc2_pin2); + let volt: f32 = 3.3 * raw as f32 / max2 as f32; + info!("Read adc2 pin 2 {}", volt); - let mut degraded1 = adc_pin1.degrade_adc(); - let mut degraded2 = adc_pin2.degrade_adc(); + // **** ADC4 blocking read **** + let raw: u16 = adc4.blocking_read(&mut adc4_pin1); + let volt: f32 = 3.3 * raw as f32 / max4 as f32; + info!("Read adc4 pin 1 {}", volt); + + let raw: u16 = adc4.blocking_read(&mut adc4_pin2); + let volt: f32 = 3.3 * raw as f32 / max4 as f32; + info!("Read adc4 pin 2 {}", volt); + + // **** ADC1 async read **** + let mut degraded11 = adc1_pin1.degrade_adc(); + let mut degraded12 = adc1_pin2.degrade_adc(); let mut measurements = [0u16; 2]; - adc.read( + adc1.read( &mut p.GPDMA1_CH0, [ - (&mut degraded2, adc::SampleTime::CYCLES160_5), - (&mut degraded1, adc::SampleTime::CYCLES160_5), + (&mut degraded11, adc::SampleTime::CYCLES160_5), + (&mut degraded12, adc::SampleTime::CYCLES160_5), ] .into_iter(), &mut measurements, ).await; - let volt1: f32 = 3.3 * measurements[1] as f32 / max as f32; - let volt2: f32 = 3.3 * measurements[0] as f32 / max as f32; + let volt1: f32 = 3.3 * measurements[0] as f32 / max1 as f32; + let volt2: f32 = 3.3 * measurements[1] as f32 / max1 as f32; info!("Async read 1 pin 1 {}", volt1); info!("Async read 1 pin 2 {}", volt2); + // **** ADC2 does not support async read **** + + // **** ADC4 async read **** + let mut degraded41 = adc4_pin1.degrade_adc(); + let mut degraded42 = adc4_pin2.degrade_adc(); + let mut measurements = [0u16; 2]; + + // The channels must be in ascending order and can't repeat for ADC4 + adc4.read( + &mut p.GPDMA1_CH1, + [ + &mut degraded42, + &mut degraded41, + ] + .into_iter(), + &mut measurements, + ).await.unwrap(); + let volt2: f32 = 3.3 * measurements[0] as f32 / max4 as f32; + let volt1: f32 = 3.3 * measurements[1] as f32 / max4 as f32; + info!("Async read 4 pin 1 {}", volt1); + info!("Async read 4 pin 2 {}", volt2); } \ No newline at end of file From a5a90156ce2eeb09760075cecf0eea8f4d1a9e73 Mon Sep 17 00:00:00 2001 From: klownfish Date: Fri, 27 Dec 2024 02:54:38 +0100 Subject: [PATCH 0544/1217] cleanup --- embassy-stm32/src/adc/u5_adc4.rs | 74 +++++++++++++++++++++----------- embassy-stm32/src/lib.rs | 2 +- examples/stm32u5/src/bin/adc.rs | 19 -------- 3 files changed, 49 insertions(+), 46 deletions(-) diff --git a/embassy-stm32/src/adc/u5_adc4.rs b/embassy-stm32/src/adc/u5_adc4.rs index ddc1b58a2..468d16640 100644 --- a/embassy-stm32/src/adc/u5_adc4.rs +++ b/embassy-stm32/src/adc/u5_adc4.rs @@ -221,16 +221,16 @@ impl<'d, T: Instance> Adc4<'d, T> { } fn power_up(&mut self) { - T::regs().isr().modify(|reg| { - reg.set_ldordy(true); + T::regs().isr().modify(|w| { + w.set_ldordy(true); }); - T::regs().cr().modify(|reg| { - reg.set_advregen(true); + T::regs().cr().modify(|w| { + w.set_advregen(true); }); while !T::regs().isr().read().ldordy() { }; - T::regs().isr().modify(|reg| { - reg.set_ldordy(true); + T::regs().isr().modify(|w| { + w.set_ldordy(true); }); } @@ -253,6 +253,7 @@ impl<'d, T: Instance> Adc4<'d, T> { w.set_cont(false); w.set_discen(false); w.set_exten(Adc4Exten::DISABLED); + w.set_chselrmod(false); }); // only use one channel at the moment @@ -265,8 +266,8 @@ impl<'d, T: Instance> Adc4<'d, T> { /// Enable reading the voltage reference internal channel. pub fn enable_vrefint(&self) -> VrefInt { - T::regs().ccr().modify(|reg| { - reg.set_vrefen(true); + T::regs().ccr().modify(|w| { + w.set_vrefen(true); }); VrefInt {} @@ -274,8 +275,8 @@ impl<'d, T: Instance> Adc4<'d, T> { /// Enable reading the temperature internal channel. pub fn enable_temperature(&self) -> Temperature { - T::regs().ccr().modify(|reg| { - reg.set_vsensesel(true); + T::regs().ccr().modify(|w| { + w.set_vsensesel(true); }); Temperature {} @@ -283,8 +284,8 @@ impl<'d, T: Instance> Adc4<'d, T> { /// Enable reading the vbat internal channel. pub fn enable_vbat(&self) -> Vbat { - T::regs().ccr().modify(|reg| { - reg.set_vbaten(true); + T::regs().ccr().modify(|w| { + w.set_vbaten(true); }); Vbat {} @@ -320,7 +321,7 @@ impl<'d, T: Instance> Adc4<'d, T> { /// Set the ADC resolution. pub fn set_resolution(&mut self, resolution: Resolution) { - T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into())); + T::regs().cfgr1().modify(|w| w.set_res(resolution.into())); } /// Set hardware averaging. @@ -337,25 +338,24 @@ impl<'d, T: Instance> Adc4<'d, T> { Averaging::Samples256 => (true, Adc4OversamplingRatio::OVERSAMPLE256X, 8), }; - T::regs().cfgr2().modify(|reg| { - reg.set_ovsr(samples); - reg.set_ovss(right_shift); - reg.set_ovse(enable) + T::regs().cfgr2().modify(|w| { + w.set_ovsr(samples); + w.set_ovss(right_shift); + w.set_ovse(enable) }) } /// Read an ADC channel. pub fn blocking_read(&mut self, channel: &mut impl AdcChannel) -> u16{ channel.setup(); - T::regs().cfgr1().modify(|reg| { - reg.set_chselrmod(false); - }); + // Select channel T::regs().chselrmod0().write_value(Adc4Chselrmod0(0_u32)); T::regs().chselrmod0().modify(|w| { w.set_chsel(channel.channel() as usize, true); }); + // Reset interrupts T::regs().isr().modify(|reg| { reg.set_eos(true); reg.set_eoc(true); @@ -373,8 +373,33 @@ impl<'d, T: Instance> Adc4<'d, T> { T::regs().dr().read().0 as u16 } - /// Channels can not be repeated and must be in ascending order! - /// TODO: broken + /// Read one or multiple ADC channels using DMA. + /// + /// `sequence` iterator and `readings` must have the same length. + /// The channels in `sequence` must be in ascending order. + /// + /// Example + /// ```rust,ignore + /// use embassy_stm32::adc::adc4; + /// use embassy_stm32::adc::AdcChannel; + /// + /// let mut adc4 = adc4::Adc4::new(p.ADC4); + /// let mut adc4_pin1 = p.PC1; + /// let mut adc4_pin2 = p.PC0; + /// let mut degraded41 = adc4_pin1.degrade_adc(); + /// let mut degraded42 = adc4_pin2.degrade_adc(); + /// let mut measurements = [0u16; 2]; + /// // not that the channels must be in ascending order + /// adc4.read( + /// &mut p.GPDMA1_CH1, + /// [ + /// &mut degraded42, + /// &mut degraded41, + /// ] + /// .into_iter(), + /// &mut measurements, + /// ).await.unwrap(); + /// ``` pub async fn read( &mut self, rx_dma: &mut impl RxDma4, @@ -402,7 +427,7 @@ impl<'d, T: Instance> Adc4<'d, T> { reg.set_chselrmod(false); }); - + // Verify and activate sequence let mut prev_channel: i16 = -1; T::regs().chselrmod0().write_value(Adc4Chselrmod0(0_u32)); for channel in sequence { @@ -433,11 +458,8 @@ impl<'d, T: Instance> Adc4<'d, T> { reg.set_adstart(true); }); - // Wait for conversion sequence to finish. transfer.await; - blocking_delay_us(10); - // Ensure conversions are finished. Self::cancel_conversions(); diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index fb10f2a5f..d04199d05 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -238,7 +238,7 @@ pub struct Config { #[cfg(any(stm32l4, stm32l5, stm32u5))] pub enable_independent_io_supply: bool, - /// On the U5 series all analog peripherals are powere by a separate supply. + /// On the U5 series all analog peripherals are powered by a separate supply. #[cfg(stm32u5)] pub enable_independent_analog_supply: bool, diff --git a/examples/stm32u5/src/bin/adc.rs b/examples/stm32u5/src/bin/adc.rs index 4632f2cd1..05e3faeb1 100644 --- a/examples/stm32u5/src/bin/adc.rs +++ b/examples/stm32u5/src/bin/adc.rs @@ -14,25 +14,6 @@ use panic_probe as _; #[embassy_executor::main] async fn main(spawner: embassy_executor::Spawner) { let mut config = embassy_stm32::Config::default(); - { - use embassy_stm32::rcc::*; - config.rcc.hsi = true; - - config.rcc.pll1 = Some(Pll { - source: PllSource::HSI, // 16 MHz - prediv: PllPreDiv::DIV1, // 16 MHz - mul: PllMul::MUL10, // 160 MHz - divp: Some(PllDiv::DIV1), // don't care - divq: Some(PllDiv::DIV1), // don't care - divr: Some(PllDiv::DIV1), // 160 MHz - }); - - config.rcc.sys = Sysclk::PLL1_R; - config.rcc.voltage_range = VoltageScale::RANGE1; - config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); // needed for USB - config.rcc.mux.iclksel = mux::Iclksel::HSI48; // USB uses ICLK - - } let mut p = embassy_stm32::init(config); From 56f9296581800dca70474459debf4a429b312e50 Mon Sep 17 00:00:00 2001 From: Bailey Townsend Date: Fri, 27 Dec 2024 12:29:17 -0600 Subject: [PATCH 0545/1217] Added a new rm2 feature flag --- cyw43-pio/Cargo.toml | 2 ++ cyw43-pio/src/lib.rs | 8 +++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/cyw43-pio/Cargo.toml b/cyw43-pio/Cargo.toml index 4e21c255f..794bf2479 100644 --- a/cyw43-pio/Cargo.toml +++ b/cyw43-pio/Cargo.toml @@ -13,6 +13,8 @@ documentation = "https://docs.embassy.dev/cyw43-pio" # If disabled, SPI runs at 31.25MHz # If enabled, SPI runs at 62.5MHz, which is 25% higher than 50Mhz which is the maximum according to the CYW43439 datasheet. overclock = [] +# If enabled the PIO runs at a speed that works with the rm2 module +rm2 = [] [dependencies] cyw43 = { version = "0.2.0", path = "../cyw43" } diff --git a/cyw43-pio/src/lib.rs b/cyw43-pio/src/lib.rs index 40cf63a17..1280e2059 100644 --- a/cyw43-pio/src/lib.rs +++ b/cyw43-pio/src/lib.rs @@ -120,7 +120,7 @@ where cfg.clock_divider = FixedU32::from_bits(0x0100); } - #[cfg(not(feature = "overclock"))] + #[cfg(not(any(feature = "overclock", feature = "rm2")))] { // same speed as pico-sdk, 62.5Mhz // This is actually the fastest we can go without overclocking. @@ -132,6 +132,12 @@ where cfg.clock_divider = FixedU32::from_bits(0x0200); } + #[cfg(feature = "rm2")] + { + // This is found to work better with the RM2 module which is found on the Pimoroni Pico Plus 2 W + cfg.clock_divider = FixedU32::from_bits(0x0300); + } + sm.set_config(&cfg); sm.set_pin_dirs(Direction::Out, &[&pin_clk, &pin_io]); From dd31ffadfbd145f26b6bb54cf2036cb54149aefe Mon Sep 17 00:00:00 2001 From: Bailey Townsend Date: Fri, 27 Dec 2024 23:43:38 -0600 Subject: [PATCH 0546/1217] Work done --- cyw43-pio/Cargo.toml | 2 -- cyw43-pio/src/lib.rs | 48 +++++++++++++++++++++----------------------- 2 files changed, 23 insertions(+), 27 deletions(-) diff --git a/cyw43-pio/Cargo.toml b/cyw43-pio/Cargo.toml index 794bf2479..4e21c255f 100644 --- a/cyw43-pio/Cargo.toml +++ b/cyw43-pio/Cargo.toml @@ -13,8 +13,6 @@ documentation = "https://docs.embassy.dev/cyw43-pio" # If disabled, SPI runs at 31.25MHz # If enabled, SPI runs at 62.5MHz, which is 25% higher than 50Mhz which is the maximum according to the CYW43439 datasheet. overclock = [] -# If enabled the PIO runs at a speed that works with the rm2 module -rm2 = [] [dependencies] cyw43 = { version = "0.2.0", path = "../cyw43" } diff --git a/cyw43-pio/src/lib.rs b/cyw43-pio/src/lib.rs index 1280e2059..abf3830d9 100644 --- a/cyw43-pio/src/lib.rs +++ b/cyw43-pio/src/lib.rs @@ -10,6 +10,7 @@ use embassy_rp::dma::Channel; use embassy_rp::gpio::{Drive, Level, Output, Pull, SlewRate}; use embassy_rp::pio::{instr, Common, Config, Direction, Instance, Irq, PioPin, ShiftDirection, StateMachine}; use embassy_rp::{Peripheral, PeripheralRef}; +use fixed::types::extra::U8; use fixed::FixedU32; use pio_proc::pio_asm; @@ -22,6 +23,26 @@ pub struct PioSpi<'d, PIO: Instance, const SM: usize, DMA> { wrap_target: u8, } +/// The default clock divider that works for Pico 1 and 2 W. As well as the RM2 on rp2040 devices. +/// same speed as pico-sdk, 62.5Mhz +/// This is actually the fastest we can go without overclocking. +/// According to data sheet, the theoretical maximum is 100Mhz Pio => 50Mhz SPI Freq. +/// However, the PIO uses a fractional divider, which works by introducing jitter when +/// the divider is not an integer. It does some clocks at 125mhz and others at 62.5mhz +/// so that it averages out to the desired frequency of 100mhz. The 125mhz clock cycles +/// violate the maximum from the data sheet. +pub const DEFAULT_CLOCK_DIVIDER: FixedU32 = FixedU32::from_bits(0x0200); + +/// The overclock clock divider for the Pico 1 W. Does not work on any known RM2 devices. +/// 125mhz Pio => 62.5Mhz SPI Freq. 25% higher than theoretical maximum according to +/// data sheet, but seems to work fine. +pub const OVERCLOCK_CLOCK_DIVIDER: FixedU32 = FixedU32::from_bits(0x0100); + +/// The clock divider for the RM2 module. Found to be needed for the Pimoroni Pico Plus 2 W, +/// Pico Plus 2 Non w with the RM2 breakout module, and the Pico 2 with the RM2 breakout module. +/// Does not work with the feature "overclock". +pub const RM2_CLOCK_DIVIDER: FixedU32 = FixedU32::from_bits(0x0300); + impl<'d, PIO, const SM: usize, DMA> PioSpi<'d, PIO, SM, DMA> where DMA: Channel, @@ -31,6 +52,7 @@ where pub fn new( common: &mut Common<'d, PIO>, mut sm: StateMachine<'d, PIO, SM>, + clock_divider: FixedU32, irq: Irq<'d, PIO, 0>, cs: Output<'d>, dio: DIO, @@ -112,31 +134,7 @@ where cfg.shift_in.direction = ShiftDirection::Left; cfg.shift_in.auto_fill = true; //cfg.shift_in.threshold = 32; - - #[cfg(feature = "overclock")] - { - // 125mhz Pio => 62.5Mhz SPI Freq. 25% higher than theoretical maximum according to - // data sheet, but seems to work fine. - cfg.clock_divider = FixedU32::from_bits(0x0100); - } - - #[cfg(not(any(feature = "overclock", feature = "rm2")))] - { - // same speed as pico-sdk, 62.5Mhz - // This is actually the fastest we can go without overclocking. - // According to data sheet, the theoretical maximum is 100Mhz Pio => 50Mhz SPI Freq. - // However, the PIO uses a fractional divider, which works by introducing jitter when - // the divider is not an integer. It does some clocks at 125mhz and others at 62.5mhz - // so that it averages out to the desired frequency of 100mhz. The 125mhz clock cycles - // violate the maximum from the data sheet. - cfg.clock_divider = FixedU32::from_bits(0x0200); - } - - #[cfg(feature = "rm2")] - { - // This is found to work better with the RM2 module which is found on the Pimoroni Pico Plus 2 W - cfg.clock_divider = FixedU32::from_bits(0x0300); - } + cfg.clock_divider = clock_divider; sm.set_config(&cfg); From 8243a8a3892dc499be560a0bf2134e641b856760 Mon Sep 17 00:00:00 2001 From: Bailey Townsend Date: Sat, 28 Dec 2024 00:07:14 -0600 Subject: [PATCH 0547/1217] Added new param to examples and created a pico plus 2 w example --- examples/rp/src/bin/wifi_ap_tcp_server.rs | 13 ++- examples/rp/src/bin/wifi_blinky.rs | 13 ++- examples/rp/src/bin/wifi_scan.rs | 13 ++- examples/rp/src/bin/wifi_tcp_server.rs | 13 ++- examples/rp/src/bin/wifi_webrequest.rs | 13 ++- .../rp23/src/bin/wifi_blinky_pico_plus_2.rs | 94 +++++++++++++++++++ 6 files changed, 149 insertions(+), 10 deletions(-) create mode 100644 examples/rp23/src/bin/wifi_blinky_pico_plus_2.rs diff --git a/examples/rp/src/bin/wifi_ap_tcp_server.rs b/examples/rp/src/bin/wifi_ap_tcp_server.rs index 4c9651433..e97ddb4c1 100644 --- a/examples/rp/src/bin/wifi_ap_tcp_server.rs +++ b/examples/rp/src/bin/wifi_ap_tcp_server.rs @@ -7,7 +7,7 @@ use core::str::from_utf8; -use cyw43_pio::PioSpi; +use cyw43_pio::{PioSpi, DEFAULT_CLOCK_DIVIDER}; use defmt::*; use embassy_executor::Spawner; use embassy_net::tcp::TcpSocket; @@ -57,7 +57,16 @@ async fn main(spawner: Spawner) { let pwr = Output::new(p.PIN_23, Level::Low); let cs = Output::new(p.PIN_25, Level::High); let mut pio = Pio::new(p.PIO0, Irqs); - let spi = PioSpi::new(&mut pio.common, pio.sm0, pio.irq0, cs, p.PIN_24, p.PIN_29, p.DMA_CH0); + let spi = PioSpi::new( + &mut pio.common, + pio.sm0, + DEFAULT_CLOCK_DIVIDER, + pio.irq0, + cs, + p.PIN_24, + p.PIN_29, + p.DMA_CH0, + ); static STATE: StaticCell = StaticCell::new(); let state = STATE.init(cyw43::State::new()); diff --git a/examples/rp/src/bin/wifi_blinky.rs b/examples/rp/src/bin/wifi_blinky.rs index 0107a2326..6e91ce167 100644 --- a/examples/rp/src/bin/wifi_blinky.rs +++ b/examples/rp/src/bin/wifi_blinky.rs @@ -5,7 +5,7 @@ #![no_std] #![no_main] -use cyw43_pio::PioSpi; +use cyw43_pio::{PioSpi, DEFAULT_CLOCK_DIVIDER}; use defmt::*; use embassy_executor::Spawner; use embassy_rp::bind_interrupts; @@ -41,7 +41,16 @@ async fn main(spawner: Spawner) { let pwr = Output::new(p.PIN_23, Level::Low); let cs = Output::new(p.PIN_25, Level::High); let mut pio = Pio::new(p.PIO0, Irqs); - let spi = PioSpi::new(&mut pio.common, pio.sm0, pio.irq0, cs, p.PIN_24, p.PIN_29, p.DMA_CH0); + let spi = PioSpi::new( + &mut pio.common, + pio.sm0, + DEFAULT_CLOCK_DIVIDER, + pio.irq0, + cs, + p.PIN_24, + p.PIN_29, + p.DMA_CH0, + ); static STATE: StaticCell = StaticCell::new(); let state = STATE.init(cyw43::State::new()); diff --git a/examples/rp/src/bin/wifi_scan.rs b/examples/rp/src/bin/wifi_scan.rs index 2ef899080..fe9c363d9 100644 --- a/examples/rp/src/bin/wifi_scan.rs +++ b/examples/rp/src/bin/wifi_scan.rs @@ -7,7 +7,7 @@ use core::str; -use cyw43_pio::PioSpi; +use cyw43_pio::{PioSpi, DEFAULT_CLOCK_DIVIDER}; use defmt::*; use embassy_executor::Spawner; use embassy_rp::bind_interrupts; @@ -45,7 +45,16 @@ async fn main(spawner: Spawner) { let pwr = Output::new(p.PIN_23, Level::Low); let cs = Output::new(p.PIN_25, Level::High); let mut pio = Pio::new(p.PIO0, Irqs); - let spi = PioSpi::new(&mut pio.common, pio.sm0, pio.irq0, cs, p.PIN_24, p.PIN_29, p.DMA_CH0); + let spi = PioSpi::new( + &mut pio.common, + pio.sm0, + DEFAULT_CLOCK_DIVIDER, + pio.irq0, + cs, + p.PIN_24, + p.PIN_29, + p.DMA_CH0, + ); static STATE: StaticCell = StaticCell::new(); let state = STATE.init(cyw43::State::new()); diff --git a/examples/rp/src/bin/wifi_tcp_server.rs b/examples/rp/src/bin/wifi_tcp_server.rs index 7bf546e01..14dbf4552 100644 --- a/examples/rp/src/bin/wifi_tcp_server.rs +++ b/examples/rp/src/bin/wifi_tcp_server.rs @@ -8,7 +8,7 @@ use core::str::from_utf8; use cyw43::JoinOptions; -use cyw43_pio::PioSpi; +use cyw43_pio::{PioSpi, DEFAULT_CLOCK_DIVIDER}; use defmt::*; use embassy_executor::Spawner; use embassy_net::tcp::TcpSocket; @@ -61,7 +61,16 @@ async fn main(spawner: Spawner) { let pwr = Output::new(p.PIN_23, Level::Low); let cs = Output::new(p.PIN_25, Level::High); let mut pio = Pio::new(p.PIO0, Irqs); - let spi = PioSpi::new(&mut pio.common, pio.sm0, pio.irq0, cs, p.PIN_24, p.PIN_29, p.DMA_CH0); + let spi = PioSpi::new( + &mut pio.common, + pio.sm0, + DEFAULT_CLOCK_DIVIDER, + pio.irq0, + cs, + p.PIN_24, + p.PIN_29, + p.DMA_CH0, + ); static STATE: StaticCell = StaticCell::new(); let state = STATE.init(cyw43::State::new()); diff --git a/examples/rp/src/bin/wifi_webrequest.rs b/examples/rp/src/bin/wifi_webrequest.rs index 1ae909917..f1b398b65 100644 --- a/examples/rp/src/bin/wifi_webrequest.rs +++ b/examples/rp/src/bin/wifi_webrequest.rs @@ -8,7 +8,7 @@ use core::str::from_utf8; use cyw43::JoinOptions; -use cyw43_pio::PioSpi; +use cyw43_pio::{PioSpi, DEFAULT_CLOCK_DIVIDER}; use defmt::*; use embassy_executor::Spawner; use embassy_net::dns::DnsSocket; @@ -63,7 +63,16 @@ async fn main(spawner: Spawner) { let pwr = Output::new(p.PIN_23, Level::Low); let cs = Output::new(p.PIN_25, Level::High); let mut pio = Pio::new(p.PIO0, Irqs); - let spi = PioSpi::new(&mut pio.common, pio.sm0, pio.irq0, cs, p.PIN_24, p.PIN_29, p.DMA_CH0); + let spi = PioSpi::new( + &mut pio.common, + pio.sm0, + DEFAULT_CLOCK_DIVIDER, + pio.irq0, + cs, + p.PIN_24, + p.PIN_29, + p.DMA_CH0, + ); static STATE: StaticCell = StaticCell::new(); let state = STATE.init(cyw43::State::new()); diff --git a/examples/rp23/src/bin/wifi_blinky_pico_plus_2.rs b/examples/rp23/src/bin/wifi_blinky_pico_plus_2.rs new file mode 100644 index 000000000..240588762 --- /dev/null +++ b/examples/rp23/src/bin/wifi_blinky_pico_plus_2.rs @@ -0,0 +1,94 @@ +//! This example test the Pimoroni Pico Plus 2 on board LED. +//! +//! It does not work with the RP Pico board. See blinky.rs. + +#![no_std] +#![no_main] + +use cyw43_pio::{PioSpi, RM2_CLOCK_DIVIDER}; +use defmt::*; +use embassy_executor::Spawner; +use embassy_rp::block::ImageDef; +use embassy_rp::gpio; +use embassy_rp::peripherals::{DMA_CH0, PIO0}; +use embassy_rp::pio::Pio; +use embassy_rp::{bind_interrupts, pio::InterruptHandler}; +use embassy_time::{Duration, Timer}; +use gpio::{Level, Output}; +use static_cell::StaticCell; +use {defmt_rtt as _, panic_probe as _}; + +#[link_section = ".start_block"] +#[used] +pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); + +// Program metadata for `picotool info`. +// This isn't needed, but it's recomended to have these minimal entries. +#[link_section = ".bi_entries"] +#[used] +pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ + embassy_rp::binary_info::rp_program_name!(c"Blinky Example"), + embassy_rp::binary_info::rp_program_description!( + c"This example tests the RP Pico on board LED, connected to gpio 25" + ), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_build_attribute!(), +]; + +bind_interrupts!(struct Irqs { + PIO0_IRQ_0 => InterruptHandler; +}); + +#[embassy_executor::task] +async fn cyw43_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>) -> ! { + runner.run().await +} + +#[embassy_executor::main] +async fn main(spawner: Spawner) { + let p = embassy_rp::init(Default::default()); + let fw = include_bytes!("../../../../cyw43-firmware/43439A0.bin"); + let clm = include_bytes!("../../../../cyw43-firmware/43439A0_clm.bin"); + + // To make flashing faster for development, you may want to flash the firmwares independently + // at hardcoded addresses, instead of baking them into the program with `include_bytes!`: + // probe-rs download ../../cyw43-firmware/43439A0.bin --binary-format bin --chip RP2040 --base-address 0x10100000 + // probe-rs download ../../cyw43-firmware/43439A0_clm.bin --binary-format bin --chip RP2040 --base-address 0x10140000 + //let fw = unsafe { core::slice::from_raw_parts(0x10100000 as *const u8, 230321) }; + //let clm = unsafe { core::slice::from_raw_parts(0x10140000 as *const u8, 4752) }; + + let pwr = Output::new(p.PIN_23, Level::Low); + let cs = Output::new(p.PIN_25, Level::High); + let mut pio = Pio::new(p.PIO0, Irqs); + let spi = PioSpi::new( + &mut pio.common, + pio.sm0, + RM2_CLOCK_DIVIDER, + pio.irq0, + cs, + p.PIN_24, + p.PIN_29, + p.DMA_CH0, + ); + + static STATE: StaticCell = StaticCell::new(); + let state = STATE.init(cyw43::State::new()); + let (_net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await; + unwrap!(spawner.spawn(cyw43_task(runner))); + + control.init(clm).await; + control + .set_power_management(cyw43::PowerManagementMode::PowerSave) + .await; + + let delay = Duration::from_secs(1); + loop { + info!("led on!"); + control.gpio_set(0, true).await; + Timer::after(delay).await; + + info!("led off!"); + control.gpio_set(0, false).await; + Timer::after(delay).await; + } +} From 388103275e8648492e27514e00048492a55a931c Mon Sep 17 00:00:00 2001 From: Bailey Townsend Date: Sat, 28 Dec 2024 00:40:52 -0600 Subject: [PATCH 0548/1217] Fixes ci (hopefully) --- examples/rp23/src/bin/wifi_blinky_pico_plus_2.rs | 5 ++--- tests/rp/src/bin/cyw43-perf.rs | 13 +++++++++++-- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/examples/rp23/src/bin/wifi_blinky_pico_plus_2.rs b/examples/rp23/src/bin/wifi_blinky_pico_plus_2.rs index 240588762..ebb3c4373 100644 --- a/examples/rp23/src/bin/wifi_blinky_pico_plus_2.rs +++ b/examples/rp23/src/bin/wifi_blinky_pico_plus_2.rs @@ -9,10 +9,9 @@ use cyw43_pio::{PioSpi, RM2_CLOCK_DIVIDER}; use defmt::*; use embassy_executor::Spawner; use embassy_rp::block::ImageDef; -use embassy_rp::gpio; use embassy_rp::peripherals::{DMA_CH0, PIO0}; -use embassy_rp::pio::Pio; -use embassy_rp::{bind_interrupts, pio::InterruptHandler}; +use embassy_rp::pio::{InterruptHandler, Pio}; +use embassy_rp::{bind_interrupts, gpio}; use embassy_time::{Duration, Timer}; use gpio::{Level, Output}; use static_cell::StaticCell; diff --git a/tests/rp/src/bin/cyw43-perf.rs b/tests/rp/src/bin/cyw43-perf.rs index 30e4afb07..34119722b 100644 --- a/tests/rp/src/bin/cyw43-perf.rs +++ b/tests/rp/src/bin/cyw43-perf.rs @@ -3,7 +3,7 @@ teleprobe_meta::target!(b"rpi-pico"); use cyw43::JoinOptions; -use cyw43_pio::PioSpi; +use cyw43_pio::{PioSpi, DEFAULT_CLOCK_DIVIDER}; use defmt::{panic, *}; use embassy_executor::Spawner; use embassy_net::{Config, StackResources}; @@ -54,7 +54,16 @@ async fn main(spawner: Spawner) { let pwr = Output::new(p.PIN_23, Level::Low); let cs = Output::new(p.PIN_25, Level::High); let mut pio = Pio::new(p.PIO0, Irqs); - let spi = PioSpi::new(&mut pio.common, pio.sm0, pio.irq0, cs, p.PIN_24, p.PIN_29, p.DMA_CH0); + let spi = PioSpi::new( + &mut pio.common, + pio.sm0, + DEFAULT_CLOCK_DIVIDER, + pio.irq0, + cs, + p.PIN_24, + p.PIN_29, + p.DMA_CH0, + ); static STATE: StaticCell = StaticCell::new(); let state = STATE.init(cyw43::State::new()); From adf3134e7d722d4c400e09715b3a49a7ffd45edb Mon Sep 17 00:00:00 2001 From: 9names <60134748+9names@users.noreply.github.com> Date: Sat, 28 Dec 2024 23:41:36 +1100 Subject: [PATCH 0549/1217] embassy-usb: fix building with optional log feature --- embassy-usb/src/class/uac1/speaker.rs | 2 +- embassy-usb/src/types.rs | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/embassy-usb/src/class/uac1/speaker.rs b/embassy-usb/src/class/uac1/speaker.rs index 96456d94a..6c3a4e378 100644 --- a/embassy-usb/src/class/uac1/speaker.rs +++ b/embassy-usb/src/class/uac1/speaker.rs @@ -579,7 +579,7 @@ impl<'d> Control<'d> { if endpoint_address != self.streaming_endpoint_address { debug!( - "Unhandled endpoint set request for endpoint {} and control {} with data {}", + "Unhandled endpoint set request for endpoint {} and control {} with data {:?}", endpoint_address, control_selector, data ); return None; diff --git a/embassy-usb/src/types.rs b/embassy-usb/src/types.rs index cb9fe2576..ea6347c7d 100644 --- a/embassy-usb/src/types.rs +++ b/embassy-usb/src/types.rs @@ -18,6 +18,12 @@ impl From for u8 { } } +impl core::fmt::Display for InterfaceNumber { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + write!(f, "{}", self.0) + } +} + /// A handle for a USB string descriptor that contains its index. #[derive(Copy, Clone, Eq, PartialEq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] From 147fd60255a94292a2e0e685c0cad068cc7760e7 Mon Sep 17 00:00:00 2001 From: Bailey Townsend Date: Sat, 28 Dec 2024 17:31:14 -0600 Subject: [PATCH 0550/1217] Removed the cyw43-pio overclock feature --- ci.sh | 2 +- cyw43-pio/Cargo.toml | 5 --- cyw43-pio/src/lib.rs | 87 ++++++++++++++++++++++---------------------- tests/rp/Cargo.toml | 2 +- 4 files changed, 46 insertions(+), 50 deletions(-) diff --git a/ci.sh b/ci.sh index e7f1504aa..2bfe082cf 100755 --- a/ci.sh +++ b/ci.sh @@ -178,7 +178,7 @@ cargo batch \ --- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'log,firmware-logs,bluetooth' \ --- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'defmt,firmware-logs,bluetooth' \ --- build --release --manifest-path cyw43-pio/Cargo.toml --target thumbv6m-none-eabi --features 'embassy-rp/rp2040' \ - --- build --release --manifest-path cyw43-pio/Cargo.toml --target thumbv6m-none-eabi --features 'embassy-rp/rp2040,overclock' \ + --- build --release --manifest-path cyw43-pio/Cargo.toml --target thumbv6m-none-eabi --features 'embassy-rp/rp2040' \ --- build --release --manifest-path embassy-boot-nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840 \ --- build --release --manifest-path embassy-boot-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9160-ns \ --- build --release --manifest-path embassy-boot-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9120-ns \ diff --git a/cyw43-pio/Cargo.toml b/cyw43-pio/Cargo.toml index 4e21c255f..e400d95ea 100644 --- a/cyw43-pio/Cargo.toml +++ b/cyw43-pio/Cargo.toml @@ -9,11 +9,6 @@ license = "MIT OR Apache-2.0" repository = "https://github.com/embassy-rs/embassy" documentation = "https://docs.embassy.dev/cyw43-pio" -[features] -# If disabled, SPI runs at 31.25MHz -# If enabled, SPI runs at 62.5MHz, which is 25% higher than 50Mhz which is the maximum according to the CYW43439 datasheet. -overclock = [] - [dependencies] cyw43 = { version = "0.2.0", path = "../cyw43" } embassy-rp = { version = "0.2.0", path = "../embassy-rp" } diff --git a/cyw43-pio/src/lib.rs b/cyw43-pio/src/lib.rs index abf3830d9..5fe7af95d 100644 --- a/cyw43-pio/src/lib.rs +++ b/cyw43-pio/src/lib.rs @@ -40,7 +40,6 @@ pub const OVERCLOCK_CLOCK_DIVIDER: FixedU32 = FixedU32::from_bits(0x0100); /// The clock divider for the RM2 module. Found to be needed for the Pimoroni Pico Plus 2 W, /// Pico Plus 2 Non w with the RM2 breakout module, and the Pico 2 with the RM2 breakout module. -/// Does not work with the feature "overclock". pub const RM2_CLOCK_DIVIDER: FixedU32 = FixedU32::from_bits(0x0300); impl<'d, PIO, const SM: usize, DMA> PioSpi<'d, PIO, SM, DMA> @@ -63,53 +62,56 @@ where DIO: PioPin, CLK: PioPin, { - #[cfg(feature = "overclock")] - let program = pio_asm!( - ".side_set 1" + let loaded_program = if clock_divider < DEFAULT_CLOCK_DIVIDER { + let overclock_program = pio_asm!( + ".side_set 1" - ".wrap_target" - // write out x-1 bits - "lp:" - "out pins, 1 side 0" - "jmp x-- lp side 1" - // switch directions - "set pindirs, 0 side 0" - "nop side 1" // necessary for clkdiv=1. - "nop side 0" - // read in y-1 bits - "lp2:" - "in pins, 1 side 1" - "jmp y-- lp2 side 0" + ".wrap_target" + // write out x-1 bits + "lp:" + "out pins, 1 side 0" + "jmp x-- lp side 1" + // switch directions + "set pindirs, 0 side 0" + "nop side 1" // necessary for clkdiv=1. + "nop side 0" + // read in y-1 bits + "lp2:" + "in pins, 1 side 1" + "jmp y-- lp2 side 0" - // wait for event and irq host - "wait 1 pin 0 side 0" - "irq 0 side 0" + // wait for event and irq host + "wait 1 pin 0 side 0" + "irq 0 side 0" - ".wrap" - ); - #[cfg(not(feature = "overclock"))] - let program = pio_asm!( - ".side_set 1" + ".wrap" + ); + common.load_program(&overclock_program.program) + } else { + let default_program = pio_asm!( + ".side_set 1" - ".wrap_target" - // write out x-1 bits - "lp:" - "out pins, 1 side 0" - "jmp x-- lp side 1" - // switch directions - "set pindirs, 0 side 0" - "nop side 0" - // read in y-1 bits - "lp2:" - "in pins, 1 side 1" - "jmp y-- lp2 side 0" + ".wrap_target" + // write out x-1 bits + "lp:" + "out pins, 1 side 0" + "jmp x-- lp side 1" + // switch directions + "set pindirs, 0 side 0" + "nop side 0" + // read in y-1 bits + "lp2:" + "in pins, 1 side 1" + "jmp y-- lp2 side 0" - // wait for event and irq host - "wait 1 pin 0 side 0" - "irq 0 side 0" + // wait for event and irq host + "wait 1 pin 0 side 0" + "irq 0 side 0" - ".wrap" - ); + ".wrap" + ); + common.load_program(&default_program.program) + }; let mut pin_io: embassy_rp::pio::Pin = common.make_pio_pin(dio); pin_io.set_pull(Pull::None); @@ -123,7 +125,6 @@ where pin_clk.set_slew_rate(SlewRate::Fast); let mut cfg = Config::default(); - let loaded_program = common.load_program(&program.program); cfg.use_program(&loaded_program, &[&pin_clk]); cfg.set_out_pins(&[&pin_io]); cfg.set_in_pins(&[&pin_io]); diff --git a/tests/rp/Cargo.toml b/tests/rp/Cargo.toml index d5aabc6ac..842cdf51d 100644 --- a/tests/rp/Cargo.toml +++ b/tests/rp/Cargo.toml @@ -16,7 +16,7 @@ embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defm embassy-net-wiznet = { version = "0.1.0", path = "../../embassy-net-wiznet", features = ["defmt"] } embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal/"} cyw43 = { path = "../../cyw43", features = ["defmt", "firmware-logs"] } -cyw43-pio = { path = "../../cyw43-pio", features = ["defmt", "overclock"] } +cyw43-pio = { path = "../../cyw43-pio", features = ["defmt"] } perf-client = { path = "../perf-client" } defmt = "0.3.0" From 2c5ae2e0117f44bb19714417a3edc8656271f3bf Mon Sep 17 00:00:00 2001 From: 9names <60134748+9names@users.noreply.github.com> Date: Sun, 29 Dec 2024 10:54:51 +1100 Subject: [PATCH 0551/1217] ci: add embassy-usb to build tests --- ci.sh | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/ci.sh b/ci.sh index e7f1504aa..b6a950bdb 100755 --- a/ci.sh +++ b/ci.sh @@ -186,6 +186,15 @@ cargo batch \ --- build --release --manifest-path embassy-boot-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9161-ns \ --- build --release --manifest-path embassy-boot-rp/Cargo.toml --target thumbv6m-none-eabi --features embassy-rp/rp2040 \ --- build --release --manifest-path embassy-boot-stm32/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32l496zg \ + --- build --release --manifest-path embassy-usb/Cargo.toml --target thumbv6m-none-eabi --no-default-features \ + --- build --release --manifest-path embassy-usb/Cargo.toml --target thumbv6m-none-eabi \ + --- build --release --manifest-path embassy-usb/Cargo.toml --target thumbv6m-none-eabi --features log \ + --- build --release --manifest-path embassy-usb/Cargo.toml --target thumbv6m-none-eabi --features defmt \ + --- build --release --manifest-path embassy-usb/Cargo.toml --target thumbv6m-none-eabi --features usbd-hid \ + --- build --release --manifest-path embassy-usb/Cargo.toml --target thumbv6m-none-eabi --features max-interface-count-1 \ + --- build --release --manifest-path embassy-usb/Cargo.toml --target thumbv6m-none-eabi --features max-interface-count-8 \ + --- build --release --manifest-path embassy-usb/Cargo.toml --target thumbv6m-none-eabi --features max-handler-count-8 \ + --- build --release --manifest-path embassy-usb/Cargo.toml --target thumbv6m-none-eabi --features max-handler-count-8 \ --- build --release --manifest-path docs/examples/basic/Cargo.toml --target thumbv7em-none-eabi \ --- build --release --manifest-path docs/examples/layer-by-layer/blinky-pac/Cargo.toml --target thumbv7em-none-eabi \ --- build --release --manifest-path docs/examples/layer-by-layer/blinky-hal/Cargo.toml --target thumbv7em-none-eabi \ From 10def24e7251de1cd915feb760c545870a329abe Mon Sep 17 00:00:00 2001 From: Paul Sbarra Date: Sun, 29 Dec 2024 23:33:18 -0600 Subject: [PATCH 0552/1217] fix embassy-time-driver example --- embassy-time-driver/Cargo.toml | 4 ++++ embassy-time-driver/src/lib.rs | 9 +++++---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/embassy-time-driver/Cargo.toml b/embassy-time-driver/Cargo.toml index 2a1d5ee1d..b709cafc1 100644 --- a/embassy-time-driver/Cargo.toml +++ b/embassy-time-driver/Cargo.toml @@ -368,3 +368,7 @@ tick-hz-5_242_880_000 = [] [dependencies] document-features = "0.2.7" + +[dev-dependencies] +critical-section = "1" +embassy-time-queue-utils = { path = "../embassy-time-queue-utils" } \ No newline at end of file diff --git a/embassy-time-driver/src/lib.rs b/embassy-time-driver/src/lib.rs index b77683a52..f198a3ead 100644 --- a/embassy-time-driver/src/lib.rs +++ b/embassy-time-driver/src/lib.rs @@ -49,15 +49,16 @@ //! Note that if you are using multiple queues, you will need to ensure that a single timer //! queue item is only ever enqueued into a single queue at a time. //! -//! ```ignore +//! ``` //! use core::cell::RefCell; //! use core::task::Waker; //! +//! use critical_section::{CriticalSection, Mutex}; //! use embassy_time_queue_utils::Queue; //! use embassy_time_driver::Driver; //! //! struct MyDriver { -//! timer_queue: critical_section::Mutex>, +//! queue: Mutex>, //! } //! //! impl MyDriver { @@ -67,14 +68,14 @@ //! } //! //! impl Driver for MyDriver { -//! // fn now(&self) -> u64 { ... } +//! fn now(&self) -> u64 { todo!() } //! //! fn schedule_wake(&self, at: u64, waker: &Waker) { //! critical_section::with(|cs| { //! let mut queue = self.queue.borrow(cs).borrow_mut(); //! if queue.schedule_wake(at, waker) { //! let mut next = queue.next_expiration(self.now()); -//! while !self.set_alarm(cs, next) { +//! while !self.set_alarm(&cs, next) { //! next = queue.next_expiration(self.now()); //! } //! } From 44217aa0924e7590aa0afabdf17babd5c2ea5b82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Mon, 30 Dec 2024 12:13:13 +0100 Subject: [PATCH 0553/1217] Desugar some async fns --- cyw43/src/ioctl.rs | 14 +++---- embassy-executor/src/spawner.rs | 8 ++-- embassy-net-esp-hosted/src/ioctl.rs | 8 ++-- embassy-net-nrf91/src/lib.rs | 5 +-- embassy-net/src/raw.rs | 19 +++++----- embassy-net/src/tcp.rs | 53 +++++++++++++-------------- embassy-net/src/udp.rs | 22 ++++++----- embassy-nrf/src/buffered_uarte.rs | 11 ++---- embassy-nrf/src/qspi.rs | 5 +-- embassy-nrf/src/usb/mod.rs | 14 +++---- embassy-nrf/src/usb/vbus_detect.rs | 10 ++--- embassy-rp/src/adc.rs | 8 ++-- embassy-sync/src/mutex.rs | 5 +-- embassy-sync/src/once_lock.rs | 5 +-- embassy-sync/src/watch.rs | 6 +-- embassy-sync/src/zerocopy_channel.rs | 24 ++++++------ embassy-usb/src/class/cdc_acm.rs | 5 +-- embassy-usb/src/class/uac1/speaker.rs | 5 +-- 18 files changed, 103 insertions(+), 124 deletions(-) diff --git a/cyw43/src/ioctl.rs b/cyw43/src/ioctl.rs index f8b2d9aba..af8bb695b 100644 --- a/cyw43/src/ioctl.rs +++ b/cyw43/src/ioctl.rs @@ -1,5 +1,5 @@ use core::cell::{Cell, RefCell}; -use core::future::poll_fn; +use core::future::{poll_fn, Future}; use core::task::{Poll, Waker}; use embassy_sync::waitqueue::WakerRegistration; @@ -71,7 +71,7 @@ impl IoctlState { self.wakers.borrow_mut().runner.register(waker); } - pub async fn wait_complete(&self) -> usize { + pub fn wait_complete(&self) -> impl Future + '_ { poll_fn(|cx| { if let IoctlStateInner::Done { resp_len } = self.state.get() { Poll::Ready(resp_len) @@ -80,22 +80,18 @@ impl IoctlState { Poll::Pending } }) - .await } - pub async fn wait_pending(&self) -> PendingIoctl { - let pending = poll_fn(|cx| { + pub fn wait_pending(&self) -> impl Future + '_ { + poll_fn(|cx| { if let IoctlStateInner::Pending(pending) = self.state.get() { + self.state.set(IoctlStateInner::Sent { buf: pending.buf }); Poll::Ready(pending) } else { self.register_runner(cx.waker()); Poll::Pending } }) - .await; - - self.state.set(IoctlStateInner::Sent { buf: pending.buf }); - pending } pub fn cancel_ioctl(&self) { diff --git a/embassy-executor/src/spawner.rs b/embassy-executor/src/spawner.rs index 41320d4c3..ce24589bf 100644 --- a/embassy-executor/src/spawner.rs +++ b/embassy-executor/src/spawner.rs @@ -1,4 +1,4 @@ -use core::future::poll_fn; +use core::future::{poll_fn, Future}; use core::marker::PhantomData; use core::mem; use core::sync::atomic::Ordering; @@ -100,7 +100,7 @@ impl Spawner { /// # Panics /// /// Panics if the current executor is not an Embassy executor. - pub async fn for_current_executor() -> Self { + pub fn for_current_executor() -> impl Future { poll_fn(|cx| { let task = raw::task_from_waker(cx.waker()); let executor = unsafe { @@ -113,7 +113,6 @@ impl Spawner { let executor = unsafe { raw::Executor::wrap(executor) }; Poll::Ready(Self::new(executor)) }) - .await } /// Spawn a task into an executor. @@ -178,7 +177,7 @@ impl SendSpawner { /// # Panics /// /// Panics if the current executor is not an Embassy executor. - pub async fn for_current_executor() -> Self { + pub fn for_current_executor() -> impl Future { poll_fn(|cx| { let task = raw::task_from_waker(cx.waker()); let executor = unsafe { @@ -190,7 +189,6 @@ impl SendSpawner { }; Poll::Ready(Self::new(executor)) }) - .await } /// Spawn a task into an executor. diff --git a/embassy-net-esp-hosted/src/ioctl.rs b/embassy-net-esp-hosted/src/ioctl.rs index e2a6815aa..512023206 100644 --- a/embassy-net-esp-hosted/src/ioctl.rs +++ b/embassy-net-esp-hosted/src/ioctl.rs @@ -1,5 +1,5 @@ use core::cell::RefCell; -use core::future::poll_fn; +use core::future::{poll_fn, Future}; use core::task::Poll; use embassy_sync::waitqueue::WakerRegistration; @@ -38,7 +38,7 @@ impl Shared { })) } - pub async fn ioctl_wait_complete(&self) -> usize { + pub fn ioctl_wait_complete(&self) -> impl Future + '_ { poll_fn(|cx| { let mut this = self.0.borrow_mut(); if let IoctlState::Done { resp_len } = this.ioctl { @@ -48,7 +48,6 @@ impl Shared { Poll::Pending } }) - .await } pub async fn ioctl_wait_pending(&self) -> PendingIoctl { @@ -108,7 +107,7 @@ impl Shared { this.control_waker.wake(); } - pub async fn init_wait(&self) { + pub fn init_wait(&self) -> impl Future + '_ { poll_fn(|cx| { let mut this = self.0.borrow_mut(); if this.is_init { @@ -118,6 +117,5 @@ impl Shared { Poll::Pending } }) - .await } } diff --git a/embassy-net-nrf91/src/lib.rs b/embassy-net-nrf91/src/lib.rs index 3abe2c766..61fcaea1f 100644 --- a/embassy-net-nrf91/src/lib.rs +++ b/embassy-net-nrf91/src/lib.rs @@ -9,7 +9,7 @@ mod fmt; pub mod context; use core::cell::RefCell; -use core::future::poll_fn; +use core::future::{poll_fn, Future}; use core::marker::PhantomData; use core::mem::{self, MaybeUninit}; use core::ptr::{self, addr_of, addr_of_mut, copy_nonoverlapping}; @@ -737,7 +737,7 @@ pub struct Control<'a> { impl<'a> Control<'a> { /// Wait for modem IPC to be initialized. - pub async fn wait_init(&self) { + pub fn wait_init(&self) -> impl Future + '_ { poll_fn(|cx| { let mut state = self.state.borrow_mut(); if state.init { @@ -746,7 +746,6 @@ impl<'a> Control<'a> { state.init_waker.register(cx.waker()); Poll::Pending }) - .await } async fn request(&self, msg: &mut Message, req_data: &[u8], resp_data: &mut [u8]) -> usize { diff --git a/embassy-net/src/raw.rs b/embassy-net/src/raw.rs index a88bcc458..c9f753f13 100644 --- a/embassy-net/src/raw.rs +++ b/embassy-net/src/raw.rs @@ -1,6 +1,6 @@ //! Raw sockets. -use core::future::poll_fn; +use core::future::{poll_fn, Future}; use core::mem; use core::task::{Context, Poll}; @@ -66,8 +66,8 @@ impl<'a> RawSocket<'a> { /// /// A socket is readable when a packet has been received, or when there are queued packets in /// the buffer. - pub async fn wait_recv_ready(&self) { - poll_fn(move |cx| self.poll_recv_ready(cx)).await + pub fn wait_recv_ready(&self) -> impl Future + '_ { + poll_fn(move |cx| self.poll_recv_ready(cx)) } /// Receive a datagram. @@ -115,8 +115,8 @@ impl<'a> RawSocket<'a> { /// /// A socket becomes writable when there is space in the buffer, from initial memory or after /// dispatching datagrams on a full buffer. - pub async fn wait_send_ready(&self) { - poll_fn(move |cx| self.poll_send_ready(cx)).await + pub fn wait_send_ready(&self) -> impl Future + '_ { + poll_fn(move |cx| self.poll_send_ready(cx)) } /// Wait until a datagram can be sent. @@ -141,8 +141,8 @@ impl<'a> RawSocket<'a> { /// Send a datagram. /// /// This method will wait until the datagram has been sent.` - pub async fn send(&self, buf: &[u8]) { - poll_fn(move |cx| self.poll_send(buf, cx)).await + pub fn send<'s>(&'s self, buf: &'s [u8]) -> impl Future + 's { + poll_fn(|cx| self.poll_send(buf, cx)) } /// Send a datagram. @@ -165,8 +165,8 @@ impl<'a> RawSocket<'a> { /// Flush the socket. /// /// This method will wait until the socket is flushed. - pub async fn flush(&mut self) { - poll_fn(move |cx| { + pub fn flush(&mut self) -> impl Future + '_ { + poll_fn(|cx| { self.with_mut(|s, _| { if s.send_queue() == 0 { Poll::Ready(()) @@ -176,7 +176,6 @@ impl<'a> RawSocket<'a> { } }) }) - .await } } diff --git a/embassy-net/src/tcp.rs b/embassy-net/src/tcp.rs index 32d374064..d0230b581 100644 --- a/embassy-net/src/tcp.rs +++ b/embassy-net/src/tcp.rs @@ -8,7 +8,7 @@ //! Incoming connections when no socket is listening are rejected. To accept many incoming //! connections, create many sockets and put them all into listening mode. -use core::future::poll_fn; +use core::future::{poll_fn, Future}; use core::mem; use core::task::{Context, Poll}; @@ -79,8 +79,8 @@ impl<'a> TcpReader<'a> { /// (see [`may_recv()`](TcpSocket::may_recv)), and there is some pending data in the receive buffer. /// /// This is the equivalent of [read](#method.read), without buffering any data. - pub async fn wait_read_ready(&self) { - poll_fn(move |cx| self.io.poll_read_ready(cx)).await + pub fn wait_read_ready(&self) -> impl Future + '_ { + poll_fn(move |cx| self.io.poll_read_ready(cx)) } /// Read data from the socket. @@ -131,24 +131,24 @@ impl<'a> TcpWriter<'a> { /// (see [`may_send()`](TcpSocket::may_send)), and the transmit buffer is not full. /// /// This is the equivalent of [write](#method.write), without sending any data. - pub async fn wait_write_ready(&self) { - poll_fn(move |cx| self.io.poll_write_ready(cx)).await + pub fn wait_write_ready(&self) -> impl Future + '_ { + poll_fn(move |cx| self.io.poll_write_ready(cx)) } /// Write data to the socket. /// /// Returns how many bytes were written, or an error. If the socket is not ready to /// accept data, it waits until it is. - pub async fn write(&mut self, buf: &[u8]) -> Result { - self.io.write(buf).await + pub fn write<'s>(&'s mut self, buf: &'s [u8]) -> impl Future> + 's { + self.io.write(buf) } /// Flushes the written data to the socket. /// /// This waits until all data has been sent, and ACKed by the remote host. For a connection /// closed with [`abort()`](TcpSocket::abort) it will wait for the TCP RST packet to be sent. - pub async fn flush(&mut self) -> Result<(), Error> { - self.io.flush().await + pub fn flush(&mut self) -> impl Future> + '_ { + self.io.flush() } /// Call `f` with the largest contiguous slice of octets in the transmit buffer, @@ -300,8 +300,8 @@ impl<'a> TcpSocket<'a> { /// (see [may_recv](#method.may_recv)), and there is some pending data in the receive buffer. /// /// This is the equivalent of [read](#method.read), without buffering any data. - pub async fn wait_read_ready(&self) { - poll_fn(move |cx| self.io.poll_read_ready(cx)).await + pub fn wait_read_ready(&self) -> impl Future + '_ { + poll_fn(move |cx| self.io.poll_read_ready(cx)) } /// Read data from the socket. @@ -311,8 +311,8 @@ impl<'a> TcpSocket<'a> { /// /// A return value of Ok(0) means that the socket was closed and is longer /// able to receive any data. - pub async fn read(&mut self, buf: &mut [u8]) -> Result { - self.io.read(buf).await + pub fn read<'s>(&'s mut self, buf: &'s mut [u8]) -> impl Future> + 's { + self.io.read(buf) } /// Wait until the socket becomes writable. @@ -321,24 +321,24 @@ impl<'a> TcpSocket<'a> { /// (see [may_send](#method.may_send)), and the transmit buffer is not full. /// /// This is the equivalent of [write](#method.write), without sending any data. - pub async fn wait_write_ready(&self) { - poll_fn(move |cx| self.io.poll_write_ready(cx)).await + pub fn wait_write_ready(&self) -> impl Future + '_ { + poll_fn(move |cx| self.io.poll_write_ready(cx)) } /// Write data to the socket. /// /// Returns how many bytes were written, or an error. If the socket is not ready to /// accept data, it waits until it is. - pub async fn write(&mut self, buf: &[u8]) -> Result { - self.io.write(buf).await + pub fn write<'s>(&'s mut self, buf: &'s [u8]) -> impl Future> + 's { + self.io.write(buf) } /// Flushes the written data to the socket. /// /// This waits until all data has been sent, and ACKed by the remote host. For a connection /// closed with [`abort()`](TcpSocket::abort) it will wait for the TCP RST packet to be sent. - pub async fn flush(&mut self) -> Result<(), Error> { - self.io.flush().await + pub fn flush(&mut self) -> impl Future> + '_ { + self.io.flush() } /// Set the timeout for the socket. @@ -501,8 +501,8 @@ impl<'d> TcpIo<'d> { }) } - async fn read(&mut self, buf: &mut [u8]) -> Result { - poll_fn(move |cx| { + fn read<'s>(&'s mut self, buf: &'s mut [u8]) -> impl Future> + 's { + poll_fn(|cx| { // CAUTION: smoltcp semantics around EOF are different to what you'd expect // from posix-like IO, so we have to tweak things here. self.with_mut(|s, _| match s.recv_slice(buf) { @@ -526,7 +526,6 @@ impl<'d> TcpIo<'d> { Err(tcp::RecvError::InvalidState) => Poll::Ready(Err(Error::ConnectionReset)), }) }) - .await } fn poll_write_ready(&self, cx: &mut Context<'_>) -> Poll<()> { @@ -540,8 +539,8 @@ impl<'d> TcpIo<'d> { }) } - async fn write(&mut self, buf: &[u8]) -> Result { - poll_fn(move |cx| { + fn write<'s>(&'s mut self, buf: &'s [u8]) -> impl Future> + 's { + poll_fn(|cx| { self.with_mut(|s, _| match s.send_slice(buf) { // Not ready to send (no space in the tx buffer) Ok(0) => { @@ -554,7 +553,6 @@ impl<'d> TcpIo<'d> { Err(tcp::SendError::InvalidState) => Poll::Ready(Err(Error::ConnectionReset)), }) }) - .await } async fn write_with(&mut self, f: F) -> Result @@ -615,8 +613,8 @@ impl<'d> TcpIo<'d> { .await } - async fn flush(&mut self) -> Result<(), Error> { - poll_fn(move |cx| { + fn flush(&mut self) -> impl Future> + '_ { + poll_fn(|cx| { self.with_mut(|s, _| { let data_pending = (s.send_queue() > 0) && s.state() != tcp::State::Closed; let fin_pending = matches!( @@ -636,7 +634,6 @@ impl<'d> TcpIo<'d> { } }) }) - .await } fn recv_capacity(&self) -> usize { diff --git a/embassy-net/src/udp.rs b/embassy-net/src/udp.rs index 76602edc2..64a22d45b 100644 --- a/embassy-net/src/udp.rs +++ b/embassy-net/src/udp.rs @@ -1,6 +1,6 @@ //! UDP sockets. -use core::future::poll_fn; +use core::future::{poll_fn, Future}; use core::mem; use core::task::{Context, Poll}; @@ -107,8 +107,8 @@ impl<'a> UdpSocket<'a> { /// /// A socket is readable when a packet has been received, or when there are queued packets in /// the buffer. - pub async fn wait_recv_ready(&self) { - poll_fn(move |cx| self.poll_recv_ready(cx)).await + pub fn wait_recv_ready(&self) -> impl Future + '_ { + poll_fn(move |cx| self.poll_recv_ready(cx)) } /// Wait until a datagram can be read. @@ -134,8 +134,11 @@ impl<'a> UdpSocket<'a> { /// This method will wait until a datagram is received. /// /// Returns the number of bytes received and the remote endpoint. - pub async fn recv_from(&self, buf: &mut [u8]) -> Result<(usize, UdpMetadata), RecvError> { - poll_fn(move |cx| self.poll_recv_from(buf, cx)).await + pub fn recv_from<'s>( + &'s self, + buf: &'s mut [u8], + ) -> impl Future> + 's { + poll_fn(|cx| self.poll_recv_from(buf, cx)) } /// Receive a datagram. @@ -194,8 +197,8 @@ impl<'a> UdpSocket<'a> { /// /// A socket becomes writable when there is space in the buffer, from initial memory or after /// dispatching datagrams on a full buffer. - pub async fn wait_send_ready(&self) { - poll_fn(move |cx| self.poll_send_ready(cx)).await + pub fn wait_send_ready(&self) -> impl Future + '_ { + poll_fn(|cx| self.poll_send_ready(cx)) } /// Wait until a datagram can be sent. @@ -297,8 +300,8 @@ impl<'a> UdpSocket<'a> { /// Flush the socket. /// /// This method will wait until the socket is flushed. - pub async fn flush(&mut self) { - poll_fn(move |cx| { + pub fn flush(&mut self) -> impl Future + '_ { + poll_fn(|cx| { self.with_mut(|s, _| { if s.send_queue() == 0 { Poll::Ready(()) @@ -308,7 +311,6 @@ impl<'a> UdpSocket<'a> { } }) }) - .await } /// Returns the local endpoint of the socket. diff --git a/embassy-nrf/src/buffered_uarte.rs b/embassy-nrf/src/buffered_uarte.rs index b55e70a36..c3fcfd06e 100644 --- a/embassy-nrf/src/buffered_uarte.rs +++ b/embassy-nrf/src/buffered_uarte.rs @@ -9,7 +9,7 @@ //! Please also see [crate::uarte] to understand when [BufferedUarte] should be used. use core::cmp::min; -use core::future::poll_fn; +use core::future::{poll_fn, Future}; use core::marker::PhantomData; use core::slice; use core::sync::atomic::{compiler_fence, AtomicBool, AtomicU8, AtomicUsize, Ordering}; @@ -452,7 +452,7 @@ impl<'d, U: UarteInstance> BufferedUarteTx<'d, U> { } /// Write a buffer into this writer, returning how many bytes were written. - pub async fn write(&mut self, buf: &[u8]) -> Result { + pub fn write<'a>(&'a mut self, buf: &'a [u8]) -> impl Future> + 'a { poll_fn(move |cx| { //trace!("poll_write: {:?}", buf.len()); let ss = U::state(); @@ -477,7 +477,6 @@ impl<'d, U: UarteInstance> BufferedUarteTx<'d, U> { Poll::Ready(Ok(n)) }) - .await } /// Try writing a buffer without waiting, returning how many bytes were written. @@ -504,7 +503,7 @@ impl<'d, U: UarteInstance> BufferedUarteTx<'d, U> { } /// Flush this output stream, ensuring that all intermediately buffered contents reach their destination. - pub async fn flush(&mut self) -> Result<(), Error> { + pub fn flush(&mut self) -> impl Future> + '_ { poll_fn(move |cx| { //trace!("poll_flush"); let ss = U::state(); @@ -517,7 +516,6 @@ impl<'d, U: UarteInstance> BufferedUarteTx<'d, U> { Poll::Ready(Ok(())) }) - .await } } @@ -721,7 +719,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarteRx<'d, U, T> { } /// Return the contents of the internal buffer, filling it with more data from the inner reader if it is empty. - pub async fn fill_buf(&mut self) -> Result<&[u8], Error> { + pub fn fill_buf(&mut self) -> impl Future> { poll_fn(move |cx| { compiler_fence(Ordering::SeqCst); //trace!("poll_read"); @@ -771,7 +769,6 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarteRx<'d, U, T> { let buf = s.rx_buf.buf.load(Ordering::Relaxed); Poll::Ready(Ok(unsafe { slice::from_raw_parts(buf.add(start), n) })) }) - .await } /// Tell this buffer that `amt` bytes have been consumed from the buffer, so they should no longer be returned in calls to `fill_buf`. diff --git a/embassy-nrf/src/qspi.rs b/embassy-nrf/src/qspi.rs index 255b43c33..17e127700 100755 --- a/embassy-nrf/src/qspi.rs +++ b/embassy-nrf/src/qspi.rs @@ -2,7 +2,7 @@ #![macro_use] -use core::future::poll_fn; +use core::future::{poll_fn, Future}; use core::marker::PhantomData; use core::ptr; use core::task::Poll; @@ -314,7 +314,7 @@ impl<'d, T: Instance> Qspi<'d, T> { Ok(()) } - async fn wait_ready(&mut self) { + fn wait_ready(&mut self) -> impl Future { poll_fn(move |cx| { let r = T::regs(); let s = T::state(); @@ -324,7 +324,6 @@ impl<'d, T: Instance> Qspi<'d, T> { } Poll::Pending }) - .await } fn blocking_wait_ready() { diff --git a/embassy-nrf/src/usb/mod.rs b/embassy-nrf/src/usb/mod.rs index a9bf16708..06dae694b 100644 --- a/embassy-nrf/src/usb/mod.rs +++ b/embassy-nrf/src/usb/mod.rs @@ -4,7 +4,7 @@ pub mod vbus_detect; -use core::future::poll_fn; +use core::future::{poll_fn, Future}; use core::marker::PhantomData; use core::mem::MaybeUninit; use core::sync::atomic::{compiler_fence, AtomicU32, Ordering}; @@ -219,8 +219,8 @@ impl<'d, T: Instance, V: VbusDetect> driver::Bus for Bus<'d, T, V> { regs.enable().write(|x| x.set_enable(false)); } - async fn poll(&mut self) -> Event { - poll_fn(move |cx| { + fn poll(&mut self) -> impl Future { + poll_fn(|cx| { BUS_WAKER.register(cx.waker()); let regs = T::regs(); @@ -277,7 +277,6 @@ impl<'d, T: Instance, V: VbusDetect> driver::Bus for Bus<'d, T, V> { Poll::Pending }) - .await } fn endpoint_set_stalled(&mut self, ep_addr: EndpointAddress, stalled: bool) { @@ -468,7 +467,7 @@ impl<'d, T: Instance, Dir: EndpointDir> driver::Endpoint for Endpoint<'d, T, Dir #[allow(private_bounds)] impl<'d, T: Instance, Dir: EndpointDir> Endpoint<'d, T, Dir> { - async fn wait_enabled_state(&mut self, state: bool) { + fn wait_enabled_state(&mut self, state: bool) -> impl Future { let i = self.info.addr.index(); assert!(i != 0); @@ -480,12 +479,11 @@ impl<'d, T: Instance, Dir: EndpointDir> Endpoint<'d, T, Dir> { Poll::Pending } }) - .await } /// Wait for the endpoint to be disabled - pub async fn wait_disabled(&mut self) { - self.wait_enabled_state(false).await + pub fn wait_disabled(&mut self) -> impl Future { + self.wait_enabled_state(false) } } diff --git a/embassy-nrf/src/usb/vbus_detect.rs b/embassy-nrf/src/usb/vbus_detect.rs index bdc088dcb..8794beb2d 100644 --- a/embassy-nrf/src/usb/vbus_detect.rs +++ b/embassy-nrf/src/usb/vbus_detect.rs @@ -1,6 +1,6 @@ //! Trait and implementations for performing VBUS detection. -use core::future::poll_fn; +use core::future::{poll_fn, Future}; use core::sync::atomic::{AtomicBool, Ordering}; use core::task::Poll; @@ -99,8 +99,8 @@ impl VbusDetect for HardwareVbusDetect { regs.usbregstatus().read().vbusdetect() } - async fn wait_power_ready(&mut self) -> Result<(), ()> { - poll_fn(move |cx| { + fn wait_power_ready(&mut self) -> impl Future> { + poll_fn(|cx| { POWER_WAKER.register(cx.waker()); let regs = USB_REG_PERI; @@ -112,7 +112,6 @@ impl VbusDetect for HardwareVbusDetect { Poll::Pending } }) - .await } } @@ -163,7 +162,7 @@ impl VbusDetect for &SoftwareVbusDetect { self.usb_detected.load(Ordering::Relaxed) } - async fn wait_power_ready(&mut self) -> Result<(), ()> { + fn wait_power_ready(&mut self) -> impl Future> { poll_fn(move |cx| { POWER_WAKER.register(cx.waker()); @@ -175,6 +174,5 @@ impl VbusDetect for &SoftwareVbusDetect { Poll::Pending } }) - .await } } diff --git a/embassy-rp/src/adc.rs b/embassy-rp/src/adc.rs index 9582e43c8..19441f194 100644 --- a/embassy-rp/src/adc.rs +++ b/embassy-rp/src/adc.rs @@ -1,5 +1,5 @@ //! ADC driver. -use core::future::poll_fn; +use core::future::{poll_fn, Future}; use core::marker::PhantomData; use core::mem; use core::sync::atomic::{compiler_fence, Ordering}; @@ -193,18 +193,18 @@ impl<'d> Adc<'d, Async> { Self { phantom: PhantomData } } - async fn wait_for_ready() { + fn wait_for_ready() -> impl Future { let r = Self::regs(); r.inte().write(|w| w.set_fifo(true)); compiler_fence(Ordering::SeqCst); - poll_fn(|cx| { + + poll_fn(move |cx| { WAKER.register(cx.waker()); if r.cs().read().ready() { return Poll::Ready(()); } Poll::Pending }) - .await; } /// Sample a value from a channel until completed. diff --git a/embassy-sync/src/mutex.rs b/embassy-sync/src/mutex.rs index 08f66e374..f25f74336 100644 --- a/embassy-sync/src/mutex.rs +++ b/embassy-sync/src/mutex.rs @@ -2,7 +2,7 @@ //! //! This module provides a mutex that can be used to synchronize data between asynchronous tasks. use core::cell::{RefCell, UnsafeCell}; -use core::future::poll_fn; +use core::future::{poll_fn, Future}; use core::ops::{Deref, DerefMut}; use core::task::Poll; use core::{fmt, mem}; @@ -73,7 +73,7 @@ where /// Lock the mutex. /// /// This will wait for the mutex to be unlocked if it's already locked. - pub async fn lock(&self) -> MutexGuard<'_, M, T> { + pub fn lock(&self) -> impl Future> { poll_fn(|cx| { let ready = self.state.lock(|s| { let mut s = s.borrow_mut(); @@ -92,7 +92,6 @@ where Poll::Pending } }) - .await } /// Attempt to immediately lock the mutex. diff --git a/embassy-sync/src/once_lock.rs b/embassy-sync/src/once_lock.rs index 55608ba32..cd05b986d 100644 --- a/embassy-sync/src/once_lock.rs +++ b/embassy-sync/src/once_lock.rs @@ -1,7 +1,7 @@ //! Synchronization primitive for initializing a value once, allowing others to await a reference to the value. use core::cell::Cell; -use core::future::poll_fn; +use core::future::{poll_fn, Future}; use core::mem::MaybeUninit; use core::sync::atomic::{AtomicBool, Ordering}; use core::task::Poll; @@ -55,7 +55,7 @@ impl OnceLock { /// Get a reference to the underlying value, waiting for it to be set. /// If the value is already set, this will return immediately. - pub async fn get(&self) -> &T { + pub fn get(&self) -> impl Future { poll_fn(|cx| match self.try_get() { Some(data) => Poll::Ready(data), None => { @@ -63,7 +63,6 @@ impl OnceLock { Poll::Pending } }) - .await } /// Try to get a reference to the underlying value if it exists. diff --git a/embassy-sync/src/watch.rs b/embassy-sync/src/watch.rs index 404e31714..e76646c0b 100644 --- a/embassy-sync/src/watch.rs +++ b/embassy-sync/src/watch.rs @@ -1,7 +1,7 @@ //! A synchronization primitive for passing the latest value to **multiple** receivers. use core::cell::RefCell; -use core::future::poll_fn; +use core::future::{poll_fn, Future}; use core::marker::PhantomData; use core::ops::{Deref, DerefMut}; use core::task::{Context, Poll}; @@ -547,8 +547,8 @@ impl<'a, T: Clone, W: WatchBehavior + ?Sized> Rcv<'a, T, W> { /// Returns the current value of the `Watch` once it is initialized, marking it as seen. /// /// **Note**: Futures do nothing unless you `.await` or poll them. - pub async fn get(&mut self) -> T { - poll_fn(|cx| self.watch.poll_get(&mut self.at_id, cx)).await + pub fn get(&mut self) -> impl Future + '_ { + poll_fn(|cx| self.watch.poll_get(&mut self.at_id, cx)) } /// Tries to get the current value of the `Watch` without waiting, marking it as seen. diff --git a/embassy-sync/src/zerocopy_channel.rs b/embassy-sync/src/zerocopy_channel.rs index fabb69bf6..56433cd8a 100644 --- a/embassy-sync/src/zerocopy_channel.rs +++ b/embassy-sync/src/zerocopy_channel.rs @@ -15,7 +15,7 @@ //! another message will result in an error being returned. use core::cell::RefCell; -use core::future::poll_fn; +use core::future::{poll_fn, Future}; use core::marker::PhantomData; use core::task::{Context, Poll}; @@ -131,12 +131,15 @@ impl<'a, M: RawMutex, T> Sender<'a, M, T> { } /// Asynchronously send a value over the channel. - pub async fn send(&mut self) -> &mut T { - let i = poll_fn(|cx| { + pub fn send(&mut self) -> impl Future { + poll_fn(|cx| { self.channel.state.lock(|s| { let s = &mut *s.borrow_mut(); match s.push_index() { - Some(i) => Poll::Ready(i), + Some(i) => { + let r = unsafe { &mut *self.channel.buf.add(i) }; + Poll::Ready(r) + } None => { s.receive_waker.register(cx.waker()); Poll::Pending @@ -144,8 +147,6 @@ impl<'a, M: RawMutex, T> Sender<'a, M, T> { } }) }) - .await; - unsafe { &mut *self.channel.buf.add(i) } } /// Notify the channel that the sending of the value has been finalized. @@ -213,12 +214,15 @@ impl<'a, M: RawMutex, T> Receiver<'a, M, T> { } /// Asynchronously receive a value over the channel. - pub async fn receive(&mut self) -> &mut T { - let i = poll_fn(|cx| { + pub fn receive(&mut self) -> impl Future { + poll_fn(|cx| { self.channel.state.lock(|s| { let s = &mut *s.borrow_mut(); match s.pop_index() { - Some(i) => Poll::Ready(i), + Some(i) => { + let r = unsafe { &mut *self.channel.buf.add(i) }; + Poll::Ready(r) + } None => { s.send_waker.register(cx.waker()); Poll::Pending @@ -226,8 +230,6 @@ impl<'a, M: RawMutex, T> Receiver<'a, M, T> { } }) }) - .await; - unsafe { &mut *self.channel.buf.add(i) } } /// Notify the channel that the receiving of the value has been finalized. diff --git a/embassy-usb/src/class/cdc_acm.rs b/embassy-usb/src/class/cdc_acm.rs index 2823e522e..c5b1a56fe 100644 --- a/embassy-usb/src/class/cdc_acm.rs +++ b/embassy-usb/src/class/cdc_acm.rs @@ -1,7 +1,7 @@ //! CDC-ACM class implementation, aka Serial over USB. use core::cell::{Cell, RefCell}; -use core::future::poll_fn; +use core::future::{poll_fn, Future}; use core::mem::{self, MaybeUninit}; use core::sync::atomic::{AtomicBool, Ordering}; use core::task::Poll; @@ -108,7 +108,7 @@ impl Default for ControlShared { } impl ControlShared { - async fn changed(&self) { + fn changed(&self) -> impl Future + '_ { poll_fn(|cx| { if self.changed.load(Ordering::Relaxed) { self.changed.store(false, Ordering::Relaxed); @@ -118,7 +118,6 @@ impl ControlShared { Poll::Pending } }) - .await; } } diff --git a/embassy-usb/src/class/uac1/speaker.rs b/embassy-usb/src/class/uac1/speaker.rs index 6c3a4e378..25de25d9c 100644 --- a/embassy-usb/src/class/uac1/speaker.rs +++ b/embassy-usb/src/class/uac1/speaker.rs @@ -11,7 +11,7 @@ //! The class provides volume and mute controls for each channel. use core::cell::{Cell, RefCell}; -use core::future::poll_fn; +use core::future::{poll_fn, Future}; use core::marker::PhantomData; use core::sync::atomic::{AtomicBool, AtomicU32, Ordering}; use core::task::Poll; @@ -389,7 +389,7 @@ impl<'d> Default for SharedControl<'d> { } impl<'d> SharedControl<'d> { - async fn changed(&self) { + fn changed(&self) -> impl Future + '_ { poll_fn(|context| { if self.changed.load(Ordering::Relaxed) { self.changed.store(false, Ordering::Relaxed); @@ -399,7 +399,6 @@ impl<'d> SharedControl<'d> { Poll::Pending } }) - .await; } } From 8639692ce38bd0e33e87a42b9d51780ccc66952c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Mon, 30 Dec 2024 20:25:42 +0100 Subject: [PATCH 0554/1217] Update faq --- docs/pages/faq.adoc | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/docs/pages/faq.adoc b/docs/pages/faq.adoc index ed88515d0..9c4d277f9 100644 --- a/docs/pages/faq.adoc +++ b/docs/pages/faq.adoc @@ -92,17 +92,9 @@ If you see linker error like this: >>> referenced by driver.rs:127 (src/driver.rs:127) >>> embassy_time-846f66f1620ad42c.embassy_time.4f6a638abb75dd4c-cgu.0.rcgu.o:(embassy_time::driver::now::hefb1f99d6e069842) in archive Devel/Embedded/pogodyna/target/thumbv7em-none-eabihf/debug/deps/libembassy_time-846f66f1620ad42c.rlib - rust-lld: error: undefined symbol: _embassy_time_allocate_alarm - >>> referenced by driver.rs:134 (src/driver.rs:134) - >>> embassy_time-846f66f1620ad42c.embassy_time.4f6a638abb75dd4c-cgu.0.rcgu.o:(embassy_time::driver::allocate_alarm::hf5145b6bd46706b2) in archive Devel/Embedded/pogodyna/target/thumbv7em-none-eabihf/debug/deps/libembassy_time-846f66f1620ad42c.rlib - - rust-lld: error: undefined symbol: _embassy_time_set_alarm_callback - >>> referenced by driver.rs:139 (src/driver.rs:139) - >>> embassy_time-846f66f1620ad42c.embassy_time.4f6a638abb75dd4c-cgu.0.rcgu.o:(embassy_time::driver::set_alarm_callback::h24f92388d96eafd2) in archive Devel/Embedded/pogodyna/target/thumbv7em-none-eabihf/debug/deps/libembassy_time-846f66f1620ad42c.rlib - - rust-lld: error: undefined symbol: _embassy_time_set_alarm + rust-lld: error: undefined symbol: _embassy_time_schedule_wake >>> referenced by driver.rs:144 (src/driver.rs:144) - >>> embassy_time-846f66f1620ad42c.embassy_time.4f6a638abb75dd4c-cgu.0.rcgu.o:(embassy_time::driver::set_alarm::h530a5b1f444a6d5b) in archive Devel/Embedded/pogodyna/target/thumbv7em-none-eabihf/debug/deps/libembassy_time-846f66f1620ad42c.rlib + >>> embassy_time-846f66f1620ad42c.embassy_time.4f6a638abb75dd4c-cgu.0.rcgu.o:(embassy_time::driver::schedule_wake::h530a5b1f444a6d5b) in archive Devel/Embedded/pogodyna/target/thumbv7em-none-eabihf/debug/deps/libembassy_time-846f66f1620ad42c.rlib ---- You probably need to enable a time driver for your HAL (not in `embassy-time`!). For example with `embassy-stm32`, you might need to enable `time-driver-any`: @@ -158,10 +150,9 @@ Note that the git revision should match any other embassy patches or git depende * Set the following keys in the `[unstable]` section of your `.cargo/config.toml` ** `build-std = ["core"]` ** `build-std-features = ["panic_immediate_abort"]` -* Enable feature `embassy-time/generic-queue`, disable feature `embassy-executor/integrated-timers` * When using `InterruptExecutor`: ** disable `executor-thread` - ** make `main`` spawn everything, then enable link:https://docs.rs/cortex-m/latest/cortex_m/peripheral/struct.SCB.html#method.set_sleeponexit[SCB.SLEEPONEXIT] and `loop { cortex_m::asm::wfi() }` + ** make `main` spawn everything, then enable link:https://docs.rs/cortex-m/latest/cortex_m/peripheral/struct.SCB.html#method.set_sleeponexit[SCB.SLEEPONEXIT] and `loop { cortex_m::asm::wfi() }` ** *Note:* If you need 2 priority levels, using 2 interrupt executors is better than 1 thread executor + 1 interrupt executor. == How do I set up the task arenas on stable? From 306a7812672f47aa327e79c854992f90ac7fdb25 Mon Sep 17 00:00:00 2001 From: Fabian Wolter Date: Mon, 30 Dec 2024 20:46:56 +0100 Subject: [PATCH 0555/1217] =?UTF-8?q?STM32:=20set=20USB=20initialization?= =?UTF-8?q?=20delay=20to=201=C2=B5s?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- embassy-stm32/src/usb/usb.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/embassy-stm32/src/usb/usb.rs b/embassy-stm32/src/usb/usb.rs index 94af00b6e..8be051968 100644 --- a/embassy-stm32/src/usb/usb.rs +++ b/embassy-stm32/src/usb/usb.rs @@ -305,10 +305,8 @@ impl<'d, T: Instance> Driver<'d, T> { w.set_fres(true); }); - #[cfg(feature = "time")] - embassy_time::block_for(embassy_time::Duration::from_millis(100)); - #[cfg(not(feature = "time"))] - cortex_m::asm::delay(unsafe { crate::rcc::get_freqs() }.sys.to_hertz().unwrap().0 / 10); + // wait t_STARTUP = 1us + cortex_m::asm::delay(unsafe { crate::rcc::get_freqs() }.sys.to_hertz().unwrap().0 / 1_000_000); #[cfg(not(usb_v4))] regs.btable().write(|w| w.set_btable(0)); From 41c8bf867bc185507e1b9eadbf5645e57004cd4f Mon Sep 17 00:00:00 2001 From: klownfish Date: Tue, 31 Dec 2024 01:04:18 +0100 Subject: [PATCH 0556/1217] fix formatting --- embassy-stm32/src/adc/mod.rs | 2 +- embassy-stm32/src/adc/u5_adc4.rs | 35 +++++++++++++------------------- embassy-stm32/src/adc/v4.rs | 10 +++------ examples/stm32u5/src/bin/adc.rs | 30 +++++++++++---------------- 4 files changed, 30 insertions(+), 47 deletions(-) diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index 3cf2ca72e..36898b8f9 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs @@ -259,4 +259,4 @@ pub const fn resolution_to_max_count(res: Resolution) -> u32 { #[allow(unreachable_patterns)] _ => core::unreachable!(), } -} \ No newline at end of file +} diff --git a/embassy-stm32/src/adc/u5_adc4.rs b/embassy-stm32/src/adc/u5_adc4.rs index 468d16640..0635dad9b 100644 --- a/embassy-stm32/src/adc/u5_adc4.rs +++ b/embassy-stm32/src/adc/u5_adc4.rs @@ -1,17 +1,12 @@ -pub use crate::pac::adc::vals::Adc4Res as Resolution; -pub use crate::pac::adc::vals::Adc4SampleTime as SampleTime; -pub use crate::pac::adc::vals::Adc4Presc as Presc; -pub use crate::pac::adc::regs::Adc4Chselrmod0; - #[allow(unused)] -use pac::adc::vals::{Adc4Exten, Adc4OversamplingRatio, Adc4Dmacfg}; +use pac::adc::vals::{Adc4Dmacfg, Adc4Exten, Adc4OversamplingRatio}; -use super::{ - blocking_delay_us, AdcChannel, SealedAdcChannel, AnyAdcChannel, RxDma4 -}; +use super::{blocking_delay_us, AdcChannel, AnyAdcChannel, RxDma4, SealedAdcChannel}; +use crate::dma::Transfer; +pub use crate::pac::adc::regs::Adc4Chselrmod0; +pub use crate::pac::adc::vals::{Adc4Presc as Presc, Adc4Res as Resolution, Adc4SampleTime as SampleTime}; use crate::time::Hertz; use crate::{pac, rcc, Peripheral}; -use crate::dma::Transfer; const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(55); @@ -74,7 +69,7 @@ impl SealedAdcChannel for Vcore { pub enum DacChannel { OUT1, - OUT2 + OUT2, } /// Number of samples used for averaging. @@ -186,7 +181,7 @@ pub struct Adc4<'d, T: Instance> { #[derive(Debug)] pub enum Adc4Error { InvalidSequence, - DMAError + DMAError, } impl<'d, T: Instance> Adc4<'d, T> { @@ -205,9 +200,7 @@ impl<'d, T: Instance> Adc4<'d, T> { panic!("Maximal allowed frequency for ADC4 is {} MHz and it varies with different packages, refer to ST docs for more information.", MAX_ADC_CLK_FREQ.0 / 1_000_000 ); } - let mut s = Self { - adc, - }; + let mut s = Self { adc }; s.power_up(); @@ -227,7 +220,7 @@ impl<'d, T: Instance> Adc4<'d, T> { T::regs().cr().modify(|w| { w.set_advregen(true); }); - while !T::regs().isr().read().ldordy() { }; + while !T::regs().isr().read().ldordy() {} T::regs().isr().modify(|w| { w.set_ldordy(true); @@ -300,8 +293,8 @@ impl<'d, T: Instance> Adc4<'d, T> { pub fn enable_dac_channel(&self, dac: DacChannel) -> Dac { let mux; match dac { - DacChannel::OUT1 => {mux = false}, - DacChannel::OUT2 => {mux = true} + DacChannel::OUT1 => mux = false, + DacChannel::OUT2 => mux = true, } T::regs().or().modify(|w| w.set_chn21sel(mux)); Dac {} @@ -346,7 +339,7 @@ impl<'d, T: Instance> Adc4<'d, T> { } /// Read an ADC channel. - pub fn blocking_read(&mut self, channel: &mut impl AdcChannel) -> u16{ + pub fn blocking_read(&mut self, channel: &mut impl AdcChannel) -> u16 { channel.setup(); // Select channel @@ -440,7 +433,7 @@ impl<'d, T: Instance> Adc4<'d, T> { T::regs().chselrmod0().modify(|w| { w.set_chsel(channel.channel as usize, true); }); - }; + } let request = rx_dma.request(); let transfer = unsafe { @@ -483,4 +476,4 @@ impl<'d, T: Instance> Adc4<'d, T> { while T::regs().cr().read().adstart() {} } } -} \ No newline at end of file +} diff --git a/embassy-stm32/src/adc/v4.rs b/embassy-stm32/src/adc/v4.rs index 96dae25bd..46f9c7ac7 100644 --- a/embassy-stm32/src/adc/v4.rs +++ b/embassy-stm32/src/adc/v4.rs @@ -1,9 +1,7 @@ -#[allow(unused)] -use pac::adc::vals::{Adstp, Difsel, Exten, Pcsel, Dmngt}; - #[cfg(not(stm32u5))] -use pac::adc::vals::{Adcaldif, Boost}; - +use pac::adc::vals::{Adcaldif, Boost}; +#[allow(unused)] +use pac::adc::vals::{Adstp, Difsel, Dmngt, Exten, Pcsel}; use pac::adccommon::vals::Presc; use super::{ @@ -26,7 +24,6 @@ const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(50); #[cfg(stm32u5)] const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(55); - #[cfg(stm32g4)] const VREF_CHANNEL: u8 = 18; #[cfg(stm32g4)] @@ -41,7 +38,6 @@ const TEMP_CHANNEL: u8 = 18; #[cfg(not(stm32u5))] const VBAT_CHANNEL: u8 = 17; - #[cfg(stm32u5)] const VREF_CHANNEL: u8 = 0; #[cfg(stm32u5)] diff --git a/examples/stm32u5/src/bin/adc.rs b/examples/stm32u5/src/bin/adc.rs index 05e3faeb1..6ba21cc63 100644 --- a/examples/stm32u5/src/bin/adc.rs +++ b/examples/stm32u5/src/bin/adc.rs @@ -1,19 +1,14 @@ #![no_std] #![no_main] - -use defmt::{*}; -use defmt_rtt as _; - +use defmt::*; use embassy_stm32::adc; -use embassy_stm32::adc::AdcChannel; -use embassy_stm32::adc::adc4; -use panic_probe as _; - +use embassy_stm32::adc::{adc4, AdcChannel}; +use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] -async fn main(spawner: embassy_executor::Spawner) { - let mut config = embassy_stm32::Config::default(); +async fn main(_spawner: embassy_executor::Spawner) { + let config = embassy_stm32::Config::default(); let mut p = embassy_stm32::init(config); @@ -84,7 +79,8 @@ async fn main(spawner: embassy_executor::Spawner) { ] .into_iter(), &mut measurements, - ).await; + ) + .await; let volt1: f32 = 3.3 * measurements[0] as f32 / max1 as f32; let volt2: f32 = 3.3 * measurements[1] as f32 / max1 as f32; @@ -101,15 +97,13 @@ async fn main(spawner: embassy_executor::Spawner) { // The channels must be in ascending order and can't repeat for ADC4 adc4.read( &mut p.GPDMA1_CH1, - [ - &mut degraded42, - &mut degraded41, - ] - .into_iter(), + [&mut degraded42, &mut degraded41].into_iter(), &mut measurements, - ).await.unwrap(); + ) + .await + .unwrap(); let volt2: f32 = 3.3 * measurements[0] as f32 / max4 as f32; let volt1: f32 = 3.3 * measurements[1] as f32 / max4 as f32; info!("Async read 4 pin 1 {}", volt1); info!("Async read 4 pin 2 {}", volt2); -} \ No newline at end of file +} From e6001e66f8b21483a707d0015f9d278556759a7c Mon Sep 17 00:00:00 2001 From: 1-rafael-1 Date: Tue, 31 Dec 2024 15:54:42 +0100 Subject: [PATCH 0557/1217] Improve orchestrate_tasks example with shared state and better documentation Add mutex-protected shared system state Improve task coordination and signaling Add more documentation --- examples/rp/src/bin/orchestrate_tasks.rs | 322 +++++++++++------------ 1 file changed, 161 insertions(+), 161 deletions(-) diff --git a/examples/rp/src/bin/orchestrate_tasks.rs b/examples/rp/src/bin/orchestrate_tasks.rs index 0e21d5833..6f209da95 100644 --- a/examples/rp/src/bin/orchestrate_tasks.rs +++ b/examples/rp/src/bin/orchestrate_tasks.rs @@ -1,20 +1,18 @@ //! This example demonstrates some approaches to communicate between tasks in order to orchestrate the state of the system. //! +//! The system consists of several tasks: +//! - Three tasks that generate random numbers at different intervals (simulating i.e. sensor readings) +//! - A task that monitors USB power connection (hardware event handling) +//! - A task that reads system voltage (ADC sampling) +//! - A consumer task that processes all this information +//! +//! The system maintains state in a single place, wrapped in a Mutex. +//! //! We demonstrate how to: -//! - use a channel to send messages between tasks, in this case here in order to have one task control the state of the system. -//! - use a signal to terminate a task. -//! - use command channels to send commands to another task. -//! - use different ways to receive messages, from a straightforwar awaiting on one channel to a more complex awaiting on multiple futures. -//! -//! There are more patterns to orchestrate tasks, this is just one example. -//! -//! We will use these tasks to generate example "state information": -//! - a task that generates random numbers in intervals of 60s -//! - a task that generates random numbers in intervals of 30s -//! - a task that generates random numbers in intervals of 90s -//! - a task that notifies about being attached/disattached from usb power -//! - a task that measures vsys voltage in intervals of 30s -//! - a task that consumes the state information and reacts to it +//! - use a mutex to maintain shared state between tasks +//! - use a channel to send events between tasks +//! - use an orchestrator task to coordinate tasks and handle state transitions +//! - use signals to notify about state changes and terminate tasks #![no_std] #![no_main] @@ -28,15 +26,12 @@ use embassy_rp::clocks::RoscRng; use embassy_rp::gpio::{Input, Pull}; use embassy_rp::{bind_interrupts, peripherals}; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; -use embassy_sync::{channel, signal}; +use embassy_sync::{channel, mutex::Mutex, signal}; use embassy_time::{Duration, Timer}; use rand::RngCore; use {defmt_rtt as _, panic_probe as _}; -// This is just some preparation, see example `assign_resources.rs` for more information on this. We prep the rresources that we will be using in different tasks. -// **Note**: This will not work with a board that has a wifi chip, because the wifi chip uses pins 24 and 29 for its own purposes. A way around this in software -// is not trivial, at least if you intend to use wifi, too. Workaround is to wire from vsys and vbus pins to appropriate pins on the board through a voltage divider. Then use those pins. -// For this example it will not matter much, the concept of what we are showing remains valid. +// Hardware resource assignment. See other examples for different ways of doing this. assign_resources! { vsys: Vsys { adc: ADC, @@ -47,228 +42,233 @@ assign_resources! { }, } +// Interrupt binding - required for hardware peripherals like ADC bind_interrupts!(struct Irqs { ADC_IRQ_FIFO => InterruptHandler; }); -/// This is the type of Events that we will send from the worker tasks to the orchestrating task. +/// Events that worker tasks send to the orchestrator enum Events { - UsbPowered(bool), - VsysVoltage(f32), - FirstRandomSeed(u32), - SecondRandomSeed(u32), - ThirdRandomSeed(u32), - ResetFirstRandomSeed, + UsbPowered(bool), // USB connection state changed + VsysVoltage(f32), // New voltage reading + FirstRandomSeed(u32), // Random number from 30s timer + SecondRandomSeed(u32), // Random number from 60s timer + ThirdRandomSeed(u32), // Random number from 90s timer + ResetFirstRandomSeed, // Signal to reset the first counter } -/// This is the type of Commands that we will send from the orchestrating task to the worker tasks. -/// Note that we are lazy here and only have one command, you might want to have more. +/// Commands that can control task behavior. +/// Currently only used to stop tasks, but could be extended for other controls. enum Commands { - /// This command will stop the appropriate worker task + /// Signals a task to stop execution Stop, } -/// This is the state of the system, we will use this to orchestrate the system. This is a simple example, in a real world application this would be more complex. -#[derive(Default, Debug, Clone, Format)] +/// The central state of our system, shared between tasks. +#[derive(Clone, Format)] struct State { usb_powered: bool, vsys_voltage: f32, first_random_seed: u32, second_random_seed: u32, third_random_seed: u32, + first_random_seed_task_running: bool, times_we_got_first_random_seed: u8, maximum_times_we_want_first_random_seed: u8, } +/// A formatted view of the system status, used for logging. Used for the below `get_system_summary` fn. +#[derive(Format)] +struct SystemStatus { + power_source: &'static str, + voltage: f32, +} + impl State { - fn new() -> Self { + const fn new() -> Self { Self { usb_powered: false, vsys_voltage: 0.0, first_random_seed: 0, second_random_seed: 0, third_random_seed: 0, + first_random_seed_task_running: false, times_we_got_first_random_seed: 0, maximum_times_we_want_first_random_seed: 3, } } + + /// Returns a formatted summary of power state and voltage. + /// Shows how to create methods that work with shared state. + fn get_system_summary(&self) -> SystemStatus { + SystemStatus { + power_source: if self.usb_powered { + "USB powered" + } else { + "Battery powered" + }, + voltage: self.vsys_voltage, + } + } } -/// Channel for the events that we want the orchestrator to react to, all state events are of the type Enum Events. -/// We use a channel with an arbitrary size of 10, the precise size of the queue depends on your use case. This depends on how many events we -/// expect to be generated in a given time frame and how fast the orchestrator can react to them. And then if we rather want the senders to wait for -/// new slots in the queue or if we want the orchestrator to have a backlog of events to process. In this case here we expect to always be enough slots -/// in the queue, so the worker tasks can in all nominal cases send their events and continue with their work without waiting. -/// For the events we - in this case here - do not want to loose any events, so a channel is a good choice. See embassy_sync docs for other options. +/// The shared state protected by a mutex +static SYSTEM_STATE: Mutex = Mutex::new(State::new()); + +/// Channel for events from worker tasks to the orchestrator static EVENT_CHANNEL: channel::Channel = channel::Channel::new(); -/// Signal for stopping the first random signal task. We use a signal here, because we need no queue. It is suffiient to have one signal active. +/// Signal used to stop the first random number task static STOP_FIRST_RANDOM_SIGNAL: signal::Signal = signal::Signal::new(); -/// Channel for the state that we want the consumer task to react to. We use a channel here, because we want to have a queue of state changes, although -/// we want the queue to be of size 1, because we want to finish rwacting to the state change before the next one comes in. This is just a design choice -/// and depends on your use case. -static CONSUMER_CHANNEL: channel::Channel = channel::Channel::new(); +/// Signal for notifying about state changes +static STATE_CHANGED: signal::Signal = signal::Signal::new(); -// And now we can put all this into use - -/// This is the main task, that will not do very much besides spawning the other tasks. This is a design choice, you could do the -/// orchestrating here. This is to show that we do not need a main loop here, the system will run indefinitely as long as at least one task is running. #[embassy_executor::main] async fn main(spawner: Spawner) { - // initialize the peripherals let p = embassy_rp::init(Default::default()); - // split the resources, for convenience - see above let r = split_resources! {p}; - // spawn the tasks spawner.spawn(orchestrate(spawner)).unwrap(); spawner.spawn(random_60s(spawner)).unwrap(); spawner.spawn(random_90s(spawner)).unwrap(); + // `random_30s` is not spawned here, butin the orchestrate task depending on state spawner.spawn(usb_power(spawner, r.vbus)).unwrap(); spawner.spawn(vsys_voltage(spawner, r.vsys)).unwrap(); spawner.spawn(consumer(spawner)).unwrap(); } -/// This is the task handling the system state and orchestrating the other tasks. WEe can regard this as the "main loop" of the system. +/// Main task that processes all events and updates system state. #[embassy_executor::task] -async fn orchestrate(_spawner: Spawner) { - let mut state = State::new(); - - // we need to have a receiver for the events +async fn orchestrate(spawner: Spawner) { let receiver = EVENT_CHANNEL.receiver(); - // and we need a sender for the consumer task - let state_sender = CONSUMER_CHANNEL.sender(); - loop { - // we await on the receiver, this will block until a new event is available - // as an alternative to this, we could also await on multiple channels, this would block until at least one of the channels has an event - // see the embassy_futures docs: https://docs.embassy.dev/embassy-futures/git/default/select/index.html - // The task random_30s does a select, if you want to have a look at that. - // Another reason to use select may also be that we want to have a timeout, so we can react to the absence of events within a time frame. - // We keep it simple here. + // Do nothing until we receive any event let event = receiver.receive().await; - // react to the events - match event { - Events::UsbPowered(usb_powered) => { - // update the state and/or react to the event here - state.usb_powered = usb_powered; - info!("Usb powered: {}", usb_powered); - } - Events::VsysVoltage(voltage) => { - // update the state and/or react to the event here - state.vsys_voltage = voltage; - info!("Vsys voltage: {}", voltage); - } - Events::FirstRandomSeed(seed) => { - // update the state and/or react to the event here - state.first_random_seed = seed; - // here we change some meta state, we count how many times we got the first random seed - state.times_we_got_first_random_seed += 1; - info!( - "First random seed: {}, and that was iteration {} of receiving this.", - seed, &state.times_we_got_first_random_seed - ); - } - Events::SecondRandomSeed(seed) => { - // update the state and/or react to the event here - state.second_random_seed = seed; - info!("Second random seed: {}", seed); - } - Events::ThirdRandomSeed(seed) => { - // update the state and/or react to the event here - state.third_random_seed = seed; - info!("Third random seed: {}", seed); - } - Events::ResetFirstRandomSeed => { - // update the state and/or react to the event here - state.times_we_got_first_random_seed = 0; - state.first_random_seed = 0; - info!("Resetting the first random seed counter"); - } - } - // we now have an altered state - // there is a crate for detecting field changes on crates.io (https://crates.io/crates/fieldset) that might be useful here - // for now we just keep it simple + // Scope in which we want to lock the system state. As an alternative we could also call `drop` on the state + { + let mut state = SYSTEM_STATE.lock().await; - // we send the state to the consumer task - // since the channel has a size of 1, this will block until the consumer task has received the state, which is what we want here in this example - // **Note:** It is bad design to send too much data between tasks, with no clear definition of what "too much" is. In this example we send the - // whole state, in a real world application you might want to send only the data, that is relevant to the consumer task AND only when it has changed. - // We keep it simple here. - state_sender.send(state.clone()).await; - } -} - -/// This task will consume the state information and react to it. This is a simple example, in a real world application this would be more complex -/// and we could have multiple consumer tasks, each reacting to different parts of the state. -#[embassy_executor::task] -async fn consumer(spawner: Spawner) { - // we need to have a receiver for the state - let receiver = CONSUMER_CHANNEL.receiver(); - let sender = EVENT_CHANNEL.sender(); - loop { - // we await on the receiver, this will block until a new state is available - let state = receiver.receive().await; - // react to the state, in this case here we just log it - info!("The consumer has reveived this state: {:?}", &state); - - // here we react to the state, in this case here we want to start or stop the first random signal task depending on the state of the system - match state.times_we_got_first_random_seed { - max if max == state.maximum_times_we_want_first_random_seed => { - info!("Stopping the first random signal task"); - // we send a command to the task - STOP_FIRST_RANDOM_SIGNAL.signal(Commands::Stop); - // we notify the orchestrator that we have sent the command - sender.send(Events::ResetFirstRandomSeed).await; - } - 0 => { - // we start the task, which presents us with an interesting problem, because we may return here before the task has started - // here we just try and log if the task has started, in a real world application you might want to handle this more gracefully - info!("Starting the first random signal task"); - match spawner.spawn(random_30s(spawner)) { - Ok(_) => info!("Successfully spawned random_30s task"), - Err(e) => info!("Failed to spawn random_30s task: {:?}", e), + match event { + Events::UsbPowered(usb_powered) => { + state.usb_powered = usb_powered; + info!("Usb powered: {}", usb_powered); + info!("System summary: {}", state.get_system_summary()); + } + Events::VsysVoltage(voltage) => { + state.vsys_voltage = voltage; + info!("Vsys voltage: {}", voltage); + } + Events::FirstRandomSeed(seed) => { + state.first_random_seed = seed; + state.times_we_got_first_random_seed += 1; + info!( + "First random seed: {}, and that was iteration {} of receiving this.", + seed, &state.times_we_got_first_random_seed + ); + } + Events::SecondRandomSeed(seed) => { + state.second_random_seed = seed; + info!("Second random seed: {}", seed); + } + Events::ThirdRandomSeed(seed) => { + state.third_random_seed = seed; + info!("Third random seed: {}", seed); + } + Events::ResetFirstRandomSeed => { + state.times_we_got_first_random_seed = 0; + state.first_random_seed = 0; + info!("Resetting the first random seed counter"); } } - _ => {} + + // Handle task orchestration based on state + // Just placed as an example here, could be hooked into the event system, puton a timer, ... + match state.times_we_got_first_random_seed { + max if max == state.maximum_times_we_want_first_random_seed => { + info!("Stopping the first random signal task"); + STOP_FIRST_RANDOM_SIGNAL.signal(Commands::Stop); + EVENT_CHANNEL.sender().send(Events::ResetFirstRandomSeed).await; + } + 0 => { + let respawn_first_random_seed_task = !state.first_random_seed_task_running; + // Deliberately dropping the Mutex lock here to release it before a lengthy operation + drop(state); + if respawn_first_random_seed_task { + info!("(Re)-Starting the first random signal task"); + spawner.spawn(random_30s(spawner)).unwrap(); + } + } + _ => {} + } } + + STATE_CHANGED.signal(()); } } -/// This task will generate random numbers in intervals of 30s -/// The task will terminate after it has received a command signal to stop, see the orchestrate task for that. -/// Note that we are not spawning this task from main, as we will show how such a task can be spawned and closed dynamically. +/// Task that monitors state changes and logs system status. +#[embassy_executor::task] +async fn consumer(_spawner: Spawner) { + loop { + // Wait for state change notification + STATE_CHANGED.wait().await; + + let state = SYSTEM_STATE.lock().await; + info!( + "State update - {} | Seeds - First: {} (count: {}/{}, running: {}), Second: {}, Third: {}", + state.get_system_summary(), + state.first_random_seed, + state.times_we_got_first_random_seed, + state.maximum_times_we_want_first_random_seed, + state.first_random_seed_task_running, + state.second_random_seed, + state.third_random_seed + ); + } +} + +/// Task that generates random numbers every 30 seconds until stopped. +/// Shows how to handle both timer events and stop signals. +/// As an example of some routine we want to be on or off depending on other needs. #[embassy_executor::task] async fn random_30s(_spawner: Spawner) { + { + let mut state = SYSTEM_STATE.lock().await; + state.first_random_seed_task_running = true; + } + let mut rng = RoscRng; let sender = EVENT_CHANNEL.sender(); + loop { - // we either await on the timer or the signal, whichever comes first. - let futures = select(Timer::after(Duration::from_secs(30)), STOP_FIRST_RANDOM_SIGNAL.wait()).await; - match futures { + // Wait for either 30s timer or stop signal (like select() in Go) + match select(Timer::after(Duration::from_secs(30)), STOP_FIRST_RANDOM_SIGNAL.wait()).await { Either::First(_) => { - // we received are operating on the timer info!("30s are up, generating random number"); let random_number = rng.next_u32(); sender.send(Events::FirstRandomSeed(random_number)).await; } Either::Second(_) => { - // we received the signal to stop info!("Received signal to stop, goodbye!"); + + let mut state = SYSTEM_STATE.lock().await; + state.first_random_seed_task_running = false; + break; } } } } -/// This task will generate random numbers in intervals of 60s +/// Task that generates random numbers every 60 seconds. As an example of some routine. #[embassy_executor::task] async fn random_60s(_spawner: Spawner) { let mut rng = RoscRng; let sender = EVENT_CHANNEL.sender(); + loop { Timer::after(Duration::from_secs(60)).await; let random_number = rng.next_u32(); @@ -276,11 +276,12 @@ async fn random_60s(_spawner: Spawner) { } } -/// This task will generate random numbers in intervals of 90s +/// Task that generates random numbers every 90 seconds. . As an example of some routine. #[embassy_executor::task] async fn random_90s(_spawner: Spawner) { let mut rng = RoscRng; let sender = EVENT_CHANNEL.sender(); + loop { Timer::after(Duration::from_secs(90)).await; let random_number = rng.next_u32(); @@ -288,31 +289,30 @@ async fn random_90s(_spawner: Spawner) { } } -/// This task will notify if we are connected to usb power +/// Task that monitors USB power connection. As an example of some Interrupt somewhere. #[embassy_executor::task] pub async fn usb_power(_spawner: Spawner, r: Vbus) { let mut vbus_in = Input::new(r.pin_24, Pull::None); let sender = EVENT_CHANNEL.sender(); + loop { sender.send(Events::UsbPowered(vbus_in.is_high())).await; vbus_in.wait_for_any_edge().await; } } -/// This task will measure the vsys voltage in intervals of 30s +/// Task that reads system voltage through ADC. As an example of some continuous sensor reading. #[embassy_executor::task] pub async fn vsys_voltage(_spawner: Spawner, r: Vsys) { let mut adc = Adc::new(r.adc, Irqs, Config::default()); let vsys_in = r.pin_29; let mut channel = Channel::new_pin(vsys_in, Pull::None); let sender = EVENT_CHANNEL.sender(); + loop { - // read the adc value + Timer::after(Duration::from_secs(30)).await; let adc_value = adc.read(&mut channel).await.unwrap(); - // convert the adc value to voltage. - // 3.3 is the reference voltage, 3.0 is the factor for the inbuilt voltage divider and 4096 is the resolution of the adc let voltage = (adc_value as f32) * 3.3 * 3.0 / 4096.0; sender.send(Events::VsysVoltage(voltage)).await; - Timer::after(Duration::from_secs(30)).await; } } From 6efd6a457f938a65aea85b671a79214fe5e79b96 Mon Sep 17 00:00:00 2001 From: 1-rafael-1 Date: Tue, 31 Dec 2024 15:58:57 +0100 Subject: [PATCH 0558/1217] fmt --- examples/rp/src/bin/orchestrate_tasks.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/rp/src/bin/orchestrate_tasks.rs b/examples/rp/src/bin/orchestrate_tasks.rs index 6f209da95..31f10d8db 100644 --- a/examples/rp/src/bin/orchestrate_tasks.rs +++ b/examples/rp/src/bin/orchestrate_tasks.rs @@ -26,7 +26,8 @@ use embassy_rp::clocks::RoscRng; use embassy_rp::gpio::{Input, Pull}; use embassy_rp::{bind_interrupts, peripherals}; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; -use embassy_sync::{channel, mutex::Mutex, signal}; +use embassy_sync::{channel, signal}; ++use embassy_sync::mutex::Mutex; use embassy_time::{Duration, Timer}; use rand::RngCore; use {defmt_rtt as _, panic_probe as _}; From 463a3346de74ce354bf5bb55b67eb77e7c5ace73 Mon Sep 17 00:00:00 2001 From: 1-rafael-1 Date: Tue, 31 Dec 2024 16:01:09 +0100 Subject: [PATCH 0559/1217] fmt --- examples/rp/src/bin/orchestrate_tasks.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/rp/src/bin/orchestrate_tasks.rs b/examples/rp/src/bin/orchestrate_tasks.rs index 31f10d8db..7ff004860 100644 --- a/examples/rp/src/bin/orchestrate_tasks.rs +++ b/examples/rp/src/bin/orchestrate_tasks.rs @@ -26,8 +26,8 @@ use embassy_rp::clocks::RoscRng; use embassy_rp::gpio::{Input, Pull}; use embassy_rp::{bind_interrupts, peripherals}; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; +use embassy_sync::mutex::Mutex; use embassy_sync::{channel, signal}; -+use embassy_sync::mutex::Mutex; use embassy_time::{Duration, Timer}; use rand::RngCore; use {defmt_rtt as _, panic_probe as _}; From 6b3ca677631a360bc1e485f0edd158f5b7afa1f1 Mon Sep 17 00:00:00 2001 From: Bart Massey Date: Tue, 31 Dec 2024 14:27:41 -0800 Subject: [PATCH 0560/1217] modified examples/std README to avoid possible problems --- examples/std/README.md | 14 +++++--------- examples/std/tap.sh | 7 +++++++ 2 files changed, 12 insertions(+), 9 deletions(-) create mode 100644 examples/std/tap.sh diff --git a/examples/std/README.md b/examples/std/README.md index e3a59d6ea..dcc152fc2 100644 --- a/examples/std/README.md +++ b/examples/std/README.md @@ -1,16 +1,12 @@ ## Running the `embassy-net` examples -First, create the tap0 interface. You only need to do this once. +First, create the tap99 interface. (The number was chosen to +hopefully not collide with anything.) You only need to do +this once. ```sh -sudo ip tuntap add name tap0 mode tap user $USER -sudo ip link set tap0 up -sudo ip addr add 192.168.69.100/24 dev tap0 -sudo ip -6 addr add fe80::100/64 dev tap0 -sudo ip -6 addr add fdaa::100/64 dev tap0 -sudo ip -6 route add fe80::/64 dev tap0 -sudo ip -6 route add fdaa::/64 dev tap0 +sudo sh tap.sh ``` Second, have something listening there. For example `nc -lp 8000` @@ -19,5 +15,5 @@ Then run the example located in the `examples` folder: ```sh cd $EMBASSY_ROOT/examples/std/ -cargo run --bin net -- --static-ip +sudo cargo run --bin net -- --tap tap99 --static-ip ``` diff --git a/examples/std/tap.sh b/examples/std/tap.sh new file mode 100644 index 000000000..39d92a099 --- /dev/null +++ b/examples/std/tap.sh @@ -0,0 +1,7 @@ +ip tuntap add name tap99 mode tap user $USER +ip link set tap99 up +ip addr add 192.168.69.100/24 dev tap99 +ip -6 addr add fe80::100/64 dev tap99 +ip -6 addr add fdaa::100/64 dev tap99 +ip -6 route add fe80::/64 dev tap99 +ip -6 route add fdaa::/64 dev tap99 From a38a1c2e1cb7757df65eb4b76ebca695a6d189cd Mon Sep 17 00:00:00 2001 From: Lofty Inclination Date: Tue, 31 Dec 2024 23:26:21 +0000 Subject: [PATCH 0561/1217] Enable docs for `ble` and `mac` --- embassy-stm32-wpan/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-stm32-wpan/Cargo.toml b/embassy-stm32-wpan/Cargo.toml index 552d80982..74e7a67d9 100644 --- a/embassy-stm32-wpan/Cargo.toml +++ b/embassy-stm32-wpan/Cargo.toml @@ -13,10 +13,10 @@ documentation = "https://docs.embassy.dev/embassy-stm32-wpan" src_base = "https://github.com/embassy-rs/embassy/blob/embassy-stm32-wpan-v$VERSION/embassy-stm32-wpan/src/" src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-stm32-wpan/src/" target = "thumbv7em-none-eabihf" -features = ["stm32wb55rg"] +features = ["stm32wb55rg", "ble", "mac"] [package.metadata.docs.rs] -features = ["stm32wb55rg"] +features = ["stm32wb55rg", "ble", "mac"] [dependencies] embassy-stm32 = { version = "0.1.0", path = "../embassy-stm32" } From c84aef75af6c1e7b60b6c86b7dcd20293f3f5a89 Mon Sep 17 00:00:00 2001 From: Lofty Inclination Date: Tue, 31 Dec 2024 23:26:42 +0000 Subject: [PATCH 0562/1217] Fix spelling --- embassy-stm32-wpan/src/consts.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32-wpan/src/consts.rs b/embassy-stm32-wpan/src/consts.rs index 6aaef1d35..e2ae6ca86 100644 --- a/embassy-stm32-wpan/src/consts.rs +++ b/embassy-stm32-wpan/src/consts.rs @@ -69,7 +69,7 @@ pub const TL_CS_EVT_SIZE: usize = core::mem::size_of::(); * enough to store all asynchronous events received in between. * When CFG_TLBLE_MOST_EVENT_PAYLOAD_SIZE is set to 27, this allow to store three 255 bytes long asynchronous events * between the HCI command and its event. - * This parameter depends on the value given to CFG_TLBLE_MOST_EVENT_PAYLOAD_SIZE. When the queue size is to small, + * This parameter depends on the value given to CFG_TLBLE_MOST_EVENT_PAYLOAD_SIZE. When the queue size is too small, * the system may hang if the queue is full with asynchronous events and the HCI layer is still waiting * for a CC/CS event, In that case, the notification TL_BLE_HCI_ToNot() is called to indicate * to the application a HCI command did not receive its command event within 30s (Default HCI Timeout). From b2cc2fda26a7ecd6d64482e1f53eaf213f2b0a54 Mon Sep 17 00:00:00 2001 From: Lofty Inclination Date: Wed, 1 Jan 2025 00:56:16 +0000 Subject: [PATCH 0563/1217] Add docs for the BLE bindings These new docs explain a lot of the current implementation for the BLE stack, with reference to AN5289 14.1. They also detail the additional requirements around BLE startup behaviour; specifically, that certain SYS events must be awaited, and that shci_c2_ble_init should be called. Since the ble feature is now enabled by default for the docs, the remaining documentation for the BLE behaviour (as implemented by the `stm32wb-hci` crate) should be bought in automatically. --- embassy-stm32-wpan/src/lib.rs | 32 +++++++++++++++++++++++++++++++ embassy-stm32-wpan/src/sub/ble.rs | 10 ++++++++++ embassy-stm32-wpan/src/sub/sys.rs | 10 ++++++++++ embassy-stm32-wpan/src/tables.rs | 7 +++++++ 4 files changed, 59 insertions(+) diff --git a/embassy-stm32-wpan/src/lib.rs b/embassy-stm32-wpan/src/lib.rs index fb34d4ba0..1a01be200 100644 --- a/embassy-stm32-wpan/src/lib.rs +++ b/embassy-stm32-wpan/src/lib.rs @@ -37,6 +37,7 @@ pub use crate::sub::ble::hci; type PacketHeader = LinkedListNode; +/// Transport Layer for the Mailbox interface pub struct TlMbox<'d> { _ipcc: PeripheralRef<'d, IPCC>, @@ -49,6 +50,33 @@ pub struct TlMbox<'d> { } impl<'d> TlMbox<'d> { + /// Initialise the Transport Layer, and creates and returns a wrapper around it. + /// + /// This method performs the initialisation laid out in AN5289 annex 14.1. However, it differs + /// from the implementation documented in Figure 64, to avoid needing to reference any C + /// function pointers. + /// + /// Annex 14.1 lays out the following methods that should be called: + /// 1. tl_mbox.c/TL_Init, which initialises the reference table that is shared between CPU1 + /// and CPU2. + /// 2. shci_tl.c/shci_init(), which initialises the system transport layer, and in turn + /// calls tl_mbox.c/TL_SYS_Init, which initialises SYSTEM_EVT_QUEUE channel. + /// 3. tl_mbox.c/TL_MM_Init(), which initialises the channel used for sending memory + /// manager commands. + /// 4. tl_mbox.c/TL_Enable(), which enables the IPCC, and starts CPU2. + /// This implementation initialises all of the shared refernce tables and all IPCC channel that + /// would be initialised by this process. The developer should therefore treat this method as + /// completing all steps in Figure 64. + /// + /// Once this method has been called, no system commands may be sent until the CPU2 ready + /// signal is received, via [sys_subsystem.read]; this completes the procedure laid out in + /// Figure 65. + /// + /// If the `ble` feature is enabled, at this point, the user should call + /// [sys_subsystem.shci_c2_ble_init], before any commands are written to the [ble_subsystem] + /// ([Ble::new()] completes the process that would otherwise be handled by `TL_BLE_Init`; see + /// Figure 66). This completes the procedure laid out in Figure 66. + // TODO: document what the user should do after calling init to use the mac_802_15_4 subsystem pub fn init( ipcc: impl Peripheral

+ 'd, _irqs: impl interrupt::typelevel::Binding @@ -57,6 +85,9 @@ impl<'d> TlMbox<'d> { ) -> Self { into_ref!(ipcc); + // this is an inlined version of TL_Init from the STM32WB firmware as requested by AN5289. + // HW_IPCC_Init is not called, and its purpose is (presumably?) covered by this + // implementation unsafe { TL_REF_TABLE.as_mut_ptr().write_volatile(RefTable { device_info_table: TL_DEVICE_INFO_TABLE.as_ptr(), @@ -140,6 +171,7 @@ impl<'d> TlMbox<'d> { compiler_fence(Ordering::SeqCst); + // this is equivalent to `HW_IPCC_Enable`, which is called by `TL_Enable` Ipcc::enable(config); Self { diff --git a/embassy-stm32-wpan/src/sub/ble.rs b/embassy-stm32-wpan/src/sub/ble.rs index c5f2334f4..a47c6a699 100644 --- a/embassy-stm32-wpan/src/sub/ble.rs +++ b/embassy-stm32-wpan/src/sub/ble.rs @@ -11,11 +11,20 @@ use crate::tables::{BleTable, BLE_CMD_BUFFER, CS_BUFFER, EVT_QUEUE, HCI_ACL_DATA use crate::unsafe_linked_list::LinkedListNode; use crate::{channels, evt}; +/// A guard that, once constructed, may be used to send BLE commands to CPU2. +/// +/// It is the responsibility of the caller to ensure that they have awaited an event via +/// [crate::sub::Sys::read] before sending any of these commands, and to call +/// [crate::sub::Sys::shci_c2_ble_init] and await the HCI_COMMAND_COMPLETE_EVENT before sending any +/// other commands. pub struct Ble { _private: (), } impl Ble { + /// Constructs a guard that allows for BLE commands to be sent to CPU2. + /// + /// This takes the place of `TL_BLE_Init`, completing that step as laid out in AN5289, Fig 66. pub(crate) fn new() -> Self { unsafe { LinkedListNode::init_head(EVT_QUEUE.as_mut_ptr()); @@ -30,6 +39,7 @@ impl Ble { Self { _private: () } } + /// `HW_IPCC_BLE_EvtNot` pub async fn tl_read(&self) -> EvtBox { Ipcc::receive(channels::cpu2::IPCC_BLE_EVENT_CHANNEL, || unsafe { diff --git a/embassy-stm32-wpan/src/sub/sys.rs b/embassy-stm32-wpan/src/sub/sys.rs index bd2ea3f74..fcc2c651e 100644 --- a/embassy-stm32-wpan/src/sub/sys.rs +++ b/embassy-stm32-wpan/src/sub/sys.rs @@ -10,6 +10,7 @@ use crate::tables::{SysTable, WirelessFwInfoTable}; use crate::unsafe_linked_list::LinkedListNode; use crate::{channels, Ipcc, SYSTEM_EVT_QUEUE, SYS_CMD_BUF, TL_DEVICE_INFO_TABLE, TL_SYS_TABLE}; +/// A guard that, once constructed, allows for sys commands to be sent to CPU2. pub struct Sys { _private: (), } @@ -86,12 +87,21 @@ impl Sys { self.write_and_get_response(ShciOpcode::Mac802_15_4Init, &[]).await } + /// Send a request to CPU2 to initialise the BLE stack. + /// + /// This must be called before any BLE commands are sent via the BLE channel (according to + /// AN5289, Figures 65 and 66). It should only be called after CPU2 sends a system event, via + /// `HW_IPCC_SYS_EvtNot`, aka `IoBusCallBackUserEvt` (as detailed in Figure 65), aka [read]. #[cfg(feature = "ble")] pub async fn shci_c2_ble_init(&self, param: ShciBleInitCmdParam) -> Result { self.write_and_get_response(ShciOpcode::BleInit, param.payload()).await } /// `HW_IPCC_SYS_EvtNot` + /// + /// This method takes the place of the `HW_IPCC_SYS_EvtNot`/`SysUserEvtRx`/`APPE_SysUserEvtRx`, + /// as the embassy implementation avoids the need to call C public bindings, and instead + /// handles the event channels directly. pub async fn read(&self) -> EvtBox { Ipcc::receive(channels::cpu2::IPCC_SYSTEM_EVENT_CHANNEL, || unsafe { if let Some(node_ptr) = LinkedListNode::remove_head(SYSTEM_EVT_QUEUE.as_mut_ptr()) { diff --git a/embassy-stm32-wpan/src/tables.rs b/embassy-stm32-wpan/src/tables.rs index f2c250527..e730d6d87 100644 --- a/embassy-stm32-wpan/src/tables.rs +++ b/embassy-stm32-wpan/src/tables.rs @@ -89,12 +89,19 @@ pub struct DeviceInfoTable { pub wireless_fw_info_table: WirelessFwInfoTable, } +/// The bluetooth reference table, as defined in figure 67 of STM32WX AN5289. #[derive(Debug)] #[repr(C)] pub struct BleTable { + /// A pointer to the buffer that is used for sending BLE commands. pub pcmd_buffer: *mut CmdPacket, + /// A pointer to the buffer used for storing Command statuses. pub pcs_buffer: *const u8, + /// A pointer to the event queue, over which IPCC BLE events are sent. This may be accessed via + /// [crate::sub::ble::tl_read]. pub pevt_queue: *const u8, + /// A pointer to the buffer that is used for sending HCI (Host-Controller Interface) ACL + /// (Asynchronous Connection-oriented Logical transport) commands (unused). pub phci_acl_data_buffer: *mut AclDataPacket, } From c967c368769ea2308acbe7e96977e4a1833fad22 Mon Sep 17 00:00:00 2001 From: Lofty Inclination Date: Wed, 1 Jan 2025 00:59:31 +0000 Subject: [PATCH 0564/1217] Make arrow in comment point at magic numbers This got broken during a move, and the arrows weren't pointing at anything meaningful. Not sure what the reason for them existing is, but it's probably better that they be accurate, even if they're still confusing. --- embassy-stm32-wpan/src/tables.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32-wpan/src/tables.rs b/embassy-stm32-wpan/src/tables.rs index e730d6d87..152930ac6 100644 --- a/embassy-stm32-wpan/src/tables.rs +++ b/embassy-stm32-wpan/src/tables.rs @@ -278,6 +278,6 @@ pub static mut BLE_SPARE_EVT_BUF: Aligned> = Aligned(MaybeUninit::uninit()); From 7d387f52a2b9a3bac063665f1b0706af02c7da6c Mon Sep 17 00:00:00 2001 From: Lofty Inclination Date: Wed, 1 Jan 2025 01:14:34 +0000 Subject: [PATCH 0565/1217] fixup! Add docs for the BLE bindings --- embassy-stm32-wpan/src/lib.rs | 7 ++++--- embassy-stm32-wpan/src/sub/ble.rs | 6 +++--- embassy-stm32-wpan/src/sub/sys.rs | 3 ++- embassy-stm32-wpan/src/tables.rs | 2 +- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/embassy-stm32-wpan/src/lib.rs b/embassy-stm32-wpan/src/lib.rs index 1a01be200..00eaac867 100644 --- a/embassy-stm32-wpan/src/lib.rs +++ b/embassy-stm32-wpan/src/lib.rs @@ -73,9 +73,10 @@ impl<'d> TlMbox<'d> { /// Figure 65. /// /// If the `ble` feature is enabled, at this point, the user should call - /// [sys_subsystem.shci_c2_ble_init], before any commands are written to the [ble_subsystem] - /// ([Ble::new()] completes the process that would otherwise be handled by `TL_BLE_Init`; see - /// Figure 66). This completes the procedure laid out in Figure 66. + /// [sys_subsystem.shci_c2_ble_init], before any commands are written to the + /// [TlMbox.ble_subsystem] ([sub::ble::Ble::new()] completes the process that would otherwise + /// be handled by `TL_BLE_Init`; see Figure 66). This completes the procedure laid out in + /// Figure 66. // TODO: document what the user should do after calling init to use the mac_802_15_4 subsystem pub fn init( ipcc: impl Peripheral

+ 'd, diff --git a/embassy-stm32-wpan/src/sub/ble.rs b/embassy-stm32-wpan/src/sub/ble.rs index a47c6a699..37a2f3b0c 100644 --- a/embassy-stm32-wpan/src/sub/ble.rs +++ b/embassy-stm32-wpan/src/sub/ble.rs @@ -14,9 +14,9 @@ use crate::{channels, evt}; /// A guard that, once constructed, may be used to send BLE commands to CPU2. /// /// It is the responsibility of the caller to ensure that they have awaited an event via -/// [crate::sub::Sys::read] before sending any of these commands, and to call -/// [crate::sub::Sys::shci_c2_ble_init] and await the HCI_COMMAND_COMPLETE_EVENT before sending any -/// other commands. +/// [crate::sub::sys::Sys::read] before sending any of these commands, and to call +/// [crate::sub::sys::Sys::shci_c2_ble_init] and await the HCI_COMMAND_COMPLETE_EVENT before +/// sending any other commands. pub struct Ble { _private: (), } diff --git a/embassy-stm32-wpan/src/sub/sys.rs b/embassy-stm32-wpan/src/sub/sys.rs index fcc2c651e..cf6df58bf 100644 --- a/embassy-stm32-wpan/src/sub/sys.rs +++ b/embassy-stm32-wpan/src/sub/sys.rs @@ -91,7 +91,8 @@ impl Sys { /// /// This must be called before any BLE commands are sent via the BLE channel (according to /// AN5289, Figures 65 and 66). It should only be called after CPU2 sends a system event, via - /// `HW_IPCC_SYS_EvtNot`, aka `IoBusCallBackUserEvt` (as detailed in Figure 65), aka [read]. + /// `HW_IPCC_SYS_EvtNot`, aka `IoBusCallBackUserEvt` (as detailed in Figure 65), aka + /// [crate::sub::ble::hci::host::uart::UartHci::read]. #[cfg(feature = "ble")] pub async fn shci_c2_ble_init(&self, param: ShciBleInitCmdParam) -> Result { self.write_and_get_response(ShciOpcode::BleInit, param.payload()).await diff --git a/embassy-stm32-wpan/src/tables.rs b/embassy-stm32-wpan/src/tables.rs index 152930ac6..d374814a3 100644 --- a/embassy-stm32-wpan/src/tables.rs +++ b/embassy-stm32-wpan/src/tables.rs @@ -98,7 +98,7 @@ pub struct BleTable { /// A pointer to the buffer used for storing Command statuses. pub pcs_buffer: *const u8, /// A pointer to the event queue, over which IPCC BLE events are sent. This may be accessed via - /// [crate::sub::ble::tl_read]. + /// [crate::sub::ble::Ble::tl_read]. pub pevt_queue: *const u8, /// A pointer to the buffer that is used for sending HCI (Host-Controller Interface) ACL /// (Asynchronous Connection-oriented Logical transport) commands (unused). From 0318ac83165c253605ec7e0357af0b05e2722e4b Mon Sep 17 00:00:00 2001 From: Lofty Inclination Date: Wed, 1 Jan 2025 01:14:37 +0000 Subject: [PATCH 0566/1217] Escape existing illegal html characters --- embassy-stm32-wpan/src/tables.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/embassy-stm32-wpan/src/tables.rs b/embassy-stm32-wpan/src/tables.rs index d374814a3..fe6fc47a3 100644 --- a/embassy-stm32-wpan/src/tables.rs +++ b/embassy-stm32-wpan/src/tables.rs @@ -25,17 +25,17 @@ pub struct RssInfoTable { /** * Version - * [0:3] = Build - 0: Untracked - 15:Released - x: Tracked version - * [4:7] = branch - 0: Mass Market - x: ... - * [8:15] = Subversion - * [16:23] = Version minor - * [24:31] = Version major + * \[0:3\] = Build - 0: Untracked - 15:Released - x: Tracked version + * \[4:7\] = branch - 0: Mass Market - x: ... + * \[8:15\] = Subversion + * \[16:23\] = Version minor + * \[24:31\] = Version major * * Memory Size - * [0:7] = Flash ( Number of 4k sector) - * [8:15] = Reserved ( Shall be set to 0 - may be used as flash extension ) - * [16:23] = SRAM2b ( Number of 1k sector) - * [24:31] = SRAM2a ( Number of 1k sector) + * \[0:7\] = Flash ( Number of 4k sector) + * \[8:15\] = Reserved ( Shall be set to 0 - may be used as flash extension ) + * \[16:23\] = SRAM2b ( Number of 1k sector) + * \[24:31\] = SRAM2a ( Number of 1k sector) */ #[derive(Debug, Copy, Clone)] #[repr(C, packed)] From 2d5e1e9cfa1cc9168a43ca3409be765e94719a70 Mon Sep 17 00:00:00 2001 From: Lofty Inclination Date: Wed, 1 Jan 2025 01:29:24 +0000 Subject: [PATCH 0567/1217] Remove duplicate command from BLE Gatt Server example --- examples/stm32wb/src/bin/gatt_server.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/examples/stm32wb/src/bin/gatt_server.rs b/examples/stm32wb/src/bin/gatt_server.rs index 1cc50e134..041dc0cf5 100644 --- a/examples/stm32wb/src/bin/gatt_server.rs +++ b/examples/stm32wb/src/bin/gatt_server.rs @@ -151,11 +151,6 @@ async fn main(_spawner: Spawner) { let response = mbox.ble_subsystem.read().await; defmt::debug!("{}", response); - info!("set scan response data..."); - mbox.ble_subsystem.le_set_scan_response_data(b"TXTX").await.unwrap(); - let response = mbox.ble_subsystem.read().await; - defmt::debug!("{}", response); - defmt::info!("initializing services and characteristics..."); let mut ble_context = init_gatt_services(&mut mbox.ble_subsystem).await.unwrap(); defmt::info!("{}", ble_context); From 81948b3f2f0cf8f5b671b05e8d16f077ad4483bd Mon Sep 17 00:00:00 2001 From: Lofty Inclination Date: Wed, 1 Jan 2025 01:30:43 +0000 Subject: [PATCH 0568/1217] Add crate description --- embassy-stm32-wpan/src/lib.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/embassy-stm32-wpan/src/lib.rs b/embassy-stm32-wpan/src/lib.rs index 00eaac867..25e6d965a 100644 --- a/embassy-stm32-wpan/src/lib.rs +++ b/embassy-stm32-wpan/src/lib.rs @@ -1,3 +1,16 @@ +//! The embassy-stm32-wpan crate aims to provide safe use of the commands necessary to interface +//! with the Cortex C0 CPU2 coprocessor of STM32WB microcontrollers. It implements safe wrappers +//! around the Transport Layer, and in particular the system, memory, BLE and Mac channels. +//! +//! # Design +//! +//! This crate loosely follows the Application Note 5289 "How to build wireless applications with +//! STM32WB MCUs"; several of the startup procedures laid out in Annex 14.1 are implemented using +//! inline copies of the code contained within the `stm32wb_copro` C library. +//! +//! BLE commands are implemented via use of the [stm32wb_hci] crate, for which the +//! [stm32wb_hci::Controller] trait has been implemented. + #![no_std] #![allow(async_fn_in_trait)] #![doc = include_str!("../README.md")] From c6e0508da0e5a8689b833c60e0d8e59b922ebd8f Mon Sep 17 00:00:00 2001 From: Lofty Inclination Date: Wed, 1 Jan 2025 01:31:03 +0000 Subject: [PATCH 0569/1217] Add example to doc for BLE initialisation --- embassy-stm32-wpan/src/sub/ble.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/embassy-stm32-wpan/src/sub/ble.rs b/embassy-stm32-wpan/src/sub/ble.rs index 37a2f3b0c..0f770d92c 100644 --- a/embassy-stm32-wpan/src/sub/ble.rs +++ b/embassy-stm32-wpan/src/sub/ble.rs @@ -17,6 +17,25 @@ use crate::{channels, evt}; /// [crate::sub::sys::Sys::read] before sending any of these commands, and to call /// [crate::sub::sys::Sys::shci_c2_ble_init] and await the HCI_COMMAND_COMPLETE_EVENT before /// sending any other commands. +/// +/// # Example +/// +/// ``` +/// # embassy_stm32::bind_interrupts!(struct Irqs{ +/// # IPCC_C1_RX => ReceiveInterruptHandler; +/// # IPCC_C1_TX => TransmitInterruptHandler; +/// # }); +/// # +/// # let p = embassy_stm32::init(embassy_stm32::Config::default()); +/// # let mut mbox = embassy_stm32_wpan::TlMbox::init(p.IPCC, Irqs, embassy_stm32::ipcc::Config::default()); +/// # +/// # let sys_event = mbox.sys_subsystem.read().await; +/// # let _command_status = mbox.sys_subsystem.shci_c2_ble_init(Default::default()); +/// # // BLE commands may now be sent +/// # +/// # mbox.ble_subsystem.reset().await; +/// # let _reset_response = mbox.ble_subsystem.read().await; +/// ``` pub struct Ble { _private: (), } From cbc7a9fe5b9bfda8a53316cd231d6a4b7a3bbfd9 Mon Sep 17 00:00:00 2001 From: Liu Hancheng Date: Wed, 1 Jan 2025 17:05:48 +0800 Subject: [PATCH 0570/1217] feat: Add 32-bit timer support for waveform function --- embassy-stm32/src/timer/low_level.rs | 4 +++ embassy-stm32/src/timer/simple_pwm.rs | 39 ++++++++++++++++++++------- 2 files changed, 34 insertions(+), 9 deletions(-) diff --git a/embassy-stm32/src/timer/low_level.rs b/embassy-stm32/src/timer/low_level.rs index 7360d6aef..448069ab3 100644 --- a/embassy-stm32/src/timer/low_level.rs +++ b/embassy-stm32/src/timer/low_level.rs @@ -235,6 +235,10 @@ impl<'d, T: CoreInstance> Timer<'d, T> { self.regs_core().cnt().write(|r| r.set_cnt(0)); } + pub fn get_bits(&self) -> TimerBits { + T::BITS + } + /// Set the frequency of how many times per second the timer counts up to the max value or down to 0. /// /// This means that in the default edge-aligned mode, diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs index 56fb1871e..c6808593a 100644 --- a/embassy-stm32/src/timer/simple_pwm.rs +++ b/embassy-stm32/src/timer/simple_pwm.rs @@ -6,6 +6,7 @@ use core::mem::ManuallyDrop; use embassy_hal_internal::{into_ref, PeripheralRef}; use super::low_level::{CountingMode, OutputCompareMode, OutputPolarity, Timer}; +use super::TimerBits; use super::{Channel, Channel1Pin, Channel2Pin, Channel3Pin, Channel4Pin, GeneralInstance4Channel}; use crate::gpio::{AfType, AnyPin, OutputType, Speed}; use crate::time::Hertz; @@ -365,7 +366,7 @@ macro_rules! impl_waveform_chx { /// /// Note: /// you will need to provide corresponding TIMx_CHy DMA channel to use this method. - pub async fn $fn_name(&mut self, dma: impl Peripheral

>, duty: &[u16]) { + pub async fn $fn_name(&mut self, dma: impl Peripheral

>, duty: &[u8]) { use crate::pac::timer::vals::Ccds; into_ref!(dma); @@ -406,14 +407,34 @@ macro_rules! impl_waveform_chx { ..Default::default() }; - Transfer::new_write( - &mut dma, - req, - duty, - self.inner.regs_gp16().ccr(cc_channel.index()).as_ptr() as *mut _, - dma_transfer_option, - ) - .await + match self.inner.get_bits() { + TimerBits::Bits16 => { + // the data must be aligned to double words + assert!(duty.len() % 2 == 0); + let duty = core::slice::from_raw_parts(duty.as_ptr() as *const u16, duty.len() / 2); + Transfer::new_write( + &mut dma, + req, + duty, + self.inner.regs_gp16().ccr(cc_channel.index()).as_ptr() as *mut _, + dma_transfer_option, + ) + .await + } + TimerBits::Bits32 => { + // the data must be aligned to quad words + assert!(duty.len() % 4 == 0); + let duty = core::slice::from_raw_parts(duty.as_ptr() as *const u32, duty.len() / 4); + Transfer::new_write( + &mut dma, + req, + duty, + self.inner.regs_gp16().ccr(cc_channel.index()).as_ptr() as *mut _, + dma_transfer_option, + ) + .await + } + }; }; // restore output compare state From 89a1346d0098791cde9579597a13f2c059887094 Mon Sep 17 00:00:00 2001 From: Liu Hancheng Date: Wed, 1 Jan 2025 17:17:23 +0800 Subject: [PATCH 0571/1217] docs: Update PWM waveform function documentation for data alignment --- embassy-stm32/src/timer/simple_pwm.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs index c6808593a..cce9f619a 100644 --- a/embassy-stm32/src/timer/simple_pwm.rs +++ b/embassy-stm32/src/timer/simple_pwm.rs @@ -365,7 +365,10 @@ macro_rules! impl_waveform_chx { /// Generate a sequence of PWM waveform /// /// Note: - /// you will need to provide corresponding TIMx_CHy DMA channel to use this method. + /// 1. you will need to provide corresponding TIMx_CHy DMA channel to use this method. + /// 2. Please make sure the duty data length is aligned to the timer data width(16-bit or 32-bit). + /// 3. Please notice the endianess of the duty data. STM32 use little endian, + /// for example, 0x12345678 as u32 will be stored as [0x78, 0x56, 0x34, 0x12] in memory. pub async fn $fn_name(&mut self, dma: impl Peripheral

>, duty: &[u8]) { use crate::pac::timer::vals::Ccds; From 99ce2853979a22e3f4573ea7f06db957a41f0a35 Mon Sep 17 00:00:00 2001 From: Liu Hancheng Date: Wed, 1 Jan 2025 17:21:33 +0800 Subject: [PATCH 0572/1217] refactor: change import style --- embassy-stm32/src/timer/simple_pwm.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs index cce9f619a..e3c790213 100644 --- a/embassy-stm32/src/timer/simple_pwm.rs +++ b/embassy-stm32/src/timer/simple_pwm.rs @@ -6,8 +6,7 @@ use core::mem::ManuallyDrop; use embassy_hal_internal::{into_ref, PeripheralRef}; use super::low_level::{CountingMode, OutputCompareMode, OutputPolarity, Timer}; -use super::TimerBits; -use super::{Channel, Channel1Pin, Channel2Pin, Channel3Pin, Channel4Pin, GeneralInstance4Channel}; +use super::{Channel, Channel1Pin, Channel2Pin, Channel3Pin, Channel4Pin, GeneralInstance4Channel, TimerBits}; use crate::gpio::{AfType, AnyPin, OutputType, Speed}; use crate::time::Hertz; use crate::Peripheral; From e2c866119f941a1fa54e95b91076d1e299757bdb Mon Sep 17 00:00:00 2001 From: Liu Hancheng Date: Wed, 1 Jan 2025 17:24:00 +0800 Subject: [PATCH 0573/1217] doc: add doc for timer get_bits fn --- embassy-stm32/src/timer/low_level.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/embassy-stm32/src/timer/low_level.rs b/embassy-stm32/src/timer/low_level.rs index 448069ab3..a9c6dc303 100644 --- a/embassy-stm32/src/timer/low_level.rs +++ b/embassy-stm32/src/timer/low_level.rs @@ -235,6 +235,7 @@ impl<'d, T: CoreInstance> Timer<'d, T> { self.regs_core().cnt().write(|r| r.set_cnt(0)); } + /// get the capability of the timer pub fn get_bits(&self) -> TimerBits { T::BITS } From a3a8dee57906bffdd2a6f29c46abab48bfe0b2c3 Mon Sep 17 00:00:00 2001 From: Liu Hancheng Date: Wed, 1 Jan 2025 17:28:37 +0800 Subject: [PATCH 0574/1217] refactor: exclude stm32l0 for 32bit timer branch Signed-off-by: Liu Hancheng --- embassy-stm32/src/timer/simple_pwm.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs index e3c790213..0fc2a1bf0 100644 --- a/embassy-stm32/src/timer/simple_pwm.rs +++ b/embassy-stm32/src/timer/simple_pwm.rs @@ -423,6 +423,7 @@ macro_rules! impl_waveform_chx { ) .await } + #[cfg(not(stm32l0))] TimerBits::Bits32 => { // the data must be aligned to quad words assert!(duty.len() % 4 == 0); From e012e1385814647e1c17cb64175a19745c18bb8f Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Wed, 1 Jan 2025 19:47:39 +0100 Subject: [PATCH 0575/1217] Ensure alarm is re-scheduled if timetamp is in the past Fixes #3672 --- embassy-nrf/src/time_driver.rs | 82 ++++++++++++++++++---------------- 1 file changed, 44 insertions(+), 38 deletions(-) diff --git a/embassy-nrf/src/time_driver.rs b/embassy-nrf/src/time_driver.rs index ade6fd2a1..01079e26a 100644 --- a/embassy-nrf/src/time_driver.rs +++ b/embassy-nrf/src/time_driver.rs @@ -209,47 +209,53 @@ impl RtcDriver { let r = rtc(); - let t = self.now(); - if timestamp <= t { - // If alarm timestamp has passed the alarm will not fire. - // Disarm the alarm and return `false` to indicate that. - r.intenclr().write(|w| w.0 = compare_n(n)); + loop { + let t = self.now(); + if timestamp <= t { + // If alarm timestamp has passed the alarm will not fire. + // Disarm the alarm and return `false` to indicate that. + r.intenclr().write(|w| w.0 = compare_n(n)); - alarm.timestamp.set(u64::MAX); + alarm.timestamp.set(u64::MAX); - return false; + return false; + } + + // If it hasn't triggered yet, setup it in the compare channel. + + // Write the CC value regardless of whether we're going to enable it now or not. + // This way, when we enable it later, the right value is already set. + + // nrf52 docs say: + // If the COUNTER is N, writing N or N+1 to a CC register may not trigger a COMPARE event. + // To workaround this, we never write a timestamp smaller than N+3. + // N+2 is not safe because rtc can tick from N to N+1 between calling now() and writing cc. + // + // It is impossible for rtc to tick more than once because + // - this code takes less time than 1 tick + // - it runs with interrupts disabled so nothing else can preempt it. + // + // This means that an alarm can be delayed for up to 2 ticks (from t+1 to t+3), but this is allowed + // by the Alarm trait contract. What's not allowed is triggering alarms *before* their scheduled time, + // and we don't do that here. + let safe_timestamp = timestamp.max(t + 3); + r.cc(n).write(|w| w.set_compare(safe_timestamp as u32 & 0xFFFFFF)); + + let diff = timestamp - t; + if diff < 0xc00000 { + r.intenset().write(|w| w.0 = compare_n(n)); + } else { + // If it's too far in the future, don't setup the compare channel yet. + // It will be setup later by `next_period`. + r.intenclr().write(|w| w.0 = compare_n(n)); + } + + // If we have not passed the safe timestamp, we can be sure the alarm will be invoked. Otherwise, + // we need to retry setting the alarm. + if self.now() <= safe_timestamp { + return true; + } } - - // If it hasn't triggered yet, setup it in the compare channel. - - // Write the CC value regardless of whether we're going to enable it now or not. - // This way, when we enable it later, the right value is already set. - - // nrf52 docs say: - // If the COUNTER is N, writing N or N+1 to a CC register may not trigger a COMPARE event. - // To workaround this, we never write a timestamp smaller than N+3. - // N+2 is not safe because rtc can tick from N to N+1 between calling now() and writing cc. - // - // It is impossible for rtc to tick more than once because - // - this code takes less time than 1 tick - // - it runs with interrupts disabled so nothing else can preempt it. - // - // This means that an alarm can be delayed for up to 2 ticks (from t+1 to t+3), but this is allowed - // by the Alarm trait contract. What's not allowed is triggering alarms *before* their scheduled time, - // and we don't do that here. - let safe_timestamp = timestamp.max(t + 3); - r.cc(n).write(|w| w.set_compare(safe_timestamp as u32 & 0xFFFFFF)); - - let diff = timestamp - t; - if diff < 0xc00000 { - r.intenset().write(|w| w.0 = compare_n(n)); - } else { - // If it's too far in the future, don't setup the compare channel yet. - // It will be setup later by `next_period`. - r.intenclr().write(|w| w.0 = compare_n(n)); - } - - true } } From b5ef53ac1349d2c96f37c5186c2f4945604767be Mon Sep 17 00:00:00 2001 From: Bart Massey Date: Tue, 31 Dec 2024 15:15:11 -0800 Subject: [PATCH 0576/1217] gave examples/std a cleaner and more informational Hello --- examples/std/src/bin/net.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/examples/std/src/bin/net.rs b/examples/std/src/bin/net.rs index cefa5448c..6e50b1a01 100644 --- a/examples/std/src/bin/net.rs +++ b/examples/std/src/bin/net.rs @@ -1,3 +1,5 @@ +use core::fmt::Write as _; + use clap::Parser; use embassy_executor::{Executor, Spawner}; use embassy_net::tcp::TcpSocket; @@ -71,8 +73,10 @@ async fn main_task(spawner: Spawner) { return; } info!("connected!"); - loop { - let r = socket.write_all(b"Hello!\n").await; + for i in 0.. { + let mut buf = heapless::String::<100>::new(); + write!(buf, "Hello! ({})\r\n", i).unwrap(); + let r = socket.write_all(buf.as_bytes()).await; if let Err(e) = r { warn!("write error: {:?}", e); return; From 90b41644261440a535c35c1c75c22ce2606c5037 Mon Sep 17 00:00:00 2001 From: Liu Hancheng Date: Thu, 2 Jan 2025 12:47:13 +0800 Subject: [PATCH 0577/1217] dev: change name to bits --- embassy-stm32/src/timer/low_level.rs | 2 +- embassy-stm32/src/timer/simple_pwm.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/timer/low_level.rs b/embassy-stm32/src/timer/low_level.rs index a9c6dc303..796c33a27 100644 --- a/embassy-stm32/src/timer/low_level.rs +++ b/embassy-stm32/src/timer/low_level.rs @@ -236,7 +236,7 @@ impl<'d, T: CoreInstance> Timer<'d, T> { } /// get the capability of the timer - pub fn get_bits(&self) -> TimerBits { + pub fn bits(&self) -> TimerBits { T::BITS } diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs index 0fc2a1bf0..f36fa026c 100644 --- a/embassy-stm32/src/timer/simple_pwm.rs +++ b/embassy-stm32/src/timer/simple_pwm.rs @@ -409,7 +409,7 @@ macro_rules! impl_waveform_chx { ..Default::default() }; - match self.inner.get_bits() { + match self.inner.bits() { TimerBits::Bits16 => { // the data must be aligned to double words assert!(duty.len() % 2 == 0); From 9e9fa1cbefcd12bf3f645c02630b1566df864376 Mon Sep 17 00:00:00 2001 From: Ian McKernan Date: Wed, 1 Jan 2025 21:47:44 -0800 Subject: [PATCH 0578/1217] added fix for https://github.com/embassy-rs/embassy/issues/2496 in the v1 driver --- embassy-stm32/src/eth/v1/mod.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/embassy-stm32/src/eth/v1/mod.rs b/embassy-stm32/src/eth/v1/mod.rs index cce75ece7..693355593 100644 --- a/embassy-stm32/src/eth/v1/mod.rs +++ b/embassy-stm32/src/eth/v1/mod.rs @@ -163,6 +163,11 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> { // TODO: Carrier sense ? ECRSFD }); + // Set the mac to pass all multicast packets + mac.macffr().modify(|w| { + w.set_pam(true); + }); + // Note: Writing to LR triggers synchronisation of both LR and HR into the MAC core, // so the LR write must happen after the HR write. mac.maca0hr() From 28d58578d69cc80653cf0620cbd22385749a5eb1 Mon Sep 17 00:00:00 2001 From: Ian McKernan Date: Wed, 1 Jan 2025 21:59:29 -0800 Subject: [PATCH 0579/1217] remove trailing space from comment --- embassy-stm32/src/eth/v1/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/src/eth/v1/mod.rs b/embassy-stm32/src/eth/v1/mod.rs index 693355593..b96275cb7 100644 --- a/embassy-stm32/src/eth/v1/mod.rs +++ b/embassy-stm32/src/eth/v1/mod.rs @@ -163,7 +163,7 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> { // TODO: Carrier sense ? ECRSFD }); - // Set the mac to pass all multicast packets + // Set the mac to pass all multicast packets mac.macffr().modify(|w| { w.set_pam(true); }); From 9c7d508bcf3384ab0883c7ef710e485106ccbb6c Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Thu, 2 Jan 2025 11:59:57 +0100 Subject: [PATCH 0580/1217] Fix case where a short interrupt caused wrong alarm set --- embassy-nrf/src/time_driver.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-nrf/src/time_driver.rs b/embassy-nrf/src/time_driver.rs index 01079e26a..ad61f5ca7 100644 --- a/embassy-nrf/src/time_driver.rs +++ b/embassy-nrf/src/time_driver.rs @@ -250,9 +250,9 @@ impl RtcDriver { r.intenclr().write(|w| w.0 = compare_n(n)); } - // If we have not passed the safe timestamp, we can be sure the alarm will be invoked. Otherwise, + // If we have not passed the timestamp, we can be sure the alarm will be invoked. Otherwise, // we need to retry setting the alarm. - if self.now() <= safe_timestamp { + if self.now() + 3 <= timestamp { return true; } } From 06901c3279430a40a449e5944e8ba3788388deb7 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Thu, 2 Jan 2025 12:03:03 +0100 Subject: [PATCH 0581/1217] Update comment to reflect reality --- embassy-nrf/src/time_driver.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/embassy-nrf/src/time_driver.rs b/embassy-nrf/src/time_driver.rs index ad61f5ca7..b8c19014e 100644 --- a/embassy-nrf/src/time_driver.rs +++ b/embassy-nrf/src/time_driver.rs @@ -231,9 +231,9 @@ impl RtcDriver { // To workaround this, we never write a timestamp smaller than N+3. // N+2 is not safe because rtc can tick from N to N+1 between calling now() and writing cc. // - // It is impossible for rtc to tick more than once because - // - this code takes less time than 1 tick - // - it runs with interrupts disabled so nothing else can preempt it. + // Since the critical section does not guarantee that a higher prio interrupt causes + // this to be delayed, we need to re-check how much time actually passed after setting the + // alarm, and retry if we are within the unsafe interval still. // // This means that an alarm can be delayed for up to 2 ticks (from t+1 to t+3), but this is allowed // by the Alarm trait contract. What's not allowed is triggering alarms *before* their scheduled time, From 422938745a03ae36ffc058ff28011fe15dff2d00 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Thu, 2 Jan 2025 12:53:55 +0100 Subject: [PATCH 0582/1217] Move safeguard if compare irq is enabled --- embassy-nrf/src/time_driver.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/embassy-nrf/src/time_driver.rs b/embassy-nrf/src/time_driver.rs index b8c19014e..61ae96718 100644 --- a/embassy-nrf/src/time_driver.rs +++ b/embassy-nrf/src/time_driver.rs @@ -244,15 +244,16 @@ impl RtcDriver { let diff = timestamp - t; if diff < 0xc00000 { r.intenset().write(|w| w.0 = compare_n(n)); + + // If we have not passed the timestamp, we can be sure the alarm will be invoked. Otherwise, + // we need to retry setting the alarm. + if self.now() + 3 <= timestamp { + return true; + } } else { // If it's too far in the future, don't setup the compare channel yet. // It will be setup later by `next_period`. r.intenclr().write(|w| w.0 = compare_n(n)); - } - - // If we have not passed the timestamp, we can be sure the alarm will be invoked. Otherwise, - // we need to retry setting the alarm. - if self.now() + 3 <= timestamp { return true; } } From 92d67c3ccda06fecf5864a90fe1a74be8495bd36 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Thu, 2 Jan 2025 13:35:55 +0100 Subject: [PATCH 0583/1217] Relax timestamp check --- embassy-nrf/src/time_driver.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-nrf/src/time_driver.rs b/embassy-nrf/src/time_driver.rs index 61ae96718..03f4c2e2b 100644 --- a/embassy-nrf/src/time_driver.rs +++ b/embassy-nrf/src/time_driver.rs @@ -247,7 +247,7 @@ impl RtcDriver { // If we have not passed the timestamp, we can be sure the alarm will be invoked. Otherwise, // we need to retry setting the alarm. - if self.now() + 3 <= timestamp { + if self.now() + 2 <= timestamp { return true; } } else { From 3aca6150251a6bab6592a1c3173324e3c6eb9416 Mon Sep 17 00:00:00 2001 From: lonesometraveler Date: Thu, 2 Jan 2025 10:28:29 -0500 Subject: [PATCH 0584/1217] Fix broken link to WIZnet W5500-EVB-Pico --- examples/rp/src/bin/ethernet_w5500_multisocket.rs | 2 +- examples/rp/src/bin/ethernet_w5500_tcp_client.rs | 2 +- examples/rp/src/bin/ethernet_w5500_tcp_server.rs | 2 +- examples/rp/src/bin/ethernet_w5500_udp.rs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/rp/src/bin/ethernet_w5500_multisocket.rs b/examples/rp/src/bin/ethernet_w5500_multisocket.rs index 12003adbe..2bea9fc9d 100644 --- a/examples/rp/src/bin/ethernet_w5500_multisocket.rs +++ b/examples/rp/src/bin/ethernet_w5500_multisocket.rs @@ -1,6 +1,6 @@ //! This example shows how you can allow multiple simultaneous TCP connections, by having multiple sockets listening on the same port. //! -//! Example written for the [`WIZnet W5500-EVB-Pico`](https://www.wiznet.io/product-item/w5500-evb-pico/) board. +//! Example written for the [`WIZnet W5500-EVB-Pico`](https://docs.wiznet.io/Product/iEthernet/W5500/w5500-evb-pico) board. #![no_std] #![no_main] diff --git a/examples/rp/src/bin/ethernet_w5500_tcp_client.rs b/examples/rp/src/bin/ethernet_w5500_tcp_client.rs index d66a43a88..78d1b0b83 100644 --- a/examples/rp/src/bin/ethernet_w5500_tcp_client.rs +++ b/examples/rp/src/bin/ethernet_w5500_tcp_client.rs @@ -1,6 +1,6 @@ //! This example implements a TCP client that attempts to connect to a host on port 1234 and send it some data once per second. //! -//! Example written for the [`WIZnet W5500-EVB-Pico`](https://www.wiznet.io/product-item/w5500-evb-pico/) board. +//! Example written for the [`WIZnet W5500-EVB-Pico`](https://docs.wiznet.io/Product/iEthernet/W5500/w5500-evb-pico) board. #![no_std] #![no_main] diff --git a/examples/rp/src/bin/ethernet_w5500_tcp_server.rs b/examples/rp/src/bin/ethernet_w5500_tcp_server.rs index 97d9bd4c9..25a38c714 100644 --- a/examples/rp/src/bin/ethernet_w5500_tcp_server.rs +++ b/examples/rp/src/bin/ethernet_w5500_tcp_server.rs @@ -1,7 +1,7 @@ //! This example implements a TCP echo server on port 1234 and using DHCP. //! Send it some data, you should see it echoed back and printed in the console. //! -//! Example written for the [`WIZnet W5500-EVB-Pico`](https://www.wiznet.io/product-item/w5500-evb-pico/) board. +//! Example written for the [`WIZnet W5500-EVB-Pico`](https://docs.wiznet.io/Product/iEthernet/W5500/w5500-evb-pico) board. #![no_std] #![no_main] diff --git a/examples/rp/src/bin/ethernet_w5500_udp.rs b/examples/rp/src/bin/ethernet_w5500_udp.rs index b1b5f9758..683e29222 100644 --- a/examples/rp/src/bin/ethernet_w5500_udp.rs +++ b/examples/rp/src/bin/ethernet_w5500_udp.rs @@ -1,6 +1,6 @@ //! This example implements a UDP server listening on port 1234 and echoing back the data. //! -//! Example written for the [`WIZnet W5500-EVB-Pico`](https://www.wiznet.io/product-item/w5500-evb-pico/) board. +//! Example written for the [`WIZnet W5500-EVB-Pico`](https://docs.wiznet.io/Product/iEthernet/W5500/w5500-evb-pico) board. #![no_std] #![no_main] From 1de400bdcbb8b0872dc1fc03b66cfcb42017affd Mon Sep 17 00:00:00 2001 From: Karim <112777959+karimpanacci@users.noreply.github.com> Date: Tue, 10 Dec 2024 20:24:16 +0100 Subject: [PATCH 0585/1217] Fix ScanType enum export Exports the ScanType enum, which is needed to build the ScanOptions struct --- cyw43/src/control.rs | 5 +++++ cyw43/src/lib.rs | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/cyw43/src/control.rs b/cyw43/src/control.rs index 071ba88e4..888cf4b90 100644 --- a/cyw43/src/control.rs +++ b/cyw43/src/control.rs @@ -35,10 +35,15 @@ pub struct Control<'a> { ioctl_state: &'a IoctlState, } +/// WiFi scan type. #[derive(Copy, Clone, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum ScanType { + /// Active scan: the station actively transmits probes that make APs respond. + /// Faster, but uses more power. Active, + /// Passive scan: the station doesn't transmit any probes, just listens for beacons. + /// Slower, but uses less power. Passive, } diff --git a/cyw43/src/lib.rs b/cyw43/src/lib.rs index 3cd0e4988..aab13d8b8 100644 --- a/cyw43/src/lib.rs +++ b/cyw43/src/lib.rs @@ -30,7 +30,7 @@ use ioctl::IoctlState; use crate::bus::Bus; pub use crate::bus::SpiBusCyw43; pub use crate::control::{ - AddMulticastAddressError, Control, Error as ControlError, JoinAuth, JoinOptions, ScanOptions, Scanner, + AddMulticastAddressError, Control, Error as ControlError, JoinAuth, JoinOptions, ScanOptions, ScanType, Scanner, }; pub use crate::runner::Runner; pub use crate::structs::BssInfo; From 41790316eb06a02b909b99df2c4fd5c0bc855445 Mon Sep 17 00:00:00 2001 From: James Munns Date: Thu, 2 Jan 2025 18:23:34 +0100 Subject: [PATCH 0586/1217] Add note for nRF52840-dk board details --- examples/nrf52840/src/bin/pwm_sequence_ws2812b.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/examples/nrf52840/src/bin/pwm_sequence_ws2812b.rs b/examples/nrf52840/src/bin/pwm_sequence_ws2812b.rs index 751cf4425..6f04a53b8 100644 --- a/examples/nrf52840/src/bin/pwm_sequence_ws2812b.rs +++ b/examples/nrf52840/src/bin/pwm_sequence_ws2812b.rs @@ -14,6 +14,16 @@ use {defmt_rtt as _, panic_probe as _}; // https://cdn-shop.adafruit.com/datasheets/WS2812B.pdf. // This demo lights up a single LED in blue. It then proceeds // to pulsate the LED rapidly. +// +// /!\ NOTE FOR nRF52840-DK users /!\ +// +// If you're using the nRF52840-DK, the default "Vdd" power source +// will set the GPIO I/O voltage to 3.0v, using the onboard regulator. +// This can sometimes not be enough to drive the WS2812B signal if you +// are not using an external regulator. If you set the board to "USB" power +// instead (and provide power via the "nRF USB" connector), the board will +// instead power the I/Os at 3.3v, which is often enough (but still out of +// official spec) for the WS2812Bs to work properly. // In the following declarations, setting the high bit tells the PWM // to reverse polarity, which is what the WS2812B expects. From 5c74e6085c24d8808433fa8862c7eecb4ff767ba Mon Sep 17 00:00:00 2001 From: James Munns Date: Thu, 2 Jan 2025 18:25:39 +0100 Subject: [PATCH 0587/1217] Clarify --- examples/nrf52840/src/bin/pwm_sequence_ws2812b.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/nrf52840/src/bin/pwm_sequence_ws2812b.rs b/examples/nrf52840/src/bin/pwm_sequence_ws2812b.rs index 6f04a53b8..df8da8800 100644 --- a/examples/nrf52840/src/bin/pwm_sequence_ws2812b.rs +++ b/examples/nrf52840/src/bin/pwm_sequence_ws2812b.rs @@ -20,10 +20,10 @@ use {defmt_rtt as _, panic_probe as _}; // If you're using the nRF52840-DK, the default "Vdd" power source // will set the GPIO I/O voltage to 3.0v, using the onboard regulator. // This can sometimes not be enough to drive the WS2812B signal if you -// are not using an external regulator. If you set the board to "USB" power -// instead (and provide power via the "nRF USB" connector), the board will -// instead power the I/Os at 3.3v, which is often enough (but still out of -// official spec) for the WS2812Bs to work properly. +// are not using an external level shifter. If you set the board to "USB" +// power instead (and provide power via the "nRF USB" connector), the board +// will instead power the I/Os at 3.3v, which is often enough (but still +// out of official spec) for the WS2812Bs to work properly. // In the following declarations, setting the high bit tells the PWM // to reverse polarity, which is what the WS2812B expects. From cefdbfab2f1efb0797f661a9d8cc0aa686fe881a Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 2 Jan 2025 18:57:40 +0100 Subject: [PATCH 0588/1217] Release embassy-executor v0.7.0, embassy-time v0.4.0, embassy-time-driver v0.2.0. --- embassy-executor/CHANGELOG.md | 9 ++++----- embassy-time-driver/CHANGELOG.md | 2 +- embassy-time/CHANGELOG.md | 3 ++- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/embassy-executor/CHANGELOG.md b/embassy-executor/CHANGELOG.md index ee8003a54..2c7f8c62e 100644 --- a/embassy-executor/CHANGELOG.md +++ b/embassy-executor/CHANGELOG.md @@ -5,13 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## 0.7.0 - 2024-12-22 +## 0.7.0 - 2024-01-02 -- embassy-executor no longer provides an `embassy-time-queue-driver` implementation +- Performance optimizations. +- Remove feature `integrated-timers`. Starting with `embassy-time-driver` v0.2, `embassy-time` v0.4 the timer queue is now part of the time driver, so it's no longer the executor's responsibility. Therefore, `embassy-executor` no longer provides an `embassy-time-queue-driver` implementation. +- Added the possibility for timer driver implementations to store arbitrary data in task headers. This can be used to make a timer queue intrusive list, similar to the previous `integrated-timers` feature. Payload size is controlled by the `timer-item-payload-size-X` features. - Added `TaskRef::executor` to obtain a reference to a task's executor -- integrated-timers are no longer processed when polling the executor. -- Added the option to store data in timer queue items -- Added `timer-item-payload-size-X` features for time driver implementors ## 0.6.3 - 2024-11-12 diff --git a/embassy-time-driver/CHANGELOG.md b/embassy-time-driver/CHANGELOG.md index 30d56fd56..e251a6020 100644 --- a/embassy-time-driver/CHANGELOG.md +++ b/embassy-time-driver/CHANGELOG.md @@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## 0.2.0 - 2024-12-22 +## 0.2.0 - 2024-01-02 - The `allocate_alarm`, `set_alarm_callback`, `set_alarm` functions have been removed. - `schedule_wake` has been added to the `Driver` trait. diff --git a/embassy-time/CHANGELOG.md b/embassy-time/CHANGELOG.md index cd4c1afcb..215ec27af 100644 --- a/embassy-time/CHANGELOG.md +++ b/embassy-time/CHANGELOG.md @@ -5,8 +5,9 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## 0.4.0 - 2024-12-22 +## 0.4.0 - 2024-01-02 +- `embassy-time-driver` updated from v0.1 to v0.2. - embassy-time no longer provides an `embassy-time-queue-driver` implementation ## 0.3.2 - 2024-08-05 From f1ffbf2f7edc2afbf83ce75c7a3e0f59da09de00 Mon Sep 17 00:00:00 2001 From: chanterheld Date: Thu, 2 Jan 2025 20:05:01 +0100 Subject: [PATCH 0589/1217] embassy-stm32. support g0 second flash bank --- embassy-stm32/src/flash/g.rs | 18 ++++++++++++++++-- embassy-stm32/src/flash/mod.rs | 4 ++-- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/embassy-stm32/src/flash/g.rs b/embassy-stm32/src/flash/g.rs index 01a0c603f..d02e1435d 100644 --- a/embassy-stm32/src/flash/g.rs +++ b/embassy-stm32/src/flash/g.rs @@ -20,7 +20,7 @@ pub(crate) unsafe fn lock() { } pub(crate) unsafe fn unlock() { // Wait, while the memory interface is busy. - while pac::FLASH.sr().read().bsy() {} + wait_busy(); // Unlock flash if pac::FLASH.cr().read().lock() { @@ -53,12 +53,16 @@ pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> { let idx = (sector.start - super::FLASH_BASE as u32) / super::BANK1_REGION.erase_size as u32; - while pac::FLASH.sr().read().bsy() {} + wait_busy(); clear_all_err(); interrupt::free(|_| { pac::FLASH.cr().modify(|w| { w.set_per(true); + w.set_bker(sector.bank == crate::flash::FlashBank::Bank2); + #[cfg(flash_g0x0)] + w.set_pnb(idx as u16); + #[cfg(not(flash_g0x0))] w.set_pnb(idx as u8); w.set_strt(true); }); @@ -94,3 +98,13 @@ pub(crate) unsafe fn clear_all_err() { // This clears all "write 1 to clear" bits. pac::FLASH.sr().modify(|_| {}); } + +#[cfg(any(flash_g0x0, flash_g0x1))] +fn wait_busy(){ + while pac::FLASH.sr().read().bsy() & pac::FLASH.sr().read().bsy2() {} +} + +#[cfg(not(any(flash_g0x0, flash_g0x1)))] +fn wait_busy(){ + while pac::FLASH.sr().read().bsy() {} +} \ No newline at end of file diff --git a/embassy-stm32/src/flash/mod.rs b/embassy-stm32/src/flash/mod.rs index 88fe6a291..a7eb3fbcc 100644 --- a/embassy-stm32/src/flash/mod.rs +++ b/embassy-stm32/src/flash/mod.rs @@ -97,7 +97,7 @@ pub enum FlashBank { #[cfg_attr(flash_f2, path = "f2.rs")] #[cfg_attr(flash_f4, path = "f4.rs")] #[cfg_attr(flash_f7, path = "f7.rs")] -#[cfg_attr(any(flash_g0, flash_g4c2, flash_g4c3, flash_g4c4), path = "g.rs")] +#[cfg_attr(any(flash_g0x0, flash_g0x1, flash_g4c2, flash_g4c3, flash_g4c4), path = "g.rs")] #[cfg_attr(flash_h7, path = "h7.rs")] #[cfg_attr(flash_h7ab, path = "h7.rs")] #[cfg_attr(flash_u5, path = "u5.rs")] @@ -107,7 +107,7 @@ pub enum FlashBank { #[cfg_attr( not(any( flash_l0, flash_l1, flash_l4, flash_l5, flash_wl, flash_wb, flash_f0, flash_f1, flash_f2, flash_f3, flash_f4, - flash_f7, flash_g0, flash_g4c2, flash_g4c3, flash_g4c4, flash_h7, flash_h7ab, flash_u5, flash_h50, flash_u0, + flash_f7, flash_g0x0, flash_g0x1, flash_g4c2, flash_g4c3, flash_g4c4, flash_h7, flash_h7ab, flash_u5, flash_h50, flash_u0, flash_h5, )), path = "other.rs" From 18386fed64f532aa4c727eca3851db7f8cc2a9d9 Mon Sep 17 00:00:00 2001 From: chanterheld Date: Thu, 2 Jan 2025 20:15:15 +0100 Subject: [PATCH 0590/1217] update stm32-metapac tag --- embassy-stm32/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index f35271016..da5e18b44 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -73,7 +73,7 @@ rand_core = "0.6.3" sdio-host = "0.5.0" critical-section = "1.1" #stm32-metapac = { version = "15" } -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-392e41259ffc5ffbfd79169ee80451114fb367fe" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-d87131cfec93a6dbd21422ac36d43ce9562aab7f" } vcell = "0.1.3" nb = "1.0.0" @@ -102,7 +102,7 @@ proc-macro2 = "1.0.36" quote = "1.0.15" #stm32-metapac = { version = "15", default-features = false, features = ["metadata"]} -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-392e41259ffc5ffbfd79169ee80451114fb367fe", default-features = false, features = ["metadata"] } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-d87131cfec93a6dbd21422ac36d43ce9562aab7f", default-features = false, features = ["metadata"] } [features] default = ["rt"] From c706e3797a7fb2408aa6f1cfaeba8a6bb951ce25 Mon Sep 17 00:00:00 2001 From: chanterheld Date: Thu, 2 Jan 2025 20:20:38 +0100 Subject: [PATCH 0591/1217] fix g0 wait_busy --- embassy-stm32/src/flash/g.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/src/flash/g.rs b/embassy-stm32/src/flash/g.rs index d02e1435d..7d9c7718b 100644 --- a/embassy-stm32/src/flash/g.rs +++ b/embassy-stm32/src/flash/g.rs @@ -101,7 +101,7 @@ pub(crate) unsafe fn clear_all_err() { #[cfg(any(flash_g0x0, flash_g0x1))] fn wait_busy(){ - while pac::FLASH.sr().read().bsy() & pac::FLASH.sr().read().bsy2() {} + while pac::FLASH.sr().read().bsy() | pac::FLASH.sr().read().bsy2() {} } #[cfg(not(any(flash_g0x0, flash_g0x1)))] From d36876042410b056d39dbb08a5d3125c103ea170 Mon Sep 17 00:00:00 2001 From: chanterheld Date: Thu, 2 Jan 2025 21:14:06 +0100 Subject: [PATCH 0592/1217] fix stmd g0/g4 formatting and bker bit access --- embassy-stm32/src/flash/g.rs | 7 ++++--- embassy-stm32/src/flash/mod.rs | 4 ++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/embassy-stm32/src/flash/g.rs b/embassy-stm32/src/flash/g.rs index 7d9c7718b..83663743c 100644 --- a/embassy-stm32/src/flash/g.rs +++ b/embassy-stm32/src/flash/g.rs @@ -59,6 +59,7 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E interrupt::free(|_| { pac::FLASH.cr().modify(|w| { w.set_per(true); + #[cfg(any(flash_g0x0, flash_g0x1, flash_g4c3))] w.set_bker(sector.bank == crate::flash::FlashBank::Bank2); #[cfg(flash_g0x0)] w.set_pnb(idx as u16); @@ -100,11 +101,11 @@ pub(crate) unsafe fn clear_all_err() { } #[cfg(any(flash_g0x0, flash_g0x1))] -fn wait_busy(){ +fn wait_busy() { while pac::FLASH.sr().read().bsy() | pac::FLASH.sr().read().bsy2() {} } #[cfg(not(any(flash_g0x0, flash_g0x1)))] -fn wait_busy(){ +fn wait_busy() { while pac::FLASH.sr().read().bsy() {} -} \ No newline at end of file +} diff --git a/embassy-stm32/src/flash/mod.rs b/embassy-stm32/src/flash/mod.rs index a7eb3fbcc..aef1f1482 100644 --- a/embassy-stm32/src/flash/mod.rs +++ b/embassy-stm32/src/flash/mod.rs @@ -107,8 +107,8 @@ pub enum FlashBank { #[cfg_attr( not(any( flash_l0, flash_l1, flash_l4, flash_l5, flash_wl, flash_wb, flash_f0, flash_f1, flash_f2, flash_f3, flash_f4, - flash_f7, flash_g0x0, flash_g0x1, flash_g4c2, flash_g4c3, flash_g4c4, flash_h7, flash_h7ab, flash_u5, flash_h50, flash_u0, - flash_h5, + flash_f7, flash_g0x0, flash_g0x1, flash_g4c2, flash_g4c3, flash_g4c4, flash_h7, flash_h7ab, flash_u5, + flash_h50, flash_u0, flash_h5, )), path = "other.rs" )] From b127ca9844a7e4e9079800be81d173e2725066c6 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Fri, 3 Jan 2025 00:16:43 +0100 Subject: [PATCH 0593/1217] Update bt-hci to 0.2 --- cyw43/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cyw43/Cargo.toml b/cyw43/Cargo.toml index 334e1f75e..91873d663 100644 --- a/cyw43/Cargo.toml +++ b/cyw43/Cargo.toml @@ -36,7 +36,7 @@ heapless = "0.8.0" # Bluetooth deps embedded-io-async = { version = "0.6.0", optional = true } -bt-hci = { version = "0.1.0", optional = true } +bt-hci = { version = "0.2.0", optional = true } [package.metadata.embassy_docs] src_base = "https://github.com/embassy-rs/embassy/blob/cyw43-v$VERSION/cyw43/src/" From d9ef2c94d70adb94d77bee184c852e0e3d186f97 Mon Sep 17 00:00:00 2001 From: elagil Date: Fri, 3 Jan 2025 17:54:59 +0100 Subject: [PATCH 0594/1217] chore: clean up stm32h5 ucpd --- embassy-stm32/src/ucpd.rs | 22 ++++++++-------------- examples/stm32h5/src/bin/usb_c_pd.rs | 9 +++++---- 2 files changed, 13 insertions(+), 18 deletions(-) diff --git a/embassy-stm32/src/ucpd.rs b/embassy-stm32/src/ucpd.rs index 403d54f4b..fd5b952ef 100644 --- a/embassy-stm32/src/ucpd.rs +++ b/embassy-stm32/src/ucpd.rs @@ -299,24 +299,18 @@ impl<'d, T: Instance> CcPhy<'d, T> { #[cfg(stm32h5)] T::REGS.cfgr3().modify(|w| match cc_pull { CcPull::Source1_5A => { - #[cfg(stm32h5)] - { - let trim_1a5_cc1 = unsafe { *(0x08FF_F844 as *const u32) & 0xF }; - let trim_1a5_cc2 = unsafe { ((*(0x08FF_F844 as *const u32)) >> 16) & 0xF }; + let trim_1a5_cc1 = unsafe { *(0x08FF_F844 as *const u32) & 0xF }; + let trim_1a5_cc2 = unsafe { ((*(0x08FF_F844 as *const u32)) >> 16) & 0xF }; - w.set_trim_cc1_rp(trim_1a5_cc1 as u8); - w.set_trim_cc2_rp(trim_1a5_cc2 as u8); - }; + w.set_trim_cc1_rp(trim_1a5_cc1 as u8); + w.set_trim_cc2_rp(trim_1a5_cc2 as u8); } _ => { - #[cfg(stm32h5)] - { - let trim_3a0_cc1 = unsafe { (*(0x4002_242C as *const u32) >> 4) & 0xF }; - let trim_3a0_cc2 = unsafe { ((*(0x4002_242C as *const u32)) >> 12) & 0xF }; + let trim_3a0_cc1 = unsafe { (*(0x4002_242C as *const u32) >> 4) & 0xF }; + let trim_3a0_cc2 = unsafe { ((*(0x4002_242C as *const u32)) >> 12) & 0xF }; - w.set_trim_cc1_rp(trim_3a0_cc1 as u8); - w.set_trim_cc2_rp(trim_3a0_cc2 as u8); - }; + w.set_trim_cc1_rp(trim_3a0_cc1 as u8); + w.set_trim_cc2_rp(trim_3a0_cc2 as u8); } }); diff --git a/examples/stm32h5/src/bin/usb_c_pd.rs b/examples/stm32h5/src/bin/usb_c_pd.rs index 00cb3b3da..acb03e498 100644 --- a/examples/stm32h5/src/bin/usb_c_pd.rs +++ b/examples/stm32h5/src/bin/usb_c_pd.rs @@ -57,13 +57,14 @@ async fn main(_spawner: Spawner) { info!("Hello World!"); - // This pin controls the dead-battery mode on the attached TCPP01-M12. - // If low, TCPP01-M12 disconnects CC lines and presents dead-battery resistance on CC lines, thus set high. - let _tcpp01_m12_ndb = Output::new(p.PA9, embassy_stm32::gpio::Level::High, embassy_stm32::gpio::Speed::Low); - let mut ucpd = Ucpd::new(p.UCPD1, Irqs {}, p.PB13, p.PB14, Default::default()); ucpd.cc_phy().set_pull(CcPull::Sink); + // This pin controls the dead-battery mode on the attached TCPP01-M12. + // If low, TCPP01-M12 disconnects CC lines and presents dead-battery resistance on CC lines, thus set high. + // Must only be set after the CC pull is established. + let _tcpp01_m12_ndb = Output::new(p.PA9, embassy_stm32::gpio::Level::High, embassy_stm32::gpio::Speed::Low); + info!("Waiting for USB connection..."); let cable_orientation = wait_attached(ucpd.cc_phy()).await; info!("USB cable connected, orientation: {}", cable_orientation); From 96819805ea12af548636e1e2bbeaf02f20f27847 Mon Sep 17 00:00:00 2001 From: elagil Date: Fri, 3 Jan 2025 17:55:37 +0100 Subject: [PATCH 0595/1217] chore: update stm32-data --- embassy-stm32/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index da5e18b44..229f902fa 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -73,7 +73,7 @@ rand_core = "0.6.3" sdio-host = "0.5.0" critical-section = "1.1" #stm32-metapac = { version = "15" } -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-d87131cfec93a6dbd21422ac36d43ce9562aab7f" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-567fd0b1b7dfd9c1aa9e54d365547afe1ceb1241" } vcell = "0.1.3" nb = "1.0.0" @@ -102,7 +102,7 @@ proc-macro2 = "1.0.36" quote = "1.0.15" #stm32-metapac = { version = "15", default-features = false, features = ["metadata"]} -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-d87131cfec93a6dbd21422ac36d43ce9562aab7f", default-features = false, features = ["metadata"] } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-567fd0b1b7dfd9c1aa9e54d365547afe1ceb1241", default-features = false, features = ["metadata"] } [features] default = ["rt"] From eba8089601450fdf2a666f3d3316c8412cadf470 Mon Sep 17 00:00:00 2001 From: elagil Date: Fri, 3 Jan 2025 18:18:00 +0100 Subject: [PATCH 0596/1217] chore: fix build --- embassy-stm32/src/adc/g4.rs | 8 ++-- embassy-stm32/src/adc/ringbuffered_v2.rs | 2 +- embassy-stm32/src/adc/u5_adc4.rs | 2 +- embassy-stm32/src/adc/v1.rs | 2 +- embassy-stm32/src/adc/v3.rs | 4 +- embassy-stm32/src/adc/v4.rs | 6 +-- embassy-stm32/src/can/bxcan/registers.rs | 8 ++-- embassy-stm32/src/crc/v2v3.rs | 2 +- embassy-stm32/src/dma/dma_bdma.rs | 14 +++--- embassy-stm32/src/dma/gpdma.rs | 6 +-- embassy-stm32/src/eth/v1/mod.rs | 8 ++-- embassy-stm32/src/eth/v1/rx_desc.rs | 6 +-- embassy-stm32/src/flash/f4.rs | 2 +- embassy-stm32/src/gpio.rs | 38 ++++++++-------- embassy-stm32/src/i2c/v2.rs | 6 +-- embassy-stm32/src/i2s.rs | 16 +++---- .../src/lptim/timer/channel_direction.rs | 4 +- embassy-stm32/src/ltdc.rs | 16 +++---- embassy-stm32/src/opamp.rs | 6 +-- embassy-stm32/src/ospi/mod.rs | 26 ++++++----- embassy-stm32/src/rcc/bd.rs | 4 +- embassy-stm32/src/rcc/f013.rs | 12 ++--- embassy-stm32/src/rcc/h.rs | 8 ++-- embassy-stm32/src/rng.rs | 8 ++-- embassy-stm32/src/rtc/v2.rs | 4 +- embassy-stm32/src/rtc/v3.rs | 12 ++--- embassy-stm32/src/sai/mod.rs | 44 +++++++++---------- embassy-stm32/src/spi/mod.rs | 24 +++++----- embassy-stm32/src/time_driver.rs | 4 +- embassy-stm32/src/timer/input_capture.rs | 2 +- embassy-stm32/src/timer/low_level.rs | 40 ++++++++--------- embassy-stm32/src/timer/simple_pwm.rs | 8 ++-- embassy-stm32/src/ucpd.rs | 10 ++--- examples/stm32f469/src/bin/dsi_bsp.rs | 14 +++--- 34 files changed, 191 insertions(+), 185 deletions(-) diff --git a/embassy-stm32/src/adc/g4.rs b/embassy-stm32/src/adc/g4.rs index 872cf3f06..555a91d17 100644 --- a/embassy-stm32/src/adc/g4.rs +++ b/embassy-stm32/src/adc/g4.rs @@ -178,14 +178,14 @@ impl<'d, T: Instance> Adc<'d, T> { fn configure_differential_inputs(&mut self) { T::regs().difsel().modify(|w| { for n in 0..18 { - w.set_difsel(n, Difsel::SINGLEENDED); + w.set_difsel(n, Difsel::SINGLE_ENDED); } }); } fn calibrate(&mut self) { T::regs().cr().modify(|w| { - w.set_adcaldif(Adcaldif::SINGLEENDED); + w.set_adcaldif(Adcaldif::SINGLE_ENDED); }); T::regs().cr().modify(|w| w.set_adcal(true)); @@ -266,7 +266,7 @@ impl<'d, T: Instance> Adc<'d, T> { if enable { Difsel::DIFFERENTIAL } else { - Difsel::SINGLEENDED + Difsel::SINGLE_ENDED }, ); }); @@ -435,7 +435,7 @@ impl<'d, T: Instance> Adc<'d, T> { T::regs().cfgr().modify(|reg| { reg.set_discen(false); reg.set_cont(true); - reg.set_dmacfg(Dmacfg::ONESHOT); + reg.set_dmacfg(Dmacfg::ONE_SHOT); reg.set_dmaen(Dmaen::ENABLE); }); diff --git a/embassy-stm32/src/adc/ringbuffered_v2.rs b/embassy-stm32/src/adc/ringbuffered_v2.rs index 3f0c1a57a..f3d1ca0ab 100644 --- a/embassy-stm32/src/adc/ringbuffered_v2.rs +++ b/embassy-stm32/src/adc/ringbuffered_v2.rs @@ -312,7 +312,7 @@ impl<'d, T: Instance> RingBufferedAdc<'d, T> { // DMA requests are issues as long as DMA=1 and data are converted. w.set_dds(vals::Dds::CONTINUOUS); // EOC flag is set at the end of each conversion. - w.set_eocs(vals::Eocs::EACHCONVERSION); + w.set_eocs(vals::Eocs::EACH_CONVERSION); }); // Begin ADC conversions diff --git a/embassy-stm32/src/adc/u5_adc4.rs b/embassy-stm32/src/adc/u5_adc4.rs index 0635dad9b..cec88d482 100644 --- a/embassy-stm32/src/adc/u5_adc4.rs +++ b/embassy-stm32/src/adc/u5_adc4.rs @@ -416,7 +416,7 @@ impl<'d, T: Instance> Adc4<'d, T> { T::regs().cfgr1().modify(|reg| { reg.set_dmaen(true); - reg.set_dmacfg(Adc4Dmacfg::ONESHOT); + reg.set_dmacfg(Adc4Dmacfg::ONE_SHOT); reg.set_chselrmod(false); }); diff --git a/embassy-stm32/src/adc/v1.rs b/embassy-stm32/src/adc/v1.rs index 9bec2e13b..d5cd14661 100644 --- a/embassy-stm32/src/adc/v1.rs +++ b/embassy-stm32/src/adc/v1.rs @@ -160,7 +160,7 @@ impl<'d, T: Instance> Adc<'d, T> { channel.setup(); // A.7.5 Single conversion sequence code example - Software trigger - T::regs().chselr().write(|reg| reg.set_chselx(ch_num as usize, true)); + T::regs().chselr().write(|reg| reg.set_chsel_x(ch_num as usize, true)); self.convert().await } diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs index 9441e42ff..fc20974dd 100644 --- a/embassy-stm32/src/adc/v3.rs +++ b/embassy-stm32/src/adc/v3.rs @@ -366,14 +366,14 @@ impl<'d, T: Instance> Adc<'d, T> { T::regs().cfgr().modify(|reg| { reg.set_discen(false); reg.set_cont(true); - reg.set_dmacfg(Dmacfg::ONESHOT); + reg.set_dmacfg(Dmacfg::ONE_SHOT); reg.set_dmaen(true); }); #[cfg(any(adc_g0, adc_u0))] T::regs().cfgr1().modify(|reg| { reg.set_discen(false); reg.set_cont(true); - reg.set_dmacfg(Dmacfg::ONESHOT); + reg.set_dmacfg(Dmacfg::ONE_SHOT); reg.set_dmaen(true); }); diff --git a/embassy-stm32/src/adc/v4.rs b/embassy-stm32/src/adc/v4.rs index 46f9c7ac7..9860efa8a 100644 --- a/embassy-stm32/src/adc/v4.rs +++ b/embassy-stm32/src/adc/v4.rs @@ -214,7 +214,7 @@ impl<'d, T: Instance> Adc<'d, T> { fn configure_differential_inputs(&mut self) { T::regs().difsel().modify(|w| { for n in 0..20 { - w.set_difsel(n, Difsel::SINGLEENDED); + w.set_difsel(n, Difsel::SINGLE_ENDED); } }); } @@ -222,7 +222,7 @@ impl<'d, T: Instance> Adc<'d, T> { fn calibrate(&mut self) { T::regs().cr().modify(|w| { #[cfg(not(adc_u5))] - w.set_adcaldif(Adcaldif::SINGLEENDED); + w.set_adcaldif(Adcaldif::SINGLE_ENDED); w.set_adcallin(true); }); @@ -420,7 +420,7 @@ impl<'d, T: Instance> Adc<'d, T> { }); T::regs().cfgr().modify(|reg| { reg.set_cont(true); - reg.set_dmngt(Dmngt::DMA_ONESHOT); + reg.set_dmngt(Dmngt::DMA_ONE_SHOT); }); let request = rx_dma.request(); diff --git a/embassy-stm32/src/can/bxcan/registers.rs b/embassy-stm32/src/can/bxcan/registers.rs index 9798a058b..c5467dfe8 100644 --- a/embassy-stm32/src/can/bxcan/registers.rs +++ b/embassy-stm32/src/can/bxcan/registers.rs @@ -166,16 +166,16 @@ impl Registers { return Some(BusError::BusPassive); } else if err.ewgf() { return Some(BusError::BusWarning); - } else if err.lec() != Lec::NOERROR { + } else if err.lec() != Lec::NO_ERROR { return Some(match err.lec() { Lec::STUFF => BusError::Stuff, Lec::FORM => BusError::Form, Lec::ACK => BusError::Acknowledge, - Lec::BITRECESSIVE => BusError::BitRecessive, - Lec::BITDOMINANT => BusError::BitDominant, + Lec::BIT_RECESSIVE => BusError::BitRecessive, + Lec::BIT_DOMINANT => BusError::BitDominant, Lec::CRC => BusError::Crc, Lec::CUSTOM => BusError::Software, - Lec::NOERROR => unreachable!(), + Lec::NO_ERROR => unreachable!(), }); } None diff --git a/embassy-stm32/src/crc/v2v3.rs b/embassy-stm32/src/crc/v2v3.rs index 09d956d7c..ecb507ff4 100644 --- a/embassy-stm32/src/crc/v2v3.rs +++ b/embassy-stm32/src/crc/v2v3.rs @@ -118,7 +118,7 @@ impl<'d> Crc<'d> { w.set_rev_in(match self._config.reverse_in { InputReverseConfig::None => vals::RevIn::NORMAL, InputReverseConfig::Byte => vals::RevIn::BYTE, - InputReverseConfig::Halfword => vals::RevIn::HALFWORD, + InputReverseConfig::Halfword => vals::RevIn::HALF_WORD, InputReverseConfig::Word => vals::RevIn::WORD, }); // configure the polynomial. diff --git a/embassy-stm32/src/dma/dma_bdma.rs b/embassy-stm32/src/dma/dma_bdma.rs index 1945c3587..3cc7a1e69 100644 --- a/embassy-stm32/src/dma/dma_bdma.rs +++ b/embassy-stm32/src/dma/dma_bdma.rs @@ -100,7 +100,7 @@ impl From for pac::dma::vals::Pl { Priority::Low => pac::dma::vals::Pl::LOW, Priority::Medium => pac::dma::vals::Pl::MEDIUM, Priority::High => pac::dma::vals::Pl::HIGH, - Priority::VeryHigh => pac::dma::vals::Pl::VERYHIGH, + Priority::VeryHigh => pac::dma::vals::Pl::VERY_HIGH, } } } @@ -112,7 +112,7 @@ impl From for pac::bdma::vals::Pl { Priority::Low => pac::bdma::vals::Pl::LOW, Priority::Medium => pac::bdma::vals::Pl::MEDIUM, Priority::High => pac::bdma::vals::Pl::HIGH, - Priority::VeryHigh => pac::bdma::vals::Pl::VERYHIGH, + Priority::VeryHigh => pac::bdma::vals::Pl::VERY_HIGH, } } } @@ -138,8 +138,8 @@ mod dma_only { impl From

for vals::Dir { fn from(raw: Dir) -> Self { match raw { - Dir::MemoryToPeripheral => Self::MEMORYTOPERIPHERAL, - Dir::PeripheralToMemory => Self::PERIPHERALTOMEMORY, + Dir::MemoryToPeripheral => Self::MEMORY_TO_PERIPHERAL, + Dir::PeripheralToMemory => Self::PERIPHERAL_TO_MEMORY, } } } @@ -207,7 +207,7 @@ mod dma_only { match value { FifoThreshold::Quarter => vals::Fth::QUARTER, FifoThreshold::Half => vals::Fth::HALF, - FifoThreshold::ThreeQuarters => vals::Fth::THREEQUARTERS, + FifoThreshold::ThreeQuarters => vals::Fth::THREE_QUARTERS, FifoThreshold::Full => vals::Fth::FULL, } } @@ -233,8 +233,8 @@ mod bdma_only { impl From for vals::Dir { fn from(raw: Dir) -> Self { match raw { - Dir::MemoryToPeripheral => Self::FROMMEMORY, - Dir::PeripheralToMemory => Self::FROMPERIPHERAL, + Dir::MemoryToPeripheral => Self::FROM_MEMORY, + Dir::PeripheralToMemory => Self::FROM_PERIPHERAL, } } } diff --git a/embassy-stm32/src/dma/gpdma.rs b/embassy-stm32/src/dma/gpdma.rs index a877bb8d4..fc5fb6592 100644 --- a/embassy-stm32/src/dma/gpdma.rs +++ b/embassy-stm32/src/dma/gpdma.rs @@ -38,7 +38,7 @@ impl From for vals::Dw { fn from(raw: WordSize) -> Self { match raw { WordSize::OneByte => Self::BYTE, - WordSize::TwoBytes => Self::HALFWORD, + WordSize::TwoBytes => Self::HALF_WORD, WordSize::FourBytes => Self::WORD, } } @@ -240,8 +240,8 @@ impl<'a> Transfer<'a> { }); ch.tr2().write(|w| { w.set_dreq(match dir { - Dir::MemoryToPeripheral => vals::Dreq::DESTINATIONPERIPHERAL, - Dir::PeripheralToMemory => vals::Dreq::SOURCEPERIPHERAL, + Dir::MemoryToPeripheral => vals::Dreq::DESTINATION_PERIPHERAL, + Dir::PeripheralToMemory => vals::Dreq::SOURCE_PERIPHERAL, }); w.set_reqsel(request); }); diff --git a/embassy-stm32/src/eth/v1/mod.rs b/embassy-stm32/src/eth/v1/mod.rs index b96275cb7..438b28020 100644 --- a/embassy-stm32/src/eth/v1/mod.rs +++ b/embassy-stm32/src/eth/v1/mod.rs @@ -159,8 +159,8 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> { w.set_ifg(Ifg::IFG96); // inter frame gap 96 bit times w.set_apcs(Apcs::STRIP); // automatic padding and crc stripping w.set_fes(Fes::FES100); // fast ethernet speed - w.set_dm(Dm::FULLDUPLEX); // full duplex - // TODO: Carrier sense ? ECRSFD + w.set_dm(Dm::FULL_DUPLEX); // full duplex + // TODO: Carrier sense ? ECRSFD }); // Set the mac to pass all multicast packets @@ -186,8 +186,8 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> { // Transfer and Forward, Receive and Forward dma.dmaomr().modify(|w| { - w.set_tsf(Tsf::STOREFORWARD); - w.set_rsf(Rsf::STOREFORWARD); + w.set_tsf(Tsf::STORE_FORWARD); + w.set_rsf(Rsf::STORE_FORWARD); }); dma.dmabmr().modify(|w| { diff --git a/embassy-stm32/src/eth/v1/rx_desc.rs b/embassy-stm32/src/eth/v1/rx_desc.rs index 668378bea..2a46c1895 100644 --- a/embassy-stm32/src/eth/v1/rx_desc.rs +++ b/embassy-stm32/src/eth/v1/rx_desc.rs @@ -168,15 +168,15 @@ impl<'a> RDesRing<'a> { // Reset or Stop Receive Command issued Rps::STOPPED => RunningState::Stopped, // Fetching receive transfer descriptor - Rps::RUNNINGFETCHING => RunningState::Running, + Rps::RUNNING_FETCHING => RunningState::Running, // Waiting for receive packet - Rps::RUNNINGWAITING => RunningState::Running, + Rps::RUNNING_WAITING => RunningState::Running, // Receive descriptor unavailable Rps::SUSPENDED => RunningState::Stopped, // Closing receive descriptor Rps::_RESERVED_5 => RunningState::Running, // Transferring the receive packet data from receive buffer to host memory - Rps::RUNNINGWRITING => RunningState::Running, + Rps::RUNNING_WRITING => RunningState::Running, _ => RunningState::Unknown, } } diff --git a/embassy-stm32/src/flash/f4.rs b/embassy-stm32/src/flash/f4.rs index d0bb957ee..8ebeae95b 100644 --- a/embassy-stm32/src/flash/f4.rs +++ b/embassy-stm32/src/flash/f4.rs @@ -469,7 +469,7 @@ fn pa12_is_output_pull_low() -> bool { use pac::GPIOA; const PIN: usize = 12; GPIOA.moder().read().moder(PIN) == vals::Moder::OUTPUT - && GPIOA.pupdr().read().pupdr(PIN) == vals::Pupdr::PULLDOWN + && GPIOA.pupdr().read().pupdr(PIN) == vals::Pupdr::PULL_DOWN && GPIOA.odr().read().odr(PIN) == vals::Odr::LOW } diff --git a/embassy-stm32/src/gpio.rs b/embassy-stm32/src/gpio.rs index c047f84ae..6967ecc7c 100644 --- a/embassy-stm32/src/gpio.rs +++ b/embassy-stm32/src/gpio.rs @@ -61,7 +61,7 @@ impl<'d> Flex<'d> { #[cfg(gpio_v2)] { r.pupdr().modify(|w| w.set_pupdr(n, pull.to_pupdr())); - r.otyper().modify(|w| w.set_ot(n, vals::Ot::PUSHPULL)); + r.otyper().modify(|w| w.set_ot(n, vals::Ot::PUSH_PULL)); r.moder().modify(|w| w.set_moder(n, vals::Moder::INPUT)); } }); @@ -82,13 +82,13 @@ impl<'d> Flex<'d> { { r.cr(n / 8).modify(|w| { w.set_mode(n % 8, speed.to_mode()); - w.set_cnf_out(n % 8, vals::CnfOut::PUSHPULL); + w.set_cnf_out(n % 8, vals::CnfOut::PUSH_PULL); }); } #[cfg(gpio_v2)] { r.pupdr().modify(|w| w.set_pupdr(n, vals::Pupdr::FLOATING)); - r.otyper().modify(|w| w.set_ot(n, vals::Ot::PUSHPULL)); + r.otyper().modify(|w| w.set_ot(n, vals::Ot::PUSH_PULL)); r.ospeedr().modify(|w| w.set_ospeedr(n, speed.to_ospeedr())); r.moder().modify(|w| w.set_moder(n, vals::Moder::OUTPUT)); } @@ -112,7 +112,7 @@ impl<'d> Flex<'d> { let r = self.pin.block(); let n = self.pin.pin() as usize; r.cr(n / 8).modify(|w| w.set_mode(n % 8, speed.to_mode())); - r.cr(n / 8).modify(|w| w.set_cnf_out(n % 8, vals::CnfOut::OPENDRAIN)); + r.cr(n / 8).modify(|w| w.set_cnf_out(n % 8, vals::CnfOut::OPEN_DRAIN)); }); #[cfg(gpio_v2)] @@ -130,7 +130,7 @@ impl<'d> Flex<'d> { let r = self.pin.block(); let n = self.pin.pin() as usize; r.pupdr().modify(|w| w.set_pupdr(n, pull.to_pupdr())); - r.otyper().modify(|w| w.set_ot(n, vals::Ot::OPENDRAIN)); + r.otyper().modify(|w| w.set_ot(n, vals::Ot::OPEN_DRAIN)); r.ospeedr().modify(|w| w.set_ospeedr(n, speed.to_ospeedr())); r.moder().modify(|w| w.set_moder(n, vals::Moder::OUTPUT)); }); @@ -253,8 +253,8 @@ impl Pull { const fn to_pupdr(self) -> vals::Pupdr { match self { Pull::None => vals::Pupdr::FLOATING, - Pull::Up => vals::Pupdr::PULLUP, - Pull::Down => vals::Pupdr::PULLDOWN, + Pull::Up => vals::Pupdr::PULL_UP, + Pull::Down => vals::Pupdr::PULL_DOWN, } } } @@ -293,11 +293,11 @@ impl Speed { #[cfg(gpio_v2)] const fn to_ospeedr(self: Speed) -> vals::Ospeedr { match self { - Speed::Low => vals::Ospeedr::LOWSPEED, - Speed::Medium => vals::Ospeedr::MEDIUMSPEED, + Speed::Low => vals::Ospeedr::LOW_SPEED, + Speed::Medium => vals::Ospeedr::MEDIUM_SPEED, #[cfg(not(syscfg_f0))] - Speed::High => vals::Ospeedr::HIGHSPEED, - Speed::VeryHigh => vals::Ospeedr::VERYHIGHSPEED, + Speed::High => vals::Ospeedr::HIGH_SPEED, + Speed::VeryHigh => vals::Ospeedr::VERY_HIGH_SPEED, } } } @@ -539,16 +539,16 @@ impl OutputType { #[cfg(gpio_v1)] const fn to_cnf_out(self) -> vals::CnfOut { match self { - OutputType::PushPull => vals::CnfOut::ALTPUSHPULL, - OutputType::OpenDrain => vals::CnfOut::ALTOPENDRAIN, + OutputType::PushPull => vals::CnfOut::ALT_PUSH_PULL, + OutputType::OpenDrain => vals::CnfOut::ALT_OPEN_DRAIN, } } #[cfg(gpio_v2)] const fn to_ot(self) -> vals::Ot { match self { - OutputType::PushPull => vals::Ot::PUSHPULL, - OutputType::OpenDrain => vals::Ot::OPENDRAIN, + OutputType::PushPull => vals::Ot::PUSH_PULL, + OutputType::OpenDrain => vals::Ot::OPEN_DRAIN, } } } @@ -624,8 +624,8 @@ impl AfType { pub const fn input(pull: Pull) -> Self { Self { pupdr: pull.to_pupdr(), - ot: vals::Ot::PUSHPULL, - ospeedr: vals::Ospeedr::LOWSPEED, + ot: vals::Ot::PUSH_PULL, + ospeedr: vals::Ospeedr::LOW_SPEED, } } @@ -705,8 +705,8 @@ fn get_pull(pin_port: u8) -> Pull { #[cfg(gpio_v2)] return match r.pupdr().read().pupdr(n) { vals::Pupdr::FLOATING => Pull::None, - vals::Pupdr::PULLDOWN => Pull::Down, - vals::Pupdr::PULLUP => Pull::Up, + vals::Pupdr::PULL_DOWN => Pull::Down, + vals::Pupdr::PULL_UP => Pull::Up, vals::Pupdr::_RESERVED_3 => Pull::None, }; } diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs index 8c8df79dd..05ac9afcc 100644 --- a/embassy-stm32/src/i2c/v2.rs +++ b/embassy-stm32/src/i2c/v2.rs @@ -74,7 +74,7 @@ impl<'d, M: Mode> I2c<'d, M> { // is BUSY or I2C is in slave mode. let reload = if reload { - i2c::vals::Reload::NOTCOMPLETED + i2c::vals::Reload::NOT_COMPLETED } else { i2c::vals::Reload::COMPLETED }; @@ -115,7 +115,7 @@ impl<'d, M: Mode> I2c<'d, M> { } let reload = if reload { - i2c::vals::Reload::NOTCOMPLETED + i2c::vals::Reload::NOT_COMPLETED } else { i2c::vals::Reload::COMPLETED }; @@ -144,7 +144,7 @@ impl<'d, M: Mode> I2c<'d, M> { } let reload = if reload { - i2c::vals::Reload::NOTCOMPLETED + i2c::vals::Reload::NOT_COMPLETED } else { i2c::vals::Reload::COMPLETED }; diff --git a/embassy-stm32/src/i2s.rs b/embassy-stm32/src/i2s.rs index f11371f98..79d6279f6 100644 --- a/embassy-stm32/src/i2s.rs +++ b/embassy-stm32/src/i2s.rs @@ -141,8 +141,8 @@ impl ClockPolarity { #[cfg(any(spi_v1, spi_v3, spi_f1))] const fn ckpol(&self) -> vals::Ckpol { match self { - ClockPolarity::IdleHigh => vals::Ckpol::IDLEHIGH, - ClockPolarity::IdleLow => vals::Ckpol::IDLELOW, + ClockPolarity::IdleHigh => vals::Ckpol::IDLE_HIGH, + ClockPolarity::IdleLow => vals::Ckpol::IDLE_LOW, } } } @@ -564,14 +564,14 @@ impl<'d, W: Word> I2S<'d, W> { w.set_chlen(config.format.chlen()); w.set_i2scfg(match (config.mode, function) { - (Mode::Master, Function::Transmit) => I2scfg::MASTERTX, - (Mode::Master, Function::Receive) => I2scfg::MASTERRX, + (Mode::Master, Function::Transmit) => I2scfg::MASTER_TX, + (Mode::Master, Function::Receive) => I2scfg::MASTER_RX, #[cfg(spi_v3)] - (Mode::Master, Function::FullDuplex) => I2scfg::MASTERFULLDUPLEX, - (Mode::Slave, Function::Transmit) => I2scfg::SLAVETX, - (Mode::Slave, Function::Receive) => I2scfg::SLAVERX, + (Mode::Master, Function::FullDuplex) => I2scfg::MASTER_FULL_DUPLEX, + (Mode::Slave, Function::Transmit) => I2scfg::SLAVE_TX, + (Mode::Slave, Function::Receive) => I2scfg::SLAVE_RX, #[cfg(spi_v3)] - (Mode::Slave, Function::FullDuplex) => I2scfg::SLAVEFULLDUPLEX, + (Mode::Slave, Function::FullDuplex) => I2scfg::SLAVE_FULL_DUPLEX, }); #[cfg(any(spi_v1, spi_f1))] diff --git a/embassy-stm32/src/lptim/timer/channel_direction.rs b/embassy-stm32/src/lptim/timer/channel_direction.rs index a38df63cd..e4af8f45f 100644 --- a/embassy-stm32/src/lptim/timer/channel_direction.rs +++ b/embassy-stm32/src/lptim/timer/channel_direction.rs @@ -11,8 +11,8 @@ pub enum ChannelDirection { impl From for vals::Ccsel { fn from(direction: ChannelDirection) -> Self { match direction { - ChannelDirection::OutputPwm => vals::Ccsel::OUTPUTCOMPARE, - ChannelDirection::InputCapture => vals::Ccsel::INPUTCAPTURE, + ChannelDirection::OutputPwm => vals::Ccsel::OUTPUT_COMPARE, + ChannelDirection::InputCapture => vals::Ccsel::INPUT_CAPTURE, } } } diff --git a/embassy-stm32/src/ltdc.rs b/embassy-stm32/src/ltdc.rs index e25c4f3fb..16210b7dc 100644 --- a/embassy-stm32/src/ltdc.rs +++ b/embassy-stm32/src/ltdc.rs @@ -261,23 +261,23 @@ impl<'d, T: Instance> Ltdc<'d, T> { // configure the HS, VS, DE and PC polarity ltdc.gcr().modify(|w| { w.set_hspol(match config.h_sync_polarity { - PolarityActive::ActiveHigh => Hspol::ACTIVEHIGH, - PolarityActive::ActiveLow => Hspol::ACTIVELOW, + PolarityActive::ActiveHigh => Hspol::ACTIVE_HIGH, + PolarityActive::ActiveLow => Hspol::ACTIVE_LOW, }); w.set_vspol(match config.v_sync_polarity { - PolarityActive::ActiveHigh => Vspol::ACTIVEHIGH, - PolarityActive::ActiveLow => Vspol::ACTIVELOW, + PolarityActive::ActiveHigh => Vspol::ACTIVE_HIGH, + PolarityActive::ActiveLow => Vspol::ACTIVE_LOW, }); w.set_depol(match config.data_enable_polarity { - PolarityActive::ActiveHigh => Depol::ACTIVEHIGH, - PolarityActive::ActiveLow => Depol::ACTIVELOW, + PolarityActive::ActiveHigh => Depol::ACTIVE_HIGH, + PolarityActive::ActiveLow => Depol::ACTIVE_LOW, }); w.set_pcpol(match config.pixel_clock_polarity { - PolarityEdge::RisingEdge => Pcpol::RISINGEDGE, - PolarityEdge::FallingEdge => Pcpol::FALLINGEDGE, + PolarityEdge::RisingEdge => Pcpol::RISING_EDGE, + PolarityEdge::FallingEdge => Pcpol::FALLING_EDGE, }); }); diff --git a/embassy-stm32/src/opamp.rs b/embassy-stm32/src/opamp.rs index d1c53a740..c7610f4b5 100644 --- a/embassy-stm32/src/opamp.rs +++ b/embassy-stm32/src/opamp.rs @@ -30,7 +30,7 @@ impl From for crate::pac::opamp::vals::Opahsm { fn from(v: OpAmpSpeed) -> Self { match v { OpAmpSpeed::Normal => crate::pac::opamp::vals::Opahsm::NORMAL, - OpAmpSpeed::HighSpeed => crate::pac::opamp::vals::Opahsm::HIGHSPEED, + OpAmpSpeed::HighSpeed => crate::pac::opamp::vals::Opahsm::HIGH_SPEED, } } } @@ -105,7 +105,7 @@ impl<'d, T: Instance> OpAmp<'d, T> { w.set_vm_sel(VmSel::from_bits(vm_sel)); w.set_pga_gain(PgaGain::from_bits(pga_gain)); #[cfg(opamp_g4)] - w.set_opaintoen(Opaintoen::OUTPUTPIN); + w.set_opaintoen(Opaintoen::OUTPUT_PIN); w.set_opampen(true); }); @@ -131,7 +131,7 @@ impl<'d, T: Instance> OpAmp<'d, T> { w.set_vm_sel(VmSel::OUTPUT); w.set_vp_sel(VpSel::DAC3_CH1); - w.set_opaintoen(Opaintoen::OUTPUTPIN); + w.set_opaintoen(Opaintoen::OUTPUT_PIN); w.set_opampen(true); }); diff --git a/embassy-stm32/src/ospi/mod.rs b/embassy-stm32/src/ospi/mod.rs index 38217a9a4..33e19f4f8 100644 --- a/embassy-stm32/src/ospi/mod.rs +++ b/embassy-stm32/src/ospi/mod.rs @@ -218,7 +218,7 @@ impl<'d, T: Instance, M: PeriMode> Ospi<'d, T, M> { // Enable memory mapped mode reg.cr().modify(|r| { - r.set_fmode(crate::ospi::vals::FunctionalMode::MEMORYMAPPED); + r.set_fmode(crate::ospi::vals::FunctionalMode::MEMORY_MAPPED); r.set_tcen(false); }); Ok(()) @@ -229,7 +229,7 @@ impl<'d, T: Instance, M: PeriMode> Ospi<'d, T, M> { let reg = T::REGS; reg.cr().modify(|r| { - r.set_fmode(crate::ospi::vals::FunctionalMode::INDIRECTWRITE); + r.set_fmode(crate::ospi::vals::FunctionalMode::INDIRECT_WRITE); r.set_abort(true); r.set_dmaen(false); r.set_en(false); @@ -388,7 +388,7 @@ impl<'d, T: Instance, M: PeriMode> Ospi<'d, T, M> { T::REGS.tcr().modify(|w| { w.set_sshift(match config.sample_shifting { - true => vals::SampleShift::HALFCYCLE, + true => vals::SampleShift::HALF_CYCLE, false => vals::SampleShift::NONE, }); w.set_dhqc(config.delay_hold_quarter_cycle); @@ -556,7 +556,9 @@ impl<'d, T: Instance, M: PeriMode> Ospi<'d, T, M> { let current_instruction = T::REGS.ir().read().instruction(); // For a indirect read transaction, the transaction begins when the instruction/address is set - T::REGS.cr().modify(|v| v.set_fmode(vals::FunctionalMode::INDIRECTREAD)); + T::REGS + .cr() + .modify(|v| v.set_fmode(vals::FunctionalMode::INDIRECT_READ)); if T::REGS.ccr().read().admode() == vals::PhaseMode::NONE { T::REGS.ir().write(|v| v.set_instruction(current_instruction)); } else { @@ -591,7 +593,7 @@ impl<'d, T: Instance, M: PeriMode> Ospi<'d, T, M> { T::REGS .cr() - .modify(|v| v.set_fmode(vals::FunctionalMode::INDIRECTWRITE)); + .modify(|v| v.set_fmode(vals::FunctionalMode::INDIRECT_WRITE)); for idx in 0..buf.len() { while !T::REGS.sr().read().ftf() {} @@ -653,7 +655,7 @@ impl<'d, T: Instance, M: PeriMode> Ospi<'d, T, M> { T::REGS.tcr().modify(|w| { w.set_sshift(match config.sample_shifting { - true => vals::SampleShift::HALFCYCLE, + true => vals::SampleShift::HALF_CYCLE, false => vals::SampleShift::NONE, }); w.set_dhqc(config.delay_hold_quarter_cycle); @@ -1051,7 +1053,9 @@ impl<'d, T: Instance> Ospi<'d, T, Async> { let current_instruction = T::REGS.ir().read().instruction(); // For a indirect read transaction, the transaction begins when the instruction/address is set - T::REGS.cr().modify(|v| v.set_fmode(vals::FunctionalMode::INDIRECTREAD)); + T::REGS + .cr() + .modify(|v| v.set_fmode(vals::FunctionalMode::INDIRECT_READ)); if T::REGS.ccr().read().admode() == vals::PhaseMode::NONE { T::REGS.ir().write(|v| v.set_instruction(current_instruction)); } else { @@ -1086,7 +1090,7 @@ impl<'d, T: Instance> Ospi<'d, T, Async> { self.configure_command(&transaction, Some(buf.len()))?; T::REGS .cr() - .modify(|v| v.set_fmode(vals::FunctionalMode::INDIRECTWRITE)); + .modify(|v| v.set_fmode(vals::FunctionalMode::INDIRECT_WRITE)); let transfer = unsafe { self.dma @@ -1119,7 +1123,9 @@ impl<'d, T: Instance> Ospi<'d, T, Async> { let current_instruction = T::REGS.ir().read().instruction(); // For a indirect read transaction, the transaction begins when the instruction/address is set - T::REGS.cr().modify(|v| v.set_fmode(vals::FunctionalMode::INDIRECTREAD)); + T::REGS + .cr() + .modify(|v| v.set_fmode(vals::FunctionalMode::INDIRECT_READ)); if T::REGS.ccr().read().admode() == vals::PhaseMode::NONE { T::REGS.ir().write(|v| v.set_instruction(current_instruction)); } else { @@ -1154,7 +1160,7 @@ impl<'d, T: Instance> Ospi<'d, T, Async> { self.configure_command(&transaction, Some(buf.len()))?; T::REGS .cr() - .modify(|v| v.set_fmode(vals::FunctionalMode::INDIRECTWRITE)); + .modify(|v| v.set_fmode(vals::FunctionalMode::INDIRECT_WRITE)); let transfer = unsafe { self.dma diff --git a/embassy-stm32/src/rcc/bd.rs b/embassy-stm32/src/rcc/bd.rs index 791367954..57aaba1c7 100644 --- a/embassy-stm32/src/rcc/bd.rs +++ b/embassy-stm32/src/rcc/bd.rs @@ -45,8 +45,8 @@ impl From for crate::pac::rcc::vals::Lsedrv { match value { #[cfg(not(stm32h5))] // ES0565: LSE Low drive mode is not functional LseDrive::Low => Lsedrv::LOW, - LseDrive::MediumLow => Lsedrv::MEDIUMLOW, - LseDrive::MediumHigh => Lsedrv::MEDIUMHIGH, + LseDrive::MediumLow => Lsedrv::MEDIUM_LOW, + LseDrive::MediumHigh => Lsedrv::MEDIUM_HIGH, LseDrive::High => Lsedrv::HIGH, } } diff --git a/embassy-stm32/src/rcc/f013.rs b/embassy-stm32/src/rcc/f013.rs index a38ca955e..57c5cd5b2 100644 --- a/embassy-stm32/src/rcc/f013.rs +++ b/embassy-stm32/src/rcc/f013.rs @@ -332,9 +332,9 @@ pub(crate) unsafe fn init(config: Config) { assert!(!(adcpres == AdcHclkPrescaler::Div1 && config.ahb_pre != AHBPrescaler::DIV1)); let (div, ckmode) = match adcpres { - AdcHclkPrescaler::Div1 => (1u32, Ckmode::SYNCDIV1), - AdcHclkPrescaler::Div2 => (2u32, Ckmode::SYNCDIV2), - AdcHclkPrescaler::Div4 => (4u32, Ckmode::SYNCDIV4), + AdcHclkPrescaler::Div1 => (1u32, Ckmode::SYNC_DIV1), + AdcHclkPrescaler::Div2 => (2u32, Ckmode::SYNC_DIV2), + AdcHclkPrescaler::Div4 => (4u32, Ckmode::SYNC_DIV4), }; common.ccr().modify(|w| w.set_ckmode(ckmode)); @@ -361,9 +361,9 @@ pub(crate) unsafe fn init(config: Config) { assert!(!(adcpres == AdcHclkPrescaler::Div1 && config.ahb_pre != AHBPrescaler::DIV1)); let (div, ckmode) = match adcpres { - AdcHclkPrescaler::Div1 => (1u32, Ckmode::SYNCDIV1), - AdcHclkPrescaler::Div2 => (2u32, Ckmode::SYNCDIV2), - AdcHclkPrescaler::Div4 => (4u32, Ckmode::SYNCDIV4), + AdcHclkPrescaler::Div1 => (1u32, Ckmode::SYNC_DIV1), + AdcHclkPrescaler::Div2 => (2u32, Ckmode::SYNC_DIV2), + AdcHclkPrescaler::Div4 => (4u32, Ckmode::SYNC_DIV4), }; common.ccr().modify(|w| w.set_ckmode(ckmode)); diff --git a/embassy-stm32/src/rcc/h.rs b/embassy-stm32/src/rcc/h.rs index df2929ba4..d80fbeb1e 100644 --- a/embassy-stm32/src/rcc/h.rs +++ b/embassy-stm32/src/rcc/h.rs @@ -113,8 +113,8 @@ pub enum TimerPrescaler { impl From for Timpre { fn from(value: TimerPrescaler) -> Self { match value { - TimerPrescaler::DefaultX2 => Timpre::DEFAULTX2, - TimerPrescaler::DefaultX4 => Timpre::DEFAULTX4, + TimerPrescaler::DefaultX2 => Timpre::DEFAULT_X2, + TimerPrescaler::DefaultX4 => Timpre::DEFAULT_X4, } } } @@ -788,9 +788,9 @@ fn init_pll(num: usize, config: Option, input: &PllInput) -> PllOutput { let vco_clk = ref_clk * config.mul; let vco_range = if VCO_RANGE.contains(&vco_clk) { - Pllvcosel::MEDIUMVCO + Pllvcosel::MEDIUM_VCO } else if wide_allowed && VCO_WIDE_RANGE.contains(&vco_clk) { - Pllvcosel::WIDEVCO + Pllvcosel::WIDE_VCO } else { panic!("pll vco_clk out of range: {} hz", vco_clk.0) }; diff --git a/embassy-stm32/src/rng.rs b/embassy-stm32/src/rng.rs index 6f4c81c8a..b96200e5e 100644 --- a/embassy-stm32/src/rng.rs +++ b/embassy-stm32/src/rng.rs @@ -88,10 +88,10 @@ impl<'d, T: Instance> Rng<'d, T> { reg.set_nistc(pac::rng::vals::Nistc::CUSTOM); // set RNG config "A" according to reference manual // this has to be written within the same write access as setting the CONDRST bit - reg.set_rng_config1(pac::rng::vals::RngConfig1::CONFIGA); - reg.set_clkdiv(pac::rng::vals::Clkdiv::NODIV); - reg.set_rng_config2(pac::rng::vals::RngConfig2::CONFIGA_B); - reg.set_rng_config3(pac::rng::vals::RngConfig3::CONFIGA); + reg.set_rng_config1(pac::rng::vals::RngConfig1::CONFIG_A); + reg.set_clkdiv(pac::rng::vals::Clkdiv::NO_DIV); + reg.set_rng_config2(pac::rng::vals::RngConfig2::CONFIG_A_B); + reg.set_rng_config3(pac::rng::vals::RngConfig3::CONFIG_A); reg.set_ced(true); reg.set_ie(false); reg.set_rngen(true); diff --git a/embassy-stm32/src/rtc/v2.rs b/embassy-stm32/src/rtc/v2.rs index 5d9025bbe..b7d25635b 100644 --- a/embassy-stm32/src/rtc/v2.rs +++ b/embassy-stm32/src/rtc/v2.rs @@ -77,7 +77,7 @@ impl super::Rtc { // When the offset is positive (0 to 512), the opposite of // the offset (512 - offset) is masked, i.e. for the // maximum offset (512), 0 pulses are masked. - w.set_calp(stm32_metapac::rtc::vals::Calp::INCREASEFREQ); + w.set_calp(stm32_metapac::rtc::vals::Calp::INCREASE_FREQ); w.set_calm(512 - clock_drift as u16); } else { // Minimum (about -510.7) rounds to -511. @@ -86,7 +86,7 @@ impl super::Rtc { // When the offset is negative or zero (-511 to 0), // the absolute offset is masked, i.e. for the minimum // offset (-511), 511 pulses are masked. - w.set_calp(stm32_metapac::rtc::vals::Calp::NOCHANGE); + w.set_calp(stm32_metapac::rtc::vals::Calp::NO_CHANGE); w.set_calm((clock_drift * -1.0) as u16); } }); diff --git a/embassy-stm32/src/rtc/v3.rs b/embassy-stm32/src/rtc/v3.rs index de2c202bc..39aa6c5cb 100644 --- a/embassy-stm32/src/rtc/v3.rs +++ b/embassy-stm32/src/rtc/v3.rs @@ -12,7 +12,7 @@ impl super::Rtc { self.write(true, |rtc| { rtc.cr().modify(|w| { w.set_bypshad(true); - w.set_fmt(Fmt::TWENTYFOURHOUR); + w.set_fmt(Fmt::TWENTY_FOUR_HOUR); w.set_osel(Osel::DISABLED); w.set_pol(Pol::HIGH); }); @@ -25,7 +25,7 @@ impl super::Rtc { // TODO: configuration for output pins rtc.cr().modify(|w| { w.set_out2en(false); - w.set_tampalrm_type(TampalrmType::PUSHPULL); + w.set_tampalrm_type(TampalrmType::PUSH_PULL); w.set_tampalrm_pu(false); }); }); @@ -56,10 +56,10 @@ impl super::Rtc { rtc.calr().write(|w| { match period { RtcCalibrationCyclePeriod::Seconds8 => { - w.set_calw8(Calw8::EIGHTSECONDS); + w.set_calw8(Calw8::EIGHT_SECONDS); } RtcCalibrationCyclePeriod::Seconds16 => { - w.set_calw16(Calw16::SIXTEENSECONDS); + w.set_calw16(Calw16::SIXTEEN_SECONDS); } RtcCalibrationCyclePeriod::Seconds32 => { // Set neither `calw8` nor `calw16` to use 32 seconds @@ -79,7 +79,7 @@ impl super::Rtc { // When the offset is positive (0 to 512), the opposite of // the offset (512 - offset) is masked, i.e. for the // maximum offset (512), 0 pulses are masked. - w.set_calp(Calp::INCREASEFREQ); + w.set_calp(Calp::INCREASE_FREQ); w.set_calm(512 - clock_drift as u16); } else { // Minimum (about -510.7) rounds to -511. @@ -88,7 +88,7 @@ impl super::Rtc { // When the offset is negative or zero (-511 to 0), // the absolute offset is masked, i.e. for the minimum // offset (-511), 511 pulses are masked. - w.set_calp(Calp::NOCHANGE); + w.set_calp(Calp::NO_CHANGE); w.set_calm((clock_drift * -1.0) as u16); } }); diff --git a/embassy-stm32/src/sai/mod.rs b/embassy-stm32/src/sai/mod.rs index a8d02f825..18d5d7568 100644 --- a/embassy-stm32/src/sai/mod.rs +++ b/embassy-stm32/src/sai/mod.rs @@ -52,12 +52,12 @@ impl Mode { const fn mode(&self, tx_rx: TxRx) -> vals::Mode { match tx_rx { TxRx::Transmitter => match self { - Mode::Master => vals::Mode::MASTERTX, - Mode::Slave => vals::Mode::SLAVETX, + Mode::Master => vals::Mode::MASTER_TX, + Mode::Slave => vals::Mode::SLAVE_TX, }, TxRx::Receiver => match self { - Mode::Master => vals::Mode::MASTERRX, - Mode::Slave => vals::Mode::SLAVERX, + Mode::Master => vals::Mode::MASTER_RX, + Mode::Slave => vals::Mode::SLAVE_RX, }, } } @@ -86,7 +86,7 @@ impl SlotSize { #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))] const fn slotsz(&self) -> vals::Slotsz { match self { - SlotSize::DataSize => vals::Slotsz::DATASIZE, + SlotSize::DataSize => vals::Slotsz::DATA_SIZE, SlotSize::Channel16 => vals::Slotsz::BIT16, SlotSize::Channel32 => vals::Slotsz::BIT32, } @@ -155,8 +155,8 @@ impl MuteValue { #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))] const fn muteval(&self) -> vals::Muteval { match self { - MuteValue::Zero => vals::Muteval::SENDZERO, - MuteValue::LastValue => vals::Muteval::SENDLAST, + MuteValue::Zero => vals::Muteval::SEND_ZERO, + MuteValue::LastValue => vals::Muteval::SEND_LAST, } } } @@ -251,8 +251,8 @@ impl BitOrder { #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))] const fn lsbfirst(&self) -> vals::Lsbfirst { match self { - BitOrder::LsbFirst => vals::Lsbfirst::LSBFIRST, - BitOrder::MsbFirst => vals::Lsbfirst::MSBFIRST, + BitOrder::LsbFirst => vals::Lsbfirst::LSB_FIRST, + BitOrder::MsbFirst => vals::Lsbfirst::MSB_FIRST, } } } @@ -270,8 +270,8 @@ impl FrameSyncOffset { #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))] const fn fsoff(&self) -> vals::Fsoff { match self { - FrameSyncOffset::OnFirstBit => vals::Fsoff::ONFIRST, - FrameSyncOffset::BeforeFirstBit => vals::Fsoff::BEFOREFIRST, + FrameSyncOffset::OnFirstBit => vals::Fsoff::ON_FIRST, + FrameSyncOffset::BeforeFirstBit => vals::Fsoff::BEFORE_FIRST, } } } @@ -289,8 +289,8 @@ impl FrameSyncPolarity { #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))] const fn fspol(&self) -> vals::Fspol { match self { - FrameSyncPolarity::ActiveLow => vals::Fspol::FALLINGEDGE, - FrameSyncPolarity::ActiveHigh => vals::Fspol::RISINGEDGE, + FrameSyncPolarity::ActiveLow => vals::Fspol::FALLING_EDGE, + FrameSyncPolarity::ActiveHigh => vals::Fspol::RISING_EDGE, } } } @@ -325,8 +325,8 @@ impl ClockStrobe { #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))] const fn ckstr(&self) -> vals::Ckstr { match self { - ClockStrobe::Falling => vals::Ckstr::FALLINGEDGE, - ClockStrobe::Rising => vals::Ckstr::RISINGEDGE, + ClockStrobe::Falling => vals::Ckstr::FALLING_EDGE, + ClockStrobe::Rising => vals::Ckstr::RISING_EDGE, } } } @@ -343,8 +343,8 @@ impl ComplementFormat { #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))] const fn cpl(&self) -> vals::Cpl { match self { - ComplementFormat::OnesComplement => vals::Cpl::ONESCOMPLEMENT, - ComplementFormat::TwosComplement => vals::Cpl::TWOSCOMPLEMENT, + ComplementFormat::OnesComplement => vals::Cpl::ONES_COMPLEMENT, + ComplementFormat::TwosComplement => vals::Cpl::TWOS_COMPLEMENT, } } } @@ -362,8 +362,8 @@ impl Companding { #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))] const fn comp(&self) -> vals::Comp { match self { - Companding::None => vals::Comp::NOCOMPANDING, - Companding::MuLaw => vals::Comp::MULAW, + Companding::None => vals::Comp::NO_COMPANDING, + Companding::MuLaw => vals::Comp::MU_LAW, Companding::ALaw => vals::Comp::ALAW, } } @@ -381,7 +381,7 @@ impl OutputDrive { #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))] const fn outdriv(&self) -> vals::Outdriv { match self { - OutputDrive::OnStart => vals::Outdriv::ONSTART, + OutputDrive::OnStart => vals::Outdriv::ON_START, OutputDrive::Immediately => vals::Outdriv::IMMEDIATELY, } } @@ -907,9 +907,9 @@ impl<'d, T: Instance, W: word::Word> Sai<'d, T, W> { w.set_mckdiv(config.master_clock_divider.mckdiv()); w.set_nodiv( if config.master_clock_divider == MasterClockDivider::MasterClockDisabled { - vals::Nodiv::NODIV + vals::Nodiv::NO_DIV } else { - vals::Nodiv::MASTERCLOCK + vals::Nodiv::MASTER_CLOCK }, ); w.set_dmaen(true); diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs index bf8284233..45893d24b 100644 --- a/embassy-stm32/src/spi/mod.rs +++ b/embassy-stm32/src/spi/mod.rs @@ -75,15 +75,15 @@ impl Default for Config { impl Config { fn raw_phase(&self) -> vals::Cpha { match self.mode.phase { - Phase::CaptureOnSecondTransition => vals::Cpha::SECONDEDGE, - Phase::CaptureOnFirstTransition => vals::Cpha::FIRSTEDGE, + Phase::CaptureOnSecondTransition => vals::Cpha::SECOND_EDGE, + Phase::CaptureOnFirstTransition => vals::Cpha::FIRST_EDGE, } } fn raw_polarity(&self) -> vals::Cpol { match self.mode.polarity { - Polarity::IdleHigh => vals::Cpol::IDLEHIGH, - Polarity::IdleLow => vals::Cpol::IDLELOW, + Polarity::IdleHigh => vals::Cpol::IDLE_HIGH, + Polarity::IdleLow => vals::Cpol::IDLE_LOW, } } @@ -180,7 +180,7 @@ impl<'d, M: PeriMode> Spi<'d, M> { // we're doing "fake rxonly", by actually writing one // byte to TXDR for each byte we want to receive. if we // set OUTPUTDISABLED here, this hangs. - w.set_rxonly(vals::Rxonly::FULLDUPLEX); + w.set_rxonly(vals::Rxonly::FULL_DUPLEX); w.set_dff(::CONFIG) }); } @@ -217,18 +217,18 @@ impl<'d, M: PeriMode> Spi<'d, M> { w.set_lsbfirst(lsbfirst); w.set_ssm(true); w.set_master(vals::Master::MASTER); - w.set_comm(vals::Comm::FULLDUPLEX); + w.set_comm(vals::Comm::FULL_DUPLEX); w.set_ssom(vals::Ssom::ASSERTED); w.set_midi(0); w.set_mssi(0); w.set_afcntr(true); - w.set_ssiop(vals::Ssiop::ACTIVEHIGH); + w.set_ssiop(vals::Ssiop::ACTIVE_HIGH); }); regs.cfg1().modify(|w| { w.set_crcen(false); w.set_mbr(br); w.set_dsize(::CONFIG); - w.set_fthlv(vals::Fthlv::ONEFRAME); + w.set_fthlv(vals::Fthlv::ONE_FRAME); }); regs.cr2().modify(|w| { w.set_tsize(0); @@ -291,12 +291,12 @@ impl<'d, M: PeriMode> Spi<'d, M> { #[cfg(any(spi_v3, spi_v4, spi_v5))] let cfg1 = self.info.regs.cfg1().read(); - let polarity = if cfg.cpol() == vals::Cpol::IDLELOW { + let polarity = if cfg.cpol() == vals::Cpol::IDLE_LOW { Polarity::IdleLow } else { Polarity::IdleHigh }; - let phase = if cfg.cpha() == vals::Cpha::FIRSTEDGE { + let phase = if cfg.cpha() == vals::Cpha::FIRST_EDGE { Phase::CaptureOnFirstTransition } else { Phase::CaptureOnSecondTransition @@ -693,8 +693,8 @@ impl<'d> Spi<'d, Async> { w.i2smod().then(|| { let prev = w.i2scfg(); w.set_i2scfg(match prev { - vals::I2scfg::SLAVERX | vals::I2scfg::SLAVEFULLDUPLEX => vals::I2scfg::SLAVERX, - vals::I2scfg::MASTERRX | vals::I2scfg::MASTERFULLDUPLEX => vals::I2scfg::MASTERRX, + vals::I2scfg::SLAVE_RX | vals::I2scfg::SLAVE_FULL_DUPLEX => vals::I2scfg::SLAVE_RX, + vals::I2scfg::MASTER_RX | vals::I2scfg::MASTER_FULL_DUPLEX => vals::I2scfg::MASTER_RX, _ => panic!("unsupported configuration"), }); prev diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs index fbe148359..7db74bdf6 100644 --- a/embassy-stm32/src/time_driver.rs +++ b/embassy-stm32/src/time_driver.rs @@ -246,9 +246,9 @@ impl RtcDriver { r.arr().write(|w| w.set_arr(u16::MAX)); // Set URS, generate update and clear URS - r.cr1().modify(|w| w.set_urs(vals::Urs::COUNTERONLY)); + r.cr1().modify(|w| w.set_urs(vals::Urs::COUNTER_ONLY)); r.egr().write(|w| w.set_ug(true)); - r.cr1().modify(|w| w.set_urs(vals::Urs::ANYEVENT)); + r.cr1().modify(|w| w.set_urs(vals::Urs::ANY_EVENT)); // Mid-way point r.ccr(0).write(|w| w.set_ccr(0x8000)); diff --git a/embassy-stm32/src/timer/input_capture.rs b/embassy-stm32/src/timer/input_capture.rs index 341ac2c04..b7c13343c 100644 --- a/embassy-stm32/src/timer/input_capture.rs +++ b/embassy-stm32/src/timer/input_capture.rs @@ -129,7 +129,7 @@ impl<'d, T: GeneralInstance4Channel> InputCapture<'d, T> { // Configuration steps from ST RM0390 (STM32F446) chapter 17.3.5 // or ST RM0008 (STM32F103) chapter 15.3.5 Input capture mode self.inner.set_input_ti_selection(channel, tisel); - self.inner.set_input_capture_filter(channel, FilterValue::NOFILTER); + self.inner.set_input_capture_filter(channel, FilterValue::NO_FILTER); self.inner.set_input_capture_mode(channel, mode); self.inner.set_input_capture_prescaler(channel, 0); self.inner.enable_channel(channel, true); diff --git a/embassy-stm32/src/timer/low_level.rs b/embassy-stm32/src/timer/low_level.rs index 7360d6aef..80f77586c 100644 --- a/embassy-stm32/src/timer/low_level.rs +++ b/embassy-stm32/src/timer/low_level.rs @@ -95,11 +95,11 @@ impl CountingMode { impl From for (vals::Cms, vals::Dir) { fn from(value: CountingMode) -> Self { match value { - CountingMode::EdgeAlignedUp => (vals::Cms::EDGEALIGNED, vals::Dir::UP), - CountingMode::EdgeAlignedDown => (vals::Cms::EDGEALIGNED, vals::Dir::DOWN), - CountingMode::CenterAlignedDownInterrupts => (vals::Cms::CENTERALIGNED1, vals::Dir::UP), - CountingMode::CenterAlignedUpInterrupts => (vals::Cms::CENTERALIGNED2, vals::Dir::UP), - CountingMode::CenterAlignedBothInterrupts => (vals::Cms::CENTERALIGNED3, vals::Dir::UP), + CountingMode::EdgeAlignedUp => (vals::Cms::EDGE_ALIGNED, vals::Dir::UP), + CountingMode::EdgeAlignedDown => (vals::Cms::EDGE_ALIGNED, vals::Dir::DOWN), + CountingMode::CenterAlignedDownInterrupts => (vals::Cms::CENTER_ALIGNED1, vals::Dir::UP), + CountingMode::CenterAlignedUpInterrupts => (vals::Cms::CENTER_ALIGNED2, vals::Dir::UP), + CountingMode::CenterAlignedBothInterrupts => (vals::Cms::CENTER_ALIGNED3, vals::Dir::UP), } } } @@ -107,11 +107,11 @@ impl From for (vals::Cms, vals::Dir) { impl From<(vals::Cms, vals::Dir)> for CountingMode { fn from(value: (vals::Cms, vals::Dir)) -> Self { match value { - (vals::Cms::EDGEALIGNED, vals::Dir::UP) => CountingMode::EdgeAlignedUp, - (vals::Cms::EDGEALIGNED, vals::Dir::DOWN) => CountingMode::EdgeAlignedDown, - (vals::Cms::CENTERALIGNED1, _) => CountingMode::CenterAlignedDownInterrupts, - (vals::Cms::CENTERALIGNED2, _) => CountingMode::CenterAlignedUpInterrupts, - (vals::Cms::CENTERALIGNED3, _) => CountingMode::CenterAlignedBothInterrupts, + (vals::Cms::EDGE_ALIGNED, vals::Dir::UP) => CountingMode::EdgeAlignedUp, + (vals::Cms::EDGE_ALIGNED, vals::Dir::DOWN) => CountingMode::EdgeAlignedDown, + (vals::Cms::CENTER_ALIGNED1, _) => CountingMode::CenterAlignedDownInterrupts, + (vals::Cms::CENTER_ALIGNED2, _) => CountingMode::CenterAlignedUpInterrupts, + (vals::Cms::CENTER_ALIGNED3, _) => CountingMode::CenterAlignedBothInterrupts, } } } @@ -150,13 +150,13 @@ impl From for stm32_metapac::timer::vals::Ocm { fn from(mode: OutputCompareMode) -> Self { match mode { OutputCompareMode::Frozen => stm32_metapac::timer::vals::Ocm::FROZEN, - OutputCompareMode::ActiveOnMatch => stm32_metapac::timer::vals::Ocm::ACTIVEONMATCH, - OutputCompareMode::InactiveOnMatch => stm32_metapac::timer::vals::Ocm::INACTIVEONMATCH, + OutputCompareMode::ActiveOnMatch => stm32_metapac::timer::vals::Ocm::ACTIVE_ON_MATCH, + OutputCompareMode::InactiveOnMatch => stm32_metapac::timer::vals::Ocm::INACTIVE_ON_MATCH, OutputCompareMode::Toggle => stm32_metapac::timer::vals::Ocm::TOGGLE, - OutputCompareMode::ForceInactive => stm32_metapac::timer::vals::Ocm::FORCEINACTIVE, - OutputCompareMode::ForceActive => stm32_metapac::timer::vals::Ocm::FORCEACTIVE, - OutputCompareMode::PwmMode1 => stm32_metapac::timer::vals::Ocm::PWMMODE1, - OutputCompareMode::PwmMode2 => stm32_metapac::timer::vals::Ocm::PWMMODE2, + OutputCompareMode::ForceInactive => stm32_metapac::timer::vals::Ocm::FORCE_INACTIVE, + OutputCompareMode::ForceActive => stm32_metapac::timer::vals::Ocm::FORCE_ACTIVE, + OutputCompareMode::PwmMode1 => stm32_metapac::timer::vals::Ocm::PWM_MODE1, + OutputCompareMode::PwmMode2 => stm32_metapac::timer::vals::Ocm::PWM_MODE2, } } } @@ -271,9 +271,9 @@ impl<'d, T: CoreInstance> Timer<'d, T> { regs.psc().write_value(psc); regs.arr().write(|r| r.set_arr(arr)); - regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTERONLY)); + regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTER_ONLY)); regs.egr().write(|r| r.set_ug(true)); - regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT)); + regs.cr1().modify(|r| r.set_urs(vals::Urs::ANY_EVENT)); } #[cfg(not(stm32l0))] TimerBits::Bits32 => { @@ -284,9 +284,9 @@ impl<'d, T: CoreInstance> Timer<'d, T> { regs.psc().write_value(psc); regs.arr().write_value(arr); - regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTERONLY)); + regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTER_ONLY)); regs.egr().write(|r| r.set_ug(true)); - regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT)); + regs.cr1().modify(|r| r.set_urs(vals::Urs::ANY_EVENT)); } } } diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs index 56fb1871e..6d5d6c062 100644 --- a/embassy-stm32/src/timer/simple_pwm.rs +++ b/embassy-stm32/src/timer/simple_pwm.rs @@ -292,7 +292,7 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> { /// Generate a sequence of PWM waveform /// - /// Note: + /// Note: /// you will need to provide corresponding TIMx_UP DMA channel to use this method. pub async fn waveform_up( &mut self, @@ -377,12 +377,12 @@ macro_rules! impl_waveform_chx { let original_duty_state = self.channel(cc_channel).current_duty_cycle(); let original_enable_state = self.channel(cc_channel).is_enabled(); - let original_cc_dma_on_update = self.inner.get_cc_dma_selection() == Ccds::ONUPDATE; + let original_cc_dma_on_update = self.inner.get_cc_dma_selection() == Ccds::ON_UPDATE; let original_cc_dma_enabled = self.inner.get_cc_dma_enable_state(cc_channel); // redirect CC DMA request onto Update Event if !original_cc_dma_on_update { - self.inner.set_cc_dma_selection(Ccds::ONUPDATE) + self.inner.set_cc_dma_selection(Ccds::ON_UPDATE) } if !original_cc_dma_enabled { @@ -433,7 +433,7 @@ macro_rules! impl_waveform_chx { } if !original_cc_dma_on_update { - self.inner.set_cc_dma_selection(Ccds::ONCOMPARE) + self.inner.set_cc_dma_selection(Ccds::ON_COMPARE) } } } diff --git a/embassy-stm32/src/ucpd.rs b/embassy-stm32/src/ucpd.rs index fd5b952ef..2d44bf8ff 100644 --- a/embassy-stm32/src/ucpd.rs +++ b/embassy-stm32/src/ucpd.rs @@ -484,11 +484,11 @@ impl<'d, T: Instance> PdPhy<'d, T> { let sop = match r.rx_ordsetr().read().rxordset() { Rxordset::SOP => Sop::Sop, - Rxordset::SOPPRIME => Sop::SopPrime, - Rxordset::SOPDOUBLEPRIME => Sop::SopDoublePrime, - Rxordset::SOPPRIMEDEBUG => Sop::SopPrimeDebug, - Rxordset::SOPDOUBLEPRIMEDEBUG => Sop::SopDoublePrimeDebug, - Rxordset::CABLERESET => return Err(RxError::HardReset), + Rxordset::SOP_PRIME => Sop::SopPrime, + Rxordset::SOP_DOUBLE_PRIME => Sop::SopDoublePrime, + Rxordset::SOP_PRIME_DEBUG => Sop::SopPrimeDebug, + Rxordset::SOP_DOUBLE_PRIME_DEBUG => Sop::SopDoublePrimeDebug, + Rxordset::CABLE_RESET => return Err(RxError::HardReset), // Extension headers are not supported _ => unreachable!(), }; diff --git a/examples/stm32f469/src/bin/dsi_bsp.rs b/examples/stm32f469/src/bin/dsi_bsp.rs index e4e9e9c01..3a24d5dcf 100644 --- a/examples/stm32f469/src/bin/dsi_bsp.rs +++ b/examples/stm32f469/src/bin/dsi_bsp.rs @@ -363,20 +363,20 @@ async fn main(_spawner: Spawner) { const _PCPOLARITY: bool = false; // LTDC_PCPOLARITY_IPC == 0 const LTDC_DE_POLARITY: Depol = if !DE_POLARITY { - Depol::ACTIVELOW + Depol::ACTIVE_LOW } else { - Depol::ACTIVEHIGH + Depol::ACTIVE_HIGH }; const LTDC_VS_POLARITY: Vspol = if !VS_POLARITY { - Vspol::ACTIVEHIGH + Vspol::ACTIVE_HIGH } else { - Vspol::ACTIVELOW + Vspol::ACTIVE_LOW }; const LTDC_HS_POLARITY: Hspol = if !HS_POLARITY { - Hspol::ACTIVEHIGH + Hspol::ACTIVE_HIGH } else { - Hspol::ACTIVELOW + Hspol::ACTIVE_LOW }; /* Timing Configuration */ @@ -397,7 +397,7 @@ async fn main(_spawner: Spawner) { w.set_hspol(LTDC_HS_POLARITY); w.set_vspol(LTDC_VS_POLARITY); w.set_depol(LTDC_DE_POLARITY); - w.set_pcpol(Pcpol::RISINGEDGE); + w.set_pcpol(Pcpol::RISING_EDGE); }); // Set Synchronization size From cf606a161f9bed59f912f3e521bc48a8cda11d6f Mon Sep 17 00:00:00 2001 From: elagil Date: Fri, 3 Jan 2025 22:57:31 +0100 Subject: [PATCH 0597/1217] fix: STM32F4 I2S clock calculations --- embassy-stm32/build.rs | 10 ++++++++++ embassy-stm32/src/i2s.rs | 8 ++++---- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index e293cf965..a70524916 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -712,6 +712,16 @@ fn main() { // Generate RCC clock_gen.clock_names.insert("sys".to_string()); clock_gen.clock_names.insert("rtc".to_string()); + + // STM32F4 SPI in I2S mode receives a clock input from the dedicated I2S PLL. + // For this, there is an additional clock MUX, which is not present in other + // peripherals and does not fit the current RCC structure of stm32-data. + if chip_name.starts_with("stm32f4") && !chip_name.starts_with("stm32f410") { + clock_gen.clock_names.insert("plli2s1_p".to_string()); + clock_gen.clock_names.insert("plli2s1_q".to_string()); + clock_gen.clock_names.insert("plli2s1_r".to_string()); + } + let clock_idents: Vec<_> = clock_gen.clock_names.iter().map(|n| format_ident!("{}", n)).collect(); g.extend(quote! { #[derive(Clone, Copy, Debug)] diff --git a/embassy-stm32/src/i2s.rs b/embassy-stm32/src/i2s.rs index 79d6279f6..1a7393ba4 100644 --- a/embassy-stm32/src/i2s.rs +++ b/embassy-stm32/src/i2s.rs @@ -7,6 +7,7 @@ use stm32_metapac::spi::vals; use crate::dma::{ringbuffer, ChannelAndRequest, ReadableRingBuffer, TransferOptions, WritableRingBuffer}; use crate::gpio::{AfType, AnyPin, OutputType, SealedPin, Speed}; use crate::mode::Async; +use crate::rcc::get_freqs; use crate::spi::{Config as SpiConfig, RegsExt as _, *}; use crate::time::Hertz; use crate::{Peripheral, PeripheralRef}; @@ -491,10 +492,9 @@ impl<'d, W: Word> I2S<'d, W> { let regs = T::info().regs; - // TODO move i2s to the new mux infra. - //#[cfg(all(rcc_f4, not(stm32f410)))] - //let pclk = unsafe { get_freqs() }.plli2s1_q.unwrap(); - //#[cfg(stm32f410)] + #[cfg(all(rcc_f4, not(stm32f410)))] + let pclk = unsafe { get_freqs() }.plli2s1_r.to_hertz().unwrap(); + #[cfg(stm32f410)] let pclk = T::frequency(); let (odd, div) = compute_baud_rate(pclk, freq, config.master_clock, config.format); From 24fdd25e5102e1e21bb40d58d4423536882d31ba Mon Sep 17 00:00:00 2001 From: elagil Date: Fri, 3 Jan 2025 23:01:46 +0100 Subject: [PATCH 0598/1217] fix: configuration logic --- embassy-stm32/src/i2s.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/src/i2s.rs b/embassy-stm32/src/i2s.rs index 1a7393ba4..f5ec97d02 100644 --- a/embassy-stm32/src/i2s.rs +++ b/embassy-stm32/src/i2s.rs @@ -494,7 +494,7 @@ impl<'d, W: Word> I2S<'d, W> { #[cfg(all(rcc_f4, not(stm32f410)))] let pclk = unsafe { get_freqs() }.plli2s1_r.to_hertz().unwrap(); - #[cfg(stm32f410)] + #[cfg(not(all(rcc_f4, not(stm32f410))))] let pclk = T::frequency(); let (odd, div) = compute_baud_rate(pclk, freq, config.master_clock, config.format); From a901fe2f025ac4bdc78bbf9774c67f16b8abf72d Mon Sep 17 00:00:00 2001 From: elagil Date: Fri, 3 Jan 2025 23:03:42 +0100 Subject: [PATCH 0599/1217] fix: unused import --- embassy-stm32/src/i2s.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/embassy-stm32/src/i2s.rs b/embassy-stm32/src/i2s.rs index f5ec97d02..518371af8 100644 --- a/embassy-stm32/src/i2s.rs +++ b/embassy-stm32/src/i2s.rs @@ -7,7 +7,6 @@ use stm32_metapac::spi::vals; use crate::dma::{ringbuffer, ChannelAndRequest, ReadableRingBuffer, TransferOptions, WritableRingBuffer}; use crate::gpio::{AfType, AnyPin, OutputType, SealedPin, Speed}; use crate::mode::Async; -use crate::rcc::get_freqs; use crate::spi::{Config as SpiConfig, RegsExt as _, *}; use crate::time::Hertz; use crate::{Peripheral, PeripheralRef}; @@ -493,7 +492,7 @@ impl<'d, W: Word> I2S<'d, W> { let regs = T::info().regs; #[cfg(all(rcc_f4, not(stm32f410)))] - let pclk = unsafe { get_freqs() }.plli2s1_r.to_hertz().unwrap(); + let pclk = unsafe { crate::rcc::get_freqs() }.plli2s1_r.to_hertz().unwrap(); #[cfg(not(all(rcc_f4, not(stm32f410))))] let pclk = T::frequency(); From d672dc8626003002869c2d131589fafce6d07059 Mon Sep 17 00:00:00 2001 From: elagil Date: Fri, 3 Jan 2025 23:40:09 +0100 Subject: [PATCH 0600/1217] fix: unneeded mutability --- embassy-stm32/src/i2s.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/src/i2s.rs b/embassy-stm32/src/i2s.rs index 518371af8..ce166d718 100644 --- a/embassy-stm32/src/i2s.rs +++ b/embassy-stm32/src/i2s.rs @@ -458,7 +458,7 @@ impl<'d, W: Word> I2S<'d, W> { /// Write data directly to the raw I2S ringbuffer. /// This can be used to fill the buffer before starting the DMA transfer. - pub async fn write_immediate(&mut self, data: &mut [W]) -> Result<(usize, usize), Error> { + pub async fn write_immediate(&mut self, data: &[W]) -> Result<(usize, usize), Error> { match &mut self.tx_ring_buffer { Some(ring) => Ok(ring.write_immediate(data)?), _ => return Err(Error::NotATransmitter), From 2cc50bac444e8bbf081f2ffbea0170d507b9be71 Mon Sep 17 00:00:00 2001 From: Gabriel Smith Date: Fri, 3 Jan 2025 22:10:04 -0500 Subject: [PATCH 0601/1217] stm32: Update stm32-data --- embassy-stm32/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 229f902fa..df4f9f371 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -73,7 +73,7 @@ rand_core = "0.6.3" sdio-host = "0.5.0" critical-section = "1.1" #stm32-metapac = { version = "15" } -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-567fd0b1b7dfd9c1aa9e54d365547afe1ceb1241" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-274eeb0ed4477768d026276c4e9873586c1b9a05" } vcell = "0.1.3" nb = "1.0.0" @@ -102,7 +102,7 @@ proc-macro2 = "1.0.36" quote = "1.0.15" #stm32-metapac = { version = "15", default-features = false, features = ["metadata"]} -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-567fd0b1b7dfd9c1aa9e54d365547afe1ceb1241", default-features = false, features = ["metadata"] } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-274eeb0ed4477768d026276c4e9873586c1b9a05", default-features = false, features = ["metadata"] } [features] default = ["rt"] From ca349813ab073108b13b226b0a7dd74bdb88bf5a Mon Sep 17 00:00:00 2001 From: Reed Date: Sat, 4 Jan 2025 21:20:43 +1300 Subject: [PATCH 0602/1217] Remove un-needed embassy-eh time feature --- embassy-nrf/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml index 45666ade8..5a7f4cfb1 100644 --- a/embassy-nrf/Cargo.toml +++ b/embassy-nrf/Cargo.toml @@ -139,7 +139,7 @@ embassy-time-queue-utils = { version = "0.1", path = "../embassy-time-queue-util embassy-time = { version = "0.4.0", path = "../embassy-time", optional = true } embassy-sync = { version = "0.6.1", path = "../embassy-sync" } embassy-hal-internal = {version = "0.2.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-3"] } -embassy-embedded-hal = {version = "0.2.0", path = "../embassy-embedded-hal" } +embassy-embedded-hal = {version = "0.2.0", path = "../embassy-embedded-hal", default-features = false } embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver" } embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } From 0d824beb1139ad18d36a5e3a321f2c3fb46ce868 Mon Sep 17 00:00:00 2001 From: Reed Date: Sat, 4 Jan 2025 21:26:46 +1300 Subject: [PATCH 0603/1217] Enable embassy-eh time feature when appropriate --- embassy-nrf/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml index 5a7f4cfb1..79e919f68 100644 --- a/embassy-nrf/Cargo.toml +++ b/embassy-nrf/Cargo.toml @@ -32,7 +32,7 @@ default = ["rt"] rt = ["nrf-pac/rt"] ## Enable features requiring `embassy-time` -time = ["dep:embassy-time"] +time = ["dep:embassy-time", "embassy-embedded-hal/time"] ## Enable defmt defmt = ["dep:defmt", "embassy-hal-internal/defmt", "embassy-sync/defmt", "embassy-usb-driver/defmt", "embassy-embedded-hal/defmt"] @@ -119,7 +119,7 @@ _nrf52 = ["_ppi"] _nrf51 = ["_ppi"] _nrf91 = [] -_time-driver = ["dep:embassy-time-driver", "embassy-time-driver?/tick-hz-32_768", "dep:embassy-time-queue-utils"] +_time-driver = ["dep:embassy-time-driver", "embassy-time-driver?/tick-hz-32_768", "dep:embassy-time-queue-utils", "embassy-embedded-hal/time"] # trustzone state. _s = [] From ff526e1604f4e9edc682f4bc270ddc815a860e48 Mon Sep 17 00:00:00 2001 From: Liu Hancheng Date: Sat, 4 Jan 2025 20:16:34 +0800 Subject: [PATCH 0604/1217] refactor: update DMA transfer functions to use separate memory and peripheral sizes --- embassy-stm32/src/dma/dma_bdma.rs | 38 ++++++++++++++++++--------- embassy-stm32/src/timer/simple_pwm.rs | 26 +++++++----------- 2 files changed, 35 insertions(+), 29 deletions(-) diff --git a/embassy-stm32/src/dma/dma_bdma.rs b/embassy-stm32/src/dma/dma_bdma.rs index 1945c3587..8b4b454c0 100644 --- a/embassy-stm32/src/dma/dma_bdma.rs +++ b/embassy-stm32/src/dma/dma_bdma.rs @@ -340,7 +340,8 @@ impl AnyChannel { mem_addr: *mut u32, mem_len: usize, incr_mem: bool, - data_size: WordSize, + mem_size: WordSize, + peripheral_size: WordSize, options: TransferOptions, ) { let info = self.info(); @@ -380,8 +381,8 @@ impl AnyChannel { }); ch.cr().write(|w| { w.set_dir(dir.into()); - w.set_msize(data_size.into()); - w.set_psize(data_size.into()); + w.set_msize(mem_size.into()); + w.set_psize(peripheral_size.into()); w.set_pl(options.priority.into()); w.set_minc(incr_mem); w.set_pinc(false); @@ -414,8 +415,8 @@ impl AnyChannel { ch.mar().write_value(mem_addr as u32); ch.ndtr().write(|w| w.set_ndt(mem_len as u16)); ch.cr().write(|w| { - w.set_psize(data_size.into()); - w.set_msize(data_size.into()); + w.set_psize(peripheral_size.into()); + w.set_msize(mem_size.into()); w.set_minc(incr_mem); w.set_dir(dir.into()); w.set_teie(true); @@ -602,27 +603,28 @@ impl<'a> Transfer<'a> { buf.len(), true, W::size(), + W::size(), options, ) } /// Create a new write DMA transfer (memory to peripheral). - pub unsafe fn new_write( + pub unsafe fn new_write( channel: impl Peripheral

+ 'a, request: Request, - buf: &'a [W], - peri_addr: *mut W, + buf: &'a [MW], + peri_addr: *mut PW, options: TransferOptions, ) -> Self { Self::new_write_raw(channel, request, buf, peri_addr, options) } /// Create a new write DMA transfer (memory to peripheral), using raw pointers. - pub unsafe fn new_write_raw( + pub unsafe fn new_write_raw( channel: impl Peripheral

+ 'a, request: Request, buf: *const [W], - peri_addr: *mut W, + peri_addr: *mut PW, options: TransferOptions, ) -> Self { into_ref!(channel); @@ -636,6 +638,7 @@ impl<'a> Transfer<'a> { buf.len(), true, W::size(), + W::size(), options, ) } @@ -660,6 +663,7 @@ impl<'a> Transfer<'a> { count, false, W::size(), + W::size(), options, ) } @@ -673,15 +677,23 @@ impl<'a> Transfer<'a> { mem_len: usize, incr_mem: bool, data_size: WordSize, + peripheral_size: WordSize, options: TransferOptions, ) -> Self { assert!(mem_len > 0 && mem_len <= 0xFFFF); channel.configure( - _request, dir, peri_addr, mem_addr, mem_len, incr_mem, data_size, options, + _request, + dir, + peri_addr, + mem_addr, + mem_len, + incr_mem, + data_size, + peripheral_size, + options, ); channel.start(); - Self { channel } } @@ -814,6 +826,7 @@ impl<'a, W: Word> ReadableRingBuffer<'a, W> { len, true, data_size, + data_size, options, ); @@ -966,6 +979,7 @@ impl<'a, W: Word> WritableRingBuffer<'a, W> { len, true, data_size, + data_size, options, ); diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs index f36fa026c..8d3c9a131 100644 --- a/embassy-stm32/src/timer/simple_pwm.rs +++ b/embassy-stm32/src/timer/simple_pwm.rs @@ -334,7 +334,7 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> { &mut dma, req, duty, - self.inner.regs_1ch().ccr(channel.index()).as_ptr() as *mut _, + self.inner.regs_1ch().ccr(channel.index()).as_ptr() as *mut u16, dma_transfer_option, ) .await @@ -362,13 +362,7 @@ macro_rules! impl_waveform_chx { ($fn_name:ident, $dma_ch:ident, $cc_ch:ident) => { impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> { /// Generate a sequence of PWM waveform - /// - /// Note: - /// 1. you will need to provide corresponding TIMx_CHy DMA channel to use this method. - /// 2. Please make sure the duty data length is aligned to the timer data width(16-bit or 32-bit). - /// 3. Please notice the endianess of the duty data. STM32 use little endian, - /// for example, 0x12345678 as u32 will be stored as [0x78, 0x56, 0x34, 0x12] in memory. - pub async fn $fn_name(&mut self, dma: impl Peripheral

>, duty: &[u8]) { + pub async fn $fn_name(&mut self, dma: impl Peripheral

>, duty: &[u16]) { use crate::pac::timer::vals::Ccds; into_ref!(dma); @@ -411,32 +405,30 @@ macro_rules! impl_waveform_chx { match self.inner.bits() { TimerBits::Bits16 => { - // the data must be aligned to double words - assert!(duty.len() % 2 == 0); - let duty = core::slice::from_raw_parts(duty.as_ptr() as *const u16, duty.len() / 2); Transfer::new_write( &mut dma, req, duty, - self.inner.regs_gp16().ccr(cc_channel.index()).as_ptr() as *mut _, + self.inner.regs_gp16().ccr(cc_channel.index()).as_ptr() as *mut u16, dma_transfer_option, ) .await } - #[cfg(not(stm32l0))] + #[cfg(not(any(stm32l0, bdma, gpdma)))] TimerBits::Bits32 => { - // the data must be aligned to quad words - assert!(duty.len() % 4 == 0); - let duty = core::slice::from_raw_parts(duty.as_ptr() as *const u32, duty.len() / 4); Transfer::new_write( &mut dma, req, duty, - self.inner.regs_gp16().ccr(cc_channel.index()).as_ptr() as *mut _, + self.inner.regs_gp16().ccr(cc_channel.index()).as_ptr() as *mut u32, dma_transfer_option, ) .await } + #[cfg(any(stm32l0, bdma, gpdma))] + _ => { + panic!("unsupported timer bits") + } }; }; From 7d74d15b184a58f010551571051055ce9ca0023a Mon Sep 17 00:00:00 2001 From: Liu Hancheng Date: Sat, 4 Jan 2025 21:10:32 +0800 Subject: [PATCH 0605/1217] refactor: update DMA pointer types for cryp and hash modules --- embassy-stm32/src/cryp/mod.rs | 8 ++++---- embassy-stm32/src/hash/mod.rs | 15 +++++++++++---- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/embassy-stm32/src/cryp/mod.rs b/embassy-stm32/src/cryp/mod.rs index 8d600c73c..6afe68a39 100644 --- a/embassy-stm32/src/cryp/mod.rs +++ b/embassy-stm32/src/cryp/mod.rs @@ -1785,9 +1785,9 @@ impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> { assert_eq!(blocks.len() % block_size, 0); // Configure DMA to transfer input to crypto core. let dma_request = dma.request(); - let dst_ptr = T::regs().din().as_ptr(); + let dst_ptr: *mut u32 = T::regs().din().as_ptr(); let num_words = blocks.len() / 4; - let src_ptr = ptr::slice_from_raw_parts(blocks.as_ptr().cast(), num_words); + let src_ptr: *const [u8] = ptr::slice_from_raw_parts(blocks.as_ptr().cast(), num_words); let options = TransferOptions { #[cfg(not(gpdma))] priority: crate::dma::Priority::High, @@ -1825,9 +1825,9 @@ impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> { assert_eq!((blocks.len() * 4) % block_size, 0); // Configure DMA to transfer input to crypto core. let dma_request = dma.request(); - let dst_ptr = T::regs().din().as_ptr(); + let dst_ptr: *mut u32 = T::regs().din().as_ptr(); let num_words = blocks.len(); - let src_ptr = ptr::slice_from_raw_parts(blocks.as_ptr().cast(), num_words); + let src_ptr: *const [u32] = ptr::slice_from_raw_parts(blocks.as_ptr().cast(), num_words); let options = TransferOptions { #[cfg(not(gpdma))] priority: crate::dma::Priority::High, diff --git a/embassy-stm32/src/hash/mod.rs b/embassy-stm32/src/hash/mod.rs index 4d4a8ec5b..3c2125498 100644 --- a/embassy-stm32/src/hash/mod.rs +++ b/embassy-stm32/src/hash/mod.rs @@ -515,14 +515,21 @@ impl<'d, T: Instance, D> Hash<'d, T, D> { // Configure DMA to transfer input to hash core. let dma_request = self.dma.request(); - let dst_ptr = T::regs().din().as_ptr(); + let dst_ptr: *mut u32 = T::regs().din().as_ptr(); let mut num_words = input.len() / 4; if input.len() % 4 > 0 { num_words += 1; } - let src_ptr = ptr::slice_from_raw_parts(input.as_ptr().cast(), num_words); - let dma_transfer = - unsafe { Transfer::new_write_raw(&mut self.dma, dma_request, src_ptr, dst_ptr, Default::default()) }; + let src_ptr: *const [u8] = ptr::slice_from_raw_parts(input.as_ptr().cast(), num_words); + let dma_transfer = unsafe { + Transfer::new_write_raw( + &mut self.dma, + dma_request, + src_ptr, + dst_ptr as *mut u32, + Default::default(), + ) + }; T::regs().cr().modify(|w| w.set_dmae(true)); // Wait for the transfer to complete. From 03dd50316c6f41a2bfab62289aa22abdaaa3189d Mon Sep 17 00:00:00 2001 From: Liu Hancheng Date: Sat, 4 Jan 2025 21:38:22 +0800 Subject: [PATCH 0606/1217] refactor: simplify timer bits handling --- embassy-stm32/src/timer/simple_pwm.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs index 8d3c9a131..757536c2d 100644 --- a/embassy-stm32/src/timer/simple_pwm.rs +++ b/embassy-stm32/src/timer/simple_pwm.rs @@ -414,8 +414,10 @@ macro_rules! impl_waveform_chx { ) .await } - #[cfg(not(any(stm32l0, bdma, gpdma)))] + #[cfg(not(any(stm32l0)))] TimerBits::Bits32 => { + #[cfg(any(bdma, gpdma))] + panic("unsupported timer bits"); Transfer::new_write( &mut dma, req, @@ -425,10 +427,6 @@ macro_rules! impl_waveform_chx { ) .await } - #[cfg(any(stm32l0, bdma, gpdma))] - _ => { - panic!("unsupported timer bits") - } }; }; From 50e98a9a58bf7f3356aa8261ba301d4d1c6440aa Mon Sep 17 00:00:00 2001 From: Liu Hancheng Date: Sat, 4 Jan 2025 22:10:47 +0800 Subject: [PATCH 0607/1217] refactor: update DMA transfer functions to support separate memory and peripheral word types --- embassy-stm32/src/dma/gpdma.rs | 32 +++++++++++++++------------ embassy-stm32/src/timer/simple_pwm.rs | 4 +++- 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/embassy-stm32/src/dma/gpdma.rs b/embassy-stm32/src/dma/gpdma.rs index a877bb8d4..e57bf04ed 100644 --- a/embassy-stm32/src/dma/gpdma.rs +++ b/embassy-stm32/src/dma/gpdma.rs @@ -143,27 +143,28 @@ impl<'a> Transfer<'a> { buf.len(), true, W::size(), + W::size(), options, ) } /// Create a new write DMA transfer (memory to peripheral). - pub unsafe fn new_write( + pub unsafe fn new_write( channel: impl Peripheral

+ 'a, request: Request, - buf: &'a [W], - peri_addr: *mut W, + buf: &'a [MW], + peri_addr: *mut PW, options: TransferOptions, ) -> Self { Self::new_write_raw(channel, request, buf, peri_addr, options) } /// Create a new write DMA transfer (memory to peripheral), using raw pointers. - pub unsafe fn new_write_raw( + pub unsafe fn new_write_raw( channel: impl Peripheral

+ 'a, request: Request, - buf: *const [W], - peri_addr: *mut W, + buf: *const [MW], + peri_addr: *mut PW, options: TransferOptions, ) -> Self { into_ref!(channel); @@ -173,21 +174,22 @@ impl<'a> Transfer<'a> { request, Dir::MemoryToPeripheral, peri_addr as *const u32, - buf as *const W as *mut u32, + buf as *const MW as *mut u32, buf.len(), true, - W::size(), + MW::size(), + PW::size(), options, ) } /// Create a new write DMA transfer (memory to peripheral), writing the same value repeatedly. - pub unsafe fn new_write_repeated( + pub unsafe fn new_write_repeated( channel: impl Peripheral

+ 'a, request: Request, - repeated: &'a W, + repeated: &'a MW, count: usize, - peri_addr: *mut W, + peri_addr: *mut PW, options: TransferOptions, ) -> Self { into_ref!(channel); @@ -197,10 +199,11 @@ impl<'a> Transfer<'a> { request, Dir::MemoryToPeripheral, peri_addr as *const u32, - repeated as *const W as *mut u32, + repeated as *const MW as *mut u32, count, false, - W::size(), + MW::size(), + PW::size(), options, ) } @@ -214,6 +217,7 @@ impl<'a> Transfer<'a> { mem_len: usize, incr_mem: bool, data_size: WordSize, + dst_size: WordSize, _options: TransferOptions, ) -> Self { // BNDT is specified as bytes, not as number of transfers. @@ -234,7 +238,7 @@ impl<'a> Transfer<'a> { ch.llr().write(|_| {}); // no linked list ch.tr1().write(|w| { w.set_sdw(data_size.into()); - w.set_ddw(data_size.into()); + w.set_ddw(dst_size.into()); w.set_sinc(dir == Dir::MemoryToPeripheral && incr_mem); w.set_dinc(dir == Dir::PeripheralToMemory && incr_mem); }); diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs index 757536c2d..5b3cf8fea 100644 --- a/embassy-stm32/src/timer/simple_pwm.rs +++ b/embassy-stm32/src/timer/simple_pwm.rs @@ -416,8 +416,10 @@ macro_rules! impl_waveform_chx { } #[cfg(not(any(stm32l0)))] TimerBits::Bits32 => { + #[cfg(not(any(bdma, gpdma)))] + panic!("unsupported timer bits"); + #[cfg(any(bdma, gpdma))] - panic("unsupported timer bits"); Transfer::new_write( &mut dma, req, From 4c8ee8786f4b0e9307189c032c33beb00bb159cf Mon Sep 17 00:00:00 2001 From: Gabriel Smith Date: Fri, 3 Jan 2025 10:41:04 -0500 Subject: [PATCH 0608/1217] stm32: Implement reads of DTS peripheral Only PCLK-driven operation is supported. --- embassy-stm32/src/dts/mod.rs | 239 ++++++++++++++++++++++++++++++++ embassy-stm32/src/dts/tsel.rs | 51 +++++++ embassy-stm32/src/lib.rs | 2 + examples/stm32h5/src/bin/dts.rs | 75 ++++++++++ 4 files changed, 367 insertions(+) create mode 100644 embassy-stm32/src/dts/mod.rs create mode 100644 embassy-stm32/src/dts/tsel.rs create mode 100644 examples/stm32h5/src/bin/dts.rs diff --git a/embassy-stm32/src/dts/mod.rs b/embassy-stm32/src/dts/mod.rs new file mode 100644 index 000000000..58d7cf841 --- /dev/null +++ b/embassy-stm32/src/dts/mod.rs @@ -0,0 +1,239 @@ +//! Digital Temperature Sensor (DTS) + +use core::future::poll_fn; +use core::sync::atomic::{compiler_fence, Ordering}; +use core::task::Poll; + +use embassy_hal_internal::{into_ref, PeripheralRef}; +use embassy_sync::waitqueue::AtomicWaker; + +use crate::interrupt::InterruptExt; +use crate::peripherals::DTS; +use crate::time::Hertz; +use crate::{interrupt, pac, rcc, Peripheral}; + +mod tsel; +pub use tsel::TriggerSel; + +#[allow(missing_docs)] +#[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Copy, Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum SampleTime { + ClockCycles1 = 1, + ClockCycles2 = 2, + ClockCycles3 = 3, + ClockCycles4 = 4, + ClockCycles5 = 5, + ClockCycles6 = 6, + ClockCycles7 = 7, + ClockCycles8 = 8, + ClockCycles9 = 9, + ClockCycles10 = 10, + ClockCycles11 = 11, + ClockCycles12 = 12, + ClockCycles13 = 13, + ClockCycles14 = 14, + ClockCycles15 = 15, +} + +#[non_exhaustive] +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +/// Config +pub struct Config { + /// Sample time + pub sample_time: SampleTime, + /// Trigger selection + pub trigger: TriggerSel, +} + +impl Default for Config { + fn default() -> Self { + Self { + sample_time: SampleTime::ClockCycles1, + trigger: TriggerSel::Software, + } + } +} + +/// The read-only factory calibration values used for converting a +/// measurement to a temperature. +#[derive(Clone, Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct FactoryCalibration { + /// The calibration temperature in degrees Celsius. + pub t0: u8, + /// The frequency at the calibration temperature. + pub fmt0: Hertz, + /// The ramp coefficient in Hertz per degree Celsius. + pub ramp_coeff: u16, +} + +const MAX_DTS_CLK_FREQ: Hertz = Hertz::mhz(1); + +/// Digital temperature sensor driver. +pub struct Dts<'d> { + _peri: PeripheralRef<'d, DTS>, +} + +static WAKER: AtomicWaker = AtomicWaker::new(); + +impl<'d> Dts<'d> { + /// Create a new temperature sensor driver. + pub fn new( + _peri: impl Peripheral

+ 'd, + _irq: impl interrupt::typelevel::Binding + 'd, + config: Config, + ) -> Self { + into_ref!(_peri); + rcc::enable_and_reset::(); + + let prescaler = rcc::frequency::() / MAX_DTS_CLK_FREQ; + + if prescaler > 127 { + panic!("DTS PCLK frequency must be less than 127 MHz."); + } + + Self::regs().cfgr1().modify(|w| { + w.set_refclk_sel(false); + w.set_hsref_clk_div(prescaler as u8); + w.set_q_meas_opt(false); + // Software trigger + w.set_intrig_sel(0); + w.set_smp_time(config.sample_time as u8); + w.set_intrig_sel(config.trigger as u8); + w.set_start(true); + w.set_en(true); + }); + + interrupt::DTS.unpend(); + unsafe { interrupt::DTS.enable() }; + + Self { _peri } + } + + /// Reconfigure the driver. + pub fn set_config(&mut self, config: &Config) { + Self::regs().cfgr1().modify(|w| { + w.set_smp_time(config.sample_time as u8); + w.set_intrig_sel(config.trigger as u8); + }); + } + + /// Get the read-only factory calibration values used for converting a + /// measurement to a temperature. + pub fn factory_calibration() -> FactoryCalibration { + let t0valr1 = Self::regs().t0valr1().read(); + let t0 = match t0valr1.t0() { + 0 => 30, + 1 => 130, + _ => unimplemented!(), + }; + let fmt0 = Hertz::hz(t0valr1.fmt0() as u32 * 100); + + let ramp_coeff = Self::regs().rampvalr().read().ramp_coeff(); + + FactoryCalibration { t0, fmt0, ramp_coeff } + } + + /// Perform an asynchronous temperature measurement. The returned future can + /// be awaited to obtain the measurement. + /// + /// The future returned waits for the next measurement to complete. + /// + /// # Example + /// + /// ```no_run + /// use embassy_stm32::{bind_interrupts, dts}; + /// use embassy_stm32::dts::Dts; + /// + /// bind_interrupts!(struct Irqs { + /// DTS => temp::InterruptHandler; + /// }); + /// + /// # async { + /// # let p: embassy_stm32::Peripherals = todo!(); + /// let mut dts = Dts::new(p.DTS, Irqs, Default::default()); + /// let v: u16 = dts.read().await; + /// # }; + /// ``` + pub async fn read(&mut self) -> u16 { + let r = Self::regs(); + + r.itenr().modify(|w| w.set_iteen(true)); + + poll_fn(|cx| { + WAKER.register(cx.waker()); + if r.itenr().read().iteen() { + Poll::Pending + } else { + Poll::Ready(r.dr().read().mfreq()) + } + }) + .await + } + + /// Returns the last measurement made, if any. + /// + /// There is no guarantee that the measurement is recent or that a + /// measurement has ever completed. + pub fn read_immediate(&mut self) -> u16 { + Self::regs().dr().read().mfreq() + } + + fn regs() -> pac::dts::Dts { + pac::DTS + } +} + +impl<'d> Drop for Dts<'d> { + fn drop(&mut self) { + Self::regs().cfgr1().modify(|w| w.set_en(false)); + rcc::disable::(); + } +} + +/// Interrupt handler. +pub struct InterruptHandler { + _private: (), +} + +impl interrupt::typelevel::Handler for InterruptHandler { + unsafe fn on_interrupt() { + let r = pac::DTS; + let (sr, itenr) = (r.sr().read(), r.itenr().read()); + + if (itenr.iteen() && sr.itef()) || (itenr.aiteen() && sr.aitef()) { + r.itenr().modify(|w| { + w.set_iteen(false); + w.set_aiteen(false); + }); + r.icifr().modify(|w| { + w.set_citef(true); + w.set_caitef(true); + }); + } else if (itenr.itlen() && sr.itlf()) || (itenr.aitlen() && sr.aitlf()) { + r.itenr().modify(|w| { + w.set_itlen(false); + w.set_aitlen(false); + }); + r.icifr().modify(|w| { + w.set_citlf(true); + w.set_caitlf(true); + }); + } else if (itenr.ithen() && sr.ithf()) || (itenr.aithen() && sr.aithf()) { + r.itenr().modify(|w| { + w.set_ithen(false); + w.set_aithen(false); + }); + r.icifr().modify(|w| { + w.set_cithf(true); + w.set_caithf(true); + }); + } else { + return; + } + + compiler_fence(Ordering::SeqCst); + WAKER.wake(); + } +} diff --git a/embassy-stm32/src/dts/tsel.rs b/embassy-stm32/src/dts/tsel.rs new file mode 100644 index 000000000..99eab6dd8 --- /dev/null +++ b/embassy-stm32/src/dts/tsel.rs @@ -0,0 +1,51 @@ +/// Trigger selection for H5 +#[cfg(stm32h5)] +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum TriggerSel { + /// Software triggering. Performs continuous measurements. + Software = 0, + /// LPTIM1 CH1 + Lptim1 = 1, + /// LPTIM2 CH1 + Lptim2 = 2, + /// LPTIM3 CH1 + #[cfg(not(stm32h503))] + Lptim3 = 3, + /// EXTI13 + Exti13 = 4, +} + +/// Trigger selection for H7, except for H7R and H7S +#[cfg(stm32h7)] +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum TriggerSel { + /// Software triggering. Performs continuous measurements. + Software = 0, + /// LPTIM1 OUT + Lptim1 = 1, + /// LPTIM2 OUT + Lptim2 = 2, + /// LPTIM3 OUT + Lptim3 = 3, + /// EXTI13 + Exti13 = 4, +} + +/// Trigger selection for H7R and H7S +#[cfg(stm32h7rs)] +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum TriggerSel { + /// Software triggering. Performs continuous measurements. + Software = 0, + /// LPTIM4 OUT + Lptim4 = 1, + /// LPTIM2 CH1 + Lptim2 = 2, + /// LPTIM3 CH1 + Lptim3 = 3, + /// EXTI13 + Exti13 = 4, +} diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index d04199d05..61da754c3 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -68,6 +68,8 @@ pub mod dac; pub mod dcmi; #[cfg(dsihost)] pub mod dsihost; +#[cfg(dts)] +pub mod dts; #[cfg(eth)] pub mod eth; #[cfg(feature = "exti")] diff --git a/examples/stm32h5/src/bin/dts.rs b/examples/stm32h5/src/bin/dts.rs new file mode 100644 index 000000000..8c18fafea --- /dev/null +++ b/examples/stm32h5/src/bin/dts.rs @@ -0,0 +1,75 @@ +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::dts::{Dts, InterruptHandler, SampleTime}; +use embassy_stm32::peripherals::DTS; +use embassy_stm32::rcc::frequency; +use embassy_stm32::{bind_interrupts, dts, Config}; +use embassy_time::Timer; +use {defmt_rtt as _, panic_probe as _}; + +bind_interrupts!(struct Irqs { + DTS => InterruptHandler; +}); + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let mut config = Config::default(); + { + use embassy_stm32::rcc::*; + config.rcc.hsi = Some(HSIPrescaler::DIV1); + config.rcc.csi = true; + config.rcc.pll1 = Some(Pll { + source: PllSource::HSI, + prediv: PllPreDiv::DIV4, + mul: PllMul::MUL25, + divp: Some(PllDiv::DIV2), + divq: Some(PllDiv::DIV4), // SPI1 cksel defaults to pll1_q + divr: None, + }); + config.rcc.pll2 = Some(Pll { + source: PllSource::HSI, + prediv: PllPreDiv::DIV4, + mul: PllMul::MUL25, + divp: None, + divq: None, + divr: Some(PllDiv::DIV4), // 100mhz + }); + config.rcc.sys = Sysclk::PLL1_P; // 200 Mhz + config.rcc.ahb_pre = AHBPrescaler::DIV1; // 200 Mhz + config.rcc.apb1_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.apb2_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.voltage_scale = VoltageScale::Scale1; + config.rcc.mux.adcdacsel = mux::Adcdacsel::PLL2_R; + } + let p = embassy_stm32::init(config); + + info!("Hello World!"); + + let mut config = dts::Config::default(); + config.sample_time = SampleTime::ClockCycles15; + let mut dts = Dts::new(p.DTS, Irqs, config); + + let cal = Dts::factory_calibration(); + let convert_to_celsius = |raw_temp: u16| { + let raw_temp = raw_temp as f32; + let sample_time = (config.sample_time as u8) as f32; + + let f = frequency::().0 as f32; + + let t0 = cal.t0 as f32; + let fmt0 = cal.fmt0.0 as f32; + let ramp_coeff = cal.ramp_coeff as f32; + + ((f * sample_time / raw_temp) - fmt0) / ramp_coeff + t0 + }; + + loop { + let temp = dts.read().await; + info!("Temp: {} degrees", convert_to_celsius(temp)); + Timer::after_millis(500).await; + } +} From 4ad3b66e453971c3df44945dbe1d7815dae81d9e Mon Sep 17 00:00:00 2001 From: Liu Hancheng Date: Sun, 5 Jan 2025 10:25:10 +0800 Subject: [PATCH 0609/1217] refactor: update write DMA transfer function to use separate memory word type --- embassy-stm32/src/dma/dma_bdma.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/embassy-stm32/src/dma/dma_bdma.rs b/embassy-stm32/src/dma/dma_bdma.rs index 8b4b454c0..fa32bd8cb 100644 --- a/embassy-stm32/src/dma/dma_bdma.rs +++ b/embassy-stm32/src/dma/dma_bdma.rs @@ -620,10 +620,10 @@ impl<'a> Transfer<'a> { } /// Create a new write DMA transfer (memory to peripheral), using raw pointers. - pub unsafe fn new_write_raw( + pub unsafe fn new_write_raw( channel: impl Peripheral

+ 'a, request: Request, - buf: *const [W], + buf: *const [MW], peri_addr: *mut PW, options: TransferOptions, ) -> Self { @@ -634,11 +634,11 @@ impl<'a> Transfer<'a> { request, Dir::MemoryToPeripheral, peri_addr as *const u32, - buf as *const W as *mut u32, + buf as *const MW as *mut u32, buf.len(), true, - W::size(), - W::size(), + MW::size(), + PW::size(), options, ) } From e15e30add2c483b0154af1c8b6f7fcbf0bcd7d7d Mon Sep 17 00:00:00 2001 From: Liu Hancheng Date: Sun, 5 Jan 2025 20:00:15 +0800 Subject: [PATCH 0610/1217] fix: fix qspi waiting condition --- embassy-stm32/src/qspi/mod.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/qspi/mod.rs b/embassy-stm32/src/qspi/mod.rs index 0c65d0556..ffa9798b8 100644 --- a/embassy-stm32/src/qspi/mod.rs +++ b/embassy-stm32/src/qspi/mod.rs @@ -172,7 +172,7 @@ impl<'d, T: Instance, M: PeriMode> Qspi<'d, T, M> { }); for b in buf { - while !T::REGS.sr().read().tcf() && !T::REGS.sr().read().ftf() {} + while !T::REGS.sr().read().tcf() && (T::REGS.sr().read().flevel() == 0) {} *b = unsafe { (T::REGS.dr().as_ptr() as *mut u8).read_volatile() }; } @@ -402,7 +402,10 @@ impl<'d, T: Instance> Qspi<'d, T, Async> { // STM32H7 does not have dmaen #[cfg(not(stm32h7))] - T::REGS.cr().modify(|v| v.set_dmaen(true)); + T::REGS.cr().modify(|v| { + v.set_en(true); + v.set_dmaen(true) + }); transfer } From cfd5c92375a10c33c9aeb3cecbc2bdb6dd399f1b Mon Sep 17 00:00:00 2001 From: Liu Hancheng Date: Sun, 5 Jan 2025 20:10:45 +0800 Subject: [PATCH 0611/1217] fix typo --- embassy-stm32/src/qspi/mod.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/embassy-stm32/src/qspi/mod.rs b/embassy-stm32/src/qspi/mod.rs index ffa9798b8..3d5b31815 100644 --- a/embassy-stm32/src/qspi/mod.rs +++ b/embassy-stm32/src/qspi/mod.rs @@ -402,10 +402,7 @@ impl<'d, T: Instance> Qspi<'d, T, Async> { // STM32H7 does not have dmaen #[cfg(not(stm32h7))] - T::REGS.cr().modify(|v| { - v.set_en(true); - v.set_dmaen(true) - }); + T::REGS.cr().modify(|v| v.set_dmaen(true)); transfer } From 9f21cf627b12358d5fcfdcafdab93ee3588d85da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Sun, 5 Jan 2025 21:11:43 +0100 Subject: [PATCH 0612/1217] Prepare embassy-embedded-hal 0.3 --- embassy-boot/Cargo.toml | 2 +- embassy-embedded-hal/CHANGELOG.md | 5 +++++ embassy-embedded-hal/Cargo.toml | 2 +- embassy-nrf/Cargo.toml | 6 +++--- embassy-stm32-wpan/Cargo.toml | 2 +- examples/boot/application/nrf/Cargo.toml | 2 +- examples/boot/application/rp/Cargo.toml | 2 +- examples/boot/application/stm32f3/Cargo.toml | 2 +- examples/boot/application/stm32f7/Cargo.toml | 2 +- examples/boot/application/stm32h7/Cargo.toml | 2 +- examples/boot/application/stm32l0/Cargo.toml | 2 +- examples/boot/application/stm32l1/Cargo.toml | 2 +- examples/boot/application/stm32l4/Cargo.toml | 2 +- examples/boot/application/stm32wb-dfu/Cargo.toml | 2 +- examples/boot/application/stm32wl/Cargo.toml | 2 +- examples/rp/Cargo.toml | 2 +- examples/rp23/Cargo.toml | 2 +- examples/stm32h7/Cargo.toml | 2 +- examples/stm32h735/Cargo.toml | 2 +- examples/stm32h755cm4/Cargo.toml | 2 +- examples/stm32h755cm7/Cargo.toml | 2 +- examples/stm32h7b0/Cargo.toml | 2 +- examples/stm32l4/Cargo.toml | 2 +- examples/stm32wl/Cargo.toml | 2 +- tests/rp/Cargo.toml | 2 +- 25 files changed, 31 insertions(+), 26 deletions(-) diff --git a/embassy-boot/Cargo.toml b/embassy-boot/Cargo.toml index b385020cc..34f8f560e 100644 --- a/embassy-boot/Cargo.toml +++ b/embassy-boot/Cargo.toml @@ -28,7 +28,7 @@ defmt = { version = "0.3", optional = true } digest = "0.10" log = { version = "0.4", optional = true } ed25519-dalek = { version = "2", default-features = false, features = ["digest"], optional = true } -embassy-embedded-hal = { version = "0.2.0", path = "../embassy-embedded-hal" } +embassy-embedded-hal = { version = "0.3.0", path = "../embassy-embedded-hal" } embassy-sync = { version = "0.6.1", path = "../embassy-sync" } embedded-storage = "0.3.1" embedded-storage-async = { version = "0.4.1" } diff --git a/embassy-embedded-hal/CHANGELOG.md b/embassy-embedded-hal/CHANGELOG.md index f8e272160..224036af4 100644 --- a/embassy-embedded-hal/CHANGELOG.md +++ b/embassy-embedded-hal/CHANGELOG.md @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +## 0.3.0 - 2025-01-05 + +- The `std` feature has been removed +- Updated `embassy-time` to v0.4 + ## 0.2.0 - 2024-08-05 - Add Clone derive to flash Partition in embassy-embedded-hal diff --git a/embassy-embedded-hal/Cargo.toml b/embassy-embedded-hal/Cargo.toml index 0407bd5b6..ce2ea4aa8 100644 --- a/embassy-embedded-hal/Cargo.toml +++ b/embassy-embedded-hal/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "embassy-embedded-hal" -version = "0.2.0" +version = "0.3.0" edition = "2021" license = "MIT OR Apache-2.0" description = "Collection of utilities to use `embedded-hal` and `embedded-storage` traits with Embassy." diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml index 79e919f68..efaf03356 100644 --- a/embassy-nrf/Cargo.toml +++ b/embassy-nrf/Cargo.toml @@ -138,9 +138,9 @@ embassy-time-driver = { version = "0.2", path = "../embassy-time-driver", option embassy-time-queue-utils = { version = "0.1", path = "../embassy-time-queue-utils", optional = true } embassy-time = { version = "0.4.0", path = "../embassy-time", optional = true } embassy-sync = { version = "0.6.1", path = "../embassy-sync" } -embassy-hal-internal = {version = "0.2.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-3"] } -embassy-embedded-hal = {version = "0.2.0", path = "../embassy-embedded-hal", default-features = false } -embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver" } +embassy-hal-internal = { version = "0.2.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-3"] } +embassy-embedded-hal = { version = "0.3.0", path = "../embassy-embedded-hal", default-features = false } +embassy-usb-driver = { version = "0.1.0", path = "../embassy-usb-driver" } embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } embedded-hal-1 = { package = "embedded-hal", version = "1.0" } diff --git a/embassy-stm32-wpan/Cargo.toml b/embassy-stm32-wpan/Cargo.toml index 74e7a67d9..876fc92b9 100644 --- a/embassy-stm32-wpan/Cargo.toml +++ b/embassy-stm32-wpan/Cargo.toml @@ -24,7 +24,7 @@ embassy-sync = { version = "0.6.1", path = "../embassy-sync" } embassy-time = { version = "0.4.0", path = "../embassy-time", optional = true } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } embassy-hal-internal = { version = "0.2.0", path = "../embassy-hal-internal" } -embassy-embedded-hal = { version = "0.2.0", path = "../embassy-embedded-hal" } +embassy-embedded-hal = { version = "0.3.0", path = "../embassy-embedded-hal" } embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver", optional=true } defmt = { version = "0.3", optional = true } diff --git a/examples/boot/application/nrf/Cargo.toml b/examples/boot/application/nrf/Cargo.toml index bfe6532ad..180882d8a 100644 --- a/examples/boot/application/nrf/Cargo.toml +++ b/examples/boot/application/nrf/Cargo.toml @@ -11,7 +11,7 @@ embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features embassy-nrf = { version = "0.2.0", path = "../../../../embassy-nrf", features = ["time-driver-rtc1", "gpiote", ] } embassy-boot = { version = "0.3.0", path = "../../../../embassy-boot", features = [] } embassy-boot-nrf = { version = "0.3.0", path = "../../../../embassy-boot-nrf", features = [] } -embassy-embedded-hal = { version = "0.2.0", path = "../../../../embassy-embedded-hal" } +embassy-embedded-hal = { version = "0.3.0", path = "../../../../embassy-embedded-hal" } defmt = { version = "0.3", optional = true } defmt-rtt = { version = "0.4", optional = true } diff --git a/examples/boot/application/rp/Cargo.toml b/examples/boot/application/rp/Cargo.toml index 6217cf64b..8b5016faf 100644 --- a/examples/boot/application/rp/Cargo.toml +++ b/examples/boot/application/rp/Cargo.toml @@ -10,7 +10,7 @@ embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", f embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [] } embassy-rp = { version = "0.2.0", path = "../../../../embassy-rp", features = ["time-driver", "rp2040"] } embassy-boot-rp = { version = "0.3.0", path = "../../../../embassy-boot-rp", features = [] } -embassy-embedded-hal = { version = "0.2.0", path = "../../../../embassy-embedded-hal" } +embassy-embedded-hal = { version = "0.3.0", path = "../../../../embassy-embedded-hal" } defmt = "0.3" defmt-rtt = "0.4" diff --git a/examples/boot/application/stm32f3/Cargo.toml b/examples/boot/application/stm32f3/Cargo.toml index 68f65e384..c49dd8335 100644 --- a/examples/boot/application/stm32f3/Cargo.toml +++ b/examples/boot/application/stm32f3/Cargo.toml @@ -10,7 +10,7 @@ embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", f embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32f303re", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32" } -embassy-embedded-hal = { version = "0.2.0", path = "../../../../embassy-embedded-hal" } +embassy-embedded-hal = { version = "0.3.0", path = "../../../../embassy-embedded-hal" } defmt = { version = "0.3", optional = true } defmt-rtt = { version = "0.4", optional = true } diff --git a/examples/boot/application/stm32f7/Cargo.toml b/examples/boot/application/stm32f7/Cargo.toml index 90391af5c..a14536e9e 100644 --- a/examples/boot/application/stm32f7/Cargo.toml +++ b/examples/boot/application/stm32f7/Cargo.toml @@ -10,7 +10,7 @@ embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", f embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32f767zi", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } -embassy-embedded-hal = { version = "0.2.0", path = "../../../../embassy-embedded-hal" } +embassy-embedded-hal = { version = "0.3.0", path = "../../../../embassy-embedded-hal" } defmt = { version = "0.3", optional = true } defmt-rtt = { version = "0.4", optional = true } diff --git a/examples/boot/application/stm32h7/Cargo.toml b/examples/boot/application/stm32h7/Cargo.toml index 33e210d44..f7b9f630e 100644 --- a/examples/boot/application/stm32h7/Cargo.toml +++ b/examples/boot/application/stm32h7/Cargo.toml @@ -10,7 +10,7 @@ embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", f embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32h743zi", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } -embassy-embedded-hal = { version = "0.2.0", path = "../../../../embassy-embedded-hal" } +embassy-embedded-hal = { version = "0.3.0", path = "../../../../embassy-embedded-hal" } defmt = { version = "0.3", optional = true } defmt-rtt = { version = "0.4", optional = true } diff --git a/examples/boot/application/stm32l0/Cargo.toml b/examples/boot/application/stm32l0/Cargo.toml index f9402904f..75eaf8312 100644 --- a/examples/boot/application/stm32l0/Cargo.toml +++ b/examples/boot/application/stm32l0/Cargo.toml @@ -10,7 +10,7 @@ embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", f embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l072cz", "time-driver-any", "exti", "memory-x"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } -embassy-embedded-hal = { version = "0.2.0", path = "../../../../embassy-embedded-hal" } +embassy-embedded-hal = { version = "0.3.0", path = "../../../../embassy-embedded-hal" } defmt = { version = "0.3", optional = true } defmt-rtt = { version = "0.4", optional = true } diff --git a/examples/boot/application/stm32l1/Cargo.toml b/examples/boot/application/stm32l1/Cargo.toml index d02986850..93d651f3c 100644 --- a/examples/boot/application/stm32l1/Cargo.toml +++ b/examples/boot/application/stm32l1/Cargo.toml @@ -10,7 +10,7 @@ embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", f embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l151cb-a", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } -embassy-embedded-hal = { version = "0.2.0", path = "../../../../embassy-embedded-hal" } +embassy-embedded-hal = { version = "0.3.0", path = "../../../../embassy-embedded-hal" } defmt = { version = "0.3", optional = true } defmt-rtt = { version = "0.4", optional = true } diff --git a/examples/boot/application/stm32l4/Cargo.toml b/examples/boot/application/stm32l4/Cargo.toml index fedfe2b33..20f521084 100644 --- a/examples/boot/application/stm32l4/Cargo.toml +++ b/examples/boot/application/stm32l4/Cargo.toml @@ -10,7 +10,7 @@ embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", f embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l475vg", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } -embassy-embedded-hal = { version = "0.2.0", path = "../../../../embassy-embedded-hal" } +embassy-embedded-hal = { version = "0.3.0", path = "../../../../embassy-embedded-hal" } defmt = { version = "0.3", optional = true } defmt-rtt = { version = "0.4", optional = true } diff --git a/examples/boot/application/stm32wb-dfu/Cargo.toml b/examples/boot/application/stm32wb-dfu/Cargo.toml index ab359a948..70d854953 100644 --- a/examples/boot/application/stm32wb-dfu/Cargo.toml +++ b/examples/boot/application/stm32wb-dfu/Cargo.toml @@ -10,7 +10,7 @@ embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", f embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32wb55rg", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } -embassy-embedded-hal = { version = "0.2.0", path = "../../../../embassy-embedded-hal" } +embassy-embedded-hal = { version = "0.3.0", path = "../../../../embassy-embedded-hal" } embassy-usb = { version = "0.3.0", path = "../../../../embassy-usb" } embassy-usb-dfu = { version = "0.1.0", path = "../../../../embassy-usb-dfu", features = ["application", "cortex-m"] } diff --git a/examples/boot/application/stm32wl/Cargo.toml b/examples/boot/application/stm32wl/Cargo.toml index 8e24fdcf1..8981690af 100644 --- a/examples/boot/application/stm32wl/Cargo.toml +++ b/examples/boot/application/stm32wl/Cargo.toml @@ -10,7 +10,7 @@ embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", f embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32wl55jc-cm4", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } -embassy-embedded-hal = { version = "0.2.0", path = "../../../../embassy-embedded-hal" } +embassy-embedded-hal = { version = "0.3.0", path = "../../../../embassy-embedded-hal" } defmt = { version = "0.3", optional = true } defmt-rtt = { version = "0.4", optional = true } diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index bdd50707a..e7e2f6aaa 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] -embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal", features = ["defmt"] } +embassy-embedded-hal = { version = "0.3.0", path = "../../embassy-embedded-hal", features = ["defmt"] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-98304", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } diff --git a/examples/rp23/Cargo.toml b/examples/rp23/Cargo.toml index 3afd2cddb..e1bf533a6 100644 --- a/examples/rp23/Cargo.toml +++ b/examples/rp23/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] -embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal", features = ["defmt"] } +embassy-embedded-hal = { version = "0.3.0", path = "../../embassy-embedded-hal", features = ["defmt"] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-98304", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } diff --git a/examples/stm32h7/Cargo.toml b/examples/stm32h7/Cargo.toml index 3cefdcd31..881b13871 100644 --- a/examples/stm32h7/Cargo.toml +++ b/examples/stm32h7/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32h743bi to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h743bi", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } -embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } +embassy-embedded-hal = { version = "0.3.0", path = "../../embassy-embedded-hal" } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } diff --git a/examples/stm32h735/Cargo.toml b/examples/stm32h735/Cargo.toml index 021dff0e3..99e2c1049 100644 --- a/examples/stm32h735/Cargo.toml +++ b/examples/stm32h735/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h735ig", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } -embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } +embassy-embedded-hal = { version = "0.3.0", path = "../../embassy-embedded-hal" } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32h755cm4/Cargo.toml b/examples/stm32h755cm4/Cargo.toml index f3fd5f894..862365c1e 100644 --- a/examples/stm32h755cm4/Cargo.toml +++ b/examples/stm32h755cm4/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32h755zi-cm4 to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h755zi-cm4", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } -embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } +embassy-embedded-hal = { version = "0.3.0", path = "../../embassy-embedded-hal" } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } diff --git a/examples/stm32h755cm7/Cargo.toml b/examples/stm32h755cm7/Cargo.toml index 81c8eecc2..9c11bdd51 100644 --- a/examples/stm32h755cm7/Cargo.toml +++ b/examples/stm32h755cm7/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32h743bi to your chip name, if necessary. embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h755zi-cm7", "time-driver-tim3", "exti", "memory-x", "unstable-pac", "chrono"] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } -embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } +embassy-embedded-hal = { version = "0.3.0", path = "../../embassy-embedded-hal" } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } diff --git a/examples/stm32h7b0/Cargo.toml b/examples/stm32h7b0/Cargo.toml index 660a340cf..b9de41f33 100644 --- a/examples/stm32h7b0/Cargo.toml +++ b/examples/stm32h7b0/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h7b0vb", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } -embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } +embassy-embedded-hal = { version = "0.3.0", path = "../../embassy-embedded-hal" } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } diff --git a/examples/stm32l4/Cargo.toml b/examples/stm32l4/Cargo.toml index 7d08a18ed..97e3964c9 100644 --- a/examples/stm32l4/Cargo.toml +++ b/examples/stm32l4/Cargo.toml @@ -10,7 +10,7 @@ embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768", ] } -embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } +embassy-embedded-hal = { version = "0.3.0", path = "../../embassy-embedded-hal" } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embassy-net-adin1110 = { version = "0.2.0", path = "../../embassy-net-adin1110" } embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "udp", "tcp", "dhcpv4", "medium-ethernet"] } diff --git a/examples/stm32wl/Cargo.toml b/examples/stm32wl/Cargo.toml index 7dbb40567..379fdc572 100644 --- a/examples/stm32wl/Cargo.toml +++ b/examples/stm32wl/Cargo.toml @@ -10,7 +10,7 @@ embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [" embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-4096", "arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } -embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } +embassy-embedded-hal = { version = "0.3.0", path = "../../embassy-embedded-hal" } defmt = "0.3" defmt-rtt = "0.4" diff --git a/tests/rp/Cargo.toml b/tests/rp/Cargo.toml index 842cdf51d..d7f640dc2 100644 --- a/tests/rp/Cargo.toml +++ b/tests/rp/Cargo.toml @@ -14,7 +14,7 @@ embassy-rp = { version = "0.2.0", path = "../../embassy-rp", features = [ "defmt embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "dhcpv4", "medium-ethernet"] } embassy-net-wiznet = { version = "0.1.0", path = "../../embassy-net-wiznet", features = ["defmt"] } -embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal/"} +embassy-embedded-hal = { version = "0.3.0", path = "../../embassy-embedded-hal/"} cyw43 = { path = "../../cyw43", features = ["defmt", "firmware-logs"] } cyw43-pio = { path = "../../cyw43-pio", features = ["defmt"] } perf-client = { path = "../perf-client" } From 3c1e862f611190f93bbad1b3b115424acb5b4a05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Sun, 5 Jan 2025 21:13:43 +0100 Subject: [PATCH 0613/1217] Prepare embassy-boot 0.4 --- embassy-boot-nrf/Cargo.toml | 2 +- embassy-boot-rp/Cargo.toml | 2 +- embassy-boot-stm32/Cargo.toml | 2 +- embassy-boot/Cargo.toml | 2 +- embassy-usb-dfu/Cargo.toml | 2 +- examples/boot/application/nrf/Cargo.toml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/embassy-boot-nrf/Cargo.toml b/embassy-boot-nrf/Cargo.toml index dd5c0780e..f72aa8fe1 100644 --- a/embassy-boot-nrf/Cargo.toml +++ b/embassy-boot-nrf/Cargo.toml @@ -26,7 +26,7 @@ log = { version = "0.4.17", optional = true } embassy-sync = { version = "0.6.1", path = "../embassy-sync" } embassy-nrf = { version = "0.2.0", path = "../embassy-nrf", default-features = false } -embassy-boot = { version = "0.3.0", path = "../embassy-boot" } +embassy-boot = { version = "0.4.0", path = "../embassy-boot" } cortex-m = { version = "0.7.6" } cortex-m-rt = { version = "0.7" } embedded-storage = "0.3.1" diff --git a/embassy-boot-rp/Cargo.toml b/embassy-boot-rp/Cargo.toml index 23994c171..74c3ab470 100644 --- a/embassy-boot-rp/Cargo.toml +++ b/embassy-boot-rp/Cargo.toml @@ -26,7 +26,7 @@ log = { version = "0.4", optional = true } embassy-sync = { version = "0.6.1", path = "../embassy-sync" } embassy-rp = { version = "0.2.0", path = "../embassy-rp", default-features = false } -embassy-boot = { version = "0.3.0", path = "../embassy-boot" } +embassy-boot = { version = "0.4.0", path = "../embassy-boot" } embassy-time = { version = "0.4.0", path = "../embassy-time" } cortex-m = { version = "0.7.6" } diff --git a/embassy-boot-stm32/Cargo.toml b/embassy-boot-stm32/Cargo.toml index 1afdde75a..e2d7c19cb 100644 --- a/embassy-boot-stm32/Cargo.toml +++ b/embassy-boot-stm32/Cargo.toml @@ -26,7 +26,7 @@ log = { version = "0.4", optional = true } embassy-sync = { version = "0.6.1", path = "../embassy-sync" } embassy-stm32 = { version = "0.1.0", path = "../embassy-stm32", default-features = false } -embassy-boot = { version = "0.3.0", path = "../embassy-boot" } +embassy-boot = { version = "0.4.0", path = "../embassy-boot" } cortex-m = { version = "0.7.6" } cortex-m-rt = { version = "0.7" } embedded-storage = "0.3.1" diff --git a/embassy-boot/Cargo.toml b/embassy-boot/Cargo.toml index 34f8f560e..0a04d661f 100644 --- a/embassy-boot/Cargo.toml +++ b/embassy-boot/Cargo.toml @@ -1,7 +1,7 @@ [package] edition = "2021" name = "embassy-boot" -version = "0.3.0" +version = "0.4.0" description = "A lightweight bootloader supporting firmware updates in a power-fail-safe way, with trial boots and rollbacks." license = "MIT OR Apache-2.0" repository = "https://github.com/embassy-rs/embassy" diff --git a/embassy-usb-dfu/Cargo.toml b/embassy-usb-dfu/Cargo.toml index baee0205e..e6522b04d 100644 --- a/embassy-usb-dfu/Cargo.toml +++ b/embassy-usb-dfu/Cargo.toml @@ -31,7 +31,7 @@ log = { version = "0.4.17", optional = true } bitflags = "2.4.1" cortex-m = { version = "0.7.7", features = ["inline-asm"], optional = true } -embassy-boot = { version = "0.3.0", path = "../embassy-boot" } +embassy-boot = { version = "0.4.0", path = "../embassy-boot" } embassy-futures = { version = "0.1.1", path = "../embassy-futures" } embassy-sync = { version = "0.6.1", path = "../embassy-sync" } embassy-time = { version = "0.4.0", path = "../embassy-time" } diff --git a/examples/boot/application/nrf/Cargo.toml b/examples/boot/application/nrf/Cargo.toml index 180882d8a..6045656f5 100644 --- a/examples/boot/application/nrf/Cargo.toml +++ b/examples/boot/application/nrf/Cargo.toml @@ -9,7 +9,7 @@ embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["task-arena-size-16384", "arch-cortex-m", "executor-thread", "arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [] } embassy-nrf = { version = "0.2.0", path = "../../../../embassy-nrf", features = ["time-driver-rtc1", "gpiote", ] } -embassy-boot = { version = "0.3.0", path = "../../../../embassy-boot", features = [] } +embassy-boot = { version = "0.4.0", path = "../../../../embassy-boot", features = [] } embassy-boot-nrf = { version = "0.3.0", path = "../../../../embassy-boot-nrf", features = [] } embassy-embedded-hal = { version = "0.3.0", path = "../../../../embassy-embedded-hal" } From 776b2b540bfb10660f4cc67b92ed11cedcec80b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Sun, 5 Jan 2025 21:17:01 +0100 Subject: [PATCH 0614/1217] Prepare embassy-net 0.6 --- embassy-net/CHANGELOG.md | 6 ++++++ embassy-net/Cargo.toml | 2 +- examples/nrf52840/Cargo.toml | 2 +- examples/nrf5340/Cargo.toml | 2 +- examples/nrf9160/Cargo.toml | 2 +- examples/rp/Cargo.toml | 2 +- examples/rp23/Cargo.toml | 2 +- examples/std/Cargo.toml | 2 +- examples/stm32f4/Cargo.toml | 2 +- examples/stm32f7/Cargo.toml | 2 +- examples/stm32h5/Cargo.toml | 2 +- examples/stm32h7/Cargo.toml | 2 +- examples/stm32h755cm4/Cargo.toml | 2 +- examples/stm32h755cm7/Cargo.toml | 2 +- examples/stm32h7b0/Cargo.toml | 2 +- examples/stm32h7rs/Cargo.toml | 2 +- examples/stm32l4/Cargo.toml | 2 +- examples/stm32l5/Cargo.toml | 2 +- examples/stm32wb/Cargo.toml | 2 +- examples/stm32wba/Cargo.toml | 2 +- tests/nrf/Cargo.toml | 2 +- tests/perf-client/Cargo.toml | 2 +- tests/rp/Cargo.toml | 2 +- tests/stm32/Cargo.toml | 2 +- 24 files changed, 29 insertions(+), 23 deletions(-) diff --git a/embassy-net/CHANGELOG.md b/embassy-net/CHANGELOG.md index c4ccff277..0b98e213e 100644 --- a/embassy-net/CHANGELOG.md +++ b/embassy-net/CHANGELOG.md @@ -9,6 +9,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 No unreleased changes yet... Quick, go send a PR! +## 0.6 - 2025-01-05 + +- Make `Config` constructors `const` +- The `std` feature has been removed +- Updated `embassy-time` to v0.4 + ## 0.5 - 2024-11-28 - Refactor the API structure, simplifying lifetimes and generics. diff --git a/embassy-net/Cargo.toml b/embassy-net/Cargo.toml index a7f7ffad2..0f332f2af 100644 --- a/embassy-net/Cargo.toml +++ b/embassy-net/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "embassy-net" -version = "0.5.0" +version = "0.6.0" edition = "2021" license = "MIT OR Apache-2.0" description = "Async TCP/IP network stack for embedded systems" diff --git a/examples/nrf52840/Cargo.toml b/examples/nrf52840/Cargo.toml index 7a4aa803b..c8cf0504b 100644 --- a/examples/nrf52840/Cargo.toml +++ b/examples/nrf52840/Cargo.toml @@ -10,7 +10,7 @@ embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["de embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } -embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } +embassy-net = { version = "0.6.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embedded-io = { version = "0.6.0", features = ["defmt-03"] } embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } diff --git a/examples/nrf5340/Cargo.toml b/examples/nrf5340/Cargo.toml index b9d336db7..8eaf0e42b 100644 --- a/examples/nrf5340/Cargo.toml +++ b/examples/nrf5340/Cargo.toml @@ -10,7 +10,7 @@ embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["de embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf5340-app-s", "time-driver-rtc1", "gpiote", "unstable-pac"] } -embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } +embassy-net = { version = "0.6.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embedded-io-async = { version = "0.6.1" } diff --git a/examples/nrf9160/Cargo.toml b/examples/nrf9160/Cargo.toml index 885adb337..0c785d367 100644 --- a/examples/nrf9160/Cargo.toml +++ b/examples/nrf9160/Cargo.toml @@ -9,7 +9,7 @@ embassy-executor = { version = "0.7.0", path = "../../embassy-executor", feature embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf9160-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } embassy-net-nrf91 = { version = "0.1.0", path = "../../embassy-net-nrf91", features = ["defmt"] } -embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "proto-ipv4", "medium-ip"] } +embassy-net = { version = "0.6.0", path = "../../embassy-net", features = ["defmt", "tcp", "proto-ipv4", "medium-ip"] } defmt = "0.3" defmt-rtt = "0.4" diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index e7e2f6aaa..7b461aedc 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml @@ -12,7 +12,7 @@ embassy-executor = { version = "0.7.0", path = "../../embassy-executor", feature embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-rp = { version = "0.2.0", path = "../../embassy-rp", features = ["defmt", "unstable-pac", "time-driver", "critical-section-impl", "rp2040"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } -embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "raw", "dhcpv4", "medium-ethernet", "dns", "proto-ipv4", "proto-ipv6", "multicast"] } +embassy-net = { version = "0.6.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "raw", "dhcpv4", "medium-ethernet", "dns", "proto-ipv4", "proto-ipv6", "multicast"] } embassy-net-wiznet = { version = "0.1.0", path = "../../embassy-net-wiznet", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-usb-logger = { version = "0.2.0", path = "../../embassy-usb-logger" } diff --git a/examples/rp23/Cargo.toml b/examples/rp23/Cargo.toml index e1bf533a6..d92478896 100644 --- a/examples/rp23/Cargo.toml +++ b/examples/rp23/Cargo.toml @@ -12,7 +12,7 @@ embassy-executor = { version = "0.7.0", path = "../../embassy-executor", feature embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-rp = { version = "0.2.0", path = "../../embassy-rp", features = ["defmt", "unstable-pac", "time-driver", "critical-section-impl", "rp235xa", "binary-info"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } -embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "raw", "dhcpv4", "medium-ethernet", "dns"] } +embassy-net = { version = "0.6.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "raw", "dhcpv4", "medium-ethernet", "dns"] } embassy-net-wiznet = { version = "0.1.0", path = "../../embassy-net-wiznet", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-usb-logger = { version = "0.2.0", path = "../../embassy-usb-logger" } diff --git a/examples/std/Cargo.toml b/examples/std/Cargo.toml index f67422f85..44b62a616 100644 --- a/examples/std/Cargo.toml +++ b/examples/std/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["log"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-std", "executor-thread", "log"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["log", "std", ] } -embassy-net = { version = "0.5.0", path = "../../embassy-net", features=[ "log", "medium-ethernet", "medium-ip", "tcp", "udp", "dns", "dhcpv4", "proto-ipv6"] } +embassy-net = { version = "0.6.0", path = "../../embassy-net", features=[ "log", "medium-ethernet", "medium-ip", "tcp", "udp", "dns", "dhcpv4", "proto-ipv6"] } embassy-net-tuntap = { version = "0.1.0", path = "../../embassy-net-tuntap" } embassy-net-ppp = { version = "0.1.0", path = "../../embassy-net-ppp", features = ["log"]} embedded-io-async = { version = "0.6.1" } diff --git a/examples/stm32f4/Cargo.toml b/examples/stm32f4/Cargo.toml index 8656dbc61..85902b22b 100644 --- a/examples/stm32f4/Cargo.toml +++ b/examples/stm32f4/Cargo.toml @@ -11,7 +11,7 @@ embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["de embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt" ] } -embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", ] } +embassy-net = { version = "0.6.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", ] } embassy-net-wiznet = { version = "0.1.0", path = "../../embassy-net-wiznet", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32f7/Cargo.toml b/examples/stm32f7/Cargo.toml index 45e56b63f..96eb46c5c 100644 --- a/examples/stm32f7/Cargo.toml +++ b/examples/stm32f7/Cargo.toml @@ -10,7 +10,7 @@ embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [" embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } -embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } +embassy-net = { version = "0.6.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } embedded-io-async = { version = "0.6.1" } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32h5/Cargo.toml b/examples/stm32h5/Cargo.toml index 7495b88ac..8d43c4c1a 100644 --- a/examples/stm32h5/Cargo.toml +++ b/examples/stm32h5/Cargo.toml @@ -10,7 +10,7 @@ embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [" embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } -embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6"] } +embassy-net = { version = "0.6.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32h7/Cargo.toml b/examples/stm32h7/Cargo.toml index 881b13871..0dbaf28ce 100644 --- a/examples/stm32h7/Cargo.toml +++ b/examples/stm32h7/Cargo.toml @@ -11,7 +11,7 @@ embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["de embassy-embedded-hal = { version = "0.3.0", path = "../../embassy-embedded-hal" } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } -embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } +embassy-net = { version = "0.6.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32h755cm4/Cargo.toml b/examples/stm32h755cm4/Cargo.toml index 862365c1e..699561214 100644 --- a/examples/stm32h755cm4/Cargo.toml +++ b/examples/stm32h755cm4/Cargo.toml @@ -11,7 +11,7 @@ embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["de embassy-embedded-hal = { version = "0.3.0", path = "../../embassy-embedded-hal" } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } -embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } +embassy-net = { version = "0.6.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32h755cm7/Cargo.toml b/examples/stm32h755cm7/Cargo.toml index 9c11bdd51..1f830ec6b 100644 --- a/examples/stm32h755cm7/Cargo.toml +++ b/examples/stm32h755cm7/Cargo.toml @@ -11,7 +11,7 @@ embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["de embassy-embedded-hal = { version = "0.3.0", path = "../../embassy-embedded-hal" } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } -embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } +embassy-net = { version = "0.6.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32h7b0/Cargo.toml b/examples/stm32h7b0/Cargo.toml index b9de41f33..a1b96baa9 100644 --- a/examples/stm32h7b0/Cargo.toml +++ b/examples/stm32h7b0/Cargo.toml @@ -10,7 +10,7 @@ embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["de embassy-embedded-hal = { version = "0.3.0", path = "../../embassy-embedded-hal" } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } -embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } +embassy-net = { version = "0.6.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32h7rs/Cargo.toml b/examples/stm32h7rs/Cargo.toml index 45bfde41c..bd41827a5 100644 --- a/examples/stm32h7rs/Cargo.toml +++ b/examples/stm32h7rs/Cargo.toml @@ -10,7 +10,7 @@ embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [" embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } -embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } +embassy-net = { version = "0.6.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32l4/Cargo.toml b/examples/stm32l4/Cargo.toml index 97e3964c9..9d9cc6c9d 100644 --- a/examples/stm32l4/Cargo.toml +++ b/examples/stm32l4/Cargo.toml @@ -13,7 +13,7 @@ embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["de embassy-embedded-hal = { version = "0.3.0", path = "../../embassy-embedded-hal" } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embassy-net-adin1110 = { version = "0.2.0", path = "../../embassy-net-adin1110" } -embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "udp", "tcp", "dhcpv4", "medium-ethernet"] } +embassy-net = { version = "0.6.0", path = "../../embassy-net", features = ["defmt", "udp", "tcp", "dhcpv4", "medium-ethernet"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } embedded-io = { version = "0.6.0", features = ["defmt-03"] } diff --git a/examples/stm32l5/Cargo.toml b/examples/stm32l5/Cargo.toml index 281dea430..7572fed3f 100644 --- a/examples/stm32l5/Cargo.toml +++ b/examples/stm32l5/Cargo.toml @@ -11,7 +11,7 @@ embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["de embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } -embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } +embassy-net = { version = "0.6.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } usbd-hid = "0.8.1" diff --git a/examples/stm32wb/Cargo.toml b/examples/stm32wb/Cargo.toml index 1b8535d8a..268e9347b 100644 --- a/examples/stm32wb/Cargo.toml +++ b/examples/stm32wb/Cargo.toml @@ -11,7 +11,7 @@ embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", fea embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } -embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", ], optional=true } +embassy-net = { version = "0.6.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", ], optional=true } defmt = "0.3" defmt-rtt = "0.4" diff --git a/examples/stm32wba/Cargo.toml b/examples/stm32wba/Cargo.toml index 126f47e42..00c8b92d5 100644 --- a/examples/stm32wba/Cargo.toml +++ b/examples/stm32wba/Cargo.toml @@ -9,7 +9,7 @@ embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } -embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", ], optional=true } +embassy-net = { version = "0.6.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", ], optional=true } defmt = "0.3" defmt-rtt = "0.4" diff --git a/tests/nrf/Cargo.toml b/tests/nrf/Cargo.toml index e0c5e90cf..8d48ae874 100644 --- a/tests/nrf/Cargo.toml +++ b/tests/nrf/Cargo.toml @@ -13,7 +13,7 @@ embassy-executor = { version = "0.7.0", path = "../../embassy-executor", feature embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "time-driver-rtc1", "gpiote", "unstable-pac"] } embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } -embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", ] } +embassy-net = { version = "0.6.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", ] } embassy-net-esp-hosted = { version = "0.1.0", path = "../../embassy-net-esp-hosted", features = ["defmt"] } embassy-net-enc28j60 = { version = "0.1.0", path = "../../embassy-net-enc28j60", features = ["defmt"] } embedded-hal-async = { version = "1.0" } diff --git a/tests/perf-client/Cargo.toml b/tests/perf-client/Cargo.toml index 22137e2e7..cb3dd3df6 100644 --- a/tests/perf-client/Cargo.toml +++ b/tests/perf-client/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" edition = "2021" [dependencies] -embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4"] } +embassy-net = { version = "0.6.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", ] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } defmt = "0.3.0" diff --git a/tests/rp/Cargo.toml b/tests/rp/Cargo.toml index d7f640dc2..200e8e0da 100644 --- a/tests/rp/Cargo.toml +++ b/tests/rp/Cargo.toml @@ -12,7 +12,7 @@ embassy-executor = { version = "0.7.0", path = "../../embassy-executor", feature embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", ] } embassy-rp = { version = "0.2.0", path = "../../embassy-rp", features = [ "defmt", "unstable-pac", "time-driver", "critical-section-impl", "intrinsics", "rom-v2-intrinsics", "run-from-ram", "rp2040"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } -embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "dhcpv4", "medium-ethernet"] } +embassy-net = { version = "0.6.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "dhcpv4", "medium-ethernet"] } embassy-net-wiznet = { version = "0.1.0", path = "../../embassy-net-wiznet", features = ["defmt"] } embassy-embedded-hal = { version = "0.3.0", path = "../../embassy-embedded-hal/"} cyw43 = { path = "../../cyw43", features = ["defmt", "firmware-logs"] } diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml index afc96cb61..c48b23f1e 100644 --- a/tests/stm32/Cargo.toml +++ b/tests/stm32/Cargo.toml @@ -65,7 +65,7 @@ embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["de embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "memory-x", "time-driver-any"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", optional = true, features = ["defmt", "stm32wb55rg", "ble"] } -embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "dhcpv4", "medium-ethernet"] } +embassy-net = { version = "0.6.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "dhcpv4", "medium-ethernet"] } perf-client = { path = "../perf-client" } defmt = "0.3.0" From 09588321e52746d21f27ededfede5c4c362975d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Sun, 5 Jan 2025 21:21:01 +0100 Subject: [PATCH 0615/1217] Prepare embassy-net drivers --- embassy-net-adin1110/Cargo.toml | 2 +- embassy-net-enc28j60/Cargo.toml | 2 +- embassy-net-esp-hosted/Cargo.toml | 2 +- embassy-net-wiznet/Cargo.toml | 2 +- examples/nrf52840/Cargo.toml | 4 ++-- examples/rp/Cargo.toml | 2 +- examples/rp23/Cargo.toml | 2 +- examples/stm32f4/Cargo.toml | 2 +- examples/stm32l4/Cargo.toml | 2 +- tests/nrf/Cargo.toml | 4 ++-- tests/rp/Cargo.toml | 2 +- 11 files changed, 13 insertions(+), 13 deletions(-) diff --git a/embassy-net-adin1110/Cargo.toml b/embassy-net-adin1110/Cargo.toml index 3c988a732..22d494b84 100644 --- a/embassy-net-adin1110/Cargo.toml +++ b/embassy-net-adin1110/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "embassy-net-adin1110" -version = "0.2.0" +version = "0.3.0" description = "embassy-net driver for the ADIN1110 ethernet chip" keywords = ["embedded", "ADIN1110", "embassy-net", "embedded-hal-async", "ethernet"] categories = ["embedded", "hardware-support", "no-std", "network-programming", "asynchronous"] diff --git a/embassy-net-enc28j60/Cargo.toml b/embassy-net-enc28j60/Cargo.toml index f3e66bbdb..74f94816a 100644 --- a/embassy-net-enc28j60/Cargo.toml +++ b/embassy-net-enc28j60/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "embassy-net-enc28j60" -version = "0.1.0" +version = "0.2.0" description = "embassy-net driver for the ENC28J60 ethernet chip" keywords = ["embedded", "enc28j60", "embassy-net", "embedded-hal-async", "ethernet"] categories = ["embedded", "hardware-support", "no-std", "network-programming", "asynchronous"] diff --git a/embassy-net-esp-hosted/Cargo.toml b/embassy-net-esp-hosted/Cargo.toml index 45534925d..11ff32988 100644 --- a/embassy-net-esp-hosted/Cargo.toml +++ b/embassy-net-esp-hosted/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "embassy-net-esp-hosted" -version = "0.1.0" +version = "0.2.0" edition = "2021" description = "embassy-net driver for ESP-Hosted" keywords = ["embedded", "esp-hosted", "embassy-net", "embedded-hal-async", "wifi"] diff --git a/embassy-net-wiznet/Cargo.toml b/embassy-net-wiznet/Cargo.toml index 30c76d46e..2ad5a6f48 100644 --- a/embassy-net-wiznet/Cargo.toml +++ b/embassy-net-wiznet/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "embassy-net-wiznet" -version = "0.1.0" +version = "0.2.0" description = "embassy-net driver for WIZnet SPI Ethernet chips" keywords = ["embedded", "embassy-net", "embedded-hal-async", "ethernet", "async"] categories = ["embedded", "hardware-support", "no-std", "network-programming", "asynchronous"] diff --git a/examples/nrf52840/Cargo.toml b/examples/nrf52840/Cargo.toml index c8cf0504b..c3463c039 100644 --- a/examples/nrf52840/Cargo.toml +++ b/examples/nrf52840/Cargo.toml @@ -14,8 +14,8 @@ embassy-net = { version = "0.6.0", path = "../../embassy-net", features = ["defm embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embedded-io = { version = "0.6.0", features = ["defmt-03"] } embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } -embassy-net-esp-hosted = { version = "0.1.0", path = "../../embassy-net-esp-hosted", features = ["defmt"] } -embassy-net-enc28j60 = { version = "0.1.0", path = "../../embassy-net-enc28j60", features = ["defmt"] } +embassy-net-esp-hosted = { version = "0.2.0", path = "../../embassy-net-esp-hosted", features = ["defmt"] } +embassy-net-enc28j60 = { version = "0.2.0", path = "../../embassy-net-enc28j60", features = ["defmt"] } defmt = "0.3" defmt-rtt = "0.4" diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index 7b461aedc..a3deb5dc9 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml @@ -13,7 +13,7 @@ embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["de embassy-rp = { version = "0.2.0", path = "../../embassy-rp", features = ["defmt", "unstable-pac", "time-driver", "critical-section-impl", "rp2040"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embassy-net = { version = "0.6.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "raw", "dhcpv4", "medium-ethernet", "dns", "proto-ipv4", "proto-ipv6", "multicast"] } -embassy-net-wiznet = { version = "0.1.0", path = "../../embassy-net-wiznet", features = ["defmt"] } +embassy-net-wiznet = { version = "0.2.0", path = "../../embassy-net-wiznet", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-usb-logger = { version = "0.2.0", path = "../../embassy-usb-logger" } cyw43 = { version = "0.2.0", path = "../../cyw43", features = ["defmt", "firmware-logs"] } diff --git a/examples/rp23/Cargo.toml b/examples/rp23/Cargo.toml index d92478896..4cccafb0b 100644 --- a/examples/rp23/Cargo.toml +++ b/examples/rp23/Cargo.toml @@ -13,7 +13,7 @@ embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["de embassy-rp = { version = "0.2.0", path = "../../embassy-rp", features = ["defmt", "unstable-pac", "time-driver", "critical-section-impl", "rp235xa", "binary-info"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embassy-net = { version = "0.6.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "raw", "dhcpv4", "medium-ethernet", "dns"] } -embassy-net-wiznet = { version = "0.1.0", path = "../../embassy-net-wiznet", features = ["defmt"] } +embassy-net-wiznet = { version = "0.2.0", path = "../../embassy-net-wiznet", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-usb-logger = { version = "0.2.0", path = "../../embassy-usb-logger" } cyw43 = { version = "0.2.0", path = "../../cyw43", features = ["defmt", "firmware-logs"] } diff --git a/examples/stm32f4/Cargo.toml b/examples/stm32f4/Cargo.toml index 85902b22b..72cd0d7f5 100644 --- a/examples/stm32f4/Cargo.toml +++ b/examples/stm32f4/Cargo.toml @@ -12,7 +12,7 @@ embassy-executor = { version = "0.7.0", path = "../../embassy-executor", feature embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt" ] } embassy-net = { version = "0.6.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", ] } -embassy-net-wiznet = { version = "0.1.0", path = "../../embassy-net-wiznet", features = ["defmt"] } +embassy-net-wiznet = { version = "0.2.0", path = "../../embassy-net-wiznet", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } defmt = "0.3" diff --git a/examples/stm32l4/Cargo.toml b/examples/stm32l4/Cargo.toml index 9d9cc6c9d..4e210a35d 100644 --- a/examples/stm32l4/Cargo.toml +++ b/examples/stm32l4/Cargo.toml @@ -12,7 +12,7 @@ embassy-executor = { version = "0.7.0", path = "../../embassy-executor", feature embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768", ] } embassy-embedded-hal = { version = "0.3.0", path = "../../embassy-embedded-hal" } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } -embassy-net-adin1110 = { version = "0.2.0", path = "../../embassy-net-adin1110" } +embassy-net-adin1110 = { version = "0.3.0", path = "../../embassy-net-adin1110" } embassy-net = { version = "0.6.0", path = "../../embassy-net", features = ["defmt", "udp", "tcp", "dhcpv4", "medium-ethernet"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } diff --git a/tests/nrf/Cargo.toml b/tests/nrf/Cargo.toml index 8d48ae874..5f9d0343a 100644 --- a/tests/nrf/Cargo.toml +++ b/tests/nrf/Cargo.toml @@ -14,8 +14,8 @@ embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["de embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "time-driver-rtc1", "gpiote", "unstable-pac"] } embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } embassy-net = { version = "0.6.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", ] } -embassy-net-esp-hosted = { version = "0.1.0", path = "../../embassy-net-esp-hosted", features = ["defmt"] } -embassy-net-enc28j60 = { version = "0.1.0", path = "../../embassy-net-enc28j60", features = ["defmt"] } +embassy-net-esp-hosted = { version = "0.2.0", path = "../../embassy-net-esp-hosted", features = ["defmt"] } +embassy-net-enc28j60 = { version = "0.2.0", path = "../../embassy-net-enc28j60", features = ["defmt"] } embedded-hal-async = { version = "1.0" } embedded-hal-bus = { version = "0.1", features = ["async"] } static_cell = "2" diff --git a/tests/rp/Cargo.toml b/tests/rp/Cargo.toml index 200e8e0da..ed9d0af15 100644 --- a/tests/rp/Cargo.toml +++ b/tests/rp/Cargo.toml @@ -13,7 +13,7 @@ embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["de embassy-rp = { version = "0.2.0", path = "../../embassy-rp", features = [ "defmt", "unstable-pac", "time-driver", "critical-section-impl", "intrinsics", "rom-v2-intrinsics", "run-from-ram", "rp2040"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-net = { version = "0.6.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "dhcpv4", "medium-ethernet"] } -embassy-net-wiznet = { version = "0.1.0", path = "../../embassy-net-wiznet", features = ["defmt"] } +embassy-net-wiznet = { version = "0.2.0", path = "../../embassy-net-wiznet", features = ["defmt"] } embassy-embedded-hal = { version = "0.3.0", path = "../../embassy-embedded-hal/"} cyw43 = { path = "../../cyw43", features = ["defmt", "firmware-logs"] } cyw43-pio = { path = "../../cyw43-pio", features = ["defmt"] } From 89b97c2d7c213a36c97606996e16ef115f836ea9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Sun, 5 Jan 2025 21:30:29 +0100 Subject: [PATCH 0616/1217] Fix search-and-replacability --- embassy-nxp/Cargo.toml | 2 +- embassy-rp/Cargo.toml | 10 +++++----- embassy-stm32/Cargo.toml | 8 ++++---- embassy-usb-synopsys-otg/Cargo.toml | 2 +- examples/lpc55s69/Cargo.toml | 2 +- examples/stm32f7/Cargo.toml | 2 +- tests/stm32/Cargo.toml | 4 ++-- 7 files changed, 15 insertions(+), 15 deletions(-) diff --git a/embassy-nxp/Cargo.toml b/embassy-nxp/Cargo.toml index b0f73b63c..fb0a0fed2 100644 --- a/embassy-nxp/Cargo.toml +++ b/embassy-nxp/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" cortex-m = "0.7.7" cortex-m-rt = "0.7.0" critical-section = "1.1.2" -embassy-hal-internal = {version = "0.2.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-2"] } +embassy-hal-internal = { version = "0.2.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-2"] } embassy-sync = { version = "0.6.1", path = "../embassy-sync" } lpc55-pac = "0.5.0" defmt = "0.3.8" diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index 37d9d916f..4b3a67ff4 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml @@ -113,9 +113,9 @@ embassy-time-driver = { version = "0.2", path = "../embassy-time-driver", option embassy-time-queue-utils = { version = "0.1", path = "../embassy-time-queue-utils", optional = true } embassy-time = { version = "0.4.0", path = "../embassy-time" } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } -embassy-hal-internal = {version = "0.2.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-2"] } -embassy-embedded-hal = {version = "0.2.0", path = "../embassy-embedded-hal" } -embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver" } +embassy-hal-internal = { version = "0.2.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-2"] } +embassy-embedded-hal = { version = "0.3.0", path = "../embassy-embedded-hal" } +embassy-usb-driver = { version = "0.1.0", path = "../embassy-usb-driver" } atomic-polyfill = "1.0.1" defmt = { version = "0.3", optional = true } log = { version = "0.4.14", optional = true } @@ -139,8 +139,8 @@ embedded-hal-1 = { package = "embedded-hal", version = "1.0" } embedded-hal-async = { version = "1.0" } embedded-hal-nb = { version = "1.0" } -pio-proc = {version= "0.2" } -pio = {version= "0.2.1" } +pio-proc = { version= "0.2" } +pio = { version= "0.2.1" } rp2040-boot2 = "0.3" document-features = "0.2.10" sha2-const-stable = "0.1" diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 229f902fa..4bd9e112d 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -47,11 +47,11 @@ embassy-time = { version = "0.4.0", path = "../embassy-time", optional = true } embassy-time-driver = { version = "0.2", path = "../embassy-time-driver", optional = true } embassy-time-queue-utils = { version = "0.1", path = "../embassy-time-queue-utils", optional = true } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } -embassy-hal-internal = {version = "0.2.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-4"] } -embassy-embedded-hal = {version = "0.2.0", path = "../embassy-embedded-hal", default-features = false } +embassy-hal-internal = { version = "0.2.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-4"] } +embassy-embedded-hal = { version = "0.3.0", path = "../embassy-embedded-hal", default-features = false } embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver" } -embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver" } -embassy-usb-synopsys-otg = {version = "0.2.0", path = "../embassy-usb-synopsys-otg" } +embassy-usb-driver = { version = "0.1.0", path = "../embassy-usb-driver" } +embassy-usb-synopsys-otg = { version = "0.2.0", path = "../embassy-usb-synopsys-otg" } embassy-executor = { version = "0.7.0", path = "../embassy-executor", optional = true } embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } diff --git a/embassy-usb-synopsys-otg/Cargo.toml b/embassy-usb-synopsys-otg/Cargo.toml index 7a9143ef9..487cc556b 100644 --- a/embassy-usb-synopsys-otg/Cargo.toml +++ b/embassy-usb-synopsys-otg/Cargo.toml @@ -19,7 +19,7 @@ target = "thumbv7em-none-eabi" critical-section = "1.1" embassy-sync = { version = "0.6.1", path = "../embassy-sync" } -embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver" } +embassy-usb-driver = { version = "0.1.0", path = "../embassy-usb-driver" } defmt = { version = "0.3", optional = true } log = { version = "0.4.14", optional = true } diff --git a/examples/lpc55s69/Cargo.toml b/examples/lpc55s69/Cargo.toml index 1c8d5f456..c8efc2e72 100644 --- a/examples/lpc55s69/Cargo.toml +++ b/examples/lpc55s69/Cargo.toml @@ -12,7 +12,7 @@ embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["de embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt"] } panic-halt = "0.2.0" cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } -cortex-m-rt = {version = "0.7.0"} +cortex-m-rt = { version = "0.7.0"} defmt = "0.3" defmt-rtt = "0.4" panic-probe = { version = "0.3.2", features = ["print-defmt"] } diff --git a/examples/stm32f7/Cargo.toml b/examples/stm32f7/Cargo.toml index 96eb46c5c..f9f2ae9a4 100644 --- a/examples/stm32f7/Cargo.toml +++ b/examples/stm32f7/Cargo.toml @@ -30,7 +30,7 @@ embedded-storage = "0.3.1" static_cell = "2" sha2 = { version = "0.10.8", default-features = false } hmac = "0.12.1" -aes-gcm = {version = "0.10.3", default-features = false, features = ["aes", "heapless"] } +aes-gcm = { version = "0.10.3", default-features = false, features = ["aes", "heapless"] } [profile.release] debug = 2 diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml index c48b23f1e..5537969a4 100644 --- a/tests/stm32/Cargo.toml +++ b/tests/stm32/Cargo.toml @@ -87,8 +87,8 @@ portable-atomic = { version = "1.5", features = [] } chrono = { version = "^0.4", default-features = false, optional = true} sha2 = { version = "0.10.8", default-features = false } hmac = "0.12.1" -aes-gcm = {version = "0.10.3", default-features = false, features = ["aes", "heapless"] } -num-traits = {version="0.2", default-features = false,features = ["libm"], optional = true} +aes-gcm = { version = "0.10.3", default-features = false, features = ["aes", "heapless"] } +num-traits = { version="0.2", default-features = false,features = ["libm"], optional = true} # BEGIN TESTS # Generated by gen_test.py. DO NOT EDIT. From de27d9cd00f4b1bfe8eeda5bc2cdfc6fde746e47 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Mon, 6 Jan 2025 09:22:09 +0100 Subject: [PATCH 0617/1217] Update cyw43, nrf, rp hals and embassy-boot --- cyw43-pio/Cargo.toml | 4 ++-- docs/examples/basic/Cargo.toml | 2 +- embassy-boot-nrf/Cargo.toml | 2 +- embassy-boot-rp/Cargo.toml | 2 +- examples/boot/application/nrf/Cargo.toml | 4 ++-- examples/boot/application/rp/Cargo.toml | 4 ++-- examples/nrf-rtos-trace/Cargo.toml | 2 +- examples/nrf51/Cargo.toml | 2 +- examples/nrf52810/Cargo.toml | 2 +- examples/nrf52840-rtic/Cargo.toml | 2 +- examples/nrf52840/Cargo.toml | 2 +- examples/nrf5340/Cargo.toml | 2 +- examples/nrf54l15/Cargo.toml | 2 +- examples/nrf9151/ns/Cargo.toml | 2 +- examples/nrf9151/s/Cargo.toml | 2 +- examples/nrf9160/Cargo.toml | 2 +- examples/rp/Cargo.toml | 6 +++--- examples/rp23/Cargo.toml | 6 +++--- tests/nrf/Cargo.toml | 2 +- tests/rp/Cargo.toml | 2 +- 20 files changed, 27 insertions(+), 27 deletions(-) diff --git a/cyw43-pio/Cargo.toml b/cyw43-pio/Cargo.toml index e400d95ea..2f9994d23 100644 --- a/cyw43-pio/Cargo.toml +++ b/cyw43-pio/Cargo.toml @@ -10,8 +10,8 @@ repository = "https://github.com/embassy-rs/embassy" documentation = "https://docs.embassy.dev/cyw43-pio" [dependencies] -cyw43 = { version = "0.2.0", path = "../cyw43" } -embassy-rp = { version = "0.2.0", path = "../embassy-rp" } +cyw43 = { version = "0.3.0", path = "../cyw43" } +embassy-rp = { version = "0.3.0", path = "../embassy-rp" } pio-proc = "0.2" pio = "0.2.1" fixed = "1.23.1" diff --git a/docs/examples/basic/Cargo.toml b/docs/examples/basic/Cargo.toml index 613fc2041..04d042250 100644 --- a/docs/examples/basic/Cargo.toml +++ b/docs/examples/basic/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-executor = { version = "0.7.0", path = "../../../embassy-executor", features = ["defmt", "arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.4.0", path = "../../../embassy-time", features = ["defmt"] } -embassy-nrf = { version = "0.2.0", path = "../../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote"] } +embassy-nrf = { version = "0.3.0", path = "../../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote"] } defmt = "0.3" defmt-rtt = "0.3" diff --git a/embassy-boot-nrf/Cargo.toml b/embassy-boot-nrf/Cargo.toml index f72aa8fe1..9eaebfd5a 100644 --- a/embassy-boot-nrf/Cargo.toml +++ b/embassy-boot-nrf/Cargo.toml @@ -25,7 +25,7 @@ defmt = { version = "0.3", optional = true } log = { version = "0.4.17", optional = true } embassy-sync = { version = "0.6.1", path = "../embassy-sync" } -embassy-nrf = { version = "0.2.0", path = "../embassy-nrf", default-features = false } +embassy-nrf = { version = "0.3.0", path = "../embassy-nrf", default-features = false } embassy-boot = { version = "0.4.0", path = "../embassy-boot" } cortex-m = { version = "0.7.6" } cortex-m-rt = { version = "0.7" } diff --git a/embassy-boot-rp/Cargo.toml b/embassy-boot-rp/Cargo.toml index 74c3ab470..f092ff786 100644 --- a/embassy-boot-rp/Cargo.toml +++ b/embassy-boot-rp/Cargo.toml @@ -25,7 +25,7 @@ defmt = { version = "0.3", optional = true } log = { version = "0.4", optional = true } embassy-sync = { version = "0.6.1", path = "../embassy-sync" } -embassy-rp = { version = "0.2.0", path = "../embassy-rp", default-features = false } +embassy-rp = { version = "0.3.0", path = "../embassy-rp", default-features = false } embassy-boot = { version = "0.4.0", path = "../embassy-boot" } embassy-time = { version = "0.4.0", path = "../embassy-time" } diff --git a/examples/boot/application/nrf/Cargo.toml b/examples/boot/application/nrf/Cargo.toml index 6045656f5..7e57436ff 100644 --- a/examples/boot/application/nrf/Cargo.toml +++ b/examples/boot/application/nrf/Cargo.toml @@ -8,9 +8,9 @@ license = "MIT OR Apache-2.0" embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["task-arena-size-16384", "arch-cortex-m", "executor-thread", "arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [] } -embassy-nrf = { version = "0.2.0", path = "../../../../embassy-nrf", features = ["time-driver-rtc1", "gpiote", ] } +embassy-nrf = { version = "0.3.0", path = "../../../../embassy-nrf", features = ["time-driver-rtc1", "gpiote", ] } embassy-boot = { version = "0.4.0", path = "../../../../embassy-boot", features = [] } -embassy-boot-nrf = { version = "0.3.0", path = "../../../../embassy-boot-nrf", features = [] } +embassy-boot-nrf = { version = "0.4.0", path = "../../../../embassy-boot-nrf", features = [] } embassy-embedded-hal = { version = "0.3.0", path = "../../../../embassy-embedded-hal" } defmt = { version = "0.3", optional = true } diff --git a/examples/boot/application/rp/Cargo.toml b/examples/boot/application/rp/Cargo.toml index 8b5016faf..0c58bc624 100644 --- a/examples/boot/application/rp/Cargo.toml +++ b/examples/boot/application/rp/Cargo.toml @@ -8,8 +8,8 @@ license = "MIT OR Apache-2.0" embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["task-arena-size-16384", "arch-cortex-m", "executor-thread", "arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [] } -embassy-rp = { version = "0.2.0", path = "../../../../embassy-rp", features = ["time-driver", "rp2040"] } -embassy-boot-rp = { version = "0.3.0", path = "../../../../embassy-boot-rp", features = [] } +embassy-rp = { version = "0.3.0", path = "../../../../embassy-rp", features = ["time-driver", "rp2040"] } +embassy-boot-rp = { version = "0.4.0", path = "../../../../embassy-boot-rp", features = [] } embassy-embedded-hal = { version = "0.3.0", path = "../../../../embassy-embedded-hal" } defmt = "0.3" diff --git a/examples/nrf-rtos-trace/Cargo.toml b/examples/nrf-rtos-trace/Cargo.toml index 0623b27ea..66c0efe80 100644 --- a/examples/nrf-rtos-trace/Cargo.toml +++ b/examples/nrf-rtos-trace/Cargo.toml @@ -18,7 +18,7 @@ log = [ embassy-sync = { version = "0.6.1", path = "../../embassy-sync" } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "rtos-trace"] } embassy-time = { version = "0.4.0", path = "../../embassy-time" } -embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] } +embassy-nrf = { version = "0.3.0", path = "../../embassy-nrf", features = ["nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] } cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } cortex-m-rt = "0.7.0" diff --git a/examples/nrf51/Cargo.toml b/examples/nrf51/Cargo.toml index 492ebadd7..a91280419 100644 --- a/examples/nrf51/Cargo.toml +++ b/examples/nrf51/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-4096", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } -embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf51", "gpiote", "time-driver-rtc1", "unstable-pac", "time", "rt"] } +embassy-nrf = { version = "0.3.0", path = "../../embassy-nrf", features = ["defmt", "nrf51", "gpiote", "time-driver-rtc1", "unstable-pac", "time", "rt"] } defmt = "0.3" defmt-rtt = "0.4" diff --git a/examples/nrf52810/Cargo.toml b/examples/nrf52810/Cargo.toml index 8cd3b83e3..d0590b559 100644 --- a/examples/nrf52810/Cargo.toml +++ b/examples/nrf52810/Cargo.toml @@ -9,7 +9,7 @@ embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } -embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf52810", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } +embassy-nrf = { version = "0.3.0", path = "../../embassy-nrf", features = ["defmt", "nrf52810", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } defmt = "0.3" defmt-rtt = "0.4" diff --git a/examples/nrf52840-rtic/Cargo.toml b/examples/nrf52840-rtic/Cargo.toml index 00dfe9d80..9703218a1 100644 --- a/examples/nrf52840-rtic/Cargo.toml +++ b/examples/nrf52840-rtic/Cargo.toml @@ -11,7 +11,7 @@ embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = [ "defmt", "defmt-timestamp-uptime"] } embassy-time-queue-utils = { version = "0.1", path = "../../embassy-time-queue-utils", features = ["generic-queue-8"] } -embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = [ "defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } +embassy-nrf = { version = "0.3.0", path = "../../embassy-nrf", features = [ "defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } defmt = "0.3" defmt-rtt = "0.4" diff --git a/examples/nrf52840/Cargo.toml b/examples/nrf52840/Cargo.toml index c3463c039..72d5c63f4 100644 --- a/examples/nrf52840/Cargo.toml +++ b/examples/nrf52840/Cargo.toml @@ -9,7 +9,7 @@ embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } -embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } +embassy-nrf = { version = "0.3.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } embassy-net = { version = "0.6.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embedded-io = { version = "0.6.0", features = ["defmt-03"] } diff --git a/examples/nrf5340/Cargo.toml b/examples/nrf5340/Cargo.toml index 8eaf0e42b..237cfc69a 100644 --- a/examples/nrf5340/Cargo.toml +++ b/examples/nrf5340/Cargo.toml @@ -9,7 +9,7 @@ embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } -embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf5340-app-s", "time-driver-rtc1", "gpiote", "unstable-pac"] } +embassy-nrf = { version = "0.3.0", path = "../../embassy-nrf", features = ["defmt", "nrf5340-app-s", "time-driver-rtc1", "gpiote", "unstable-pac"] } embassy-net = { version = "0.6.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embedded-io-async = { version = "0.6.1" } diff --git a/examples/nrf54l15/Cargo.toml b/examples/nrf54l15/Cargo.toml index 3f8f091ec..3ee0c63e8 100644 --- a/examples/nrf54l15/Cargo.toml +++ b/examples/nrf54l15/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } -embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf54l15-app-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } +embassy-nrf = { version = "0.3.0", path = "../../embassy-nrf", features = ["defmt", "nrf54l15-app-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } defmt = "0.3" defmt-rtt = "0.4" diff --git a/examples/nrf9151/ns/Cargo.toml b/examples/nrf9151/ns/Cargo.toml index f32139d9e..c7a67fefc 100644 --- a/examples/nrf9151/ns/Cargo.toml +++ b/examples/nrf9151/ns/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-executor = { version = "0.7.0", path = "../../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } -embassy-nrf = { version = "0.2.0", path = "../../../embassy-nrf", features = ["defmt", "nrf9120-ns", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } +embassy-nrf = { version = "0.3.0", path = "../../../embassy-nrf", features = ["defmt", "nrf9120-ns", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } defmt = "0.3" defmt-rtt = "0.4" diff --git a/examples/nrf9151/s/Cargo.toml b/examples/nrf9151/s/Cargo.toml index 6ff5c4106..967baa3cd 100644 --- a/examples/nrf9151/s/Cargo.toml +++ b/examples/nrf9151/s/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-executor = { version = "0.7.0", path = "../../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } -embassy-nrf = { version = "0.2.0", path = "../../../embassy-nrf", features = ["defmt", "nrf9120-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } +embassy-nrf = { version = "0.3.0", path = "../../../embassy-nrf", features = ["defmt", "nrf9120-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } defmt = "0.3" defmt-rtt = "0.4" diff --git a/examples/nrf9160/Cargo.toml b/examples/nrf9160/Cargo.toml index 0c785d367..2e02671a7 100644 --- a/examples/nrf9160/Cargo.toml +++ b/examples/nrf9160/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } -embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf9160-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } +embassy-nrf = { version = "0.3.0", path = "../../embassy-nrf", features = ["defmt", "nrf9160-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } embassy-net-nrf91 = { version = "0.1.0", path = "../../embassy-net-nrf91", features = ["defmt"] } embassy-net = { version = "0.6.0", path = "../../embassy-net", features = ["defmt", "tcp", "proto-ipv4", "medium-ip"] } diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index a3deb5dc9..73ca4b5a5 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml @@ -10,14 +10,14 @@ embassy-embedded-hal = { version = "0.3.0", path = "../../embassy-embedded-hal", embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-98304", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } -embassy-rp = { version = "0.2.0", path = "../../embassy-rp", features = ["defmt", "unstable-pac", "time-driver", "critical-section-impl", "rp2040"] } +embassy-rp = { version = "0.3.0", path = "../../embassy-rp", features = ["defmt", "unstable-pac", "time-driver", "critical-section-impl", "rp2040"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embassy-net = { version = "0.6.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "raw", "dhcpv4", "medium-ethernet", "dns", "proto-ipv4", "proto-ipv6", "multicast"] } embassy-net-wiznet = { version = "0.2.0", path = "../../embassy-net-wiznet", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-usb-logger = { version = "0.2.0", path = "../../embassy-usb-logger" } -cyw43 = { version = "0.2.0", path = "../../cyw43", features = ["defmt", "firmware-logs"] } -cyw43-pio = { version = "0.2.0", path = "../../cyw43-pio", features = ["defmt"] } +cyw43 = { version = "0.3.0", path = "../../cyw43", features = ["defmt", "firmware-logs"] } +cyw43-pio = { version = "0.3.0", path = "../../cyw43-pio", features = ["defmt"] } defmt = "0.3" defmt-rtt = "0.4" diff --git a/examples/rp23/Cargo.toml b/examples/rp23/Cargo.toml index 4cccafb0b..68ceee933 100644 --- a/examples/rp23/Cargo.toml +++ b/examples/rp23/Cargo.toml @@ -10,14 +10,14 @@ embassy-embedded-hal = { version = "0.3.0", path = "../../embassy-embedded-hal", embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-98304", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } -embassy-rp = { version = "0.2.0", path = "../../embassy-rp", features = ["defmt", "unstable-pac", "time-driver", "critical-section-impl", "rp235xa", "binary-info"] } +embassy-rp = { version = "0.3.0", path = "../../embassy-rp", features = ["defmt", "unstable-pac", "time-driver", "critical-section-impl", "rp235xa", "binary-info"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embassy-net = { version = "0.6.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "raw", "dhcpv4", "medium-ethernet", "dns"] } embassy-net-wiznet = { version = "0.2.0", path = "../../embassy-net-wiznet", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-usb-logger = { version = "0.2.0", path = "../../embassy-usb-logger" } -cyw43 = { version = "0.2.0", path = "../../cyw43", features = ["defmt", "firmware-logs"] } -cyw43-pio = { version = "0.2.0", path = "../../cyw43-pio", features = ["defmt"] } +cyw43 = { version = "0.3.0", path = "../../cyw43", features = ["defmt", "firmware-logs"] } +cyw43-pio = { version = "0.3.0", path = "../../cyw43-pio", features = ["defmt"] } defmt = "0.3" defmt-rtt = "0.4" diff --git a/tests/nrf/Cargo.toml b/tests/nrf/Cargo.toml index 5f9d0343a..390a594bc 100644 --- a/tests/nrf/Cargo.toml +++ b/tests/nrf/Cargo.toml @@ -11,7 +11,7 @@ embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt", ] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } -embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "time-driver-rtc1", "gpiote", "unstable-pac"] } +embassy-nrf = { version = "0.3.0", path = "../../embassy-nrf", features = ["defmt", "time-driver-rtc1", "gpiote", "unstable-pac"] } embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } embassy-net = { version = "0.6.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", ] } embassy-net-esp-hosted = { version = "0.2.0", path = "../../embassy-net-esp-hosted", features = ["defmt"] } diff --git a/tests/rp/Cargo.toml b/tests/rp/Cargo.toml index ed9d0af15..4278f7b2c 100644 --- a/tests/rp/Cargo.toml +++ b/tests/rp/Cargo.toml @@ -10,7 +10,7 @@ teleprobe-meta = "1.1" embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", ] } -embassy-rp = { version = "0.2.0", path = "../../embassy-rp", features = [ "defmt", "unstable-pac", "time-driver", "critical-section-impl", "intrinsics", "rom-v2-intrinsics", "run-from-ram", "rp2040"] } +embassy-rp = { version = "0.3.0", path = "../../embassy-rp", features = [ "defmt", "unstable-pac", "time-driver", "critical-section-impl", "intrinsics", "rom-v2-intrinsics", "run-from-ram", "rp2040"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-net = { version = "0.6.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "dhcpv4", "medium-ethernet"] } embassy-net-wiznet = { version = "0.2.0", path = "../../embassy-net-wiznet", features = ["defmt"] } From 4caeeade4d67c9513e83c2cd711f3d222d7616f3 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Mon, 6 Jan 2025 09:54:51 +0100 Subject: [PATCH 0618/1217] Update changelogs --- cyw43-pio/CHANGELOG.md | 6 ++++++ cyw43/CHANGELOG.md | 5 +++++ embassy-nrf/CHANGELOG.md | 16 ++++++++++++++++ embassy-rp/CHANGELOG.md | 7 +++++++ 4 files changed, 34 insertions(+) diff --git a/cyw43-pio/CHANGELOG.md b/cyw43-pio/CHANGELOG.md index 913f3515a..e65ca5679 100644 --- a/cyw43-pio/CHANGELOG.md +++ b/cyw43-pio/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +## 0.3.0 - 2025-01-05 + +- Update embassy-time to 0.4.0 +- Update cyw43 to 0.3.0 +- Update embassy-rp to 0.3.0 + ## 0.2.0 - 2024-08-05 - Update to cyw43 0.2.0 diff --git a/cyw43/CHANGELOG.md b/cyw43/CHANGELOG.md index 1859f7317..8db77da5d 100644 --- a/cyw43/CHANGELOG.md +++ b/cyw43/CHANGELOG.md @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +## 0.3.0 - 2025-01-05 + +- Update embassy-time to 0.4.0 +- Update embassy-rp to 0.3.0 + ## 0.2.0 - 2024-08-05 - Update to new versions of embassy-{time,sync} diff --git a/embassy-nrf/CHANGELOG.md b/embassy-nrf/CHANGELOG.md index f8d6ab753..a472c1d07 100644 --- a/embassy-nrf/CHANGELOG.md +++ b/embassy-nrf/CHANGELOG.md @@ -7,6 +7,22 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +## 0.3.0 - 2025-01-06 + +- Updated `embassy-time` to v0.4 +- Add basic nrf54 support +- Switch to use nrf-pac chiptool based PAC +- Fix bug where timer alarm was not scheduled if interrupted +- Add RESET operations helpers for nrf5340 +- Allow debug access from firmware for nrf54l +- Add trait `embedded_io_async` to uarte +- Add system off and wake-on-field for nrf +- Use inline const for initializing arrays +- Add NFCT driver and related changes for nrf +- Add support for transactions to Twim (embassy-nrf) +- Fix build issues related to nrf9120 features +- Disconnect input and fix bad pin assignment in nrf/pwm + ## 0.2.0 - 2024-08-05 - Support for NRF chips: diff --git a/embassy-rp/CHANGELOG.md b/embassy-rp/CHANGELOG.md index 7eef64292..196fcf528 100644 --- a/embassy-rp/CHANGELOG.md +++ b/embassy-rp/CHANGELOG.md @@ -7,6 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +## 0.3.0 - 2025-01-05 + +- Initial rp235x support +- Setup timer0 tick when initializing clocks +- Allow separate control of duty cycle for each channel in a pwm slice by splitting the Pwm driver. +- Implement `embedded_io::Write` for Uart<'d, T: Instance, Blocking> and UartTx<'d, T: Instance, Blocking> + ## 0.2.0 - 2024-08-05 - Add read_to_break_with_count From 0ef98c70e754d480121753a3727e7e06b814f252 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Mon, 6 Jan 2025 10:18:21 +0100 Subject: [PATCH 0619/1217] Bump the versions --- cyw43-pio/Cargo.toml | 2 +- cyw43/Cargo.toml | 2 +- embassy-boot-nrf/Cargo.toml | 2 +- embassy-boot-rp/Cargo.toml | 2 +- embassy-nrf/Cargo.toml | 2 +- embassy-rp/Cargo.toml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/cyw43-pio/Cargo.toml b/cyw43-pio/Cargo.toml index 2f9994d23..292cccf66 100644 --- a/cyw43-pio/Cargo.toml +++ b/cyw43-pio/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cyw43-pio" -version = "0.2.0" +version = "0.3.0" edition = "2021" description = "RP2040 PIO SPI implementation for cyw43" keywords = ["embedded", "cyw43", "embassy-net", "embedded-hal-async", "wifi"] diff --git a/cyw43/Cargo.toml b/cyw43/Cargo.toml index 91873d663..aac6b19db 100644 --- a/cyw43/Cargo.toml +++ b/cyw43/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cyw43" -version = "0.2.0" +version = "0.3.0" edition = "2021" description = "Rust driver for the CYW43439 WiFi chip, used in the Raspberry Pi Pico W." keywords = ["embedded", "cyw43", "embassy-net", "embedded-hal-async", "wifi"] diff --git a/embassy-boot-nrf/Cargo.toml b/embassy-boot-nrf/Cargo.toml index 9eaebfd5a..e49bed15d 100644 --- a/embassy-boot-nrf/Cargo.toml +++ b/embassy-boot-nrf/Cargo.toml @@ -1,7 +1,7 @@ [package] edition = "2021" name = "embassy-boot-nrf" -version = "0.3.0" +version = "0.4.0" description = "Bootloader lib for nRF chips" license = "MIT OR Apache-2.0" repository = "https://github.com/embassy-rs/embassy" diff --git a/embassy-boot-rp/Cargo.toml b/embassy-boot-rp/Cargo.toml index f092ff786..6e8a104cd 100644 --- a/embassy-boot-rp/Cargo.toml +++ b/embassy-boot-rp/Cargo.toml @@ -1,7 +1,7 @@ [package] edition = "2021" name = "embassy-boot-rp" -version = "0.3.0" +version = "0.4.0" description = "Bootloader lib for RP2040 chips" license = "MIT OR Apache-2.0" repository = "https://github.com/embassy-rs/embassy" diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml index efaf03356..056b4c508 100644 --- a/embassy-nrf/Cargo.toml +++ b/embassy-nrf/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "embassy-nrf" -version = "0.2.0" +version = "0.3.0" edition = "2021" license = "MIT OR Apache-2.0" description = "Embassy Hardware Abstraction Layer (HAL) for nRF series microcontrollers" diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index 4b3a67ff4..a5e5b81b4 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "embassy-rp" -version = "0.2.0" +version = "0.3.0" edition = "2021" license = "MIT OR Apache-2.0" description = "Embassy Hardware Abstraction Layer (HAL) for the Raspberry Pi RP2040 microcontroller" From caea4067fb9b02eec9f3d278f8cc86770a7c2ec9 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Mon, 6 Jan 2025 10:38:01 +0100 Subject: [PATCH 0620/1217] Bump pac version --- embassy-rp/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index a5e5b81b4..56cc39bbf 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml @@ -132,7 +132,7 @@ embedded-storage-async = { version = "0.4.1" } rand_core = "0.6.4" fixed = "1.28.0" -rp-pac = { git = "https://github.com/embassy-rs/rp-pac.git", rev = "a7f42d25517f7124ad3b4ed492dec8b0f50a0e6c", feature = ["rt"] } +rp-pac = { version = "7.0.0", feature = ["rt"] } embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } embedded-hal-1 = { package = "embedded-hal", version = "1.0" } From 3c87bb588b38ebba6395a0d7b1c37727a7919fe2 Mon Sep 17 00:00:00 2001 From: Georges Palauqui Date: Mon, 6 Jan 2025 12:43:48 +0100 Subject: [PATCH 0621/1217] `embassy-rp`: add `set_pullup()` for `OutputOpenDrain` --- embassy-rp/src/gpio.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/embassy-rp/src/gpio.rs b/embassy-rp/src/gpio.rs index 203192827..b3a53d1b9 100644 --- a/embassy-rp/src/gpio.rs +++ b/embassy-rp/src/gpio.rs @@ -450,6 +450,16 @@ impl<'d> OutputOpenDrain<'d> { Self { pin } } + /// Set the pin's pull-up. + #[inline] + pub fn set_pullup(&mut self, enable: bool) { + if enable { + self.pin.set_pull(Pull::Up); + } else { + self.pin.set_pull(Pull::None); + } + } + /// Set the pin's drive strength. #[inline] pub fn set_drive_strength(&mut self, strength: Drive) { From c7e7603a243591fbef8d386d0b2d294fb5998549 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Mon, 6 Jan 2025 13:06:32 +0100 Subject: [PATCH 0622/1217] Use released nrf pac --- embassy-nrf/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml index 056b4c508..9f8cd85d8 100644 --- a/embassy-nrf/Cargo.toml +++ b/embassy-nrf/Cargo.toml @@ -148,7 +148,7 @@ embedded-hal-async = { version = "1.0" } embedded-io = { version = "0.6.0" } embedded-io-async = { version = "0.6.1" } -nrf-pac = { git = "https://github.com/embassy-rs/nrf-pac", rev = "52e3a757f06035c94291bfc42b0c03f71e4d677e" } +nrf-pac = "0.1.0" defmt = { version = "0.3", optional = true } bitflags = "2.4.2" From 41dcebe44621a51cc0c3f39b9cec14aefce63b0d Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 6 Jan 2025 13:08:09 +0100 Subject: [PATCH 0623/1217] changelog fixes --- cyw43/CHANGELOG.md | 6 ++++-- cyw43/README.md | 43 ++++++++++++++++++++++++---------------- embassy-nrf/CHANGELOG.md | 2 +- embassy-rp/CHANGELOG.md | 2 ++ 4 files changed, 33 insertions(+), 20 deletions(-) diff --git a/cyw43/CHANGELOG.md b/cyw43/CHANGELOG.md index 8db77da5d..40a638388 100644 --- a/cyw43/CHANGELOG.md +++ b/cyw43/CHANGELOG.md @@ -9,8 +9,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## 0.3.0 - 2025-01-05 -- Update embassy-time to 0.4.0 -- Update embassy-rp to 0.3.0 +- Update `embassy-time` to 0.4.0 +- Add Bluetooth support. +- Add WPA3 support. +- Expand wifi security configuration options. ## 0.2.0 - 2024-08-05 diff --git a/cyw43/README.md b/cyw43/README.md index 5b4a5d789..9e9f7a34c 100644 --- a/cyw43/README.md +++ b/cyw43/README.md @@ -1,27 +1,36 @@ # cyw43 -Rust driver for the CYW43439 wifi chip, used in the Raspberry Pi Pico W. Implementation based on [Infineon/wifi-host-driver](https://github.com/Infineon/wifi-host-driver). +Rust driver for the CYW43439 wifi+bluetooth chip. Implementation based on [Infineon/wifi-host-driver](https://github.com/Infineon/wifi-host-driver). -## Current status +Works on the following boards: + +- Raspberry Pi Pico W (RP2040) +- Raspberry Pi Pico 2 W (RP2350A) +- Pimoroni Pico Plus 2 W (RP2350B) +- Any board with Raspberry Pi RM2 radio module. +- Any board with the CYW43439 chip, and possibly others if the protocol is similar enough. + +## Features Working: -- Station mode (joining an AP). -- AP mode (creating an AP) -- Scanning -- Sending and receiving Ethernet frames. -- Using the default MAC address. -- [`embassy-net`](https://embassy.dev) integration. -- RP2040 PIO driver for the nonstandard half-duplex SPI used in the Pico W. -- Using IRQ for device events -- GPIO support (for LED on the Pico W) +- WiFi support + - Station mode (joining an AP). + - AP mode (creating an AP) + - Scanning + - Sending and receiving Ethernet frames. + - Using the default MAC address. + - [`embassy-net`](https://embassy.dev) integration. + - RP2040 PIO driver for the nonstandard half-duplex SPI used in the Pico W. + - Using IRQ for device events, no busy polling. + - GPIO support (for LED on the Pico W). +- Bluetooth support + - Bluetooth Classic + LE HCI commands. + - Concurrent operation with WiFi. + - Implements the [bt-hci](https://crates.io/crates/bt-hci) controller traits. + - Works with the [TrouBLE](https://github.com/embassy-rs/trouble) bluetooth LE stack. Check its repo for examples using `cyw43`. -TODO: - -- Setting a custom MAC address. -- Bus sleep (for power consumption optimization) - -## Running the examples +## Running the WiFi examples - Install `probe-rs` following the instructions at . - `cd examples/rp` diff --git a/embassy-nrf/CHANGELOG.md b/embassy-nrf/CHANGELOG.md index a472c1d07..4d68950a7 100644 --- a/embassy-nrf/CHANGELOG.md +++ b/embassy-nrf/CHANGELOG.md @@ -11,7 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Updated `embassy-time` to v0.4 - Add basic nrf54 support -- Switch to use nrf-pac chiptool based PAC +- Switch to use `nrf-pac` chiptool-based PAC - Fix bug where timer alarm was not scheduled if interrupted - Add RESET operations helpers for nrf5340 - Allow debug access from firmware for nrf54l diff --git a/embassy-rp/CHANGELOG.md b/embassy-rp/CHANGELOG.md index 196fcf528..117882f38 100644 --- a/embassy-rp/CHANGELOG.md +++ b/embassy-rp/CHANGELOG.md @@ -9,10 +9,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## 0.3.0 - 2025-01-05 +- Updated `embassy-time` to v0.4 - Initial rp235x support - Setup timer0 tick when initializing clocks - Allow separate control of duty cycle for each channel in a pwm slice by splitting the Pwm driver. - Implement `embedded_io::Write` for Uart<'d, T: Instance, Blocking> and UartTx<'d, T: Instance, Blocking> +- Add `set_pullup()` to OutputOpenDrain. ## 0.2.0 - 2024-08-05 From 209183ebea26743e95a140b47cdfd9d67083595b Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 6 Jan 2025 13:22:44 +0100 Subject: [PATCH 0624/1217] Fixes for new PACs. --- embassy-net-nrf91/Cargo.toml | 2 +- embassy-rp/src/gpio.rs | 8 ++++---- embassy-rp/src/pio/mod.rs | 8 ++++---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/embassy-net-nrf91/Cargo.toml b/embassy-net-nrf91/Cargo.toml index 4e2f17ab2..6c7af9c80 100644 --- a/embassy-net-nrf91/Cargo.toml +++ b/embassy-net-nrf91/Cargo.toml @@ -17,7 +17,7 @@ log = [ "dep:log" ] defmt = { version = "0.3", optional = true } log = { version = "0.4.14", optional = true } -nrf-pac = { git = "https://github.com/embassy-rs/nrf-pac", rev = "52e3a757f06035c94291bfc42b0c03f71e4d677e" } +nrf-pac = "0.1.0" cortex-m = "0.7.7" embassy-time = { version = "0.4.0", path = "../embassy-time" } diff --git a/embassy-rp/src/gpio.rs b/embassy-rp/src/gpio.rs index 203192827..d3486b0fa 100644 --- a/embassy-rp/src/gpio.rs +++ b/embassy-rp/src/gpio.rs @@ -624,10 +624,10 @@ impl<'d> Flex<'d> { pub fn set_drive_strength(&mut self, strength: Drive) { self.pin.pad_ctrl().modify(|w| { w.set_drive(match strength { - Drive::_2mA => pac::pads::vals::Drive::_2MA, - Drive::_4mA => pac::pads::vals::Drive::_4MA, - Drive::_8mA => pac::pads::vals::Drive::_8MA, - Drive::_12mA => pac::pads::vals::Drive::_12MA, + Drive::_2mA => pac::pads::vals::Drive::_2M_A, + Drive::_4mA => pac::pads::vals::Drive::_4M_A, + Drive::_8mA => pac::pads::vals::Drive::_8M_A, + Drive::_12mA => pac::pads::vals::Drive::_12M_A, }); }); } diff --git a/embassy-rp/src/pio/mod.rs b/embassy-rp/src/pio/mod.rs index e3c25020f..8916cbef0 100644 --- a/embassy-rp/src/pio/mod.rs +++ b/embassy-rp/src/pio/mod.rs @@ -230,10 +230,10 @@ impl<'l, PIO: Instance> Pin<'l, PIO> { pub fn set_drive_strength(&mut self, strength: Drive) { self.pin.pad_ctrl().modify(|w| { w.set_drive(match strength { - Drive::_2mA => pac::pads::vals::Drive::_2MA, - Drive::_4mA => pac::pads::vals::Drive::_4MA, - Drive::_8mA => pac::pads::vals::Drive::_8MA, - Drive::_12mA => pac::pads::vals::Drive::_12MA, + Drive::_2mA => pac::pads::vals::Drive::_2M_A, + Drive::_4mA => pac::pads::vals::Drive::_4M_A, + Drive::_8mA => pac::pads::vals::Drive::_8M_A, + Drive::_12mA => pac::pads::vals::Drive::_12M_A, }); }); } From 7f05c1e43904081f16cdf7e3f7df99fc9d7f3fee Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 6 Jan 2025 15:37:31 +0100 Subject: [PATCH 0625/1217] Update stm32-metapac. --- embassy-stm32/Cargo.toml | 131 ++++++++++++++-------------- embassy-stm32/build.rs | 137 +++++++++++++++++++++++++++++- embassy-stm32/src/exti.rs | 9 +- embassy-stm32/src/flash/common.rs | 2 +- embassy-stm32/src/flash/f4.rs | 4 +- embassy-stm32/src/flash/mod.rs | 3 +- embassy-stm32/src/gpio.rs | 6 +- 7 files changed, 216 insertions(+), 76 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 30ea143c0..d66d3bc1d 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -73,7 +73,7 @@ rand_core = "0.6.3" sdio-host = "0.5.0" critical-section = "1.1" #stm32-metapac = { version = "15" } -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-274eeb0ed4477768d026276c4e9873586c1b9a05" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-fad4bc0f2baac29ecebb5153d2997b649b71025f" } vcell = "0.1.3" nb = "1.0.0" @@ -102,7 +102,7 @@ proc-macro2 = "1.0.36" quote = "1.0.15" #stm32-metapac = { version = "15", default-features = false, features = ["metadata"]} -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-274eeb0ed4477768d026276c4e9873586c1b9a05", default-features = false, features = ["metadata"] } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-fad4bc0f2baac29ecebb5153d2997b649b71025f", default-features = false, features = ["metadata"] } [features] default = ["rt"] @@ -127,8 +127,8 @@ exti = [] low-power = [ "dep:embassy-executor", "embassy-executor?/arch-cortex-m", "time" ] low-power-debug-with-sleep = [] -## Automatically generate `memory.x` file using [`stm32-metapac`](https://docs.rs/stm32-metapac/) -memory-x = ["stm32-metapac/memory-x"] +## Automatically generate `memory.x` file based on the memory map from [`stm32-metapac`](https://docs.rs/stm32-metapac/) +memory-x = [] ## Use secure registers when TrustZone is enabled trustzone-secure = [] @@ -202,6 +202,9 @@ _split-pins-enabled = [] ## internal use only _dual-core = [] +_core-cm0p = [] +_core-cm4 = [] +_core-cm7 = [] #! ## Chip-selection features #! Select your chip by specifying the model as a feature, e.g. `stm32c011d6`. @@ -1026,40 +1029,40 @@ stm32h743xg = [ "stm32-metapac/stm32h743xg" ] stm32h743xi = [ "stm32-metapac/stm32h743xi" ] stm32h743zg = [ "stm32-metapac/stm32h743zg" ] stm32h743zi = [ "stm32-metapac/stm32h743zi" ] -stm32h745bg-cm7 = [ "stm32-metapac/stm32h745bg-cm7", "_dual-core" ] -stm32h745bg-cm4 = [ "stm32-metapac/stm32h745bg-cm4", "_dual-core" ] -stm32h745bi-cm7 = [ "stm32-metapac/stm32h745bi-cm7", "_dual-core" ] -stm32h745bi-cm4 = [ "stm32-metapac/stm32h745bi-cm4", "_dual-core" ] -stm32h745ig-cm7 = [ "stm32-metapac/stm32h745ig-cm7", "_dual-core" ] -stm32h745ig-cm4 = [ "stm32-metapac/stm32h745ig-cm4", "_dual-core" ] -stm32h745ii-cm7 = [ "stm32-metapac/stm32h745ii-cm7", "_dual-core" ] -stm32h745ii-cm4 = [ "stm32-metapac/stm32h745ii-cm4", "_dual-core" ] -stm32h745xg-cm7 = [ "stm32-metapac/stm32h745xg-cm7", "_dual-core" ] -stm32h745xg-cm4 = [ "stm32-metapac/stm32h745xg-cm4", "_dual-core" ] -stm32h745xi-cm7 = [ "stm32-metapac/stm32h745xi-cm7", "_dual-core" ] -stm32h745xi-cm4 = [ "stm32-metapac/stm32h745xi-cm4", "_dual-core" ] -stm32h745zg-cm7 = [ "stm32-metapac/stm32h745zg-cm7", "_dual-core" ] -stm32h745zg-cm4 = [ "stm32-metapac/stm32h745zg-cm4", "_dual-core" ] -stm32h745zi-cm7 = [ "stm32-metapac/stm32h745zi-cm7", "_dual-core" ] -stm32h745zi-cm4 = [ "stm32-metapac/stm32h745zi-cm4", "_dual-core" ] -stm32h747ag-cm7 = [ "stm32-metapac/stm32h747ag-cm7", "_dual-core" ] -stm32h747ag-cm4 = [ "stm32-metapac/stm32h747ag-cm4", "_dual-core" ] -stm32h747ai-cm7 = [ "stm32-metapac/stm32h747ai-cm7", "_dual-core" ] -stm32h747ai-cm4 = [ "stm32-metapac/stm32h747ai-cm4", "_dual-core" ] -stm32h747bg-cm7 = [ "stm32-metapac/stm32h747bg-cm7", "_dual-core" ] -stm32h747bg-cm4 = [ "stm32-metapac/stm32h747bg-cm4", "_dual-core" ] -stm32h747bi-cm7 = [ "stm32-metapac/stm32h747bi-cm7", "_dual-core" ] -stm32h747bi-cm4 = [ "stm32-metapac/stm32h747bi-cm4", "_dual-core" ] -stm32h747ig-cm7 = [ "stm32-metapac/stm32h747ig-cm7", "_dual-core" ] -stm32h747ig-cm4 = [ "stm32-metapac/stm32h747ig-cm4", "_dual-core" ] -stm32h747ii-cm7 = [ "stm32-metapac/stm32h747ii-cm7", "_dual-core" ] -stm32h747ii-cm4 = [ "stm32-metapac/stm32h747ii-cm4", "_dual-core" ] -stm32h747xg-cm7 = [ "stm32-metapac/stm32h747xg-cm7", "_dual-core" ] -stm32h747xg-cm4 = [ "stm32-metapac/stm32h747xg-cm4", "_dual-core" ] -stm32h747xi-cm7 = [ "stm32-metapac/stm32h747xi-cm7", "_dual-core" ] -stm32h747xi-cm4 = [ "stm32-metapac/stm32h747xi-cm4", "_dual-core" ] -stm32h747zi-cm7 = [ "stm32-metapac/stm32h747zi-cm7", "_dual-core" ] -stm32h747zi-cm4 = [ "stm32-metapac/stm32h747zi-cm4", "_dual-core" ] +stm32h745bg-cm7 = [ "stm32-metapac/stm32h745bg-cm7", "_dual-core", "_core-cm7" ] +stm32h745bg-cm4 = [ "stm32-metapac/stm32h745bg-cm4", "_dual-core", "_core-cm4" ] +stm32h745bi-cm7 = [ "stm32-metapac/stm32h745bi-cm7", "_dual-core", "_core-cm7" ] +stm32h745bi-cm4 = [ "stm32-metapac/stm32h745bi-cm4", "_dual-core", "_core-cm4" ] +stm32h745ig-cm7 = [ "stm32-metapac/stm32h745ig-cm7", "_dual-core", "_core-cm7" ] +stm32h745ig-cm4 = [ "stm32-metapac/stm32h745ig-cm4", "_dual-core", "_core-cm4" ] +stm32h745ii-cm7 = [ "stm32-metapac/stm32h745ii-cm7", "_dual-core", "_core-cm7" ] +stm32h745ii-cm4 = [ "stm32-metapac/stm32h745ii-cm4", "_dual-core", "_core-cm4" ] +stm32h745xg-cm7 = [ "stm32-metapac/stm32h745xg-cm7", "_dual-core", "_core-cm7" ] +stm32h745xg-cm4 = [ "stm32-metapac/stm32h745xg-cm4", "_dual-core", "_core-cm4" ] +stm32h745xi-cm7 = [ "stm32-metapac/stm32h745xi-cm7", "_dual-core", "_core-cm7" ] +stm32h745xi-cm4 = [ "stm32-metapac/stm32h745xi-cm4", "_dual-core", "_core-cm4" ] +stm32h745zg-cm7 = [ "stm32-metapac/stm32h745zg-cm7", "_dual-core", "_core-cm7" ] +stm32h745zg-cm4 = [ "stm32-metapac/stm32h745zg-cm4", "_dual-core", "_core-cm4" ] +stm32h745zi-cm7 = [ "stm32-metapac/stm32h745zi-cm7", "_dual-core", "_core-cm7" ] +stm32h745zi-cm4 = [ "stm32-metapac/stm32h745zi-cm4", "_dual-core", "_core-cm4" ] +stm32h747ag-cm7 = [ "stm32-metapac/stm32h747ag-cm7", "_dual-core", "_core-cm7" ] +stm32h747ag-cm4 = [ "stm32-metapac/stm32h747ag-cm4", "_dual-core", "_core-cm4" ] +stm32h747ai-cm7 = [ "stm32-metapac/stm32h747ai-cm7", "_dual-core", "_core-cm7" ] +stm32h747ai-cm4 = [ "stm32-metapac/stm32h747ai-cm4", "_dual-core", "_core-cm4" ] +stm32h747bg-cm7 = [ "stm32-metapac/stm32h747bg-cm7", "_dual-core", "_core-cm7" ] +stm32h747bg-cm4 = [ "stm32-metapac/stm32h747bg-cm4", "_dual-core", "_core-cm4" ] +stm32h747bi-cm7 = [ "stm32-metapac/stm32h747bi-cm7", "_dual-core", "_core-cm7" ] +stm32h747bi-cm4 = [ "stm32-metapac/stm32h747bi-cm4", "_dual-core", "_core-cm4" ] +stm32h747ig-cm7 = [ "stm32-metapac/stm32h747ig-cm7", "_dual-core", "_core-cm7" ] +stm32h747ig-cm4 = [ "stm32-metapac/stm32h747ig-cm4", "_dual-core", "_core-cm4" ] +stm32h747ii-cm7 = [ "stm32-metapac/stm32h747ii-cm7", "_dual-core", "_core-cm7" ] +stm32h747ii-cm4 = [ "stm32-metapac/stm32h747ii-cm4", "_dual-core", "_core-cm4" ] +stm32h747xg-cm7 = [ "stm32-metapac/stm32h747xg-cm7", "_dual-core", "_core-cm7" ] +stm32h747xg-cm4 = [ "stm32-metapac/stm32h747xg-cm4", "_dual-core", "_core-cm4" ] +stm32h747xi-cm7 = [ "stm32-metapac/stm32h747xi-cm7", "_dual-core", "_core-cm7" ] +stm32h747xi-cm4 = [ "stm32-metapac/stm32h747xi-cm4", "_dual-core", "_core-cm4" ] +stm32h747zi-cm7 = [ "stm32-metapac/stm32h747zi-cm7", "_dual-core", "_core-cm7" ] +stm32h747zi-cm4 = [ "stm32-metapac/stm32h747zi-cm4", "_dual-core", "_core-cm4" ] stm32h750ib = [ "stm32-metapac/stm32h750ib" ] stm32h750vb = [ "stm32-metapac/stm32h750vb" ] stm32h750xb = [ "stm32-metapac/stm32h750xb" ] @@ -1070,24 +1073,24 @@ stm32h753ii = [ "stm32-metapac/stm32h753ii" ] stm32h753vi = [ "stm32-metapac/stm32h753vi" ] stm32h753xi = [ "stm32-metapac/stm32h753xi" ] stm32h753zi = [ "stm32-metapac/stm32h753zi" ] -stm32h755bi-cm7 = [ "stm32-metapac/stm32h755bi-cm7", "_dual-core" ] -stm32h755bi-cm4 = [ "stm32-metapac/stm32h755bi-cm4", "_dual-core" ] -stm32h755ii-cm7 = [ "stm32-metapac/stm32h755ii-cm7", "_dual-core" ] -stm32h755ii-cm4 = [ "stm32-metapac/stm32h755ii-cm4", "_dual-core" ] -stm32h755xi-cm7 = [ "stm32-metapac/stm32h755xi-cm7", "_dual-core" ] -stm32h755xi-cm4 = [ "stm32-metapac/stm32h755xi-cm4", "_dual-core" ] -stm32h755zi-cm7 = [ "stm32-metapac/stm32h755zi-cm7", "_dual-core" ] -stm32h755zi-cm4 = [ "stm32-metapac/stm32h755zi-cm4", "_dual-core" ] -stm32h757ai-cm7 = [ "stm32-metapac/stm32h757ai-cm7", "_dual-core" ] -stm32h757ai-cm4 = [ "stm32-metapac/stm32h757ai-cm4", "_dual-core" ] -stm32h757bi-cm7 = [ "stm32-metapac/stm32h757bi-cm7", "_dual-core" ] -stm32h757bi-cm4 = [ "stm32-metapac/stm32h757bi-cm4", "_dual-core" ] -stm32h757ii-cm7 = [ "stm32-metapac/stm32h757ii-cm7", "_dual-core" ] -stm32h757ii-cm4 = [ "stm32-metapac/stm32h757ii-cm4", "_dual-core" ] -stm32h757xi-cm7 = [ "stm32-metapac/stm32h757xi-cm7", "_dual-core" ] -stm32h757xi-cm4 = [ "stm32-metapac/stm32h757xi-cm4", "_dual-core" ] -stm32h757zi-cm7 = [ "stm32-metapac/stm32h757zi-cm7", "_dual-core" ] -stm32h757zi-cm4 = [ "stm32-metapac/stm32h757zi-cm4", "_dual-core" ] +stm32h755bi-cm7 = [ "stm32-metapac/stm32h755bi-cm7", "_dual-core", "_core-cm7" ] +stm32h755bi-cm4 = [ "stm32-metapac/stm32h755bi-cm4", "_dual-core", "_core-cm4" ] +stm32h755ii-cm7 = [ "stm32-metapac/stm32h755ii-cm7", "_dual-core", "_core-cm7" ] +stm32h755ii-cm4 = [ "stm32-metapac/stm32h755ii-cm4", "_dual-core", "_core-cm4" ] +stm32h755xi-cm7 = [ "stm32-metapac/stm32h755xi-cm7", "_dual-core", "_core-cm7" ] +stm32h755xi-cm4 = [ "stm32-metapac/stm32h755xi-cm4", "_dual-core", "_core-cm4" ] +stm32h755zi-cm7 = [ "stm32-metapac/stm32h755zi-cm7", "_dual-core", "_core-cm7" ] +stm32h755zi-cm4 = [ "stm32-metapac/stm32h755zi-cm4", "_dual-core", "_core-cm4" ] +stm32h757ai-cm7 = [ "stm32-metapac/stm32h757ai-cm7", "_dual-core", "_core-cm7" ] +stm32h757ai-cm4 = [ "stm32-metapac/stm32h757ai-cm4", "_dual-core", "_core-cm4" ] +stm32h757bi-cm7 = [ "stm32-metapac/stm32h757bi-cm7", "_dual-core", "_core-cm7" ] +stm32h757bi-cm4 = [ "stm32-metapac/stm32h757bi-cm4", "_dual-core", "_core-cm4" ] +stm32h757ii-cm7 = [ "stm32-metapac/stm32h757ii-cm7", "_dual-core", "_core-cm7" ] +stm32h757ii-cm4 = [ "stm32-metapac/stm32h757ii-cm4", "_dual-core", "_core-cm4" ] +stm32h757xi-cm7 = [ "stm32-metapac/stm32h757xi-cm7", "_dual-core", "_core-cm7" ] +stm32h757xi-cm4 = [ "stm32-metapac/stm32h757xi-cm4", "_dual-core", "_core-cm4" ] +stm32h757zi-cm7 = [ "stm32-metapac/stm32h757zi-cm7", "_dual-core", "_core-cm7" ] +stm32h757zi-cm4 = [ "stm32-metapac/stm32h757zi-cm4", "_dual-core", "_core-cm4" ] stm32h7a3ag = [ "stm32-metapac/stm32h7a3ag" ] stm32h7a3ai = [ "stm32-metapac/stm32h7a3ai" ] stm32h7a3ig = [ "stm32-metapac/stm32h7a3ig" ] @@ -1620,14 +1623,14 @@ stm32wba55he = [ "stm32-metapac/stm32wba55he" ] stm32wba55hg = [ "stm32-metapac/stm32wba55hg" ] stm32wba55ue = [ "stm32-metapac/stm32wba55ue" ] stm32wba55ug = [ "stm32-metapac/stm32wba55ug" ] -stm32wl54cc-cm4 = [ "stm32-metapac/stm32wl54cc-cm4", "_dual-core" ] -stm32wl54cc-cm0p = [ "stm32-metapac/stm32wl54cc-cm0p", "_dual-core" ] -stm32wl54jc-cm4 = [ "stm32-metapac/stm32wl54jc-cm4", "_dual-core" ] -stm32wl54jc-cm0p = [ "stm32-metapac/stm32wl54jc-cm0p", "_dual-core" ] -stm32wl55cc-cm4 = [ "stm32-metapac/stm32wl55cc-cm4", "_dual-core" ] -stm32wl55cc-cm0p = [ "stm32-metapac/stm32wl55cc-cm0p", "_dual-core" ] -stm32wl55jc-cm4 = [ "stm32-metapac/stm32wl55jc-cm4", "_dual-core" ] -stm32wl55jc-cm0p = [ "stm32-metapac/stm32wl55jc-cm0p", "_dual-core" ] +stm32wl54cc-cm4 = [ "stm32-metapac/stm32wl54cc-cm4", "_dual-core", "_core-cm4" ] +stm32wl54cc-cm0p = [ "stm32-metapac/stm32wl54cc-cm0p", "_dual-core", "_core-cm0p" ] +stm32wl54jc-cm4 = [ "stm32-metapac/stm32wl54jc-cm4", "_dual-core", "_core-cm4" ] +stm32wl54jc-cm0p = [ "stm32-metapac/stm32wl54jc-cm0p", "_dual-core", "_core-cm0p" ] +stm32wl55cc-cm4 = [ "stm32-metapac/stm32wl55cc-cm4", "_dual-core", "_core-cm4" ] +stm32wl55cc-cm0p = [ "stm32-metapac/stm32wl55cc-cm0p", "_dual-core", "_core-cm0p" ] +stm32wl55jc-cm4 = [ "stm32-metapac/stm32wl55jc-cm4", "_dual-core", "_core-cm4" ] +stm32wl55jc-cm0p = [ "stm32-metapac/stm32wl55jc-cm0p", "_dual-core", "_core-cm0p" ] stm32wle4c8 = [ "stm32-metapac/stm32wle4c8" ] stm32wle4cb = [ "stm32-metapac/stm32wle4cb" ] stm32wle4cc = [ "stm32-metapac/stm32wle4cc" ] diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index e293cf965..43bbef7e4 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -9,8 +9,8 @@ use proc_macro2::{Ident, TokenStream}; use quote::{format_ident, quote}; use stm32_metapac::metadata::ir::BitOffset; use stm32_metapac::metadata::{ - MemoryRegionKind, PeripheralRccKernelClock, PeripheralRccRegister, PeripheralRegisters, StopMode, ALL_CHIPS, - ALL_PERIPHERAL_VERSIONS, METADATA, + MemoryRegion, MemoryRegionKind, PeripheralRccKernelClock, PeripheralRccRegister, PeripheralRegisters, StopMode, + ALL_CHIPS, ALL_PERIPHERAL_VERSIONS, METADATA, }; #[path = "./build_common.rs"] @@ -1678,6 +1678,59 @@ fn main() { pub(crate) const DMA_CHANNELS: &[crate::dma::ChannelInfo] = &[#dmas]; }); + // ======== + // Generate gpio_block() function + + let gpio_base = METADATA.peripherals.iter().find(|p| p.name == "GPIOA").unwrap().address as usize; + let gpio_stride = 0x400 as usize; + + for p in METADATA.peripherals { + if let Some(bi) = &p.registers { + if bi.kind == "gpio" { + assert_eq!(0, (p.address as usize - gpio_base) % gpio_stride); + } + } + } + + g.extend(quote!( + pub fn gpio_block(n: usize) -> crate::pac::gpio::Gpio {{ + unsafe {{ crate::pac::gpio::Gpio::from_ptr((#gpio_base + #gpio_stride*n) as _) }} + }} + )); + + // ======== + // Generate flash constants + + let flash_regions: Vec<&MemoryRegion> = METADATA + .memory + .iter() + .filter(|x| x.kind == MemoryRegionKind::Flash && x.name.starts_with("BANK_")) + .collect(); + let first_flash = flash_regions.first().unwrap(); + let total_flash_size = flash_regions + .iter() + .map(|x| x.size) + .reduce(|acc, item| acc + item) + .unwrap(); + let write_sizes: HashSet<_> = flash_regions + .iter() + .map(|r| r.settings.as_ref().unwrap().write_size) + .collect(); + assert_eq!(1, write_sizes.len()); + + let flash_base = first_flash.address as usize; + let total_flash_size = total_flash_size as usize; + let write_size = (*write_sizes.iter().next().unwrap()) as usize; + + g.extend(quote!( + pub const FLASH_BASE: usize = #flash_base; + pub const FLASH_SIZE: usize = #total_flash_size; + pub const WRITE_SIZE: usize = #write_size; + )); + + // ======== + // Generate macro-tables + for irq in METADATA.interrupts { let name = irq.name.to_ascii_uppercase(); interrupts_table.push(vec![name.clone()]); @@ -1772,6 +1825,11 @@ fn main() { } println!("cargo:rerun-if-changed=build.rs"); + + if cfg!(feature = "memory-x") { + gen_memory_x(out_dir); + println!("cargo:rustc-link-search={}", out_dir.display()); + } } enum GetOneError { @@ -1857,3 +1915,78 @@ fn rustfmt(path: impl AsRef) { } } } + +fn gen_memory_x(out_dir: &Path) { + let mut memory_x = String::new(); + + let flash = get_memory_range(MemoryRegionKind::Flash); + let ram = get_memory_range(MemoryRegionKind::Ram); + + write!(memory_x, "MEMORY\n{{\n").unwrap(); + writeln!( + memory_x, + " FLASH : ORIGIN = 0x{:08x}, LENGTH = {:>4}K /* {} */", + flash.0, + flash.1 / 1024, + flash.2 + ) + .unwrap(); + writeln!( + memory_x, + " RAM : ORIGIN = 0x{:08x}, LENGTH = {:>4}K /* {} */", + ram.0, + ram.1 / 1024, + ram.2 + ) + .unwrap(); + write!(memory_x, "}}").unwrap(); + + std::fs::write(out_dir.join("memory.x"), memory_x.as_bytes()).unwrap(); +} + +fn get_memory_range(kind: MemoryRegionKind) -> (u32, u32, String) { + let mut mems: Vec<_> = METADATA + .memory + .iter() + .filter(|m| m.kind == kind && m.size != 0) + .collect(); + mems.sort_by_key(|m| m.address); + + let mut start = u32::MAX; + let mut end = u32::MAX; + let mut names = Vec::new(); + let mut best: Option<(u32, u32, String)> = None; + for m in mems { + if !mem_filter(&METADATA.name, &m.name) { + continue; + } + + if m.address != end { + names = Vec::new(); + start = m.address; + end = m.address; + } + + end += m.size; + names.push(m.name.to_string()); + + if best.is_none() || end - start > best.as_ref().unwrap().1 { + best = Some((start, end - start, names.join(" + "))); + } + } + + best.unwrap() +} + +fn mem_filter(chip: &str, region: &str) -> bool { + // in STM32WB, SRAM2a/SRAM2b are reserved for the radio core. + if chip.starts_with("STM32WB") + && !chip.starts_with("STM32WBA") + && !chip.starts_with("STM32WB0") + && region.starts_with("SRAM2") + { + return false; + } + + true +} diff --git a/embassy-stm32/src/exti.rs b/embassy-stm32/src/exti.rs index 5cff74264..9604c5149 100644 --- a/embassy-stm32/src/exti.rs +++ b/embassy-stm32/src/exti.rs @@ -16,9 +16,14 @@ use crate::{interrupt, pac, peripherals, Peripheral}; const EXTI_COUNT: usize = 16; static EXTI_WAKERS: [AtomicWaker; EXTI_COUNT] = [const { AtomicWaker::new() }; EXTI_COUNT]; -#[cfg(exti_w)] +#[cfg(all(exti_w, feature = "_core-cm0p"))] fn cpu_regs() -> pac::exti::Cpu { - EXTI.cpu(crate::pac::CORE_INDEX) + EXTI.cpu(1) +} + +#[cfg(all(exti_w, not(feature = "_core-cm0p")))] +fn cpu_regs() -> pac::exti::Cpu { + EXTI.cpu(0) } #[cfg(not(exti_w))] diff --git a/embassy-stm32/src/flash/common.rs b/embassy-stm32/src/flash/common.rs index 8ec4bb2a1..0004a7488 100644 --- a/embassy-stm32/src/flash/common.rs +++ b/embassy-stm32/src/flash/common.rs @@ -3,12 +3,12 @@ use core::sync::atomic::{fence, Ordering}; use embassy_hal_internal::drop::OnDrop; use embassy_hal_internal::{into_ref, PeripheralRef}; -use stm32_metapac::FLASH_BASE; use super::{ family, Async, Blocking, Error, FlashBank, FlashLayout, FlashRegion, FlashSector, FLASH_SIZE, MAX_ERASE_SIZE, READ_SIZE, WRITE_SIZE, }; +use crate::_generated::FLASH_BASE; use crate::peripherals::FLASH; use crate::Peripheral; diff --git a/embassy-stm32/src/flash/f4.rs b/embassy-stm32/src/flash/f4.rs index 8ebeae95b..d818c77d0 100644 --- a/embassy-stm32/src/flash/f4.rs +++ b/embassy-stm32/src/flash/f4.rs @@ -3,9 +3,9 @@ use core::sync::atomic::{fence, AtomicBool, Ordering}; use embassy_sync::waitqueue::AtomicWaker; use pac::flash::regs::Sr; -use pac::FLASH_SIZE; use super::{FlashBank, FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; +use crate::_generated::FLASH_SIZE; use crate::flash::Error; use crate::pac; #[allow(missing_docs)] // TODO @@ -14,9 +14,9 @@ mod alt_regions { use core::marker::PhantomData; use embassy_hal_internal::PeripheralRef; - use stm32_metapac::FLASH_SIZE; use crate::_generated::flash_regions::{BANK1_REGION1, BANK1_REGION2, BANK1_REGION3}; + use crate::_generated::FLASH_SIZE; use crate::flash::{asynch, Async, Bank1Region1, Bank1Region2, Blocking, Error, Flash, FlashBank, FlashRegion}; use crate::peripherals::FLASH; diff --git a/embassy-stm32/src/flash/mod.rs b/embassy-stm32/src/flash/mod.rs index aef1f1482..b564de093 100644 --- a/embassy-stm32/src/flash/mod.rs +++ b/embassy-stm32/src/flash/mod.rs @@ -12,8 +12,7 @@ pub use asynch::InterruptHandler; pub use common::*; pub use crate::_generated::flash_regions::*; -pub use crate::_generated::MAX_ERASE_SIZE; -pub use crate::pac::{FLASH_BASE, FLASH_SIZE, WRITE_SIZE}; +pub use crate::_generated::{FLASH_BASE, FLASH_SIZE, MAX_ERASE_SIZE, WRITE_SIZE}; /// Get whether the default flash layout is being used. /// diff --git a/embassy-stm32/src/gpio.rs b/embassy-stm32/src/gpio.rs index 6967ecc7c..65e1bfb8c 100644 --- a/embassy-stm32/src/gpio.rs +++ b/embassy-stm32/src/gpio.rs @@ -7,7 +7,7 @@ use critical_section::CriticalSection; use embassy_hal_internal::{impl_peripheral, into_ref, PeripheralRef}; use crate::pac::gpio::{self, vals}; -use crate::{pac, peripherals, Peripheral}; +use crate::{peripherals, Peripheral}; /// GPIO flexible pin. /// @@ -726,7 +726,7 @@ pub(crate) trait SealedPin { #[inline] fn block(&self) -> gpio::Gpio { - pac::GPIO(self._port() as _) + crate::_generated::gpio_block(self._port() as _) } /// Set the output as high. @@ -835,7 +835,7 @@ impl AnyPin { #[cfg(feature = "unstable-pac")] #[inline] pub fn block(&self) -> gpio::Gpio { - pac::GPIO(self._port() as _) + crate::_generated::gpio_block(self._port() as _) } } From 38033a2e148cc5394965edf3e9215ed17c61cdf2 Mon Sep 17 00:00:00 2001 From: Jonas Spinner Date: Mon, 6 Jan 2025 19:28:07 +0100 Subject: [PATCH 0626/1217] fix typo in executor README.md --- embassy-executor/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-executor/README.md b/embassy-executor/README.md index aa9d59907..074c73555 100644 --- a/embassy-executor/README.md +++ b/embassy-executor/README.md @@ -17,7 +17,7 @@ When the `nightly` Cargo feature is not enabled, `embassy-executor` allocates ta If the task arena gets full, the program will panic at runtime. To guarantee this doesn't happen, you must set the size to the sum of sizes of all tasks. -Tasks are allocated from the arena when spawned for the first time. If the task exists, the allocation is not released to the arena, but can be reused to spawn the task again. For multiple-instance tasks (like `#[embassy_executor::task(pool_size = 4)]`), the first spawn will allocate memory for all instances. This is done for performance and to increase predictability (for example, spawning at least 1 instance of every task at boot guarantees an immediate panic if the arena is too small, while allocating instances on-demand could delay the panic to only when the program is under load). +Tasks are allocated from the arena when spawned for the first time. If the task exits, the allocation is not released to the arena, but can be reused to spawn the task again. For multiple-instance tasks (like `#[embassy_executor::task(pool_size = 4)]`), the first spawn will allocate memory for all instances. This is done for performance and to increase predictability (for example, spawning at least 1 instance of every task at boot guarantees an immediate panic if the arena is too small, while allocating instances on-demand could delay the panic to only when the program is under load). The arena size can be configured in two ways: From 7ac2a4f674030bf82f7892b25a43a5efc01d9e62 Mon Sep 17 00:00:00 2001 From: Tamme Dittrich Date: Tue, 7 Jan 2025 09:25:25 +0100 Subject: [PATCH 0627/1217] Allow split CAN Rx to modify the filters --- embassy-stm32/src/can/bxcan/mod.rs | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/embassy-stm32/src/can/bxcan/mod.rs b/embassy-stm32/src/can/bxcan/mod.rs index 19f1cea29..8165364f5 100644 --- a/embassy-stm32/src/can/bxcan/mod.rs +++ b/embassy-stm32/src/can/bxcan/mod.rs @@ -502,6 +502,14 @@ impl<'d, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCan<'d, TX_ pub fn reader(&self) -> BufferedCanReceiver { self.rx.reader() } + + /// Accesses the filter banks owned by this CAN peripheral. + /// + /// To modify filters of a slave peripheral, `modify_filters` has to be called on the master + /// peripheral instead. + pub fn modify_filters(&mut self) -> MasterFilters<'_> { + self.rx.modify_filters() + } } /// CAN driver, transmit half. @@ -733,6 +741,14 @@ impl<'d> CanRx<'d> { ) -> BufferedCanRx<'d, RX_BUF_SIZE> { BufferedCanRx::new(self.info, self.state, self, rxb) } + + /// Accesses the filter banks owned by this CAN peripheral. + /// + /// To modify filters of a slave peripheral, `modify_filters` has to be called on the master + /// peripheral instead. + pub fn modify_filters(&mut self) -> MasterFilters<'_> { + unsafe { MasterFilters::new(self.info) } + } } /// User supplied buffer for RX Buffering @@ -742,16 +758,16 @@ pub type RxBuf = Channel { info: &'static Info, state: &'static State, - _rx: CanRx<'d>, + rx: CanRx<'d>, rx_buf: &'static RxBuf, } impl<'d, const RX_BUF_SIZE: usize> BufferedCanRx<'d, RX_BUF_SIZE> { - fn new(info: &'static Info, state: &'static State, _rx: CanRx<'d>, rx_buf: &'static RxBuf) -> Self { + fn new(info: &'static Info, state: &'static State, rx: CanRx<'d>, rx_buf: &'static RxBuf) -> Self { BufferedCanRx { info, state, - _rx, + rx, rx_buf, } .setup() @@ -811,6 +827,14 @@ impl<'d, const RX_BUF_SIZE: usize> BufferedCanRx<'d, RX_BUF_SIZE> { pub fn reader(&self) -> BufferedCanReceiver { self.rx_buf.receiver().into() } + + /// Accesses the filter banks owned by this CAN peripheral. + /// + /// To modify filters of a slave peripheral, `modify_filters` has to be called on the master + /// peripheral instead. + pub fn modify_filters(&mut self) -> MasterFilters<'_> { + self.rx.modify_filters() + } } impl<'d, const RX_BUF_SIZE: usize> Drop for BufferedCanRx<'d, RX_BUF_SIZE> { From e7c70f1097e6a7f69d09819e22901ac6f15a4a21 Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Tue, 7 Jan 2025 12:59:26 +0200 Subject: [PATCH 0628/1217] nrf: Refactor changelog a bit A bit late with my changes, but here they come. --- embassy-nrf/CHANGELOG.md | 49 +++++++++++++++++++++++++++++----------- 1 file changed, 36 insertions(+), 13 deletions(-) diff --git a/embassy-nrf/CHANGELOG.md b/embassy-nrf/CHANGELOG.md index 4d68950a7..e9eb1443a 100644 --- a/embassy-nrf/CHANGELOG.md +++ b/embassy-nrf/CHANGELOG.md @@ -9,19 +9,42 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## 0.3.0 - 2025-01-06 -- Updated `embassy-time` to v0.4 -- Add basic nrf54 support -- Switch to use `nrf-pac` chiptool-based PAC -- Fix bug where timer alarm was not scheduled if interrupted -- Add RESET operations helpers for nrf5340 -- Allow debug access from firmware for nrf54l -- Add trait `embedded_io_async` to uarte -- Add system off and wake-on-field for nrf -- Use inline const for initializing arrays -- Add NFCT driver and related changes for nrf -- Add support for transactions to Twim (embassy-nrf) -- Fix build issues related to nrf9120 features -- Disconnect input and fix bad pin assignment in nrf/pwm +Firstly, this release switches embassy-nrf to chiptool-based `nrf-pac` +implementations and lots of improvements, but also changes to API like +peripheral and interrupt naming. + +Second big change is a refactoring of time driver contract with +embassy-time-driver. From now on, the timer queue is handled by the +time-driver implementation and `generic-queue` feature is provided by +the `embassy-time-queue-utils` crate. Newly required dependencies are +following: + - embassy-time-0.4 + - embassy-time-driver-0.2 + - embassy-time-queue-utils-0.1 + +Add support for following NRF chips: + - nRF54L15 (only gpio and timer support) + +Support for chip-specific features: + - RESET operations for nrf5340 + - POWER operations (system-off and wake-on-field) for nrf52840 and nrf9160 + +- nfc: + - Adds support for NFC Tag emulator driver +- pwm: + - Fix incorrect pin assignments + - Properly disconnect inputs when pins are set as output +- uart: + - `try_write` support for `BufferedUarte` + - Support for `embedded_io_async` trait +- spim: + - Support SPIM4 peripheral on nrf5340-app +- time: + - Generic refactor of embassy-time-driver API + - Fix for missed executor alarms in certain occasions (issue #3672, PR #3705). +- twim: + - Implement support for transactions + - Remove support for consecutive Read operations due to hardware limitations ## 0.2.0 - 2024-08-05 From a3c1b18b0279065470939b823d11dc777b257dc1 Mon Sep 17 00:00:00 2001 From: Ivan Li Date: Tue, 7 Jan 2025 21:28:55 +0800 Subject: [PATCH 0629/1217] feat: calibrating Differential ADC for G4 Signed-off-by: Ivan Li --- embassy-stm32/src/adc/g4.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/embassy-stm32/src/adc/g4.rs b/embassy-stm32/src/adc/g4.rs index 555a91d17..0291ef4de 100644 --- a/embassy-stm32/src/adc/g4.rs +++ b/embassy-stm32/src/adc/g4.rs @@ -191,6 +191,14 @@ impl<'d, T: Instance> Adc<'d, T> { T::regs().cr().modify(|w| w.set_adcal(true)); while T::regs().cr().read().adcal() {} + + T::regs().cr().modify(|w| { + w.set_adcaldif(Adcaldif::DIFFERENTIAL); + }); + + T::regs().cr().modify(|w| w.set_adcal(true)); + + while T::regs().cr().read().adcal() {} } fn enable(&mut self) { From d92ed4b00c09ea1d03faea00777008b2da0cfee0 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 7 Jan 2025 19:57:31 +0100 Subject: [PATCH 0630/1217] Remove useless patches in examples. --- examples/rp/Cargo.toml | 8 -------- examples/rp23/Cargo.toml | 8 -------- 2 files changed, 16 deletions(-) diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index 73ca4b5a5..f80ccbc0b 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml @@ -69,11 +69,3 @@ opt-level = 'z' debug = 2 lto = true opt-level = "z" - -[patch.crates-io] -embassy-executor = { path = "../../embassy-executor" } -embassy-sync = { path = "../../embassy-sync" } -embassy-futures = { path = "../../embassy-futures" } -embassy-time = { path = "../../embassy-time" } -embassy-time-driver = { path = "../../embassy-time-driver" } -embassy-embedded-hal = { path = "../../embassy-embedded-hal" } diff --git a/examples/rp23/Cargo.toml b/examples/rp23/Cargo.toml index 68ceee933..7c94166bd 100644 --- a/examples/rp23/Cargo.toml +++ b/examples/rp23/Cargo.toml @@ -66,11 +66,3 @@ debug = 2 [profile.dev] lto = true opt-level = "z" - -[patch.crates-io] -embassy-executor = { path = "../../embassy-executor" } -embassy-sync = { path = "../../embassy-sync" } -embassy-futures = { path = "../../embassy-futures" } -embassy-time = { path = "../../embassy-time" } -embassy-time-driver = { path = "../../embassy-time-driver" } -embassy-embedded-hal = { path = "../../embassy-embedded-hal" } From 103bb0dfaad02f8391872bfdbc6a7a26591aca11 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 7 Jan 2025 20:44:11 +0100 Subject: [PATCH 0631/1217] stm32: generate singletons only for pins that actually exist. Before we'd generate all pins Px0..Px15 for each GPIOx port. This changes codegen to only generate singletons for actually-existing pins. (AFs were already previously filtered, so these non-existing pins were already mostly useless) --- embassy-stm32/Cargo.toml | 4 +- embassy-stm32/build.rs | 85 +++++++++++++++--------------- examples/stm32u0/src/bin/spi.rs | 2 +- examples/stm32u5/src/bin/blinky.rs | 3 +- 4 files changed, 48 insertions(+), 46 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index d66d3bc1d..cf336e4d0 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -73,7 +73,7 @@ rand_core = "0.6.3" sdio-host = "0.5.0" critical-section = "1.1" #stm32-metapac = { version = "15" } -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-fad4bc0f2baac29ecebb5153d2997b649b71025f" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-db71f6aa03b7db26548b461d3844fc404d40c98c" } vcell = "0.1.3" nb = "1.0.0" @@ -102,7 +102,7 @@ proc-macro2 = "1.0.36" quote = "1.0.15" #stm32-metapac = { version = "15", default-features = false, features = ["metadata"]} -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-fad4bc0f2baac29ecebb5153d2997b649b71025f", default-features = false, features = ["metadata"] } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-db71f6aa03b7db26548b461d3844fc404d40c98c", default-features = false, features = ["metadata"] } [features] default = ["rt"] diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 43bbef7e4..09f940d29 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -53,6 +53,13 @@ fn main() { // Generate singletons let mut singletons: Vec = Vec::new(); + + // Generate one singleton per pin + for p in METADATA.pins { + singletons.push(p.name.to_string()); + } + + // generate one singleton per peripheral (with many exceptions...) for p in METADATA.peripherals { if let Some(r) = &p.registers { if r.kind == "adccommon" || r.kind == "sai" || r.kind == "ucpd" || r.kind == "otg" || r.kind == "octospi" { @@ -63,13 +70,8 @@ fn main() { } match r.kind { - // Generate singletons per pin, not per port - "gpio" => { - let port_letter = p.name.strip_prefix("GPIO").unwrap(); - for pin_num in 0..16 { - singletons.push(format!("P{}{}", port_letter, pin_num)); - } - } + // handled above + "gpio" => {} // No singleton for these, the HAL handles them specially. "exti" => {} @@ -1478,43 +1480,42 @@ fn main() { let gpio_base = METADATA.peripherals.iter().find(|p| p.name == "GPIOA").unwrap().address as u32; let gpio_stride = 0x400; + for pin in METADATA.pins { + let port_letter = pin.name.chars().nth(1).unwrap(); + let pname = format!("GPIO{}", port_letter); + let p = METADATA.peripherals.iter().find(|p| p.name == pname).unwrap(); + assert_eq!(0, (p.address as u32 - gpio_base) % gpio_stride); + let port_num = (p.address as u32 - gpio_base) / gpio_stride; + let pin_num: u32 = pin.name[2..].parse().unwrap(); + + pins_table.push(vec![ + pin.name.to_string(), + p.name.to_string(), + port_num.to_string(), + pin_num.to_string(), + format!("EXTI{}", pin_num), + ]); + + // If we have the split pins, we need to do a little extra work: + // Add the "_C" variant to the table. The solution is not optimal, though. + // Adding them only when the corresponding GPIOx also appears. + // This should avoid unintended side-effects as much as possible. + #[cfg(feature = "_split-pins-enabled")] + for split_feature in &split_features { + if split_feature.pin_name_without_c == pin_name { + pins_table.push(vec![ + split_feature.pin_name_with_c.to_string(), + p.name.to_string(), + port_num.to_string(), + pin_num.to_string(), + format!("EXTI{}", pin_num), + ]); + } + } + } + for p in METADATA.peripherals { if let Some(regs) = &p.registers { - if regs.kind == "gpio" { - let port_letter = p.name.chars().nth(4).unwrap(); - assert_eq!(0, (p.address as u32 - gpio_base) % gpio_stride); - let port_num = (p.address as u32 - gpio_base) / gpio_stride; - - for pin_num in 0u32..16 { - let pin_name = format!("P{}{}", port_letter, pin_num); - - pins_table.push(vec![ - pin_name.clone(), - p.name.to_string(), - port_num.to_string(), - pin_num.to_string(), - format!("EXTI{}", pin_num), - ]); - - // If we have the split pins, we need to do a little extra work: - // Add the "_C" variant to the table. The solution is not optimal, though. - // Adding them only when the corresponding GPIOx also appears. - // This should avoid unintended side-effects as much as possible. - #[cfg(feature = "_split-pins-enabled")] - for split_feature in &split_features { - if split_feature.pin_name_without_c == pin_name { - pins_table.push(vec![ - split_feature.pin_name_with_c.to_string(), - p.name.to_string(), - port_num.to_string(), - pin_num.to_string(), - format!("EXTI{}", pin_num), - ]); - } - } - } - } - if regs.kind == "adc" { let adc_num = p.name.strip_prefix("ADC").unwrap(); let mut adc_common = None; diff --git a/examples/stm32u0/src/bin/spi.rs b/examples/stm32u0/src/bin/spi.rs index 5693a3765..e03591daf 100644 --- a/examples/stm32u0/src/bin/spi.rs +++ b/examples/stm32u0/src/bin/spi.rs @@ -18,7 +18,7 @@ fn main() -> ! { let mut spi = Spi::new_blocking(p.SPI3, p.PC10, p.PC12, p.PC11, spi_config); - let mut cs = Output::new(p.PE0, Level::High, Speed::VeryHigh); + let mut cs = Output::new(p.PC13, Level::High, Speed::VeryHigh); loop { let mut buf = [0x0Au8; 4]; diff --git a/examples/stm32u5/src/bin/blinky.rs b/examples/stm32u5/src/bin/blinky.rs index 7fe88c183..1fdfc7679 100644 --- a/examples/stm32u5/src/bin/blinky.rs +++ b/examples/stm32u5/src/bin/blinky.rs @@ -12,7 +12,8 @@ async fn main(_spawner: Spawner) -> ! { let p = embassy_stm32::init(Default::default()); info!("Hello World!"); - let mut led = Output::new(p.PH7, Level::Low, Speed::Medium); + // replace PC13 with the right pin for your board. + let mut led = Output::new(p.PC13, Level::Low, Speed::Medium); loop { defmt::info!("on!"); From 09cc9c65c9c24e4dee8f66ccaca8463152d8277f Mon Sep 17 00:00:00 2001 From: Liu Hancheng Date: Sun, 5 Jan 2025 21:49:42 +0800 Subject: [PATCH 0632/1217] feat: mmap mode for qspi and example --- ci.sh | 1 + embassy-stm32/src/qspi/mod.rs | 20 ++ examples/stm32l432/.cargo/config.toml | 13 ++ examples/stm32l432/Cargo.toml | 30 +++ examples/stm32l432/README.md | 30 +++ examples/stm32l432/build.rs | 5 + examples/stm32l432/src/bin/qspi_mmap.rs | 274 ++++++++++++++++++++++++ 7 files changed, 373 insertions(+) create mode 100644 examples/stm32l432/.cargo/config.toml create mode 100644 examples/stm32l432/Cargo.toml create mode 100644 examples/stm32l432/README.md create mode 100644 examples/stm32l432/build.rs create mode 100644 examples/stm32l432/src/bin/qspi_mmap.rs diff --git a/ci.sh b/ci.sh index 32bddf62a..1aa206c1d 100755 --- a/ci.sh +++ b/ci.sh @@ -231,6 +231,7 @@ cargo batch \ --- build --release --manifest-path examples/stm32l0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/stm32l0 \ --- build --release --manifest-path examples/stm32l1/Cargo.toml --target thumbv7m-none-eabi --out-dir out/examples/stm32l1 \ --- build --release --manifest-path examples/stm32l4/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32l4 \ + --- build --release --manifest-path examples/stm32l432/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32l432 \ --- build --release --manifest-path examples/stm32l5/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/stm32l5 \ --- build --release --manifest-path examples/stm32u0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/stm32u0 \ --- build --release --manifest-path examples/stm32u5/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/stm32u5 \ diff --git a/embassy-stm32/src/qspi/mod.rs b/embassy-stm32/src/qspi/mod.rs index 0c65d0556..bf08189f8 100644 --- a/embassy-stm32/src/qspi/mod.rs +++ b/embassy-stm32/src/qspi/mod.rs @@ -201,6 +201,26 @@ impl<'d, T: Instance, M: PeriMode> Qspi<'d, T, M> { T::REGS.fcr().modify(|v| v.set_ctcf(true)); } + /// Enable memory map mode + pub fn enable_memory_map(&mut self, transaction: &TransferConfig) { + T::REGS.fcr().modify(|v| { + v.set_csmf(true); + v.set_ctcf(true); + v.set_ctef(true); + v.set_ctof(true); + }); + T::REGS.ccr().write(|v| { + v.set_fmode(QspiMode::MemoryMapped.into()); + v.set_imode(transaction.iwidth.into()); + v.set_instruction(transaction.instruction); + v.set_admode(transaction.awidth.into()); + v.set_adsize(self.config.address_size.into()); + v.set_dmode(transaction.dwidth.into()); + v.set_abmode(QspiWidth::NONE.into()); + v.set_dcyc(transaction.dummy.into()); + }); + } + fn setup_transaction(&mut self, fmode: QspiMode, transaction: &TransferConfig, data_len: Option) { match (transaction.address, transaction.awidth) { (Some(_), QspiWidth::NONE) => panic!("QSPI address can't be sent with an address width of NONE"), diff --git a/examples/stm32l432/.cargo/config.toml b/examples/stm32l432/.cargo/config.toml new file mode 100644 index 000000000..0a42c584b --- /dev/null +++ b/examples/stm32l432/.cargo/config.toml @@ -0,0 +1,13 @@ +[target.'cfg(all(target_arch = "arm", target_os = "none"))'] +# replace STM32F429ZITx with your chip as listed in `probe-rs chip list` +#runner = "probe-rs run --chip STM32L475VGT6" +#runner = "probe-rs run --chip STM32L475VG" +#runner = "probe-rs run --chip STM32L4S5QI" +runner = "probe-rs run --chip STM32L432KCUx --connect-under-reset --speed 3300" + + +[build] +target = "thumbv7em-none-eabi" + +[env] +DEFMT_LOG = "trace" diff --git a/examples/stm32l432/Cargo.toml b/examples/stm32l432/Cargo.toml new file mode 100644 index 000000000..460561b36 --- /dev/null +++ b/examples/stm32l432/Cargo.toml @@ -0,0 +1,30 @@ +[package] +edition = "2021" +name = "embassy-stm32l4-examples" +version = "0.1.1" +license = "MIT OR Apache-2.0" + +[dependencies] +# Change stm32l4s5vi to your chip name, if necessary. +embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32l432kc", "memory-x", "time-driver-any", "exti", "chrono"] } +embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = [ "defmt" ] } +embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = [ "task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt" ] } +embassy-time = { version = "0.4.0", path = "../../embassy-time", features = [ "defmt", "defmt-timestamp-uptime", "tick-hz-32_768" ] } +defmt = "0.3" +defmt-rtt = "0.4" + +cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } +cortex-m-rt = "0.7.0" +embedded-hal = "0.2.6" +embedded-hal-1 = { package = "embedded-hal", version = "1.0" } +embedded-hal-async = { version = "1.0" } +embedded-hal-bus = { version = "0.1", features = ["async"] } +panic-probe = { version = "0.3", features = ["print-defmt"] } + +[profile.release] +debug = 2 + +[[bin]] +name = "qspi_mmap" +path = "src/bin/qspi_mmap.rs" +test = false diff --git a/examples/stm32l432/README.md b/examples/stm32l432/README.md new file mode 100644 index 000000000..3dac97f03 --- /dev/null +++ b/examples/stm32l432/README.md @@ -0,0 +1,30 @@ + +# Examples for STM32L432 family + +Examples in this repo should work with [NUCLEO-L432KC](https://www.st.com/en/evaluation-tools/nucleo-l432kc.html) board. + +Run individual examples with +``` +cargo run --bin +``` +for example +``` +cargo run --bin blinky +``` + + + +## Checklist before running examples +You might need to adjust `.cargo/config.toml`, `Cargo.toml` and possibly update pin numbers or peripherals to match the specific MCU or board you are using. + +* [ ] Update .cargo/config.toml with the correct probe-rs command to use your specific MCU. For example for L432KCU6 it should be `probe-rs run --chip STM32L432KCUx`. (use `probe-rs chip list` to find your chip) +* [ ] Update Cargo.toml to have the correct `embassy-stm32` feature. For example for L432KCU6 it should be `stm32l432kc`. Look in the `Cargo.toml` file of the `embassy-stm32` project to find the correct feature flag for your chip. +* [ ] If your board has a special clock or power configuration, make sure that it is set up appropriately. +* [ ] If your board has different pin mapping, update any pin numbers or peripherals in the given example code to match your schematic + +If you are unsure, please drop by the Embassy Matrix chat for support, and let us know: + +* Which example you are trying to run +* Which chip and board you are using + +Embassy Chat: https://matrix.to/#/#embassy-rs:matrix.org diff --git a/examples/stm32l432/build.rs b/examples/stm32l432/build.rs new file mode 100644 index 000000000..8cd32d7ed --- /dev/null +++ b/examples/stm32l432/build.rs @@ -0,0 +1,5 @@ +fn main() { + println!("cargo:rustc-link-arg-bins=--nmagic"); + println!("cargo:rustc-link-arg-bins=-Tlink.x"); + println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); +} diff --git a/examples/stm32l432/src/bin/qspi_mmap.rs b/examples/stm32l432/src/bin/qspi_mmap.rs new file mode 100644 index 000000000..86a20eb3d --- /dev/null +++ b/examples/stm32l432/src/bin/qspi_mmap.rs @@ -0,0 +1,274 @@ +#![no_std] +#![no_main] +#![allow(dead_code)] +/// This example demonstrates how to use the QSPI peripheral in both indirect-mode and memory-mapped mode. +/// If you want to test this example, please pay attention to flash pins and check flash device datasheet +/// to make sure operations in this example are compatible with your device, especially registers I/O operations. +use defmt::info; +use embassy_stm32::mode; +use embassy_stm32::qspi::enums::{ + AddressSize, ChipSelectHighTime, DummyCycles, FIFOThresholdLevel, MemorySize, QspiWidth, +}; +use embassy_stm32::qspi::{self, Instance, TransferConfig}; +pub struct FlashMemory { + qspi: qspi::Qspi<'static, I, mode::Async>, +} +use embassy_executor::Spawner; +use embassy_time::Timer; +use {defmt_rtt as _, panic_probe as _}; + +const MEMORY_PAGE_SIZE: usize = 256; +const CMD_READ_SR: u8 = 0x05; +const CMD_READ_CR: u8 = 0x35; +const CMD_QUAD_READ: u8 = 0x6B; +const CMD_QUAD_WRITE_PG: u8 = 0x32; +const CMD_READ_ID: u8 = 0x9F; +const CMD_READ_MID: u8 = 0x90; +const CMD_READ_UUID: u8 = 0x4B; +const CMD_ENABLE_RESET: u8 = 0x66; +const CMD_RESET: u8 = 0x99; +const CMD_WRITE_ENABLE: u8 = 0x06; +const CMD_SECTOR_ERASE: u8 = 0x20; + +const CMD_WRITE_SR: u8 = 0x01; + +impl FlashMemory { + pub fn new(qspi: qspi::Qspi<'static, I, mode::Async>) -> Self { + let mut memory = Self { qspi }; + + memory.reset_memory(); + memory.enable_quad(); + + memory + } + fn enable_quad(&mut self) { + let sr = self.read_sr_lsb(); + let cr = self.read_sr_msb(); + + self.write_sr(sr, cr | 0x02); + } + fn read_register(&mut self, cmd: u8) -> u8 { + let mut buffer = [0; 1]; + let transaction = TransferConfig { + iwidth: QspiWidth::SING, + awidth: QspiWidth::NONE, + dwidth: QspiWidth::SING, + instruction: cmd, + address: None, + dummy: DummyCycles::_0, + }; + self.qspi.blocking_read(&mut buffer, transaction); + buffer[0] + } + + fn write_register(&mut self, cmd: u8, value: u8) { + let buffer = [value; 1]; + let transaction: TransferConfig = TransferConfig { + iwidth: QspiWidth::SING, + awidth: QspiWidth::NONE, + dwidth: QspiWidth::SING, + instruction: cmd, + address: None, + dummy: DummyCycles::_0, + }; + self.qspi.blocking_write(&buffer, transaction); + } + pub fn write_sr(&mut self, lsb: u8, msb: u8) { + let buffer = [lsb, msb]; + let transaction: TransferConfig = TransferConfig { + iwidth: QspiWidth::SING, + awidth: QspiWidth::NONE, + dwidth: QspiWidth::SING, + instruction: CMD_WRITE_SR, + address: None, + dummy: DummyCycles::_0, + }; + self.qspi.blocking_write(&buffer, transaction); + } + + pub fn read_sr_lsb(&mut self) -> u8 { + self.read_register(CMD_READ_SR) + } + pub fn read_sr_msb(&mut self) -> u8 { + self.read_register(CMD_READ_CR) + } + + pub fn reset_memory(&mut self) { + self.exec_command(CMD_ENABLE_RESET); + self.exec_command(CMD_RESET); + self.wait_write_finish(); + } + fn exec_command(&mut self, cmd: u8) { + let transaction = TransferConfig { + iwidth: QspiWidth::SING, + awidth: QspiWidth::NONE, + dwidth: QspiWidth::NONE, + instruction: cmd, + address: None, + dummy: DummyCycles::_0, + }; + self.qspi.blocking_command(transaction); + } + fn wait_write_finish(&mut self) { + while (self.read_sr_lsb() & 0x01) != 0 {} + } + + pub fn read_mid(&mut self) -> [u8; 2] { + let mut buffer = [0; 2]; + let transaction: TransferConfig = TransferConfig { + iwidth: QspiWidth::SING, + awidth: QspiWidth::SING, + dwidth: QspiWidth::SING, + instruction: CMD_READ_MID, + address: Some(0), + dummy: DummyCycles::_0, + }; + self.qspi.blocking_read(&mut buffer, transaction); + buffer + } + pub fn read_uuid(&mut self) -> [u8; 16] { + let mut buffer = [0; 16]; + let transaction: TransferConfig = TransferConfig { + iwidth: QspiWidth::SING, + awidth: QspiWidth::SING, + dwidth: QspiWidth::SING, + instruction: CMD_READ_UUID, + address: Some(0), + dummy: DummyCycles::_8, + }; + self.qspi.blocking_read(&mut buffer, transaction); + buffer + } + pub fn read_id(&mut self) -> [u8; 3] { + let mut buffer = [0; 3]; + let transaction: TransferConfig = TransferConfig { + iwidth: QspiWidth::SING, + awidth: QspiWidth::NONE, + dwidth: QspiWidth::SING, + instruction: CMD_READ_ID, + address: None, + dummy: DummyCycles::_0, + }; + self.qspi.blocking_read(&mut buffer, transaction); + buffer + } + + pub fn enable_mmap(&mut self) { + let transaction: TransferConfig = TransferConfig { + iwidth: QspiWidth::SING, + awidth: QspiWidth::SING, + dwidth: QspiWidth::QUAD, + instruction: CMD_QUAD_READ, + address: Some(0), + dummy: DummyCycles::_8, + }; + self.qspi.enable_memory_map(&transaction); + } + fn perform_erase(&mut self, addr: u32, cmd: u8) { + let transaction = TransferConfig { + iwidth: QspiWidth::SING, + awidth: QspiWidth::SING, + dwidth: QspiWidth::NONE, + instruction: cmd, + address: Some(addr), + dummy: DummyCycles::_0, + }; + self.enable_write(); + self.qspi.blocking_command(transaction); + self.wait_write_finish(); + } + pub fn enable_write(&mut self) { + self.exec_command(CMD_WRITE_ENABLE); + } + pub fn erase_sector(&mut self, addr: u32) { + self.perform_erase(addr, CMD_SECTOR_ERASE); + } + fn write_page(&mut self, addr: u32, buffer: &[u8], len: usize, use_dma: bool) { + assert!( + (len as u32 + (addr & 0x000000ff)) <= MEMORY_PAGE_SIZE as u32, + "write_page(): page write length exceeds page boundary (len = {}, addr = {:X}", + len, + addr + ); + + let transaction = TransferConfig { + iwidth: QspiWidth::SING, + awidth: QspiWidth::SING, + dwidth: QspiWidth::QUAD, + instruction: CMD_QUAD_WRITE_PG, + address: Some(addr), + dummy: DummyCycles::_0, + }; + self.enable_write(); + if use_dma { + self.qspi.blocking_write_dma(buffer, transaction); + } else { + self.qspi.blocking_write(buffer, transaction); + } + self.wait_write_finish(); + } + pub fn write_memory(&mut self, addr: u32, buffer: &[u8], use_dma: bool) { + let mut left = buffer.len(); + let mut place = addr; + let mut chunk_start = 0; + + while left > 0 { + let max_chunk_size = MEMORY_PAGE_SIZE - (place & 0x000000ff) as usize; + let chunk_size = if left >= max_chunk_size { max_chunk_size } else { left }; + let chunk = &buffer[chunk_start..(chunk_start + chunk_size)]; + self.write_page(place, chunk, chunk_size, use_dma); + place += chunk_size as u32; + left -= chunk_size; + chunk_start += chunk_size; + } + } + + pub fn read_memory(&mut self, addr: u32, buffer: &mut [u8], use_dma: bool) { + let transaction = TransferConfig { + iwidth: QspiWidth::SING, + awidth: QspiWidth::SING, + dwidth: QspiWidth::QUAD, + instruction: CMD_QUAD_READ, + address: Some(addr), + dummy: DummyCycles::_8, + }; + if use_dma { + self.qspi.blocking_read_dma(buffer, transaction); + } else { + self.qspi.blocking_read(buffer, transaction); + } + } +} + +const MEMORY_ADDR: u32 = 0x00000000 as u32; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_stm32::init(Default::default()); + + let config = qspi::Config { + memory_size: MemorySize::_16MiB, + address_size: AddressSize::_24bit, + prescaler: 200, + cs_high_time: ChipSelectHighTime::_1Cycle, + fifo_threshold: FIFOThresholdLevel::_16Bytes, + }; + let driver = qspi::Qspi::new_bank1(p.QUADSPI, p.PB1, p.PB0, p.PA7, p.PA6, p.PA3, p.PA2, p.DMA2_CH7, config); + let mut flash = FlashMemory::new(driver); + let mut wr_buf = [0u8; 256]; + for i in 0..32 { + wr_buf[i] = i as u8; + } + let mut rd_buf = [0u8; 32]; + flash.erase_sector(MEMORY_ADDR); + flash.write_memory(MEMORY_ADDR, &wr_buf, false); + flash.read_memory(MEMORY_ADDR, &mut rd_buf, false); + + info!("data read from indirect mode: {}", rd_buf); + flash.enable_mmap(); + let qspi_base = unsafe { core::slice::from_raw_parts(0x9000_0000 as *const u8, 32) }; + info!("data read from mmap: {}", qspi_base); + loop { + Timer::after_millis(1000).await; + } +} From 19efea195d44e44468f039131ec2c9c77e7048ed Mon Sep 17 00:00:00 2001 From: William Spinelli <174336620+williams-one@users.noreply.github.com> Date: Thu, 19 Dec 2024 12:15:40 +0100 Subject: [PATCH 0633/1217] stm32u5: Add support for HSPI peripheral --- embassy-stm32/build.rs | 22 + embassy-stm32/src/hspi/enums.rs | 411 +++++++++++++ embassy-stm32/src/hspi/mod.rs | 1008 +++++++++++++++++++++++++++++++ embassy-stm32/src/lib.rs | 2 + 4 files changed, 1443 insertions(+) create mode 100644 embassy-stm32/src/hspi/enums.rs create mode 100644 embassy-stm32/src/hspi/mod.rs diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 09f940d29..704fa9e41 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -1081,6 +1081,27 @@ fn main() { (("octospim", "P2_NCS"), quote!(crate::ospi::NSSPin)), (("octospim", "P2_CLK"), quote!(crate::ospi::SckPin)), (("octospim", "P2_NCLK"), quote!(crate::ospi::NckPin)), + (("hspi", "IO0"), quote!(crate::hspi::D0Pin)), + (("hspi", "IO1"), quote!(crate::hspi::D1Pin)), + (("hspi", "IO2"), quote!(crate::hspi::D2Pin)), + (("hspi", "IO3"), quote!(crate::hspi::D3Pin)), + (("hspi", "IO4"), quote!(crate::hspi::D4Pin)), + (("hspi", "IO5"), quote!(crate::hspi::D5Pin)), + (("hspi", "IO6"), quote!(crate::hspi::D6Pin)), + (("hspi", "IO7"), quote!(crate::hspi::D7Pin)), + (("hspi", "IO8"), quote!(crate::hspi::D8Pin)), + (("hspi", "IO9"), quote!(crate::hspi::D9Pin)), + (("hspi", "IO10"), quote!(crate::hspi::D10Pin)), + (("hspi", "IO11"), quote!(crate::hspi::D11Pin)), + (("hspi", "IO12"), quote!(crate::hspi::D12Pin)), + (("hspi", "IO13"), quote!(crate::hspi::D13Pin)), + (("hspi", "IO14"), quote!(crate::hspi::D14Pin)), + (("hspi", "IO15"), quote!(crate::hspi::D15Pin)), + (("hspi", "DQS0"), quote!(crate::hspi::DQS0Pin)), + (("hspi", "DQS1"), quote!(crate::hspi::DQS1Pin)), + (("hspi", "NCS"), quote!(crate::hspi::NSSPin)), + (("hspi", "CLK"), quote!(crate::hspi::SckPin)), + (("hspi", "NCLK"), quote!(crate::hspi::NckPin)), (("tsc", "G1_IO1"), quote!(crate::tsc::G1IO1Pin)), (("tsc", "G1_IO2"), quote!(crate::tsc::G1IO2Pin)), (("tsc", "G1_IO3"), quote!(crate::tsc::G1IO3Pin)), @@ -1265,6 +1286,7 @@ fn main() { (("sdmmc", "RX"), quote!(crate::sdmmc::SdmmcDma)), (("quadspi", "QUADSPI"), quote!(crate::qspi::QuadDma)), (("octospi", "OCTOSPI1"), quote!(crate::ospi::OctoDma)), + (("hspi", "HSPI1"), quote!(crate::hspi::HspiDma)), (("dac", "CH1"), quote!(crate::dac::DacDma1)), (("dac", "CH2"), quote!(crate::dac::DacDma2)), (("timer", "UP"), quote!(crate::timer::UpDma)), diff --git a/embassy-stm32/src/hspi/enums.rs b/embassy-stm32/src/hspi/enums.rs new file mode 100644 index 000000000..351fc9ec6 --- /dev/null +++ b/embassy-stm32/src/hspi/enums.rs @@ -0,0 +1,411 @@ +//! Enums used in Hspi configuration. + +#[allow(dead_code)] +#[derive(Copy, Clone, defmt::Format)] +pub(crate) enum HspiMode { + IndirectWrite, + IndirectRead, + AutoPolling, + MemoryMapped, +} + +impl Into for HspiMode { + fn into(self) -> u8 { + match self { + HspiMode::IndirectWrite => 0b00, + HspiMode::IndirectRead => 0b01, + HspiMode::AutoPolling => 0b10, + HspiMode::MemoryMapped => 0b11, + } + } +} + +/// Hspi lane width +#[allow(dead_code)] +#[derive(Copy, Clone, defmt::Format)] +pub enum HspiWidth { + /// None + NONE, + /// Single lane + SING, + /// Dual lanes + DUAL, + /// Quad lanes + QUAD, + /// Eight lanes + OCTO, + /// Sixteen lanes + HEXADECA, +} + +impl Into for HspiWidth { + fn into(self) -> u8 { + match self { + HspiWidth::NONE => 0b00, + HspiWidth::SING => 0b01, + HspiWidth::DUAL => 0b10, + HspiWidth::QUAD => 0b11, + HspiWidth::OCTO => 0b100, + HspiWidth::HEXADECA => 0b101, + } + } +} + +/// Flash bank selection +#[allow(dead_code)] +#[derive(Copy, Clone, defmt::Format)] +pub enum FlashSelection { + /// Bank 1 + Flash1, + /// Bank 2 + Flash2, +} + +impl Into for FlashSelection { + fn into(self) -> bool { + match self { + FlashSelection::Flash1 => false, + FlashSelection::Flash2 => true, + } + } +} + +/// Wrap Size +#[allow(dead_code)] +#[allow(missing_docs)] +#[derive(Copy, Clone, defmt::Format)] +pub enum WrapSize { + None, + _16Bytes, + _32Bytes, + _64Bytes, + _128Bytes, +} + +impl Into for WrapSize { + fn into(self) -> u8 { + match self { + WrapSize::None => 0x00, + WrapSize::_16Bytes => 0x02, + WrapSize::_32Bytes => 0x03, + WrapSize::_64Bytes => 0x04, + WrapSize::_128Bytes => 0x05, + } + } +} + +/// Memory Type +#[allow(missing_docs)] +#[allow(dead_code)] +#[derive(Copy, Clone, defmt::Format)] +pub enum MemoryType { + Micron, + Macronix, + Standard, + MacronixRam, + HyperBusMemory, + HyperBusRegister, +} + +impl Into for MemoryType { + fn into(self) -> u8 { + match self { + MemoryType::Micron => 0x00, + MemoryType::Macronix => 0x01, + MemoryType::Standard => 0x02, + MemoryType::MacronixRam => 0x03, + MemoryType::HyperBusMemory => 0x04, + MemoryType::HyperBusRegister => 0x04, + } + } +} + +/// Hspi memory size. +#[allow(missing_docs)] +#[derive(Copy, Clone, defmt::Format)] +pub enum MemorySize { + _1KiB, + _2KiB, + _4KiB, + _8KiB, + _16KiB, + _32KiB, + _64KiB, + _128KiB, + _256KiB, + _512KiB, + _1MiB, + _2MiB, + _4MiB, + _8MiB, + _16MiB, + _32MiB, + _64MiB, + _128MiB, + _256MiB, + _512MiB, + _1GiB, + _2GiB, + _4GiB, + Other(u8), +} + +impl Into for MemorySize { + fn into(self) -> u8 { + match self { + MemorySize::_1KiB => 6, + MemorySize::_2KiB => 7, + MemorySize::_4KiB => 8, + MemorySize::_8KiB => 9, + MemorySize::_16KiB => 10, + MemorySize::_32KiB => 11, + MemorySize::_64KiB => 12, + MemorySize::_128KiB => 13, + MemorySize::_256KiB => 14, + MemorySize::_512KiB => 15, + MemorySize::_1MiB => 16, + MemorySize::_2MiB => 17, + MemorySize::_4MiB => 18, + MemorySize::_8MiB => 19, + MemorySize::_16MiB => 20, + MemorySize::_32MiB => 21, + MemorySize::_64MiB => 22, + MemorySize::_128MiB => 23, + MemorySize::_256MiB => 24, + MemorySize::_512MiB => 25, + MemorySize::_1GiB => 26, + MemorySize::_2GiB => 27, + MemorySize::_4GiB => 28, + MemorySize::Other(val) => val, + } + } +} + +/// Hspi Address size +#[derive(Copy, Clone, defmt::Format)] +pub enum AddressSize { + /// 8-bit address + _8Bit, + /// 16-bit address + _16Bit, + /// 24-bit address + _24Bit, + /// 32-bit address + _32Bit, +} + +impl Into for AddressSize { + fn into(self) -> u8 { + match self { + AddressSize::_8Bit => 0b00, + AddressSize::_16Bit => 0b01, + AddressSize::_24Bit => 0b10, + AddressSize::_32Bit => 0b11, + } + } +} + +/// Time the Chip Select line stays high. +#[allow(missing_docs)] +#[derive(Copy, Clone, defmt::Format)] +pub enum ChipSelectHighTime { + _1Cycle, + _2Cycle, + _3Cycle, + _4Cycle, + _5Cycle, + _6Cycle, + _7Cycle, + _8Cycle, +} + +impl Into for ChipSelectHighTime { + fn into(self) -> u8 { + match self { + ChipSelectHighTime::_1Cycle => 0, + ChipSelectHighTime::_2Cycle => 1, + ChipSelectHighTime::_3Cycle => 2, + ChipSelectHighTime::_4Cycle => 3, + ChipSelectHighTime::_5Cycle => 4, + ChipSelectHighTime::_6Cycle => 5, + ChipSelectHighTime::_7Cycle => 6, + ChipSelectHighTime::_8Cycle => 7, + } + } +} + +/// FIFO threshold. +#[allow(missing_docs)] +#[derive(Copy, Clone, defmt::Format)] +pub enum FIFOThresholdLevel { + _1Bytes, + _2Bytes, + _3Bytes, + _4Bytes, + _5Bytes, + _6Bytes, + _7Bytes, + _8Bytes, + _9Bytes, + _10Bytes, + _11Bytes, + _12Bytes, + _13Bytes, + _14Bytes, + _15Bytes, + _16Bytes, + _17Bytes, + _18Bytes, + _19Bytes, + _20Bytes, + _21Bytes, + _22Bytes, + _23Bytes, + _24Bytes, + _25Bytes, + _26Bytes, + _27Bytes, + _28Bytes, + _29Bytes, + _30Bytes, + _31Bytes, + _32Bytes, +} + +impl Into for FIFOThresholdLevel { + fn into(self) -> u8 { + match self { + FIFOThresholdLevel::_1Bytes => 0, + FIFOThresholdLevel::_2Bytes => 1, + FIFOThresholdLevel::_3Bytes => 2, + FIFOThresholdLevel::_4Bytes => 3, + FIFOThresholdLevel::_5Bytes => 4, + FIFOThresholdLevel::_6Bytes => 5, + FIFOThresholdLevel::_7Bytes => 6, + FIFOThresholdLevel::_8Bytes => 7, + FIFOThresholdLevel::_9Bytes => 8, + FIFOThresholdLevel::_10Bytes => 9, + FIFOThresholdLevel::_11Bytes => 10, + FIFOThresholdLevel::_12Bytes => 11, + FIFOThresholdLevel::_13Bytes => 12, + FIFOThresholdLevel::_14Bytes => 13, + FIFOThresholdLevel::_15Bytes => 14, + FIFOThresholdLevel::_16Bytes => 15, + FIFOThresholdLevel::_17Bytes => 16, + FIFOThresholdLevel::_18Bytes => 17, + FIFOThresholdLevel::_19Bytes => 18, + FIFOThresholdLevel::_20Bytes => 19, + FIFOThresholdLevel::_21Bytes => 20, + FIFOThresholdLevel::_22Bytes => 21, + FIFOThresholdLevel::_23Bytes => 22, + FIFOThresholdLevel::_24Bytes => 23, + FIFOThresholdLevel::_25Bytes => 24, + FIFOThresholdLevel::_26Bytes => 25, + FIFOThresholdLevel::_27Bytes => 26, + FIFOThresholdLevel::_28Bytes => 27, + FIFOThresholdLevel::_29Bytes => 28, + FIFOThresholdLevel::_30Bytes => 29, + FIFOThresholdLevel::_31Bytes => 30, + FIFOThresholdLevel::_32Bytes => 31, + } + } +} + +/// Dummy cycle count +#[allow(missing_docs)] +#[derive(Copy, Clone, defmt::Format)] +pub enum DummyCycles { + _0, + _1, + _2, + _3, + _4, + _5, + _6, + _7, + _8, + _9, + _10, + _11, + _12, + _13, + _14, + _15, + _16, + _17, + _18, + _19, + _20, + _21, + _22, + _23, + _24, + _25, + _26, + _27, + _28, + _29, + _30, + _31, +} + +impl Into for DummyCycles { + fn into(self) -> u8 { + match self { + DummyCycles::_0 => 0, + DummyCycles::_1 => 1, + DummyCycles::_2 => 2, + DummyCycles::_3 => 3, + DummyCycles::_4 => 4, + DummyCycles::_5 => 5, + DummyCycles::_6 => 6, + DummyCycles::_7 => 7, + DummyCycles::_8 => 8, + DummyCycles::_9 => 9, + DummyCycles::_10 => 10, + DummyCycles::_11 => 11, + DummyCycles::_12 => 12, + DummyCycles::_13 => 13, + DummyCycles::_14 => 14, + DummyCycles::_15 => 15, + DummyCycles::_16 => 16, + DummyCycles::_17 => 17, + DummyCycles::_18 => 18, + DummyCycles::_19 => 19, + DummyCycles::_20 => 20, + DummyCycles::_21 => 21, + DummyCycles::_22 => 22, + DummyCycles::_23 => 23, + DummyCycles::_24 => 24, + DummyCycles::_25 => 25, + DummyCycles::_26 => 26, + DummyCycles::_27 => 27, + DummyCycles::_28 => 28, + DummyCycles::_29 => 29, + DummyCycles::_30 => 30, + DummyCycles::_31 => 31, + } + } +} + +/// Functional mode +#[allow(missing_docs)] +#[allow(dead_code)] +#[derive(Copy, Clone, defmt::Format)] +pub enum FunctionalMode { + IndirectWrite, + IndirectRead, + AutoStatusPolling, + MemoryMapped, +} + +impl Into for FunctionalMode { + fn into(self) -> u8 { + match self { + FunctionalMode::IndirectWrite => 0x00, + FunctionalMode::IndirectRead => 0x01, + FunctionalMode::AutoStatusPolling => 0x02, + FunctionalMode::MemoryMapped => 0x03, + } + } +} diff --git a/embassy-stm32/src/hspi/mod.rs b/embassy-stm32/src/hspi/mod.rs new file mode 100644 index 000000000..97e1993dd --- /dev/null +++ b/embassy-stm32/src/hspi/mod.rs @@ -0,0 +1,1008 @@ +//! HSPI Serial Peripheral Interface +//! + +// NOTE: This is a partial implementation of the HSPI driver. +// It implements only Single and Octal SPI modes, but additional +// modes can be added as needed following the same pattern and +// using ospi/mod.rs as a reference. + +#![macro_use] + +pub mod enums; + +use core::marker::PhantomData; + +use embassy_embedded_hal::{GetConfig, SetConfig}; +use embassy_hal_internal::{into_ref, PeripheralRef}; +pub use enums::*; + +use crate::dma::{word, ChannelAndRequest}; +use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed}; +use crate::mode::{Async, Blocking, Mode as PeriMode}; +use crate::pac::hspi::Hspi as Regs; +use crate::rcc::{self, RccPeripheral}; +use crate::{peripherals, Peripheral}; + +/// HSPI driver config. +#[derive(Clone, Copy, defmt::Format)] +pub struct Config { + /// Fifo threshold used by the peripheral to generate the interrupt indicating data + /// or space is available in the FIFO + pub fifo_threshold: FIFOThresholdLevel, + /// Indicates the type of external device connected + pub memory_type: MemoryType, // Need to add an additional enum to provide this public interface + /// Defines the size of the external device connected to the HSPI corresponding + /// to the number of address bits required to access the device + pub device_size: MemorySize, + /// Sets the minimum number of clock cycles that the chip select signal must be held high + /// between commands + pub chip_select_high_time: ChipSelectHighTime, + /// Enables the free running clock + pub free_running_clock: bool, + /// Sets the clock level when the device is not selected + pub clock_mode: bool, + /// Indicates the wrap size corresponding to the external device configuration + pub wrap_size: WrapSize, + /// Specified the prescaler factor used for generating the external clock based + /// on the AHB clock + pub clock_prescaler: u8, + /// Allows the delay of 1/2 cycle the data sampling to account for external + /// signal delays + pub sample_shifting: bool, + /// Allows hold to 1/4 cycle the data + pub delay_hold_quarter_cycle: bool, + /// Enables the transaction boundary feature and defines the boundary to release + /// the chip select + pub chip_select_boundary: u8, + /// Enables the delay block bypass so the sampling is not affected by the delay block + pub delay_block_bypass: bool, + /// Enables communication regulation feature. Chip select is released when the other + /// HSPI requests access to the bus + pub max_transfer: u8, + /// Enables the refresh feature, chip select is released every refresh + 1 clock cycles + pub refresh: u32, +} + +impl Default for Config { + fn default() -> Self { + Self { + fifo_threshold: FIFOThresholdLevel::_16Bytes, + memory_type: MemoryType::Micron, + device_size: MemorySize::Other(0), + chip_select_high_time: ChipSelectHighTime::_5Cycle, + free_running_clock: false, + clock_mode: false, + wrap_size: WrapSize::None, + clock_prescaler: 0, + sample_shifting: false, + delay_hold_quarter_cycle: false, + chip_select_boundary: 0, // Acceptable range 0 to 31 + delay_block_bypass: true, + max_transfer: 0, + refresh: 0, + } + } +} + +/// HSPI transfer configuration. +pub struct TransferConfig { + /// Instruction width (IMODE) + pub iwidth: HspiWidth, + /// Instruction Id + pub instruction: Option, + /// Number of Instruction Bytes + pub isize: AddressSize, + /// Instruction Double Transfer rate enable + pub idtr: bool, + + /// Address width (ADMODE) + pub adwidth: HspiWidth, + /// Device memory address + pub address: Option, + /// Number of Address Bytes + pub adsize: AddressSize, + /// Address Double Transfer rate enable + pub addtr: bool, + + /// Alternate bytes width (ABMODE) + pub abwidth: HspiWidth, + /// Alternate Bytes + pub alternate_bytes: Option, + /// Number of Alternate Bytes + pub absize: AddressSize, + /// Alternate Bytes Double Transfer rate enable + pub abdtr: bool, + + /// Data width (DMODE) + pub dwidth: HspiWidth, + /// Data buffer + pub ddtr: bool, + + /// Number of dummy cycles (DCYC) + pub dummy: DummyCycles, +} + +impl Default for TransferConfig { + fn default() -> Self { + Self { + iwidth: HspiWidth::NONE, + instruction: None, + isize: AddressSize::_8Bit, + idtr: false, + + adwidth: HspiWidth::NONE, + address: None, + adsize: AddressSize::_8Bit, + addtr: false, + + abwidth: HspiWidth::NONE, + alternate_bytes: None, + absize: AddressSize::_8Bit, + abdtr: false, + + dwidth: HspiWidth::NONE, + ddtr: false, + + dummy: DummyCycles::_0, + } + } +} + +/// Error used for HSPI implementation +#[derive(Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum HspiError { + /// Peripheral configuration is invalid + InvalidConfiguration, + /// Operation configuration is invalid + InvalidCommand, + /// Size zero buffer passed to instruction + EmptyBuffer, +} + +/// HSPI driver. +pub struct Hspi<'d, T: Instance, M: PeriMode> { + _peri: PeripheralRef<'d, T>, + sck: Option>, + d0: Option>, + d1: Option>, + d2: Option>, + d3: Option>, + d4: Option>, + d5: Option>, + d6: Option>, + d7: Option>, + d8: Option>, + d9: Option>, + d10: Option>, + d11: Option>, + d12: Option>, + d13: Option>, + d14: Option>, + d15: Option>, + nss: Option>, + dqs0: Option>, + dqs1: Option>, + dma: Option>, + _phantom: PhantomData, + config: Config, + width: HspiWidth, +} + +impl<'d, T: Instance, M: PeriMode> Hspi<'d, T, M> { + /// Enter memory mode. + /// The Input `read_config` is used to configure the read operation in memory mode + pub fn enable_memory_mapped_mode( + &mut self, + read_config: TransferConfig, + write_config: TransferConfig, + ) -> Result<(), HspiError> { + // Use configure command to set read config + self.configure_command(&read_config, None)?; + + // Set writing configurations, there are separate registers for write configurations in memory mapped mode + T::REGS.wccr().modify(|w| { + w.set_imode(write_config.iwidth.into()); + w.set_idtr(write_config.idtr); + w.set_isize(write_config.isize.into()); + + w.set_admode(write_config.adwidth.into()); + w.set_addtr(write_config.idtr); + w.set_adsize(write_config.adsize.into()); + + w.set_dmode(write_config.dwidth.into()); + w.set_ddtr(write_config.ddtr); + + w.set_abmode(write_config.abwidth.into()); + w.set_dqse(true); + }); + + T::REGS.wtcr().modify(|w| w.set_dcyc(write_config.dummy.into())); + + // Enable memory mapped mode + T::REGS.cr().modify(|r| { + r.set_fmode(FunctionalMode::MemoryMapped.into()); + r.set_tcen(false); + }); + Ok(()) + } + + /// Quit from memory mapped mode + pub fn disable_memory_mapped_mode(&mut self) { + T::REGS.cr().modify(|r| { + r.set_fmode(FunctionalMode::IndirectWrite.into()); + r.set_abort(true); + r.set_dmaen(false); + r.set_en(false); + }); + + // Clear transfer complete flag + T::REGS.fcr().write(|w| w.set_ctcf(true)); + + // Re-enable HSPI + T::REGS.cr().modify(|r| { + r.set_en(true); + }); + } + + fn new_inner( + peri: impl Peripheral

+ 'd, + d0: Option>, + d1: Option>, + d2: Option>, + d3: Option>, + d4: Option>, + d5: Option>, + d6: Option>, + d7: Option>, + d8: Option>, + d9: Option>, + d10: Option>, + d11: Option>, + d12: Option>, + d13: Option>, + d14: Option>, + d15: Option>, + sck: Option>, + nss: Option>, + dqs0: Option>, + dqs1: Option>, + dma: Option>, + config: Config, + width: HspiWidth, + dual_memory_mode: bool, + ) -> Self { + into_ref!(peri); + + // System configuration + rcc::enable_and_reset::(); + + // Call this function just to check that the clock for HSPI1 is properly setup + let _ = T::frequency(); + + while T::REGS.sr().read().busy() {} + + Self::configure_registers(&config, Some(dual_memory_mode)); + + Self { + _peri: peri, + sck, + d0, + d1, + d2, + d3, + d4, + d5, + d6, + d7, + d8, + d9, + d10, + d11, + d12, + d13, + d14, + d15, + nss, + dqs0, + dqs1, + dma, + _phantom: PhantomData, + config, + width, + } + } + + fn configure_registers(config: &Config, dual_memory_mode: Option) { + // Device configuration + T::REGS.dcr1().modify(|w| { + w.set_mtyp(config.memory_type.into()); + w.set_devsize(config.device_size.into()); + w.set_csht(config.chip_select_high_time.into()); + w.set_frck(false); + w.set_ckmode(config.clock_mode); + w.set_dlybyp(config.delay_block_bypass); + }); + + T::REGS.dcr2().modify(|w| { + w.set_wrapsize(config.wrap_size.into()); + }); + + T::REGS.dcr3().modify(|w| { + w.set_csbound(config.chip_select_boundary); + w.set_maxtran(config.max_transfer); + }); + + T::REGS.dcr4().modify(|w| { + w.set_refresh(config.refresh); + }); + + T::REGS.cr().modify(|w| { + w.set_fthres(config.fifo_threshold.into()); + }); + + // Wait for busy flag to clear + while T::REGS.sr().read().busy() {} + + T::REGS.dcr2().modify(|w| { + w.set_prescaler(config.clock_prescaler); + }); + + // The configuration of clock prescaler trigger automatically a calibration process + // So it is necessary to wait the calibration is complete + while T::REGS.sr().read().busy() {} + + if let Some(dual_memory_mode) = dual_memory_mode { + T::REGS.cr().modify(|w| { + w.set_dmm(dual_memory_mode); + }); + } + + T::REGS.tcr().modify(|w| { + w.set_sshift(config.sample_shifting); + w.set_dhqc(config.delay_hold_quarter_cycle); + }); + + // Enable peripheral + T::REGS.cr().modify(|w| { + w.set_en(true); + }); + + // Free running clock needs to be set after peripheral enable + if config.free_running_clock { + T::REGS.dcr1().modify(|w| { + w.set_frck(config.free_running_clock); + }); + } + } + + // Function to configure the peripheral for the requested command + fn configure_command(&mut self, command: &TransferConfig, data_len: Option) -> Result<(), HspiError> { + // Check that transaction doesn't use more than hardware initialized pins + if >::into(command.iwidth) > >::into(self.width) + || >::into(command.adwidth) > >::into(self.width) + || >::into(command.abwidth) > >::into(self.width) + || >::into(command.dwidth) > >::into(self.width) + { + return Err(HspiError::InvalidCommand); + } + + while T::REGS.sr().read().busy() {} + + T::REGS.cr().modify(|w| { + w.set_fmode(0.into()); + }); + + // Configure alternate bytes + if let Some(ab) = command.alternate_bytes { + T::REGS.abr().write(|v| v.set_alternate(ab)); + T::REGS.ccr().modify(|w| { + w.set_abmode(command.abwidth.into()); + w.set_abdtr(command.abdtr); + w.set_absize(command.absize.into()); + }) + } + + // Configure dummy cycles + T::REGS.tcr().modify(|w| { + w.set_dcyc(command.dummy.into()); + }); + + // Configure data + if let Some(data_length) = data_len { + T::REGS.dlr().write(|v| { + v.set_dl((data_length - 1) as u32); + }) + } else { + T::REGS.dlr().write(|v| { + v.set_dl((0) as u32); + }) + } + + // Configure instruction/address/data modes + T::REGS.ccr().modify(|w| { + w.set_imode(command.iwidth.into()); + w.set_idtr(command.idtr); + w.set_isize(command.isize.into()); + + w.set_admode(command.adwidth.into()); + w.set_addtr(command.addtr); + w.set_adsize(command.adsize.into()); + + w.set_dmode(command.dwidth.into()); + w.set_ddtr(command.ddtr); + }); + + // Configure DQS + T::REGS.ccr().modify(|w| { + w.set_dqse(command.ddtr && command.instruction.unwrap_or(0) != 0x12ED); + }); + + // Set information required to initiate transaction + if let Some(instruction) = command.instruction { + if let Some(address) = command.address { + T::REGS.ir().write(|v| { + v.set_instruction(instruction); + }); + + T::REGS.ar().write(|v| { + v.set_address(address); + }); + } else { + T::REGS.ir().write(|v| { + v.set_instruction(instruction); + }); + } + } else { + if let Some(address) = command.address { + T::REGS.ar().write(|v| { + v.set_address(address); + }); + } else { + // The only single phase transaction supported is instruction only + return Err(HspiError::InvalidCommand); + } + } + + Ok(()) + } + + /// Function used to control or configure the target device without data transfer + pub fn blocking_command(&mut self, command: &TransferConfig) -> Result<(), HspiError> { + // Wait for peripheral to be free + while T::REGS.sr().read().busy() {} + + // Need additional validation that command configuration doesn't have data set + self.configure_command(command, None)?; + + // Transaction initiated by setting final configuration, i.e the instruction register + while !T::REGS.sr().read().tcf() {} + T::REGS.fcr().write(|w| { + w.set_ctcf(true); + }); + + Ok(()) + } + + /// Blocking read with byte by byte data transfer + pub fn blocking_read(&mut self, buf: &mut [W], transaction: TransferConfig) -> Result<(), HspiError> { + if buf.is_empty() { + return Err(HspiError::EmptyBuffer); + } + + // Wait for peripheral to be free + while T::REGS.sr().read().busy() {} + + // Ensure DMA is not enabled for this transaction + T::REGS.cr().modify(|w| { + w.set_dmaen(false); + }); + + self.configure_command(&transaction, Some(buf.len()))?; + + let current_address = T::REGS.ar().read().address(); + let current_instruction = T::REGS.ir().read().instruction(); + + // For a indirect read transaction, the transaction begins when the instruction/address is set + T::REGS + .cr() + .modify(|v| v.set_fmode(FunctionalMode::IndirectRead.into())); + if T::REGS.ccr().read().admode() == HspiWidth::NONE.into() { + T::REGS.ir().write(|v| v.set_instruction(current_instruction)); + } else { + T::REGS.ar().write(|v| v.set_address(current_address)); + } + + for idx in 0..buf.len() { + while !T::REGS.sr().read().tcf() && !T::REGS.sr().read().ftf() {} + buf[idx] = unsafe { (T::REGS.dr().as_ptr() as *mut W).read_volatile() }; + } + + while !T::REGS.sr().read().tcf() {} + T::REGS.fcr().write(|v| v.set_ctcf(true)); + + Ok(()) + } + + /// Blocking write with byte by byte data transfer + pub fn blocking_write(&mut self, buf: &[W], transaction: TransferConfig) -> Result<(), HspiError> { + if buf.is_empty() { + return Err(HspiError::EmptyBuffer); + } + + // Wait for peripheral to be free + while T::REGS.sr().read().busy() {} + + T::REGS.cr().modify(|w| { + w.set_dmaen(false); + }); + + self.configure_command(&transaction, Some(buf.len()))?; + + T::REGS + .cr() + .modify(|v| v.set_fmode(FunctionalMode::IndirectWrite.into())); + + for idx in 0..buf.len() { + while !T::REGS.sr().read().ftf() {} + unsafe { (T::REGS.dr().as_ptr() as *mut W).write_volatile(buf[idx]) }; + } + + while !T::REGS.sr().read().tcf() {} + T::REGS.fcr().write(|v| v.set_ctcf(true)); + + Ok(()) + } + + /// Set new bus configuration + pub fn set_config(&mut self, config: &Config) { + // Wait for busy flag to clear + while T::REGS.sr().read().busy() {} + + // Disable DMA channel while configuring the peripheral + T::REGS.cr().modify(|w| { + w.set_dmaen(false); + }); + + Self::configure_registers(config, None); + + self.config = *config; + } + + /// Get current configuration + pub fn get_config(&self) -> Config { + self.config + } +} + +impl<'d, T: Instance> Hspi<'d, T, Blocking> { + /// Create new blocking HSPI driver for single spi external chip + pub fn new_blocking_singlespi( + peri: impl Peripheral

+ 'd, + sck: impl Peripheral

> + 'd, + d0: impl Peripheral

> + 'd, + d1: impl Peripheral

> + 'd, + nss: impl Peripheral

> + 'd, + config: Config, + ) -> Self { + Self::new_inner( + peri, + new_pin!(d0, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + new_pin!(d1, AfType::input(Pull::None)), + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + new_pin!(sck, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + new_pin!( + nss, + AfType::output_pull(OutputType::PushPull, Speed::VeryHigh, Pull::Up) + ), + None, + None, + None, + config, + HspiWidth::SING, + false, + ) + } + + /// Create new blocking HSPI driver for octospi external chip + pub fn new_blocking_octospi( + peri: impl Peripheral

+ 'd, + sck: impl Peripheral

> + 'd, + d0: impl Peripheral

> + 'd, + d1: impl Peripheral

> + 'd, + d2: impl Peripheral

> + 'd, + d3: impl Peripheral

> + 'd, + d4: impl Peripheral

> + 'd, + d5: impl Peripheral

> + 'd, + d6: impl Peripheral

> + 'd, + d7: impl Peripheral

> + 'd, + nss: impl Peripheral

> + 'd, + dqs0: impl Peripheral

> + 'd, + config: Config, + ) -> Self { + Self::new_inner( + peri, + new_pin!(d0, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + new_pin!(d1, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + new_pin!(d2, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + new_pin!(d3, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + new_pin!(d4, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + new_pin!(d5, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + new_pin!(d6, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + new_pin!(d7, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + None, + None, + None, + None, + None, + None, + None, + None, + new_pin!(sck, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + new_pin!( + nss, + AfType::output_pull(OutputType::PushPull, Speed::VeryHigh, Pull::Up) + ), + new_pin!(dqs0, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + None, + None, + config, + HspiWidth::OCTO, + false, + ) + } +} + +impl<'d, T: Instance> Hspi<'d, T, Async> { + /// Create new HSPI driver for a single spi external chip + pub fn new_singlespi( + peri: impl Peripheral

+ 'd, + sck: impl Peripheral

> + 'd, + d0: impl Peripheral

> + 'd, + d1: impl Peripheral

> + 'd, + nss: impl Peripheral

> + 'd, + dma: impl Peripheral

> + 'd, + config: Config, + ) -> Self { + Self::new_inner( + peri, + new_pin!(d0, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + new_pin!(d1, AfType::input(Pull::None)), + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + new_pin!(sck, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + new_pin!( + nss, + AfType::output_pull(OutputType::PushPull, Speed::VeryHigh, Pull::Up) + ), + None, + None, + new_dma!(dma), + config, + HspiWidth::SING, + false, + ) + } + + /// Create new HSPI driver for octospi external chip + pub fn new_octospi( + peri: impl Peripheral

+ 'd, + sck: impl Peripheral

> + 'd, + d0: impl Peripheral

> + 'd, + d1: impl Peripheral

> + 'd, + d2: impl Peripheral

> + 'd, + d3: impl Peripheral

> + 'd, + d4: impl Peripheral

> + 'd, + d5: impl Peripheral

> + 'd, + d6: impl Peripheral

> + 'd, + d7: impl Peripheral

> + 'd, + nss: impl Peripheral

> + 'd, + dqs0: impl Peripheral

> + 'd, + dma: impl Peripheral

> + 'd, + config: Config, + ) -> Self { + Self::new_inner( + peri, + new_pin!(d0, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + new_pin!(d1, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + new_pin!(d2, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + new_pin!(d3, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + new_pin!(d4, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + new_pin!(d5, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + new_pin!(d6, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + new_pin!(d7, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + new_pin!(sck, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + None, + None, + None, + None, + None, + None, + None, + None, + new_pin!( + nss, + AfType::output_pull(OutputType::PushPull, Speed::VeryHigh, Pull::Up) + ), + new_pin!(dqs0, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + None, + new_dma!(dma), + config, + HspiWidth::OCTO, + false, + ) + } + + /// Blocking read with DMA transfer + pub fn blocking_read_dma(&mut self, buf: &mut [W], transaction: TransferConfig) -> Result<(), HspiError> { + if buf.is_empty() { + return Err(HspiError::EmptyBuffer); + } + + // Wait for peripheral to be free + while T::REGS.sr().read().busy() {} + + self.configure_command(&transaction, Some(buf.len()))?; + + let current_address = T::REGS.ar().read().address(); + let current_instruction = T::REGS.ir().read().instruction(); + + // For a indirect read transaction, the transaction begins when the instruction/address is set + T::REGS + .cr() + .modify(|v| v.set_fmode(FunctionalMode::IndirectRead.into())); + if T::REGS.ccr().read().admode() == HspiWidth::NONE.into() { + T::REGS.ir().write(|v| v.set_instruction(current_instruction)); + } else { + T::REGS.ar().write(|v| v.set_address(current_address)); + } + + let transfer = unsafe { + self.dma + .as_mut() + .unwrap() + .read(T::REGS.dr().as_ptr() as *mut W, buf, Default::default()) + }; + + T::REGS.cr().modify(|w| w.set_dmaen(true)); + + transfer.blocking_wait(); + + finish_dma(T::REGS); + + Ok(()) + } + + /// Blocking write with DMA transfer + pub fn blocking_write_dma(&mut self, buf: &[W], transaction: TransferConfig) -> Result<(), HspiError> { + if buf.is_empty() { + return Err(HspiError::EmptyBuffer); + } + + // Wait for peripheral to be free + while T::REGS.sr().read().busy() {} + + self.configure_command(&transaction, Some(buf.len()))?; + T::REGS + .cr() + .modify(|v| v.set_fmode(FunctionalMode::IndirectWrite.into())); + + let transfer = unsafe { + self.dma + .as_mut() + .unwrap() + .write(buf, T::REGS.dr().as_ptr() as *mut W, Default::default()) + }; + + T::REGS.cr().modify(|w| w.set_dmaen(true)); + + transfer.blocking_wait(); + + finish_dma(T::REGS); + + Ok(()) + } + + /// Asynchronous read from external device + pub async fn read(&mut self, buf: &mut [W], transaction: TransferConfig) -> Result<(), HspiError> { + if buf.is_empty() { + return Err(HspiError::EmptyBuffer); + } + + // Wait for peripheral to be free + while T::REGS.sr().read().busy() {} + + self.configure_command(&transaction, Some(buf.len()))?; + + let current_address = T::REGS.ar().read().address(); + let current_instruction = T::REGS.ir().read().instruction(); + + // For a indirect read transaction, the transaction begins when the instruction/address is set + T::REGS + .cr() + .modify(|v| v.set_fmode(FunctionalMode::IndirectRead.into())); + if T::REGS.ccr().read().admode() == HspiWidth::NONE.into() { + T::REGS.ir().write(|v| v.set_instruction(current_instruction)); + } else { + T::REGS.ar().write(|v| v.set_address(current_address)); + } + + let transfer = unsafe { + self.dma + .as_mut() + .unwrap() + .read(T::REGS.dr().as_ptr() as *mut W, buf, Default::default()) + }; + + T::REGS.cr().modify(|w| w.set_dmaen(true)); + + transfer.await; + + finish_dma(T::REGS); + + Ok(()) + } + + /// Asynchronous write to external device + pub async fn write(&mut self, buf: &[W], transaction: TransferConfig) -> Result<(), HspiError> { + if buf.is_empty() { + return Err(HspiError::EmptyBuffer); + } + + // Wait for peripheral to be free + while T::REGS.sr().read().busy() {} + + self.configure_command(&transaction, Some(buf.len()))?; + T::REGS + .cr() + .modify(|v| v.set_fmode(FunctionalMode::IndirectWrite.into())); + + let transfer = unsafe { + self.dma + .as_mut() + .unwrap() + .write(buf, T::REGS.dr().as_ptr() as *mut W, Default::default()) + }; + + T::REGS.cr().modify(|w| w.set_dmaen(true)); + + transfer.await; + + finish_dma(T::REGS); + + Ok(()) + } +} + +impl<'d, T: Instance, M: PeriMode> Drop for Hspi<'d, T, M> { + fn drop(&mut self) { + self.sck.as_ref().map(|x| x.set_as_disconnected()); + self.d0.as_ref().map(|x| x.set_as_disconnected()); + self.d1.as_ref().map(|x| x.set_as_disconnected()); + self.d2.as_ref().map(|x| x.set_as_disconnected()); + self.d3.as_ref().map(|x| x.set_as_disconnected()); + self.d4.as_ref().map(|x| x.set_as_disconnected()); + self.d5.as_ref().map(|x| x.set_as_disconnected()); + self.d6.as_ref().map(|x| x.set_as_disconnected()); + self.d7.as_ref().map(|x| x.set_as_disconnected()); + self.d8.as_ref().map(|x| x.set_as_disconnected()); + self.d9.as_ref().map(|x| x.set_as_disconnected()); + self.d10.as_ref().map(|x| x.set_as_disconnected()); + self.d11.as_ref().map(|x| x.set_as_disconnected()); + self.d12.as_ref().map(|x| x.set_as_disconnected()); + self.d13.as_ref().map(|x| x.set_as_disconnected()); + self.d14.as_ref().map(|x| x.set_as_disconnected()); + self.d15.as_ref().map(|x| x.set_as_disconnected()); + self.nss.as_ref().map(|x| x.set_as_disconnected()); + self.dqs0.as_ref().map(|x| x.set_as_disconnected()); + self.dqs1.as_ref().map(|x| x.set_as_disconnected()); + + rcc::disable::(); + } +} + +fn finish_dma(regs: Regs) { + while !regs.sr().read().tcf() {} + regs.fcr().write(|v| v.set_ctcf(true)); + + regs.cr().modify(|w| { + w.set_dmaen(false); + }); +} + +/// HSPI instance trait. +pub(crate) trait SealedInstance { + const REGS: Regs; +} + +/// HSPI instance trait. +#[allow(private_bounds)] +pub trait Instance: Peripheral

+ SealedInstance + RccPeripheral {} + +pin_trait!(SckPin, Instance); +pin_trait!(NckPin, Instance); +pin_trait!(D0Pin, Instance); +pin_trait!(D1Pin, Instance); +pin_trait!(D2Pin, Instance); +pin_trait!(D3Pin, Instance); +pin_trait!(D4Pin, Instance); +pin_trait!(D5Pin, Instance); +pin_trait!(D6Pin, Instance); +pin_trait!(D7Pin, Instance); +pin_trait!(D8Pin, Instance); +pin_trait!(D9Pin, Instance); +pin_trait!(D10Pin, Instance); +pin_trait!(D11Pin, Instance); +pin_trait!(D12Pin, Instance); +pin_trait!(D13Pin, Instance); +pin_trait!(D14Pin, Instance); +pin_trait!(D15Pin, Instance); +pin_trait!(DQS0Pin, Instance); +pin_trait!(DQS1Pin, Instance); +pin_trait!(NSSPin, Instance); +dma_trait!(HspiDma, Instance); + +foreach_peripheral!( + (hspi, $inst:ident) => { + impl SealedInstance for peripherals::$inst { + const REGS: Regs = crate::pac::$inst; + } + + impl Instance for peripherals::$inst {} + }; +); + +impl<'d, T: Instance, M: PeriMode> SetConfig for Hspi<'d, T, M> { + type Config = Config; + type ConfigError = (); + fn set_config(&mut self, config: &Self::Config) -> Result<(), ()> { + self.set_config(config); + Ok(()) + } +} + +impl<'d, T: Instance, M: PeriMode> GetConfig for Hspi<'d, T, M> { + type Config = Config; + fn get_config(&self) -> Self::Config { + self.get_config() + } +} + +/// Word sizes usable for HSPI. +#[allow(private_bounds)] +pub trait Word: word::Word {} + +macro_rules! impl_word { + ($T:ty) => { + impl Word for $T {} + }; +} + +impl_word!(u8); +impl_word!(u16); +impl_word!(u32); diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 61da754c3..c37908dbc 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -83,6 +83,8 @@ pub mod hash; pub mod hrtim; #[cfg(hsem)] pub mod hsem; +#[cfg(hspi)] +pub mod hspi; #[cfg(i2c)] pub mod i2c; #[cfg(any(all(spi_v1, rcc_f4), spi_v3))] From 29e4b4486ccb8080aa3f93e5078f00ccbdb4ef62 Mon Sep 17 00:00:00 2001 From: William Spinelli <174336620+williams-one@users.noreply.github.com> Date: Fri, 20 Dec 2024 09:52:22 +0100 Subject: [PATCH 0634/1217] stm32u5: Add HSPI example using a flash in memory mapped mode --- .../stm32u5/src/bin/hspi_memory_mapped.rs | 455 ++++++++++++++++++ 1 file changed, 455 insertions(+) create mode 100644 examples/stm32u5/src/bin/hspi_memory_mapped.rs diff --git a/examples/stm32u5/src/bin/hspi_memory_mapped.rs b/examples/stm32u5/src/bin/hspi_memory_mapped.rs new file mode 100644 index 000000000..9fef4855e --- /dev/null +++ b/examples/stm32u5/src/bin/hspi_memory_mapped.rs @@ -0,0 +1,455 @@ +#![no_main] +#![no_std] + +// Tested on an STM32U5G9J-DK2 demo board using the on-board MX66LM1G45G flash memory +// The flash is connected to the HSPI1 port as an OCTA-DTR device +// +// Use embassy-stm32 feature "stm32u5g9zj" and probe-rs chip "STM32U5G9ZJTxQ" + +use defmt::info; +use embassy_executor::Spawner; +use embassy_stm32::hspi::{ + AddressSize, ChipSelectHighTime, DummyCycles, FIFOThresholdLevel, Hspi, HspiWidth, Instance, MemorySize, + MemoryType, TransferConfig, WrapSize, +}; +use embassy_stm32::mode::Async; +use embassy_stm32::rcc; +use embassy_stm32::time::Hertz; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + info!("Start hspi_memory_mapped"); + + // RCC config + let mut config = embassy_stm32::Config::default(); + config.rcc.hse = Some(rcc::Hse { + freq: Hertz(16_000_000), + mode: rcc::HseMode::Oscillator, + }); + config.rcc.pll1 = Some(rcc::Pll { + source: rcc::PllSource::HSE, + prediv: rcc::PllPreDiv::DIV1, + mul: rcc::PllMul::MUL10, + divp: None, + divq: None, + divr: Some(rcc::PllDiv::DIV1), + }); + config.rcc.sys = rcc::Sysclk::PLL1_R; // 160 Mhz + config.rcc.pll2 = Some(rcc::Pll { + source: rcc::PllSource::HSE, + prediv: rcc::PllPreDiv::DIV4, + mul: rcc::PllMul::MUL66, + divp: None, + divq: Some(rcc::PllDiv::DIV2), + divr: None, + }); + config.rcc.mux.hspi1sel = rcc::mux::Hspisel::PLL2_Q; // 132 MHz + + // Initialize peripherals + let p = embassy_stm32::init(config); + + let flash_config = embassy_stm32::hspi::Config { + fifo_threshold: FIFOThresholdLevel::_4Bytes, + memory_type: MemoryType::Macronix, + device_size: MemorySize::_1GiB, + chip_select_high_time: ChipSelectHighTime::_2Cycle, + free_running_clock: false, + clock_mode: false, + wrap_size: WrapSize::None, + clock_prescaler: 0, + sample_shifting: false, + delay_hold_quarter_cycle: false, + chip_select_boundary: 0, + delay_block_bypass: false, + max_transfer: 0, + refresh: 0, + }; + + let use_dma = true; + + info!("Testing flash in OCTA DTR mode and memory mapped mode"); + + let hspi = Hspi::new_octospi( + p.HSPI1, + p.PI3, + p.PH10, + p.PH11, + p.PH12, + p.PH13, + p.PH14, + p.PH15, + p.PI0, + p.PI1, + p.PH9, + p.PI2, + p.GPDMA1_CH7, + flash_config, + ); + + let mut flash = OctaDtrFlashMemory::new(hspi).await; + + let flash_id = flash.read_id(); + info!("FLASH ID: {=[u8]:x}", flash_id); + + let mut rd_buf = [0u8; 16]; + flash.read_memory(0, &mut rd_buf, use_dma).await; + info!("READ BUF: {=[u8]:#X}", rd_buf); + + flash.erase_sector(0).await; + flash.read_memory(0, &mut rd_buf, use_dma).await; + info!("READ BUF: {=[u8]:#X}", rd_buf); + assert_eq!(rd_buf[0], 0xFF); + assert_eq!(rd_buf[15], 0xFF); + + let mut wr_buf = [0u8; 16]; + for i in 0..wr_buf.len() { + wr_buf[i] = i as u8; + } + info!("WRITE BUF: {=[u8]:#X}", wr_buf); + flash.write_memory(0, &wr_buf, use_dma).await; + flash.read_memory(0, &mut rd_buf, use_dma).await; + info!("READ BUF: {=[u8]:#X}", rd_buf); + assert_eq!(rd_buf[0], 0x00); + assert_eq!(rd_buf[15], 0x0F); + + flash.enable_mm().await; + info!("Enabled memory mapped mode"); + + let first_u32 = unsafe { *(0xA0000000 as *const u32) }; + info!("first_u32: 0x{=u32:X}", first_u32); + assert_eq!(first_u32, 0x03020100); + + let second_u32 = unsafe { *(0xA0000004 as *const u32) }; + assert_eq!(second_u32, 0x07060504); + info!("second_u32: 0x{=u32:X}", second_u32); + + let first_u8 = unsafe { *(0xA0000000 as *const u8) }; + assert_eq!(first_u8, 00); + info!("first_u8: 0x{=u8:X}", first_u8); + + let second_u8 = unsafe { *(0xA0000001 as *const u8) }; + assert_eq!(second_u8, 0x01); + info!("second_u8: 0x{=u8:X}", second_u8); + + let third_u8 = unsafe { *(0xA0000002 as *const u8) }; + assert_eq!(third_u8, 0x02); + info!("third_u8: 0x{=u8:X}", third_u8); + + let fourth_u8 = unsafe { *(0xA0000003 as *const u8) }; + assert_eq!(fourth_u8, 0x03); + info!("fourth_u8: 0x{=u8:X}", fourth_u8); + + info!("DONE"); +} + +// Custom implementation for MX66UW1G45G NOR flash memory from Macronix. +// Chip commands are hardcoded as they depend on the chip used. +// This implementation enables Octa I/O (OPI) and Double Transfer Rate (DTR) + +pub struct OctaDtrFlashMemory<'d, I: Instance> { + hspi: Hspi<'d, I, Async>, +} + +impl<'d, I: Instance> OctaDtrFlashMemory<'d, I> { + const MEMORY_PAGE_SIZE: usize = 256; + + const CMD_READ_OCTA_DTR: u16 = 0xEE11; + const CMD_PAGE_PROGRAM_OCTA_DTR: u16 = 0x12ED; + + const CMD_READ_ID_OCTA_DTR: u16 = 0x9F60; + + const CMD_RESET_ENABLE: u8 = 0x66; + const CMD_RESET_ENABLE_OCTA_DTR: u16 = 0x6699; + const CMD_RESET: u8 = 0x99; + const CMD_RESET_OCTA_DTR: u16 = 0x9966; + + const CMD_WRITE_ENABLE: u8 = 0x06; + const CMD_WRITE_ENABLE_OCTA_DTR: u16 = 0x06F9; + + const CMD_SECTOR_ERASE_OCTA_DTR: u16 = 0x21DE; + const CMD_BLOCK_ERASE_OCTA_DTR: u16 = 0xDC23; + + const CMD_READ_SR: u8 = 0x05; + const CMD_READ_SR_OCTA_DTR: u16 = 0x05FA; + + const CMD_READ_CR2: u8 = 0x71; + const CMD_WRITE_CR2: u8 = 0x72; + + const CR2_REG1_ADDR: u32 = 0x00000000; + const CR2_OCTA_DTR: u8 = 0x02; + + const CR2_REG3_ADDR: u32 = 0x00000300; + const CR2_DC_6_CYCLES: u8 = 0x07; + + pub async fn new(hspi: Hspi<'d, I, Async>) -> Self { + let mut memory = Self { hspi }; + + memory.reset_memory().await; + memory.enable_octa_dtr().await; + memory + } + + async fn enable_octa_dtr(&mut self) { + self.write_enable_spi().await; + self.write_cr2_spi(Self::CR2_REG3_ADDR, Self::CR2_DC_6_CYCLES); + self.write_enable_spi().await; + self.write_cr2_spi(Self::CR2_REG1_ADDR, Self::CR2_OCTA_DTR); + } + + pub async fn enable_mm(&mut self) { + let read_config = TransferConfig { + iwidth: HspiWidth::OCTO, + instruction: Some(Self::CMD_READ_OCTA_DTR as u32), + isize: AddressSize::_16Bit, + idtr: true, + adwidth: HspiWidth::OCTO, + adsize: AddressSize::_32Bit, + addtr: true, + dwidth: HspiWidth::OCTO, + ddtr: true, + dummy: DummyCycles::_6, + ..Default::default() + }; + + let write_config = TransferConfig { + iwidth: HspiWidth::OCTO, + isize: AddressSize::_16Bit, + idtr: true, + adwidth: HspiWidth::OCTO, + adsize: AddressSize::_32Bit, + addtr: true, + dwidth: HspiWidth::OCTO, + ddtr: true, + ..Default::default() + }; + self.hspi.enable_memory_mapped_mode(read_config, write_config).unwrap(); + } + + async fn exec_command_spi(&mut self, cmd: u8) { + let transaction = TransferConfig { + iwidth: HspiWidth::SING, + instruction: Some(cmd as u32), + ..Default::default() + }; + info!("Excuting command: 0x{:X}", transaction.instruction.unwrap()); + self.hspi.blocking_command(&transaction).unwrap(); + } + + async fn exec_command_octa_dtr(&mut self, cmd: u16) { + let transaction = TransferConfig { + iwidth: HspiWidth::OCTO, + instruction: Some(cmd as u32), + isize: AddressSize::_16Bit, + idtr: true, + ..Default::default() + }; + info!("Excuting command: 0x{:X}", transaction.instruction.unwrap()); + self.hspi.blocking_command(&transaction).unwrap(); + } + + fn wait_write_finish_spi(&mut self) { + while (self.read_sr_spi() & 0x01) != 0 {} + } + + fn wait_write_finish_octa_dtr(&mut self) { + while (self.read_sr_octa_dtr() & 0x01) != 0 {} + } + + pub async fn reset_memory(&mut self) { + // servono entrambi i comandi? + self.exec_command_octa_dtr(Self::CMD_RESET_ENABLE_OCTA_DTR).await; + self.exec_command_octa_dtr(Self::CMD_RESET_OCTA_DTR).await; + self.exec_command_spi(Self::CMD_RESET_ENABLE).await; + self.exec_command_spi(Self::CMD_RESET).await; + self.wait_write_finish_spi(); + } + + async fn write_enable_spi(&mut self) { + self.exec_command_spi(Self::CMD_WRITE_ENABLE).await; + } + + async fn write_enable_octa_dtr(&mut self) { + self.exec_command_octa_dtr(Self::CMD_WRITE_ENABLE_OCTA_DTR).await; + } + + pub fn read_id(&mut self) -> [u8; 3] { + let mut buffer = [0; 6]; + let transaction: TransferConfig = TransferConfig { + iwidth: HspiWidth::OCTO, + instruction: Some(Self::CMD_READ_ID_OCTA_DTR as u32), + isize: AddressSize::_16Bit, + idtr: true, + adwidth: HspiWidth::OCTO, + address: Some(0), + adsize: AddressSize::_32Bit, + addtr: true, + dwidth: HspiWidth::OCTO, + ddtr: true, + dummy: DummyCycles::_5, + ..Default::default() + }; + info!("Reading flash id: 0x{:X}", transaction.instruction.unwrap()); + self.hspi.blocking_read(&mut buffer, transaction).unwrap(); + [buffer[0], buffer[2], buffer[4]] + } + + pub async fn read_memory(&mut self, addr: u32, buffer: &mut [u8], use_dma: bool) { + let transaction = TransferConfig { + iwidth: HspiWidth::OCTO, + instruction: Some(Self::CMD_READ_OCTA_DTR as u32), + isize: AddressSize::_16Bit, + idtr: true, + adwidth: HspiWidth::OCTO, + address: Some(addr), + adsize: AddressSize::_32Bit, + addtr: true, + dwidth: HspiWidth::OCTO, + ddtr: true, + dummy: DummyCycles::_6, + ..Default::default() + }; + if use_dma { + self.hspi.read(buffer, transaction).await.unwrap(); + } else { + self.hspi.blocking_read(buffer, transaction).unwrap(); + } + } + + async fn perform_erase_octa_dtr(&mut self, addr: u32, cmd: u16) { + let transaction = TransferConfig { + iwidth: HspiWidth::OCTO, + instruction: Some(cmd as u32), + isize: AddressSize::_16Bit, + idtr: true, + adwidth: HspiWidth::OCTO, + address: Some(addr), + adsize: AddressSize::_32Bit, + addtr: true, + ..Default::default() + }; + self.write_enable_octa_dtr().await; + self.hspi.blocking_command(&transaction).unwrap(); + self.wait_write_finish_octa_dtr(); + } + + pub async fn erase_sector(&mut self, addr: u32) { + info!("Erasing 4K sector at address: 0x{:X}", addr); + self.perform_erase_octa_dtr(addr, Self::CMD_SECTOR_ERASE_OCTA_DTR).await; + } + + pub async fn erase_block(&mut self, addr: u32) { + info!("Erasing 64K block at address: 0x{:X}", addr); + self.perform_erase_octa_dtr(addr, Self::CMD_BLOCK_ERASE_OCTA_DTR).await; + } + + async fn write_page_octa_dtr(&mut self, addr: u32, buffer: &[u8], len: usize, use_dma: bool) { + assert!( + (len as u32 + (addr & 0x000000ff)) <= Self::MEMORY_PAGE_SIZE as u32, + "write_page(): page write length exceeds page boundary (len = {}, addr = {:X}", + len, + addr + ); + + let transaction = TransferConfig { + iwidth: HspiWidth::OCTO, + instruction: Some(Self::CMD_PAGE_PROGRAM_OCTA_DTR as u32), + isize: AddressSize::_16Bit, + idtr: true, + adwidth: HspiWidth::OCTO, + address: Some(addr), + adsize: AddressSize::_32Bit, + addtr: true, + dwidth: HspiWidth::OCTO, + ddtr: true, + ..Default::default() + }; + self.write_enable_octa_dtr().await; + if use_dma { + self.hspi.write(buffer, transaction).await.unwrap(); + } else { + self.hspi.blocking_write(buffer, transaction).unwrap(); + } + self.wait_write_finish_octa_dtr(); + } + + pub async fn write_memory(&mut self, addr: u32, buffer: &[u8], use_dma: bool) { + let mut left = buffer.len(); + let mut place = addr; + let mut chunk_start = 0; + + while left > 0 { + let max_chunk_size = Self::MEMORY_PAGE_SIZE - (place & 0x000000ff) as usize; + let chunk_size = if left >= max_chunk_size { max_chunk_size } else { left }; + let chunk = &buffer[chunk_start..(chunk_start + chunk_size)]; + self.write_page_octa_dtr(place, chunk, chunk_size, use_dma).await; + place += chunk_size as u32; + left -= chunk_size; + chunk_start += chunk_size; + } + } + + pub fn read_sr_spi(&mut self) -> u8 { + let mut buffer = [0; 1]; + let transaction: TransferConfig = TransferConfig { + iwidth: HspiWidth::SING, + instruction: Some(Self::CMD_READ_SR as u32), + dwidth: HspiWidth::SING, + ..Default::default() + }; + self.hspi.blocking_read(&mut buffer, transaction).unwrap(); + // info!("Read MX66LM1G45G SR register: 0x{:x}", buffer[0]); + buffer[0] + } + + pub fn read_sr_octa_dtr(&mut self) -> u8 { + let mut buffer = [0; 2]; + let transaction: TransferConfig = TransferConfig { + iwidth: HspiWidth::OCTO, + instruction: Some(Self::CMD_READ_SR_OCTA_DTR as u32), + isize: AddressSize::_16Bit, + idtr: true, + adwidth: HspiWidth::OCTO, + address: Some(0), + adsize: AddressSize::_32Bit, + addtr: true, + dwidth: HspiWidth::OCTO, + ddtr: true, + dummy: DummyCycles::_5, + ..Default::default() + }; + self.hspi.blocking_read(&mut buffer, transaction).unwrap(); + // info!("Read MX66LM1G45G SR register: 0x{:x}", buffer[0]); + buffer[0] + } + + pub fn read_cr2_spi(&mut self, addr: u32) -> u8 { + let mut buffer = [0; 1]; + let transaction: TransferConfig = TransferConfig { + iwidth: HspiWidth::SING, + instruction: Some(Self::CMD_READ_CR2 as u32), + adwidth: HspiWidth::SING, + address: Some(addr), + adsize: AddressSize::_32Bit, + dwidth: HspiWidth::SING, + ..Default::default() + }; + self.hspi.blocking_read(&mut buffer, transaction).unwrap(); + // info!("Read MX66LM1G45G CR2[0x{:X}] register: 0x{:x}", addr, buffer[0]); + buffer[0] + } + + pub fn write_cr2_spi(&mut self, addr: u32, value: u8) { + let buffer = [value; 1]; + let transaction: TransferConfig = TransferConfig { + iwidth: HspiWidth::SING, + instruction: Some(Self::CMD_WRITE_CR2 as u32), + adwidth: HspiWidth::SING, + address: Some(addr), + adsize: AddressSize::_32Bit, + dwidth: HspiWidth::SING, + ..Default::default() + }; + self.hspi.blocking_write(&buffer, transaction).unwrap(); + } +} From d08116da49161e1f0db2b104553d50035c499be8 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 7 Jan 2025 22:00:41 +0100 Subject: [PATCH 0635/1217] Fix typo. --- embassy-stm32/src/ospi/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/src/ospi/mod.rs b/embassy-stm32/src/ospi/mod.rs index 33e19f4f8..e35d51c91 100644 --- a/embassy-stm32/src/ospi/mod.rs +++ b/embassy-stm32/src/ospi/mod.rs @@ -52,7 +52,7 @@ pub struct Config { /// Enables the transaction boundary feature and defines the boundary to release /// the chip select pub chip_select_boundary: u8, - /// Enbales the delay block bypass so the sampling is not affected by the delay block + /// Enables the delay block bypass so the sampling is not affected by the delay block pub delay_block_bypass: bool, /// Enables communication regulation feature. Chip select is released when the other /// OctoSpi requests access to the bus From 844d3b38de8160149ec9bb34359f69973a3dec99 Mon Sep 17 00:00:00 2001 From: Matt Rodgers Date: Wed, 8 Jan 2025 10:11:25 +0000 Subject: [PATCH 0636/1217] stm32: flash: fix flash erase on stm32f3xx series STM32F3xx series also needs a wait of at least one clock cycle before reading the BSY bit during a flash erase - previously this was only applied to STM32F1xx series. --- embassy-stm32/src/flash/f1f3.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/flash/f1f3.rs b/embassy-stm32/src/flash/f1f3.rs index ff7f810ea..ec237b9ff 100644 --- a/embassy-stm32/src/flash/f1f3.rs +++ b/embassy-stm32/src/flash/f1f3.rs @@ -64,8 +64,8 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E // BSY bit, because there is a one-cycle delay between // setting the STRT bit and the BSY bit being asserted // by hardware. See STM32F105xx, STM32F107xx device errata, - // section 2.2.8 - #[cfg(stm32f1)] + // section 2.2.8, and also RM0316 Rev 10 section 4.2.3 for + // STM32F3xx series. pac::FLASH.cr().read(); let mut ret: Result<(), Error> = wait_ready_blocking(); From ec2ab822b8fa23c1758bf40bd7ac276bfb1ab543 Mon Sep 17 00:00:00 2001 From: dragonn Date: Fri, 27 Dec 2024 21:18:59 +0100 Subject: [PATCH 0637/1217] nrf twim return errors in async_wait --- embassy-nrf/src/twim.rs | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/embassy-nrf/src/twim.rs b/embassy-nrf/src/twim.rs index ebad39df2..df1de83a2 100644 --- a/embassy-nrf/src/twim.rs +++ b/embassy-nrf/src/twim.rs @@ -85,6 +85,8 @@ pub enum Error { Overrun, /// Timeout error. Timeout, + /// Bus error. + Bus, } /// Interrupt handler. @@ -329,7 +331,7 @@ impl<'d, T: Instance> Twim<'d, T> { } /// Wait for stop or error - fn async_wait(&mut self) -> impl Future { + fn async_wait(&mut self) -> impl Future> { poll_fn(move |cx| { let r = T::regs(); let s = T::state(); @@ -338,13 +340,23 @@ impl<'d, T: Instance> Twim<'d, T> { if r.events_suspended().read() != 0 || r.events_stopped().read() != 0 { r.events_stopped().write_value(0); - return Poll::Ready(()); + return Poll::Ready(Ok(())); } // stop if an error occurred if r.events_error().read() != 0 { r.events_error().write_value(0); r.tasks_stop().write_value(1); + let errorsrc = r.errorsrc().read(); + if errorsrc.overrun() { + return Poll::Ready(Err(Error::Overrun)); + } else if errorsrc.anack() { + return Poll::Ready(Err(Error::AddressNack)); + } else if errorsrc.dnack() { + return Poll::Ready(Err(Error::DataNack)); + } else { + return Poll::Ready(Err(Error::Bus)); + } } Poll::Pending @@ -626,7 +638,7 @@ impl<'d, T: Instance> Twim<'d, T> { while !operations.is_empty() { let ops = self.setup_operations(address, operations, Some(&mut tx_ram_buffer), last_op, true)?; let (in_progress, rest) = operations.split_at_mut(ops); - self.async_wait().await; + self.async_wait().await?; self.check_operations(in_progress)?; last_op = in_progress.last(); operations = rest; @@ -644,7 +656,7 @@ impl<'d, T: Instance> Twim<'d, T> { while !operations.is_empty() { let ops = self.setup_operations(address, operations, None, last_op, true)?; let (in_progress, rest) = operations.split_at_mut(ops); - self.async_wait().await; + self.async_wait().await?; self.check_operations(in_progress)?; last_op = in_progress.last(); operations = rest; @@ -910,6 +922,7 @@ impl embedded_hal_1::i2c::Error for Error { } Self::Overrun => embedded_hal_1::i2c::ErrorKind::Overrun, Self::Timeout => embedded_hal_1::i2c::ErrorKind::Other, + Self::Bus => embedded_hal_1::i2c::ErrorKind::Other, } } } From 0316ef86cbda80f3f724b126c4e7860571b91d8a Mon Sep 17 00:00:00 2001 From: dragonn Date: Wed, 8 Jan 2025 14:19:25 +0100 Subject: [PATCH 0638/1217] use check_errorsrc instead of matching again on errorsrc bits --- embassy-nrf/src/twim.rs | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/embassy-nrf/src/twim.rs b/embassy-nrf/src/twim.rs index df1de83a2..687f53311 100644 --- a/embassy-nrf/src/twim.rs +++ b/embassy-nrf/src/twim.rs @@ -347,13 +347,8 @@ impl<'d, T: Instance> Twim<'d, T> { if r.events_error().read() != 0 { r.events_error().write_value(0); r.tasks_stop().write_value(1); - let errorsrc = r.errorsrc().read(); - if errorsrc.overrun() { - return Poll::Ready(Err(Error::Overrun)); - } else if errorsrc.anack() { - return Poll::Ready(Err(Error::AddressNack)); - } else if errorsrc.dnack() { - return Poll::Ready(Err(Error::DataNack)); + if let Err(e) = self.check_errorsrc() { + return Poll::Ready(Err(e)); } else { return Poll::Ready(Err(Error::Bus)); } From 5102b50be71888364dff366d650b406d7ae1f50e Mon Sep 17 00:00:00 2001 From: dragonn Date: Wed, 8 Jan 2025 14:55:37 +0100 Subject: [PATCH 0639/1217] remove self from check_errorsrc to make it work in async_wait --- embassy-nrf/src/twim.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/embassy-nrf/src/twim.rs b/embassy-nrf/src/twim.rs index 687f53311..708a69082 100644 --- a/embassy-nrf/src/twim.rs +++ b/embassy-nrf/src/twim.rs @@ -257,7 +257,7 @@ impl<'d, T: Instance> Twim<'d, T> { } /// Get Error instance, if any occurred. - fn check_errorsrc(&self) -> Result<(), Error> { + fn check_errorsrc() -> Result<(), Error> { let r = T::regs(); let err = r.errorsrc().read(); @@ -347,7 +347,7 @@ impl<'d, T: Instance> Twim<'d, T> { if r.events_error().read() != 0 { r.events_error().write_value(0); r.tasks_stop().write_value(1); - if let Err(e) = self.check_errorsrc() { + if let Err(e) = Self::check_errorsrc() { return Poll::Ready(Err(e)); } else { return Poll::Ready(Err(Error::Bus)); @@ -510,7 +510,7 @@ impl<'d, T: Instance> Twim<'d, T> { fn check_operations(&mut self, operations: &[Operation<'_>]) -> Result<(), Error> { compiler_fence(SeqCst); - self.check_errorsrc()?; + Self::check_errorsrc()?; assert!(operations.len() == 1 || operations.len() == 2); match operations { From 07fe3415f5204ecffd75dcede79e827f4e48717c Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Wed, 8 Jan 2025 18:55:22 +0100 Subject: [PATCH 0640/1217] nrf/gpio: fix missing setting input as disconnected. --- embassy-nrf/src/gpio.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/embassy-nrf/src/gpio.rs b/embassy-nrf/src/gpio.rs index 130339c15..cacaf1911 100644 --- a/embassy-nrf/src/gpio.rs +++ b/embassy-nrf/src/gpio.rs @@ -375,7 +375,9 @@ impl<'d> Flex<'d> { /// Put the pin into disconnected mode. #[inline] pub fn set_as_disconnected(&mut self) { - self.pin.conf().write(|_| ()); + self.pin.conf().write(|w| { + w.set_input(vals::Input::DISCONNECT); + }); } /// Get whether the pin input level is high. @@ -448,7 +450,7 @@ impl<'d> Flex<'d> { impl<'d> Drop for Flex<'d> { fn drop(&mut self) { - self.pin.conf().write(|_| ()) + self.set_as_disconnected(); } } @@ -591,7 +593,9 @@ pub(crate) fn deconfigure_pin(psel: Psel) { if psel.connect() == Connect::DISCONNECTED { return; } - unsafe { AnyPin::steal(psel.0 as _).conf().write(|_| ()) } + unsafe { AnyPin::steal(psel.0 as _) }.conf().write(|w| { + w.set_input(vals::Input::DISCONNECT); + }) } // ==================== From cd38669ac2239c484e181bbcc8e4804e9de28039 Mon Sep 17 00:00:00 2001 From: dragonn Date: Wed, 8 Jan 2025 19:08:58 +0100 Subject: [PATCH 0641/1217] panic when events_error is set in twim without errorsrc --- embassy-nrf/src/twim.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/embassy-nrf/src/twim.rs b/embassy-nrf/src/twim.rs index 708a69082..bfce00f1b 100644 --- a/embassy-nrf/src/twim.rs +++ b/embassy-nrf/src/twim.rs @@ -85,8 +85,6 @@ pub enum Error { Overrun, /// Timeout error. Timeout, - /// Bus error. - Bus, } /// Interrupt handler. @@ -350,7 +348,7 @@ impl<'d, T: Instance> Twim<'d, T> { if let Err(e) = Self::check_errorsrc() { return Poll::Ready(Err(e)); } else { - return Poll::Ready(Err(Error::Bus)); + panic!("Found events_error bit without an error in errorsrc reg"); } } @@ -917,7 +915,6 @@ impl embedded_hal_1::i2c::Error for Error { } Self::Overrun => embedded_hal_1::i2c::ErrorKind::Overrun, Self::Timeout => embedded_hal_1::i2c::ErrorKind::Other, - Self::Bus => embedded_hal_1::i2c::ErrorKind::Other, } } } From fb1368d9c84c035005e4cbbf2314391a3ffef387 Mon Sep 17 00:00:00 2001 From: Volkalex28 Date: Thu, 9 Jan 2025 11:02:47 +0200 Subject: [PATCH 0642/1217] Fix unsupported trace! call for EndpointAddress --- embassy-stm32/src/usb/usb.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/src/usb/usb.rs b/embassy-stm32/src/usb/usb.rs index 8be051968..b9a16bbf1 100644 --- a/embassy-stm32/src/usb/usb.rs +++ b/embassy-stm32/src/usb/usb.rs @@ -638,7 +638,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> { } fn endpoint_set_enabled(&mut self, ep_addr: EndpointAddress, enabled: bool) { - trace!("set_enabled {:x} {}", ep_addr, enabled); + trace!("set_enabled {:?} {}", ep_addr, enabled); // This can race, so do a retry loop. let reg = T::regs().epr(ep_addr.index() as _); trace!("EPR before: {:04x}", reg.read().0); From 9d94d68a7f2c92dc306ea6864ef518b6e73d15ec Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Thu, 9 Jan 2025 11:41:00 +0100 Subject: [PATCH 0643/1217] Create embassy-nrf 0.3.1 --- docs/examples/basic/Cargo.toml | 2 +- embassy-boot-nrf/Cargo.toml | 2 +- embassy-nrf/CHANGELOG.md | 5 +++++ embassy-nrf/Cargo.toml | 2 +- examples/boot/application/nrf/Cargo.toml | 2 +- examples/nrf-rtos-trace/Cargo.toml | 2 +- examples/nrf51/Cargo.toml | 2 +- examples/nrf52810/Cargo.toml | 2 +- examples/nrf52840-rtic/Cargo.toml | 2 +- examples/nrf52840/Cargo.toml | 2 +- examples/nrf5340/Cargo.toml | 2 +- examples/nrf54l15/Cargo.toml | 2 +- examples/nrf9151/ns/Cargo.toml | 2 +- examples/nrf9151/s/Cargo.toml | 2 +- examples/nrf9160/Cargo.toml | 2 +- tests/nrf/Cargo.toml | 2 +- 16 files changed, 20 insertions(+), 15 deletions(-) diff --git a/docs/examples/basic/Cargo.toml b/docs/examples/basic/Cargo.toml index 04d042250..705c334a7 100644 --- a/docs/examples/basic/Cargo.toml +++ b/docs/examples/basic/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-executor = { version = "0.7.0", path = "../../../embassy-executor", features = ["defmt", "arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.4.0", path = "../../../embassy-time", features = ["defmt"] } -embassy-nrf = { version = "0.3.0", path = "../../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote"] } +embassy-nrf = { version = "0.3.1", path = "../../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote"] } defmt = "0.3" defmt-rtt = "0.3" diff --git a/embassy-boot-nrf/Cargo.toml b/embassy-boot-nrf/Cargo.toml index e49bed15d..cb83ce2a4 100644 --- a/embassy-boot-nrf/Cargo.toml +++ b/embassy-boot-nrf/Cargo.toml @@ -25,7 +25,7 @@ defmt = { version = "0.3", optional = true } log = { version = "0.4.17", optional = true } embassy-sync = { version = "0.6.1", path = "../embassy-sync" } -embassy-nrf = { version = "0.3.0", path = "../embassy-nrf", default-features = false } +embassy-nrf = { version = "0.3.1", path = "../embassy-nrf", default-features = false } embassy-boot = { version = "0.4.0", path = "../embassy-boot" } cortex-m = { version = "0.7.6" } cortex-m-rt = { version = "0.7" } diff --git a/embassy-nrf/CHANGELOG.md b/embassy-nrf/CHANGELOG.md index e9eb1443a..b77688148 100644 --- a/embassy-nrf/CHANGELOG.md +++ b/embassy-nrf/CHANGELOG.md @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +## 0.3.1 - 2025-01-09 + +- bugfix: nrf twim return errors in async\_wait instead of waiting indefinitely +- bugfix: fix missing setting input as disconnected. + ## 0.3.0 - 2025-01-06 Firstly, this release switches embassy-nrf to chiptool-based `nrf-pac` diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml index 9f8cd85d8..aa1d53b67 100644 --- a/embassy-nrf/Cargo.toml +++ b/embassy-nrf/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "embassy-nrf" -version = "0.3.0" +version = "0.3.1" edition = "2021" license = "MIT OR Apache-2.0" description = "Embassy Hardware Abstraction Layer (HAL) for nRF series microcontrollers" diff --git a/examples/boot/application/nrf/Cargo.toml b/examples/boot/application/nrf/Cargo.toml index 7e57436ff..0680c9af3 100644 --- a/examples/boot/application/nrf/Cargo.toml +++ b/examples/boot/application/nrf/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["task-arena-size-16384", "arch-cortex-m", "executor-thread", "arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [] } -embassy-nrf = { version = "0.3.0", path = "../../../../embassy-nrf", features = ["time-driver-rtc1", "gpiote", ] } +embassy-nrf = { version = "0.3.1", path = "../../../../embassy-nrf", features = ["time-driver-rtc1", "gpiote", ] } embassy-boot = { version = "0.4.0", path = "../../../../embassy-boot", features = [] } embassy-boot-nrf = { version = "0.4.0", path = "../../../../embassy-boot-nrf", features = [] } embassy-embedded-hal = { version = "0.3.0", path = "../../../../embassy-embedded-hal" } diff --git a/examples/nrf-rtos-trace/Cargo.toml b/examples/nrf-rtos-trace/Cargo.toml index 66c0efe80..09cba5073 100644 --- a/examples/nrf-rtos-trace/Cargo.toml +++ b/examples/nrf-rtos-trace/Cargo.toml @@ -18,7 +18,7 @@ log = [ embassy-sync = { version = "0.6.1", path = "../../embassy-sync" } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "rtos-trace"] } embassy-time = { version = "0.4.0", path = "../../embassy-time" } -embassy-nrf = { version = "0.3.0", path = "../../embassy-nrf", features = ["nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] } +embassy-nrf = { version = "0.3.1", path = "../../embassy-nrf", features = ["nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] } cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } cortex-m-rt = "0.7.0" diff --git a/examples/nrf51/Cargo.toml b/examples/nrf51/Cargo.toml index a91280419..b6760a428 100644 --- a/examples/nrf51/Cargo.toml +++ b/examples/nrf51/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-4096", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } -embassy-nrf = { version = "0.3.0", path = "../../embassy-nrf", features = ["defmt", "nrf51", "gpiote", "time-driver-rtc1", "unstable-pac", "time", "rt"] } +embassy-nrf = { version = "0.3.1", path = "../../embassy-nrf", features = ["defmt", "nrf51", "gpiote", "time-driver-rtc1", "unstable-pac", "time", "rt"] } defmt = "0.3" defmt-rtt = "0.4" diff --git a/examples/nrf52810/Cargo.toml b/examples/nrf52810/Cargo.toml index d0590b559..bfeaf946f 100644 --- a/examples/nrf52810/Cargo.toml +++ b/examples/nrf52810/Cargo.toml @@ -9,7 +9,7 @@ embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } -embassy-nrf = { version = "0.3.0", path = "../../embassy-nrf", features = ["defmt", "nrf52810", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } +embassy-nrf = { version = "0.3.1", path = "../../embassy-nrf", features = ["defmt", "nrf52810", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } defmt = "0.3" defmt-rtt = "0.4" diff --git a/examples/nrf52840-rtic/Cargo.toml b/examples/nrf52840-rtic/Cargo.toml index 9703218a1..518ac06bd 100644 --- a/examples/nrf52840-rtic/Cargo.toml +++ b/examples/nrf52840-rtic/Cargo.toml @@ -11,7 +11,7 @@ embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = [ "defmt", "defmt-timestamp-uptime"] } embassy-time-queue-utils = { version = "0.1", path = "../../embassy-time-queue-utils", features = ["generic-queue-8"] } -embassy-nrf = { version = "0.3.0", path = "../../embassy-nrf", features = [ "defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } +embassy-nrf = { version = "0.3.1", path = "../../embassy-nrf", features = [ "defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } defmt = "0.3" defmt-rtt = "0.4" diff --git a/examples/nrf52840/Cargo.toml b/examples/nrf52840/Cargo.toml index 72d5c63f4..81d130ad3 100644 --- a/examples/nrf52840/Cargo.toml +++ b/examples/nrf52840/Cargo.toml @@ -9,7 +9,7 @@ embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } -embassy-nrf = { version = "0.3.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } +embassy-nrf = { version = "0.3.1", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } embassy-net = { version = "0.6.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embedded-io = { version = "0.6.0", features = ["defmt-03"] } diff --git a/examples/nrf5340/Cargo.toml b/examples/nrf5340/Cargo.toml index 237cfc69a..557a9127a 100644 --- a/examples/nrf5340/Cargo.toml +++ b/examples/nrf5340/Cargo.toml @@ -9,7 +9,7 @@ embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } -embassy-nrf = { version = "0.3.0", path = "../../embassy-nrf", features = ["defmt", "nrf5340-app-s", "time-driver-rtc1", "gpiote", "unstable-pac"] } +embassy-nrf = { version = "0.3.1", path = "../../embassy-nrf", features = ["defmt", "nrf5340-app-s", "time-driver-rtc1", "gpiote", "unstable-pac"] } embassy-net = { version = "0.6.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embedded-io-async = { version = "0.6.1" } diff --git a/examples/nrf54l15/Cargo.toml b/examples/nrf54l15/Cargo.toml index 3ee0c63e8..12808fc2a 100644 --- a/examples/nrf54l15/Cargo.toml +++ b/examples/nrf54l15/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } -embassy-nrf = { version = "0.3.0", path = "../../embassy-nrf", features = ["defmt", "nrf54l15-app-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } +embassy-nrf = { version = "0.3.1", path = "../../embassy-nrf", features = ["defmt", "nrf54l15-app-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } defmt = "0.3" defmt-rtt = "0.4" diff --git a/examples/nrf9151/ns/Cargo.toml b/examples/nrf9151/ns/Cargo.toml index c7a67fefc..27def8455 100644 --- a/examples/nrf9151/ns/Cargo.toml +++ b/examples/nrf9151/ns/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-executor = { version = "0.7.0", path = "../../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } -embassy-nrf = { version = "0.3.0", path = "../../../embassy-nrf", features = ["defmt", "nrf9120-ns", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } +embassy-nrf = { version = "0.3.1", path = "../../../embassy-nrf", features = ["defmt", "nrf9120-ns", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } defmt = "0.3" defmt-rtt = "0.4" diff --git a/examples/nrf9151/s/Cargo.toml b/examples/nrf9151/s/Cargo.toml index 967baa3cd..e57f199c6 100644 --- a/examples/nrf9151/s/Cargo.toml +++ b/examples/nrf9151/s/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-executor = { version = "0.7.0", path = "../../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } -embassy-nrf = { version = "0.3.0", path = "../../../embassy-nrf", features = ["defmt", "nrf9120-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } +embassy-nrf = { version = "0.3.1", path = "../../../embassy-nrf", features = ["defmt", "nrf9120-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } defmt = "0.3" defmt-rtt = "0.4" diff --git a/examples/nrf9160/Cargo.toml b/examples/nrf9160/Cargo.toml index 2e02671a7..0ed8faf3b 100644 --- a/examples/nrf9160/Cargo.toml +++ b/examples/nrf9160/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } -embassy-nrf = { version = "0.3.0", path = "../../embassy-nrf", features = ["defmt", "nrf9160-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } +embassy-nrf = { version = "0.3.1", path = "../../embassy-nrf", features = ["defmt", "nrf9160-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } embassy-net-nrf91 = { version = "0.1.0", path = "../../embassy-net-nrf91", features = ["defmt"] } embassy-net = { version = "0.6.0", path = "../../embassy-net", features = ["defmt", "tcp", "proto-ipv4", "medium-ip"] } diff --git a/tests/nrf/Cargo.toml b/tests/nrf/Cargo.toml index 390a594bc..030d24fbd 100644 --- a/tests/nrf/Cargo.toml +++ b/tests/nrf/Cargo.toml @@ -11,7 +11,7 @@ embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt", ] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } -embassy-nrf = { version = "0.3.0", path = "../../embassy-nrf", features = ["defmt", "time-driver-rtc1", "gpiote", "unstable-pac"] } +embassy-nrf = { version = "0.3.1", path = "../../embassy-nrf", features = ["defmt", "time-driver-rtc1", "gpiote", "unstable-pac"] } embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } embassy-net = { version = "0.6.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", ] } embassy-net-esp-hosted = { version = "0.2.0", path = "../../embassy-net-esp-hosted", features = ["defmt"] } From 593d9973e0cddad753aa62c072d425781d9101b4 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Fri, 10 Jan 2025 17:38:32 +0100 Subject: [PATCH 0644/1217] Release embassy-stm32 v0.2.0 --- .../layer-by-layer/blinky-async/Cargo.toml | 2 +- .../layer-by-layer/blinky-hal/Cargo.toml | 2 +- .../layer-by-layer/blinky-irq/Cargo.toml | 2 +- embassy-boot-stm32/Cargo.toml | 2 +- embassy-stm32-wpan/Cargo.toml | 2 +- embassy-stm32/CHANGELOG.md | 275 ++++++++++++++++++ embassy-stm32/Cargo.toml | 2 +- examples/boot/application/stm32f3/Cargo.toml | 2 +- examples/boot/application/stm32f7/Cargo.toml | 2 +- examples/boot/application/stm32h7/Cargo.toml | 2 +- examples/boot/application/stm32l0/Cargo.toml | 2 +- examples/boot/application/stm32l1/Cargo.toml | 2 +- examples/boot/application/stm32l4/Cargo.toml | 2 +- .../boot/application/stm32wb-dfu/Cargo.toml | 2 +- examples/boot/application/stm32wl/Cargo.toml | 2 +- examples/stm32c0/Cargo.toml | 2 +- examples/stm32f0/Cargo.toml | 2 +- examples/stm32f1/Cargo.toml | 2 +- examples/stm32f2/Cargo.toml | 2 +- examples/stm32f3/Cargo.toml | 2 +- examples/stm32f334/Cargo.toml | 2 +- examples/stm32f4/Cargo.toml | 2 +- examples/stm32f469/Cargo.toml | 2 +- examples/stm32f7/Cargo.toml | 2 +- examples/stm32g0/Cargo.toml | 2 +- examples/stm32g4/Cargo.toml | 2 +- examples/stm32h5/Cargo.toml | 2 +- examples/stm32h7/Cargo.toml | 2 +- examples/stm32h723/Cargo.toml | 2 +- examples/stm32h735/Cargo.toml | 2 +- examples/stm32h755cm4/Cargo.toml | 2 +- examples/stm32h755cm7/Cargo.toml | 2 +- examples/stm32h7b0/Cargo.toml | 2 +- examples/stm32h7rs/Cargo.toml | 2 +- examples/stm32l0/Cargo.toml | 2 +- examples/stm32l1/Cargo.toml | 2 +- examples/stm32l4/Cargo.toml | 2 +- examples/stm32l432/Cargo.toml | 2 +- examples/stm32l5/Cargo.toml | 2 +- examples/stm32u0/Cargo.toml | 2 +- examples/stm32u5/Cargo.toml | 2 +- examples/stm32wb/Cargo.toml | 2 +- examples/stm32wba/Cargo.toml | 2 +- examples/stm32wl/Cargo.toml | 2 +- tests/stm32/Cargo.toml | 2 +- 45 files changed, 319 insertions(+), 44 deletions(-) create mode 100644 embassy-stm32/CHANGELOG.md diff --git a/docs/examples/layer-by-layer/blinky-async/Cargo.toml b/docs/examples/layer-by-layer/blinky-async/Cargo.toml index f6d2e4fc7..2c3996e87 100644 --- a/docs/examples/layer-by-layer/blinky-async/Cargo.toml +++ b/docs/examples/layer-by-layer/blinky-async/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] cortex-m = "0.7" cortex-m-rt = "0.7" -embassy-stm32 = { version = "0.1.0", features = ["stm32l475vg", "memory-x", "exti"] } +embassy-stm32 = { version = "0.2.0", features = ["stm32l475vg", "memory-x", "exti"] } embassy-executor = { version = "0.6.3", features = ["arch-cortex-m", "executor-thread"] } defmt = "0.3.0" diff --git a/docs/examples/layer-by-layer/blinky-hal/Cargo.toml b/docs/examples/layer-by-layer/blinky-hal/Cargo.toml index c15de2db2..d8f94b69d 100644 --- a/docs/examples/layer-by-layer/blinky-hal/Cargo.toml +++ b/docs/examples/layer-by-layer/blinky-hal/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] cortex-m = "0.7" cortex-m-rt = "0.7" -embassy-stm32 = { version = "0.1.0", features = ["stm32l475vg", "memory-x"] } +embassy-stm32 = { version = "0.2.0", features = ["stm32l475vg", "memory-x"] } defmt = "0.3.0" defmt-rtt = "0.3.0" diff --git a/docs/examples/layer-by-layer/blinky-irq/Cargo.toml b/docs/examples/layer-by-layer/blinky-irq/Cargo.toml index 9733658b6..15153cab4 100644 --- a/docs/examples/layer-by-layer/blinky-irq/Cargo.toml +++ b/docs/examples/layer-by-layer/blinky-irq/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] cortex-m = "0.7" cortex-m-rt = { version = "0.7" } -embassy-stm32 = { version = "0.1.0", features = ["stm32l475vg", "memory-x", "unstable-pac"] } +embassy-stm32 = { version = "0.2.0", features = ["stm32l475vg", "memory-x", "unstable-pac"] } defmt = "0.3.0" defmt-rtt = "0.3.0" diff --git a/embassy-boot-stm32/Cargo.toml b/embassy-boot-stm32/Cargo.toml index e2d7c19cb..2d38ba8b1 100644 --- a/embassy-boot-stm32/Cargo.toml +++ b/embassy-boot-stm32/Cargo.toml @@ -25,7 +25,7 @@ defmt = { version = "0.3", optional = true } log = { version = "0.4", optional = true } embassy-sync = { version = "0.6.1", path = "../embassy-sync" } -embassy-stm32 = { version = "0.1.0", path = "../embassy-stm32", default-features = false } +embassy-stm32 = { version = "0.2.0", path = "../embassy-stm32", default-features = false } embassy-boot = { version = "0.4.0", path = "../embassy-boot" } cortex-m = { version = "0.7.6" } cortex-m-rt = { version = "0.7" } diff --git a/embassy-stm32-wpan/Cargo.toml b/embassy-stm32-wpan/Cargo.toml index 876fc92b9..19adc0e1b 100644 --- a/embassy-stm32-wpan/Cargo.toml +++ b/embassy-stm32-wpan/Cargo.toml @@ -19,7 +19,7 @@ features = ["stm32wb55rg", "ble", "mac"] features = ["stm32wb55rg", "ble", "mac"] [dependencies] -embassy-stm32 = { version = "0.1.0", path = "../embassy-stm32" } +embassy-stm32 = { version = "0.2.0", path = "../embassy-stm32" } embassy-sync = { version = "0.6.1", path = "../embassy-sync" } embassy-time = { version = "0.4.0", path = "../embassy-time", optional = true } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } diff --git a/embassy-stm32/CHANGELOG.md b/embassy-stm32/CHANGELOG.md new file mode 100644 index 000000000..10b0739fb --- /dev/null +++ b/embassy-stm32/CHANGELOG.md @@ -0,0 +1,275 @@ +# Changelog for embassy-stm32 + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## 0.2.0 - 2025-01-10 + +Starting 2025 strong with a release packed with new, exciting good stuff! 🚀 + +### New chips + +This release adds support for many newly-released STM32 chips. + +- STM32H7[RS] "bootflash line" ([#2898](https://github.com/embassy-rs/embassy/pull/2898)) +- STM32U0 ([#2809](https://github.com/embassy-rs/embassy/pull/2809) [#2813](https://github.com/embassy-rs/embassy/pull/2813)) +- STM32H5[23] ([#2892](https://github.com/embassy-rs/embassy/pull/2892)) +- STM32U5[FG] ([#2892](https://github.com/embassy-rs/embassy/pull/2892)) +- STM32WBA5[045] ([#2892](https://github.com/embassy-rs/embassy/pull/2892)) + +### Simpler APIs with less generics + +Many HAL APIs have been simplified thanks to reducing the amount of generic parameters. This helps with creating arrays of pins or peripherals, and for calling the same code with different pins/peripherals without incurring in code size penalties d + +For GPIO, the pins have been eliminated. `Output<'_, PA4>` is now `Output<'_>`. + +For peripherals, both pins and DMA channels have been eliminated. Peripherals now have a "mode" generic param that specifies whether it's capable of async operation. For example, `I2c<'_, I2C2, NoDma, NoDma>` is now `I2c<'_, Blocking>` and `I2c<'_, I2C2, DMA2_CH1, DMA2_CH2>` is now `I2c<'_, Async>`. + +- Removed DMA channel generic params for UART ([#2821](https://github.com/embassy-rs/embassy/pull/2821)), I2C ([#2820](https://github.com/embassy-rs/embassy/pull/2820)), SPI ([#2819](https://github.com/embassy-rs/embassy/pull/2819)), QSPI ([#2982](https://github.com/embassy-rs/embassy/pull/2982)), OSPI ([#2941](https://github.com/embassy-rs/embassy/pull/2941)). +- Removed peripheral generic params for GPIO ([#2471](https://github.com/embassy-rs/embassy/pull/2471)), UART ([#2836](https://github.com/embassy-rs/embassy/pull/2836)), I2C ([#2974](https://github.com/embassy-rs/embassy/pull/2974)), SPI ([#2835](https://github.com/embassy-rs/embassy/pull/2835)) +- Remove generics in CAN ([#3012](https://github.com/embassy-rs/embassy/pull/3012), [#3020](https://github.com/embassy-rs/embassy/pull/3020), [#3032](https://github.com/embassy-rs/embassy/pull/3032), [#3033](https://github.com/embassy-rs/embassy/pull/3033)) + +### More complete and consistent RCC + +RCC support has been vastly expanded and improved. +- The API is now consistent across all STM32 families. Previously in some families you'd configure the desired target frequencies for `sysclk` and the buses and `embassy-stm32` would try to calculate dividers and muxes to hit them as close as possible. This has proved to be intractable in the general case and hard to extend to more exotic RCC configurations. So, we have standardized on an API where the user specifies the settings for dividers and muxes directly. It's lower level but gices more control to the user, supports all edge case exotic configurations, and makes it easier to translate a configuration from the STM32CubeMX tool. ([Tracking issue](https://github.com/embassy-rs/embassy/issues/2515). [#2624](https://github.com/embassy-rs/embassy/pull/2624). F0, F1 [#2564](https://github.com/embassy-rs/embassy/pull/2564), F3 [#2560](https://github.com/embassy-rs/embassy/pull/2560), U5 [#2617](https://github.com/embassy-rs/embassy/pull/2617), [#3514](https://github.com/embassy-rs/embassy/pull/3514), [#3513](https://github.com/embassy-rs/embassy/pull/3513), G4 [#2579](https://github.com/embassy-rs/embassy/pull/2579), [#2618](https://github.com/embassy-rs/embassy/pull/2618), WBA [#2520](https://github.com/embassy-rs/embassy/pull/2520), G0, C0 ([#2656](https://github.com/embassy-rs/embassy/pull/2656)). +- Added support for configuring all per-peripheral clock muxes (CCIPRx, DCKCFGRx registers) in `config.rcc.mux`. This was previously handled in an ad-hoc way in some drivers (e.g. USB) and not at all in others (causing e.g. wrong SPI frequency) ([#2521](https://github.com/embassy-rs/embassy/pull/2521), [#2583](https://github.com/embassy-rs/embassy/pull/2583), [#2634](https://github.com/embassy-rs/embassy/pull/2634), [#2626](https://github.com/embassy-rs/embassy/pull/2626), [#2815](https://github.com/embassy-rs/embassy/pull/2815), [#2517](https://github.com/embassy-rs/embassy/pull/2517)). +- Switch to a safe configuration before configuring RCC. This helps avoid crashes when RCC has been already configured previously (for example by a bootloader). (F2, F4, F7 [#2829](https://github.com/embassy-rs/embassy/pull/2829), C0, F0, F1, F3, G0, G4, H5, H7[#3008](https://github.com/embassy-rs/embassy/pull/3008)) +- Some new nice features: + - Expose RCC enable and disable in public API. ([#2807](https://github.com/embassy-rs/embassy/pull/2807)) + - Add `unchecked-overclocking` feature that disables all asserts, allowing running RCC out of spec. ([#3574](https://github.com/embassy-rs/embassy/pull/3574)) +- Many fixes: + - Workaround H5 errata that accidentally clears RAM on backup domain reset. ([#2616](https://github.com/embassy-rs/embassy/pull/2616)) + - Reset RTC on L0 ([#2597](https://github.com/embassy-rs/embassy/pull/2597)) + - Fix H7 to use correct unit in vco clock check ([#2537](https://github.com/embassy-rs/embassy/pull/2537)) + - Fix incorrect D1CPRE max for STM32H7 RM0468 ([#2518](https://github.com/embassy-rs/embassy/pull/2518)) + - WBA's high speed external clock has to run at 32 MHz ([#2511](https://github.com/embassy-rs/embassy/pull/2511)) + - Take into account clock propagation delay to peripherals after enabling a clock. ([#2677](https://github.com/embassy-rs/embassy/pull/2677)) + - Fix crash caused by using higher MSI range as sysclk on STM32WL ([#2786](https://github.com/embassy-rs/embassy/pull/2786)) + - fix using HSI48 as SYSCLK on F0 devices with CRS ([#3652](https://github.com/embassy-rs/embassy/pull/3652)) + - compute LSE and LSI frequency for STM32L and STM32U0 series ([#3554](https://github.com/embassy-rs/embassy/pull/3554)) + - Add support for LSESYS, used to pass LSE clock to peripherals ([#3518](https://github.com/embassy-rs/embassy/pull/3518)) + - H5: LSE low drive mode is not functional ([#2738](https://github.com/embassy-rs/embassy/pull/2738)) + +### New peripheral drivers + +- Dual-core support. First core initializes RCC and writes a struct into shared memory that the second core uses, ensuring no conflicts. ([#3158](https://github.com/embassy-rs/embassy/pull/3158), [#3263](https://github.com/embassy-rs/embassy/pull/3263), [#3687](https://github.com/embassy-rs/embassy/pull/3687)) +- USB Type-C/USB Power Delivery Interface (UCPD) ([#2652](https://github.com/embassy-rs/embassy/pull/2652), [#2683](https://github.com/embassy-rs/embassy/pull/2683), [#2701](https://github.com/embassy-rs/embassy/pull/2701), [#2925](https://github.com/embassy-rs/embassy/pull/2925), [#3084](https://github.com/embassy-rs/embassy/pull/3084), [#3271](https://github.com/embassy-rs/embassy/pull/3271), [#3678](https://github.com/embassy-rs/embassy/pull/3678), [#3714](https://github.com/embassy-rs/embassy/pull/3714)) +- Touch sensing controller (TSC) ([#2853](https://github.com/embassy-rs/embassy/pull/2853), [#3111](https://github.com/embassy-rs/embassy/pull/3111), [#3163](https://github.com/embassy-rs/embassy/pull/3163), [#3274](https://github.com/embassy-rs/embassy/pull/3274)) +- Display Serial Interface (DSI) [#2903](https://github.com/embassy-rs/embassy/pull/2903), ([#3082](https://github.com/embassy-rs/embassy/pull/3082)) +- LCD/TFT Display Controller (LTDC) ([#3126](https://github.com/embassy-rs/embassy/pull/3126), [#3458](https://github.com/embassy-rs/embassy/pull/3458)) +- SPDIF receiver (SPDIFRX) ([#3280](https://github.com/embassy-rs/embassy/pull/3280)) +- CORDIC math accelerator ([#2697](https://github.com/embassy-rs/embassy/pull/2697)) +- Digital Temperature Sensor (DTS) ([#3717](https://github.com/embassy-rs/embassy/pull/3717)) +- HMAC accelerator ([#2565](https://github.com/embassy-rs/embassy/pull/2565)) +- Hash accelerator ([#2528](https://github.com/embassy-rs/embassy/pull/2528)) +- Crypto accelerator ([#2619](https://github.com/embassy-rs/embassy/pull/2619), [#2691](https://github.com/embassy-rs/embassy/pull/2691)) +- Semaphore (HSEM) ([#2777](https://github.com/embassy-rs/embassy/pull/2777), [#3161](https://github.com/embassy-rs/embassy/pull/3161)) + +### Improvements to existing drivers + +GPIO: +- Generate singletons only for pins that actually exist. ([#3738](https://github.com/embassy-rs/embassy/pull/3738)) +- Add `set_as_analog` to Flex ([#3017](https://github.com/embassy-rs/embassy/pull/3017)) +- Add `embedded-hal` v0.2 `InputPin` impls for `OutputOpenDrain`. ([#2716](https://github.com/embassy-rs/embassy/pull/2716)) +- Add a config option to make the VDDIO2 supply line valid ([#2737](https://github.com/embassy-rs/embassy/pull/2737)) +- Refactor AfType ([#3031](https://github.com/embassy-rs/embassy/pull/3031)) +- Gpiov1: Do not call set_speed for AFType::Input ([#2996](https://github.com/embassy-rs/embassy/pull/2996)) + +UART: +- Add embedded-io impls ([#2739](https://github.com/embassy-rs/embassy/pull/2739)) +- Add support for changing baud rate ([#3512](https://github.com/embassy-rs/embassy/pull/3512)) +- Add split_ref ([#3500](https://github.com/embassy-rs/embassy/pull/3500)) +- Add data bit selection ([#3595](https://github.com/embassy-rs/embassy/pull/3595)) +- Add RX Pull configuration option ([#3415](https://github.com/embassy-rs/embassy/pull/3415)) +- Add async flush ([#3379](https://github.com/embassy-rs/embassy/pull/3379)) +- Add support for sending breaks ([#3286](https://github.com/embassy-rs/embassy/pull/3286)) +- Disconnect pins on drop ([#3006](https://github.com/embassy-rs/embassy/pull/3006)) +- Half-duplex improvements + - Add half-duplex for all USART versions ([#2833](https://github.com/embassy-rs/embassy/pull/2833)) + - configurable readback for half-duplex. ([#3679](https://github.com/embassy-rs/embassy/pull/3679)) + - Convert uart half_duplex to use user configurable IO ([#3233](https://github.com/embassy-rs/embassy/pull/3233)) + - Fix uart::flush with FIFO at Half-Duplex mode ([#2895](https://github.com/embassy-rs/embassy/pull/2895)) + - Fix Half-Duplex sequential reads and writes ([#3089](https://github.com/embassy-rs/embassy/pull/3089)) + - disable transmitter during during half-duplex flush ([#3299](https://github.com/embassy-rs/embassy/pull/3299)) +- Buffered UART improvements + - Add embedded-io ReadReady impls ([#3179](https://github.com/embassy-rs/embassy/pull/3179), [#3451](https://github.com/embassy-rs/embassy/pull/3451)) + - Add constructors for RS485 ([#3441](https://github.com/embassy-rs/embassy/pull/3441)) + - Fix RingBufferedUartRx hard-resetting DMA after initial error ([#3356](https://github.com/embassy-rs/embassy/pull/3356)) + - Don't teardown during reconfigure ([#2989](https://github.com/embassy-rs/embassy/pull/2989)) + - Wake receive task for each received byte ([#2722](https://github.com/embassy-rs/embassy/pull/2722)) + - Fix dma and idle line detection in ringbuffereduartrx ([#3319](https://github.com/embassy-rs/embassy/pull/3319)) + +SPI: +- Add MISO pullup configuration option ([#2943](https://github.com/embassy-rs/embassy/pull/2943)) +- Add slew rate configuration options ([#3669](https://github.com/embassy-rs/embassy/pull/3669)) +- Fix blocking_write on nosck spi. ([#3035](https://github.com/embassy-rs/embassy/pull/3035)) +- Restrict txonly_nosck to SPIv1, it hangs in other versions. ([#3028](https://github.com/embassy-rs/embassy/pull/3028)) +- Fix non-u8 word sizes. ([#3363](https://github.com/embassy-rs/embassy/pull/3363)) +- Issue correct DMA word length when reading to prevent hang. ([#3362](https://github.com/embassy-rs/embassy/pull/3362)) +- Add proper rxonly support for spi_v3 and force tx dma stream requirements. ([#3007](https://github.com/embassy-rs/embassy/pull/3007)) + +I2C: +- Implement asynchronous transactions ([#2742](https://github.com/embassy-rs/embassy/pull/2742)) +- Implement blocking transactions ([#2713](https://github.com/embassy-rs/embassy/pull/2713)) +- Disconnect pins on drop ([#3006](https://github.com/embassy-rs/embassy/pull/3006)) +- Ensure bus is free before master-write operation ([#3104](https://github.com/embassy-rs/embassy/pull/3104)) +- Add workaround for STM32 i2cv1 errata ([#2887](https://github.com/embassy-rs/embassy/pull/2887)) +- Fix disabling pullup accidentally enabling pulldown ([#3410](https://github.com/embassy-rs/embassy/pull/3410)) + +Flash: +- Add L5 support ([#3423](https://github.com/embassy-rs/embassy/pull/3423)) +- Add H5 support ([#3305](https://github.com/embassy-rs/embassy/pull/3305)) +- add F2 support ([#3303](https://github.com/embassy-rs/embassy/pull/3303)) +- Add U5 support ([#2591](https://github.com/embassy-rs/embassy/pull/2591), [#2792](https://github.com/embassy-rs/embassy/pull/2792)) +- Add H50x support ([#2600](https://github.com/embassy-rs/embassy/pull/2600), [#2808](https://github.com/embassy-rs/embassy/pull/2808)) +- Fix flash erase on F3 ([#3744](https://github.com/embassy-rs/embassy/pull/3744)) +- Support G0 second flash bank ([#3711](https://github.com/embassy-rs/embassy/pull/3711)) +- F1, F3: wait for BSY flag to clear before flashing ([#3217](https://github.com/embassy-rs/embassy/pull/3217)) +- H7: enhance resilience to program sequence errors (pgserr) ([#2539](https://github.com/embassy-rs/embassy/pull/2539)) + +ADC: +- Add `AnyAdcChannel` type. You can obtain it from a pin with `.degrade_adc()`. Useful for making arrays of ADC pins. ([#2985](https://github.com/embassy-rs/embassy/pull/2985)) +- Add L0 support ([#2544](https://github.com/embassy-rs/embassy/pull/2544)) +- Add U5 support ([#3688](https://github.com/embassy-rs/embassy/pull/3688)) +- Add H5 support ([#2613](https://github.com/embassy-rs/embassy/pull/2613), [#3557](https://github.com/embassy-rs/embassy/pull/3557)) +- Add G4 async support ([#3566](https://github.com/embassy-rs/embassy/pull/3566)) +- Add G4 support for calibrating differential inputs ([#3735](https://github.com/embassy-rs/embassy/pull/3735)) +- Add oversampling and differential support for G4 ([#3169](https://github.com/embassy-rs/embassy/pull/3169)) +- Add DMA support for ADC v2 ([#3116](https://github.com/embassy-rs/embassy/pull/3116)) +- Add DMA support for ADC v3 and v4 ([#3128](https://github.com/embassy-rs/embassy/pull/3128)) +- Unify naming `blocking_read` for blocking, `read` for async. ([#3148](https://github.com/embassy-rs/embassy/pull/3148)) +- Fix channel count for the STM32G4 ADCs. ([#2828](https://github.com/embassy-rs/embassy/pull/2828)) +- Fix blocking_delay_us() overflowing when sys freq is high ([#2825](https://github.com/embassy-rs/embassy/pull/2825)) +- Remove need for taking a `Delay` impl. ([#2797](https://github.com/embassy-rs/embassy/pull/2797)) +- H5: set OR.OP0 to 1 when ADCx_INP0 is selected, per RM ([#2776](https://github.com/embassy-rs/embassy/pull/2776)) +- Add oversampling support ([#3124](https://github.com/embassy-rs/embassy/pull/3124)) +- Adc averaging support for ADC v4. ([#3110](https://github.com/embassy-rs/embassy/pull/3110)) +- F2 ADC fixes ([#2513](https://github.com/embassy-rs/embassy/pull/2513)) + +DAC: +- Fix new_internal not setting mode as documented ([#2886](https://github.com/embassy-rs/embassy/pull/2886)) + +OPAMP: +- Add missing opamp external outputs for STM32G4 ([#3636](https://github.com/embassy-rs/embassy/pull/3636)) +- Add extra lifetime to opamp-using structs ([#3207](https://github.com/embassy-rs/embassy/pull/3207)) +- Make OpAmp usable in follower configuration for internal DAC channel ([#3021](https://github.com/embassy-rs/embassy/pull/3021)) + +CAN: +- Add FDCAN support. ([#2475](https://github.com/embassy-rs/embassy/pull/2475), [#2571](https://github.com/embassy-rs/embassy/pull/2571), [#2623](https://github.com/embassy-rs/embassy/pull/2623), [#2631](https://github.com/embassy-rs/embassy/pull/2631), [#2635](https://github.com/embassy-rs/embassy/pull/2635), [#2637](https://github.com/embassy-rs/embassy/pull/2637), [#2645](https://github.com/embassy-rs/embassy/pull/2645), [#2647](https://github.com/embassy-rs/embassy/pull/2647), [#2658](https://github.com/embassy-rs/embassy/pull/2658), [#2703](https://github.com/embassy-rs/embassy/pull/2703), [#3364](https://github.com/embassy-rs/embassy/pull/3364)) +- Simplify BXCAN API, make BXCAN and FDCAN APIs consistent. ([#2760](https://github.com/embassy-rs/embassy/pull/2760), [#2693](https://github.com/embassy-rs/embassy/pull/2693), [#2744](https://github.com/embassy-rs/embassy/pull/2744)) +- Add buffered mode support ([#2588](https://github.com/embassy-rs/embassy/pull/2588)) +- Add support for modifying the receiver filters from `BufferedCan`, `CanRx`, and `BufferedCanRx` ([#3733](https://github.com/embassy-rs/embassy/pull/3733)) +- Add support for optional FIFO scheduling for outgoing frames ([#2988](https://github.com/embassy-rs/embassy/pull/2988)) +- fdcan: Properties for common runtime get/set operations ([#2840](https://github.com/embassy-rs/embassy/pull/2840)) +- fdcan: implement bus-off recovery ([#2832](https://github.com/embassy-rs/embassy/pull/2832)) +- Add BXCAN sleep/wakeup functionality ([#2854](https://github.com/embassy-rs/embassy/pull/2854)) +- Fix BXCAN hangs ([#3468](https://github.com/embassy-rs/embassy/pull/3468)) +- add RTR flag if it is remote frame ([#3421](https://github.com/embassy-rs/embassy/pull/3421)) +- Fix log storm when no CAN is connected ([#3284](https://github.com/embassy-rs/embassy/pull/3284)) +- Fix error handling ([#2850](https://github.com/embassy-rs/embassy/pull/2850)) +- Give CAN a kick when writing into TX buffer via sender. ([#2646](https://github.com/embassy-rs/embassy/pull/2646)) +- Preseve the RTR flag in messages. ([#2745](https://github.com/embassy-rs/embassy/pull/2745)) + +FMC: +- Add 13bit address sdram constructors ([#3189](https://github.com/embassy-rs/embassy/pull/3189)) + +xSPI: +- Add OCTOSPI support ([#2672](https://github.com/embassy-rs/embassy/pull/2672)) +- Add OCTOSPIM support ([#3102](https://github.com/embassy-rs/embassy/pull/3102)) +- Add HEXADECASPI support ([#3667](https://github.com/embassy-rs/embassy/pull/3667)) +- Add memory mapping support for QSPI ([#3725](https://github.com/embassy-rs/embassy/pull/3725)) +- Add memory mapping support for OCTOSPI ([#3456](https://github.com/embassy-rs/embassy/pull/3456)) +- Add async support for QSPI ([#3475](https://github.com/embassy-rs/embassy/pull/3475)) +- Fix QSPI synchronous read operation hangs when FIFO is not full ([#3724](https://github.com/embassy-rs/embassy/pull/3724)) +- Stick to `blocking_*` naming convention for QSPI, OSPI ([#3661](https://github.com/embassy-rs/embassy/pull/3661)) + +SDMMC: +- Add `block-device-driver` impl for use with `embedded-fatfs` ([#2607](https://github.com/embassy-rs/embassy/pull/2607)) +- Allow cmd block to be passed in for sdmmc dma transfers ([#3188](https://github.com/embassy-rs/embassy/pull/3188)) + +ETH: +- Fix reception of multicast packets ([#3488](https://github.com/embassy-rs/embassy/pull/3488), [#3707](https://github.com/embassy-rs/embassy/pull/3707)) +- Add support for executing custom SMI commands ([#3355](https://github.com/embassy-rs/embassy/pull/3355)) +- Add support for MII interface ([#2465](https://github.com/embassy-rs/embassy/pull/2465)) + +USB: +- Assert correct clock on init. ([#2711](https://github.com/embassy-rs/embassy/pull/2711)) +- Set PWR_CR2 USV on STM32L4 ([#2605](https://github.com/embassy-rs/embassy/pull/2605)) +- USBD driver improvements: + - Add ISO endpoint support ([#3314](https://github.com/embassy-rs/embassy/pull/3314)) + - Add support for L1. ([#2452](https://github.com/embassy-rs/embassy/pull/2452)) + - set USB initialization delay to 1µs ([#3700](https://github.com/embassy-rs/embassy/pull/3700)) +- OTG driver improvements: + - Add ISO endpoint support ([#3314](https://github.com/embassy-rs/embassy/pull/3314)) + - Add support for U595, U5A5 ([#3613](https://github.com/embassy-rs/embassy/pull/3613)) + - Add support for STM32H7R/S ([#3337](https://github.com/embassy-rs/embassy/pull/3337)) + - Add support for full-speed ULPI mode ([#3281](https://github.com/embassy-rs/embassy/pull/3281)) + - Make max EP count configurable ([#2881](https://github.com/embassy-rs/embassy/pull/2881)) + - fix corruption in CONTROL OUT transfers in stm32f4. ([#3565](https://github.com/embassy-rs/embassy/pull/3565)) + - Extract Synopsys USB OTG driver to a separate crate ([#2871](https://github.com/embassy-rs/embassy/pull/2871)) + - Add critical sections to avoid USB OTG corruption Errata ([#2823](https://github.com/embassy-rs/embassy/pull/2823)) + - Fix support for OTG_HS in FS mode. ([#2805](https://github.com/embassy-rs/embassy/pull/2805)) + +I2S: +- Add SPIv3 support. ([#2992](https://github.com/embassy-rs/embassy/pull/2992)) +- Add full-duplex support. ([#2992](https://github.com/embassy-rs/embassy/pull/2992)) +- Add I2S ringbuffered DMA support ([#3023](https://github.com/embassy-rs/embassy/pull/3023)) +- Fix STM32F4 I2S clock calculations ([#3716](https://github.com/embassy-rs/embassy/pull/3716)) + +SAI: +- Add a function that waits for any SAI/ringbuffer write error ([#3545](https://github.com/embassy-rs/embassy/pull/3545)) +- Disallow start without an initial write ([#3541](https://github.com/embassy-rs/embassy/pull/3541)) +- Flush FIFO on init and disable ([#3538](https://github.com/embassy-rs/embassy/pull/3538)) +- Fix MCKDIV for SAI v3/v4 ([#2710](https://github.com/embassy-rs/embassy/pull/2710)) +- Pull down clock and data lines in receive mode ([#3326](https://github.com/embassy-rs/embassy/pull/3326)) +- Add function to check if SAI is muted ([#3282](https://github.com/embassy-rs/embassy/pull/3282)) + +Low-power support: +- Update `embassy-executor` to v0.7. +- Add support for U0 ([#3556](https://github.com/embassy-rs/embassy/pull/3556)) +- Add support for U5 ([#3496](https://github.com/embassy-rs/embassy/pull/3496)) +- Add support for H5 ([#2877](https://github.com/embassy-rs/embassy/pull/2877)) +- Add support for L4 ([#3213](https://github.com/embassy-rs/embassy/pull/3213)) +- Fix low-power EXTI IRQ handler dropped edges ([#3404](https://github.com/embassy-rs/embassy/pull/3404)) +- Fix alarms not triggering in some cases ([#3592](https://github.com/embassy-rs/embassy/pull/3592)) + +Timer: +- Add Input Capture high-level driver ([#2912](https://github.com/embassy-rs/embassy/pull/2912)) +- Add PWM Input high-level driver ([#3014](https://github.com/embassy-rs/embassy/pull/3014)) +- Add support for splitting `SimplePwm` into channels ([#3317](https://github.com/embassy-rs/embassy/pull/3317)) +- Fix `SimplePwm` not enabling output pin in some stm32 families ([#2670](https://github.com/embassy-rs/embassy/pull/2670)) +- Add LPTIM low-level driver. ([#3310](https://github.com/embassy-rs/embassy/pull/3310)) +- Low-level TIM driver improvements: + - Simplify traits, convert from trait methods to struct. ([#2728](https://github.com/embassy-rs/embassy/pull/2728)) + - Add `low_level::Timer::get_clock_frequency()` ([#2908](https://github.com/embassy-rs/embassy/pull/2908)) + - Fix 32bit timer off by one ARR error ([#2876](https://github.com/embassy-rs/embassy/pull/2876)) + - Avoid max_compare_value >= u16::MAX ([#3549](https://github.com/embassy-rs/embassy/pull/3549)) + +DMA: +- Add `AnyChannel` type. Similar to `AnyPin`, it allows representing any DMA channel at runtime without needing generics. ([#2606](https://github.com/embassy-rs/embassy/pull/2606)) +, Add support for BDMA on H7 ([#2606](https://github.com/embassy-rs/embassy/pull/2606)) +- Add async `stop()` function to BDMA, DMA ([#2757](https://github.com/embassy-rs/embassy/pull/2757)) +- Add configuration option for DMA Request Priority ([#2680](https://github.com/embassy-rs/embassy/pull/2680)) +- Rewrite DMA ringbuffers ([#3336](https://github.com/embassy-rs/embassy/pull/3336)) +- Enable half transfer IRQ when constructing a ReadableDmaRingBuffer ([#3093](https://github.com/embassy-rs/embassy/pull/3093)) +- Right-align `write_immediate()` in ring buffers ([#3588](https://github.com/embassy-rs/embassy/pull/3588)) + +`embassy-time` driver: +- Update to `embassy-time` v0.4, `embassy-time-driver` v0.2. ([#3593](https://github.com/embassy-rs/embassy/pull/3593)) +- Change preference order of `time-driver-any` to pick less-featureful timers first. ([#2570](https://github.com/embassy-rs/embassy/pull/2570)) +- Allow using more TIMx timers for the time driver of TIM1 ([#2570](https://github.com/embassy-rs/embassy/pull/2570), [#2614](https://github.com/embassy-rs/embassy/pull/2614)) +- Correctly gate `time` feature of embassy-embedded-hal in embassy-stm32 ([#3359](https://github.com/embassy-rs/embassy/pull/3359)) +- adds timer-driver for tim21 and tim22 (on L0) ([#2450](https://github.com/embassy-rs/embassy/pull/2450)) + +WDG: +- Allow higher PSC value for iwdg_v3 ... ([#2628](https://github.com/embassy-rs/embassy/pull/2628)) + +Misc: +- Allow `bind_interrupts!` to accept conditional compilation attrs ([#3444](https://github.com/embassy-rs/embassy/pull/3444)) + +## 0.1.0 - 2024-01-12 + +First release. \ No newline at end of file diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index cf336e4d0..c1dfea201 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "embassy-stm32" -version = "0.1.0" +version = "0.2.0" edition = "2021" license = "MIT OR Apache-2.0" description = "Embassy Hardware Abstraction Layer (HAL) for ST STM32 series microcontrollers" diff --git a/examples/boot/application/stm32f3/Cargo.toml b/examples/boot/application/stm32f3/Cargo.toml index c49dd8335..35a8544fd 100644 --- a/examples/boot/application/stm32f3/Cargo.toml +++ b/examples/boot/application/stm32f3/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } -embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32f303re", "time-driver-any", "exti"] } +embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32f303re", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32" } embassy-embedded-hal = { version = "0.3.0", path = "../../../../embassy-embedded-hal" } diff --git a/examples/boot/application/stm32f7/Cargo.toml b/examples/boot/application/stm32f7/Cargo.toml index a14536e9e..dee1139df 100644 --- a/examples/boot/application/stm32f7/Cargo.toml +++ b/examples/boot/application/stm32f7/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } -embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32f767zi", "time-driver-any", "exti"] } +embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32f767zi", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } embassy-embedded-hal = { version = "0.3.0", path = "../../../../embassy-embedded-hal" } diff --git a/examples/boot/application/stm32h7/Cargo.toml b/examples/boot/application/stm32h7/Cargo.toml index f7b9f630e..f0899cd86 100644 --- a/examples/boot/application/stm32h7/Cargo.toml +++ b/examples/boot/application/stm32h7/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } -embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32h743zi", "time-driver-any", "exti"] } +embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32h743zi", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } embassy-embedded-hal = { version = "0.3.0", path = "../../../../embassy-embedded-hal" } diff --git a/examples/boot/application/stm32l0/Cargo.toml b/examples/boot/application/stm32l0/Cargo.toml index 75eaf8312..fd4732742 100644 --- a/examples/boot/application/stm32l0/Cargo.toml +++ b/examples/boot/application/stm32l0/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } -embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l072cz", "time-driver-any", "exti", "memory-x"] } +embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32l072cz", "time-driver-any", "exti", "memory-x"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } embassy-embedded-hal = { version = "0.3.0", path = "../../../../embassy-embedded-hal" } diff --git a/examples/boot/application/stm32l1/Cargo.toml b/examples/boot/application/stm32l1/Cargo.toml index 93d651f3c..5792c87d6 100644 --- a/examples/boot/application/stm32l1/Cargo.toml +++ b/examples/boot/application/stm32l1/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } -embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l151cb-a", "time-driver-any", "exti"] } +embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32l151cb-a", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } embassy-embedded-hal = { version = "0.3.0", path = "../../../../embassy-embedded-hal" } diff --git a/examples/boot/application/stm32l4/Cargo.toml b/examples/boot/application/stm32l4/Cargo.toml index 20f521084..d2b600560 100644 --- a/examples/boot/application/stm32l4/Cargo.toml +++ b/examples/boot/application/stm32l4/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } -embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l475vg", "time-driver-any", "exti"] } +embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32l475vg", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } embassy-embedded-hal = { version = "0.3.0", path = "../../../../embassy-embedded-hal" } diff --git a/examples/boot/application/stm32wb-dfu/Cargo.toml b/examples/boot/application/stm32wb-dfu/Cargo.toml index 70d854953..b3170de54 100644 --- a/examples/boot/application/stm32wb-dfu/Cargo.toml +++ b/examples/boot/application/stm32wb-dfu/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } -embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32wb55rg", "time-driver-any", "exti"] } +embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32wb55rg", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } embassy-embedded-hal = { version = "0.3.0", path = "../../../../embassy-embedded-hal" } embassy-usb = { version = "0.3.0", path = "../../../../embassy-usb" } diff --git a/examples/boot/application/stm32wl/Cargo.toml b/examples/boot/application/stm32wl/Cargo.toml index 8981690af..59ef48edc 100644 --- a/examples/boot/application/stm32wl/Cargo.toml +++ b/examples/boot/application/stm32wl/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } -embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32wl55jc-cm4", "time-driver-any", "exti"] } +embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32wl55jc-cm4", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } embassy-embedded-hal = { version = "0.3.0", path = "../../../../embassy-embedded-hal" } diff --git a/examples/stm32c0/Cargo.toml b/examples/stm32c0/Cargo.toml index 21a6882ac..3f0aa632f 100644 --- a/examples/stm32c0/Cargo.toml +++ b/examples/stm32c0/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32c031c6 to your chip name, if necessary. -embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32c031c6", "memory-x", "unstable-pac", "exti"] } +embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32c031c6", "memory-x", "unstable-pac", "exti"] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } diff --git a/examples/stm32f0/Cargo.toml b/examples/stm32f0/Cargo.toml index 9bfc9701d..2f7246e29 100644 --- a/examples/stm32f0/Cargo.toml +++ b/examples/stm32f0/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32f091rc to your chip name, if necessary. -embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "memory-x", "stm32f091rc", "time-driver-tim2", "exti", "unstable-pac"] } +embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [ "defmt", "memory-x", "stm32f091rc", "time-driver-tim2", "exti", "unstable-pac"] } cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } cortex-m-rt = "0.7.0" defmt = "0.3" diff --git a/examples/stm32f1/Cargo.toml b/examples/stm32f1/Cargo.toml index 4211a07a7..191c16ed9 100644 --- a/examples/stm32f1/Cargo.toml +++ b/examples/stm32f1/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32f103c8 to your chip name, if necessary. -embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f103c8", "unstable-pac", "memory-x", "time-driver-any" ] } +embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f103c8", "unstable-pac", "memory-x", "time-driver-any" ] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } diff --git a/examples/stm32f2/Cargo.toml b/examples/stm32f2/Cargo.toml index 8b53b2f90..50b2cd67c 100644 --- a/examples/stm32f2/Cargo.toml +++ b/examples/stm32f2/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32f207zg to your chip name, if necessary. -embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f207zg", "unstable-pac", "memory-x", "time-driver-any", "exti"] } +embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f207zg", "unstable-pac", "memory-x", "time-driver-any", "exti"] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } diff --git a/examples/stm32f3/Cargo.toml b/examples/stm32f3/Cargo.toml index 60ec05f36..aa60ca692 100644 --- a/examples/stm32f3/Cargo.toml +++ b/examples/stm32f3/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32f303ze to your chip name, if necessary. -embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f303ze", "unstable-pac", "memory-x", "time-driver-tim2", "exti"] } +embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f303ze", "unstable-pac", "memory-x", "time-driver-tim2", "exti"] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } diff --git a/examples/stm32f334/Cargo.toml b/examples/stm32f334/Cargo.toml index 02306c683..54aa20a9e 100644 --- a/examples/stm32f334/Cargo.toml +++ b/examples/stm32f334/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } -embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f334r8", "unstable-pac", "memory-x", "time-driver-any", "exti"] } +embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f334r8", "unstable-pac", "memory-x", "time-driver-any", "exti"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32f4/Cargo.toml b/examples/stm32f4/Cargo.toml index 72cd0d7f5..355e264a1 100644 --- a/examples/stm32f4/Cargo.toml +++ b/examples/stm32f4/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32f429zi to your chip name, if necessary. -embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32f429zi", "unstable-pac", "memory-x", "time-driver-tim4", "exti", "chrono"] } +embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = ["defmt", "stm32f429zi", "unstable-pac", "memory-x", "time-driver-tim4", "exti", "chrono"] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } diff --git a/examples/stm32f469/Cargo.toml b/examples/stm32f469/Cargo.toml index 01984f594..2c0c9a6c8 100644 --- a/examples/stm32f469/Cargo.toml +++ b/examples/stm32f469/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Specific examples only for stm32f469 -embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32f469ni", "unstable-pac", "memory-x", "time-driver-any", "exti", "chrono"] } +embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = ["defmt", "stm32f469ni", "unstable-pac", "memory-x", "time-driver-any", "exti", "chrono"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } diff --git a/examples/stm32f7/Cargo.toml b/examples/stm32f7/Cargo.toml index f9f2ae9a4..d195088e7 100644 --- a/examples/stm32f7/Cargo.toml +++ b/examples/stm32f7/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32f777zi to your chip name, if necessary. -embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32f777zi", "memory-x", "unstable-pac", "time-driver-any", "exti"] } +embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = ["defmt", "stm32f777zi", "memory-x", "unstable-pac", "time-driver-any", "exti"] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } diff --git a/examples/stm32g0/Cargo.toml b/examples/stm32g0/Cargo.toml index 4aa665d64..de96e576f 100644 --- a/examples/stm32g0/Cargo.toml +++ b/examples/stm32g0/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32g0b1re to your chip name, if necessary. -embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32g0b1re", "memory-x", "unstable-pac", "exti"] } +embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32g0b1re", "memory-x", "unstable-pac", "exti"] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } diff --git a/examples/stm32g4/Cargo.toml b/examples/stm32g4/Cargo.toml index 83974f1af..411d91cc5 100644 --- a/examples/stm32g4/Cargo.toml +++ b/examples/stm32g4/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32g491re to your chip name, if necessary. -embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32g491re", "memory-x", "unstable-pac", "exti"] } +embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32g491re", "memory-x", "unstable-pac", "exti"] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } diff --git a/examples/stm32h5/Cargo.toml b/examples/stm32h5/Cargo.toml index 8d43c4c1a..cdc26c3ab 100644 --- a/examples/stm32h5/Cargo.toml +++ b/examples/stm32h5/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32h563zi to your chip name, if necessary. -embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h563zi", "memory-x", "time-driver-any", "exti", "unstable-pac", "low-power"] } +embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = ["defmt", "stm32h563zi", "memory-x", "time-driver-any", "exti", "unstable-pac", "low-power"] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } diff --git a/examples/stm32h7/Cargo.toml b/examples/stm32h7/Cargo.toml index 0dbaf28ce..341e8d307 100644 --- a/examples/stm32h7/Cargo.toml +++ b/examples/stm32h7/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32h743bi to your chip name, if necessary. -embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h743bi", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } +embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = ["defmt", "stm32h743bi", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-embedded-hal = { version = "0.3.0", path = "../../embassy-embedded-hal" } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } diff --git a/examples/stm32h723/Cargo.toml b/examples/stm32h723/Cargo.toml index 95a9c4a3d..e9ff3a352 100644 --- a/examples/stm32h723/Cargo.toml +++ b/examples/stm32h723/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32h723zg to your chip name, if necessary. -embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h723zg", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } +embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = ["defmt", "stm32h723zg", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } diff --git a/examples/stm32h735/Cargo.toml b/examples/stm32h735/Cargo.toml index 99e2c1049..e3e07e086 100644 --- a/examples/stm32h735/Cargo.toml +++ b/examples/stm32h735/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h735ig", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } +embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = ["defmt", "stm32h735ig", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-embedded-hal = { version = "0.3.0", path = "../../embassy-embedded-hal" } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } diff --git a/examples/stm32h755cm4/Cargo.toml b/examples/stm32h755cm4/Cargo.toml index 699561214..7705a5852 100644 --- a/examples/stm32h755cm4/Cargo.toml +++ b/examples/stm32h755cm4/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32h755zi-cm4 to your chip name, if necessary. -embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h755zi-cm4", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } +embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = ["defmt", "stm32h755zi-cm4", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-embedded-hal = { version = "0.3.0", path = "../../embassy-embedded-hal" } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } diff --git a/examples/stm32h755cm7/Cargo.toml b/examples/stm32h755cm7/Cargo.toml index 1f830ec6b..87546eb12 100644 --- a/examples/stm32h755cm7/Cargo.toml +++ b/examples/stm32h755cm7/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32h743bi to your chip name, if necessary. -embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h755zi-cm7", "time-driver-tim3", "exti", "memory-x", "unstable-pac", "chrono"] } +embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = ["defmt", "stm32h755zi-cm7", "time-driver-tim3", "exti", "memory-x", "unstable-pac", "chrono"] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-embedded-hal = { version = "0.3.0", path = "../../embassy-embedded-hal" } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } diff --git a/examples/stm32h7b0/Cargo.toml b/examples/stm32h7b0/Cargo.toml index a1b96baa9..df92ce072 100644 --- a/examples/stm32h7b0/Cargo.toml +++ b/examples/stm32h7b0/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h7b0vb", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } +embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = ["defmt", "stm32h7b0vb", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-embedded-hal = { version = "0.3.0", path = "../../embassy-embedded-hal" } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } diff --git a/examples/stm32h7rs/Cargo.toml b/examples/stm32h7rs/Cargo.toml index bd41827a5..817e1b4a8 100644 --- a/examples/stm32h7rs/Cargo.toml +++ b/examples/stm32h7rs/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32h743bi to your chip name, if necessary. -embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h7s3l8", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } +embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = ["defmt", "stm32h7s3l8", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } diff --git a/examples/stm32l0/Cargo.toml b/examples/stm32l0/Cargo.toml index 3acc62e96..5d99de570 100644 --- a/examples/stm32l0/Cargo.toml +++ b/examples/stm32l0/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32l072cz to your chip name, if necessary. -embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32l073rz", "unstable-pac", "time-driver-any", "exti", "memory-x"] } +embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = ["defmt", "stm32l073rz", "unstable-pac", "time-driver-any", "exti", "memory-x"] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } diff --git a/examples/stm32l1/Cargo.toml b/examples/stm32l1/Cargo.toml index 67a7dfbe8..1317be6e3 100644 --- a/examples/stm32l1/Cargo.toml +++ b/examples/stm32l1/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } -embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32l151cb-a", "time-driver-any", "memory-x"] } +embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [ "defmt", "stm32l151cb-a", "time-driver-any", "memory-x"] } embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32l4/Cargo.toml b/examples/stm32l4/Cargo.toml index 4e210a35d..52a6df324 100644 --- a/examples/stm32l4/Cargo.toml +++ b/examples/stm32l4/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32l4s5vi to your chip name, if necessary. -embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32l4r5zi", "memory-x", "time-driver-any", "exti", "chrono"] } +embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32l4r5zi", "memory-x", "time-driver-any", "exti", "chrono"] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768", ] } diff --git a/examples/stm32l432/Cargo.toml b/examples/stm32l432/Cargo.toml index 460561b36..87ee392a1 100644 --- a/examples/stm32l432/Cargo.toml +++ b/examples/stm32l432/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32l4s5vi to your chip name, if necessary. -embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32l432kc", "memory-x", "time-driver-any", "exti", "chrono"] } +embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32l432kc", "memory-x", "time-driver-any", "exti", "chrono"] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = [ "defmt" ] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = [ "task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt" ] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = [ "defmt", "defmt-timestamp-uptime", "tick-hz-32_768" ] } diff --git a/examples/stm32l5/Cargo.toml b/examples/stm32l5/Cargo.toml index 7572fed3f..39d434720 100644 --- a/examples/stm32l5/Cargo.toml +++ b/examples/stm32l5/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32l552ze to your chip name, if necessary. -embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32l552ze", "time-driver-any", "exti", "memory-x", "low-power"] } +embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32l552ze", "time-driver-any", "exti", "memory-x", "low-power"] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } diff --git a/examples/stm32u0/Cargo.toml b/examples/stm32u0/Cargo.toml index 1813881ba..9b03b3971 100644 --- a/examples/stm32u0/Cargo.toml +++ b/examples/stm32u0/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32u083rc to your chip name, if necessary. -embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32u083rc", "memory-x", "unstable-pac", "exti", "chrono"] } +embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32u083rc", "memory-x", "unstable-pac", "exti", "chrono"] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } diff --git a/examples/stm32u5/Cargo.toml b/examples/stm32u5/Cargo.toml index f56ee024e..4aee08986 100644 --- a/examples/stm32u5/Cargo.toml +++ b/examples/stm32u5/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32u5g9zj to your chip name, if necessary. -embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "unstable-pac", "stm32u5g9zj", "time-driver-any", "memory-x" ] } +embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = ["defmt", "unstable-pac", "stm32u5g9zj", "time-driver-any", "memory-x" ] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } diff --git a/examples/stm32wb/Cargo.toml b/examples/stm32wb/Cargo.toml index 268e9347b..a61acb9ea 100644 --- a/examples/stm32wb/Cargo.toml +++ b/examples/stm32wb/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32wb55rg to your chip name in both dependencies, if necessary. -embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32wb55rg", "time-driver-any", "memory-x", "exti"] } +embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [ "defmt", "stm32wb55rg", "time-driver-any", "memory-x", "exti"] } embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", features = ["defmt", "stm32wb55rg"] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] } diff --git a/examples/stm32wba/Cargo.toml b/examples/stm32wba/Cargo.toml index 00c8b92d5..8af3db095 100644 --- a/examples/stm32wba/Cargo.toml +++ b/examples/stm32wba/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32wba52cg", "time-driver-any", "memory-x", "exti"] } +embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [ "defmt", "stm32wba52cg", "time-driver-any", "memory-x", "exti"] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } diff --git a/examples/stm32wl/Cargo.toml b/examples/stm32wl/Cargo.toml index 379fdc572..ead72bf04 100644 --- a/examples/stm32wl/Cargo.toml +++ b/examples/stm32wl/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32wl55jc-cm4 to your chip name, if necessary. -embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32wl55jc-cm4", "time-driver-any", "memory-x", "unstable-pac", "exti", "chrono"] } +embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = ["defmt", "stm32wl55jc-cm4", "time-driver-any", "memory-x", "unstable-pac", "exti", "chrono"] } embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-4096", "arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml index 5537969a4..f064e8057 100644 --- a/tests/stm32/Cargo.toml +++ b/tests/stm32/Cargo.toml @@ -62,7 +62,7 @@ teleprobe-meta = "1" embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "tick-hz-131_072", "defmt-timestamp-uptime"] } -embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "memory-x", "time-driver-any"] } +embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "memory-x", "time-driver-any"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", optional = true, features = ["defmt", "stm32wb55rg", "ble"] } embassy-net = { version = "0.6.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "dhcpv4", "medium-ethernet"] } From 793eb72cf29635a54de1325a0ad70f7938dcfbc7 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Fri, 10 Jan 2025 18:12:41 +0100 Subject: [PATCH 0645/1217] Update stm32-metapac, actually release embassy-stm32 v0.2.0 --- embassy-stm32/Cargo.toml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index c1dfea201..163524343 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -72,8 +72,8 @@ futures-util = { version = "0.3.30", default-features = false } rand_core = "0.6.3" sdio-host = "0.5.0" critical-section = "1.1" -#stm32-metapac = { version = "15" } -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-db71f6aa03b7db26548b461d3844fc404d40c98c" } +stm32-metapac = { version = "16" } +#stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-db71f6aa03b7db26548b461d3844fc404d40c98c" } vcell = "0.1.3" nb = "1.0.0" @@ -101,8 +101,8 @@ proptest-state-machine = "0.3.0" proc-macro2 = "1.0.36" quote = "1.0.15" -#stm32-metapac = { version = "15", default-features = false, features = ["metadata"]} -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-db71f6aa03b7db26548b461d3844fc404d40c98c", default-features = false, features = ["metadata"] } +stm32-metapac = { version = "16", default-features = false, features = ["metadata"]} +#stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-db71f6aa03b7db26548b461d3844fc404d40c98c", default-features = false, features = ["metadata"] } [features] default = ["rt"] From 6003582bebf07bcfcf57b957e897697d35a8b46c Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Fri, 10 Jan 2025 21:51:29 +0100 Subject: [PATCH 0646/1217] docs: add intro to embassy by therustybits --- docs/pages/overview.adoc | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/pages/overview.adoc b/docs/pages/overview.adoc index 8f97d937f..6e9e58ad3 100644 --- a/docs/pages/overview.adoc +++ b/docs/pages/overview.adoc @@ -80,4 +80,5 @@ For more reading material on async Rust and Embassy: Videos: +* link:https://www.youtube.com/watch?v=pDd5mXBF4tY[Intro to Embassy] * link:https://www.youtube.com/watch?v=wni5h5vIPhU[From Zero to Async in Embedded Rust] From 9cd2deba4d7da2b607613c98b004896512e9aabf Mon Sep 17 00:00:00 2001 From: Diego Barrios Romero Date: Sat, 11 Jan 2025 16:23:30 +0100 Subject: [PATCH 0647/1217] Fix typo --- docs/pages/overview.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/pages/overview.adoc b/docs/pages/overview.adoc index 6e9e58ad3..6ac0e0b2b 100644 --- a/docs/pages/overview.adoc +++ b/docs/pages/overview.adoc @@ -6,7 +6,7 @@ Embassy is a project to make async/await a first-class option for embedded devel When handling I/O, software must call functions that block program execution until the I/O operation completes. When running inside of an OS such as Linux, such functions generally transfer control to the kernel so that another task (known as a “threadâ€) can be executed if available, or the CPU can be put to sleep until another task is ready. -Because an OS cannot presume that threads will behave cooperatively, threads are relatively resource-intensive, and may be forcibly interrupted they do not transfer control back to the kernel within an allotted time. If tasks could be presumed to behave cooperatively, or at least not maliciously, it would be possible to create tasks that appear to be almost free when compared to a traditional OS thread. +Because an OS cannot presume that threads will behave cooperatively, threads are relatively resource-intensive, and may be forcibly interrupted if they do not transfer control back to the kernel within an allotted time. If tasks could be presumed to behave cooperatively, or at least not maliciously, it would be possible to create tasks that appear to be almost free when compared to a traditional OS thread. In other programming languages, these lightweight tasks are known as “coroutines†or â€goroutinesâ€. In Rust, they are implemented with async. Async-await works by transforming each async function into an object called a future. When a future blocks on I/O the future yields, and the scheduler, called an executor, can select a different future to execute. From 31b50e6291256d8ec2ba88af771d9711855156a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Pol=C3=A1=C4=8Dek?= Date: Sun, 12 Jan 2025 15:06:06 +0100 Subject: [PATCH 0648/1217] Fix year in changelog --- embassy-executor/CHANGELOG.md | 2 +- embassy-time-driver/CHANGELOG.md | 2 +- embassy-time/CHANGELOG.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/embassy-executor/CHANGELOG.md b/embassy-executor/CHANGELOG.md index 2c7f8c62e..5d2468c58 100644 --- a/embassy-executor/CHANGELOG.md +++ b/embassy-executor/CHANGELOG.md @@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## 0.7.0 - 2024-01-02 +## 0.7.0 - 2025-01-02 - Performance optimizations. - Remove feature `integrated-timers`. Starting with `embassy-time-driver` v0.2, `embassy-time` v0.4 the timer queue is now part of the time driver, so it's no longer the executor's responsibility. Therefore, `embassy-executor` no longer provides an `embassy-time-queue-driver` implementation. diff --git a/embassy-time-driver/CHANGELOG.md b/embassy-time-driver/CHANGELOG.md index e251a6020..744b0f648 100644 --- a/embassy-time-driver/CHANGELOG.md +++ b/embassy-time-driver/CHANGELOG.md @@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## 0.2.0 - 2024-01-02 +## 0.2.0 - 2025-01-02 - The `allocate_alarm`, `set_alarm_callback`, `set_alarm` functions have been removed. - `schedule_wake` has been added to the `Driver` trait. diff --git a/embassy-time/CHANGELOG.md b/embassy-time/CHANGELOG.md index 215ec27af..09e951ce4 100644 --- a/embassy-time/CHANGELOG.md +++ b/embassy-time/CHANGELOG.md @@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## 0.4.0 - 2024-01-02 +## 0.4.0 - 2025-01-02 - `embassy-time-driver` updated from v0.1 to v0.2. - embassy-time no longer provides an `embassy-time-queue-driver` implementation From 31e0794e79daec4f990acc2b6cbf41a48283cebb Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sun, 12 Jan 2025 20:51:17 +0100 Subject: [PATCH 0649/1217] Simplify some std examples. --- examples/std/src/bin/net_ppp.rs | 52 +----------------------------- examples/std/src/bin/tcp_accept.rs | 17 ++-------- 2 files changed, 3 insertions(+), 66 deletions(-) diff --git a/examples/std/src/bin/net_ppp.rs b/examples/std/src/bin/net_ppp.rs index ea3fbebef..f667e8d4c 100644 --- a/examples/std/src/bin/net_ppp.rs +++ b/examples/std/src/bin/net_ppp.rs @@ -45,7 +45,7 @@ async fn net_task(mut runner: embassy_net::Runner<'static, embassy_net_ppp::Devi async fn ppp_task(stack: Stack<'static>, mut runner: Runner<'static>, port: SerialPort) -> ! { let port = Async::new(port).unwrap(); let port = BufReader::new(port); - let port = adapter::FromFutures::new(port); + let port = embedded_io_adapters::futures_03::FromFutures::new(port); let config = embassy_net_ppp::Config { username: b"myuser", @@ -163,53 +163,3 @@ fn main() { spawner.spawn(main_task(spawner)).unwrap(); }); } - -mod adapter { - use core::future::poll_fn; - use core::pin::Pin; - - use futures::AsyncBufReadExt; - - /// Adapter from `futures::io` traits. - #[derive(Clone)] - pub struct FromFutures { - inner: T, - } - - impl FromFutures { - /// Create a new adapter. - pub fn new(inner: T) -> Self { - Self { inner } - } - } - - impl embedded_io_async::ErrorType for FromFutures { - type Error = std::io::Error; - } - - impl embedded_io_async::Read for FromFutures { - async fn read(&mut self, buf: &mut [u8]) -> Result { - poll_fn(|cx| Pin::new(&mut self.inner).poll_read(cx, buf)).await - } - } - - impl embedded_io_async::BufRead for FromFutures { - async fn fill_buf(&mut self) -> Result<&[u8], Self::Error> { - self.inner.fill_buf().await - } - - fn consume(&mut self, amt: usize) { - Pin::new(&mut self.inner).consume(amt) - } - } - - impl embedded_io_async::Write for FromFutures { - async fn write(&mut self, buf: &[u8]) -> Result { - poll_fn(|cx| Pin::new(&mut self.inner).poll_write(cx, buf)).await - } - - async fn flush(&mut self) -> Result<(), Self::Error> { - poll_fn(|cx| Pin::new(&mut self.inner).poll_flush(cx)).await - } - } -} diff --git a/examples/std/src/bin/tcp_accept.rs b/examples/std/src/bin/tcp_accept.rs index 5d36b739d..18646a083 100644 --- a/examples/std/src/bin/tcp_accept.rs +++ b/examples/std/src/bin/tcp_accept.rs @@ -1,5 +1,3 @@ -use core::fmt::Write as _; - use clap::Parser; use embassy_executor::{Executor, Spawner}; use embassy_net::tcp::TcpSocket; @@ -28,16 +26,6 @@ async fn net_task(mut runner: embassy_net::Runner<'static, TunTapDevice>) -> ! { runner.run().await } -#[derive(Default)] -struct StrWrite(pub heapless::Vec); - -impl core::fmt::Write for StrWrite { - fn write_str(&mut self, s: &str) -> Result<(), core::fmt::Error> { - self.0.extend_from_slice(s.as_bytes()).unwrap(); - Ok(()) - } -} - #[embassy_executor::task] async fn main_task(spawner: Spawner) { let opts: Opts = Opts::parse(); @@ -85,9 +73,8 @@ async fn main_task(spawner: Spawner) { // Write some quick output for i in 1..=5 { - let mut w = StrWrite::default(); - write!(w, "{}! ", i).unwrap(); - let r = socket.write_all(&w.0).await; + let s = format!("{}! ", i); + let r = socket.write_all(s.as_bytes()).await; if let Err(e) = r { warn!("write error: {:?}", e); return; From 2ce56e9999287e8dcb9ac8d7a5825f21efba8d21 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sun, 12 Jan 2025 20:55:59 +0100 Subject: [PATCH 0650/1217] Release embassy-net-ppp v0.2. --- embassy-net-ppp/CHANGELOG.md | 15 +++++++++++++++ embassy-net-ppp/Cargo.toml | 4 ++-- examples/std/Cargo.toml | 2 +- 3 files changed, 18 insertions(+), 3 deletions(-) create mode 100644 embassy-net-ppp/CHANGELOG.md diff --git a/embassy-net-ppp/CHANGELOG.md b/embassy-net-ppp/CHANGELOG.md new file mode 100644 index 000000000..6ce64ddcb --- /dev/null +++ b/embassy-net-ppp/CHANGELOG.md @@ -0,0 +1,15 @@ +# Changelog for embassy-net-ppp + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## 0.2.0 - 2025-01-12 + +- Update `ppproto` to v0.2. +- Use `core::net` IP types for IPv4 configuration instead of a custom type. + +## 0.1.0 - 2024-01-12 + +First release. diff --git a/embassy-net-ppp/Cargo.toml b/embassy-net-ppp/Cargo.toml index 9c214d5ae..414be5e01 100644 --- a/embassy-net-ppp/Cargo.toml +++ b/embassy-net-ppp/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "embassy-net-ppp" -version = "0.1.0" +version = "0.2.0" description = "embassy-net driver for PPP over Serial" keywords = ["embedded", "ppp", "embassy-net", "embedded-hal-async", "async"] categories = ["embedded", "hardware-support", "no-std", "network-programming", "asynchronous"] @@ -20,7 +20,7 @@ log = { version = "0.4.14", optional = true } embedded-io-async = { version = "0.6.1" } embassy-net-driver-channel = { version = "0.3.0", path = "../embassy-net-driver-channel" } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } -ppproto = { version = "0.2.0"} +ppproto = { version = "0.2.1"} embassy-sync = { version = "0.6.1", path = "../embassy-sync" } [package.metadata.embassy_docs] diff --git a/examples/std/Cargo.toml b/examples/std/Cargo.toml index 44b62a616..3c9b571cd 100644 --- a/examples/std/Cargo.toml +++ b/examples/std/Cargo.toml @@ -10,7 +10,7 @@ embassy-executor = { version = "0.7.0", path = "../../embassy-executor", feature embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["log", "std", ] } embassy-net = { version = "0.6.0", path = "../../embassy-net", features=[ "log", "medium-ethernet", "medium-ip", "tcp", "udp", "dns", "dhcpv4", "proto-ipv6"] } embassy-net-tuntap = { version = "0.1.0", path = "../../embassy-net-tuntap" } -embassy-net-ppp = { version = "0.1.0", path = "../../embassy-net-ppp", features = ["log"]} +embassy-net-ppp = { version = "0.2.0", path = "../../embassy-net-ppp", features = ["log"]} embedded-io-async = { version = "0.6.1" } embedded-io-adapters = { version = "0.6.1", features = ["futures-03"] } critical-section = { version = "1.1", features = ["std"] } From 13b205ece275ecc8e3f020bd687af62df3f03e34 Mon Sep 17 00:00:00 2001 From: Samuel O'Brien Date: Sun, 12 Jan 2025 20:50:16 -0600 Subject: [PATCH 0651/1217] rp: Fix time driver hang --- embassy-rp/src/time_driver.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/embassy-rp/src/time_driver.rs b/embassy-rp/src/time_driver.rs index aa5d564e7..5aaca03d7 100644 --- a/embassy-rp/src/time_driver.rs +++ b/embassy-rp/src/time_driver.rs @@ -86,6 +86,9 @@ impl TimerDriver { fn check_alarm(&self) { let n = 0; critical_section::with(|cs| { + // clear the irq + TIMER.intr().write(|w| w.set_alarm(n, true)); + let alarm = &self.alarms.borrow(cs); let timestamp = alarm.timestamp.get(); if timestamp <= self.now() { @@ -97,8 +100,6 @@ impl TimerDriver { } }); - // clear the irq - TIMER.intr().write(|w| w.set_alarm(n, true)); } fn trigger_alarm(&self, cs: CriticalSection) { From 930af8efb710dd1c81a1002e3a47f6abcfb83ebb Mon Sep 17 00:00:00 2001 From: Samuel O'Brien Date: Sun, 12 Jan 2025 20:56:08 -0600 Subject: [PATCH 0652/1217] run rustfmt --- embassy-rp/src/time_driver.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/embassy-rp/src/time_driver.rs b/embassy-rp/src/time_driver.rs index 5aaca03d7..d598287a9 100644 --- a/embassy-rp/src/time_driver.rs +++ b/embassy-rp/src/time_driver.rs @@ -99,7 +99,6 @@ impl TimerDriver { TIMER.alarm(n).write_value(timestamp as u32); } }); - } fn trigger_alarm(&self, cs: CriticalSection) { From 1c9fa804929d3418292b55d653c489f50eec3805 Mon Sep 17 00:00:00 2001 From: dimi Date: Mon, 13 Jan 2025 11:30:49 +0100 Subject: [PATCH 0653/1217] stm32: impl Display for time::Hertz --- embassy-stm32/src/time.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/embassy-stm32/src/time.rs b/embassy-stm32/src/time.rs index 802ff41ce..71fe668a9 100644 --- a/embassy-stm32/src/time.rs +++ b/embassy-stm32/src/time.rs @@ -1,5 +1,6 @@ //! Time units +use core::fmt::Display; use core::ops::{Div, Mul}; /// Hertz @@ -7,6 +8,12 @@ use core::ops::{Div, Mul}; #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct Hertz(pub u32); +impl Display for Hertz { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{} Hz", self.0) + } +} + impl Hertz { /// Create a `Hertz` from the given hertz. pub const fn hz(hertz: u32) -> Self { From 4b0e20315bddbb15aaee0e0b96548de405694c7b Mon Sep 17 00:00:00 2001 From: wackazong Date: Mon, 13 Jan 2025 18:52:01 +0100 Subject: [PATCH 0654/1217] Add Clone to Pull --- embassy-nrf/src/gpio.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-nrf/src/gpio.rs b/embassy-nrf/src/gpio.rs index cacaf1911..c78fa4df5 100644 --- a/embassy-nrf/src/gpio.rs +++ b/embassy-nrf/src/gpio.rs @@ -30,7 +30,7 @@ pub enum Port { } /// Pull setting for an input. -#[derive(Debug, Eq, PartialEq)] +#[derive(Clone, Copy, Debug, Eq, PartialEq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum Pull { /// No pull. From 05df319a82c8b30458c6ccda40b831ed846310e0 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Wed, 15 Jan 2025 00:58:55 +0100 Subject: [PATCH 0655/1217] Release embassy-usb v0.4.0, embassy-usb-logger v0.4.0. --- embassy-usb-dfu/Cargo.toml | 2 +- embassy-usb-logger/CHANGELOG.md | 21 ++++++++----------- embassy-usb-logger/Cargo.toml | 4 ++-- embassy-usb/CHANGELOG.md | 13 ++++++++++++ embassy-usb/Cargo.toml | 2 +- .../boot/application/stm32wb-dfu/Cargo.toml | 2 +- .../boot/bootloader/stm32wb-dfu/Cargo.toml | 2 +- examples/nrf52840/Cargo.toml | 2 +- examples/nrf5340/Cargo.toml | 2 +- examples/rp/Cargo.toml | 4 ++-- examples/rp23/Cargo.toml | 4 ++-- examples/stm32f1/Cargo.toml | 2 +- examples/stm32f3/Cargo.toml | 2 +- examples/stm32f334/Cargo.toml | 2 +- examples/stm32f4/Cargo.toml | 2 +- examples/stm32f7/Cargo.toml | 2 +- examples/stm32g0/Cargo.toml | 2 +- examples/stm32g4/Cargo.toml | 2 +- examples/stm32h5/Cargo.toml | 2 +- examples/stm32h7/Cargo.toml | 2 +- examples/stm32h755cm4/Cargo.toml | 2 +- examples/stm32h755cm7/Cargo.toml | 2 +- examples/stm32h7b0/Cargo.toml | 2 +- examples/stm32h7rs/Cargo.toml | 2 +- examples/stm32l1/Cargo.toml | 2 +- examples/stm32l4/Cargo.toml | 2 +- examples/stm32l5/Cargo.toml | 2 +- examples/stm32u0/Cargo.toml | 2 +- examples/stm32u5/Cargo.toml | 2 +- 29 files changed, 52 insertions(+), 42 deletions(-) diff --git a/embassy-usb-dfu/Cargo.toml b/embassy-usb-dfu/Cargo.toml index e6522b04d..a9565c3a5 100644 --- a/embassy-usb-dfu/Cargo.toml +++ b/embassy-usb-dfu/Cargo.toml @@ -35,7 +35,7 @@ embassy-boot = { version = "0.4.0", path = "../embassy-boot" } embassy-futures = { version = "0.1.1", path = "../embassy-futures" } embassy-sync = { version = "0.6.1", path = "../embassy-sync" } embassy-time = { version = "0.4.0", path = "../embassy-time" } -embassy-usb = { version = "0.3.0", path = "../embassy-usb", default-features = false } +embassy-usb = { version = "0.4.0", path = "../embassy-usb", default-features = false } embedded-storage = { version = "0.3.1" } esp32c3-hal = { version = "0.13.0", optional = true, default-features = false } diff --git a/embassy-usb-logger/CHANGELOG.md b/embassy-usb-logger/CHANGELOG.md index 4cd84b8be..86a9fb032 100644 --- a/embassy-usb-logger/CHANGELOG.md +++ b/embassy-usb-logger/CHANGELOG.md @@ -7,21 +7,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +## 0.4.0 - 2025-01-15 + +- Update `embassy-usb` to 0.4.0 + +(skipped v0.3.0 to align version numbers with `embassy-usb`) + ## 0.2.0 - 2024-05-20 -### Added - -- [#2414](https://github.com/embassy-rs/embassy/pull/2414) USB logger can now use an existing USB device (@JomerDev) - -### Changed - - Update `embassy-usb` to 0.2.0 - -### Fixed - -- No more data loss at `Pipe` wraparound -- [#2414](https://github.com/embassy-rs/embassy/pull/2414) Messages that are exactly `MAX_PACKET_SIZE` long are no -longer delayed (@JomerDev) +- Add support for using an existing USB device ([#2414](https://github.com/embassy-rs/embassy/pull/2414), @JomerDev) +- Fix data loss at `Pipe` wraparound +- Messages that are exactly `MAX_PACKET_SIZE` long are no longer delayed ([#2414](https://github.com/embassy-rs/embassy/pull/2414), @JomerDev) ## 0.1.0 - 2024-01-14 diff --git a/embassy-usb-logger/Cargo.toml b/embassy-usb-logger/Cargo.toml index d5147de49..69b0a98b0 100644 --- a/embassy-usb-logger/Cargo.toml +++ b/embassy-usb-logger/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "embassy-usb-logger" -version = "0.2.0" +version = "0.4.0" edition = "2021" license = "MIT OR Apache-2.0" description = "`log` implementation for USB serial using `embassy-usb`." @@ -15,7 +15,7 @@ src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-usb-l target = "thumbv7em-none-eabi" [dependencies] -embassy-usb = { version = "0.3.0", path = "../embassy-usb" } +embassy-usb = { version = "0.4.0", path = "../embassy-usb" } embassy-sync = { version = "0.6.1", path = "../embassy-sync" } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } log = "0.4" diff --git a/embassy-usb/CHANGELOG.md b/embassy-usb/CHANGELOG.md index efdda96fb..76fafed31 100644 --- a/embassy-usb/CHANGELOG.md +++ b/embassy-usb/CHANGELOG.md @@ -7,6 +7,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +## 0.4.0 - 2025-01-15 + +- Change config defaults to to composite with IADs. This ensures embassy-usb Just Works in more cases when using classes with multiple interfaces, or multiple classes. (breaking change) + - `composite_with_iads` = `true` + - `device_class` = `0xEF` + - `device_sub_class` = `0x02` + - `device_protocol` = `0x01` +- Add support for USB Audio Class 1. +- Add support for isochronous endpoints. +- Add support for setting the USB version number. +- Add support for device qualifier descriptors. +- Allow `bos_descriptor_buf` to be a zero length if BOS descriptors aren't used. + ## 0.3.0 - 2024-08-05 - bump usbd-hid from 0.7.0 to 0.8.1 diff --git a/embassy-usb/Cargo.toml b/embassy-usb/Cargo.toml index 9abf2f200..d0ce3f1df 100644 --- a/embassy-usb/Cargo.toml +++ b/embassy-usb/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "embassy-usb" -version = "0.3.0" +version = "0.4.0" edition = "2021" license = "MIT OR Apache-2.0" description = "Async USB device stack for embedded devices in Rust." diff --git a/examples/boot/application/stm32wb-dfu/Cargo.toml b/examples/boot/application/stm32wb-dfu/Cargo.toml index b3170de54..7e0f90e3a 100644 --- a/examples/boot/application/stm32wb-dfu/Cargo.toml +++ b/examples/boot/application/stm32wb-dfu/Cargo.toml @@ -11,7 +11,7 @@ embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32wb55rg", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } embassy-embedded-hal = { version = "0.3.0", path = "../../../../embassy-embedded-hal" } -embassy-usb = { version = "0.3.0", path = "../../../../embassy-usb" } +embassy-usb = { version = "0.4.0", path = "../../../../embassy-usb" } embassy-usb-dfu = { version = "0.1.0", path = "../../../../embassy-usb-dfu", features = ["application", "cortex-m"] } defmt = { version = "0.3", optional = true } diff --git a/examples/boot/bootloader/stm32wb-dfu/Cargo.toml b/examples/boot/bootloader/stm32wb-dfu/Cargo.toml index 1431e7cc3..f8d66e777 100644 --- a/examples/boot/bootloader/stm32wb-dfu/Cargo.toml +++ b/examples/boot/bootloader/stm32wb-dfu/Cargo.toml @@ -18,7 +18,7 @@ embedded-storage = "0.3.1" embedded-storage-async = "0.4.0" cfg-if = "1.0.0" embassy-usb-dfu = { version = "0.1.0", path = "../../../../embassy-usb-dfu", features = ["dfu", "cortex-m"] } -embassy-usb = { version = "0.3.0", path = "../../../../embassy-usb", default-features = false } +embassy-usb = { version = "0.4.0", path = "../../../../embassy-usb", default-features = false } embassy-futures = { version = "0.1.1", path = "../../../../embassy-futures" } [features] diff --git a/examples/nrf52840/Cargo.toml b/examples/nrf52840/Cargo.toml index 81d130ad3..1c65098fe 100644 --- a/examples/nrf52840/Cargo.toml +++ b/examples/nrf52840/Cargo.toml @@ -11,7 +11,7 @@ embassy-executor = { version = "0.7.0", path = "../../embassy-executor", feature embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.3.1", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } embassy-net = { version = "0.6.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } -embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } +embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defmt"] } embedded-io = { version = "0.6.0", features = ["defmt-03"] } embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } embassy-net-esp-hosted = { version = "0.2.0", path = "../../embassy-net-esp-hosted", features = ["defmt"] } diff --git a/examples/nrf5340/Cargo.toml b/examples/nrf5340/Cargo.toml index 557a9127a..be46b7974 100644 --- a/examples/nrf5340/Cargo.toml +++ b/examples/nrf5340/Cargo.toml @@ -11,7 +11,7 @@ embassy-executor = { version = "0.7.0", path = "../../embassy-executor", feature embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.3.1", path = "../../embassy-nrf", features = ["defmt", "nrf5340-app-s", "time-driver-rtc1", "gpiote", "unstable-pac"] } embassy-net = { version = "0.6.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } -embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } +embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defmt"] } embedded-io-async = { version = "0.6.1" } defmt = "0.3" diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index f80ccbc0b..d9decc2b0 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml @@ -11,11 +11,11 @@ embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["de embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-98304", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-rp = { version = "0.3.0", path = "../../embassy-rp", features = ["defmt", "unstable-pac", "time-driver", "critical-section-impl", "rp2040"] } -embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } +embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defmt"] } embassy-net = { version = "0.6.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "raw", "dhcpv4", "medium-ethernet", "dns", "proto-ipv4", "proto-ipv6", "multicast"] } embassy-net-wiznet = { version = "0.2.0", path = "../../embassy-net-wiznet", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } -embassy-usb-logger = { version = "0.2.0", path = "../../embassy-usb-logger" } +embassy-usb-logger = { version = "0.4.0", path = "../../embassy-usb-logger" } cyw43 = { version = "0.3.0", path = "../../cyw43", features = ["defmt", "firmware-logs"] } cyw43-pio = { version = "0.3.0", path = "../../cyw43-pio", features = ["defmt"] } diff --git a/examples/rp23/Cargo.toml b/examples/rp23/Cargo.toml index 7c94166bd..4d99ecc72 100644 --- a/examples/rp23/Cargo.toml +++ b/examples/rp23/Cargo.toml @@ -11,11 +11,11 @@ embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["de embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-98304", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-rp = { version = "0.3.0", path = "../../embassy-rp", features = ["defmt", "unstable-pac", "time-driver", "critical-section-impl", "rp235xa", "binary-info"] } -embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } +embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defmt"] } embassy-net = { version = "0.6.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "raw", "dhcpv4", "medium-ethernet", "dns"] } embassy-net-wiznet = { version = "0.2.0", path = "../../embassy-net-wiznet", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } -embassy-usb-logger = { version = "0.2.0", path = "../../embassy-usb-logger" } +embassy-usb-logger = { version = "0.4.0", path = "../../embassy-usb-logger" } cyw43 = { version = "0.3.0", path = "../../cyw43", features = ["defmt", "firmware-logs"] } cyw43-pio = { version = "0.3.0", path = "../../cyw43-pio", features = ["defmt"] } diff --git a/examples/stm32f1/Cargo.toml b/examples/stm32f1/Cargo.toml index 191c16ed9..4a090ea04 100644 --- a/examples/stm32f1/Cargo.toml +++ b/examples/stm32f1/Cargo.toml @@ -10,7 +10,7 @@ embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [ embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } -embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } +embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } defmt = "0.3" diff --git a/examples/stm32f3/Cargo.toml b/examples/stm32f3/Cargo.toml index aa60ca692..9204971d7 100644 --- a/examples/stm32f3/Cargo.toml +++ b/examples/stm32f3/Cargo.toml @@ -10,7 +10,7 @@ embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [ embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } -embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } +embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } defmt = "0.3" diff --git a/examples/stm32f334/Cargo.toml b/examples/stm32f334/Cargo.toml index 54aa20a9e..aef92ca3f 100644 --- a/examples/stm32f334/Cargo.toml +++ b/examples/stm32f334/Cargo.toml @@ -9,7 +9,7 @@ embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["de embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f334r8", "unstable-pac", "memory-x", "time-driver-any", "exti"] } -embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } +embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } defmt = "0.3" diff --git a/examples/stm32f4/Cargo.toml b/examples/stm32f4/Cargo.toml index 355e264a1..f2b077949 100644 --- a/examples/stm32f4/Cargo.toml +++ b/examples/stm32f4/Cargo.toml @@ -10,7 +10,7 @@ embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [" embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } -embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt" ] } +embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defmt" ] } embassy-net = { version = "0.6.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", ] } embassy-net-wiznet = { version = "0.2.0", path = "../../embassy-net-wiznet", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32f7/Cargo.toml b/examples/stm32f7/Cargo.toml index d195088e7..c7a2db5df 100644 --- a/examples/stm32f7/Cargo.toml +++ b/examples/stm32f7/Cargo.toml @@ -12,7 +12,7 @@ embassy-executor = { version = "0.7.0", path = "../../embassy-executor", feature embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.6.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } embedded-io-async = { version = "0.6.1" } -embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } +embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } defmt = "0.3" diff --git a/examples/stm32g0/Cargo.toml b/examples/stm32g0/Cargo.toml index de96e576f..675b03fa2 100644 --- a/examples/stm32g0/Cargo.toml +++ b/examples/stm32g0/Cargo.toml @@ -10,7 +10,7 @@ embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [ embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } -embassy-usb = { version = "0.3.0", path = "../../embassy-usb", default-features = false, features = ["defmt"] } +embassy-usb = { version = "0.4.0", path = "../../embassy-usb", default-features = false, features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } defmt = "0.3" diff --git a/examples/stm32g4/Cargo.toml b/examples/stm32g4/Cargo.toml index 411d91cc5..6c3a4e8cb 100644 --- a/examples/stm32g4/Cargo.toml +++ b/examples/stm32g4/Cargo.toml @@ -10,7 +10,7 @@ embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [ embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } -embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } +embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } usbd-hid = "0.8.1" diff --git a/examples/stm32h5/Cargo.toml b/examples/stm32h5/Cargo.toml index cdc26c3ab..ac670ff8f 100644 --- a/examples/stm32h5/Cargo.toml +++ b/examples/stm32h5/Cargo.toml @@ -11,7 +11,7 @@ embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["de embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.6.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6"] } -embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } +embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } defmt = "0.3" diff --git a/examples/stm32h7/Cargo.toml b/examples/stm32h7/Cargo.toml index 341e8d307..224dc45c6 100644 --- a/examples/stm32h7/Cargo.toml +++ b/examples/stm32h7/Cargo.toml @@ -12,7 +12,7 @@ embassy-embedded-hal = { version = "0.3.0", path = "../../embassy-embedded-hal" embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.6.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } -embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } +embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } defmt = "0.3" diff --git a/examples/stm32h755cm4/Cargo.toml b/examples/stm32h755cm4/Cargo.toml index 7705a5852..0bafb24e3 100644 --- a/examples/stm32h755cm4/Cargo.toml +++ b/examples/stm32h755cm4/Cargo.toml @@ -12,7 +12,7 @@ embassy-embedded-hal = { version = "0.3.0", path = "../../embassy-embedded-hal" embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.6.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } -embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } +embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } defmt = "0.3" diff --git a/examples/stm32h755cm7/Cargo.toml b/examples/stm32h755cm7/Cargo.toml index 87546eb12..d21bc00a2 100644 --- a/examples/stm32h755cm7/Cargo.toml +++ b/examples/stm32h755cm7/Cargo.toml @@ -12,7 +12,7 @@ embassy-embedded-hal = { version = "0.3.0", path = "../../embassy-embedded-hal" embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.6.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } -embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } +embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } defmt = "0.3" diff --git a/examples/stm32h7b0/Cargo.toml b/examples/stm32h7b0/Cargo.toml index df92ce072..6189f225c 100644 --- a/examples/stm32h7b0/Cargo.toml +++ b/examples/stm32h7b0/Cargo.toml @@ -11,7 +11,7 @@ embassy-embedded-hal = { version = "0.3.0", path = "../../embassy-embedded-hal" embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.6.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } -embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } +embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } defmt = "0.3" diff --git a/examples/stm32h7rs/Cargo.toml b/examples/stm32h7rs/Cargo.toml index 817e1b4a8..621fea21f 100644 --- a/examples/stm32h7rs/Cargo.toml +++ b/examples/stm32h7rs/Cargo.toml @@ -11,7 +11,7 @@ embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["de embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.6.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } -embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } +embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } defmt = "0.3" diff --git a/examples/stm32l1/Cargo.toml b/examples/stm32l1/Cargo.toml index 1317be6e3..2392c4136 100644 --- a/examples/stm32l1/Cargo.toml +++ b/examples/stm32l1/Cargo.toml @@ -9,7 +9,7 @@ embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["de embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [ "defmt", "stm32l151cb-a", "time-driver-any", "memory-x"] } -embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } +embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } defmt = "0.3" diff --git a/examples/stm32l4/Cargo.toml b/examples/stm32l4/Cargo.toml index 52a6df324..d82d91d35 100644 --- a/examples/stm32l4/Cargo.toml +++ b/examples/stm32l4/Cargo.toml @@ -11,7 +11,7 @@ embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["de embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768", ] } embassy-embedded-hal = { version = "0.3.0", path = "../../embassy-embedded-hal" } -embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } +embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defmt"] } embassy-net-adin1110 = { version = "0.3.0", path = "../../embassy-net-adin1110" } embassy-net = { version = "0.6.0", path = "../../embassy-net", features = ["defmt", "udp", "tcp", "dhcpv4", "medium-ethernet"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32l5/Cargo.toml b/examples/stm32l5/Cargo.toml index 39d434720..56dc907a7 100644 --- a/examples/stm32l5/Cargo.toml +++ b/examples/stm32l5/Cargo.toml @@ -10,7 +10,7 @@ embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [ embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } -embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } +embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defmt"] } embassy-net = { version = "0.6.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } usbd-hid = "0.8.1" diff --git a/examples/stm32u0/Cargo.toml b/examples/stm32u0/Cargo.toml index 9b03b3971..722e2125b 100644 --- a/examples/stm32u0/Cargo.toml +++ b/examples/stm32u0/Cargo.toml @@ -10,7 +10,7 @@ embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [ embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } -embassy-usb = { version = "0.3.0", path = "../../embassy-usb", default-features = false, features = ["defmt"] } +embassy-usb = { version = "0.4.0", path = "../../embassy-usb", default-features = false, features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } defmt = "0.3" diff --git a/examples/stm32u5/Cargo.toml b/examples/stm32u5/Cargo.toml index 4aee08986..d31a34410 100644 --- a/examples/stm32u5/Cargo.toml +++ b/examples/stm32u5/Cargo.toml @@ -10,7 +10,7 @@ embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [" embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } -embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } +embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } defmt = "0.3" From 933e888ed059d03f8c306537f14369521166e3a3 Mon Sep 17 00:00:00 2001 From: Pedro Ferreira Date: Wed, 11 Sep 2024 21:21:41 +0200 Subject: [PATCH 0656/1217] RP235x: support new FIFO options, set IE, OD on PIO pins. --- cyw43-pio/Cargo.toml | 4 +- embassy-rp/Cargo.toml | 4 +- embassy-rp/src/pio/mod.rs | 46 +++++++ examples/rp/Cargo.toml | 4 +- examples/rp23/Cargo.toml | 4 +- .../rp23/src/bin/pio_rotary_encoder_rxf.rs | 116 ++++++++++++++++++ tests/rp/Cargo.toml | 4 +- 7 files changed, 172 insertions(+), 10 deletions(-) create mode 100644 examples/rp23/src/bin/pio_rotary_encoder_rxf.rs diff --git a/cyw43-pio/Cargo.toml b/cyw43-pio/Cargo.toml index 292cccf66..f52788ba3 100644 --- a/cyw43-pio/Cargo.toml +++ b/cyw43-pio/Cargo.toml @@ -12,8 +12,8 @@ documentation = "https://docs.embassy.dev/cyw43-pio" [dependencies] cyw43 = { version = "0.3.0", path = "../cyw43" } embassy-rp = { version = "0.3.0", path = "../embassy-rp" } -pio-proc = "0.2" -pio = "0.2.1" +pio-proc = { git = "https://github.com/rp-rs/pio-rs", rev = "fa586448b0b223217eec8c92c19fe6823dd04cc4" } +pio = { git = "https://github.com/rp-rs/pio-rs", rev = "fa586448b0b223217eec8c92c19fe6823dd04cc4" } fixed = "1.23.1" defmt = { version = "0.3", optional = true } diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index 56cc39bbf..120e058ed 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml @@ -139,8 +139,8 @@ embedded-hal-1 = { package = "embedded-hal", version = "1.0" } embedded-hal-async = { version = "1.0" } embedded-hal-nb = { version = "1.0" } -pio-proc = { version= "0.2" } -pio = { version= "0.2.1" } +pio-proc = { git = "https://github.com/rp-rs/pio-rs", rev = "fa586448b0b223217eec8c92c19fe6823dd04cc4" } +pio = { git = "https://github.com/rp-rs/pio-rs", rev = "fa586448b0b223217eec8c92c19fe6823dd04cc4" } rp2040-boot2 = "0.3" document-features = "0.2.10" sha2-const-stable = "0.1" diff --git a/embassy-rp/src/pio/mod.rs b/embassy-rp/src/pio/mod.rs index 8916cbef0..7632d3168 100644 --- a/embassy-rp/src/pio/mod.rs +++ b/embassy-rp/src/pio/mod.rs @@ -50,6 +50,18 @@ pub enum FifoJoin { RxOnly, /// Tx fifo twice as deep. RX fifo disabled TxOnly, + /// Enable random writes (`FJOIN_RX_PUT`) from the state machine (through ISR), + /// and random reads from the system (using [`StateMachine::get_rxf_entry`]). + #[cfg(feature = "_rp235x")] + RxAsStatus, + /// Enable random reads (`FJOIN_RX_GET`) from the state machine (through OSR), + /// and random writes from the system (using [`StateMachine::set_rxf_entry`]). + #[cfg(feature = "_rp235x")] + RxAsControl, + /// FJOIN_RX_PUT | FJOIN_RX_GET: RX can be used as a scratch register, + /// not accesible from the CPU + #[cfg(feature = "_rp235x")] + PioScratch, } /// Shift direction. @@ -730,6 +742,17 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> { w.set_in_shiftdir(config.shift_in.direction == ShiftDirection::Right); w.set_autopull(config.shift_out.auto_fill); w.set_autopush(config.shift_in.auto_fill); + + #[cfg(feature = "_rp235x")] + { + w.set_fjoin_rx_get( + config.fifo_join == FifoJoin::RxAsControl || config.fifo_join == FifoJoin::PioScratch, + ); + w.set_fjoin_rx_put( + config.fifo_join == FifoJoin::RxAsStatus || config.fifo_join == FifoJoin::PioScratch, + ); + w.set_in_count(config.in_count); + } }); #[cfg(feature = "rp2040")] @@ -907,6 +930,20 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> { pub fn rx_tx(&mut self) -> (&mut StateMachineRx<'d, PIO, SM>, &mut StateMachineTx<'d, PIO, SM>) { (&mut self.rx, &mut self.tx) } + + /// Return the contents of the nth entry of the RX FIFO + /// (should be used only when the FIFO config is set to [`FifoJoin::RxAsStatus`]) + #[cfg(feature = "_rp235x")] + pub fn get_rxf_entry(&self, n: usize) -> u32 { + PIO::PIO.rxf_putget(SM).putget(n).read() + } + + /// Set the contents of the nth entry of the RX FIFO + /// (should be used only when the FIFO config is set to [`FifoJoin::RxAsControl`]) + #[cfg(feature = "_rp235x")] + pub fn set_rxf_entry(&self, n: usize, val: u32) { + PIO::PIO.rxf_putget(SM).putget(n).write_value(val) + } } /// PIO handle. @@ -993,6 +1030,9 @@ impl<'d, PIO: Instance> Common<'d, PIO> { prog: &Program, origin: u8, ) -> Result, usize> { + #[cfg(not(feature = "_rp235x"))] + assert!(prog.version == pio::PioVersion::V0); + let prog = RelocatedProgram::new_with_origin(prog, origin); let used_memory = self.try_write_instr(prog.origin() as _, prog.code())?; Ok(LoadedProgram { @@ -1053,6 +1093,12 @@ impl<'d, PIO: Instance> Common<'d, PIO> { /// of [`Pio`] do not keep pin registrations alive.** pub fn make_pio_pin(&mut self, pin: impl Peripheral

+ 'd) -> Pin<'d, PIO> { into_ref!(pin); + + // enable the outputs + pin.pad_ctrl().write(|w| w.set_od(false)); + // especially important on the 235x, where IE defaults to 0 + pin.pad_ctrl().write(|w| w.set_ie(true)); + pin.gpio().ctrl().write(|w| w.set_funcsel(PIO::FUNCSEL as _)); pin.pad_ctrl().write(|w| { #[cfg(feature = "_rp235x")] diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index d9decc2b0..5294ec477 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml @@ -55,8 +55,8 @@ embedded-storage = { version = "0.3" } static_cell = "2.1" portable-atomic = { version = "1.5", features = ["critical-section"] } log = "0.4" -pio-proc = "0.2" -pio = "0.2.1" +pio-proc = { git = "https://github.com/rp-rs/pio-rs", rev = "fa586448b0b223217eec8c92c19fe6823dd04cc4" } +pio = { git = "https://github.com/rp-rs/pio-rs", rev = "fa586448b0b223217eec8c92c19fe6823dd04cc4" } rand = { version = "0.8.5", default-features = false } embedded-sdmmc = "0.7.0" diff --git a/examples/rp23/Cargo.toml b/examples/rp23/Cargo.toml index 4d99ecc72..8f9c14c5c 100644 --- a/examples/rp23/Cargo.toml +++ b/examples/rp23/Cargo.toml @@ -55,8 +55,8 @@ embedded-storage = { version = "0.3" } static_cell = "2.1" portable-atomic = { version = "1.5", features = ["critical-section"] } log = "0.4" -pio-proc = "0.2" -pio = "0.2.1" +pio-proc = { git = "https://github.com/rp-rs/pio-rs", rev = "fa586448b0b223217eec8c92c19fe6823dd04cc4" } +pio = { git = "https://github.com/rp-rs/pio-rs", rev = "fa586448b0b223217eec8c92c19fe6823dd04cc4" } rand = { version = "0.8.5", default-features = false } embedded-sdmmc = "0.7.0" diff --git a/examples/rp23/src/bin/pio_rotary_encoder_rxf.rs b/examples/rp23/src/bin/pio_rotary_encoder_rxf.rs new file mode 100644 index 000000000..7a1046610 --- /dev/null +++ b/examples/rp23/src/bin/pio_rotary_encoder_rxf.rs @@ -0,0 +1,116 @@ +//! This example shows how to use the PIO module in the RP235x to read a quadrature rotary encoder. +//! It differs from the other example in that it uses the RX FIFO as a status register + +#![no_std] +#![no_main] + +use defmt::info; +use embassy_executor::Spawner; +use embassy_rp::block::ImageDef; +use embassy_rp::gpio::Pull; +use embassy_rp::peripherals::PIO0; +use embassy_rp::{bind_interrupts, pio}; +use embassy_time::Timer; +use fixed::traits::ToFixed; +use pio::{Common, Config, FifoJoin, Instance, InterruptHandler, Pio, PioPin, ShiftDirection, StateMachine}; +use {defmt_rtt as _, panic_probe as _}; + +#[link_section = ".start_block"] +#[used] +pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); + +// Program metadata for `picotool info` +#[link_section = ".bi_entries"] +#[used] +pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ + embassy_rp::binary_info::rp_program_name!(c"example_pio_rotary_encoder_rxf"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Rotary encoder (RXF)"), + embassy_rp::binary_info::rp_program_build_attribute!(), +]; + +bind_interrupts!(struct Irqs { + PIO0_IRQ_0 => InterruptHandler; +}); + +pub struct PioEncoder<'d, T: Instance, const SM: usize> { + sm: StateMachine<'d, T, SM>, +} + +impl<'d, T: Instance, const SM: usize> PioEncoder<'d, T, SM> { + pub fn new( + pio: &mut Common<'d, T>, + mut sm: StateMachine<'d, T, SM>, + pin_a: impl PioPin, + pin_b: impl PioPin, + ) -> Self { + let mut pin_a = pio.make_pio_pin(pin_a); + let mut pin_b = pio.make_pio_pin(pin_b); + pin_a.set_pull(Pull::Up); + pin_b.set_pull(Pull::Up); + + sm.set_pin_dirs(pio::Direction::In, &[&pin_a, &pin_b]); + + let prg = pio_proc::pio_asm!( + "start:" + // encoder count is stored in X + "mov isr, x" + // and then moved to the RX FIFO register + "mov rxfifo[0], isr" + + // wait for encoder transition + "wait 1 pin 1" + "wait 0 pin 1" + + "set y, 0" + "mov y, pins[1]" + + // update X depending on pin 1 + "jmp !y decr" + + // this is just a clever way of doing x++ + "mov x, ~x" + "jmp x--, incr" + "incr:" + "mov x, ~x" + "jmp start" + + // and this is x-- + "decr:" + "jmp x--, start" + ); + + let mut cfg = Config::default(); + cfg.set_in_pins(&[&pin_a, &pin_b]); + cfg.fifo_join = FifoJoin::RxAsStatus; + cfg.shift_in.direction = ShiftDirection::Left; + cfg.clock_divider = 10_000.to_fixed(); + cfg.use_program(&pio.load_program(&prg.program), &[]); + sm.set_config(&cfg); + + sm.set_enable(true); + Self { sm } + } + + pub async fn read(&mut self) -> u32 { + self.sm.get_rxf_entry(0) + } +} + +pub enum Direction { + Clockwise, + CounterClockwise, +} + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_rp::init(Default::default()); + let Pio { mut common, sm0, .. } = Pio::new(p.PIO0, Irqs); + + let mut encoder = PioEncoder::new(&mut common, sm0, p.PIN_4, p.PIN_5); + + loop { + info!("Count: {}", encoder.read().await); + Timer::after_millis(1000).await; + } +} diff --git a/tests/rp/Cargo.toml b/tests/rp/Cargo.toml index 4278f7b2c..26f3f21f6 100644 --- a/tests/rp/Cargo.toml +++ b/tests/rp/Cargo.toml @@ -33,8 +33,8 @@ embedded-io-async = { version = "0.6.1" } embedded-storage = { version = "0.3" } static_cell = "2" portable-atomic = { version = "1.5", features = ["critical-section"] } -pio = "0.2" -pio-proc = "0.2" +pio-proc = { git = "https://github.com/rp-rs/pio-rs", rev = "fa586448b0b223217eec8c92c19fe6823dd04cc4" } +pio = { git = "https://github.com/rp-rs/pio-rs", rev = "fa586448b0b223217eec8c92c19fe6823dd04cc4" } rand = { version = "0.8.5", default-features = false } [profile.dev] From 2fab8d0b9ba8eecc40b76c00fab19abf0426a8ff Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Wed, 15 Jan 2025 02:09:24 +0100 Subject: [PATCH 0657/1217] Update doc projects deps, don't use patch.crates-io --- docs/examples/layer-by-layer/Cargo.toml | 4 -- .../layer-by-layer/blinky-async/Cargo.toml | 8 ++-- .../layer-by-layer/blinky-hal/Cargo.toml | 6 +-- .../layer-by-layer/blinky-irq/Cargo.toml | 6 +-- .../layer-by-layer/blinky-pac/Cargo.toml | 6 +-- .../layer-by-layer/blinky-pac/src/main.rs | 48 ++++++++----------- tests/perf-client/Cargo.toml | 2 +- tests/rp/Cargo.toml | 2 +- tests/stm32/Cargo.toml | 2 +- 9 files changed, 36 insertions(+), 48 deletions(-) diff --git a/docs/examples/layer-by-layer/Cargo.toml b/docs/examples/layer-by-layer/Cargo.toml index 0f233eae5..f18c9e7e4 100644 --- a/docs/examples/layer-by-layer/Cargo.toml +++ b/docs/examples/layer-by-layer/Cargo.toml @@ -7,10 +7,6 @@ members = [ "blinky-async", ] -[patch.crates-io] -embassy-executor = { path = "../../../embassy-executor" } -embassy-stm32 = { path = "../../../embassy-stm32" } - [profile.release] codegen-units = 1 debug = 2 diff --git a/docs/examples/layer-by-layer/blinky-async/Cargo.toml b/docs/examples/layer-by-layer/blinky-async/Cargo.toml index 2c3996e87..51ddf87d4 100644 --- a/docs/examples/layer-by-layer/blinky-async/Cargo.toml +++ b/docs/examples/layer-by-layer/blinky-async/Cargo.toml @@ -7,9 +7,9 @@ license = "MIT OR Apache-2.0" [dependencies] cortex-m = "0.7" cortex-m-rt = "0.7" -embassy-stm32 = { version = "0.2.0", features = ["stm32l475vg", "memory-x", "exti"] } -embassy-executor = { version = "0.6.3", features = ["arch-cortex-m", "executor-thread"] } +embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32l475vg", "memory-x", "exti"] } +embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread"] } -defmt = "0.3.0" -defmt-rtt = "0.3.0" +defmt = "0.3" +defmt-rtt = "0.4" panic-probe = { version = "0.3.0", features = ["print-defmt"] } diff --git a/docs/examples/layer-by-layer/blinky-hal/Cargo.toml b/docs/examples/layer-by-layer/blinky-hal/Cargo.toml index d8f94b69d..1e292e6b4 100644 --- a/docs/examples/layer-by-layer/blinky-hal/Cargo.toml +++ b/docs/examples/layer-by-layer/blinky-hal/Cargo.toml @@ -7,8 +7,8 @@ license = "MIT OR Apache-2.0" [dependencies] cortex-m = "0.7" cortex-m-rt = "0.7" -embassy-stm32 = { version = "0.2.0", features = ["stm32l475vg", "memory-x"] } +embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32l475vg", "memory-x"] } -defmt = "0.3.0" -defmt-rtt = "0.3.0" +defmt = "0.3" +defmt-rtt = "0.4" panic-probe = { version = "0.3.0", features = ["print-defmt"] } diff --git a/docs/examples/layer-by-layer/blinky-irq/Cargo.toml b/docs/examples/layer-by-layer/blinky-irq/Cargo.toml index 15153cab4..04ffc23ba 100644 --- a/docs/examples/layer-by-layer/blinky-irq/Cargo.toml +++ b/docs/examples/layer-by-layer/blinky-irq/Cargo.toml @@ -7,8 +7,8 @@ license = "MIT OR Apache-2.0" [dependencies] cortex-m = "0.7" cortex-m-rt = { version = "0.7" } -embassy-stm32 = { version = "0.2.0", features = ["stm32l475vg", "memory-x", "unstable-pac"] } +embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32l475vg", "memory-x", "unstable-pac"] } -defmt = "0.3.0" -defmt-rtt = "0.3.0" +defmt = "0.3" +defmt-rtt = "0.4" panic-probe = { version = "0.3.0", features = ["print-defmt"] } diff --git a/docs/examples/layer-by-layer/blinky-pac/Cargo.toml b/docs/examples/layer-by-layer/blinky-pac/Cargo.toml index f872b94cb..cf2d7fede 100644 --- a/docs/examples/layer-by-layer/blinky-pac/Cargo.toml +++ b/docs/examples/layer-by-layer/blinky-pac/Cargo.toml @@ -7,8 +7,8 @@ license = "MIT OR Apache-2.0" [dependencies] cortex-m = "0.7" cortex-m-rt = "0.7" -stm32-metapac = { version = "1", features = ["stm32l475vg", "memory-x"] } +stm32-metapac = { version = "16", features = ["stm32l475vg"] } -defmt = "0.3.0" -defmt-rtt = "0.3.0" +defmt = "0.3" +defmt-rtt = "0.4" panic-probe = { version = "0.3.0", features = ["print-defmt"] } diff --git a/docs/examples/layer-by-layer/blinky-pac/src/main.rs b/docs/examples/layer-by-layer/blinky-pac/src/main.rs index 990d46cb6..cfbd91306 100644 --- a/docs/examples/layer-by-layer/blinky-pac/src/main.rs +++ b/docs/examples/layer-by-layer/blinky-pac/src/main.rs @@ -8,46 +8,38 @@ use {defmt_rtt as _, panic_probe as _, stm32_metapac as pac}; fn main() -> ! { // Enable GPIO clock let rcc = pac::RCC; - unsafe { - rcc.ahb2enr().modify(|w| { - w.set_gpioben(true); - w.set_gpiocen(true); - }); + rcc.ahb2enr().modify(|w| { + w.set_gpioben(true); + w.set_gpiocen(true); + }); - rcc.ahb2rstr().modify(|w| { - w.set_gpiobrst(true); - w.set_gpiocrst(true); - w.set_gpiobrst(false); - w.set_gpiocrst(false); - }); - } + rcc.ahb2rstr().modify(|w| { + w.set_gpiobrst(true); + w.set_gpiocrst(true); + w.set_gpiobrst(false); + w.set_gpiocrst(false); + }); // Setup button let gpioc = pac::GPIOC; const BUTTON_PIN: usize = 13; - unsafe { - gpioc.pupdr().modify(|w| w.set_pupdr(BUTTON_PIN, vals::Pupdr::PULLUP)); - gpioc.otyper().modify(|w| w.set_ot(BUTTON_PIN, vals::Ot::PUSHPULL)); - gpioc.moder().modify(|w| w.set_moder(BUTTON_PIN, vals::Moder::INPUT)); - } + gpioc.pupdr().modify(|w| w.set_pupdr(BUTTON_PIN, vals::Pupdr::PULL_UP)); + gpioc.otyper().modify(|w| w.set_ot(BUTTON_PIN, vals::Ot::PUSH_PULL)); + gpioc.moder().modify(|w| w.set_moder(BUTTON_PIN, vals::Moder::INPUT)); // Setup LED let gpiob = pac::GPIOB; const LED_PIN: usize = 14; - unsafe { - gpiob.pupdr().modify(|w| w.set_pupdr(LED_PIN, vals::Pupdr::FLOATING)); - gpiob.otyper().modify(|w| w.set_ot(LED_PIN, vals::Ot::PUSHPULL)); - gpiob.moder().modify(|w| w.set_moder(LED_PIN, vals::Moder::OUTPUT)); - } + gpiob.pupdr().modify(|w| w.set_pupdr(LED_PIN, vals::Pupdr::FLOATING)); + gpiob.otyper().modify(|w| w.set_ot(LED_PIN, vals::Ot::PUSH_PULL)); + gpiob.moder().modify(|w| w.set_moder(LED_PIN, vals::Moder::OUTPUT)); // Main loop loop { - unsafe { - if gpioc.idr().read().idr(BUTTON_PIN) == vals::Idr::LOW { - gpiob.bsrr().write(|w| w.set_bs(LED_PIN, true)); - } else { - gpiob.bsrr().write(|w| w.set_br(LED_PIN, true)); - } + if gpioc.idr().read().idr(BUTTON_PIN) == vals::Idr::LOW { + gpiob.bsrr().write(|w| w.set_bs(LED_PIN, true)); + } else { + gpiob.bsrr().write(|w| w.set_br(LED_PIN, true)); } } } diff --git a/tests/perf-client/Cargo.toml b/tests/perf-client/Cargo.toml index cb3dd3df6..7af6a4af2 100644 --- a/tests/perf-client/Cargo.toml +++ b/tests/perf-client/Cargo.toml @@ -7,4 +7,4 @@ edition = "2021" embassy-net = { version = "0.6.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", ] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } -defmt = "0.3.0" +defmt = "0.3" diff --git a/tests/rp/Cargo.toml b/tests/rp/Cargo.toml index 26f3f21f6..dc3ca3202 100644 --- a/tests/rp/Cargo.toml +++ b/tests/rp/Cargo.toml @@ -19,7 +19,7 @@ cyw43 = { path = "../../cyw43", features = ["defmt", "firmware-logs"] } cyw43-pio = { path = "../../cyw43-pio", features = ["defmt"] } perf-client = { path = "../perf-client" } -defmt = "0.3.0" +defmt = "0.3" defmt-rtt = "0.4" cortex-m = { version = "0.7.6" } diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml index f064e8057..ff42462fe 100644 --- a/tests/stm32/Cargo.toml +++ b/tests/stm32/Cargo.toml @@ -68,7 +68,7 @@ embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", opt embassy-net = { version = "0.6.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "dhcpv4", "medium-ethernet"] } perf-client = { path = "../perf-client" } -defmt = "0.3.0" +defmt = "0.3" defmt-rtt = "0.4" cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } From c06862eeaf44eabd291194ed29f9e12558d1abf4 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Wed, 15 Jan 2025 11:37:00 +0100 Subject: [PATCH 0658/1217] feat: add dynamic dispatch variants of pipe --- embassy-sync/CHANGELOG.md | 4 + embassy-sync/src/pipe.rs | 273 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 277 insertions(+) diff --git a/embassy-sync/CHANGELOG.md b/embassy-sync/CHANGELOG.md index a7547422f..b96c9416d 100644 --- a/embassy-sync/CHANGELOG.md +++ b/embassy-sync/CHANGELOG.md @@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## Unreleased + +- Add dynamic dispatch variant of `Pipe`. + ## 0.6.1 - 2024-11-22 - Add `LazyLock` sync primitive. diff --git a/embassy-sync/src/pipe.rs b/embassy-sync/src/pipe.rs index cd5b8ed75..2598652d2 100644 --- a/embassy-sync/src/pipe.rs +++ b/embassy-sync/src/pipe.rs @@ -532,6 +532,250 @@ impl embedded_io_async::Write for Writer<'_, M, N> } } +// +// Type-erased variants +// + +pub(crate) trait DynamicPipe { + fn write<'a>(&'a self, buf: &'a [u8]) -> DynamicWriteFuture<'a>; + fn read<'a>(&'a self, buf: &'a mut [u8]) -> DynamicReadFuture<'a>; + + fn try_read(&self, buf: &mut [u8]) -> Result; + fn try_write(&self, buf: &[u8]) -> Result; + + fn try_write_with_context(&self, cx: Option<&mut Context<'_>>, buf: &[u8]) -> Result; + fn try_read_with_context(&self, cx: Option<&mut Context<'_>>, buf: &mut [u8]) -> Result; + + fn consume(&self, amt: usize); + unsafe fn try_fill_buf_with_context(&self, cx: Option<&mut Context<'_>>) -> Result<&[u8], TryReadError>; +} + +impl DynamicPipe for Pipe +where + M: RawMutex, +{ + fn consume(&self, amt: usize) { + Pipe::consume(self, amt) + } + + unsafe fn try_fill_buf_with_context(&self, cx: Option<&mut Context<'_>>) -> Result<&[u8], TryReadError> { + Pipe::try_fill_buf_with_context(self, cx) + } + + fn write<'a>(&'a self, buf: &'a [u8]) -> DynamicWriteFuture<'a> { + Pipe::write(self, buf).into() + } + + fn read<'a>(&'a self, buf: &'a mut [u8]) -> DynamicReadFuture<'a> { + Pipe::read(self, buf).into() + } + + fn try_read(&self, buf: &mut [u8]) -> Result { + Pipe::try_read(self, buf) + } + + fn try_write(&self, buf: &[u8]) -> Result { + Pipe::try_write(self, buf) + } + + fn try_write_with_context(&self, cx: Option<&mut Context<'_>>, buf: &[u8]) -> Result { + Pipe::try_write_with_context(self, cx, buf) + } + + fn try_read_with_context(&self, cx: Option<&mut Context<'_>>, buf: &mut [u8]) -> Result { + Pipe::try_read_with_context(self, cx, buf) + } +} + +/// Write-only access to a [`DynamicPipe`]. +pub struct DynamicWriter<'p> { + pipe: &'p dyn DynamicPipe, +} + +impl<'p> Clone for DynamicWriter<'p> { + fn clone(&self) -> Self { + *self + } +} + +impl<'p> Copy for DynamicWriter<'p> {} + +impl<'p> DynamicWriter<'p> { + /// Write some bytes to the pipe. + /// + /// See [`Pipe::write()`] + pub fn write<'a>(&'a self, buf: &'a [u8]) -> DynamicWriteFuture<'a> { + self.pipe.write(buf) + } + + /// Attempt to immediately write some bytes to the pipe. + /// + /// See [`Pipe::try_write()`] + pub fn try_write(&self, buf: &[u8]) -> Result { + self.pipe.try_write(buf) + } +} + +impl<'p, M, const N: usize> From> for DynamicWriter<'p> +where + M: RawMutex, +{ + fn from(value: Writer<'p, M, N>) -> Self { + Self { pipe: value.pipe } + } +} + +/// Future returned by [`DynamicWriter::write`]. +#[must_use = "futures do nothing unless you `.await` or poll them"] +pub struct DynamicWriteFuture<'p> { + pipe: &'p dyn DynamicPipe, + buf: &'p [u8], +} + +impl<'p> Future for DynamicWriteFuture<'p> { + type Output = usize; + + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + match self.pipe.try_write_with_context(Some(cx), self.buf) { + Ok(n) => Poll::Ready(n), + Err(TryWriteError::Full) => Poll::Pending, + } + } +} + +impl<'p> Unpin for DynamicWriteFuture<'p> {} + +impl<'p, M, const N: usize> From> for DynamicWriteFuture<'p> +where + M: RawMutex, +{ + fn from(value: WriteFuture<'p, M, N>) -> Self { + Self { + pipe: value.pipe, + buf: value.buf, + } + } +} + +/// Read-only access to a [`DynamicPipe`]. +pub struct DynamicReader<'p> { + pipe: &'p dyn DynamicPipe, +} + +impl<'p> DynamicReader<'p> { + /// Read some bytes from the pipe. + /// + /// See [`Pipe::read()`] + pub fn read<'a>(&'a self, buf: &'a mut [u8]) -> DynamicReadFuture<'a> { + self.pipe.read(buf) + } + + /// Attempt to immediately read some bytes from the pipe. + /// + /// See [`Pipe::try_read()`] + pub fn try_read(&self, buf: &mut [u8]) -> Result { + self.pipe.try_read(buf) + } + + /// Return the contents of the internal buffer, filling it with more data from the inner reader if it is empty. + /// + /// If no bytes are currently available to read, this function waits until at least one byte is available. + /// + /// If the reader is at end-of-file (EOF), an empty slice is returned. + pub fn fill_buf(&mut self) -> DynamicFillBufFuture<'_> { + DynamicFillBufFuture { pipe: Some(self.pipe) } + } + + /// Try returning contents of the internal buffer. + /// + /// If no bytes are currently available to read, this function returns `Err(TryReadError::Empty)`. + /// + /// If the reader is at end-of-file (EOF), an empty slice is returned. + pub fn try_fill_buf(&mut self) -> Result<&[u8], TryReadError> { + unsafe { self.pipe.try_fill_buf_with_context(None) } + } + + /// Tell this buffer that `amt` bytes have been consumed from the buffer, so they should no longer be returned in calls to `fill_buf`. + pub fn consume(&mut self, amt: usize) { + self.pipe.consume(amt) + } +} + +impl<'p, M, const N: usize> From> for DynamicReader<'p> +where + M: RawMutex, +{ + fn from(value: Reader<'p, M, N>) -> Self { + Self { pipe: value.pipe } + } +} + +/// Future returned by [`Pipe::read`] and [`Reader::read`]. +#[must_use = "futures do nothing unless you `.await` or poll them"] +pub struct DynamicReadFuture<'p> { + pipe: &'p dyn DynamicPipe, + buf: &'p mut [u8], +} + +impl<'p> Future for DynamicReadFuture<'p> { + type Output = usize; + + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + match self.pipe.try_read_with_context(Some(cx), self.buf) { + Ok(n) => Poll::Ready(n), + Err(TryReadError::Empty) => Poll::Pending, + } + } +} + +impl<'p> Unpin for DynamicReadFuture<'p> {} + +impl<'p, M, const N: usize> From> for DynamicReadFuture<'p> +where + M: RawMutex, +{ + fn from(value: ReadFuture<'p, M, N>) -> Self { + Self { + pipe: value.pipe, + buf: value.buf, + } + } +} + +/// Future returned by [`DynamicPipe::fill_buf`] and [`DynamicReader::fill_buf`]. +#[must_use = "futures do nothing unless you `.await` or poll them"] +pub struct DynamicFillBufFuture<'p> { + pipe: Option<&'p dyn DynamicPipe>, +} + +impl<'p> Future for DynamicFillBufFuture<'p> { + type Output = &'p [u8]; + + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + let pipe = self.pipe.take().unwrap(); + match unsafe { pipe.try_fill_buf_with_context(Some(cx)) } { + Ok(buf) => Poll::Ready(buf), + Err(TryReadError::Empty) => { + self.pipe = Some(pipe); + Poll::Pending + } + } + } +} + +impl<'p> Unpin for DynamicFillBufFuture<'p> {} + +impl<'p, M, const N: usize> From> for DynamicFillBufFuture<'p> +where + M: RawMutex, +{ + fn from(value: FillBufFuture<'p, M, N>) -> Self { + Self { + pipe: value.pipe.map(|p| p as &dyn DynamicPipe), + } + } +} + #[cfg(test)] mod tests { use futures_executor::ThreadPool; @@ -619,6 +863,35 @@ mod tests { let _ = w.clone(); } + #[test] + fn dynamic_dispatch_pipe() { + let mut c = Pipe::::new(); + let (r, w) = c.split(); + let (mut r, w): (DynamicReader<'_>, DynamicWriter<'_>) = (r.into(), w.into()); + + assert!(w.try_write(&[42, 43]).is_ok()); + let buf = r.try_fill_buf().unwrap(); + assert_eq!(buf, &[42, 43]); + let buf = r.try_fill_buf().unwrap(); + assert_eq!(buf, &[42, 43]); + r.consume(1); + let buf = r.try_fill_buf().unwrap(); + assert_eq!(buf, &[43]); + r.consume(1); + assert_eq!(r.try_fill_buf(), Err(TryReadError::Empty)); + assert_eq!(w.try_write(&[44, 45, 46]), Ok(1)); + assert_eq!(w.try_write(&[45, 46]), Ok(2)); + let buf = r.try_fill_buf().unwrap(); + assert_eq!(buf, &[44]); // only one byte due to wraparound. + r.consume(1); + let buf = r.try_fill_buf().unwrap(); + assert_eq!(buf, &[45, 46]); + assert!(w.try_write(&[47]).is_ok()); + let buf = r.try_fill_buf().unwrap(); + assert_eq!(buf, &[45, 46, 47]); + r.consume(3); + } + #[futures_test::test] async fn receiver_receives_given_try_write_async() { let executor = ThreadPool::new().unwrap(); From ed63f8063732fe9df96c4adf823639c20d7f99af Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Wed, 15 Jan 2025 16:12:36 +0100 Subject: [PATCH 0659/1217] chore: bump embassy-sync version Prepare version 0.6.2 for release --- cyw43/Cargo.toml | 2 +- embassy-boot-nrf/Cargo.toml | 2 +- embassy-boot-rp/Cargo.toml | 2 +- embassy-boot-stm32/Cargo.toml | 2 +- embassy-boot/Cargo.toml | 2 +- embassy-embedded-hal/Cargo.toml | 2 +- embassy-net-driver-channel/Cargo.toml | 2 +- embassy-net-esp-hosted/Cargo.toml | 2 +- embassy-net-nrf91/Cargo.toml | 2 +- embassy-net-ppp/Cargo.toml | 2 +- embassy-net/Cargo.toml | 2 +- embassy-nrf/Cargo.toml | 2 +- embassy-nxp/Cargo.toml | 2 +- embassy-rp/Cargo.toml | 2 +- embassy-stm32-wpan/Cargo.toml | 2 +- embassy-stm32/Cargo.toml | 2 +- embassy-sync/CHANGELOG.md | 2 ++ embassy-sync/Cargo.toml | 2 +- embassy-usb-dfu/Cargo.toml | 2 +- embassy-usb-logger/Cargo.toml | 2 +- embassy-usb-synopsys-otg/Cargo.toml | 2 +- embassy-usb/Cargo.toml | 2 +- examples/boot/application/nrf/Cargo.toml | 2 +- examples/boot/application/rp/Cargo.toml | 2 +- examples/boot/application/stm32f3/Cargo.toml | 2 +- examples/boot/application/stm32f7/Cargo.toml | 2 +- examples/boot/application/stm32h7/Cargo.toml | 2 +- examples/boot/application/stm32l0/Cargo.toml | 2 +- examples/boot/application/stm32l1/Cargo.toml | 2 +- examples/boot/application/stm32l4/Cargo.toml | 2 +- examples/boot/application/stm32wb-dfu/Cargo.toml | 2 +- examples/boot/application/stm32wl/Cargo.toml | 2 +- examples/boot/bootloader/nrf/Cargo.toml | 2 +- examples/boot/bootloader/rp/Cargo.toml | 2 +- examples/boot/bootloader/stm32-dual-bank/Cargo.toml | 2 +- examples/boot/bootloader/stm32/Cargo.toml | 2 +- examples/boot/bootloader/stm32wb-dfu/Cargo.toml | 2 +- examples/lpc55s69/Cargo.toml | 2 +- examples/nrf-rtos-trace/Cargo.toml | 2 +- examples/nrf52810/Cargo.toml | 2 +- examples/nrf52840-rtic/Cargo.toml | 2 +- examples/nrf52840/Cargo.toml | 2 +- examples/nrf5340/Cargo.toml | 2 +- examples/rp/Cargo.toml | 2 +- examples/rp23/Cargo.toml | 2 +- examples/std/Cargo.toml | 2 +- examples/stm32c0/Cargo.toml | 2 +- examples/stm32f0/Cargo.toml | 2 +- examples/stm32f1/Cargo.toml | 2 +- examples/stm32f2/Cargo.toml | 2 +- examples/stm32f3/Cargo.toml | 2 +- examples/stm32f334/Cargo.toml | 2 +- examples/stm32f4/Cargo.toml | 2 +- examples/stm32f7/Cargo.toml | 2 +- examples/stm32g0/Cargo.toml | 2 +- examples/stm32g4/Cargo.toml | 2 +- examples/stm32h5/Cargo.toml | 2 +- examples/stm32h7/Cargo.toml | 2 +- examples/stm32h723/Cargo.toml | 2 +- examples/stm32h735/Cargo.toml | 2 +- examples/stm32h755cm4/Cargo.toml | 2 +- examples/stm32h755cm7/Cargo.toml | 2 +- examples/stm32h7b0/Cargo.toml | 2 +- examples/stm32h7rs/Cargo.toml | 2 +- examples/stm32l0/Cargo.toml | 2 +- examples/stm32l1/Cargo.toml | 2 +- examples/stm32l4/Cargo.toml | 2 +- examples/stm32l432/Cargo.toml | 2 +- examples/stm32l5/Cargo.toml | 2 +- examples/stm32u0/Cargo.toml | 2 +- examples/stm32u5/Cargo.toml | 2 +- examples/stm32wb/Cargo.toml | 2 +- examples/stm32wba/Cargo.toml | 2 +- examples/stm32wl/Cargo.toml | 2 +- examples/wasm/Cargo.toml | 2 +- rustfmt.toml | 3 ++- tests/nrf/Cargo.toml | 2 +- tests/riscv32/Cargo.toml | 2 +- tests/rp/Cargo.toml | 2 +- tests/stm32/Cargo.toml | 2 +- 80 files changed, 82 insertions(+), 79 deletions(-) diff --git a/cyw43/Cargo.toml b/cyw43/Cargo.toml index aac6b19db..34a51338c 100644 --- a/cyw43/Cargo.toml +++ b/cyw43/Cargo.toml @@ -19,7 +19,7 @@ firmware-logs = [] [dependencies] embassy-time = { version = "0.4.0", path = "../embassy-time"} -embassy-sync = { version = "0.6.1", path = "../embassy-sync"} +embassy-sync = { version = "0.6.2", path = "../embassy-sync"} embassy-futures = { version = "0.1.0", path = "../embassy-futures"} embassy-net-driver-channel = { version = "0.3.0", path = "../embassy-net-driver-channel"} diff --git a/embassy-boot-nrf/Cargo.toml b/embassy-boot-nrf/Cargo.toml index cb83ce2a4..c3e0cb5ec 100644 --- a/embassy-boot-nrf/Cargo.toml +++ b/embassy-boot-nrf/Cargo.toml @@ -24,7 +24,7 @@ target = "thumbv7em-none-eabi" defmt = { version = "0.3", optional = true } log = { version = "0.4.17", optional = true } -embassy-sync = { version = "0.6.1", path = "../embassy-sync" } +embassy-sync = { version = "0.6.2", path = "../embassy-sync" } embassy-nrf = { version = "0.3.1", path = "../embassy-nrf", default-features = false } embassy-boot = { version = "0.4.0", path = "../embassy-boot" } cortex-m = { version = "0.7.6" } diff --git a/embassy-boot-rp/Cargo.toml b/embassy-boot-rp/Cargo.toml index 6e8a104cd..8f6499a7b 100644 --- a/embassy-boot-rp/Cargo.toml +++ b/embassy-boot-rp/Cargo.toml @@ -24,7 +24,7 @@ features = ["embassy-rp/rp2040"] defmt = { version = "0.3", optional = true } log = { version = "0.4", optional = true } -embassy-sync = { version = "0.6.1", path = "../embassy-sync" } +embassy-sync = { version = "0.6.2", path = "../embassy-sync" } embassy-rp = { version = "0.3.0", path = "../embassy-rp", default-features = false } embassy-boot = { version = "0.4.0", path = "../embassy-boot" } embassy-time = { version = "0.4.0", path = "../embassy-time" } diff --git a/embassy-boot-stm32/Cargo.toml b/embassy-boot-stm32/Cargo.toml index 2d38ba8b1..7dbe7e22b 100644 --- a/embassy-boot-stm32/Cargo.toml +++ b/embassy-boot-stm32/Cargo.toml @@ -24,7 +24,7 @@ target = "thumbv7em-none-eabi" defmt = { version = "0.3", optional = true } log = { version = "0.4", optional = true } -embassy-sync = { version = "0.6.1", path = "../embassy-sync" } +embassy-sync = { version = "0.6.2", path = "../embassy-sync" } embassy-stm32 = { version = "0.2.0", path = "../embassy-stm32", default-features = false } embassy-boot = { version = "0.4.0", path = "../embassy-boot" } cortex-m = { version = "0.7.6" } diff --git a/embassy-boot/Cargo.toml b/embassy-boot/Cargo.toml index 0a04d661f..4906da0ea 100644 --- a/embassy-boot/Cargo.toml +++ b/embassy-boot/Cargo.toml @@ -29,7 +29,7 @@ digest = "0.10" log = { version = "0.4", optional = true } ed25519-dalek = { version = "2", default-features = false, features = ["digest"], optional = true } embassy-embedded-hal = { version = "0.3.0", path = "../embassy-embedded-hal" } -embassy-sync = { version = "0.6.1", path = "../embassy-sync" } +embassy-sync = { version = "0.6.2", path = "../embassy-sync" } embedded-storage = "0.3.1" embedded-storage-async = { version = "0.4.1" } salty = { version = "0.3", optional = true } diff --git a/embassy-embedded-hal/Cargo.toml b/embassy-embedded-hal/Cargo.toml index ce2ea4aa8..9dd2e419f 100644 --- a/embassy-embedded-hal/Cargo.toml +++ b/embassy-embedded-hal/Cargo.toml @@ -23,7 +23,7 @@ default = ["time"] [dependencies] embassy-futures = { version = "0.1.0", path = "../embassy-futures" } -embassy-sync = { version = "0.6.1", path = "../embassy-sync" } +embassy-sync = { version = "0.6.2", path = "../embassy-sync" } embassy-time = { version = "0.4.0", path = "../embassy-time", optional = true } embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = [ "unproven", diff --git a/embassy-net-driver-channel/Cargo.toml b/embassy-net-driver-channel/Cargo.toml index cabc0c38f..5165621b7 100644 --- a/embassy-net-driver-channel/Cargo.toml +++ b/embassy-net-driver-channel/Cargo.toml @@ -25,6 +25,6 @@ features = ["defmt"] defmt = { version = "0.3", optional = true } log = { version = "0.4.14", optional = true } -embassy-sync = { version = "0.6.1", path = "../embassy-sync" } +embassy-sync = { version = "0.6.2", path = "../embassy-sync" } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver" } diff --git a/embassy-net-esp-hosted/Cargo.toml b/embassy-net-esp-hosted/Cargo.toml index 11ff32988..bab0e6d7c 100644 --- a/embassy-net-esp-hosted/Cargo.toml +++ b/embassy-net-esp-hosted/Cargo.toml @@ -18,7 +18,7 @@ defmt = { version = "0.3", optional = true } log = { version = "0.4.14", optional = true } embassy-time = { version = "0.4.0", path = "../embassy-time" } -embassy-sync = { version = "0.6.1", path = "../embassy-sync"} +embassy-sync = { version = "0.6.2", path = "../embassy-sync"} embassy-futures = { version = "0.1.0", path = "../embassy-futures"} embassy-net-driver-channel = { version = "0.3.0", path = "../embassy-net-driver-channel"} diff --git a/embassy-net-nrf91/Cargo.toml b/embassy-net-nrf91/Cargo.toml index 6c7af9c80..99ec5a318 100644 --- a/embassy-net-nrf91/Cargo.toml +++ b/embassy-net-nrf91/Cargo.toml @@ -21,7 +21,7 @@ nrf-pac = "0.1.0" cortex-m = "0.7.7" embassy-time = { version = "0.4.0", path = "../embassy-time" } -embassy-sync = { version = "0.6.1", path = "../embassy-sync"} +embassy-sync = { version = "0.6.2", path = "../embassy-sync"} embassy-futures = { version = "0.1.0", path = "../embassy-futures"} embassy-net-driver-channel = { version = "0.3.0", path = "../embassy-net-driver-channel"} diff --git a/embassy-net-ppp/Cargo.toml b/embassy-net-ppp/Cargo.toml index 414be5e01..2d82e2ad0 100644 --- a/embassy-net-ppp/Cargo.toml +++ b/embassy-net-ppp/Cargo.toml @@ -21,7 +21,7 @@ embedded-io-async = { version = "0.6.1" } embassy-net-driver-channel = { version = "0.3.0", path = "../embassy-net-driver-channel" } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } ppproto = { version = "0.2.1"} -embassy-sync = { version = "0.6.1", path = "../embassy-sync" } +embassy-sync = { version = "0.6.2", path = "../embassy-sync" } [package.metadata.embassy_docs] src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-ppp-v$VERSION/embassy-net-ppp/src/" diff --git a/embassy-net/Cargo.toml b/embassy-net/Cargo.toml index 0f332f2af..a0827d96b 100644 --- a/embassy-net/Cargo.toml +++ b/embassy-net/Cargo.toml @@ -72,7 +72,7 @@ smoltcp = { version = "0.12.0", default-features = false, features = [ embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver" } embassy-time = { version = "0.4.0", path = "../embassy-time" } -embassy-sync = { version = "0.6.1", path = "../embassy-sync" } +embassy-sync = { version = "0.6.2", path = "../embassy-sync" } embedded-io-async = { version = "0.6.1" } managed = { version = "0.8.0", default-features = false, features = [ "map" ] } diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml index aa1d53b67..1d5485f2a 100644 --- a/embassy-nrf/Cargo.toml +++ b/embassy-nrf/Cargo.toml @@ -137,7 +137,7 @@ _nrf52832_anomaly_109 = [] embassy-time-driver = { version = "0.2", path = "../embassy-time-driver", optional = true } embassy-time-queue-utils = { version = "0.1", path = "../embassy-time-queue-utils", optional = true } embassy-time = { version = "0.4.0", path = "../embassy-time", optional = true } -embassy-sync = { version = "0.6.1", path = "../embassy-sync" } +embassy-sync = { version = "0.6.2", path = "../embassy-sync" } embassy-hal-internal = { version = "0.2.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-3"] } embassy-embedded-hal = { version = "0.3.0", path = "../embassy-embedded-hal", default-features = false } embassy-usb-driver = { version = "0.1.0", path = "../embassy-usb-driver" } diff --git a/embassy-nxp/Cargo.toml b/embassy-nxp/Cargo.toml index fb0a0fed2..cf36a67ec 100644 --- a/embassy-nxp/Cargo.toml +++ b/embassy-nxp/Cargo.toml @@ -8,7 +8,7 @@ cortex-m = "0.7.7" cortex-m-rt = "0.7.0" critical-section = "1.1.2" embassy-hal-internal = { version = "0.2.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-2"] } -embassy-sync = { version = "0.6.1", path = "../embassy-sync" } +embassy-sync = { version = "0.6.2", path = "../embassy-sync" } lpc55-pac = "0.5.0" defmt = "0.3.8" diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index 120e058ed..528d433e1 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml @@ -108,7 +108,7 @@ _test = [] binary-info = ["rt", "dep:rp-binary-info", "rp-binary-info?/binary-info"] [dependencies] -embassy-sync = { version = "0.6.1", path = "../embassy-sync" } +embassy-sync = { version = "0.6.2", path = "../embassy-sync" } embassy-time-driver = { version = "0.2", path = "../embassy-time-driver", optional = true } embassy-time-queue-utils = { version = "0.1", path = "../embassy-time-queue-utils", optional = true } embassy-time = { version = "0.4.0", path = "../embassy-time" } diff --git a/embassy-stm32-wpan/Cargo.toml b/embassy-stm32-wpan/Cargo.toml index 19adc0e1b..3bcfd11a9 100644 --- a/embassy-stm32-wpan/Cargo.toml +++ b/embassy-stm32-wpan/Cargo.toml @@ -20,7 +20,7 @@ features = ["stm32wb55rg", "ble", "mac"] [dependencies] embassy-stm32 = { version = "0.2.0", path = "../embassy-stm32" } -embassy-sync = { version = "0.6.1", path = "../embassy-sync" } +embassy-sync = { version = "0.6.2", path = "../embassy-sync" } embassy-time = { version = "0.4.0", path = "../embassy-time", optional = true } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } embassy-hal-internal = { version = "0.2.0", path = "../embassy-hal-internal" } diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 163524343..068c5e230 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -42,7 +42,7 @@ features = ["defmt", "unstable-pac", "exti", "time-driver-any", "time", "stm32h7 rustdoc-args = ["--cfg", "docsrs"] [dependencies] -embassy-sync = { version = "0.6.1", path = "../embassy-sync" } +embassy-sync = { version = "0.6.2", path = "../embassy-sync" } embassy-time = { version = "0.4.0", path = "../embassy-time", optional = true } embassy-time-driver = { version = "0.2", path = "../embassy-time-driver", optional = true } embassy-time-queue-utils = { version = "0.1", path = "../embassy-time-queue-utils", optional = true } diff --git a/embassy-sync/CHANGELOG.md b/embassy-sync/CHANGELOG.md index b96c9416d..2049e0f11 100644 --- a/embassy-sync/CHANGELOG.md +++ b/embassy-sync/CHANGELOG.md @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +## 0.6.2 - 2025-01-15 + - Add dynamic dispatch variant of `Pipe`. ## 0.6.1 - 2024-11-22 diff --git a/embassy-sync/Cargo.toml b/embassy-sync/Cargo.toml index 1bd2f290e..4430f1956 100644 --- a/embassy-sync/Cargo.toml +++ b/embassy-sync/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "embassy-sync" -version = "0.6.1" +version = "0.6.2" edition = "2021" description = "no-std, no-alloc synchronization primitives with async support" repository = "https://github.com/embassy-rs/embassy" diff --git a/embassy-usb-dfu/Cargo.toml b/embassy-usb-dfu/Cargo.toml index a9565c3a5..eba902c74 100644 --- a/embassy-usb-dfu/Cargo.toml +++ b/embassy-usb-dfu/Cargo.toml @@ -33,7 +33,7 @@ bitflags = "2.4.1" cortex-m = { version = "0.7.7", features = ["inline-asm"], optional = true } embassy-boot = { version = "0.4.0", path = "../embassy-boot" } embassy-futures = { version = "0.1.1", path = "../embassy-futures" } -embassy-sync = { version = "0.6.1", path = "../embassy-sync" } +embassy-sync = { version = "0.6.2", path = "../embassy-sync" } embassy-time = { version = "0.4.0", path = "../embassy-time" } embassy-usb = { version = "0.4.0", path = "../embassy-usb", default-features = false } embedded-storage = { version = "0.3.1" } diff --git a/embassy-usb-logger/Cargo.toml b/embassy-usb-logger/Cargo.toml index 69b0a98b0..c670b41b6 100644 --- a/embassy-usb-logger/Cargo.toml +++ b/embassy-usb-logger/Cargo.toml @@ -16,6 +16,6 @@ target = "thumbv7em-none-eabi" [dependencies] embassy-usb = { version = "0.4.0", path = "../embassy-usb" } -embassy-sync = { version = "0.6.1", path = "../embassy-sync" } +embassy-sync = { version = "0.6.2", path = "../embassy-sync" } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } log = "0.4" diff --git a/embassy-usb-synopsys-otg/Cargo.toml b/embassy-usb-synopsys-otg/Cargo.toml index 487cc556b..f9703a54a 100644 --- a/embassy-usb-synopsys-otg/Cargo.toml +++ b/embassy-usb-synopsys-otg/Cargo.toml @@ -18,7 +18,7 @@ target = "thumbv7em-none-eabi" [dependencies] critical-section = "1.1" -embassy-sync = { version = "0.6.1", path = "../embassy-sync" } +embassy-sync = { version = "0.6.2", path = "../embassy-sync" } embassy-usb-driver = { version = "0.1.0", path = "../embassy-usb-driver" } defmt = { version = "0.3", optional = true } diff --git a/embassy-usb/Cargo.toml b/embassy-usb/Cargo.toml index d0ce3f1df..771190c89 100644 --- a/embassy-usb/Cargo.toml +++ b/embassy-usb/Cargo.toml @@ -48,7 +48,7 @@ max-handler-count-8 = [] [dependencies] embassy-futures = { version = "0.1.0", path = "../embassy-futures" } embassy-usb-driver = { version = "0.1.0", path = "../embassy-usb-driver" } -embassy-sync = { version = "0.6.1", path = "../embassy-sync" } +embassy-sync = { version = "0.6.2", path = "../embassy-sync" } embassy-net-driver-channel = { version = "0.3.0", path = "../embassy-net-driver-channel" } defmt = { version = "0.3", optional = true } diff --git a/examples/boot/application/nrf/Cargo.toml b/examples/boot/application/nrf/Cargo.toml index 0680c9af3..78227c49c 100644 --- a/examples/boot/application/nrf/Cargo.toml +++ b/examples/boot/application/nrf/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } +embassy-sync = { version = "0.6.2", path = "../../../../embassy-sync" } embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["task-arena-size-16384", "arch-cortex-m", "executor-thread", "arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [] } embassy-nrf = { version = "0.3.1", path = "../../../../embassy-nrf", features = ["time-driver-rtc1", "gpiote", ] } diff --git a/examples/boot/application/rp/Cargo.toml b/examples/boot/application/rp/Cargo.toml index 0c58bc624..ee0247c17 100644 --- a/examples/boot/application/rp/Cargo.toml +++ b/examples/boot/application/rp/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } +embassy-sync = { version = "0.6.2", path = "../../../../embassy-sync" } embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["task-arena-size-16384", "arch-cortex-m", "executor-thread", "arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [] } embassy-rp = { version = "0.3.0", path = "../../../../embassy-rp", features = ["time-driver", "rp2040"] } diff --git a/examples/boot/application/stm32f3/Cargo.toml b/examples/boot/application/stm32f3/Cargo.toml index 35a8544fd..2590e9c49 100644 --- a/examples/boot/application/stm32f3/Cargo.toml +++ b/examples/boot/application/stm32f3/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } +embassy-sync = { version = "0.6.2", path = "../../../../embassy-sync" } embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32f303re", "time-driver-any", "exti"] } diff --git a/examples/boot/application/stm32f7/Cargo.toml b/examples/boot/application/stm32f7/Cargo.toml index dee1139df..fac73afd7 100644 --- a/examples/boot/application/stm32f7/Cargo.toml +++ b/examples/boot/application/stm32f7/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } +embassy-sync = { version = "0.6.2", path = "../../../../embassy-sync" } embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32f767zi", "time-driver-any", "exti"] } diff --git a/examples/boot/application/stm32h7/Cargo.toml b/examples/boot/application/stm32h7/Cargo.toml index f0899cd86..587d303ab 100644 --- a/examples/boot/application/stm32h7/Cargo.toml +++ b/examples/boot/application/stm32h7/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } +embassy-sync = { version = "0.6.2", path = "../../../../embassy-sync" } embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32h743zi", "time-driver-any", "exti"] } diff --git a/examples/boot/application/stm32l0/Cargo.toml b/examples/boot/application/stm32l0/Cargo.toml index fd4732742..b3c580d3d 100644 --- a/examples/boot/application/stm32l0/Cargo.toml +++ b/examples/boot/application/stm32l0/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } +embassy-sync = { version = "0.6.2", path = "../../../../embassy-sync" } embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32l072cz", "time-driver-any", "exti", "memory-x"] } diff --git a/examples/boot/application/stm32l1/Cargo.toml b/examples/boot/application/stm32l1/Cargo.toml index 5792c87d6..8c49be914 100644 --- a/examples/boot/application/stm32l1/Cargo.toml +++ b/examples/boot/application/stm32l1/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } +embassy-sync = { version = "0.6.2", path = "../../../../embassy-sync" } embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32l151cb-a", "time-driver-any", "exti"] } diff --git a/examples/boot/application/stm32l4/Cargo.toml b/examples/boot/application/stm32l4/Cargo.toml index d2b600560..28c74303a 100644 --- a/examples/boot/application/stm32l4/Cargo.toml +++ b/examples/boot/application/stm32l4/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } +embassy-sync = { version = "0.6.2", path = "../../../../embassy-sync" } embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32l475vg", "time-driver-any", "exti"] } diff --git a/examples/boot/application/stm32wb-dfu/Cargo.toml b/examples/boot/application/stm32wb-dfu/Cargo.toml index 7e0f90e3a..deaf4c388 100644 --- a/examples/boot/application/stm32wb-dfu/Cargo.toml +++ b/examples/boot/application/stm32wb-dfu/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } +embassy-sync = { version = "0.6.2", path = "../../../../embassy-sync" } embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32wb55rg", "time-driver-any", "exti"] } diff --git a/examples/boot/application/stm32wl/Cargo.toml b/examples/boot/application/stm32wl/Cargo.toml index 59ef48edc..890d0b510 100644 --- a/examples/boot/application/stm32wl/Cargo.toml +++ b/examples/boot/application/stm32wl/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } +embassy-sync = { version = "0.6.2", path = "../../../../embassy-sync" } embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32wl55jc-cm4", "time-driver-any", "exti"] } diff --git a/examples/boot/bootloader/nrf/Cargo.toml b/examples/boot/bootloader/nrf/Cargo.toml index c2e8bbe53..34a0553e3 100644 --- a/examples/boot/bootloader/nrf/Cargo.toml +++ b/examples/boot/bootloader/nrf/Cargo.toml @@ -12,7 +12,7 @@ defmt-rtt = { version = "0.4", optional = true } embassy-nrf = { path = "../../../../embassy-nrf", features = [] } embassy-boot-nrf = { path = "../../../../embassy-boot-nrf" } cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } -embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } +embassy-sync = { version = "0.6.2", path = "../../../../embassy-sync" } cortex-m-rt = { version = "0.7" } cfg-if = "1.0.0" diff --git a/examples/boot/bootloader/rp/Cargo.toml b/examples/boot/bootloader/rp/Cargo.toml index 24df3da82..7c9c3c779 100644 --- a/examples/boot/bootloader/rp/Cargo.toml +++ b/examples/boot/bootloader/rp/Cargo.toml @@ -11,7 +11,7 @@ defmt-rtt = { version = "0.4", optional = true } embassy-rp = { path = "../../../../embassy-rp", features = ["rp2040"] } embassy-boot-rp = { path = "../../../../embassy-boot-rp" } -embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } +embassy-sync = { version = "0.6.2", path = "../../../../embassy-sync" } embassy-time = { path = "../../../../embassy-time", features = [] } cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } diff --git a/examples/boot/bootloader/stm32-dual-bank/Cargo.toml b/examples/boot/bootloader/stm32-dual-bank/Cargo.toml index 81e0026c6..4beb9c61c 100644 --- a/examples/boot/bootloader/stm32-dual-bank/Cargo.toml +++ b/examples/boot/bootloader/stm32-dual-bank/Cargo.toml @@ -15,7 +15,7 @@ cortex-m = { version = "0.7.6", features = [ "inline-asm", "critical-section-single-core", ] } -embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } +embassy-sync = { version = "0.6.2", path = "../../../../embassy-sync" } cortex-m-rt = { version = "0.7" } embedded-storage = "0.3.1" embedded-storage-async = "0.4.0" diff --git a/examples/boot/bootloader/stm32/Cargo.toml b/examples/boot/bootloader/stm32/Cargo.toml index f35e4e713..9abad8636 100644 --- a/examples/boot/bootloader/stm32/Cargo.toml +++ b/examples/boot/bootloader/stm32/Cargo.toml @@ -12,7 +12,7 @@ defmt-rtt = { version = "0.4", optional = true } embassy-stm32 = { path = "../../../../embassy-stm32", features = [] } embassy-boot-stm32 = { path = "../../../../embassy-boot-stm32" } cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } -embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } +embassy-sync = { version = "0.6.2", path = "../../../../embassy-sync" } cortex-m-rt = { version = "0.7" } embedded-storage = "0.3.1" embedded-storage-async = "0.4.0" diff --git a/examples/boot/bootloader/stm32wb-dfu/Cargo.toml b/examples/boot/bootloader/stm32wb-dfu/Cargo.toml index f8d66e777..01343b86b 100644 --- a/examples/boot/bootloader/stm32wb-dfu/Cargo.toml +++ b/examples/boot/bootloader/stm32wb-dfu/Cargo.toml @@ -12,7 +12,7 @@ defmt-rtt = { version = "0.4", optional = true } embassy-stm32 = { path = "../../../../embassy-stm32", features = [] } embassy-boot-stm32 = { path = "../../../../embassy-boot-stm32" } cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } -embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } +embassy-sync = { version = "0.6.2", path = "../../../../embassy-sync" } cortex-m-rt = { version = "0.7" } embedded-storage = "0.3.1" embedded-storage-async = "0.4.0" diff --git a/examples/lpc55s69/Cargo.toml b/examples/lpc55s69/Cargo.toml index c8efc2e72..afd76f9ac 100644 --- a/examples/lpc55s69/Cargo.toml +++ b/examples/lpc55s69/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-nxp = { version = "0.1.0", path = "../../embassy-nxp", features = ["rt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt"] } -embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt"] } panic-halt = "0.2.0" cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } diff --git a/examples/nrf-rtos-trace/Cargo.toml b/examples/nrf-rtos-trace/Cargo.toml index 09cba5073..af12212cd 100644 --- a/examples/nrf-rtos-trace/Cargo.toml +++ b/examples/nrf-rtos-trace/Cargo.toml @@ -15,7 +15,7 @@ log = [ ] [dependencies] -embassy-sync = { version = "0.6.1", path = "../../embassy-sync" } +embassy-sync = { version = "0.6.2", path = "../../embassy-sync" } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "rtos-trace"] } embassy-time = { version = "0.4.0", path = "../../embassy-time" } embassy-nrf = { version = "0.3.1", path = "../../embassy-nrf", features = ["nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] } diff --git a/examples/nrf52810/Cargo.toml b/examples/nrf52810/Cargo.toml index bfeaf946f..297a52537 100644 --- a/examples/nrf52810/Cargo.toml +++ b/examples/nrf52810/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } -embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.3.1", path = "../../embassy-nrf", features = ["defmt", "nrf52810", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } diff --git a/examples/nrf52840-rtic/Cargo.toml b/examples/nrf52840-rtic/Cargo.toml index 518ac06bd..ac3d2006c 100644 --- a/examples/nrf52840-rtic/Cargo.toml +++ b/examples/nrf52840-rtic/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" rtic = { version = "2", features = ["thumbv7-backend"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } -embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = [ "defmt", "defmt-timestamp-uptime"] } embassy-time-queue-utils = { version = "0.1", path = "../../embassy-time-queue-utils", features = ["generic-queue-8"] } embassy-nrf = { version = "0.3.1", path = "../../embassy-nrf", features = [ "defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } diff --git a/examples/nrf52840/Cargo.toml b/examples/nrf52840/Cargo.toml index 1c65098fe..f48cbf586 100644 --- a/examples/nrf52840/Cargo.toml +++ b/examples/nrf52840/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } -embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.3.1", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } diff --git a/examples/nrf5340/Cargo.toml b/examples/nrf5340/Cargo.toml index be46b7974..93bec8668 100644 --- a/examples/nrf5340/Cargo.toml +++ b/examples/nrf5340/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } -embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.3.1", path = "../../embassy-nrf", features = ["defmt", "nrf5340-app-s", "time-driver-rtc1", "gpiote", "unstable-pac"] } diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index 5294ec477..50cfdca1e 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-embedded-hal = { version = "0.3.0", path = "../../embassy-embedded-hal", features = ["defmt"] } -embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-98304", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-rp = { version = "0.3.0", path = "../../embassy-rp", features = ["defmt", "unstable-pac", "time-driver", "critical-section-impl", "rp2040"] } diff --git a/examples/rp23/Cargo.toml b/examples/rp23/Cargo.toml index 8f9c14c5c..9cfaf8a3f 100644 --- a/examples/rp23/Cargo.toml +++ b/examples/rp23/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-embedded-hal = { version = "0.3.0", path = "../../embassy-embedded-hal", features = ["defmt"] } -embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-98304", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-rp = { version = "0.3.0", path = "../../embassy-rp", features = ["defmt", "unstable-pac", "time-driver", "critical-section-impl", "rp235xa", "binary-info"] } diff --git a/examples/std/Cargo.toml b/examples/std/Cargo.toml index 3c9b571cd..b67e5e817 100644 --- a/examples/std/Cargo.toml +++ b/examples/std/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["log"] } +embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["log"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-std", "executor-thread", "log"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["log", "std", ] } embassy-net = { version = "0.6.0", path = "../../embassy-net", features=[ "log", "medium-ethernet", "medium-ip", "tcp", "udp", "dns", "dhcpv4", "proto-ipv6"] } diff --git a/examples/stm32c0/Cargo.toml b/examples/stm32c0/Cargo.toml index 3f0aa632f..767b742f7 100644 --- a/examples/stm32c0/Cargo.toml +++ b/examples/stm32c0/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32c031c6 to your chip name, if necessary. embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32c031c6", "memory-x", "unstable-pac", "exti"] } -embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } diff --git a/examples/stm32f0/Cargo.toml b/examples/stm32f0/Cargo.toml index 2f7246e29..932a97dc8 100644 --- a/examples/stm32f0/Cargo.toml +++ b/examples/stm32f0/Cargo.toml @@ -12,7 +12,7 @@ cortex-m-rt = "0.7.0" defmt = "0.3" defmt-rtt = "0.4" panic-probe = { version = "0.3", features = ["print-defmt"] } -embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } static_cell = "2" diff --git a/examples/stm32f1/Cargo.toml b/examples/stm32f1/Cargo.toml index 4a090ea04..fe800bc80 100644 --- a/examples/stm32f1/Cargo.toml +++ b/examples/stm32f1/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32f103c8 to your chip name, if necessary. embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f103c8", "unstable-pac", "memory-x", "time-driver-any" ] } -embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/stm32f2/Cargo.toml b/examples/stm32f2/Cargo.toml index 50b2cd67c..26be3f485 100644 --- a/examples/stm32f2/Cargo.toml +++ b/examples/stm32f2/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32f207zg to your chip name, if necessary. embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f207zg", "unstable-pac", "memory-x", "time-driver-any", "exti"] } -embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } diff --git a/examples/stm32f3/Cargo.toml b/examples/stm32f3/Cargo.toml index 9204971d7..31bf040b0 100644 --- a/examples/stm32f3/Cargo.toml +++ b/examples/stm32f3/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32f303ze to your chip name, if necessary. embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f303ze", "unstable-pac", "memory-x", "time-driver-tim2", "exti"] } -embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/stm32f334/Cargo.toml b/examples/stm32f334/Cargo.toml index aef92ca3f..5fb6d60c5 100644 --- a/examples/stm32f334/Cargo.toml +++ b/examples/stm32f334/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f334r8", "unstable-pac", "memory-x", "time-driver-any", "exti"] } diff --git a/examples/stm32f4/Cargo.toml b/examples/stm32f4/Cargo.toml index f2b077949..8b145a01e 100644 --- a/examples/stm32f4/Cargo.toml +++ b/examples/stm32f4/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32f429zi to your chip name, if necessary. embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = ["defmt", "stm32f429zi", "unstable-pac", "memory-x", "time-driver-tim4", "exti", "chrono"] } -embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defmt" ] } diff --git a/examples/stm32f7/Cargo.toml b/examples/stm32f7/Cargo.toml index c7a2db5df..1f2eae539 100644 --- a/examples/stm32f7/Cargo.toml +++ b/examples/stm32f7/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32f777zi to your chip name, if necessary. embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = ["defmt", "stm32f777zi", "memory-x", "unstable-pac", "time-driver-any", "exti"] } -embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.6.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } diff --git a/examples/stm32g0/Cargo.toml b/examples/stm32g0/Cargo.toml index 675b03fa2..319d84179 100644 --- a/examples/stm32g0/Cargo.toml +++ b/examples/stm32g0/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32g0b1re to your chip name, if necessary. embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32g0b1re", "memory-x", "unstable-pac", "exti"] } -embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.4.0", path = "../../embassy-usb", default-features = false, features = ["defmt"] } diff --git a/examples/stm32g4/Cargo.toml b/examples/stm32g4/Cargo.toml index 6c3a4e8cb..aa01d84e2 100644 --- a/examples/stm32g4/Cargo.toml +++ b/examples/stm32g4/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32g491re to your chip name, if necessary. embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32g491re", "memory-x", "unstable-pac", "exti"] } -embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/stm32h5/Cargo.toml b/examples/stm32h5/Cargo.toml index ac670ff8f..99101144e 100644 --- a/examples/stm32h5/Cargo.toml +++ b/examples/stm32h5/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32h563zi to your chip name, if necessary. embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = ["defmt", "stm32h563zi", "memory-x", "time-driver-any", "exti", "unstable-pac", "low-power"] } -embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.6.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6"] } diff --git a/examples/stm32h7/Cargo.toml b/examples/stm32h7/Cargo.toml index 224dc45c6..8730693c8 100644 --- a/examples/stm32h7/Cargo.toml +++ b/examples/stm32h7/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32h743bi to your chip name, if necessary. embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = ["defmt", "stm32h743bi", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } -embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } embassy-embedded-hal = { version = "0.3.0", path = "../../embassy-embedded-hal" } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } diff --git a/examples/stm32h723/Cargo.toml b/examples/stm32h723/Cargo.toml index e9ff3a352..148d09dd6 100644 --- a/examples/stm32h723/Cargo.toml +++ b/examples/stm32h723/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32h723zg to your chip name, if necessary. embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = ["defmt", "stm32h723zg", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } -embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32h735/Cargo.toml b/examples/stm32h735/Cargo.toml index e3e07e086..1ae6ed253 100644 --- a/examples/stm32h735/Cargo.toml +++ b/examples/stm32h735/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = ["defmt", "stm32h735ig", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } -embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } embassy-embedded-hal = { version = "0.3.0", path = "../../embassy-embedded-hal" } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } diff --git a/examples/stm32h755cm4/Cargo.toml b/examples/stm32h755cm4/Cargo.toml index 0bafb24e3..01e7ffcbf 100644 --- a/examples/stm32h755cm4/Cargo.toml +++ b/examples/stm32h755cm4/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32h755zi-cm4 to your chip name, if necessary. embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = ["defmt", "stm32h755zi-cm4", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } -embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } embassy-embedded-hal = { version = "0.3.0", path = "../../embassy-embedded-hal" } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } diff --git a/examples/stm32h755cm7/Cargo.toml b/examples/stm32h755cm7/Cargo.toml index d21bc00a2..67d270bdb 100644 --- a/examples/stm32h755cm7/Cargo.toml +++ b/examples/stm32h755cm7/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32h743bi to your chip name, if necessary. embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = ["defmt", "stm32h755zi-cm7", "time-driver-tim3", "exti", "memory-x", "unstable-pac", "chrono"] } -embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } embassy-embedded-hal = { version = "0.3.0", path = "../../embassy-embedded-hal" } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } diff --git a/examples/stm32h7b0/Cargo.toml b/examples/stm32h7b0/Cargo.toml index 6189f225c..67ae54047 100644 --- a/examples/stm32h7b0/Cargo.toml +++ b/examples/stm32h7b0/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = ["defmt", "stm32h7b0vb", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } -embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } embassy-embedded-hal = { version = "0.3.0", path = "../../embassy-embedded-hal" } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } diff --git a/examples/stm32h7rs/Cargo.toml b/examples/stm32h7rs/Cargo.toml index 621fea21f..d53c546f2 100644 --- a/examples/stm32h7rs/Cargo.toml +++ b/examples/stm32h7rs/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32h743bi to your chip name, if necessary. embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = ["defmt", "stm32h7s3l8", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } -embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.6.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } diff --git a/examples/stm32l0/Cargo.toml b/examples/stm32l0/Cargo.toml index 5d99de570..189b0e8d4 100644 --- a/examples/stm32l0/Cargo.toml +++ b/examples/stm32l0/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32l072cz to your chip name, if necessary. embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = ["defmt", "stm32l073rz", "unstable-pac", "time-driver-any", "exti", "memory-x"] } -embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } diff --git a/examples/stm32l1/Cargo.toml b/examples/stm32l1/Cargo.toml index 2392c4136..6066b6dc7 100644 --- a/examples/stm32l1/Cargo.toml +++ b/examples/stm32l1/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [ "defmt", "stm32l151cb-a", "time-driver-any", "memory-x"] } diff --git a/examples/stm32l4/Cargo.toml b/examples/stm32l4/Cargo.toml index d82d91d35..76e2b1e6e 100644 --- a/examples/stm32l4/Cargo.toml +++ b/examples/stm32l4/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32l4s5vi to your chip name, if necessary. embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32l4r5zi", "memory-x", "time-driver-any", "exti", "chrono"] } -embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768", ] } embassy-embedded-hal = { version = "0.3.0", path = "../../embassy-embedded-hal" } diff --git a/examples/stm32l432/Cargo.toml b/examples/stm32l432/Cargo.toml index 87ee392a1..71bff8667 100644 --- a/examples/stm32l432/Cargo.toml +++ b/examples/stm32l432/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32l4s5vi to your chip name, if necessary. embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32l432kc", "memory-x", "time-driver-any", "exti", "chrono"] } -embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = [ "defmt" ] } +embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = [ "defmt" ] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = [ "task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt" ] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = [ "defmt", "defmt-timestamp-uptime", "tick-hz-32_768" ] } defmt = "0.3" diff --git a/examples/stm32l5/Cargo.toml b/examples/stm32l5/Cargo.toml index 56dc907a7..0fe5876c8 100644 --- a/examples/stm32l5/Cargo.toml +++ b/examples/stm32l5/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32l552ze to your chip name, if necessary. embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32l552ze", "time-driver-any", "exti", "memory-x", "low-power"] } -embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/stm32u0/Cargo.toml b/examples/stm32u0/Cargo.toml index 722e2125b..efcb9bf4d 100644 --- a/examples/stm32u0/Cargo.toml +++ b/examples/stm32u0/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32u083rc to your chip name, if necessary. embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32u083rc", "memory-x", "unstable-pac", "exti", "chrono"] } -embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.4.0", path = "../../embassy-usb", default-features = false, features = ["defmt"] } diff --git a/examples/stm32u5/Cargo.toml b/examples/stm32u5/Cargo.toml index d31a34410..33e75cf1e 100644 --- a/examples/stm32u5/Cargo.toml +++ b/examples/stm32u5/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32u5g9zj to your chip name, if necessary. embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = ["defmt", "unstable-pac", "stm32u5g9zj", "time-driver-any", "memory-x" ] } -embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/stm32wb/Cargo.toml b/examples/stm32wb/Cargo.toml index a61acb9ea..4a5c79053 100644 --- a/examples/stm32wb/Cargo.toml +++ b/examples/stm32wb/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32wb55rg to your chip name in both dependencies, if necessary. embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [ "defmt", "stm32wb55rg", "time-driver-any", "memory-x", "exti"] } embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", features = ["defmt", "stm32wb55rg"] } -embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.6.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", ], optional=true } diff --git a/examples/stm32wba/Cargo.toml b/examples/stm32wba/Cargo.toml index 8af3db095..59a41da88 100644 --- a/examples/stm32wba/Cargo.toml +++ b/examples/stm32wba/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [ "defmt", "stm32wba52cg", "time-driver-any", "memory-x", "exti"] } -embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.6.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", ], optional=true } diff --git a/examples/stm32wl/Cargo.toml b/examples/stm32wl/Cargo.toml index ead72bf04..194e58459 100644 --- a/examples/stm32wl/Cargo.toml +++ b/examples/stm32wl/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32wl55jc-cm4 to your chip name, if necessary. embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = ["defmt", "stm32wl55jc-cm4", "time-driver-any", "memory-x", "unstable-pac", "exti", "chrono"] } -embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-4096", "arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-embedded-hal = { version = "0.3.0", path = "../../embassy-embedded-hal" } diff --git a/examples/wasm/Cargo.toml b/examples/wasm/Cargo.toml index 8a97f4d25..3a27f913c 100644 --- a/examples/wasm/Cargo.toml +++ b/examples/wasm/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" crate-type = ["cdylib"] [dependencies] -embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["log"] } +embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["log"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-wasm", "executor-thread", "log"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["log", "wasm", ] } diff --git a/rustfmt.toml b/rustfmt.toml index 3639f4386..592ad27ff 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -1,3 +1,4 @@ group_imports = "StdExternalCrate" imports_granularity = "Module" -max_width=120 \ No newline at end of file +edition = "2021" +max_width=120 diff --git a/tests/nrf/Cargo.toml b/tests/nrf/Cargo.toml index 030d24fbd..3f76031f0 100644 --- a/tests/nrf/Cargo.toml +++ b/tests/nrf/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" teleprobe-meta = "1" embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } -embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt", ] } +embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt", ] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.3.1", path = "../../embassy-nrf", features = ["defmt", "time-driver-rtc1", "gpiote", "unstable-pac"] } diff --git a/tests/riscv32/Cargo.toml b/tests/riscv32/Cargo.toml index 51a113115..446326d8a 100644 --- a/tests/riscv32/Cargo.toml +++ b/tests/riscv32/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] critical-section = { version = "1.1.1", features = ["restore-state-bool"] } -embassy-sync = { version = "0.6.1", path = "../../embassy-sync" } +embassy-sync = { version = "0.6.2", path = "../../embassy-sync" } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-riscv32", "executor-thread"] } embassy-time = { version = "0.4.0", path = "../../embassy-time" } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/tests/rp/Cargo.toml b/tests/rp/Cargo.toml index dc3ca3202..03e387886 100644 --- a/tests/rp/Cargo.toml +++ b/tests/rp/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] teleprobe-meta = "1.1" -embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", ] } embassy-rp = { version = "0.3.0", path = "../../embassy-rp", features = [ "defmt", "unstable-pac", "time-driver", "critical-section-impl", "intrinsics", "rom-v2-intrinsics", "run-from-ram", "rp2040"] } diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml index ff42462fe..0b96ab503 100644 --- a/tests/stm32/Cargo.toml +++ b/tests/stm32/Cargo.toml @@ -59,7 +59,7 @@ cm0 = ["portable-atomic/unsafe-assume-single-core"] [dependencies] teleprobe-meta = "1" -embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "tick-hz-131_072", "defmt-timestamp-uptime"] } embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "memory-x", "time-driver-any"] } From 617f6e7855dfe6f9b36840263cd3bda5c86f61e7 Mon Sep 17 00:00:00 2001 From: Adrian Wowk Date: Wed, 15 Jan 2025 14:52:49 -0600 Subject: [PATCH 0660/1217] fix: enable RP2350 watchdog tick generator --- embassy-rp/src/clocks.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs index e82beb0f1..2ac2c925e 100644 --- a/embassy-rp/src/clocks.rs +++ b/embassy-rp/src/clocks.rs @@ -524,8 +524,13 @@ pub(crate) unsafe fn init(config: ClockConfig) { // Configure tick generator on the 2350 #[cfg(feature = "_rp235x")] { - pac::TICKS.timer0_cycles().write(|w| w.0 = clk_ref_freq / 1_000_000); + let cycle_count = clk_ref_freq / 1_000_000; + + pac::TICKS.timer0_cycles().write(|w| w.0 = cycle_count); pac::TICKS.timer0_ctrl().write(|w| w.set_enable(true)); + + pac::TICKS.watchdog_cycles().write(|w| w.0 = cycle_count); + pac::TICKS.watchdog_ctrl().write(|w| w.set_enable(true)); } let (sys_src, sys_aux, clk_sys_freq) = { From a40e1699cd2a1ca00e28f8f08b2bbd5c47a93686 Mon Sep 17 00:00:00 2001 From: Haobo Gu Date: Thu, 16 Jan 2025 14:18:37 +0800 Subject: [PATCH 0661/1217] doc: embassy-time doc Signed-off-by: Haobo Gu --- embassy-time/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-time/Cargo.toml b/embassy-time/Cargo.toml index 374b460c9..a25673ef5 100644 --- a/embassy-time/Cargo.toml +++ b/embassy-time/Cargo.toml @@ -51,7 +51,7 @@ mock-driver = ["tick-hz-1_000_000", "dep:embassy-time-queue-utils"] #! To enable it, enable any of the features below. #! #! The features also set how many timers are used for the generic queue. At most one -#! `generic-queue-*` feature can be enabled. If none is enabled, a default of 64 timers is used. +#! `generic-queue-*` feature can be enabled. If none is enabled, `queue_integrated` is used. #! #! When using embassy-time from libraries, you should *not* enable any `generic-queue-*` feature, to allow the #! end user to pick. From 9a159a8db0638ea2971eed130a2ae34743da640a Mon Sep 17 00:00:00 2001 From: Martin Algesten Date: Thu, 16 Jan 2025 11:56:46 +0100 Subject: [PATCH 0662/1217] Full RCC support for STM32F107 --- embassy-stm32/src/rcc/f013.rs | 112 +++++++++++++++++++++++++++++++++- 1 file changed, 109 insertions(+), 3 deletions(-) diff --git a/embassy-stm32/src/rcc/f013.rs b/embassy-stm32/src/rcc/f013.rs index 57c5cd5b2..27e43fa56 100644 --- a/embassy-stm32/src/rcc/f013.rs +++ b/embassy-stm32/src/rcc/f013.rs @@ -4,11 +4,15 @@ pub use crate::pac::rcc::vals::Adcpre as ADCPrescaler; #[cfg(stm32f3)] pub use crate::pac::rcc::vals::Adcpres as AdcPllPrescaler; use crate::pac::rcc::vals::Pllsrc; -#[cfg(stm32f1)] +#[cfg(all(stm32f1, not(stm32f107)))] pub use crate::pac::rcc::vals::Pllxtpre as PllPreDiv; #[cfg(any(stm32f0, stm32f3))] pub use crate::pac::rcc::vals::Prediv as PllPreDiv; pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Pllmul as PllMul, Ppre as APBPrescaler, Sw as Sysclk}; +#[cfg(stm32f107)] +pub use crate::pac::rcc::vals::{ + I2s2src, Pll2mul as Pll2Mul, Prediv1 as PllPreDiv, Prediv1src as PreDiv1Src, Usbpre as UsbPre, +}; use crate::pac::{FLASH, RCC}; use crate::time::Hertz; @@ -52,6 +56,12 @@ pub struct Pll { pub mul: PllMul, } +#[cfg(stm32f107)] +#[derive(Clone, Copy)] +pub struct Pll2Or3 { + pub mul: Pll2Mul, +} + #[cfg(all(stm32f3, not(rcc_f37)))] #[derive(Clone, Copy)] pub enum AdcClockSource { @@ -85,6 +95,14 @@ pub struct Config { pub sys: Sysclk, pub pll: Option, + #[cfg(stm32f107)] + pub pll2: Option, + #[cfg(stm32f107)] + pub pll3: Option, + #[cfg(stm32f107)] + pub prediv1_src: Option, + #[cfg(stm32f107)] + pub prediv2: Option, pub ahb_pre: AHBPrescaler, pub apb1_pre: APBPrescaler, @@ -99,6 +117,11 @@ pub struct Config { #[cfg(all(stm32f3, not(rcc_f37), any(peri_adc3_common, peri_adc34_common)))] pub adc34: AdcClockSource, + #[cfg(stm32f107)] + pub i2s2_src: Option, + #[cfg(stm32f107)] + pub i2s3_src: Option, + /// Per-peripheral kernel clock selection muxes pub mux: super::mux::ClockMux, @@ -114,6 +137,16 @@ impl Default for Config { hsi48: Some(Default::default()), sys: Sysclk::HSI, pll: None, + + #[cfg(stm32f107)] + pll2: None, + #[cfg(stm32f107)] + pll3: None, + #[cfg(stm32f107)] + prediv1_src: None, + #[cfg(stm32f107)] + prediv2: None, + ahb_pre: AHBPrescaler::DIV1, apb1_pre: APBPrescaler::DIV1, #[cfg(not(stm32f0))] @@ -129,6 +162,11 @@ impl Default for Config { #[cfg(all(stm32f3, not(rcc_f37), any(peri_adc3_common, peri_adc34_common)))] adc34: AdcClockSource::Hclk(AdcHclkPrescaler::Div1), + #[cfg(stm32f107)] + i2s2_src: None, + #[cfg(stm32f107)] + i2s3_src: None, + mux: Default::default(), } } @@ -169,6 +207,13 @@ pub(crate) unsafe fn init(config: Config) { } }; + #[cfg(stm32f107)] + let pll2freq = config.pll2.map(|pll2| { + let prediv2 = config.prediv2.unwrap_or(PllPreDiv::DIV1); + let in_freq = hse.unwrap() / (prediv2.to_bits() + 1); + in_freq * pll2.mul + }); + // configure HSI48 #[cfg(crs)] let hsi48 = config.hsi48.map(|config| super::init_hsi48(config)); @@ -177,6 +222,8 @@ pub(crate) unsafe fn init(config: Config) { // Enable PLL let pll = config.pll.map(|pll| { + #[cfg(stm32f107)] + let prediv1_src = config.prediv1_src.unwrap_or(PreDiv1Src::HSE); let (src_val, src_freq) = match pll.src { #[cfg(any(rcc_f0v3, rcc_f0v4, rcc_f3v3))] PllSource::HSI => (Pllsrc::HSI_DIV_PREDIV, unwrap!(hsi)), @@ -187,21 +234,39 @@ pub(crate) unsafe fn init(config: Config) { } (Pllsrc::HSI_DIV2, unwrap!(hsi)) } + #[cfg(not(stm32f107))] PllSource::HSE => (Pllsrc::HSE_DIV_PREDIV, unwrap!(hse)), + #[cfg(stm32f107)] + PllSource::HSE => ( + Pllsrc::HSE_DIV_PREDIV, + match prediv1_src { + PreDiv1Src::HSE => unwrap!(hse), + PreDiv1Src::PLL2 => unwrap!(pll2freq), + }, + ), #[cfg(rcc_f0v4)] PllSource::HSI48 => (Pllsrc::HSI48_DIV_PREDIV, unwrap!(hsi48)), }; + #[cfg(not(stm32f107))] let in_freq = src_freq / pll.prediv; + + #[cfg(stm32f107)] + let in_freq = src_freq / (pll.prediv.to_bits() + 1); + rcc_assert!(max::PLL_IN.contains(&in_freq)); let out_freq = in_freq * pll.mul; rcc_assert!(max::PLL_OUT.contains(&out_freq)); #[cfg(not(stm32f1))] RCC.cfgr2().modify(|w| w.set_prediv(pll.prediv)); + + #[cfg(stm32f107)] + RCC.cfgr2().modify(|w| w.set_prediv1(pll.prediv)); + RCC.cfgr().modify(|w| { w.set_pllmul(pll.mul); w.set_pllsrc(src_val); - #[cfg(stm32f1)] + #[cfg(all(stm32f1, not(stm32f107)))] w.set_pllxtpre(pll.prediv); }); RCC.cr().modify(|w| w.set_pllon(true)); @@ -210,10 +275,39 @@ pub(crate) unsafe fn init(config: Config) { out_freq }); + // Prediv1 Source Mux (HSE or PLL2) + #[cfg(stm32f107)] + if let Some(prediv1_src) = config.prediv1_src { + RCC.cfgr2().modify(|w| w.set_prediv1src(prediv1_src)); + } + + // pll2 and pll3 + #[cfg(stm32f107)] + { + // Common prediv for PLL2 and PLL3 + if let Some(prediv) = config.prediv2 { + RCC.cfgr2().modify(|w| w.set_prediv2(prediv)); + } + + // Configure PLL2 + if let Some(pll2) = config.pll2 { + RCC.cfgr2().modify(|w| w.set_pll2mul(pll2.mul)); + RCC.cr().modify(|w| w.set_pll2on(true)); + while !RCC.cr().read().pll2rdy() {} + } + + // Configure PLL3 + if let Some(pll3) = config.pll3 { + RCC.cfgr2().modify(|w| w.set_pll3mul(pll3.mul)); + RCC.cr().modify(|w| w.set_pll3on(true)); + while !RCC.cr().read().pll3rdy() {} + } + } + #[cfg(stm32f3)] let pll_mul_2 = pll.map(|pll| pll * 2u32); - #[cfg(any(rcc_f1, rcc_f1cl, stm32f3))] + #[cfg(any(rcc_f1, rcc_f1cl, stm32f3, stm32f107))] let usb = match pll { Some(Hertz(72_000_000)) => Some(crate::pac::rcc::vals::Usbpre::DIV1_5), Some(Hertz(48_000_000)) => Some(crate::pac::rcc::vals::Usbpre::DIV1), @@ -293,6 +387,18 @@ pub(crate) unsafe fn init(config: Config) { w.set_adcpre(config.adc_pre); }); + // I2S2 and I2S3 + #[cfg(stm32f107)] + { + if let Some(i2s2_src) = config.i2s2_src { + RCC.cfgr2().modify(|w| w.set_i2s2src(i2s2_src)); + } + + if let Some(i2s3_src) = config.i2s3_src { + RCC.cfgr2().modify(|w| w.set_i2s3src(i2s3_src)); + } + } + // Wait for the new prescalers to kick in // "The clocks are divided with the new prescaler factor from // 1 to 16 AHB cycles after write" From 5d26bca2e7b67097da54d4b5973931c6c9f63f03 Mon Sep 17 00:00:00 2001 From: Markus Kasten Date: Fri, 17 Jan 2025 12:07:43 +0100 Subject: [PATCH 0663/1217] stm32/rcc: add HSISYS support for g0 adds support to divide HSI clock, which allows running in low power mode on HSI --- embassy-stm32/src/rcc/g0.rs | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/embassy-stm32/src/rcc/g0.rs b/embassy-stm32/src/rcc/g0.rs index 5da33720c..f55b18290 100644 --- a/embassy-stm32/src/rcc/g0.rs +++ b/embassy-stm32/src/rcc/g0.rs @@ -1,8 +1,8 @@ use crate::pac::flash::vals::Latency; pub use crate::pac::pwr::vals::Vos as VoltageRange; pub use crate::pac::rcc::vals::{ - Hpre as AHBPrescaler, Pllm as PllPreDiv, Plln as PllMul, Pllp as PllPDiv, Pllq as PllQDiv, Pllr as PllRDiv, - Pllsrc as PllSource, Ppre as APBPrescaler, Sw as Sysclk, + Hpre as AHBPrescaler, Hsidiv as HsiSysDiv, Pllm as PllPreDiv, Plln as PllMul, Pllp as PllPDiv, Pllq as PllQDiv, + Pllr as PllRDiv, Pllsrc as PllSource, Ppre as APBPrescaler, Sw as Sysclk, }; use crate::pac::{FLASH, PWR, RCC}; use crate::time::Hertz; @@ -28,6 +28,12 @@ pub struct Hse { pub mode: HseMode, } +#[derive(Clone, Copy, Eq, PartialEq)] +pub struct Hsi { + /// Division factor for HSISYS clock. Default is 1. + pub sys_div: HsiSysDiv, +} + /// PLL Configuration /// /// Use this struct to configure the PLL source, input frequency, multiplication factor, and output @@ -58,8 +64,8 @@ pub struct Pll { #[non_exhaustive] #[derive(Clone, Copy)] pub struct Config { - /// HSI Enable - pub hsi: bool, + /// HSI Configuration + pub hsi: Option, /// HSE Configuration pub hse: Option, @@ -94,7 +100,9 @@ impl Default for Config { #[inline] fn default() -> Config { Config { - hsi: true, + hsi: Some(Hsi { + sys_div: HsiSysDiv::DIV1, + }), hse: None, sys: Sysclk::HSI, #[cfg(crs)] @@ -119,7 +127,12 @@ pub struct PllFreq { pub(crate) unsafe fn init(config: Config) { // Turn on the HSI - RCC.cr().modify(|w| w.set_hsion(true)); + RCC.cr().modify(|w| { + w.set_hsion(true); + if let Some(hsi) = config.hsi { + w.set_hsidiv(hsi.sys_div); + } + }); while !RCC.cr().read().hsirdy() {} // Use the HSI clock as system clock during the actual clock setup @@ -127,9 +140,9 @@ pub(crate) unsafe fn init(config: Config) { while RCC.cfgr().read().sws() != Sysclk::HSI {} // Configure HSI - let hsi = match config.hsi { - false => None, - true => Some(HSI_FREQ), + let (hsi, hsisys) = match config.hsi { + None => (None, None), + Some(hsi) => (Some(HSI_FREQ), Some(HSI_FREQ / hsi.sys_div)), }; // Configure HSE @@ -222,7 +235,7 @@ pub(crate) unsafe fn init(config: Config) { .unwrap_or_default(); let sys = match config.sys { - Sysclk::HSI => unwrap!(hsi), + Sysclk::HSI => unwrap!(hsisys), Sysclk::HSE => unwrap!(hse), Sysclk::PLL1_R => unwrap!(pll.pll_r), _ => unreachable!(), @@ -264,7 +277,7 @@ pub(crate) unsafe fn init(config: Config) { while RCC.cfgr().read().sws() != config.sys {} // Disable HSI if not used - if !config.hsi { + if config.hsi.is_none() { RCC.cr().modify(|w| w.set_hsion(false)); } From b40d30f0ac488791f55056227ca33fc2bb08937e Mon Sep 17 00:00:00 2001 From: Markus Kasten Date: Fri, 17 Jan 2025 12:36:38 +0100 Subject: [PATCH 0664/1217] tests/stm32: fix test for g0 hsi sys_div --- tests/stm32/src/common.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/stm32/src/common.rs b/tests/stm32/src/common.rs index 935a41ed2..829f2cff0 100644 --- a/tests/stm32/src/common.rs +++ b/tests/stm32/src/common.rs @@ -284,7 +284,9 @@ pub fn config() -> Config { #[cfg(feature = "stm32g071rb")] { - config.rcc.hsi = true; + config.rcc.hsi = Some(Hsi { + sys_div: HsiSysDiv::DIV1, + }); config.rcc.pll = Some(Pll { source: PllSource::HSI, prediv: PllPreDiv::DIV1, From 083f584f29b092a68f99120373dc6ec60fe6bc3d Mon Sep 17 00:00:00 2001 From: Markus Kasten Date: Fri, 17 Jan 2025 12:45:05 +0100 Subject: [PATCH 0665/1217] examples/stm32: fix g0 hftimer example with hsi sys_div --- examples/stm32g0/src/bin/hf_timer.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/examples/stm32g0/src/bin/hf_timer.rs b/examples/stm32g0/src/bin/hf_timer.rs index 3ea06cdee..dfb6e0edc 100644 --- a/examples/stm32g0/src/bin/hf_timer.rs +++ b/examples/stm32g0/src/bin/hf_timer.rs @@ -16,7 +16,9 @@ async fn main(_spawner: Spawner) { let mut config = PeripheralConfig::default(); { use embassy_stm32::rcc::*; - config.rcc.hsi = true; + config.rcc.hsi = Some(Hsi { + sys_div: HsiSysDiv::DIV1, + }); config.rcc.pll = Some(Pll { source: PllSource::HSI, prediv: PllPreDiv::DIV1, From 08ef83430125870b34cf14cea23c0dfc4b8b36bd Mon Sep 17 00:00:00 2001 From: Andrii <14360752+Andreychik32@users.noreply.github.com> Date: Fri, 17 Jan 2025 18:05:50 +0200 Subject: [PATCH 0666/1217] fix wrong negation of fdcan set_transmit_pause function parameter --- embassy-stm32/src/can/fd/peripheral.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/src/can/fd/peripheral.rs b/embassy-stm32/src/can/fd/peripheral.rs index 1c7abfcb2..39c4112ad 100644 --- a/embassy-stm32/src/can/fd/peripheral.rs +++ b/embassy-stm32/src/can/fd/peripheral.rs @@ -458,7 +458,7 @@ impl Registers { /// [`FdCanConfig::set_transmit_pause`] #[inline] pub fn set_transmit_pause(&self, enabled: bool) { - self.regs.cccr().modify(|w| w.set_txp(!enabled)); + self.regs.cccr().modify(|w| w.set_txp(enabled)); } /// Configures non-iso mode. See [`FdCanConfig::set_non_iso_mode`] From 9f451c7f411d742d8e7c1c3a00c0fb864f14d46c Mon Sep 17 00:00:00 2001 From: Bronson Date: Mon, 11 Nov 2024 19:22:37 +1030 Subject: [PATCH 0667/1217] added remove_if to priority channel --- embassy-sync/src/priority_channel.rs | 42 ++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/embassy-sync/src/priority_channel.rs b/embassy-sync/src/priority_channel.rs index 1f4d8667c..a4eda7fbc 100644 --- a/embassy-sync/src/priority_channel.rs +++ b/embassy-sync/src/priority_channel.rs @@ -72,6 +72,17 @@ where self.channel.poll_ready_to_send(cx) } + /// Removes the elements from the channel that satisfy the predicate. + /// + /// See [`PriorityChannel::remove_if()`] + pub fn remove_if(&self, predicate: F) + where + F: Fn(&T) -> bool, + T: Clone, + { + self.channel.remove_if(predicate) + } + /// Returns the maximum number of elements the channel can hold. /// /// See [`PriorityChannel::capacity()`] @@ -189,6 +200,17 @@ where self.channel.poll_receive(cx) } + /// Removes the elements from the channel that satisfy the predicate. + /// + /// See [`PriorityChannel::remove_if()`] + pub fn remove_if(&self, predicate: F) + where + F: Fn(&T) -> bool, + T: Clone, + { + self.channel.remove_if(predicate) + } + /// Returns the maximum number of elements the channel can hold. /// /// See [`PriorityChannel::capacity()`] @@ -534,6 +556,26 @@ where self.lock(|c| c.try_receive()) } + /// Removes elements from the channel based on the given predicate. + pub fn remove_if(&self, predicate: F) + where + F: Fn(&T) -> bool, + T: Clone, + { + self.lock(|c| { + let mut new_heap = BinaryHeap::::new(); + for item in c.queue.iter() { + if !predicate(item) { + match new_heap.push(item.clone()) { + Ok(_) => (), + Err(_) => panic!("Error pushing item to heap"), + } + } + } + c.queue = new_heap; + }); + } + /// Returns the maximum number of elements the channel can hold. pub const fn capacity(&self) -> usize { N From c65b6db318da7ecbe888a0a66b85d9ffb28106f0 Mon Sep 17 00:00:00 2001 From: Bronson Date: Sat, 14 Dec 2024 14:14:59 +1030 Subject: [PATCH 0668/1217] remove from sender --- embassy-sync/src/priority_channel.rs | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/embassy-sync/src/priority_channel.rs b/embassy-sync/src/priority_channel.rs index a4eda7fbc..d466a22ff 100644 --- a/embassy-sync/src/priority_channel.rs +++ b/embassy-sync/src/priority_channel.rs @@ -72,17 +72,6 @@ where self.channel.poll_ready_to_send(cx) } - /// Removes the elements from the channel that satisfy the predicate. - /// - /// See [`PriorityChannel::remove_if()`] - pub fn remove_if(&self, predicate: F) - where - F: Fn(&T) -> bool, - T: Clone, - { - self.channel.remove_if(predicate) - } - /// Returns the maximum number of elements the channel can hold. /// /// See [`PriorityChannel::capacity()`] From 42817c4259a0a636da5215e93c8f16d4e3cab5d3 Mon Sep 17 00:00:00 2001 From: mahu-wm <127418871+mahu-wm@users.noreply.github.com> Date: Mon, 20 Jan 2025 10:55:21 +0100 Subject: [PATCH 0669/1217] Fix issue with enabled split-pxy feature The fixed error message is: error[E0425]: cannot find value `pin_name` in this scope --- embassy-stm32/build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 4abbf8d69..78569f7da 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -1534,7 +1534,7 @@ fn main() { // This should avoid unintended side-effects as much as possible. #[cfg(feature = "_split-pins-enabled")] for split_feature in &split_features { - if split_feature.pin_name_without_c == pin_name { + if split_feature.pin_name_without_c == pin.name { pins_table.push(vec![ split_feature.pin_name_with_c.to_string(), p.name.to_string(), From 8052ef037e88b034fa9eddc8e7d8e7efa5dd3f0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Tue, 21 Jan 2025 22:25:35 +0100 Subject: [PATCH 0670/1217] Add __pender error to the FAQ --- docs/pages/faq.adoc | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/docs/pages/faq.adoc b/docs/pages/faq.adoc index 9c4d277f9..f95ccf48b 100644 --- a/docs/pages/faq.adoc +++ b/docs/pages/faq.adoc @@ -117,6 +117,20 @@ If you are in the early project setup phase and not using anything from the HAL, use embassy_stm32 as _; ---- +Another common error you may experience is: + +[source,text] +---- + = note: rust-lld: error: undefined symbol: __pender + >>> referenced by mod.rs:373 (src/raw/mod.rs:373) + >>> embassy_executor-e78174e249bca7f4.embassy_executor.1e9d60fc90940543-cgu.0.rcgu.o:(embassy_executor::raw::Pender::pend::h0f19b6e01762e4cd) in archive [...]libembassy_executor-e78174e249bca7f4.rlib +---- + +There are two possible causes to this error: + +* You are using `embassy-executor` withuout enabling one of the architecture-specific features, but you are using a HAL that does not bring its own executors. For example, for Cortex-M (like the RP2040), you need to enable the `arch-cortex-m` feature of `embassy-executor`. +* You are not using `embassy-executor`. In this case, you need to enable the one of the `generic-queue-X` features of `embassy-time`. + == Error: `Only one package in the dependency graph may specify the same links value.` You have multiple versions of the same crate in your dependency tree. This means that some of your From 3de0a21acad8b8ca7d803562548084c0726a15f2 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 21 Jan 2025 23:25:49 +0100 Subject: [PATCH 0671/1217] stm32: test split pins in CI. --- ci.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci.sh b/ci.sh index 1aa206c1d..59bcab875 100755 --- a/ci.sh +++ b/ci.sh @@ -129,7 +129,7 @@ cargo batch \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f730i8,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h753zi,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h735zg,defmt,exti,time-driver-any,time \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h755zi-cm7,defmt,exti,time-driver-any,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h755zi-cm7,defmt,exti,time-driver-any,time,split-pc2,split-pc3 \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h725re,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h7b3ai,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h7b3ai,defmt,exti,time-driver-tim1,time \ From da8612e95b93eff0720150317848694a76418151 Mon Sep 17 00:00:00 2001 From: Adam Greig Date: Wed, 22 Jan 2025 01:17:20 +0000 Subject: [PATCH 0672/1217] stm32: Change unreachable panic to explicit error message when accessing clock-muxed peripherals set to invalid clocks --- embassy-stm32/build.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 4abbf8d69..03d4383ac 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -532,7 +532,11 @@ fn main() { match crate::pac::RCC.#fieldset_name().read().#field_name() { #match_arms #[allow(unreachable_patterns)] - _ => unreachable!(), + _ => panic!( + "attempted to use peripheral '{}' but its clock mux is not set to a valid \ + clock. Change 'config.rcc.mux' to another clock.", + #peripheral + ) } } } From 5885369f47d1260e58656bfc13bebba6339cf6cc Mon Sep 17 00:00:00 2001 From: nikvoid Date: Wed, 22 Jan 2025 13:23:29 +0200 Subject: [PATCH 0673/1217] Option to detect Ethernet PHY address automatically --- embassy-stm32/src/eth/generic_smi.rs | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/eth/generic_smi.rs b/embassy-stm32/src/eth/generic_smi.rs index 3b43051f4..06d01124f 100644 --- a/embassy-stm32/src/eth/generic_smi.rs +++ b/embassy-stm32/src/eth/generic_smi.rs @@ -51,6 +51,8 @@ pub struct GenericSMI { impl GenericSMI { /// Construct the PHY. It assumes the address `phy_addr` in the SMI communication + /// + /// Set `phy_addr` to `0xFF` for automatic detection pub fn new(phy_addr: u8) -> Self { Self { phy_addr, @@ -62,8 +64,24 @@ impl GenericSMI { unsafe impl PHY for GenericSMI { fn phy_reset(&mut self, sm: &mut S) { - sm.smi_write(self.phy_addr, PHY_REG_BCR, PHY_REG_BCR_RESET); - while sm.smi_read(self.phy_addr, PHY_REG_BCR) & PHY_REG_BCR_RESET == PHY_REG_BCR_RESET {} + // Detect SMI address + if self.phy_addr == 0xFF { + for addr in 0..32 { + sm.smi_write(addr, PHY_REG_BCR, PHY_REG_BCR_RESET); + for _ in 0..10 { + if sm.smi_read(addr, PHY_REG_BCR) & PHY_REG_BCR_RESET != PHY_REG_BCR_RESET { + trace!("Found ETH PHY on address {}", addr); + self.phy_addr = addr; + return; + } + cortex_m::asm::delay(1000); + } + } + panic!("PHY did not respond"); + } else { + sm.smi_write(self.phy_addr, PHY_REG_BCR, PHY_REG_BCR_RESET); + while sm.smi_read(self.phy_addr, PHY_REG_BCR) & PHY_REG_BCR_RESET == PHY_REG_BCR_RESET {} + } } fn phy_init(&mut self, sm: &mut S) { From 2d7e0b6e0fe4ee6ee1a7a32401ae3eeea3b08301 Mon Sep 17 00:00:00 2001 From: nikvoid Date: Wed, 22 Jan 2025 13:43:45 +0200 Subject: [PATCH 0674/1217] use `Delay` from `embassy-time` to wait for PHY response --- embassy-stm32/src/eth/generic_smi.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/embassy-stm32/src/eth/generic_smi.rs b/embassy-stm32/src/eth/generic_smi.rs index 06d01124f..ef673a301 100644 --- a/embassy-stm32/src/eth/generic_smi.rs +++ b/embassy-stm32/src/eth/generic_smi.rs @@ -3,7 +3,7 @@ use core::task::Context; #[cfg(feature = "time")] -use embassy_time::{Duration, Timer}; +use embassy_time::{Duration, Timer, Delay}; #[cfg(feature = "time")] use futures_util::FutureExt; @@ -52,7 +52,7 @@ pub struct GenericSMI { impl GenericSMI { /// Construct the PHY. It assumes the address `phy_addr` in the SMI communication /// - /// Set `phy_addr` to `0xFF` for automatic detection + /// Set `phy_addr` to `0xFF` for automatic detection (only with `time` feature enabled) pub fn new(phy_addr: u8) -> Self { Self { phy_addr, @@ -65,6 +65,7 @@ impl GenericSMI { unsafe impl PHY for GenericSMI { fn phy_reset(&mut self, sm: &mut S) { // Detect SMI address + #[cfg(feature = "time")] if self.phy_addr == 0xFF { for addr in 0..32 { sm.smi_write(addr, PHY_REG_BCR, PHY_REG_BCR_RESET); @@ -74,14 +75,15 @@ unsafe impl PHY for GenericSMI { self.phy_addr = addr; return; } - cortex_m::asm::delay(1000); + embedded_hal_1::delay::DelayNs::delay_us(&mut Delay, 1000); + cortex_m::asm::delay(1000000); } } panic!("PHY did not respond"); - } else { - sm.smi_write(self.phy_addr, PHY_REG_BCR, PHY_REG_BCR_RESET); - while sm.smi_read(self.phy_addr, PHY_REG_BCR) & PHY_REG_BCR_RESET == PHY_REG_BCR_RESET {} } + + sm.smi_write(self.phy_addr, PHY_REG_BCR, PHY_REG_BCR_RESET); + while sm.smi_read(self.phy_addr, PHY_REG_BCR) & PHY_REG_BCR_RESET == PHY_REG_BCR_RESET {} } fn phy_init(&mut self, sm: &mut S) { From 83ccbf48d70859b881f459e9c294acce213ac0d9 Mon Sep 17 00:00:00 2001 From: nikvoid Date: Wed, 22 Jan 2025 18:09:25 +0200 Subject: [PATCH 0675/1217] remove cortex-m delay --- embassy-stm32/src/eth/generic_smi.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/embassy-stm32/src/eth/generic_smi.rs b/embassy-stm32/src/eth/generic_smi.rs index ef673a301..acd793958 100644 --- a/embassy-stm32/src/eth/generic_smi.rs +++ b/embassy-stm32/src/eth/generic_smi.rs @@ -76,7 +76,6 @@ unsafe impl PHY for GenericSMI { return; } embedded_hal_1::delay::DelayNs::delay_us(&mut Delay, 1000); - cortex_m::asm::delay(1000000); } } panic!("PHY did not respond"); From dff8be9bb6b02c0162bcc595df34b0bc0c3e0e83 Mon Sep 17 00:00:00 2001 From: nikvoid Date: Wed, 22 Jan 2025 18:11:32 +0200 Subject: [PATCH 0676/1217] run rustfmt --- embassy-stm32/src/eth/generic_smi.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/eth/generic_smi.rs b/embassy-stm32/src/eth/generic_smi.rs index acd793958..41d19e921 100644 --- a/embassy-stm32/src/eth/generic_smi.rs +++ b/embassy-stm32/src/eth/generic_smi.rs @@ -3,7 +3,7 @@ use core::task::Context; #[cfg(feature = "time")] -use embassy_time::{Duration, Timer, Delay}; +use embassy_time::{Delay, Duration, Timer}; #[cfg(feature = "time")] use futures_util::FutureExt; @@ -80,7 +80,7 @@ unsafe impl PHY for GenericSMI { } panic!("PHY did not respond"); } - + sm.smi_write(self.phy_addr, PHY_REG_BCR, PHY_REG_BCR_RESET); while sm.smi_read(self.phy_addr, PHY_REG_BCR) & PHY_REG_BCR_RESET == PHY_REG_BCR_RESET {} } From 269dec938015c387d419afebb8402f5bee633ca9 Mon Sep 17 00:00:00 2001 From: Rex Magana Date: Wed, 22 Jan 2025 11:26:08 -0700 Subject: [PATCH 0677/1217] add stream impl --- embassy-sync/src/channel.rs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/embassy-sync/src/channel.rs b/embassy-sync/src/channel.rs index 18b053111..b3b087bf6 100644 --- a/embassy-sync/src/channel.rs +++ b/embassy-sync/src/channel.rs @@ -317,6 +317,17 @@ where } } +impl<'ch, M, T, const N: usize> futures_util::Stream for Receiver<'ch, M, T, N> +where + M: RawMutex, +{ + type Item = T; + + fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + self.channel.poll_receive(cx).map(Some) + } +} + /// Future returned by [`Channel::receive`] and [`Receiver::receive`]. #[must_use = "futures do nothing unless you `.await` or poll them"] pub struct ReceiveFuture<'ch, M, T, const N: usize> @@ -768,6 +779,17 @@ where } } +impl futures_util::Stream for Channel +where + M: RawMutex, +{ + type Item = T; + + fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + self.poll_receive(cx).map(Some) + } +} + #[cfg(test)] mod tests { use core::time::Duration; From afe6b9a192f1434bb024040a20cef9509c307871 Mon Sep 17 00:00:00 2001 From: nikvoid Date: Thu, 23 Jan 2025 13:34:54 +0200 Subject: [PATCH 0678/1217] split PHY constructor to `new` and `new_auto` --- embassy-stm32/src/eth/generic_smi.rs | 35 ++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/embassy-stm32/src/eth/generic_smi.rs b/embassy-stm32/src/eth/generic_smi.rs index 41d19e921..239c52634 100644 --- a/embassy-stm32/src/eth/generic_smi.rs +++ b/embassy-stm32/src/eth/generic_smi.rs @@ -3,7 +3,7 @@ use core::task::Context; #[cfg(feature = "time")] -use embassy_time::{Delay, Duration, Timer}; +use embassy_time::{Duration, Timer}; #[cfg(feature = "time")] use futures_util::FutureExt; @@ -52,20 +52,46 @@ pub struct GenericSMI { impl GenericSMI { /// Construct the PHY. It assumes the address `phy_addr` in the SMI communication /// - /// Set `phy_addr` to `0xFF` for automatic detection (only with `time` feature enabled) + /// # Panics + /// `phy_addr` must be in range `0..32` pub fn new(phy_addr: u8) -> Self { + assert!(phy_addr < 32); Self { phy_addr, #[cfg(feature = "time")] poll_interval: Duration::from_millis(500), } } + + /// Construct the PHY. Try to probe all addresses from 0 to 31 during initialization + /// + /// # Panics + /// Initialization panics if PHY didn't respond on any address + pub fn new_auto() -> Self { + Self { + phy_addr: 0xFF, + #[cfg(feature = "time")] + poll_interval: Duration::from_millis(500), + } + } +} + +// TODO: Factor out to shared functionality +fn blocking_delay_us(us: u32) { + #[cfg(feature = "time")] + embassy_time::block_for(Duration::from_micros(us as u64)); + #[cfg(not(feature = "time"))] + { + let freq = unsafe { crate::rcc::get_freqs() }.sys.to_hertz().unwrap().0 as u64; + let us = us as u64; + let cycles = freq * us / 1_000_000; + cortex_m::asm::delay(cycles as u32); + } } unsafe impl PHY for GenericSMI { fn phy_reset(&mut self, sm: &mut S) { // Detect SMI address - #[cfg(feature = "time")] if self.phy_addr == 0xFF { for addr in 0..32 { sm.smi_write(addr, PHY_REG_BCR, PHY_REG_BCR_RESET); @@ -75,7 +101,8 @@ unsafe impl PHY for GenericSMI { self.phy_addr = addr; return; } - embedded_hal_1::delay::DelayNs::delay_us(&mut Delay, 1000); + // Give PHY a total of 100ms to respond + blocking_delay_us(10000); } } panic!("PHY did not respond"); From c72d9ec8599e3474344f8daf8c2e5a7236201e03 Mon Sep 17 00:00:00 2001 From: Martin Algesten Date: Fri, 24 Jan 2025 09:08:11 +0100 Subject: [PATCH 0679/1217] Review fixes --- embassy-stm32/build.rs | 2 +- embassy-stm32/src/rcc/f013.rs | 77 +++++++++++++---------------------- 2 files changed, 29 insertions(+), 50 deletions(-) diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 4abbf8d69..09fcc0d03 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -1383,7 +1383,7 @@ fn main() { for e in rcc_registers.ir.enums { fn is_rcc_name(e: &str) -> bool { match e { - "Pllp" | "Pllq" | "Pllr" | "Pllm" | "Plln" => true, + "Pllp" | "Pllq" | "Pllr" | "Pllm" | "Plln" | "Prediv1" | "Prediv2" => true, "Timpre" | "Pllrclkpre" => false, e if e.ends_with("pre") || e.ends_with("pres") || e.ends_with("div") || e.ends_with("mul") => true, _ => false, diff --git a/embassy-stm32/src/rcc/f013.rs b/embassy-stm32/src/rcc/f013.rs index 27e43fa56..d256ace8f 100644 --- a/embassy-stm32/src/rcc/f013.rs +++ b/embassy-stm32/src/rcc/f013.rs @@ -41,6 +41,8 @@ pub enum PllSource { HSI, #[cfg(rcc_f0v4)] HSI48, + #[cfg(stm32f107)] + PLL2, } #[derive(Clone, Copy)] @@ -100,9 +102,7 @@ pub struct Config { #[cfg(stm32f107)] pub pll3: Option, #[cfg(stm32f107)] - pub prediv1_src: Option, - #[cfg(stm32f107)] - pub prediv2: Option, + pub prediv2: PllPreDiv, pub ahb_pre: AHBPrescaler, pub apb1_pre: APBPrescaler, @@ -118,9 +118,9 @@ pub struct Config { pub adc34: AdcClockSource, #[cfg(stm32f107)] - pub i2s2_src: Option, + pub i2s2_src: I2s2src, #[cfg(stm32f107)] - pub i2s3_src: Option, + pub i2s3_src: I2s2src, /// Per-peripheral kernel clock selection muxes pub mux: super::mux::ClockMux, @@ -143,9 +143,7 @@ impl Default for Config { #[cfg(stm32f107)] pll3: None, #[cfg(stm32f107)] - prediv1_src: None, - #[cfg(stm32f107)] - prediv2: None, + prediv2: PllPreDiv::DIV1, ahb_pre: AHBPrescaler::DIV1, apb1_pre: APBPrescaler::DIV1, @@ -163,9 +161,9 @@ impl Default for Config { adc34: AdcClockSource::Hclk(AdcHclkPrescaler::Div1), #[cfg(stm32f107)] - i2s2_src: None, + i2s2_src: I2s2src::SYS, #[cfg(stm32f107)] - i2s3_src: None, + i2s3_src: I2s2src::SYS, mux: Default::default(), } @@ -207,13 +205,6 @@ pub(crate) unsafe fn init(config: Config) { } }; - #[cfg(stm32f107)] - let pll2freq = config.pll2.map(|pll2| { - let prediv2 = config.prediv2.unwrap_or(PllPreDiv::DIV1); - let in_freq = hse.unwrap() / (prediv2.to_bits() + 1); - in_freq * pll2.mul - }); - // configure HSI48 #[cfg(crs)] let hsi48 = config.hsi48.map(|config| super::init_hsi48(config)); @@ -222,8 +213,6 @@ pub(crate) unsafe fn init(config: Config) { // Enable PLL let pll = config.pll.map(|pll| { - #[cfg(stm32f107)] - let prediv1_src = config.prediv1_src.unwrap_or(PreDiv1Src::HSE); let (src_val, src_freq) = match pll.src { #[cfg(any(rcc_f0v3, rcc_f0v4, rcc_f3v3))] PllSource::HSI => (Pllsrc::HSI_DIV_PREDIV, unwrap!(hsi)), @@ -234,25 +223,28 @@ pub(crate) unsafe fn init(config: Config) { } (Pllsrc::HSI_DIV2, unwrap!(hsi)) } - #[cfg(not(stm32f107))] - PllSource::HSE => (Pllsrc::HSE_DIV_PREDIV, unwrap!(hse)), - #[cfg(stm32f107)] - PllSource::HSE => ( - Pllsrc::HSE_DIV_PREDIV, - match prediv1_src { - PreDiv1Src::HSE => unwrap!(hse), - PreDiv1Src::PLL2 => unwrap!(pll2freq), - }, - ), + PllSource::HSE => { + #[cfg(stm32f107)] + RCC.cfgr2().modify(|w| w.set_prediv1src(PreDiv1Src::HSE)); + + (Pllsrc::HSE_DIV_PREDIV, unwrap!(hse)) + } #[cfg(rcc_f0v4)] PllSource::HSI48 => (Pllsrc::HSI48_DIV_PREDIV, unwrap!(hsi48)), + #[cfg(stm32f107)] + PllSource::PLL2 => { + if config.pll2.is_none() { + panic!("if PLL source is PLL2, Config::pll2 must also be set."); + } + let pll2 = unwrap!(config.pll2); + let in_freq = hse.unwrap() / config.prediv2; + let pll2freq = in_freq * pll2.mul; + RCC.cfgr2().modify(|w| w.set_prediv1src(PreDiv1Src::PLL2)); + (Pllsrc::HSE_DIV_PREDIV, pll2freq) + } }; - #[cfg(not(stm32f107))] let in_freq = src_freq / pll.prediv; - #[cfg(stm32f107)] - let in_freq = src_freq / (pll.prediv.to_bits() + 1); - rcc_assert!(max::PLL_IN.contains(&in_freq)); let out_freq = in_freq * pll.mul; rcc_assert!(max::PLL_OUT.contains(&out_freq)); @@ -275,19 +267,11 @@ pub(crate) unsafe fn init(config: Config) { out_freq }); - // Prediv1 Source Mux (HSE or PLL2) - #[cfg(stm32f107)] - if let Some(prediv1_src) = config.prediv1_src { - RCC.cfgr2().modify(|w| w.set_prediv1src(prediv1_src)); - } - // pll2 and pll3 #[cfg(stm32f107)] { // Common prediv for PLL2 and PLL3 - if let Some(prediv) = config.prediv2 { - RCC.cfgr2().modify(|w| w.set_prediv2(prediv)); - } + RCC.cfgr2().modify(|w| w.set_prediv2(config.prediv2)); // Configure PLL2 if let Some(pll2) = config.pll2 { @@ -390,13 +374,8 @@ pub(crate) unsafe fn init(config: Config) { // I2S2 and I2S3 #[cfg(stm32f107)] { - if let Some(i2s2_src) = config.i2s2_src { - RCC.cfgr2().modify(|w| w.set_i2s2src(i2s2_src)); - } - - if let Some(i2s3_src) = config.i2s3_src { - RCC.cfgr2().modify(|w| w.set_i2s3src(i2s3_src)); - } + RCC.cfgr2().modify(|w| w.set_i2s2src(config.i2s2_src)); + RCC.cfgr2().modify(|w| w.set_i2s3src(config.i2s3_src)); } // Wait for the new prescalers to kick in From 3ba94c0ab3fcb859619fa70fcf37a3505392f05c Mon Sep 17 00:00:00 2001 From: Martin Algesten Date: Fri, 24 Jan 2025 09:33:48 +0100 Subject: [PATCH 0680/1217] Fix init order of set_prediv1src --- embassy-stm32/src/rcc/f013.rs | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/embassy-stm32/src/rcc/f013.rs b/embassy-stm32/src/rcc/f013.rs index d256ace8f..8d86629b5 100644 --- a/embassy-stm32/src/rcc/f013.rs +++ b/embassy-stm32/src/rcc/f013.rs @@ -10,9 +10,7 @@ pub use crate::pac::rcc::vals::Pllxtpre as PllPreDiv; pub use crate::pac::rcc::vals::Prediv as PllPreDiv; pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Pllmul as PllMul, Ppre as APBPrescaler, Sw as Sysclk}; #[cfg(stm32f107)] -pub use crate::pac::rcc::vals::{ - I2s2src, Pll2mul as Pll2Mul, Prediv1 as PllPreDiv, Prediv1src as PreDiv1Src, Usbpre as UsbPre, -}; +pub use crate::pac::rcc::vals::{I2s2src, Pll2mul as Pll2Mul, Prediv1 as PllPreDiv, Prediv1src, Usbpre as UsbPre}; use crate::pac::{FLASH, RCC}; use crate::time::Hertz; @@ -223,12 +221,7 @@ pub(crate) unsafe fn init(config: Config) { } (Pllsrc::HSI_DIV2, unwrap!(hsi)) } - PllSource::HSE => { - #[cfg(stm32f107)] - RCC.cfgr2().modify(|w| w.set_prediv1src(PreDiv1Src::HSE)); - - (Pllsrc::HSE_DIV_PREDIV, unwrap!(hse)) - } + PllSource::HSE => (Pllsrc::HSE_DIV_PREDIV, unwrap!(hse)), #[cfg(rcc_f0v4)] PllSource::HSI48 => (Pllsrc::HSI48_DIV_PREDIV, unwrap!(hsi48)), #[cfg(stm32f107)] @@ -239,7 +232,6 @@ pub(crate) unsafe fn init(config: Config) { let pll2 = unwrap!(config.pll2); let in_freq = hse.unwrap() / config.prediv2; let pll2freq = in_freq * pll2.mul; - RCC.cfgr2().modify(|w| w.set_prediv1src(PreDiv1Src::PLL2)); (Pllsrc::HSE_DIV_PREDIV, pll2freq) } }; @@ -267,6 +259,13 @@ pub(crate) unsafe fn init(config: Config) { out_freq }); + #[cfg(stm32f107)] + match config.pll.map(|pll| pll.src) { + Some(PllSource::HSE) => RCC.cfgr2().modify(|w| w.set_prediv1src(Prediv1src::HSE)), + Some(PllSource::PLL2) => RCC.cfgr2().modify(|w| w.set_prediv1src(Prediv1src::PLL2)), + _ => {} + } + // pll2 and pll3 #[cfg(stm32f107)] { From 4743501172dadc405f71dec34b0b9fa933c916b8 Mon Sep 17 00:00:00 2001 From: Martin Algesten Date: Fri, 24 Jan 2025 10:06:32 +0100 Subject: [PATCH 0681/1217] Move PLL2/3 config to before PLL --- embassy-stm32/src/rcc/f013.rs | 60 ++++++++++++++++++----------------- 1 file changed, 31 insertions(+), 29 deletions(-) diff --git a/embassy-stm32/src/rcc/f013.rs b/embassy-stm32/src/rcc/f013.rs index 8d86629b5..13b0ae38e 100644 --- a/embassy-stm32/src/rcc/f013.rs +++ b/embassy-stm32/src/rcc/f013.rs @@ -209,6 +209,28 @@ pub(crate) unsafe fn init(config: Config) { #[cfg(not(crs))] let hsi48: Option = None; + // PLL2 and PLL3 + // Configure this before PLL since PLL2 can be the source for PLL. + #[cfg(stm32f107)] + { + // Common prediv for PLL2 and PLL3 + RCC.cfgr2().modify(|w| w.set_prediv2(config.prediv2)); + + // Configure PLL2 + if let Some(pll2) = config.pll2 { + RCC.cfgr2().modify(|w| w.set_pll2mul(pll2.mul)); + RCC.cr().modify(|w| w.set_pll2on(true)); + while !RCC.cr().read().pll2rdy() {} + } + + // Configure PLL3 + if let Some(pll3) = config.pll3 { + RCC.cfgr2().modify(|w| w.set_pll3mul(pll3.mul)); + RCC.cr().modify(|w| w.set_pll3on(true)); + while !RCC.cr().read().pll3rdy() {} + } + } + // Enable PLL let pll = config.pll.map(|pll| { let (src_val, src_freq) = match pll.src { @@ -221,7 +243,12 @@ pub(crate) unsafe fn init(config: Config) { } (Pllsrc::HSI_DIV2, unwrap!(hsi)) } - PllSource::HSE => (Pllsrc::HSE_DIV_PREDIV, unwrap!(hse)), + PllSource::HSE => { + #[cfg(stm32f107)] + RCC.cfgr2().modify(|w| w.set_prediv1src(Prediv1src::HSE)); + + (Pllsrc::HSE_DIV_PREDIV, unwrap!(hse)) + } #[cfg(rcc_f0v4)] PllSource::HSI48 => (Pllsrc::HSI48_DIV_PREDIV, unwrap!(hsi48)), #[cfg(stm32f107)] @@ -229,9 +256,12 @@ pub(crate) unsafe fn init(config: Config) { if config.pll2.is_none() { panic!("if PLL source is PLL2, Config::pll2 must also be set."); } + RCC.cfgr2().modify(|w| w.set_prediv1src(Prediv1src::PLL2)); + let pll2 = unwrap!(config.pll2); let in_freq = hse.unwrap() / config.prediv2; let pll2freq = in_freq * pll2.mul; + (Pllsrc::HSE_DIV_PREDIV, pll2freq) } }; @@ -259,34 +289,6 @@ pub(crate) unsafe fn init(config: Config) { out_freq }); - #[cfg(stm32f107)] - match config.pll.map(|pll| pll.src) { - Some(PllSource::HSE) => RCC.cfgr2().modify(|w| w.set_prediv1src(Prediv1src::HSE)), - Some(PllSource::PLL2) => RCC.cfgr2().modify(|w| w.set_prediv1src(Prediv1src::PLL2)), - _ => {} - } - - // pll2 and pll3 - #[cfg(stm32f107)] - { - // Common prediv for PLL2 and PLL3 - RCC.cfgr2().modify(|w| w.set_prediv2(config.prediv2)); - - // Configure PLL2 - if let Some(pll2) = config.pll2 { - RCC.cfgr2().modify(|w| w.set_pll2mul(pll2.mul)); - RCC.cr().modify(|w| w.set_pll2on(true)); - while !RCC.cr().read().pll2rdy() {} - } - - // Configure PLL3 - if let Some(pll3) = config.pll3 { - RCC.cfgr2().modify(|w| w.set_pll3mul(pll3.mul)); - RCC.cr().modify(|w| w.set_pll3on(true)); - while !RCC.cr().read().pll3rdy() {} - } - } - #[cfg(stm32f3)] let pll_mul_2 = pll.map(|pll| pll * 2u32); From da0f6dbe08bb574c5c2bc448199dc2e4f74692de Mon Sep 17 00:00:00 2001 From: Georges Palauqui Date: Fri, 24 Jan 2025 11:58:33 +0100 Subject: [PATCH 0682/1217] derive defmt::Format on pub struct/enum of stm32::rtc --- embassy-stm32/src/rtc/datetime.rs | 3 +++ embassy-stm32/src/rtc/mod.rs | 1 + 2 files changed, 4 insertions(+) diff --git a/embassy-stm32/src/rtc/datetime.rs b/embassy-stm32/src/rtc/datetime.rs index 32732e96e..526b0cfbd 100644 --- a/embassy-stm32/src/rtc/datetime.rs +++ b/embassy-stm32/src/rtc/datetime.rs @@ -3,6 +3,7 @@ use chrono::{Datelike, NaiveDate, Timelike, Weekday}; /// Errors regarding the [`DateTime`] struct. #[derive(Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum Error { /// The [DateTime] contains an invalid year value. Must be between `0..=4095`. InvalidYear, @@ -24,6 +25,7 @@ pub enum Error { } /// Structure containing date and time information +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct DateTime { /// 0..4095 year: u16, @@ -141,6 +143,7 @@ impl From for chrono::NaiveDateTime { /// A day of the week #[repr(u8)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Ord, PartialOrd, Hash)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[allow(missing_docs)] pub enum DayOfWeek { Monday = 1, diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs index 1a668cb37..66646de4c 100644 --- a/embassy-stm32/src/rtc/mod.rs +++ b/embassy-stm32/src/rtc/mod.rs @@ -36,6 +36,7 @@ use crate::peripherals::RTC; /// Errors that can occur on methods on [RtcClock] #[non_exhaustive] #[derive(Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum RtcError { /// An invalid DateTime was given or stored on the hardware. InvalidDateTime(DateTimeError), From 2fe299cc538c28711fd838b5f2c3da6143a7335e Mon Sep 17 00:00:00 2001 From: Easyoakland <97992568+Easyoakland@users.noreply.github.com> Date: Fri, 24 Jan 2025 18:45:43 -0700 Subject: [PATCH 0683/1217] don't infinite loop if udp::send methods receive a buffer too large to ever be sent --- embassy-net/src/udp.rs | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/embassy-net/src/udp.rs b/embassy-net/src/udp.rs index 64a22d45b..7baa89ea0 100644 --- a/embassy-net/src/udp.rs +++ b/embassy-net/src/udp.rs @@ -21,7 +21,7 @@ pub enum BindError { NoRoute, } -/// Error returned by [`UdpSocket::recv_from`] and [`UdpSocket::send_to`]. +/// Error returned by [`UdpSocket::send_to`]. #[derive(PartialEq, Eq, Clone, Copy, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum SendError { @@ -29,9 +29,11 @@ pub enum SendError { NoRoute, /// Socket not bound to an outgoing port. SocketNotBound, + /// There is not enough transmit buffer capacity to ever send this packet. + Truncated, } -/// Error returned by [`UdpSocket::recv_from`] and [`UdpSocket::send_to`]. +/// Error returned by [`UdpSocket::recv_from`]. #[derive(PartialEq, Eq, Clone, Copy, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum RecvError { @@ -224,6 +226,8 @@ impl<'a> UdpSocket<'a> { /// /// This method will wait until the datagram has been sent. /// + /// If the socket's send buffer is too small to fit `buf`, this method will return `Poll::Ready(Err(SendError::Truncated))` + /// /// When the remote endpoint is not reachable, this method will return `Err(SendError::NoRoute)` pub async fn send_to(&self, buf: &[u8], remote_endpoint: T) -> Result<(), SendError> where @@ -240,11 +244,21 @@ impl<'a> UdpSocket<'a> { /// When the socket's send buffer is full, this method will return `Poll::Pending` /// and register the current task to be notified when the buffer has space available. /// + /// If the socket's send buffer is too small to fit `buf`, this method will return `Poll::Ready(Err(SendError::Truncated))` + /// /// When the remote endpoint is not reachable, this method will return `Poll::Ready(Err(Error::NoRoute))`. pub fn poll_send_to(&self, buf: &[u8], remote_endpoint: T, cx: &mut Context<'_>) -> Poll> where T: Into, { + // Don't need to wake waker in `with_mut` if the buffer will never fit the udp tx_buffer. + let send_capacity_too_small = self + .stack + .with(|i| i.sockets.get::(self.handle).payload_send_capacity() < buf.len()); + if send_capacity_too_small { + return Poll::Ready(Err(SendError::Truncated)); + } + self.with_mut(|s, _| match s.send_slice(buf, remote_endpoint) { // Entire datagram has been sent Ok(()) => Poll::Ready(Ok(())), @@ -268,12 +282,22 @@ impl<'a> UdpSocket<'a> { /// This method will wait until the buffer can fit the requested size before /// calling the function to fill its contents. /// + /// If the socket's send buffer is too small to fit `size`, this method will return `Poll::Ready(Err(SendError::Truncated))` + /// /// When the remote endpoint is not reachable, this method will return `Err(SendError::NoRoute)` pub async fn send_to_with(&mut self, size: usize, remote_endpoint: T, f: F) -> Result where T: Into + Copy, F: FnOnce(&mut [u8]) -> R, { + // Don't need to wake waker in `with_mut` if the buffer will never fit the udp tx_buffer. + let send_capacity_too_small = self + .stack + .with(|i| i.sockets.get::(self.handle).payload_send_capacity() < size); + if send_capacity_too_small { + return Err(SendError::Truncated); + } + let mut f = Some(f); poll_fn(move |cx| { self.with_mut(|s, _| { From e2ddba92f7f3f9e64da10e8351e335989f388109 Mon Sep 17 00:00:00 2001 From: ibuki2003 Date: Sun, 26 Jan 2025 17:23:41 +0900 Subject: [PATCH 0684/1217] embassy-sync: fix clear() to wake senders --- embassy-sync/src/channel.rs | 3 +++ embassy-sync/src/priority_channel.rs | 3 +++ embassy-sync/src/pubsub/mod.rs | 3 +++ embassy-sync/src/zerocopy_channel.rs | 3 +++ 4 files changed, 12 insertions(+) diff --git a/embassy-sync/src/channel.rs b/embassy-sync/src/channel.rs index 18b053111..9a7d2fa2f 100644 --- a/embassy-sync/src/channel.rs +++ b/embassy-sync/src/channel.rs @@ -562,6 +562,9 @@ impl ChannelState { } fn clear(&mut self) { + if self.queue.is_full() { + self.senders_waker.wake(); + } self.queue.clear(); } diff --git a/embassy-sync/src/priority_channel.rs b/embassy-sync/src/priority_channel.rs index d466a22ff..36959204f 100644 --- a/embassy-sync/src/priority_channel.rs +++ b/embassy-sync/src/priority_channel.rs @@ -411,6 +411,9 @@ where } fn clear(&mut self) { + if self.queue.len() == self.queue.capacity() { + self.senders_waker.wake(); + } self.queue.clear(); } diff --git a/embassy-sync/src/pubsub/mod.rs b/embassy-sync/src/pubsub/mod.rs index a2360a1d8..606efff0a 100644 --- a/embassy-sync/src/pubsub/mod.rs +++ b/embassy-sync/src/pubsub/mod.rs @@ -421,6 +421,9 @@ impl PubSubSta } fn clear(&mut self) { + if self.is_full() { + self.publisher_wakers.wake(); + } self.queue.clear(); } diff --git a/embassy-sync/src/zerocopy_channel.rs b/embassy-sync/src/zerocopy_channel.rs index 56433cd8a..15914578e 100644 --- a/embassy-sync/src/zerocopy_channel.rs +++ b/embassy-sync/src/zerocopy_channel.rs @@ -287,6 +287,9 @@ impl State { } fn clear(&mut self) { + if self.full { + self.receive_waker.wake(); + } self.front = 0; self.back = 0; self.full = false; From f2128a2953d5d4aeb96b2ad2c3ac5f060ce1a27a Mon Sep 17 00:00:00 2001 From: James Munns Date: Sun, 26 Jan 2025 12:53:39 +0100 Subject: [PATCH 0685/1217] Update Cargo.toml Avoid docs.rs build failures like https://docs.rs/crate/embassy-rp/0.3.0/builds/1609962 --- embassy-rp/Cargo.toml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index 528d433e1..4e5c66feb 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml @@ -20,7 +20,9 @@ flavors = [ ] [package.metadata.docs.rs] -features = ["defmt", "unstable-pac", "time-driver"] +# TODO: it's not GREAT to set a specific target, but docs.rs builds will fail otherwise +# for now, default to rp2040 +features = ["defmt", "unstable-pac", "time-driver", "rp2040"] [features] default = [ "rt" ] From 72020fc0126483f61be8ce2a4c8b78b0a5a95cc7 Mon Sep 17 00:00:00 2001 From: noracarmig Date: Sun, 26 Jan 2025 14:53:10 +0000 Subject: [PATCH 0686/1217] Reset complete count global variable on Dma configure --- embassy-stm32/src/dma/dma_bdma.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/embassy-stm32/src/dma/dma_bdma.rs b/embassy-stm32/src/dma/dma_bdma.rs index 6144db0d6..d31f4d01a 100644 --- a/embassy-stm32/src/dma/dma_bdma.rs +++ b/embassy-stm32/src/dma/dma_bdma.rs @@ -359,11 +359,13 @@ impl AnyChannel { match self.info().dma { #[cfg(dma)] DmaInfo::Dma(r) => { + let state: &ChannelState = &STATE[self.id as usize]; let ch = r.st(info.num); // "Preceding reads and writes cannot be moved past subsequent writes." fence(Ordering::SeqCst); + state.complete_count.store(0, Ordering::Release); self.clear_irqs(); ch.par().write_value(peri_addr as u32); From fcacbae2335c1c6cabf76f4731e367c9245bcc74 Mon Sep 17 00:00:00 2001 From: noracarmig Date: Sun, 26 Jan 2025 14:58:56 +0000 Subject: [PATCH 0687/1217] Allow chips from L5 (sai_v3_2pdm) and H7 (sai_v3_4pdm) families to use external sai sync --- embassy-stm32/src/sai/mod.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/embassy-stm32/src/sai/mod.rs b/embassy-stm32/src/sai/mod.rs index 18d5d7568..0dc8b62d0 100644 --- a/embassy-stm32/src/sai/mod.rs +++ b/embassy-stm32/src/sai/mod.rs @@ -190,7 +190,7 @@ pub enum SyncInput { /// Syncs with the other A/B sub-block within the SAI unit Internal, /// Syncs with a sub-block in the other SAI unit - #[cfg(any(sai_v4_2pdm, sai_v4_4pdm))] + #[cfg(any(sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))] External(SyncInputInstance), } @@ -199,14 +199,14 @@ impl SyncInput { match self { SyncInput::None => vals::Syncen::ASYNCHRONOUS, SyncInput::Internal => vals::Syncen::INTERNAL, - #[cfg(any(sai_v4_2pdm, sai_v4_4pdm))] + #[cfg(any(sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))] SyncInput::External(_) => vals::Syncen::EXTERNAL, } } } /// SAI instance to sync from. -#[cfg(any(sai_v4_2pdm, sai_v4_4pdm))] +#[cfg(any(sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))] #[derive(Copy, Clone, PartialEq)] #[allow(missing_docs)] pub enum SyncInputInstance { @@ -704,12 +704,12 @@ fn update_synchronous_config(config: &mut Config) { config.mode = Mode::Slave; config.sync_output = false; - #[cfg(any(sai_v1, sai_v2, sai_v3_2pdm, sai_v3_4pdm))] + #[cfg(any(sai_v1, sai_v2))] { config.sync_input = SyncInput::Internal; } - #[cfg(any(sai_v4_2pdm, sai_v4_4pdm))] + #[cfg(any(sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))] { //this must either be Internal or External //The asynchronous sub-block on the same SAI needs to enable sync_output @@ -870,7 +870,7 @@ impl<'d, T: Instance, W: word::Word> Sai<'d, T, W> { ch.cr2().modify(|w| w.set_fflush(true)); - #[cfg(any(sai_v4_2pdm, sai_v4_4pdm))] + #[cfg(any(sai_v3_2pdm, sai_v3_4pdm, sai_v4_2pdm, sai_v4_4pdm))] { if let SyncInput::External(i) = config.sync_input { T::REGS.gcr().modify(|w| { From d9026f06fea80fcb85fca00aede1bc911fb9de1b Mon Sep 17 00:00:00 2001 From: elagil Date: Sun, 26 Jan 2025 17:33:26 +0100 Subject: [PATCH 0688/1217] fix: STM32H5 UCPD reception --- embassy-stm32/src/ucpd.rs | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/embassy-stm32/src/ucpd.rs b/embassy-stm32/src/ucpd.rs index 2d44bf8ff..133a1c827 100644 --- a/embassy-stm32/src/ucpd.rs +++ b/embassy-stm32/src/ucpd.rs @@ -137,6 +137,13 @@ impl<'d, T: Instance> Ucpd<'d, T> { unsafe { T::Interrupt::enable() }; let r = T::REGS; + + #[cfg(stm32h5)] + r.cfgr2().write(|w| { + // Only takes effect, when UCPDEN=0. + w.set_rxafilten(true); + }); + r.cfgr1().write(|w| { // "The receiver is designed to work in the clock frequency range from 6 to 18 MHz. // However, the optimum performance is ensured in the range from 6 to 12 MHz" @@ -175,11 +182,6 @@ impl<'d, T: Instance> Ucpd<'d, T> { w.set_ucpden(true); }); - #[cfg(stm32h5)] - r.cfgr2().write(|w| { - w.set_rxafilten(true); - }); - // Software trim according to RM0481, p. 2650/2668 #[cfg(stm32h5)] { @@ -436,7 +438,7 @@ impl<'d, T: Instance> PdPhy<'d, T> { pub async fn receive_with_sop(&mut self, buf: &mut [u8]) -> Result<(Sop, usize), RxError> { let r = T::REGS; - let dma = unsafe { + let mut dma = unsafe { self.rx_dma .read(r.rxdr().as_ptr() as *mut u8, buf, TransferOptions::default()) }; @@ -451,14 +453,20 @@ impl<'d, T: Instance> PdPhy<'d, T> { }); }); + // Stop DMA reception immediately after receiving a packet, to prevent storing multiple packets in the same buffer. poll_fn(|cx| { let sr = r.sr().read(); + if sr.rxhrstdet() { + dma.request_stop(); + // Clean and re-enable hard reset receive interrupt. r.icr().write(|w| w.set_rxhrstdetcf(true)); r.imr().modify(|w| w.set_rxhrstdetie(true)); Poll::Ready(Err(RxError::HardReset)) } else if sr.rxmsgend() { + dma.request_stop(); + let ret = if sr.rxovr() { Err(RxError::Overrun) } else if sr.rxerr() { From 3e5514653fd13a27b3be504513478503e8b9de2d Mon Sep 17 00:00:00 2001 From: Tom Dohrmann Date: Sun, 26 Jan 2025 17:34:33 +0100 Subject: [PATCH 0689/1217] remove checks for reserved I2c addresses There are some non-compliant devices that respond to reserved I2c addresses. rp2040 behaves sanely for these addresses, so let's just allow using them. --- embassy-rp/src/i2c.rs | 13 ++++--------- embassy-rp/src/i2c_slave.rs | 5 +---- 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/embassy-rp/src/i2c.rs b/embassy-rp/src/i2c.rs index 32778215f..3a2ee666c 100644 --- a/embassy-rp/src/i2c.rs +++ b/embassy-rp/src/i2c.rs @@ -1,3 +1,5 @@ +#![cfg_attr(feature = "defmt", allow(deprecated))] // Suppress warnings for defmt::Format using Error::AddressReserved + //! I2C driver. use core::future; use core::marker::PhantomData; @@ -40,6 +42,7 @@ pub enum Error { /// Target i2c address is out of range AddressOutOfRange(u16), /// Target i2c address is reserved + #[deprecated = "embassy_rp no longer prevents accesses to reserved addresses."] AddressReserved(u16), } @@ -470,10 +473,6 @@ impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> { return Err(Error::AddressOutOfRange(addr)); } - if i2c_reserved_addr(addr) { - return Err(Error::AddressReserved(addr)); - } - let p = T::regs(); p.ic_enable().write(|w| w.set_enable(false)); p.ic_tar().write(|w| w.set_ic_tar(addr)); @@ -680,6 +679,7 @@ impl embedded_hal_1::i2c::Error for Error { Self::InvalidReadBufferLength => embedded_hal_1::i2c::ErrorKind::Other, Self::InvalidWriteBufferLength => embedded_hal_1::i2c::ErrorKind::Other, Self::AddressOutOfRange(_) => embedded_hal_1::i2c::ErrorKind::Other, + #[allow(deprecated)] Self::AddressReserved(_) => embedded_hal_1::i2c::ErrorKind::Other, } } @@ -775,11 +775,6 @@ impl<'d, T: Instance, M: Mode> embassy_embedded_hal::SetConfig for I2c<'d, T, M> } } -/// Check if address is reserved. -pub fn i2c_reserved_addr(addr: u16) -> bool { - ((addr & 0x78) == 0 || (addr & 0x78) == 0x78) && addr != 0 -} - pub(crate) trait SealedInstance { fn regs() -> crate::pac::i2c::I2c; fn reset() -> crate::pac::resets::regs::Peripherals; diff --git a/embassy-rp/src/i2c_slave.rs b/embassy-rp/src/i2c_slave.rs index c46a55d2e..d17b11d14 100644 --- a/embassy-rp/src/i2c_slave.rs +++ b/embassy-rp/src/i2c_slave.rs @@ -6,9 +6,7 @@ use core::task::Poll; use embassy_hal_internal::into_ref; use pac::i2c; -use crate::i2c::{ - i2c_reserved_addr, set_up_i2c_pin, AbortReason, Instance, InterruptHandler, SclPin, SdaPin, FIFO_SIZE, -}; +use crate::i2c::{set_up_i2c_pin, AbortReason, Instance, InterruptHandler, SclPin, SdaPin, FIFO_SIZE}; use crate::interrupt::typelevel::{Binding, Interrupt}; use crate::{pac, Peripheral}; @@ -97,7 +95,6 @@ impl<'d, T: Instance> I2cSlave<'d, T> { ) -> Self { into_ref!(_peri, scl, sda); - assert!(!i2c_reserved_addr(config.addr)); assert!(config.addr != 0); // Configure SCL & SDA pins From ff52bde787031493ce174cdc1dcc2434fd16aa1b Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sun, 26 Jan 2025 21:53:00 +0100 Subject: [PATCH 0690/1217] stm32: change all examples and tests to use GenericSMI::new_auto(). --- examples/stm32f4/src/bin/eth.rs | 2 +- examples/stm32f7/src/bin/eth.rs | 2 +- examples/stm32h5/src/bin/eth.rs | 2 +- examples/stm32h7/src/bin/eth.rs | 2 +- examples/stm32h7/src/bin/eth_client.rs | 2 +- examples/stm32h7/src/bin/eth_client_mii.rs | 2 +- tests/stm32/src/bin/eth.rs | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/examples/stm32f4/src/bin/eth.rs b/examples/stm32f4/src/bin/eth.rs index baed96449..a3af8f75c 100644 --- a/examples/stm32f4/src/bin/eth.rs +++ b/examples/stm32f4/src/bin/eth.rs @@ -76,7 +76,7 @@ async fn main(spawner: Spawner) -> ! { p.PG13, p.PB13, p.PG11, - GenericSMI::new(0), + GenericSMI::new_auto(), mac_addr, ); diff --git a/examples/stm32f7/src/bin/eth.rs b/examples/stm32f7/src/bin/eth.rs index 1f1eadf37..f353af674 100644 --- a/examples/stm32f7/src/bin/eth.rs +++ b/examples/stm32f7/src/bin/eth.rs @@ -77,7 +77,7 @@ async fn main(spawner: Spawner) -> ! { p.PG13, p.PB13, p.PG11, - GenericSMI::new(0), + GenericSMI::new_auto(), mac_addr, ); diff --git a/examples/stm32h5/src/bin/eth.rs b/examples/stm32h5/src/bin/eth.rs index eee1632f5..ead346741 100644 --- a/examples/stm32h5/src/bin/eth.rs +++ b/examples/stm32h5/src/bin/eth.rs @@ -80,7 +80,7 @@ async fn main(spawner: Spawner) -> ! { p.PG13, p.PB15, p.PG11, - GenericSMI::new(0), + GenericSMI::new_auto(), mac_addr, ); diff --git a/examples/stm32h7/src/bin/eth.rs b/examples/stm32h7/src/bin/eth.rs index ec3f2c000..6665cd1d0 100644 --- a/examples/stm32h7/src/bin/eth.rs +++ b/examples/stm32h7/src/bin/eth.rs @@ -79,7 +79,7 @@ async fn main(spawner: Spawner) -> ! { p.PG13, // TX_D0: Transmit Bit 0 p.PB13, // TX_D1: Transmit Bit 1 p.PG11, // TX_EN: Transmit Enable - GenericSMI::new(0), + GenericSMI::new_auto(), mac_addr, ); diff --git a/examples/stm32h7/src/bin/eth_client.rs b/examples/stm32h7/src/bin/eth_client.rs index a1558b079..4fbe10f31 100644 --- a/examples/stm32h7/src/bin/eth_client.rs +++ b/examples/stm32h7/src/bin/eth_client.rs @@ -81,7 +81,7 @@ async fn main(spawner: Spawner) -> ! { p.PG13, p.PB13, p.PG11, - GenericSMI::new(0), + GenericSMI::new_auto(), mac_addr, ); diff --git a/examples/stm32h7/src/bin/eth_client_mii.rs b/examples/stm32h7/src/bin/eth_client_mii.rs index a352ef444..53f86ac80 100644 --- a/examples/stm32h7/src/bin/eth_client_mii.rs +++ b/examples/stm32h7/src/bin/eth_client_mii.rs @@ -86,7 +86,7 @@ async fn main(spawner: Spawner) -> ! { p.PC2, p.PE2, p.PG11, - GenericSMI::new(1), + GenericSMI::new_auto(), mac_addr, ); info!("Device created"); diff --git a/tests/stm32/src/bin/eth.rs b/tests/stm32/src/bin/eth.rs index bf1922dde..4ab6e234f 100644 --- a/tests/stm32/src/bin/eth.rs +++ b/tests/stm32/src/bin/eth.rs @@ -87,7 +87,7 @@ async fn main(spawner: Spawner) { #[cfg(feature = "stm32h563zi")] p.PB15, p.PG11, - GenericSMI::new(0), + GenericSMI::new_auto(), mac_addr, ); From b1245858f355e764a17eda819198f68ad83883ab Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sun, 26 Jan 2025 22:42:13 +0100 Subject: [PATCH 0691/1217] stm32/eth: rename PHY->Phy, GenericSMI -> GenericPhy. Remove unneeded unsafes. We shouldn't use `unsafe` to mark merely "dangerous" actions, only actions that actually cause UB. --- .../eth/{generic_smi.rs => generic_phy.rs} | 10 ++--- embassy-stm32/src/eth/mod.rs | 38 +++++++++---------- embassy-stm32/src/eth/v1/mod.rs | 10 ++--- embassy-stm32/src/eth/v2/mod.rs | 8 ++-- examples/stm32f4/src/bin/eth.rs | 7 ++-- .../stm32f4/src/bin/eth_compliance_test.rs | 7 ++-- examples/stm32f7/src/bin/eth.rs | 7 ++-- examples/stm32h5/src/bin/eth.rs | 7 ++-- examples/stm32h7/src/bin/eth.rs | 7 ++-- examples/stm32h7/src/bin/eth_client.rs | 7 ++-- examples/stm32h7/src/bin/eth_client_mii.rs | 7 ++-- tests/stm32/src/bin/eth.rs | 7 ++-- 12 files changed, 56 insertions(+), 66 deletions(-) rename embassy-stm32/src/eth/{generic_smi.rs => generic_phy.rs} (97%) diff --git a/embassy-stm32/src/eth/generic_smi.rs b/embassy-stm32/src/eth/generic_phy.rs similarity index 97% rename from embassy-stm32/src/eth/generic_smi.rs rename to embassy-stm32/src/eth/generic_phy.rs index 239c52634..774beef80 100644 --- a/embassy-stm32/src/eth/generic_smi.rs +++ b/embassy-stm32/src/eth/generic_phy.rs @@ -7,7 +7,7 @@ use embassy_time::{Duration, Timer}; #[cfg(feature = "time")] use futures_util::FutureExt; -use super::{StationManagement, PHY}; +use super::{Phy, StationManagement}; #[allow(dead_code)] mod phy_consts { @@ -43,13 +43,13 @@ mod phy_consts { use self::phy_consts::*; /// Generic SMI Ethernet PHY implementation -pub struct GenericSMI { +pub struct GenericPhy { phy_addr: u8, #[cfg(feature = "time")] poll_interval: Duration, } -impl GenericSMI { +impl GenericPhy { /// Construct the PHY. It assumes the address `phy_addr` in the SMI communication /// /// # Panics @@ -89,7 +89,7 @@ fn blocking_delay_us(us: u32) { } } -unsafe impl PHY for GenericSMI { +impl Phy for GenericPhy { fn phy_reset(&mut self, sm: &mut S) { // Detect SMI address if self.phy_addr == 0xFF { @@ -148,7 +148,7 @@ unsafe impl PHY for GenericSMI { } /// Public functions for the PHY -impl GenericSMI { +impl GenericPhy { /// Set the SMI polling interval. #[cfg(feature = "time")] pub fn set_poll_interval(&mut self, poll_interval: Duration) { diff --git a/embassy-stm32/src/eth/mod.rs b/embassy-stm32/src/eth/mod.rs index 773452bf2..109ceeeb3 100644 --- a/embassy-stm32/src/eth/mod.rs +++ b/embassy-stm32/src/eth/mod.rs @@ -4,7 +4,7 @@ #[cfg_attr(any(eth_v1a, eth_v1b, eth_v1c), path = "v1/mod.rs")] #[cfg_attr(eth_v2, path = "v2/mod.rs")] mod _version; -pub mod generic_smi; +mod generic_phy; use core::mem::MaybeUninit; use core::task::Context; @@ -13,6 +13,7 @@ use embassy_net_driver::{Capabilities, HardwareAddress, LinkState}; use embassy_sync::waitqueue::AtomicWaker; pub use self::_version::{InterruptHandler, *}; +pub use self::generic_phy::*; use crate::rcc::RccPeripheral; #[allow(unused)] @@ -71,7 +72,7 @@ impl PacketQueue { static WAKER: AtomicWaker = AtomicWaker::new(); -impl<'d, T: Instance, P: PHY> embassy_net_driver::Driver for Ethernet<'d, T, P> { +impl<'d, T: Instance, P: Phy> embassy_net_driver::Driver for Ethernet<'d, T, P> { type RxToken<'a> = RxToken<'a, 'd> where @@ -156,23 +157,15 @@ impl<'a, 'd> embassy_net_driver::TxToken for TxToken<'a, 'd> { } /// Station Management Interface (SMI) on an ethernet PHY -/// -/// # Safety -/// -/// The methods cannot move out of self -pub unsafe trait StationManagement { +pub trait StationManagement { /// Read a register over SMI. fn smi_read(&mut self, phy_addr: u8, reg: u8) -> u16; /// Write a register over SMI. fn smi_write(&mut self, phy_addr: u8, reg: u8, val: u16); } -/// Traits for an Ethernet PHY -/// -/// # Safety -/// -/// The methods cannot move S -pub unsafe trait PHY { +/// Trait for an Ethernet PHY +pub trait Phy { /// Reset PHY and wait for it to come out of reset. fn phy_reset(&mut self, sm: &mut S); /// PHY initialisation. @@ -181,18 +174,23 @@ pub unsafe trait PHY { fn poll_link(&mut self, sm: &mut S, cx: &mut Context) -> bool; } -impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> { +impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> { /// Directly expose the SMI interface used by the Ethernet driver. /// /// This can be used to for example configure special PHY registers for compliance testing. - /// - /// # Safety - /// - /// Revert any temporary PHY register changes such as to enable test modes before handing - /// the Ethernet device over to the networking stack otherwise things likely won't work. - pub unsafe fn station_management(&mut self) -> &mut impl StationManagement { + pub fn station_management(&mut self) -> &mut impl StationManagement { &mut self.station_management } + + /// Access the user-supplied `Phy`. + pub fn phy(&self) -> &P { + &self.phy + } + + /// Mutably access the user-supplied `Phy`. + pub fn phy_mut(&mut self) -> &mut P { + &mut self.phy + } } trait SealedInstance { diff --git a/embassy-stm32/src/eth/v1/mod.rs b/embassy-stm32/src/eth/v1/mod.rs index 438b28020..e12ac2fef 100644 --- a/embassy-stm32/src/eth/v1/mod.rs +++ b/embassy-stm32/src/eth/v1/mod.rs @@ -46,7 +46,7 @@ impl interrupt::typelevel::Handler for InterruptHandl } /// Ethernet driver. -pub struct Ethernet<'d, T: Instance, P: PHY> { +pub struct Ethernet<'d, T: Instance, P: Phy> { _peri: PeripheralRef<'d, T>, pub(crate) tx: TDesRing<'d>, pub(crate) rx: RDesRing<'d>, @@ -91,7 +91,7 @@ macro_rules! config_pins { }; } -impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> { +impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> { /// safety: the returned instance is not leak-safe pub fn new( queue: &'d mut PacketQueue, @@ -272,12 +272,12 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> { } /// Ethernet station management interface. -pub struct EthernetStationManagement { +pub(crate) struct EthernetStationManagement { peri: PhantomData, clock_range: Cr, } -unsafe impl StationManagement for EthernetStationManagement { +impl StationManagement for EthernetStationManagement { fn smi_read(&mut self, phy_addr: u8, reg: u8) -> u16 { let mac = T::regs().ethernet_mac(); @@ -307,7 +307,7 @@ unsafe impl StationManagement for EthernetStationManagement { } } -impl<'d, T: Instance, P: PHY> Drop for Ethernet<'d, T, P> { +impl<'d, T: Instance, P: Phy> Drop for Ethernet<'d, T, P> { fn drop(&mut self) { let dma = T::regs().ethernet_dma(); let mac = T::regs().ethernet_mac(); diff --git a/embassy-stm32/src/eth/v2/mod.rs b/embassy-stm32/src/eth/v2/mod.rs index 9dd7f7d95..26e4eeb63 100644 --- a/embassy-stm32/src/eth/v2/mod.rs +++ b/embassy-stm32/src/eth/v2/mod.rs @@ -36,7 +36,7 @@ impl interrupt::typelevel::Handler for InterruptHandl } /// Ethernet driver. -pub struct Ethernet<'d, T: Instance, P: PHY> { +pub struct Ethernet<'d, T: Instance, P: Phy> { _peri: PeripheralRef<'d, T>, pub(crate) tx: TDesRing<'d>, pub(crate) rx: RDesRing<'d>, @@ -63,7 +63,7 @@ macro_rules! config_pins { }; } -impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> { +impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> { /// Create a new RMII ethernet driver using 9 pins. pub fn new( queue: &'d mut PacketQueue, @@ -304,7 +304,7 @@ pub struct EthernetStationManagement { clock_range: u8, } -unsafe impl StationManagement for EthernetStationManagement { +impl StationManagement for EthernetStationManagement { fn smi_read(&mut self, phy_addr: u8, reg: u8) -> u16 { let mac = T::regs().ethernet_mac(); @@ -334,7 +334,7 @@ unsafe impl StationManagement for EthernetStationManagement { } } -impl<'d, T: Instance, P: PHY> Drop for Ethernet<'d, T, P> { +impl<'d, T: Instance, P: Phy> Drop for Ethernet<'d, T, P> { fn drop(&mut self) { let dma = T::regs().ethernet_dma(); let mac = T::regs().ethernet_mac(); diff --git a/examples/stm32f4/src/bin/eth.rs b/examples/stm32f4/src/bin/eth.rs index a3af8f75c..634d8e2c6 100644 --- a/examples/stm32f4/src/bin/eth.rs +++ b/examples/stm32f4/src/bin/eth.rs @@ -5,8 +5,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_net::tcp::TcpSocket; use embassy_net::{Ipv4Address, StackResources}; -use embassy_stm32::eth::generic_smi::GenericSMI; -use embassy_stm32::eth::{Ethernet, PacketQueue}; +use embassy_stm32::eth::{Ethernet, GenericPhy, PacketQueue}; use embassy_stm32::peripherals::ETH; use embassy_stm32::rng::Rng; use embassy_stm32::time::Hertz; @@ -21,7 +20,7 @@ bind_interrupts!(struct Irqs { HASH_RNG => rng::InterruptHandler; }); -type Device = Ethernet<'static, ETH, GenericSMI>; +type Device = Ethernet<'static, ETH, GenericPhy>; #[embassy_executor::task] async fn net_task(mut runner: embassy_net::Runner<'static, Device>) -> ! { @@ -76,7 +75,7 @@ async fn main(spawner: Spawner) -> ! { p.PG13, p.PB13, p.PG11, - GenericSMI::new_auto(), + GenericPhy::new_auto(), mac_addr, ); diff --git a/examples/stm32f4/src/bin/eth_compliance_test.rs b/examples/stm32f4/src/bin/eth_compliance_test.rs index 5946fed79..52f9d57f6 100644 --- a/examples/stm32f4/src/bin/eth_compliance_test.rs +++ b/examples/stm32f4/src/bin/eth_compliance_test.rs @@ -3,8 +3,7 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::eth::generic_smi::GenericSMI; -use embassy_stm32::eth::{Ethernet, PacketQueue, StationManagement}; +use embassy_stm32::eth::{Ethernet, GenericPhy, PacketQueue, StationManagement}; use embassy_stm32::time::Hertz; use embassy_stm32::{bind_interrupts, eth, peripherals, rng, Config}; use embassy_time::Timer; @@ -59,11 +58,11 @@ async fn main(_spawner: Spawner) -> ! { p.PG13, p.PB13, p.PG11, - GenericSMI::new(PHY_ADDR), + GenericPhy::new(PHY_ADDR), mac_addr, ); - let sm = unsafe { device.station_management() }; + let sm = device.station_management(); // Just an example. Exact register settings depend on the specific PHY and test. sm.smi_write(PHY_ADDR, 0, 0x2100); diff --git a/examples/stm32f7/src/bin/eth.rs b/examples/stm32f7/src/bin/eth.rs index f353af674..17ab7fc00 100644 --- a/examples/stm32f7/src/bin/eth.rs +++ b/examples/stm32f7/src/bin/eth.rs @@ -5,8 +5,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_net::tcp::TcpSocket; use embassy_net::{Ipv4Address, StackResources}; -use embassy_stm32::eth::generic_smi::GenericSMI; -use embassy_stm32::eth::{Ethernet, PacketQueue}; +use embassy_stm32::eth::{Ethernet, GenericPhy, PacketQueue}; use embassy_stm32::peripherals::ETH; use embassy_stm32::rng::Rng; use embassy_stm32::time::Hertz; @@ -22,7 +21,7 @@ bind_interrupts!(struct Irqs { HASH_RNG => rng::InterruptHandler; }); -type Device = Ethernet<'static, ETH, GenericSMI>; +type Device = Ethernet<'static, ETH, GenericPhy>; #[embassy_executor::task] async fn net_task(mut runner: embassy_net::Runner<'static, Device>) -> ! { @@ -77,7 +76,7 @@ async fn main(spawner: Spawner) -> ! { p.PG13, p.PB13, p.PG11, - GenericSMI::new_auto(), + GenericPhy::new_auto(), mac_addr, ); diff --git a/examples/stm32h5/src/bin/eth.rs b/examples/stm32h5/src/bin/eth.rs index ead346741..4034b552c 100644 --- a/examples/stm32h5/src/bin/eth.rs +++ b/examples/stm32h5/src/bin/eth.rs @@ -5,8 +5,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_net::tcp::TcpSocket; use embassy_net::{Ipv4Address, StackResources}; -use embassy_stm32::eth::generic_smi::GenericSMI; -use embassy_stm32::eth::{Ethernet, PacketQueue}; +use embassy_stm32::eth::{Ethernet, GenericPhy, PacketQueue}; use embassy_stm32::peripherals::ETH; use embassy_stm32::rcc::{ AHBPrescaler, APBPrescaler, Hse, HseMode, Pll, PllDiv, PllMul, PllPreDiv, PllSource, Sysclk, VoltageScale, @@ -25,7 +24,7 @@ bind_interrupts!(struct Irqs { RNG => rng::InterruptHandler; }); -type Device = Ethernet<'static, ETH, GenericSMI>; +type Device = Ethernet<'static, ETH, GenericPhy>; #[embassy_executor::task] async fn net_task(mut runner: embassy_net::Runner<'static, Device>) -> ! { @@ -80,7 +79,7 @@ async fn main(spawner: Spawner) -> ! { p.PG13, p.PB15, p.PG11, - GenericSMI::new_auto(), + GenericPhy::new_auto(), mac_addr, ); diff --git a/examples/stm32h7/src/bin/eth.rs b/examples/stm32h7/src/bin/eth.rs index 6665cd1d0..da7aa4af5 100644 --- a/examples/stm32h7/src/bin/eth.rs +++ b/examples/stm32h7/src/bin/eth.rs @@ -5,8 +5,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_net::tcp::TcpSocket; use embassy_net::{Ipv4Address, StackResources}; -use embassy_stm32::eth::generic_smi::GenericSMI; -use embassy_stm32::eth::{Ethernet, PacketQueue}; +use embassy_stm32::eth::{Ethernet, GenericPhy, PacketQueue}; use embassy_stm32::peripherals::ETH; use embassy_stm32::rng::Rng; use embassy_stm32::{bind_interrupts, eth, peripherals, rng, Config}; @@ -21,7 +20,7 @@ bind_interrupts!(struct Irqs { RNG => rng::InterruptHandler; }); -type Device = Ethernet<'static, ETH, GenericSMI>; +type Device = Ethernet<'static, ETH, GenericPhy>; #[embassy_executor::task] async fn net_task(mut runner: embassy_net::Runner<'static, Device>) -> ! { @@ -79,7 +78,7 @@ async fn main(spawner: Spawner) -> ! { p.PG13, // TX_D0: Transmit Bit 0 p.PB13, // TX_D1: Transmit Bit 1 p.PG11, // TX_EN: Transmit Enable - GenericSMI::new_auto(), + GenericPhy::new_auto(), mac_addr, ); diff --git a/examples/stm32h7/src/bin/eth_client.rs b/examples/stm32h7/src/bin/eth_client.rs index 4fbe10f31..10485109a 100644 --- a/examples/stm32h7/src/bin/eth_client.rs +++ b/examples/stm32h7/src/bin/eth_client.rs @@ -7,8 +7,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_net::tcp::client::{TcpClient, TcpClientState}; use embassy_net::StackResources; -use embassy_stm32::eth::generic_smi::GenericSMI; -use embassy_stm32::eth::{Ethernet, PacketQueue}; +use embassy_stm32::eth::{Ethernet, GenericPhy, PacketQueue}; use embassy_stm32::peripherals::ETH; use embassy_stm32::rng::Rng; use embassy_stm32::{bind_interrupts, eth, peripherals, rng, Config}; @@ -24,7 +23,7 @@ bind_interrupts!(struct Irqs { RNG => rng::InterruptHandler; }); -type Device = Ethernet<'static, ETH, GenericSMI>; +type Device = Ethernet<'static, ETH, GenericPhy>; #[embassy_executor::task] async fn net_task(mut runner: embassy_net::Runner<'static, Device>) -> ! { @@ -81,7 +80,7 @@ async fn main(spawner: Spawner) -> ! { p.PG13, p.PB13, p.PG11, - GenericSMI::new_auto(), + GenericPhy::new_auto(), mac_addr, ); diff --git a/examples/stm32h7/src/bin/eth_client_mii.rs b/examples/stm32h7/src/bin/eth_client_mii.rs index 53f86ac80..849173615 100644 --- a/examples/stm32h7/src/bin/eth_client_mii.rs +++ b/examples/stm32h7/src/bin/eth_client_mii.rs @@ -7,8 +7,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_net::tcp::client::{TcpClient, TcpClientState}; use embassy_net::StackResources; -use embassy_stm32::eth::generic_smi::GenericSMI; -use embassy_stm32::eth::{Ethernet, PacketQueue}; +use embassy_stm32::eth::{Ethernet, GenericPhy, PacketQueue}; use embassy_stm32::peripherals::ETH; use embassy_stm32::rng::Rng; use embassy_stm32::{bind_interrupts, eth, peripherals, rng, Config}; @@ -24,7 +23,7 @@ bind_interrupts!(struct Irqs { RNG => rng::InterruptHandler; }); -type Device = Ethernet<'static, ETH, GenericSMI>; +type Device = Ethernet<'static, ETH, GenericPhy>; #[embassy_executor::task] async fn net_task(mut runner: embassy_net::Runner<'static, Device>) -> ! { @@ -86,7 +85,7 @@ async fn main(spawner: Spawner) -> ! { p.PC2, p.PE2, p.PG11, - GenericSMI::new_auto(), + GenericPhy::new_auto(), mac_addr, ); info!("Device created"); diff --git a/tests/stm32/src/bin/eth.rs b/tests/stm32/src/bin/eth.rs index 4ab6e234f..a7e76fd8e 100644 --- a/tests/stm32/src/bin/eth.rs +++ b/tests/stm32/src/bin/eth.rs @@ -7,8 +7,7 @@ mod common; use common::*; use embassy_executor::Spawner; use embassy_net::StackResources; -use embassy_stm32::eth::generic_smi::GenericSMI; -use embassy_stm32::eth::{Ethernet, PacketQueue}; +use embassy_stm32::eth::{Ethernet, GenericPhy, PacketQueue}; use embassy_stm32::peripherals::ETH; use embassy_stm32::rng::Rng; use embassy_stm32::{bind_interrupts, eth, peripherals, rng}; @@ -29,7 +28,7 @@ bind_interrupts!(struct Irqs { RNG => rng::InterruptHandler; }); -type Device = Ethernet<'static, ETH, GenericSMI>; +type Device = Ethernet<'static, ETH, GenericPhy>; #[embassy_executor::task] async fn net_task(mut runner: embassy_net::Runner<'static, Device>) -> ! { @@ -87,7 +86,7 @@ async fn main(spawner: Spawner) { #[cfg(feature = "stm32h563zi")] p.PB15, p.PG11, - GenericSMI::new_auto(), + GenericPhy::new_auto(), mac_addr, ); From c0d14a145c901126a548a77026ef2ef0d6e79738 Mon Sep 17 00:00:00 2001 From: Easyoakland <97992568+Easyoakland@users.noreply.github.com> Date: Sun, 26 Jan 2025 15:51:31 -0700 Subject: [PATCH 0692/1217] - use `with` - rename to Truncated to `PacketTooLarge` --- embassy-net/src/udp.rs | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/embassy-net/src/udp.rs b/embassy-net/src/udp.rs index 7baa89ea0..eca3980b9 100644 --- a/embassy-net/src/udp.rs +++ b/embassy-net/src/udp.rs @@ -30,7 +30,7 @@ pub enum SendError { /// Socket not bound to an outgoing port. SocketNotBound, /// There is not enough transmit buffer capacity to ever send this packet. - Truncated, + PacketTooLarge, } /// Error returned by [`UdpSocket::recv_from`]. @@ -252,11 +252,9 @@ impl<'a> UdpSocket<'a> { T: Into, { // Don't need to wake waker in `with_mut` if the buffer will never fit the udp tx_buffer. - let send_capacity_too_small = self - .stack - .with(|i| i.sockets.get::(self.handle).payload_send_capacity() < buf.len()); + let send_capacity_too_small = self.with(|s, _| s.payload_send_capacity() < buf.len()); if send_capacity_too_small { - return Poll::Ready(Err(SendError::Truncated)); + return Poll::Ready(Err(SendError::PacketTooLarge)); } self.with_mut(|s, _| match s.send_slice(buf, remote_endpoint) { @@ -291,11 +289,9 @@ impl<'a> UdpSocket<'a> { F: FnOnce(&mut [u8]) -> R, { // Don't need to wake waker in `with_mut` if the buffer will never fit the udp tx_buffer. - let send_capacity_too_small = self - .stack - .with(|i| i.sockets.get::(self.handle).payload_send_capacity() < size); + let send_capacity_too_small = self.with(|s, _| s.payload_send_capacity() < size); if send_capacity_too_small { - return Err(SendError::Truncated); + return Err(SendError::PacketTooLarge); } let mut f = Some(f); From cbbc1f1a2ffc5e943e5ed9bb0d6cfa723111f7d1 Mon Sep 17 00:00:00 2001 From: Easyoakland <97992568+Easyoakland@users.noreply.github.com> Date: Sun, 26 Jan 2025 16:36:12 -0700 Subject: [PATCH 0693/1217] update comments to match code --- embassy-net/src/udp.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/embassy-net/src/udp.rs b/embassy-net/src/udp.rs index eca3980b9..7db9c5bbc 100644 --- a/embassy-net/src/udp.rs +++ b/embassy-net/src/udp.rs @@ -226,7 +226,7 @@ impl<'a> UdpSocket<'a> { /// /// This method will wait until the datagram has been sent. /// - /// If the socket's send buffer is too small to fit `buf`, this method will return `Poll::Ready(Err(SendError::Truncated))` + /// If the socket's send buffer is too small to fit `buf`, this method will return `Poll::Ready(Err(SendError::PacketTooLarge))` /// /// When the remote endpoint is not reachable, this method will return `Err(SendError::NoRoute)` pub async fn send_to(&self, buf: &[u8], remote_endpoint: T) -> Result<(), SendError> @@ -244,7 +244,7 @@ impl<'a> UdpSocket<'a> { /// When the socket's send buffer is full, this method will return `Poll::Pending` /// and register the current task to be notified when the buffer has space available. /// - /// If the socket's send buffer is too small to fit `buf`, this method will return `Poll::Ready(Err(SendError::Truncated))` + /// If the socket's send buffer is too small to fit `buf`, this method will return `Poll::Ready(Err(SendError::PacketTooLarge))` /// /// When the remote endpoint is not reachable, this method will return `Poll::Ready(Err(Error::NoRoute))`. pub fn poll_send_to(&self, buf: &[u8], remote_endpoint: T, cx: &mut Context<'_>) -> Poll> @@ -280,7 +280,7 @@ impl<'a> UdpSocket<'a> { /// This method will wait until the buffer can fit the requested size before /// calling the function to fill its contents. /// - /// If the socket's send buffer is too small to fit `size`, this method will return `Poll::Ready(Err(SendError::Truncated))` + /// If the socket's send buffer is too small to fit `size`, this method will return `Poll::Ready(Err(SendError::PacketTooLarge))` /// /// When the remote endpoint is not reachable, this method will return `Err(SendError::NoRoute)` pub async fn send_to_with(&mut self, size: usize, remote_endpoint: T, f: F) -> Result From 89e25c7b14f77ead6dd8d895d982aa684baf9874 Mon Sep 17 00:00:00 2001 From: Easyoakland <97992568+Easyoakland@users.noreply.github.com> Date: Sun, 26 Jan 2025 16:55:52 -0700 Subject: [PATCH 0694/1217] don't mention Poll::Ready for async fns as it's implied --- embassy-net/src/udp.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-net/src/udp.rs b/embassy-net/src/udp.rs index 7db9c5bbc..63c2f4c75 100644 --- a/embassy-net/src/udp.rs +++ b/embassy-net/src/udp.rs @@ -226,7 +226,7 @@ impl<'a> UdpSocket<'a> { /// /// This method will wait until the datagram has been sent. /// - /// If the socket's send buffer is too small to fit `buf`, this method will return `Poll::Ready(Err(SendError::PacketTooLarge))` + /// If the socket's send buffer is too small to fit `buf`, this method will return `Err(SendError::PacketTooLarge)` /// /// When the remote endpoint is not reachable, this method will return `Err(SendError::NoRoute)` pub async fn send_to(&self, buf: &[u8], remote_endpoint: T) -> Result<(), SendError> @@ -280,7 +280,7 @@ impl<'a> UdpSocket<'a> { /// This method will wait until the buffer can fit the requested size before /// calling the function to fill its contents. /// - /// If the socket's send buffer is too small to fit `size`, this method will return `Poll::Ready(Err(SendError::PacketTooLarge))` + /// If the socket's send buffer is too small to fit `size`, this method will return `Err(SendError::PacketTooLarge)` /// /// When the remote endpoint is not reachable, this method will return `Err(SendError::NoRoute)` pub async fn send_to_with(&mut self, size: usize, remote_endpoint: T, f: F) -> Result From 640612a47f1d574ed22a8713b26b938ff54f9655 Mon Sep 17 00:00:00 2001 From: klownfish Date: Tue, 28 Jan 2025 21:33:51 +0100 Subject: [PATCH 0695/1217] nrf52833: configure internal LDO --- embassy-nrf/src/lib.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index faef44d1b..9a9485f04 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs @@ -314,14 +314,14 @@ pub mod config { #[cfg(feature = "nrf52840")] pub reg0: bool, /// Configure the voltage of the first stage DCDC. It is stored in non-volatile memory (UICR.REGOUT0 register); pass None to not touch it. - #[cfg(feature = "nrf52840")] + #[cfg(any(feature = "nrf52840", feature = "nrf52833"))] pub reg0_voltage: Option, /// Config for the second stage DCDC (VDD -> DEC4), if disabled LDO will be used. pub reg1: bool, } /// Output voltage setting for REG0 regulator stage. - #[cfg(feature = "nrf52840")] + #[cfg(any(feature = "nrf52840", feature = "nrf52833"))] pub enum Reg0Voltage { /// 1.8 V _1V8 = 0, @@ -388,7 +388,7 @@ pub mod config { dcdc: DcdcConfig { #[cfg(feature = "nrf52840")] reg0: false, - #[cfg(feature = "nrf52840")] + #[cfg(any(feature = "nrf52840", feature = "nrf52833"))] reg0_voltage: None, reg1: false, }, @@ -664,7 +664,7 @@ pub fn init(config: config::Config) -> Peripherals { } } - #[cfg(feature = "nrf52840")] + #[cfg(any(feature = "nrf52840", feature = "nrf52833"))] unsafe { if let Some(value) = config.dcdc.reg0_voltage { let value = value as u32; From 9d353d251c644cc039679a30c0f8ab563181c1b9 Mon Sep 17 00:00:00 2001 From: flippette Date: Thu, 30 Jan 2025 00:13:56 +0200 Subject: [PATCH 0696/1217] Correct ADC channels for RP2350XB --- embassy-rp/src/adc.rs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/embassy-rp/src/adc.rs b/embassy-rp/src/adc.rs index 19441f194..8defb5231 100644 --- a/embassy-rp/src/adc.rs +++ b/embassy-rp/src/adc.rs @@ -58,11 +58,21 @@ impl<'p> Channel<'p> { } fn channel(&self) -> u8 { + #[cfg(any(feature = "rp2040", feature = "rp235xa"))] + const CH_OFFSET: u8 = 26; + #[cfg(feature = "rp235xb")] + const CH_OFFSET: u8 = 40; + + #[cfg(any(feature = "rp2040", feature = "rp235xa"))] + const TS_CHAN: u8 = 4; + #[cfg(feature = "rp235xb")] + const TS_CHAN: u8 = 8; + match &self.0 { // this requires adc pins to be sequential and matching the adc channels, - // which is the case for rp2040 - Source::Pin(p) => p._pin() - 26, - Source::TempSensor(_) => 4, + // which is the case for rp2040/rp235xy + Source::Pin(p) => p._pin() - CH_OFFSET, + Source::TempSensor(_) => TS_CHAN, } } } From 1df510e5c9f57a174e6aa2c3a1f6aa148b684662 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Wed, 29 Jan 2025 23:25:36 +0100 Subject: [PATCH 0697/1217] RIP nrf52833-dk --- ci.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/ci.sh b/ci.sh index 59bcab875..56aa8b784 100755 --- a/ci.sh +++ b/ci.sh @@ -305,6 +305,7 @@ cargo batch \ # temporarily disabled, these boards are dead. rm -rf out/tests/stm32f103c8 rm -rf out/tests/nrf52840-dk +rm -rf out/tests/nrf52833-dk rm out/tests/stm32wb55rg/wpan_mac rm out/tests/stm32wb55rg/wpan_ble From 7d66f1ca192bb5de83626cdb91f82c1caf265d73 Mon Sep 17 00:00:00 2001 From: lsartory Date: Sat, 1 Feb 2025 16:43:41 +0100 Subject: [PATCH 0698/1217] Fix issue #3828 Zero-copy channels could not be used between interrupts and thread-mode tasks because the internal buffer is stored as a raw pointer. A wrapper struct implementing the Sync trait fixes this. --- embassy-sync/src/zerocopy_channel.rs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/embassy-sync/src/zerocopy_channel.rs b/embassy-sync/src/zerocopy_channel.rs index 15914578e..ad6fe74c5 100644 --- a/embassy-sync/src/zerocopy_channel.rs +++ b/embassy-sync/src/zerocopy_channel.rs @@ -35,7 +35,7 @@ use crate::waitqueue::WakerRegistration; /// The channel requires a buffer of recyclable elements. Writing to the channel is done through /// an `&mut T`. pub struct Channel<'a, M: RawMutex, T> { - buf: *mut T, + buf: BufferPtr, phantom: PhantomData<&'a mut T>, state: Mutex>, } @@ -50,7 +50,7 @@ impl<'a, M: RawMutex, T> Channel<'a, M, T> { assert!(len != 0); Self { - buf: buf.as_mut_ptr(), + buf: BufferPtr(buf.as_mut_ptr()), phantom: PhantomData, state: Mutex::new(RefCell::new(State { capacity: len, @@ -94,6 +94,18 @@ impl<'a, M: RawMutex, T> Channel<'a, M, T> { } } +#[repr(transparent)] +struct BufferPtr(*mut T); + +impl BufferPtr { + unsafe fn add(&self, count: usize) -> *mut T { + self.0.add(count) + } +} + +unsafe impl Send for BufferPtr {} +unsafe impl Sync for BufferPtr {} + /// Send-only access to a [`Channel`]. pub struct Sender<'a, M: RawMutex, T> { channel: &'a Channel<'a, M, T>, From 89b5795eec6279911458da524dba3b3c68929913 Mon Sep 17 00:00:00 2001 From: Graic <33105645+Graicc@users.noreply.github.com> Date: Sat, 1 Feb 2025 18:06:43 -0500 Subject: [PATCH 0699/1217] Fix typo in getting started docs --- docs/pages/getting_started.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/pages/getting_started.adoc b/docs/pages/getting_started.adoc index 017409018..954f3fd28 100644 --- a/docs/pages/getting_started.adoc +++ b/docs/pages/getting_started.adoc @@ -86,7 +86,7 @@ NOTE: How does the `+cargo run+` command know how to connect to our board and pr === It didn’t work! -If you hare having issues when running `+cargo run --release+`, please check the following: +If you are having issues when running `+cargo run --release+`, please check the following: * You are specifying the correct `+--chip+` on the command line, OR * You have set `+.cargo/config.toml+`’s run line to the correct chip, AND From ec5f283d150032f721a211b219b584166434790c Mon Sep 17 00:00:00 2001 From: Marvin Gudel Date: Sun, 2 Feb 2025 14:28:45 +0100 Subject: [PATCH 0700/1217] Add cancel safety notes to Ticker --- embassy-time/src/timer.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/embassy-time/src/timer.rs b/embassy-time/src/timer.rs index 295ddbd9b..34e5762d2 100644 --- a/embassy-time/src/timer.rs +++ b/embassy-time/src/timer.rs @@ -200,6 +200,10 @@ impl Future for Timer { /// } /// } /// ``` +/// +/// ## Cancel safety +/// It is safe to cancel waiting for the next tick, +/// meaning no tick is lost if the Future is dropped. pub struct Ticker { expires_at: Instant, duration: Duration, @@ -231,6 +235,9 @@ impl Ticker { } /// Waits for the next tick. + /// + /// ## Cancel safety + /// The produced Future is cancel safe, meaning no tick is lost if the Future is dropped. pub fn next(&mut self) -> impl Future + Send + Sync + '_ { poll_fn(|cx| { if self.expires_at <= Instant::now() { From ce04cf83407f0c70d7d1eec4ed1de2dfbef06dd6 Mon Sep 17 00:00:00 2001 From: vinsynth <1.5vhunt@gmail.com> Date: Sun, 2 Feb 2025 18:12:34 -0500 Subject: [PATCH 0701/1217] set PLLI2S M and SRC for f4 chips which support it --- embassy-stm32/src/rcc/f247.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/embassy-stm32/src/rcc/f247.rs b/embassy-stm32/src/rcc/f247.rs index 3e7aff02d..b855d3c09 100644 --- a/embassy-stm32/src/rcc/f247.rs +++ b/embassy-stm32/src/rcc/f247.rs @@ -414,6 +414,11 @@ fn init_pll(instance: PllInstance, config: Option, input: &PllInput) -> Pll }), #[cfg(any(all(stm32f4, not(stm32f410)), stm32f7))] PllInstance::Plli2s => RCC.plli2scfgr().write(|w| { + #[cfg(any(stm32f411, stm32f412, stm32f413, stm32f446))] + w.set_pllm(pll.prediv); + #[cfg(any(stm32f412, stm32f413))] + w.set_pllsrc(input.source); + write_fields!(w); }), #[cfg(stm32f2)] From 6ec72c0af0b2682d5bea345832f6a0c7a6284ead Mon Sep 17 00:00:00 2001 From: vinsynth <1.5vhunt@gmail.com> Date: Sun, 2 Feb 2025 18:53:06 -0500 Subject: [PATCH 0702/1217] set PLLI2SM and plli2s_src f423 --- embassy-stm32/src/rcc/f247.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/rcc/f247.rs b/embassy-stm32/src/rcc/f247.rs index b855d3c09..79d793dcc 100644 --- a/embassy-stm32/src/rcc/f247.rs +++ b/embassy-stm32/src/rcc/f247.rs @@ -414,9 +414,9 @@ fn init_pll(instance: PllInstance, config: Option, input: &PllInput) -> Pll }), #[cfg(any(all(stm32f4, not(stm32f410)), stm32f7))] PllInstance::Plli2s => RCC.plli2scfgr().write(|w| { - #[cfg(any(stm32f411, stm32f412, stm32f413, stm32f446))] + #[cfg(any(stm32f411, stm32f412, stm32f413, stm32f423, stm32f446))] w.set_pllm(pll.prediv); - #[cfg(any(stm32f412, stm32f413))] + #[cfg(any(stm32f412, stm32f413, stm32f423))] w.set_pllsrc(input.source); write_fields!(w); From 37b180c61eb58515561fb59e0d4fc558cc8d5e53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Mon, 3 Feb 2025 17:20:35 +0100 Subject: [PATCH 0703/1217] Allow inlining on time driver boundary --- embassy-time-driver/src/lib.rs | 4 ++++ embassy-time/src/instant.rs | 1 + 2 files changed, 5 insertions(+) diff --git a/embassy-time-driver/src/lib.rs b/embassy-time-driver/src/lib.rs index f198a3ead..32cb68296 100644 --- a/embassy-time-driver/src/lib.rs +++ b/embassy-time-driver/src/lib.rs @@ -139,11 +139,13 @@ extern "Rust" { } /// See [`Driver::now`] +#[inline] pub fn now() -> u64 { unsafe { _embassy_time_now() } } /// Schedule the given waker to be woken at `at`. +#[inline] pub fn schedule_wake(at: u64, waker: &Waker) { unsafe { _embassy_time_schedule_wake(at, waker) } } @@ -157,11 +159,13 @@ macro_rules! time_driver_impl { static $name: $t = $val; #[no_mangle] + #[inline] fn _embassy_time_now() -> u64 { <$t as $crate::Driver>::now(&$name) } #[no_mangle] + #[inline] fn _embassy_time_schedule_wake(at: u64, waker: &core::task::Waker) { <$t as $crate::Driver>::schedule_wake(&$name, at, waker); } diff --git a/embassy-time/src/instant.rs b/embassy-time/src/instant.rs index 909f1b173..cae80e51f 100644 --- a/embassy-time/src/instant.rs +++ b/embassy-time/src/instant.rs @@ -17,6 +17,7 @@ impl Instant { pub const MAX: Instant = Instant { ticks: u64::MAX }; /// Returns an Instant representing the current time. + #[inline] pub fn now() -> Instant { Instant { ticks: embassy_time_driver::now(), From d363401ba519e23a189f05287ecafd95f2feba16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20van=20Dorst?= Date: Mon, 3 Feb 2025 22:08:23 +0100 Subject: [PATCH 0704/1217] embassy-usb: fix `core::intrinsics` deprecate warning in nightly. Replaced `core::intrinsics::copy_nonoverlapping` with the `core::ptr::copy_nonoverlapping`. Compiling embassy-usb v0.4.0 (embassy/embassy-usb) warning: use of deprecated module `core::intrinsics`: import this function via `std::mem` instead --> embassy/embassy-usb/src/class/cdc_ncm/mod.rs:17:23 | 17 | use core::intrinsics::copy_nonoverlapping; | ^^^^^^^^^^^^^^^^^^^ --- embassy-usb/src/class/cdc_ncm/mod.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/embassy-usb/src/class/cdc_ncm/mod.rs b/embassy-usb/src/class/cdc_ncm/mod.rs index bea9dac27..09d923d2a 100644 --- a/embassy-usb/src/class/cdc_ncm/mod.rs +++ b/embassy-usb/src/class/cdc_ncm/mod.rs @@ -14,9 +14,8 @@ //! This is due to regex spaghetti: //! and this nonsense in the linux kernel: -use core::intrinsics::copy_nonoverlapping; use core::mem::{size_of, MaybeUninit}; -use core::ptr::addr_of; +use core::ptr::{addr_of, copy_nonoverlapping}; use crate::control::{self, InResponse, OutResponse, Recipient, Request, RequestType}; use crate::driver::{Driver, Endpoint, EndpointError, EndpointIn, EndpointOut}; From c1671572b4eee06deb51547a98ffa00a7db95652 Mon Sep 17 00:00:00 2001 From: James Sizeland Date: Mon, 3 Feb 2025 23:08:55 +0000 Subject: [PATCH 0705/1217] improve SpawnError::Busy message --- embassy-executor/src/spawner.rs | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/embassy-executor/src/spawner.rs b/embassy-executor/src/spawner.rs index ce24589bf..7e76a09c6 100644 --- a/embassy-executor/src/spawner.rs +++ b/embassy-executor/src/spawner.rs @@ -51,8 +51,7 @@ impl Drop for SpawnToken { } /// Error returned when spawning a task. -#[derive(Copy, Clone, Debug)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[derive(Copy, Clone)] pub enum SpawnError { /// Too many instances of this task are already running. /// @@ -62,10 +61,25 @@ pub enum SpawnError { Busy, } +impl core::fmt::Debug for SpawnError { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + core::fmt::Display::fmt(self, f) + } +} + impl core::fmt::Display for SpawnError { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { match self { - SpawnError::Busy => write!(f, "Busy"), + SpawnError::Busy => write!(f, "Busy - Too many instances of this task are already running. Check the `pool_size` attribute of the task."), + } + } +} + +#[cfg(feature = "defmt")] +impl defmt::Format for SpawnError { + fn format(&self, f: defmt::Formatter) { + match self { + SpawnError::Busy => defmt::write!(f, "Busy - Too many instances of this task are already running. Check the `pool_size` attribute of the task."), } } } From 188828775e83cbebb7a558843eae5eb50e1dc2b8 Mon Sep 17 00:00:00 2001 From: Shaw Drastin <168159404+showier-drastic@users.noreply.github.com> Date: Tue, 4 Feb 2025 10:53:45 +0800 Subject: [PATCH 0706/1217] SpiDevice cancel safety: always set CS pin to high on drop If a transfer is dropped, the CS will stay in a low state, which seems to be unsafe. --- embassy-embedded-hal/Cargo.toml | 1 + embassy-embedded-hal/src/shared_bus/asynch/spi.rs | 15 +++++++++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/embassy-embedded-hal/Cargo.toml b/embassy-embedded-hal/Cargo.toml index 9dd2e419f..f385963f1 100644 --- a/embassy-embedded-hal/Cargo.toml +++ b/embassy-embedded-hal/Cargo.toml @@ -22,6 +22,7 @@ time = ["dep:embassy-time"] default = ["time"] [dependencies] +embassy-hal-internal = { version = "0.2.0", path = "../embassy-hal-internal" } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } embassy-sync = { version = "0.6.2", path = "../embassy-sync" } embassy-time = { version = "0.4.0", path = "../embassy-time", optional = true } diff --git a/embassy-embedded-hal/src/shared_bus/asynch/spi.rs b/embassy-embedded-hal/src/shared_bus/asynch/spi.rs index 30d4ecc36..0ba1033f6 100644 --- a/embassy-embedded-hal/src/shared_bus/asynch/spi.rs +++ b/embassy-embedded-hal/src/shared_bus/asynch/spi.rs @@ -25,6 +25,7 @@ //! let display2 = ST7735::new(spi_dev2, dc2, rst2, Default::default(), 160, 128); //! ``` +use embassy_hal_internal::drop::OnDrop; use embassy_sync::blocking_mutex::raw::RawMutex; use embassy_sync::mutex::Mutex; use embedded_hal_1::digital::OutputPin; @@ -70,6 +71,10 @@ where let mut bus = self.bus.lock().await; self.cs.set_low().map_err(SpiDeviceError::Cs)?; + let cs_drop = OnDrop::new(|| { + let _ = self.cs.set_high(); + }); + let op_res = 'ops: { for op in operations { let res = match op { @@ -97,11 +102,10 @@ where // On failure, it's important to still flush and deassert CS. let flush_res = bus.flush().await; - let cs_res = self.cs.set_high(); + drop(cs_drop); let op_res = op_res.map_err(SpiDeviceError::Spi)?; flush_res.map_err(SpiDeviceError::Spi)?; - cs_res.map_err(SpiDeviceError::Cs)?; Ok(op_res) } @@ -155,6 +159,10 @@ where bus.set_config(&self.config).map_err(|_| SpiDeviceError::Config)?; self.cs.set_low().map_err(SpiDeviceError::Cs)?; + let cs_drop = OnDrop::new(|| { + let _ = self.cs.set_high(); + }); + let op_res = 'ops: { for op in operations { let res = match op { @@ -182,11 +190,10 @@ where // On failure, it's important to still flush and deassert CS. let flush_res = bus.flush().await; - let cs_res = self.cs.set_high(); + drop(cs_drop); let op_res = op_res.map_err(SpiDeviceError::Spi)?; flush_res.map_err(SpiDeviceError::Spi)?; - cs_res.map_err(SpiDeviceError::Cs)?; Ok(op_res) } From b5a635371434f4b71554d841ca8bb66ce824578f Mon Sep 17 00:00:00 2001 From: vinsynth <1.5vhunt@gmail.com> Date: Mon, 3 Feb 2025 22:40:42 -0500 Subject: [PATCH 0707/1217] update examples/stm32f4/.../i2s_dma.rs --- examples/stm32f4/src/bin/i2s_dma.rs | 82 +++++++++++++++++++++++------ 1 file changed, 65 insertions(+), 17 deletions(-) diff --git a/examples/stm32f4/src/bin/i2s_dma.rs b/examples/stm32f4/src/bin/i2s_dma.rs index 68392847b..618717cc9 100644 --- a/examples/stm32f4/src/bin/i2s_dma.rs +++ b/examples/stm32f4/src/bin/i2s_dma.rs @@ -1,33 +1,81 @@ +// This example is written for an STM32F411 chip communicating with an external +// PCM5102a DAC. Remap pins, change clock speeds, etc. as necessary for your own +// hardware. +// +// NOTE: This example outputs potentially loud audio. Please run responsibly. + #![no_std] #![no_main] -use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::i2s::{Config, I2S}; +use embassy_stm32::i2s::{Config, Format, I2S}; use embassy_stm32::time::Hertz; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] async fn main(_spawner: Spawner) { - let p = embassy_stm32::init(Default::default()); - info!("Hello World!"); + let config = { + use embassy_stm32::rcc::*; - let mut dma_buffer = [0x00_u16; 128]; + let mut config = embassy_stm32::Config::default(); + config.rcc.hse = Some(Hse { + freq: Hertz::mhz(25), + mode: HseMode::Oscillator, + }); + config.rcc.pll_src = PllSource::HSE; + config.rcc.pll = Some(Pll { + prediv: PllPreDiv::DIV25, + mul: PllMul::MUL192, + divp: Some(PllPDiv::DIV2), + divq: Some(PllQDiv::DIV4), + divr: None, + }); + config.rcc.sys = Sysclk::PLL1_P; - let mut i2s = I2S::new_txonly( - p.SPI2, - p.PC3, // sd - p.PB12, // ws - p.PB10, // ck - p.PC6, // mck - p.DMA1_CH4, + config.rcc.ahb_pre = AHBPrescaler::DIV1; + config.rcc.apb1_pre = APBPrescaler::DIV2; + config.rcc.apb2_pre = APBPrescaler::DIV1; + + config.rcc.plli2s = Some(Pll { + prediv: PllPreDiv::DIV25, + mul: PllMul::MUL384, + divp: None, + divq: None, + divr: Some(PllRDiv::DIV5), + }); + config.enable_debug_during_sleep = true; + + config + }; + + let p = embassy_stm32::init(config); + + // stereo wavetable generation + let mut wavetable = [0u16; 1200]; + for (i, frame) in wavetable.chunks_mut(2).enumerate() { + frame[0] = ((((i / 150) % 2) * 2048) as i16 - 1024) as u16; // 160 Hz square wave in left channel + frame[1] = ((((i / 100) % 2) * 2048) as i16 - 1024) as u16; // 240 Hz square wave in right channel + } + + // i2s configuration + let mut dma_buffer = [0u16; 2400]; + + let mut i2s_config = Config::default(); + i2s_config.format = Format::Data16Channel32; + i2s_config.master_clock = false; + let mut i2s = I2S::new_txonly_nomck( + p.SPI3, + p.PB5, // sd + p.PA15, // ws + p.PB3, // ck + p.DMA1_CH7, &mut dma_buffer, - Hertz(1_000_000), - Config::default(), + Hertz(48_000), + i2s_config, ); + i2s.start(); - for i in 0_u16.. { - i2s.write(&mut [i * 2; 64]).await.ok(); - i2s.write(&mut [i * 2 + 1; 64]).await.ok(); + loop { + i2s.write(&wavetable).await.ok(); } } From b0e3a6481b5bacadc3d538f571d21f96b274934e Mon Sep 17 00:00:00 2001 From: vinsynth <1.5vhunt@gmail.com> Date: Mon, 3 Feb 2025 22:52:38 -0500 Subject: [PATCH 0708/1217] document clock settings in examples/stm32f4/.../i2s_dma.rs --- examples/stm32f4/src/bin/i2s_dma.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples/stm32f4/src/bin/i2s_dma.rs b/examples/stm32f4/src/bin/i2s_dma.rs index 618717cc9..db5103d0f 100644 --- a/examples/stm32f4/src/bin/i2s_dma.rs +++ b/examples/stm32f4/src/bin/i2s_dma.rs @@ -36,6 +36,8 @@ async fn main(_spawner: Spawner) { config.rcc.apb1_pre = APBPrescaler::DIV2; config.rcc.apb2_pre = APBPrescaler::DIV1; + // reference your chip's manual for proper clock settings; this config + // is recommended for a 32 bit frame at 48 kHz sample rate config.rcc.plli2s = Some(Pll { prediv: PllPreDiv::DIV25, mul: PllMul::MUL384, From b7fbf6d519fd2c07ec4b203351b15500cdc9e6dc Mon Sep 17 00:00:00 2001 From: wackazong Date: Tue, 4 Feb 2025 11:03:17 +0100 Subject: [PATCH 0709/1217] Add saturating_add and saturating_sub to Instant --- embassy-time/src/instant.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/embassy-time/src/instant.rs b/embassy-time/src/instant.rs index cae80e51f..e1417174c 100644 --- a/embassy-time/src/instant.rs +++ b/embassy-time/src/instant.rs @@ -115,6 +115,16 @@ impl Instant { pub fn checked_sub(&self, duration: Duration) -> Option { self.ticks.checked_sub(duration.ticks).map(|ticks| Instant { ticks }) } + + /// Adds a Duration to self. In case of overflow, the maximum value is returned. + pub fn saturating_add(&mut self, duration: Duration) { + self.ticks = self.ticks.saturating_add(duration.ticks); + } + + /// Subtracts a Duration from self. In case of overflow, the minimum value is returned. + pub fn saturating_sub(&mut self, duration: Duration) { + self.ticks = self.ticks.saturating_sub(duration.ticks); + } } impl Add for Instant { From 865266a4ae0a1e12174fbe0de0956e0a94f32800 Mon Sep 17 00:00:00 2001 From: wackazong Date: Tue, 4 Feb 2025 11:09:52 +0100 Subject: [PATCH 0710/1217] Take self instead of &mut self This is more idiomatic since methods with these names usually take self and not &mut self. --- embassy-time/src/instant.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/embassy-time/src/instant.rs b/embassy-time/src/instant.rs index e1417174c..7fc93c2ec 100644 --- a/embassy-time/src/instant.rs +++ b/embassy-time/src/instant.rs @@ -117,13 +117,15 @@ impl Instant { } /// Adds a Duration to self. In case of overflow, the maximum value is returned. - pub fn saturating_add(&mut self, duration: Duration) { + pub fn saturating_add(mut self, duration: Duration) -> Self { self.ticks = self.ticks.saturating_add(duration.ticks); + self } /// Subtracts a Duration from self. In case of overflow, the minimum value is returned. - pub fn saturating_sub(&mut self, duration: Duration) { + pub fn saturating_sub(mut self, duration: Duration) -> Self { self.ticks = self.ticks.saturating_sub(duration.ticks); + self } } From 0f048783010a6ca582b23cc06bcb47bd6ebf6fe8 Mon Sep 17 00:00:00 2001 From: wackazong Date: Tue, 4 Feb 2025 17:12:26 +0100 Subject: [PATCH 0711/1217] Add must_use to MutexGuard --- embassy-sync/src/mutex.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/embassy-sync/src/mutex.rs b/embassy-sync/src/mutex.rs index f25f74336..7528a9f68 100644 --- a/embassy-sync/src/mutex.rs +++ b/embassy-sync/src/mutex.rs @@ -171,6 +171,7 @@ where /// /// Dropping it unlocks the mutex. #[clippy::has_significant_drop] +#[must_use = "if unused the Mutex will immediately unlock"] pub struct MutexGuard<'a, M, T> where M: RawMutex, From 26c6ab7587124b697c821a91bbf289efc29db822 Mon Sep 17 00:00:00 2001 From: Victor LEFEBVRE Date: Wed, 5 Feb 2025 00:16:10 +0100 Subject: [PATCH 0712/1217] Update main.rs --- embassy-executor-macros/src/macros/main.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/embassy-executor-macros/src/macros/main.rs b/embassy-executor-macros/src/macros/main.rs index 14b1d9de2..a774cf622 100644 --- a/embassy-executor-macros/src/macros/main.rs +++ b/embassy-executor-macros/src/macros/main.rs @@ -161,6 +161,7 @@ pub fn run(args: TokenStream, item: TokenStream, arch: &Arch) -> TokenStream { let result = quote! { #[::embassy_executor::task()] + #[allow(clippy::future_not_send)] async fn __embassy_main(#fargs) #out { #f_body } From bb2d9ec7f81bbf0d83e873d53eb37f9d0b359f3b Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Wed, 5 Feb 2025 00:46:30 +0100 Subject: [PATCH 0713/1217] rp: Workaround "SIO spinlock stuck bug", reset PROC1 at boot. Just like RP2040. The bug was "working as intended" on rp2040, so it is on rp235x. --- embassy-rp/src/lib.rs | 41 +++++++++++++++++++++++++++++------------ 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs index f0893b5a0..8b0023ea5 100644 --- a/embassy-rp/src/lib.rs +++ b/embassy-rp/src/lib.rs @@ -598,7 +598,7 @@ pub fn init(config: config::Config) -> Peripherals { peripherals } -#[cfg(all(feature = "rt", feature = "rp2040"))] +#[cfg(feature = "rt")] #[cortex_m_rt::pre_init] unsafe fn pre_init() { // SIO does not get reset when core0 is reset with either `scb::sys_reset()` or with SWD. @@ -629,17 +629,34 @@ unsafe fn pre_init() { // // The PSM order is SIO -> PROC0 -> PROC1. // So, we have to force-on PROC0 to prevent it from getting reset when resetting SIO. - pac::PSM.frce_on().write_and_wait(|w| { - w.set_proc0(true); - }); - // Then reset SIO and PROC1. - pac::PSM.frce_off().write_and_wait(|w| { - w.set_sio(true); - w.set_proc1(true); - }); - // clear force_off first, force_on second. The other way around would reset PROC0. - pac::PSM.frce_off().write_and_wait(|_| {}); - pac::PSM.frce_on().write_and_wait(|_| {}); + #[cfg(feature = "rp2040")] + { + pac::PSM.frce_on().write_and_wait(|w| { + w.set_proc0(true); + }); + // Then reset SIO and PROC1. + pac::PSM.frce_off().write_and_wait(|w| { + w.set_sio(true); + w.set_proc1(true); + }); + // clear force_off first, force_on second. The other way around would reset PROC0. + pac::PSM.frce_off().write_and_wait(|_| {}); + pac::PSM.frce_on().write_and_wait(|_| {}); + } + + #[cfg(feature = "_rp235x")] + { + // on RP235x, datasheet says "The FRCE_ON register is a development feature that does nothing in production devices." + // No idea why they removed it. Removing it means we can't use PSM to reset SIO, because it comes before + // PROC0, so we'd need FRCE_ON to prevent resetting ourselves. + // + // So we just unlock the spinlock manually. + pac::SIO.spinlock(31).write_value(1); + + // We can still use PSM to reset PROC1 since it comes after PROC0 in the state machine. + pac::PSM.frce_off().write_and_wait(|w| w.set_proc1(true)); + pac::PSM.frce_off().write_and_wait(|_| {}); + } } /// Extension trait for PAC regs, adding atomic xor/bitset/bitclear writes. From 9da04cc38ea5cc17740bd9921f9f5cbb1c689a31 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Wed, 5 Feb 2025 00:48:35 +0100 Subject: [PATCH 0714/1217] rp: make atomics work properly between cores in rp235x. --- embassy-rp/src/lib.rs | 18 ++++++++++++++++++ embassy-rp/src/multicore.rs | 4 ++++ 2 files changed, 22 insertions(+) diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs index 8b0023ea5..80ee47802 100644 --- a/embassy-rp/src/lib.rs +++ b/embassy-rp/src/lib.rs @@ -656,9 +656,27 @@ unsafe fn pre_init() { // We can still use PSM to reset PROC1 since it comes after PROC0 in the state machine. pac::PSM.frce_off().write_and_wait(|w| w.set_proc1(true)); pac::PSM.frce_off().write_and_wait(|_| {}); + + // Make atomics work between cores. + enable_actlr_extexclall(); } } +/// Set the EXTEXCLALL bit in ACTLR. +/// +/// The default MPU memory map marks all memory as non-shareable, so atomics don't +/// synchronize memory accesses between cores at all. This bit forces all memory to be +/// considered shareable regardless of what the MPU says. +/// +/// TODO: does this interfere somehow if the user wants to use a custom MPU configuration? +/// maybe we need to add a way to disable this? +/// +/// This must be done FOR EACH CORE. +#[cfg(feature = "_rp235x")] +unsafe fn enable_actlr_extexclall() { + (&*cortex_m::peripheral::ICB::PTR).actlr.modify(|w| w | (1 << 29)); +} + /// Extension trait for PAC regs, adding atomic xor/bitset/bitclear writes. #[allow(unused)] trait RegExt { diff --git a/embassy-rp/src/multicore.rs b/embassy-rp/src/multicore.rs index ea0a29a36..1450505b9 100644 --- a/embassy-rp/src/multicore.rs +++ b/embassy-rp/src/multicore.rs @@ -65,6 +65,10 @@ unsafe fn core1_setup(stack_bottom: *mut usize) { // embassy, somehow. trap if so since we can't deal with that. cortex_m::asm::udf(); } + + #[cfg(feature = "_rp235x")] + crate::enable_actlr_extexclall(); + unsafe { gpio::init(); } From 401aa725ed04e3b40af8de6c73d4c83260f21a6c Mon Sep 17 00:00:00 2001 From: Max <48251088+MaximeB5@users.noreply.github.com> Date: Wed, 5 Feb 2025 16:04:59 +0100 Subject: [PATCH 0715/1217] Replace STM32WBA52CGUxT by STM32WBA55CGUx because the WBA55 Nucleo board officially replaces the WBA52 --- examples/stm32wba/.cargo/config.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/stm32wba/.cargo/config.toml b/examples/stm32wba/.cargo/config.toml index 477413397..c96a5cb6c 100644 --- a/examples/stm32wba/.cargo/config.toml +++ b/examples/stm32wba/.cargo/config.toml @@ -1,5 +1,5 @@ [target.'cfg(all(target_arch = "arm", target_os = "none"))'] -runner = "probe-rs run --chip STM32WBA52CGUxT" +runner = "probe-rs run --chip STM32WBA55CGUx" [build] target = "thumbv8m.main-none-eabihf" From 66c5fe0a757e679541334c82a3fa0f7701b6f44d Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 6 Feb 2025 00:02:52 +0100 Subject: [PATCH 0716/1217] examples/rp: remove unneeded sio spinlock stuck bug workarounds. This is now workarounded by embassy-rp itself. --- examples/rp/src/bin/interrupt.rs | 1 - examples/rp/src/bin/spi_sdmmc.rs | 1 - examples/rp23/src/bin/interrupt.rs | 1 - examples/rp23/src/bin/spi_sdmmc.rs | 1 - 4 files changed, 4 deletions(-) diff --git a/examples/rp/src/bin/interrupt.rs b/examples/rp/src/bin/interrupt.rs index 5b9d7027e..787cdc112 100644 --- a/examples/rp/src/bin/interrupt.rs +++ b/examples/rp/src/bin/interrupt.rs @@ -32,7 +32,6 @@ static ADC_VALUES: Channel = Channel::new(); #[embassy_executor::main] async fn main(spawner: Spawner) { - embassy_rp::pac::SIO.spinlock(31).write_value(1); let p = embassy_rp::init(Default::default()); let adc = Adc::new_blocking(p.ADC, Default::default()); diff --git a/examples/rp/src/bin/spi_sdmmc.rs b/examples/rp/src/bin/spi_sdmmc.rs index a60850d0f..4e3c2f199 100644 --- a/examples/rp/src/bin/spi_sdmmc.rs +++ b/examples/rp/src/bin/spi_sdmmc.rs @@ -32,7 +32,6 @@ impl embedded_sdmmc::TimeSource for DummyTimesource { #[embassy_executor::main] async fn main(_spawner: Spawner) { - embassy_rp::pac::SIO.spinlock(31).write_value(1); let p = embassy_rp::init(Default::default()); // SPI clock needs to be running at <= 400kHz during initialization diff --git a/examples/rp23/src/bin/interrupt.rs b/examples/rp23/src/bin/interrupt.rs index d9b662253..d563e6ebe 100644 --- a/examples/rp23/src/bin/interrupt.rs +++ b/examples/rp23/src/bin/interrupt.rs @@ -37,7 +37,6 @@ static ADC_VALUES: Channel = Channel::new(); #[embassy_executor::main] async fn main(spawner: Spawner) { - embassy_rp::pac::SIO.spinlock(31).write_value(1); let p = embassy_rp::init(Default::default()); let adc = Adc::new_blocking(p.ADC, Default::default()); diff --git a/examples/rp23/src/bin/spi_sdmmc.rs b/examples/rp23/src/bin/spi_sdmmc.rs index cfc38dfd9..9fea035bc 100644 --- a/examples/rp23/src/bin/spi_sdmmc.rs +++ b/examples/rp23/src/bin/spi_sdmmc.rs @@ -38,7 +38,6 @@ impl embedded_sdmmc::TimeSource for DummyTimesource { #[embassy_executor::main] async fn main(_spawner: Spawner) { - embassy_rp::pac::SIO.spinlock(31).write_value(1); let p = embassy_rp::init(Default::default()); // SPI clock needs to be running at <= 400kHz during initialization From 4e69e5b3c719ccd73e2dee47294c9f599525997d Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 6 Feb 2025 00:10:50 +0100 Subject: [PATCH 0717/1217] rp: add changelog for embassy-rp v0.3.1. --- embassy-rp/CHANGELOG.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/embassy-rp/CHANGELOG.md b/embassy-rp/CHANGELOG.md index 117882f38..df591fdf8 100644 --- a/embassy-rp/CHANGELOG.md +++ b/embassy-rp/CHANGELOG.md @@ -7,6 +7,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +## 0.3.1 - 2025-02-06 + +Small release fixing a few gnarly bugs, upgrading is strongly recommended. + +- Fix a race condition in the time driver that could cause missed interrupts. ([#3758](https://github.com/embassy-rs/embassy/issues/3758), [#3763](https://github.com/embassy-rs/embassy/pull/3763)) +- rp235x: Make atomics work across cores. ([#3851](https://github.com/embassy-rs/embassy/pull/3851)) +- rp235x: add workaround "SIO spinlock stuck after reset" bug, same as RP2040 ([#3851](https://github.com/embassy-rs/embassy/pull/3851)) +- rp235x: Ensure core1 is reset if core0 resets. ([#3851](https://github.com/embassy-rs/embassy/pull/3851)) +- rp235xb: correct ADC channel numbers. ([#3823](https://github.com/embassy-rs/embassy/pull/3823)) +- rp235x: enable watchdog tick generator. ([#3777](https://github.com/embassy-rs/embassy/pull/3777)) +- Relax I2C address validity check to allow using 7-bit addresses that would be reserved for 10-bit addresses. ([#3809](https://github.com/embassy-rs/embassy/issues/3809), [#3810](https://github.com/embassy-rs/embassy/pull/3810)) + ## 0.3.0 - 2025-01-05 - Updated `embassy-time` to v0.4 From 9acbfc9c226bc56d4c135a4b3845765043c3429a Mon Sep 17 00:00:00 2001 From: Steve Work Date: Thu, 6 Feb 2025 17:46:04 -0800 Subject: [PATCH 0718/1217] Add PIO functions. Add some (I think) needed functions: ConfigPins::set_sideset_pins (the other pin types are covered, why not this one?) Several runtime StateMachine manipulations: - addr() - tx_threshold() - set_tx_threshold - rx_threshold() - set_rx_threshold() - set_thresholds() - both at once, same value --- embassy-rp/src/pio/mod.rs | 55 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/embassy-rp/src/pio/mod.rs b/embassy-rp/src/pio/mod.rs index 7632d3168..51b526400 100644 --- a/embassy-rp/src/pio/mod.rs +++ b/embassy-rp/src/pio/mod.rs @@ -670,6 +670,16 @@ impl<'d, PIO: Instance> Config<'d, PIO> { self.exec.jmp_pin = pin.pin(); } + /// Sets the range of pins affected by SIDE instructions. The range must be consecutive. + /// Set pins must configured as outputs using [`StateMachine::set_pin_dirs`] to be + /// effective. + pub fn set_sideset_pins(&mut self, pins: &[&Pin<'d, PIO>]) { + assert!(pins.len() <= 5); + assert_consecutive(pins); + self.pins.sideset_base = pins.first().map_or(0, |p| p.pin()); + self.pins.sideset_count = pins.len() as u8; + } + /// Sets the range of pins affected by SET instructions. The range must be consecutive. /// Set pins must configured as outputs using [`StateMachine::set_pin_dirs`] to be /// effective. @@ -816,6 +826,51 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> { } } + /// Read current instruction address for this state machine + pub fn addr(&self) -> u8 { + let addr = Self::this_sm().addr(); + addr.read().addr() + } + + /// Read TX FIFO threshold for this state machine. + pub fn tx_threshold(&self) -> u8 { + let shiftctrl = Self::this_sm().shiftctrl(); + shiftctrl.read().pull_thresh() + } + + /// Set/change the TX FIFO threshold for this state machine. + pub fn set_tx_threshold(&mut self, threshold: u8) { + assert!(threshold <= 31); + let shiftctrl = Self::this_sm().shiftctrl(); + shiftctrl.modify(|w| { + w.set_pull_thresh(threshold); + }); + } + + /// Read TX FIFO threshold for this state machine. + pub fn rx_threshold(&self) -> u8 { + Self::this_sm().shiftctrl().read().push_thresh() + } + + /// Set/change the RX FIFO threshold for this state machine. + pub fn set_rx_threshold(&mut self, threshold: u8) { + assert!(threshold <= 31); + let shiftctrl = Self::this_sm().shiftctrl(); + shiftctrl.modify(|w| { + w.set_push_thresh(threshold); + }); + } + + /// Set/change both TX and RX FIFO thresholds for this state machine. + pub fn set_thresholds(&mut self, threshold: u8) { + assert!(threshold <= 31); + let shiftctrl = Self::this_sm().shiftctrl(); + shiftctrl.modify(|w| { + w.set_push_thresh(threshold); + w.set_pull_thresh(threshold); + }); + } + /// Set the clock divider for this state machine. pub fn set_clock_divider(&mut self, clock_divider: FixedU32) { let sm = Self::this_sm(); From dc2ce92e32469eb99ab0ef703b7d265ea7184630 Mon Sep 17 00:00:00 2001 From: Shaw Drastin <168159404+showier-drastic@users.noreply.github.com> Date: Fri, 7 Feb 2025 10:39:08 +0800 Subject: [PATCH 0719/1217] Add proper error handling if CS is not dropped --- .../src/shared_bus/asynch/spi.rs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/embassy-embedded-hal/src/shared_bus/asynch/spi.rs b/embassy-embedded-hal/src/shared_bus/asynch/spi.rs index 0ba1033f6..78709b7d3 100644 --- a/embassy-embedded-hal/src/shared_bus/asynch/spi.rs +++ b/embassy-embedded-hal/src/shared_bus/asynch/spi.rs @@ -72,6 +72,10 @@ where self.cs.set_low().map_err(SpiDeviceError::Cs)?; let cs_drop = OnDrop::new(|| { + // This drop guard deasserts CS pin if the async operation is cancelled. + // Errors are ignored in this drop handler, as there's nothing we can do about them. + // If the async operation is completed without cancellation, this handler will not + // be run, and the CS pin will be deasserted with proper error handling. let _ = self.cs.set_high(); }); @@ -102,10 +106,15 @@ where // On failure, it's important to still flush and deassert CS. let flush_res = bus.flush().await; - drop(cs_drop); + + // Now that all the async operations are done, we defuse the CS guard, + // and manually set the CS pin low (to better handle the possible errors). + cs_drop.defuse(); + let cs_res = self.cs.set_high(); let op_res = op_res.map_err(SpiDeviceError::Spi)?; flush_res.map_err(SpiDeviceError::Spi)?; + cs_res.map_err(SpiDeviceError::Cs)?; Ok(op_res) } @@ -160,6 +169,7 @@ where self.cs.set_low().map_err(SpiDeviceError::Cs)?; let cs_drop = OnDrop::new(|| { + // Please see comment in SpiDevice for an explanation of this drop handler. let _ = self.cs.set_high(); }); @@ -190,10 +200,12 @@ where // On failure, it's important to still flush and deassert CS. let flush_res = bus.flush().await; - drop(cs_drop); + cs_drop.defuse(); + let cs_res = self.cs.set_high(); let op_res = op_res.map_err(SpiDeviceError::Spi)?; flush_res.map_err(SpiDeviceError::Spi)?; + cs_res.map_err(SpiDeviceError::Cs)?; Ok(op_res) } From 3b74732f40c8fa65e3bdfc1d3ee65c59e9b01a71 Mon Sep 17 00:00:00 2001 From: Steve Work Date: Fri, 7 Feb 2025 09:26:34 -0800 Subject: [PATCH 0720/1217] Rename readers with get_, per CBJamo review. Tweak use_program docstring. The tweak arranges that "grep sideset" finds use_program() when grokking source - this spelling is used elsewhere, as in PinConfig for example, and I managed to miss use_program. --- embassy-rp/src/pio/mod.rs | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/embassy-rp/src/pio/mod.rs b/embassy-rp/src/pio/mod.rs index 51b526400..2776f9e3c 100644 --- a/embassy-rp/src/pio/mod.rs +++ b/embassy-rp/src/pio/mod.rs @@ -651,7 +651,7 @@ impl<'d, PIO: Instance> Config<'d, PIO> { /// of the program. The state machine is not started. /// /// `side_set` sets the range of pins affected by side-sets. The range must be consecutive. - /// Side-set pins must configured as outputs using [`StateMachine::set_pin_dirs`] to be + /// Sideset pins must configured as outputs using [`StateMachine::set_pin_dirs`] to be /// effective. pub fn use_program(&mut self, prog: &LoadedProgram<'d, PIO>, side_set: &[&Pin<'d, PIO>]) { assert!((prog.side_set.bits() - prog.side_set.optional() as u8) as usize == side_set.len()); @@ -670,16 +670,6 @@ impl<'d, PIO: Instance> Config<'d, PIO> { self.exec.jmp_pin = pin.pin(); } - /// Sets the range of pins affected by SIDE instructions. The range must be consecutive. - /// Set pins must configured as outputs using [`StateMachine::set_pin_dirs`] to be - /// effective. - pub fn set_sideset_pins(&mut self, pins: &[&Pin<'d, PIO>]) { - assert!(pins.len() <= 5); - assert_consecutive(pins); - self.pins.sideset_base = pins.first().map_or(0, |p| p.pin()); - self.pins.sideset_count = pins.len() as u8; - } - /// Sets the range of pins affected by SET instructions. The range must be consecutive. /// Set pins must configured as outputs using [`StateMachine::set_pin_dirs`] to be /// effective. @@ -827,13 +817,13 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> { } /// Read current instruction address for this state machine - pub fn addr(&self) -> u8 { + pub fn get_addr(&self) -> u8 { let addr = Self::this_sm().addr(); addr.read().addr() } /// Read TX FIFO threshold for this state machine. - pub fn tx_threshold(&self) -> u8 { + pub fn get_tx_threshold(&self) -> u8 { let shiftctrl = Self::this_sm().shiftctrl(); shiftctrl.read().pull_thresh() } @@ -848,7 +838,7 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> { } /// Read TX FIFO threshold for this state machine. - pub fn rx_threshold(&self) -> u8 { + pub fn get_rx_threshold(&self) -> u8 { Self::this_sm().shiftctrl().read().push_thresh() } From 38799c63fd493a8e3696915a5b4aadb6094a4e64 Mon Sep 17 00:00:00 2001 From: elagil Date: Fri, 7 Feb 2025 23:31:02 +0100 Subject: [PATCH 0721/1217] fix: UCPD drop logic Read rxpaysz immediately --- embassy-stm32/src/ucpd.rs | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/embassy-stm32/src/ucpd.rs b/embassy-stm32/src/ucpd.rs index 133a1c827..c40ee8ad0 100644 --- a/embassy-stm32/src/ucpd.rs +++ b/embassy-stm32/src/ucpd.rs @@ -266,7 +266,7 @@ impl<'d, T: Instance> Drop for CcPhy<'d, T> { // Check if the PdPhy part was dropped already. let drop_not_ready = &T::state().drop_not_ready; if drop_not_ready.load(Ordering::Relaxed) { - drop_not_ready.store(true, Ordering::Relaxed); + drop_not_ready.store(false, Ordering::Relaxed); } else { r.cfgr1().write(|w| w.set_ucpden(false)); rcc::disable::(); @@ -411,13 +411,14 @@ pub struct PdPhy<'d, T: Instance> { impl<'d, T: Instance> Drop for PdPhy<'d, T> { fn drop(&mut self) { - T::REGS.cr().modify(|w| w.set_phyrxen(false)); - // Check if the Type-C part was dropped already. + let r = T::REGS; + r.cr().modify(|w| w.set_phyrxen(false)); + // Check if the CcPhy part was dropped already. let drop_not_ready = &T::state().drop_not_ready; if drop_not_ready.load(Ordering::Relaxed) { - drop_not_ready.store(true, Ordering::Relaxed); + drop_not_ready.store(false, Ordering::Relaxed); } else { - T::REGS.cfgr1().write(|w| w.set_ucpden(false)); + r.cfgr1().write(|w| w.set_ucpden(false)); rcc::disable::(); T::Interrupt::disable(); } @@ -453,6 +454,8 @@ impl<'d, T: Instance> PdPhy<'d, T> { }); }); + let mut rxpaysz = 0; + // Stop DMA reception immediately after receiving a packet, to prevent storing multiple packets in the same buffer. poll_fn(|cx| { let sr = r.sr().read(); @@ -466,6 +469,8 @@ impl<'d, T: Instance> PdPhy<'d, T> { Poll::Ready(Err(RxError::HardReset)) } else if sr.rxmsgend() { dma.request_stop(); + // Should be read immediately on interrupt. + rxpaysz = r.rx_payszr().read().rxpaysz().into(); let ret = if sr.rxovr() { Err(RxError::Overrun) @@ -501,7 +506,7 @@ impl<'d, T: Instance> PdPhy<'d, T> { _ => unreachable!(), }; - Ok((sop, r.rx_payszr().read().rxpaysz().into())) + Ok((sop, rxpaysz)) } fn enable_rx_interrupt(enable: bool) { From bb6e6fe30bb61df4765a128c6e776bec15ae0675 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Sat, 8 Feb 2025 19:06:37 +0100 Subject: [PATCH 0722/1217] Document std/wasm in embassy-time --- embassy-time/Cargo.toml | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/embassy-time/Cargo.toml b/embassy-time/Cargo.toml index a25673ef5..7aaae89f9 100644 --- a/embassy-time/Cargo.toml +++ b/embassy-time/Cargo.toml @@ -24,9 +24,6 @@ target = "x86_64-unknown-linux-gnu" features = ["defmt", "std"] [features] -std = ["tick-hz-1_000_000", "critical-section/std", "dep:embassy-time-queue-utils"] -wasm = ["dep:wasm-bindgen", "dep:js-sys", "dep:wasm-timer", "tick-hz-1_000_000", "dep:embassy-time-queue-utils"] - ## Display the time since startup next to defmt log messages. ## At most 1 `defmt-timestamp-uptime-*` feature can be used. ## `defmt-timestamp-uptime` is provided for backwards compatibility (provides the same format as `uptime-us`). @@ -39,8 +36,18 @@ defmt-timestamp-uptime-ts = ["defmt"] defmt-timestamp-uptime-tms = ["defmt"] defmt-timestamp-uptime-tus = ["defmt"] +#! ### Time Drivers + +#! Usually, time drivers are defined by a HAL, or a companion crate to the HAL. For `std` and WASM +#! environments, as well as for testing purposes, `embassy-time` provides some default time drivers +#! that may be suitable for your use case. You can enable one of the following features to use them. + ## Create a `MockDriver` that can be manually advanced for testing purposes. mock-driver = ["tick-hz-1_000_000", "dep:embassy-time-queue-utils"] +## Create a time driver for `std` environments. +std = ["tick-hz-1_000_000", "critical-section/std", "dep:embassy-time-queue-utils"] +## Create a time driver for WASM. +wasm = ["dep:wasm-bindgen", "dep:js-sys", "dep:wasm-timer", "tick-hz-1_000_000", "dep:embassy-time-queue-utils"] #! ### Generic Queue From b9508bf2cb817afb9aeb7057a5c015f23a3b0d12 Mon Sep 17 00:00:00 2001 From: Flamenco Date: Sat, 8 Feb 2025 14:28:36 -0500 Subject: [PATCH 0723/1217] Update documentation Update comment to specify the correct rp chip identifier --- examples/rp23/src/bin/flash.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/rp23/src/bin/flash.rs b/examples/rp23/src/bin/flash.rs index 28dec24c9..42c226f5b 100644 --- a/examples/rp23/src/bin/flash.rs +++ b/examples/rp23/src/bin/flash.rs @@ -1,4 +1,4 @@ -//! This example test the flash connected to the RP2040 chip. +//! This example test the flash connected to the RP2350 chip. #![no_std] #![no_main] From e5d0d408296efaf4e628d608f26d8d1213c2d934 Mon Sep 17 00:00:00 2001 From: Max <48251088+MaximeB5@users.noreply.github.com> Date: Mon, 10 Feb 2025 08:14:15 +0100 Subject: [PATCH 0724/1217] Update Cargo.toml : replace STM32WBA52CGU by STM32WBA55CG Following PR https://github.com/embassy-rs/embassy/pull/3852 , I forgot to update the dependency. The WBA55 Nucleo board officially replaces the WBA52. Even if WBA52 SoC is still part of the ST CubeFW, the SW connectivity projects for WBA52 are no longer delivered. WBA55 Nucleo board is now the reference entry board. --- examples/stm32wba/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/stm32wba/Cargo.toml b/examples/stm32wba/Cargo.toml index 59a41da88..dd1ce21d9 100644 --- a/examples/stm32wba/Cargo.toml +++ b/examples/stm32wba/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [ "defmt", "stm32wba52cg", "time-driver-any", "memory-x", "exti"] } +embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [ "defmt", "stm32wba55cg", "time-driver-any", "memory-x", "exti"] } embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } From 74c42fd9d0522fdd5150b630ea8b7d493964cf31 Mon Sep 17 00:00:00 2001 From: Owen Brooks Date: Tue, 11 Feb 2025 19:58:34 +1100 Subject: [PATCH 0725/1217] Fix typos in docs --- docs/pages/best_practices.adoc | 2 +- docs/pages/layer_by_layer.adoc | 2 +- docs/pages/overview.adoc | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/pages/best_practices.adoc b/docs/pages/best_practices.adoc index bfcedec06..eabaa9eb9 100644 --- a/docs/pages/best_practices.adoc +++ b/docs/pages/best_practices.adoc @@ -35,7 +35,7 @@ After the processing, another 1024 byte buffer will be placed on the stack to be Pass the data by reference and not by value on both, the way in and the way out. For example, you could return a slice of the input buffer as the output. -Requiring the lifetime of the input slice and the output slice to be the same, the memory safetly of this procedure will be enforced by the compiler. +Requiring the lifetime of the input slice and the output slice to be the same, the memory safety of this procedure will be enforced by the compiler. [,rust] ---- diff --git a/docs/pages/layer_by_layer.adoc b/docs/pages/layer_by_layer.adoc index 7852d27b7..7dba11b5e 100644 --- a/docs/pages/layer_by_layer.adoc +++ b/docs/pages/layer_by_layer.adoc @@ -76,7 +76,7 @@ The async version looks very similar to the HAL version, apart from a few minor * The peripheral initialization is done by the main macro, and is handed to the main task. * Before checking the button state, the application is awaiting a transition in the pin state (low -> high or high -> low). -When `button.await_for_any_edge().await` is called, the executor will pause the main task and put the microcontroller in sleep mode, unless there are other tasks that can run. Internally, the Embassy HAL has configured the interrupt handler for the button (in `ExtiInput`), so that whenever an interrupt is raised, the task awaiting the button will be woken up. +When `button.wait_for_any_edge().await` is called, the executor will pause the main task and put the microcontroller in sleep mode, unless there are other tasks that can run. Internally, the Embassy HAL has configured the interrupt handler for the button (in `ExtiInput`), so that whenever an interrupt is raised, the task awaiting the button will be woken up. The minimal overhead of the executor and the ability to run multiple tasks "concurrently" combined with the enormous simplification of the application, makes `async` a great fit for embedded. diff --git a/docs/pages/overview.adoc b/docs/pages/overview.adoc index 6ac0e0b2b..a1bf180cd 100644 --- a/docs/pages/overview.adoc +++ b/docs/pages/overview.adoc @@ -74,7 +74,7 @@ include::embassy_in_the_wild.adoc[leveloffset = 2] For more reading material on async Rust and Embassy: -* link:https://tweedegolf.nl/en/blog/65/async-rust-vs-rtos-showdown[Comparsion of FreeRTOS and Embassy] +* link:https://tweedegolf.nl/en/blog/65/async-rust-vs-rtos-showdown[Comparison of FreeRTOS and Embassy] * link:https://dev.to/apollolabsbin/series/20707[Tutorials] * link:https://blog.drogue.io/firmware-updates-part-1/[Firmware Updates with Embassy] From 4b809af90538b83de42d60eb6ac5b8509feaeecf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Kr=C3=B3lczyk?= Date: Mon, 10 Feb 2025 16:14:51 +0100 Subject: [PATCH 0726/1217] fix: #3760 - typo in docs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Krzysztof Królczyk --- docs/pages/layer_by_layer.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/pages/layer_by_layer.adoc b/docs/pages/layer_by_layer.adoc index 7852d27b7..7dba11b5e 100644 --- a/docs/pages/layer_by_layer.adoc +++ b/docs/pages/layer_by_layer.adoc @@ -76,7 +76,7 @@ The async version looks very similar to the HAL version, apart from a few minor * The peripheral initialization is done by the main macro, and is handed to the main task. * Before checking the button state, the application is awaiting a transition in the pin state (low -> high or high -> low). -When `button.await_for_any_edge().await` is called, the executor will pause the main task and put the microcontroller in sleep mode, unless there are other tasks that can run. Internally, the Embassy HAL has configured the interrupt handler for the button (in `ExtiInput`), so that whenever an interrupt is raised, the task awaiting the button will be woken up. +When `button.wait_for_any_edge().await` is called, the executor will pause the main task and put the microcontroller in sleep mode, unless there are other tasks that can run. Internally, the Embassy HAL has configured the interrupt handler for the button (in `ExtiInput`), so that whenever an interrupt is raised, the task awaiting the button will be woken up. The minimal overhead of the executor and the ability to run multiple tasks "concurrently" combined with the enormous simplification of the application, makes `async` a great fit for embedded. From e173db1151585702912b572c5195bd23fb4267fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Kr=C3=B3lczyk?= Date: Mon, 10 Feb 2025 17:32:16 +0100 Subject: [PATCH 0727/1217] doc: add docu strings for dfu MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Krzysztof Królczyk --- embassy-usb-dfu/src/consts.rs | 46 ++++++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/embassy-usb-dfu/src/consts.rs b/embassy-usb-dfu/src/consts.rs index 190b5ad5a..8701dabc4 100644 --- a/embassy-usb-dfu/src/consts.rs +++ b/embassy-usb-dfu/src/consts.rs @@ -1,10 +1,16 @@ -//! USB DFU constants. +//! USB DFU constants, taken from +//! https://www.usb.org/sites/default/files/DFU_1.1.pdf +/// Device Firmware Upgrade class, App specific pub(crate) const USB_CLASS_APPN_SPEC: u8 = 0xFE; +/// Device Firmware Upgrade subclass, App specific pub(crate) const APPN_SPEC_SUBCLASS_DFU: u8 = 0x01; #[allow(unused)] +/// USB interface alternative setting pub(crate) const DFU_PROTOCOL_DFU: u8 = 0x02; #[allow(unused)] +/// DFU runtime class pub(crate) const DFU_PROTOCOL_RT: u8 = 0x01; +/// DFU functional descriptor pub(crate) const DESC_DFU_FUNCTIONAL: u8 = 0x21; macro_rules! define_dfu_attributes { @@ -34,51 +40,89 @@ define_dfu_attributes!(bitflags::bitflags); #[derive(Copy, Clone, PartialEq, Eq)] #[repr(u8)] #[allow(unused)] +/// An indication of the state that the device is going to enter immediately following transmission of this response. pub(crate) enum State { + /// Device is running its normal application. AppIdle = 0, + /// Device is running its normal application, has received the DFU_DETACH request, and is waiting for a USB reset. AppDetach = 1, + /// Device is operating in the DFU mode and is waiting for requests. DfuIdle = 2, + /// Device has received a block and is waiting for the host to solicit the status via DFU_GETSTATUS. DlSync = 3, + /// Device is programming a control-write block into its nonvolatile memories. DlBusy = 4, + /// Device is processing a download operation. Expecting DFU_DNLOAD requests. Download = 5, + /// Device has received the final block of firmware from the host, waits for DFU_GETSTATUS to start Manifestation phase or completed this phase ManifestSync = 6, + /// Device is in the Manifestation phase. Not all devices will be able to respond to DFU_GETSTATUS when in this state. Manifest = 7, + /// Device has programmed its memories and is waiting for a USB reset or a power on reset. ManifestWaitReset = 8, + /// The device is processing an upload operation. Expecting DFU_UPLOAD requests. UploadIdle = 9, + /// An error has occurred. Awaiting the DFU_CLRSTATUS request. Error = 10, } #[derive(Copy, Clone, PartialEq, Eq)] #[repr(u8)] #[allow(unused)] +/// An indication of the status resulting from the execution of the most recent request. pub(crate) enum Status { + /// No error Ok = 0x00, + /// File is not targeted for use by this device ErrTarget = 0x01, + /// File is for this device but fails some vendor-specific verification test ErrFile = 0x02, + /// Device is unable to write memory ErrWrite = 0x03, + /// Memory erase function failed ErrErase = 0x04, + /// Memory erase check failed ErrCheckErased = 0x05, + /// Program memory function failed ErrProg = 0x06, + /// Programmed memory failed verification ErrVerify = 0x07, + /// Cannot program memory due to received address that is out of range ErrAddress = 0x08, + /// Received DFU_DNLOAD with wLength = 0, but device does not think it has all of the data yet ErrNotDone = 0x09, + /// Device’s firmware is corrupt. It cannot return to run-time (non-DFU) operations ErrFirmware = 0x0A, + /// iString indicates a vendor-specific error ErrVendor = 0x0B, + /// Device detected unexpected USB reset signaling ErrUsbr = 0x0C, + /// Device detected unexpected power on reset ErrPor = 0x0D, + /// Something went wrong, but the device does not know what ErrUnknown = 0x0E, + /// Device stalled an unexpected request ErrStalledPkt = 0x0F, } #[derive(Copy, Clone, PartialEq, Eq)] #[repr(u8)] +/// DFU requests pub(crate) enum Request { + /// Host instructs the device to generate a detach-attach sequence Detach = 0, + /// Host initiates control-write transfers with this request, and sends a DFU_DNLOAD request + /// with wLength = 0 to indicate that it has completed transferring the firmware image file Dnload = 1, + /// The DFU_UPLOAD request is employed by the host to solicit firmware from the device. Upload = 2, + /// The host employs the DFU_GETSTATUS request to facilitate synchronization with the device. GetStatus = 3, + /// Any time the device detects an error, it waits with transition until ClrStatus ClrStatus = 4, + /// Requests a report about a state of the device GetState = 5, + /// Enables the host to exit from certain states and return to the DFU_IDLE state Abort = 6, } From 01b7ff8ff04af62cc04331a229f5305d320907fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Kr=C3=B3lczyk?= Date: Mon, 10 Feb 2025 17:38:39 +0100 Subject: [PATCH 0728/1217] fix: layer-by-layer examples MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit closes: #3794 #3793 Remove 'blinky-irq' from workspace. During linking from workspace level - embassy-stm32 and example code redefine EXTI15_10 symbol Building it separately, outside of workspace works Signed-off-by: Krzysztof Królczyk --- docs/examples/layer-by-layer/Cargo.toml | 1 - docs/examples/layer-by-layer/blinky-async/Cargo.toml | 2 +- docs/examples/layer-by-layer/blinky-hal/Cargo.toml | 2 +- docs/examples/layer-by-layer/blinky-irq/Cargo.toml | 4 +++- docs/examples/layer-by-layer/blinky-pac/Cargo.toml | 2 +- docs/examples/layer-by-layer/memory.x | 5 +++++ 6 files changed, 11 insertions(+), 5 deletions(-) create mode 100644 docs/examples/layer-by-layer/memory.x diff --git a/docs/examples/layer-by-layer/Cargo.toml b/docs/examples/layer-by-layer/Cargo.toml index f18c9e7e4..01666ec6e 100644 --- a/docs/examples/layer-by-layer/Cargo.toml +++ b/docs/examples/layer-by-layer/Cargo.toml @@ -3,7 +3,6 @@ resolver = "2" members = [ "blinky-pac", "blinky-hal", - "blinky-irq", "blinky-async", ] diff --git a/docs/examples/layer-by-layer/blinky-async/Cargo.toml b/docs/examples/layer-by-layer/blinky-async/Cargo.toml index 51ddf87d4..541eb6edf 100644 --- a/docs/examples/layer-by-layer/blinky-async/Cargo.toml +++ b/docs/examples/layer-by-layer/blinky-async/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" license = "MIT OR Apache-2.0" [dependencies] -cortex-m = "0.7" +cortex-m = { version = "0.7", features = ["critical-section-single-core"] } cortex-m-rt = "0.7" embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32l475vg", "memory-x", "exti"] } embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread"] } diff --git a/docs/examples/layer-by-layer/blinky-hal/Cargo.toml b/docs/examples/layer-by-layer/blinky-hal/Cargo.toml index 1e292e6b4..dd574c3e7 100644 --- a/docs/examples/layer-by-layer/blinky-hal/Cargo.toml +++ b/docs/examples/layer-by-layer/blinky-hal/Cargo.toml @@ -5,8 +5,8 @@ edition = "2021" license = "MIT OR Apache-2.0" [dependencies] -cortex-m = "0.7" cortex-m-rt = "0.7" +cortex-m = { version = "0.7", features = ["critical-section-single-core"] } embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32l475vg", "memory-x"] } defmt = "0.3" diff --git a/docs/examples/layer-by-layer/blinky-irq/Cargo.toml b/docs/examples/layer-by-layer/blinky-irq/Cargo.toml index 04ffc23ba..8733ee894 100644 --- a/docs/examples/layer-by-layer/blinky-irq/Cargo.toml +++ b/docs/examples/layer-by-layer/blinky-irq/Cargo.toml @@ -1,3 +1,5 @@ +[workspace] + [package] name = "blinky-irq" version = "0.1.0" @@ -5,7 +7,7 @@ edition = "2021" license = "MIT OR Apache-2.0" [dependencies] -cortex-m = "0.7" +cortex-m = { version = "0.7", features = ["critical-section-single-core"] } cortex-m-rt = { version = "0.7" } embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32l475vg", "memory-x", "unstable-pac"] } diff --git a/docs/examples/layer-by-layer/blinky-pac/Cargo.toml b/docs/examples/layer-by-layer/blinky-pac/Cargo.toml index cf2d7fede..155c41ec6 100644 --- a/docs/examples/layer-by-layer/blinky-pac/Cargo.toml +++ b/docs/examples/layer-by-layer/blinky-pac/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" license = "MIT OR Apache-2.0" [dependencies] -cortex-m = "0.7" +cortex-m = { version = "0.7", features = ["critical-section-single-core"] } cortex-m-rt = "0.7" stm32-metapac = { version = "16", features = ["stm32l475vg"] } diff --git a/docs/examples/layer-by-layer/memory.x b/docs/examples/layer-by-layer/memory.x new file mode 100644 index 000000000..69f5b28a1 --- /dev/null +++ b/docs/examples/layer-by-layer/memory.x @@ -0,0 +1,5 @@ +MEMORY +{ + FLASH : ORIGIN = 0x08000000, LENGTH = 2048K /* BANK_1 */ + RAM : ORIGIN = 0x20000000, LENGTH = 640K /* SRAM */ +} From 787606b991e744aa79d6d899dd556a90e4bf9853 Mon Sep 17 00:00:00 2001 From: Sebastian Scholz Date: Wed, 12 Feb 2025 13:22:43 +0100 Subject: [PATCH 0729/1217] Expose the watchdog reset reason --- embassy-rp/src/watchdog.rs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/embassy-rp/src/watchdog.rs b/embassy-rp/src/watchdog.rs index edd48e0e0..553936602 100644 --- a/embassy-rp/src/watchdog.rs +++ b/embassy-rp/src/watchdog.rs @@ -13,6 +13,15 @@ use embassy_time::Duration; use crate::pac; use crate::peripherals::WATCHDOG; +/// The reason for a system reset from the watchdog. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum ResetReason { + /// The reset was forced. + Forced, + /// The watchdog was not fed in time. + TimedOut, +} + /// Watchdog peripheral pub struct Watchdog { phantom: PhantomData, @@ -140,4 +149,17 @@ impl Watchdog { _ => panic!("Invalid watchdog scratch index"), } } + + /// Get the reason for the last system reset, if it was caused by the watchdog. + pub fn reset_reason(&self) -> Option { + let watchdog = pac::WATCHDOG; + let reason = watchdog.reason().read(); + if reason.force() { + Some(ResetReason::Forced) + } else if reason.timer() { + Some(ResetReason::TimedOut) + } else { + None + } + } } From 1c1aea62d00fcf920c8c756eb9a8518c1d9338cd Mon Sep 17 00:00:00 2001 From: Shaw Drastin <168159404+showier-drastic@users.noreply.github.com> Date: Wed, 12 Feb 2025 20:54:07 +0800 Subject: [PATCH 0730/1217] stm32: i2c-v2: Add error handling Currently when error occurres, we have to wait for timeout, which is less than ideal. Enable related interrupts, and return Err when error occurres. --- embassy-stm32/src/i2c/v2.rs | 67 +++++++++++++++++++++++++++++++++---- 1 file changed, 60 insertions(+), 7 deletions(-) diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs index 05ac9afcc..e2eb6f367 100644 --- a/embassy-stm32/src/i2c/v2.rs +++ b/embassy-stm32/src/i2c/v2.rs @@ -13,13 +13,17 @@ pub(crate) unsafe fn on_interrupt() { let regs = T::info().regs; let isr = regs.isr().read(); - if isr.tcr() || isr.tc() { + if isr.tcr() || isr.tc() || isr.nackf() || isr.berr() || isr.arlo() || isr.ovr() { T::state().waker.wake(); } - // The flag can only be cleared by writting to nbytes, we won't do that here, so disable - // the interrupt critical_section::with(|_| { - regs.cr1().modify(|w| w.set_tcie(false)); + regs.cr1().modify(|w| { + // The flag can only be cleared by writting to nbytes, we won't do that here + w.set_tcie(false); + // Error flags are to be read in the routines, so we also don't clear them here + w.set_nackie(false); + w.set_errie(false); + }); }); } @@ -449,6 +453,8 @@ impl<'d> I2c<'d, Async> { if first_slice { w.set_tcie(true); } + w.set_nackie(true); + w.set_errie(true); }); let dst = regs.txdr().as_ptr() as *mut u8; @@ -459,18 +465,41 @@ impl<'d> I2c<'d, Async> { let on_drop = OnDrop::new(|| { let regs = self.info.regs; + let isr = regs.isr().read(); regs.cr1().modify(|w| { - if last_slice { + if last_slice || isr.nackf() || isr.arlo() || isr.berr() || isr.ovr() { w.set_txdmaen(false); } w.set_tcie(false); - }) + w.set_nackie(false); + w.set_errie(false); + }); + regs.icr().write(|w| { + w.set_nackcf(true); + w.set_berrcf(true); + w.set_arlocf(true); + w.set_ovrcf(true); + }); }); poll_fn(|cx| { self.state.waker.register(cx.waker()); let isr = self.info.regs.isr().read(); + + if isr.nackf() { + return Poll::Ready(Err(Error::Nack)); + } + if isr.arlo() { + return Poll::Ready(Err(Error::Arbitration)); + } + if isr.berr() { + return Poll::Ready(Err(Error::Bus)); + } + if isr.ovr() { + return Poll::Ready(Err(Error::Overrun)); + } + if remaining_len == total_len { if first_slice { Self::master_write( @@ -531,6 +560,8 @@ impl<'d> I2c<'d, Async> { regs.cr1().modify(|w| { w.set_rxdmaen(true); w.set_tcie(true); + w.set_nackie(true); + w.set_errie(true); }); let src = regs.rxdr().as_ptr() as *mut u8; @@ -544,13 +575,35 @@ impl<'d> I2c<'d, Async> { regs.cr1().modify(|w| { w.set_rxdmaen(false); w.set_tcie(false); - }) + w.set_nackie(false); + w.set_errie(false); + }); + regs.icr().write(|w| { + w.set_nackcf(true); + w.set_berrcf(true); + w.set_arlocf(true); + w.set_ovrcf(true); + }); }); poll_fn(|cx| { self.state.waker.register(cx.waker()); let isr = self.info.regs.isr().read(); + + if isr.nackf() { + return Poll::Ready(Err(Error::Nack)); + } + if isr.arlo() { + return Poll::Ready(Err(Error::Arbitration)); + } + if isr.berr() { + return Poll::Ready(Err(Error::Bus)); + } + if isr.ovr() { + return Poll::Ready(Err(Error::Overrun)); + } + if remaining_len == total_len { Self::master_read( self.info, From f54ba5a48e8783c673488c9107a3549ec35bd45e Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Thu, 13 Feb 2025 09:06:54 +0100 Subject: [PATCH 0731/1217] docs: fix esp wording and mention trouble Fixes #3831 --- README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 8952b0358..374133c4b 100644 --- a/README.md +++ b/README.md @@ -13,11 +13,10 @@ Rust's async/await allows - **Hardware Abstraction Layers** - HALs implement safe, idiomatic Rust APIs to use the hardware capabilities, so raw register manipulation is not needed. The Embassy project maintains HALs for select hardware, but you can still use HALs from other projects with Embassy. - embassy-stm32, for all STM32 microcontroller families. - - embassy-nrf, for the Nordic Semiconductor nRF52, nRF53, nRF91 series. - - embassy-rp, for the Raspberry Pi RP2040 microcontroller. + - embassy-nrf, for the Nordic Semiconductor nRF52, nRF53, nRF54 and nRF91 series. + - embassy-rp, for the Raspberry Pi RP2040 and RP23xx microcontrollers. - esp-rs, for the Espressif Systems ESP32 series of chips. - - Embassy HAL support for Espressif chips is being developed in the [esp-rs/esp-hal](https://github.com/esp-rs/esp-hal) repository. - - Async WiFi, Bluetooth and ESP-NOW is being developed in the [esp-rs/esp-wifi](https://github.com/esp-rs/esp-wifi) repository. + - Embassy HAL support for Espressif chips, as well as Async WiFi, Bluetooth and ESP-NOW, is being developed in the [esp-rs/esp-hal](https://github.com/esp-rs/esp-hal) repository. - ch32-hal, for the WCH 32-bit RISC-V(CH32V) series of chips. - **Time that Just Works** - @@ -32,9 +31,10 @@ Easily build devices with years of battery life. The async executor automaticall - **Networking** - The embassy-net network stack implements extensive networking functionality, including Ethernet, IP, TCP, UDP, ICMP and DHCP. Async drastically simplifies managing timeouts and serving multiple connections concurrently. -- **Bluetooth** - -The nrf-softdevice crate provides Bluetooth Low Energy 4.x and 5.x support for nRF52 microcontrollers. -The embassy-stm32-wpan crate provides Bluetooth Low Energy 5.x support for stm32wb microcontrollers. +- **Bluetooth** + - The trouble crate provides a Bluetooth Low Energy 4.x and 5.x Host that runs on any microcontroller implementing the bt-hci traits (currently `nRF52`, `rp2040`, `rp23xx` and `esp32` and `serial` controllers are supported). + - The nrf-softdevice crate provides Bluetooth Low Energy 4.x and 5.x support for nRF52 microcontrollers. + - The embassy-stm32-wpan crate provides Bluetooth Low Energy 5.x support for stm32wb microcontrollers. - **LoRa** - The lora-rs project provides an async LoRa and LoRaWAN stack that works well on Embassy. From 74c1fd64d218c3ac5d1ab7a2c1155a87e4169150 Mon Sep 17 00:00:00 2001 From: skkeye Date: Sun, 9 Feb 2025 01:06:04 -0500 Subject: [PATCH 0732/1217] embassy-net: add ICMP sockets and a ping utility --- embassy-net/Cargo.toml | 2 + embassy-net/src/icmp.rs | 704 ++++++++++++++++++++++++++++++++++++++++ embassy-net/src/lib.rs | 2 + 3 files changed, 708 insertions(+) create mode 100644 embassy-net/src/icmp.rs diff --git a/embassy-net/Cargo.toml b/embassy-net/Cargo.toml index a0827d96b..eda372cb6 100644 --- a/embassy-net/Cargo.toml +++ b/embassy-net/Cargo.toml @@ -33,6 +33,8 @@ packet-trace = [] #! the [smoltcp feature flag documentation](https://github.com/smoltcp-rs/smoltcp#feature-flags) #! for more details +## Enable ICMP support +icmp = ["smoltcp/socket-icmp"] ## Enable UDP support udp = ["smoltcp/socket-udp"] ## Enable Raw support diff --git a/embassy-net/src/icmp.rs b/embassy-net/src/icmp.rs new file mode 100644 index 000000000..4cce5db50 --- /dev/null +++ b/embassy-net/src/icmp.rs @@ -0,0 +1,704 @@ +//! ICMP sockets. + +use core::future::poll_fn; +use core::mem; +use core::task::Poll; + +use smoltcp::iface::{Interface, SocketHandle}; +pub use smoltcp::phy::ChecksumCapabilities; +use smoltcp::socket::icmp; +pub use smoltcp::socket::icmp::{Endpoint as IcmpEndpoint, PacketMetadata}; +use smoltcp::wire::IpAddress; +#[cfg(feature = "proto-ipv4")] +pub use smoltcp::wire::{Icmpv4Message, Icmpv4Packet, Icmpv4Repr}; +#[cfg(feature = "proto-ipv6")] +pub use smoltcp::wire::{Icmpv6Message, Icmpv6Packet, Icmpv6Repr}; + +use crate::Stack; + +/// Error returned by [`IcmpSocket::bind`]. +#[derive(PartialEq, Eq, Clone, Copy, Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum BindError { + /// The socket was already open. + InvalidState, + /// The endpoint isn't specified + InvalidEndpoint, + /// No route to host. + NoRoute, +} + +/// Error returned by [`IcmpSocket::send_to`]. +#[derive(PartialEq, Eq, Clone, Copy, Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum SendError { + /// No route to host. + NoRoute, + /// Socket not bound to an outgoing port. + SocketNotBound, +} + +/// Error returned by [`IcmpSocket::recv_from`]. +#[derive(PartialEq, Eq, Clone, Copy, Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum RecvError { + /// Provided buffer was smaller than the received packet. + Truncated, +} + +/// An ICMP socket. +pub struct IcmpSocket<'a> { + stack: Stack<'a>, + handle: SocketHandle, +} + +impl<'a> IcmpSocket<'a> { + /// Create a new ICMP socket using the provided stack and buffers. + pub fn new( + stack: Stack<'a>, + rx_meta: &'a mut [PacketMetadata], + rx_buffer: &'a mut [u8], + tx_meta: &'a mut [PacketMetadata], + tx_buffer: &'a mut [u8], + ) -> Self { + let handle = stack.with_mut(|i| { + let rx_meta: &'static mut [PacketMetadata] = unsafe { mem::transmute(rx_meta) }; + let rx_buffer: &'static mut [u8] = unsafe { mem::transmute(rx_buffer) }; + let tx_meta: &'static mut [PacketMetadata] = unsafe { mem::transmute(tx_meta) }; + let tx_buffer: &'static mut [u8] = unsafe { mem::transmute(tx_buffer) }; + i.sockets.add(icmp::Socket::new( + icmp::PacketBuffer::new(rx_meta, rx_buffer), + icmp::PacketBuffer::new(tx_meta, tx_buffer), + )) + }); + + Self { stack, handle } + } + + /// Bind the socket to the given endpoint. + pub fn bind(&mut self, endpoint: T) -> Result<(), BindError> + where + T: Into, + { + let endpoint = endpoint.into(); + + if !endpoint.is_specified() { + return Err(BindError::InvalidEndpoint); + } + + match self.with_mut(|s, _| s.bind(endpoint)) { + Ok(()) => Ok(()), + Err(icmp::BindError::InvalidState) => Err(BindError::InvalidState), + Err(icmp::BindError::Unaddressable) => Err(BindError::NoRoute), + } + } + + fn with(&self, f: impl FnOnce(&icmp::Socket, &Interface) -> R) -> R { + self.stack.with(|i| { + let socket = i.sockets.get::(self.handle); + f(socket, &i.iface) + }) + } + + fn with_mut(&self, f: impl FnOnce(&mut icmp::Socket, &mut Interface) -> R) -> R { + self.stack.with_mut(|i| { + let socket = i.sockets.get_mut::(self.handle); + let res = f(socket, &mut i.iface); + i.waker.wake(); + res + }) + } + + /// Dequeue a packet received from a remote endpoint, copy the payload into the given slice, + /// and return the amount of octets copied as well as the `IpAddress` + /// + /// **Note**: when the size of the provided buffer is smaller than the size of the payload, + /// the packet is dropped and a `RecvError::Truncated` error is returned. + pub async fn recv_from(&self, buf: &mut [u8]) -> Result<(usize, IpAddress), RecvError> { + poll_fn(move |cx| { + self.with_mut(|s, _| match s.recv_slice(buf) { + Ok(x) => Poll::Ready(Ok(x)), + // No data ready + Err(icmp::RecvError::Exhausted) => { + //s.register_recv_waker(cx.waker()); + cx.waker().wake_by_ref(); + Poll::Pending + } + Err(icmp::RecvError::Truncated) => Poll::Ready(Err(RecvError::Truncated)), + }) + }) + .await + } + + /// Dequeue a packet received from a remote endpoint and calls the provided function with the + /// slice of the packet and the remote endpoint address and returns `Poll::Ready` with the + /// function's returned value. + /// + /// **Note**: when the size of the provided buffer is smaller than the size of the payload, + /// the packet is dropped and a `RecvError::Truncated` error is returned. + pub async fn recv_with(&self, f: F) -> Result + where + F: FnOnce((&[u8], IpAddress)) -> R, + { + let mut f = Some(f); + poll_fn(move |cx| { + self.with_mut(|s, _| match s.recv() { + Ok(x) => Poll::Ready(Ok(unwrap!(f.take())(x))), + Err(icmp::RecvError::Exhausted) => { + cx.waker().wake_by_ref(); + Poll::Pending + } + Err(icmp::RecvError::Truncated) => Poll::Ready(Err(RecvError::Truncated)), + }) + }) + .await + } + + /// Enqueue a packet to be sent to a given remote address, and fill it from a slice. + pub async fn send_to(&self, buf: &[u8], remote_endpoint: T) -> Result<(), SendError> + where + T: Into, + { + let remote_endpoint = remote_endpoint.into(); + poll_fn(move |cx| { + self.with_mut(|s, _| match s.send_slice(buf, remote_endpoint) { + // Entire datagram has been sent + Ok(()) => Poll::Ready(Ok(())), + Err(icmp::SendError::BufferFull) => { + s.register_send_waker(cx.waker()); + Poll::Pending + } + Err(icmp::SendError::Unaddressable) => Poll::Ready(Err(SendError::NoRoute)), + }) + }) + .await + } + + /// Enqueue a packet to be sent to a given remote address with a zero-copy function. + /// + /// This method will wait until the buffer can fit the requested size before + /// calling the function to fill its contents. + pub async fn send_to_with(&self, size: usize, remote_endpoint: T, f: F) -> Result + where + T: Into, + F: FnOnce(&mut [u8]) -> R, + { + let mut f = Some(f); + let remote_endpoint = remote_endpoint.into(); + poll_fn(move |cx| { + self.with_mut(|s, _| match s.send(size, remote_endpoint) { + Ok(buf) => Poll::Ready(Ok(unwrap!(f.take())(buf))), + Err(icmp::SendError::BufferFull) => { + s.register_send_waker(cx.waker()); + Poll::Pending + } + Err(icmp::SendError::Unaddressable) => Poll::Ready(Err(SendError::NoRoute)), + }) + }) + .await + } + + /// Check whether the socket is open. + pub fn is_open(&self) -> bool { + self.with(|s, _| s.is_open()) + } + + /// Returns whether the socket is ready to send data, i.e. it has enough buffer space to hold a packet. + pub fn may_send(&self) -> bool { + self.with(|s, _| s.can_send()) + } + + /// Returns whether the socket is ready to receive data, i.e. it has received a packet that's now in the buffer. + pub fn may_recv(&self) -> bool { + self.with(|s, _| s.can_recv()) + } + + /// Return the maximum number packets the socket can receive. + pub fn packet_recv_capacity(&self) -> usize { + self.with(|s, _| s.packet_recv_capacity()) + } + + /// Return the maximum number packets the socket can receive. + pub fn packet_send_capacity(&self) -> usize { + self.with(|s, _| s.packet_send_capacity()) + } + + /// Return the maximum number of bytes inside the recv buffer. + pub fn payload_recv_capacity(&self) -> usize { + self.with(|s, _| s.payload_recv_capacity()) + } + + /// Return the maximum number of bytes inside the transmit buffer. + pub fn payload_send_capacity(&self) -> usize { + self.with(|s, _| s.payload_send_capacity()) + } + + /// Return the time-to-live (IPv4) or hop limit (IPv6) value used in outgoing packets. + pub fn hop_limit(&self) -> Option { + self.with(|s, _| s.hop_limit()) + } + + /// Set the hop limit field in the IP header of sent packets. + pub fn set_hop_limit(&mut self, hop_limit: Option) { + self.with_mut(|s, _| s.set_hop_limit(hop_limit)) + } +} + +impl Drop for IcmpSocket<'_> { + fn drop(&mut self) { + self.stack.with_mut(|i| i.sockets.remove(self.handle)); + } +} + +pub mod ping { + //! Ping utilities. + //! + //! This module allows for an easy ICMP Echo message interface used to + //! ping devices with an [ICMP Socket](IcmpSocket). + //! + //! ## Usage + //! + //! ``` + //! use core::net::Ipv4Addr; + //! use core::str::FromStr; + //! + //! use embassy_net::icmp::ping::{PingManager, PingParams}; + //! use embassy_net::icmp::PacketMetadata; + //! + //! let mut rx_buffer = [0; 256]; + //! let mut tx_buffer = [0; 256]; + //! let mut rx_meta = [PacketMetadata::EMPTY]; + //! let mut tx_meta = [PacketMetadata::EMPTY]; + //! + //! let mut ping_manager = PingManager::new(stack, &mut rx_meta, &mut rx_buffer, &mut tx_meta, &mut tx_buffer); + //! let addr = "192.168.8.1"; + //! let mut ping_params = PingParams::new(Ipv4Addr::from_str(addr).unwrap()); + //! ping_params.set_payload(b"Hello, router!"); + //! match ping_manager.ping(&ping_params).await { + //! Ok(time) => info!("Ping time of {}: {}ms", addr, time.as_millis()), + //! Err(ping_error) => warn!("{:?}", ping_error), + //! }; + //! ``` + + use super::*; + use core::net::{IpAddr, Ipv6Addr}; + use embassy_time::{Duration, Instant, Timer, WithTimeout}; + + /// Error returned by [`ping()`](PingManager::ping). + #[derive(PartialEq, Eq, Clone, Copy, Debug)] + #[cfg_attr(feature = "defmt", derive(defmt::Format))] + pub enum PingError { + /// The target did not respond. + /// + /// The packet was sent but the Reply packet has not been recieved + /// in the timeout set by [`set_timeout()`](PingParams::set_timeout). + DestinationHostUnreachable, + /// The target has not been specified. + InvalidTargetAddress, + /// The source has not been specified (Ipv6 only). + #[cfg(feature = "proto-ipv6")] + InvalidSourceAddress, + /// The socket could not queue the packet in the buffer. + SocketSendTimeout, + /// Container error for [`icmp::BindError`]. + SocketBindError(BindError), + /// Container error for [`icmp::SendError`]. + SocketSendError(SendError), + /// Container error for [`icmp::RecvError`]. + SocketRecvError(RecvError), + } + + /// Manages ICMP ping operations. + /// + /// This struct provides functionality to send ICMP echo requests (pings) to a specified target + /// and measure the round-trip time for the requests. It supports both IPv4 and IPv6, depending + /// on the enabled features. + /// + /// # Fields + /// + /// * `stack` - The network stack instance used for managing network operations. + /// * `rx_meta` - Metadata buffer for receiving packets. + /// * `rx_buffer` - Buffer for receiving packets. + /// * `tx_meta` - Metadata buffer for transmitting packets. + /// * `tx_buffer` - Buffer for transmitting packets. + /// * `ident` - Identifier for the ICMP echo requests. + /// + /// # Methods + /// + /// * [`new`](PingManager::new) - Creates a new instance of `PingManager` with the specified stack and buffers. + /// * [`ping`](PingManager::ping) - Sends ICMP echo requests to the specified target and returns the average round-trip time. + pub struct PingManager<'d> { + stack: Stack<'d>, + rx_meta: &'d mut [PacketMetadata], + rx_buffer: &'d mut [u8], + tx_meta: &'d mut [PacketMetadata], + tx_buffer: &'d mut [u8], + ident: u16, + } + + impl<'d> PingManager<'d> { + /// Creates a new instance of [`PingManager`] with a [`Stack`] instance + /// and the buffers used for RX and TX. + /// + /// **note**: This does not yet creates the ICMP socket. + pub fn new( + stack: Stack<'d>, + rx_meta: &'d mut [PacketMetadata], + rx_buffer: &'d mut [u8], + tx_meta: &'d mut [PacketMetadata], + tx_buffer: &'d mut [u8], + ) -> Self { + Self { + stack, + rx_meta, + rx_buffer, + tx_meta, + tx_buffer, + ident: 0, + } + } + + /// Sends ICMP echo requests to the specified target and returns the average round-trip time. + /// + /// # Arguments + /// + /// * `params` - Parameters for configuring the ping operation. + /// + /// # Returns + /// + /// * `Ok(Duration)` - The average round-trip time for the ping requests. + /// * `Err(PingError)` - An error occurred during the ping operation. + pub async fn ping<'a>(&mut self, params: &PingParams<'a>) -> Result { + // Input validation + if params.target().is_none() { + return Err(PingError::InvalidTargetAddress); + } + #[cfg(feature = "proto-ipv6")] + if params.target().unwrap().is_ipv6() && params.source().is_none() { + return Err(PingError::InvalidSourceAddress); + } + // Increment the ident (wrapping u16) to respect standards + self.ident = self.ident.wrapping_add(1u16); + // Used to calculate the average duration + let mut total_duration = Duration::default(); + let mut num_of_durations = 0u16; + // Increment the sequence number as per standards + for seq_no in 0..params.count() { + // Make sure each ping takes at least 1 second to respect standards + let rate_limit_start = Instant::now(); + + // make a single ping + // - shorts out errors + // - select the ip version + let ping_duration = match params.target().unwrap() { + #[cfg(feature = "proto-ipv4")] + IpAddr::V4(_) => self.single_ping_v4(params, seq_no).await?, + #[cfg(feature = "proto-ipv6")] + IpAddr::V6(_) => self.single_ping_v6(params, seq_no).await?, + }; + + // safely add up the durations of each ping + if let Some(dur) = total_duration.checked_add(ping_duration) { + total_duration = dur; + num_of_durations += 1; + } + + // 1 sec min per ping + let rate_limit_end = rate_limit_start.elapsed(); + if rate_limit_end <= Duration::from_secs(1) { + Timer::after(Duration::from_secs(1).checked_sub(rate_limit_end).unwrap()).await; + } + } + // calculate and return the average duration + Ok(total_duration.checked_div(num_of_durations as u32).unwrap()) + } + + #[cfg(feature = "proto-ipv4")] + fn create_repr_ipv4<'b>(&self, params: &PingParams<'b>, seq_no: u16) -> Icmpv4Repr<'b> { + Icmpv4Repr::EchoRequest { + ident: self.ident, + seq_no, + data: params.payload, + } + } + + #[cfg(feature = "proto-ipv6")] + fn create_repr_ipv6<'b>(&self, params: &PingParams<'b>, seq_no: u16) -> Icmpv6Repr<'b> { + Icmpv6Repr::EchoRequest { + ident: self.ident, + seq_no, + data: params.payload, + } + } + + #[cfg(feature = "proto-ipv4")] + async fn single_ping_v4(&mut self, params: &PingParams<'_>, seq_no: u16) -> Result { + let ping_repr = self.create_repr_ipv4(params, seq_no); + + // Create the socket and set hop limit and bind it to the endpoint with the ident + let mut socket = IcmpSocket::new(self.stack, self.rx_meta, self.rx_buffer, self.tx_meta, self.tx_buffer); + socket.set_hop_limit(params.hop_limit); + if let Err(e) = socket.bind(IcmpEndpoint::Ident(self.ident)) { + return Err(PingError::SocketBindError(e)); + } + + // Helper func to fill the buffer when sending the ICMP packet + fn fill_packet_buffer(buf: &mut [u8], ping_repr: Icmpv4Repr<'_>) -> Instant { + let mut icmp_packet = Icmpv4Packet::new_unchecked(buf); + ping_repr.emit(&mut icmp_packet, &ChecksumCapabilities::default()); + Instant::now() + } + + // Send with timeout the ICMP packet filling it with the helper function + let send_result = socket + .send_to_with(ping_repr.buffer_len(), params.target.unwrap(), |buf| { + fill_packet_buffer(buf, ping_repr) + }) + .with_timeout(Duration::from_millis(100)) + .await; + // Filter and translate potential errors from sending the packet + let now = match send_result { + Ok(send_result) => match send_result { + Ok(i) => i, + Err(e) => return Err(PingError::SocketSendError(e)), + }, + Err(_) => return Err(PingError::SocketSendTimeout), + }; + + // Helper function for the recieve helper function to validate the echo reply + fn filter_pong(buf: &[u8], seq_no: u16) -> bool { + let pong_packet = match Icmpv4Packet::new_checked(buf) { + Ok(pak) => pak, + Err(_) => return false, + }; + pong_packet.echo_seq_no() == seq_no + } + + // Helper function to recieve and return the correct echo reply when it finds it + async fn recv_pong(socket: &IcmpSocket<'_>, seq_no: u16) -> Result<(), PingError> { + while match socket.recv_with(|(buf, _)| filter_pong(buf, seq_no)).await { + Ok(b) => !b, + Err(e) => return Err(PingError::SocketRecvError(e)), + } {} + Ok(()) + } + + // Calls the recieve helper function with a timeout + match recv_pong(&socket, seq_no).with_timeout(params.timeout).await { + Ok(res) => res?, + Err(_) => return Err(PingError::DestinationHostUnreachable), + } + + // Return the round trip duration + Ok(now.elapsed()) + } + + #[cfg(feature = "proto-ipv6")] + async fn single_ping_v6(&mut self, params: &PingParams<'_>, seq_no: u16) -> Result { + let ping_repr = self.create_repr_ipv6(params, seq_no); + + // Create the socket and set hop limit and bind it to the endpoint with the ident + let mut socket = IcmpSocket::new(self.stack, self.rx_meta, self.rx_buffer, self.tx_meta, self.tx_buffer); + socket.set_hop_limit(params.hop_limit); + if let Err(e) = socket.bind(IcmpEndpoint::Ident(self.ident)) { + return Err(PingError::SocketBindError(e)); + } + + // Helper func to fill the buffer when sending the ICMP packet + fn fill_packet_buffer(buf: &mut [u8], ping_repr: Icmpv6Repr<'_>, params: &PingParams<'_>) -> Instant { + let mut icmp_packet = Icmpv6Packet::new_unchecked(buf); + let target = match params.target().unwrap() { + IpAddr::V4(_) => unreachable!(), + IpAddr::V6(addr) => addr, + }; + ping_repr.emit( + ¶ms.source().unwrap(), + &target, + &mut icmp_packet, + &ChecksumCapabilities::default(), + ); + Instant::now() + } + + // Send with timeout the ICMP packet filling it with the helper function + let send_result = socket + .send_to_with(ping_repr.buffer_len(), params.target.unwrap(), |buf| { + fill_packet_buffer(buf, ping_repr, params) + }) + .with_timeout(Duration::from_millis(100)) + .await; + let now = match send_result { + Ok(send_result) => match send_result { + Ok(i) => i, + Err(e) => return Err(PingError::SocketSendError(e)), + }, + Err(_) => return Err(PingError::SocketSendTimeout), + }; + + // Helper function for the recieve helper function to validate the echo reply + fn filter_pong(buf: &[u8], seq_no: u16) -> bool { + let pong_packet = match Icmpv6Packet::new_checked(buf) { + Ok(pak) => pak, + Err(_) => return false, + }; + pong_packet.echo_seq_no() == seq_no + } + + // Helper function to recieve and return the correct echo reply when it finds it + async fn recv_pong(socket: &IcmpSocket<'_>, seq_no: u16) -> Result<(), PingError> { + while match socket.recv_with(|(buf, _)| filter_pong(buf, seq_no)).await { + Ok(b) => !b, + Err(e) => return Err(PingError::SocketRecvError(e)), + } {} + Ok(()) + } + + // Calls the recieve helper function with a timeout + match recv_pong(&socket, seq_no).with_timeout(params.timeout).await { + Ok(res) => res?, + Err(_) => return Err(PingError::DestinationHostUnreachable), + } + + // Return the round trip duration + Ok(now.elapsed()) + } + } + + + /// Parameters for configuring the ping operation. + /// + /// This struct provides various configuration options for performing ICMP ping operations, + /// including the target IP address, payload data, hop limit, number of pings, and timeout duration. + /// + /// # Fields + /// + /// * `target` - The target IP address for the ping operation. + /// * `source` - The source IP address for the ping operation (IPv6 only). + /// * `payload` - The data to be sent in the payload field of the ping. + /// * `hop_limit` - The hop limit to be used by the socket. + /// * `count` - The number of pings to be sent in one ping operation. + /// * `timeout` - The timeout duration before returning a [`PingError::DestinationHostUnreachable`] error. + pub struct PingParams<'a> { + target: Option, + #[cfg(feature = "proto-ipv6")] + source: Option, + payload: &'a [u8], + hop_limit: Option, + count: u16, + timeout: Duration, + } + + impl Default for PingParams<'_> { + fn default() -> Self { + Self { + target: None, + #[cfg(feature = "proto-ipv6")] + source: None, + payload: b"embassy-net", + hop_limit: None, + count: 4, + timeout: Duration::from_secs(4), + } + } + } + + impl<'a> PingParams<'a> { + /// Creates a new instance of [`PingParams`] with the specified target IP address. + pub fn new>(target: T) -> Self { + Self { + target: Some(target.into()), + #[cfg(feature = "proto-ipv6")] + source: None, + payload: b"embassy-net", + hop_limit: None, + count: 4, + timeout: Duration::from_secs(4), + } + } + + /// Sets the target IP address for the ping. + pub fn set_target>(&mut self, target: T) -> &mut Self { + self.target = Some(target.into()); + self + } + + /// Retrieves the target IP address for the ping. + pub fn target(&self) -> Option { + self.target + } + + /// Sets the source IP address for the ping (IPv6 only). + #[cfg(feature = "proto-ipv6")] + pub fn set_source(&mut self, source: Ipv6Addr) -> &mut Self { + self.source = Some(source); + self + } + + /// Retrieves the source IP address for the ping (IPv6 only). + #[cfg(feature = "proto-ipv6")] + pub fn source(&self) -> Option { + self.source + } + + /// Sets the data used in the payload field of the ping with the provided slice. + pub fn set_payload(&mut self, payload: &'a [u8]) -> &mut Self { + self.payload = payload; + self + } + + /// Gives a reference to the slice of data that's going to be sent in the payload field + /// of the ping. + pub fn payload(&self) -> &'a [u8] { + self.payload + } + + /// Sets the hop limit that will be used by the socket with [`set_hop_limit()`](IcmpSocket::set_hop_limit). + /// + /// **Note**: A hop limit of [`Some(0)`](Some()) is equivalent to a hop limit of [`None`]. + pub fn set_hop_limit(&mut self, hop_limit: Option) -> &mut Self { + let mut hop_limit = hop_limit; + if hop_limit.is_some_and(|x| x == 0) { + hop_limit = None + } + self.hop_limit = hop_limit; + self + } + + /// Retrieves the hop limit that will be used by the socket with [`set_hop_limit()`](IcmpSocket::set_hop_limit). + pub fn hop_limit(&self) -> Option { + self.hop_limit + } + + /// Sets the count used for specifying the number of pings done on one + /// [`ping()`](PingManager::ping) call. + /// + /// **Note**: A count of 0 will be set as 1. + pub fn set_count(&mut self, count: u16) -> &mut Self { + let mut count = count; + if count == 0 { + count = 1; + } + self.count = count; + self + } + + /// Retrieve the count used for specifying the number of pings done on one + /// [`ping()`](PingManager::ping) call. + pub fn count(&self) -> u16 { + self.count + } + + /// Sets the timeout used before returning [`PingError::DestinationHostUnreachable`] + /// when waiting for the Echo Reply icmp packet. + pub fn set_timeout(&mut self, timeout: Duration) -> &mut Self { + self.timeout = timeout; + self + } + + /// Retrieve the timeout used before returning [`PingError::DestinationHostUnreachable`] + /// when waiting for the Echo Reply icmp packet. + pub fn timeout(&self) -> Duration { + self.timeout + } + } +} diff --git a/embassy-net/src/lib.rs b/embassy-net/src/lib.rs index 47bd5191f..1bb112252 100644 --- a/embassy-net/src/lib.rs +++ b/embassy-net/src/lib.rs @@ -22,6 +22,8 @@ pub mod tcp; mod time; #[cfg(feature = "udp")] pub mod udp; +#[cfg(feature = "icmp")] +pub mod icmp; use core::cell::RefCell; use core::future::{poll_fn, Future}; From 38b5f8bd0afd9669e638b8d83210427d2d372a96 Mon Sep 17 00:00:00 2001 From: skkeye Date: Sun, 9 Feb 2025 01:07:25 -0500 Subject: [PATCH 0733/1217] examples/rp: add examples using ICMP sockets and the ping utility --- examples/rp/Cargo.toml | 2 +- examples/rp/src/bin/ethernet_w5500_icmp.rs | 143 ++++++++++++++++++ .../rp/src/bin/ethernet_w5500_icmp_ping.rs | 135 +++++++++++++++++ 3 files changed, 279 insertions(+), 1 deletion(-) create mode 100644 examples/rp/src/bin/ethernet_w5500_icmp.rs create mode 100644 examples/rp/src/bin/ethernet_w5500_icmp_ping.rs diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index 50cfdca1e..c7823a711 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml @@ -12,7 +12,7 @@ embassy-executor = { version = "0.7.0", path = "../../embassy-executor", feature embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-rp = { version = "0.3.0", path = "../../embassy-rp", features = ["defmt", "unstable-pac", "time-driver", "critical-section-impl", "rp2040"] } embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defmt"] } -embassy-net = { version = "0.6.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "raw", "dhcpv4", "medium-ethernet", "dns", "proto-ipv4", "proto-ipv6", "multicast"] } +embassy-net = { version = "0.6.0", path = "../../embassy-net", features = ["defmt", "icmp", "tcp", "udp", "raw", "dhcpv4", "medium-ethernet", "dns", "proto-ipv4", "proto-ipv6", "multicast"] } embassy-net-wiznet = { version = "0.2.0", path = "../../embassy-net-wiznet", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-usb-logger = { version = "0.4.0", path = "../../embassy-usb-logger" } diff --git a/examples/rp/src/bin/ethernet_w5500_icmp.rs b/examples/rp/src/bin/ethernet_w5500_icmp.rs new file mode 100644 index 000000000..a07cdf88d --- /dev/null +++ b/examples/rp/src/bin/ethernet_w5500_icmp.rs @@ -0,0 +1,143 @@ +//! This example implements an echo (ping) with an ICMP Socket and using defmt to report the results. +//! +//! Although there is a better way to execute pings using the child module ping of the icmp module, +//! this example allows for other icmp messages like `Destination unreachable` to be sent aswell. +//! +//! Example written for the [`WIZnet W5500-EVB-Pico`](https://docs.wiznet.io/Product/iEthernet/W5500/w5500-evb-pico) board. + +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_futures::yield_now; +use embassy_net::icmp::{ChecksumCapabilities, IcmpEndpoint, IcmpSocket, Icmpv4Packet, Icmpv4Repr, PacketMetadata}; +use embassy_net::{Stack, StackResources}; +use embassy_net_wiznet::chip::W5500; +use embassy_net_wiznet::*; +use embassy_rp::clocks::RoscRng; +use embassy_rp::gpio::{Input, Level, Output, Pull}; +use embassy_rp::peripherals::SPI0; +use embassy_rp::spi::{Async, Config as SpiConfig, Spi}; +use embassy_time::{Delay, Instant, Timer}; +use embedded_hal_bus::spi::ExclusiveDevice; +use rand::RngCore; +use static_cell::StaticCell; +use {defmt_rtt as _, panic_probe as _}; + +type ExclusiveSpiDevice = ExclusiveDevice, Output<'static>, Delay>; + +#[embassy_executor::task] +async fn ethernet_task(runner: Runner<'static, W5500, ExclusiveSpiDevice, Input<'static>, Output<'static>>) -> ! { + runner.run().await +} + +#[embassy_executor::task] +async fn net_task(mut runner: embassy_net::Runner<'static, Device<'static>>) -> ! { + runner.run().await +} + +#[embassy_executor::main] +async fn main(spawner: Spawner) { + let p = embassy_rp::init(Default::default()); + let mut rng = RoscRng; + + let mut spi_cfg = SpiConfig::default(); + spi_cfg.frequency = 50_000_000; + let (miso, mosi, clk) = (p.PIN_16, p.PIN_19, p.PIN_18); + let spi = Spi::new(p.SPI0, clk, mosi, miso, p.DMA_CH0, p.DMA_CH1, spi_cfg); + let cs = Output::new(p.PIN_17, Level::High); + let w5500_int = Input::new(p.PIN_21, Pull::Up); + let w5500_reset = Output::new(p.PIN_20, Level::High); + + let mac_addr = [0x02, 0x00, 0x00, 0x00, 0x00, 0x00]; + static STATE: StaticCell> = StaticCell::new(); + let state = STATE.init(State::<8, 8>::new()); + let (device, runner) = embassy_net_wiznet::new( + mac_addr, + state, + ExclusiveDevice::new(spi, cs, Delay), + w5500_int, + w5500_reset, + ) + .await + .unwrap(); + unwrap!(spawner.spawn(ethernet_task(runner))); + + // Generate random seed + let seed = rng.next_u64(); + + // Init network stack + static RESOURCES: StaticCell> = StaticCell::new(); + let (stack, runner) = embassy_net::new( + device, + embassy_net::Config::dhcpv4(Default::default()), + RESOURCES.init(StackResources::new()), + seed, + ); + + // Launch network task + unwrap!(spawner.spawn(net_task(runner))); + + info!("Waiting for DHCP..."); + let cfg = wait_for_config(stack).await; + let local_addr = cfg.address.address(); + info!("IP address: {:?}", local_addr); + + // Then we can use it! + let mut rx_buffer = [0; 256]; + let mut tx_buffer = [0; 256]; + let mut rx_meta = [PacketMetadata::EMPTY]; + let mut tx_meta = [PacketMetadata::EMPTY]; + + // Identifier used for the ICMP socket + let ident = 42; + + // Create and bind the socket + let mut socket = IcmpSocket::new(stack, &mut rx_meta, &mut rx_buffer, &mut tx_meta, &mut tx_buffer); + socket.bind(IcmpEndpoint::Ident(ident)).unwrap(); + + // Create the repr for the packet + let icmp_repr = Icmpv4Repr::EchoRequest { + ident, + seq_no: 0, + data: b"Hello, icmp!", + }; + + // Send the packet and store the starting instant to mesure latency later + let start = socket + .send_to_with( + icmp_repr.buffer_len(), + cfg.gateway.unwrap(), + |buf| { + // Create and populate the packet buffer allocated by `send_to_with` + let mut icmp_packet = Icmpv4Packet::new_unchecked(buf); + icmp_repr.emit(&mut icmp_packet, &ChecksumCapabilities::default()); + Instant::now() // Return the instant where the packet was sent + }, + ) + .await + .unwrap(); + + // Recieve and log the data of the reply + socket + .recv_with(|(buf, addr)| { + let packet = Icmpv4Packet::new_checked(buf).unwrap(); + info!("Recieved {:?} from {} in {}ms", packet.data(), addr, start.elapsed().as_millis()); + }) + .await + .unwrap(); + + loop { + Timer::after_secs(10).await; + } +} + +async fn wait_for_config(stack: Stack<'static>) -> embassy_net::StaticConfigV4 { + loop { + if let Some(config) = stack.config_v4() { + return config.clone(); + } + yield_now().await; + } +} diff --git a/examples/rp/src/bin/ethernet_w5500_icmp_ping.rs b/examples/rp/src/bin/ethernet_w5500_icmp_ping.rs new file mode 100644 index 000000000..0d83e3831 --- /dev/null +++ b/examples/rp/src/bin/ethernet_w5500_icmp_ping.rs @@ -0,0 +1,135 @@ +//! This example implements a LAN ping scan with the ping utilities in the icmp module of embassy-net. +//! +//! Example written for the [`WIZnet W5500-EVB-Pico`](https://docs.wiznet.io/Product/iEthernet/W5500/w5500-evb-pico) board. + +#![no_std] +#![no_main] + +use core::net::Ipv4Addr; +use core::ops::Not; +use core::str::FromStr; + +use defmt::*; +use embassy_executor::Spawner; +use embassy_futures::yield_now; +use embassy_net::icmp::ping::{PingManager, PingParams}; +use embassy_net::icmp::PacketMetadata; +use embassy_net::{Ipv4Cidr, Stack, StackResources}; +use embassy_net_wiznet::chip::W5500; +use embassy_net_wiznet::*; +use embassy_rp::clocks::RoscRng; +use embassy_rp::gpio::{Input, Level, Output, Pull}; +use embassy_rp::peripherals::SPI0; +use embassy_rp::spi::{Async, Config as SpiConfig, Spi}; +use embassy_time::{Delay, Duration}; +use embedded_hal_bus::spi::ExclusiveDevice; +use rand::RngCore; +use static_cell::StaticCell; +use {defmt_rtt as _, panic_probe as _}; + +type ExclusiveSpiDevice = ExclusiveDevice, Output<'static>, Delay>; + +#[embassy_executor::task] +async fn ethernet_task(runner: Runner<'static, W5500, ExclusiveSpiDevice, Input<'static>, Output<'static>>) -> ! { + runner.run().await +} + +#[embassy_executor::task] +async fn net_task(mut runner: embassy_net::Runner<'static, Device<'static>>) -> ! { + runner.run().await +} + +#[embassy_executor::main] +async fn main(spawner: Spawner) { + let p = embassy_rp::init(Default::default()); + let mut rng = RoscRng; + + let mut spi_cfg = SpiConfig::default(); + spi_cfg.frequency = 50_000_000; + let (miso, mosi, clk) = (p.PIN_16, p.PIN_19, p.PIN_18); + let spi = Spi::new(p.SPI0, clk, mosi, miso, p.DMA_CH0, p.DMA_CH1, spi_cfg); + let cs = Output::new(p.PIN_17, Level::High); + let w5500_int = Input::new(p.PIN_21, Pull::Up); + let w5500_reset = Output::new(p.PIN_20, Level::High); + + let mac_addr = [0x02, 0x00, 0x00, 0x00, 0x00, 0x00]; + static STATE: StaticCell> = StaticCell::new(); + let state = STATE.init(State::<8, 8>::new()); + let (device, runner) = embassy_net_wiznet::new( + mac_addr, + state, + ExclusiveDevice::new(spi, cs, Delay), + w5500_int, + w5500_reset, + ) + .await + .unwrap(); + unwrap!(spawner.spawn(ethernet_task(runner))); + + // Generate random seed + let seed = rng.next_u64(); + + // Init network stack + static RESOURCES: StaticCell> = StaticCell::new(); + let (stack, runner) = embassy_net::new( + device, + embassy_net::Config::dhcpv4(Default::default()), + RESOURCES.init(StackResources::new()), + seed, + ); + + // Launch network task + unwrap!(spawner.spawn(net_task(runner))); + + info!("Waiting for DHCP..."); + let cfg = wait_for_config(stack).await; + let local_addr = cfg.address.address(); + info!("IP address: {:?}", local_addr); + let gateway = cfg.gateway.unwrap(); + let mask = cfg.address.netmask(); + let lower_bound = (gateway.to_bits() & mask.to_bits()) + 1; + let upper_bound = gateway.to_bits() | mask.to_bits().not(); + let addr_range = lower_bound..=upper_bound; + + // Then we can use it! + let mut rx_buffer = [0; 256]; + let mut tx_buffer = [0; 256]; + let mut rx_meta = [PacketMetadata::EMPTY]; + let mut tx_meta = [PacketMetadata::EMPTY]; + + // Create the ping manager instance + let mut ping_manager = PingManager::new(stack, &mut rx_meta, &mut rx_buffer, &mut tx_meta, &mut tx_buffer); + let addr = "192.168.8.1"; // Address to ping to + // Create the PingParams with the target address + let mut ping_params = PingParams::new(Ipv4Addr::from_str(addr).unwrap()); + // (optional) Set custom properties of the ping + ping_params.set_payload(b"Hello, Ping!"); // custom payload + ping_params.set_count(1); // ping 1 times per ping call + ping_params.set_timeout(Duration::from_millis(500)); // wait .5 seconds instead of 4 + + info!("Online hosts in {}:", Ipv4Cidr::from_netmask(gateway, mask).unwrap()); + let mut total_online_hosts = 0u32; + for addr in addr_range { + let ip_addr = Ipv4Addr::from_bits(addr); + // Set the target address in the ping params + ping_params.set_target(ip_addr); + // Execute the ping with the given parameters and wait for the reply + match ping_manager.ping(&ping_params).await { + Ok(time) => { + info!("{} is online\n- latency: {}ms\n", ip_addr, time.as_millis()); + total_online_hosts += 1; + }, + _ => continue, + } + } + info!("Ping scan complete, total online hosts: {}", total_online_hosts); +} + +async fn wait_for_config(stack: Stack<'static>) -> embassy_net::StaticConfigV4 { + loop { + if let Some(config) = stack.config_v4() { + return config.clone(); + } + yield_now().await; + } +} From bdb1b812135b7cb22f65009242d5b61712e8e9d7 Mon Sep 17 00:00:00 2001 From: skkeye Date: Sun, 9 Feb 2025 02:11:15 -0500 Subject: [PATCH 0734/1217] fix: nightly fmt --- embassy-net/src/icmp.rs | 33 ++++++++++--------- embassy-net/src/lib.rs | 4 +-- examples/rp/src/bin/ethernet_w5500_icmp.rs | 25 +++++++------- .../rp/src/bin/ethernet_w5500_icmp_ping.rs | 4 +-- 4 files changed, 34 insertions(+), 32 deletions(-) diff --git a/embassy-net/src/icmp.rs b/embassy-net/src/icmp.rs index 4cce5db50..ba206a465 100644 --- a/embassy-net/src/icmp.rs +++ b/embassy-net/src/icmp.rs @@ -252,24 +252,24 @@ impl Drop for IcmpSocket<'_> { pub mod ping { //! Ping utilities. - //! - //! This module allows for an easy ICMP Echo message interface used to + //! + //! This module allows for an easy ICMP Echo message interface used to //! ping devices with an [ICMP Socket](IcmpSocket). - //! + //! //! ## Usage - //! + //! //! ``` //! use core::net::Ipv4Addr; //! use core::str::FromStr; - //! + //! //! use embassy_net::icmp::ping::{PingManager, PingParams}; //! use embassy_net::icmp::PacketMetadata; - //! + //! //! let mut rx_buffer = [0; 256]; //! let mut tx_buffer = [0; 256]; //! let mut rx_meta = [PacketMetadata::EMPTY]; //! let mut tx_meta = [PacketMetadata::EMPTY]; - //! + //! //! let mut ping_manager = PingManager::new(stack, &mut rx_meta, &mut rx_buffer, &mut tx_meta, &mut tx_buffer); //! let addr = "192.168.8.1"; //! let mut ping_params = PingParams::new(Ipv4Addr::from_str(addr).unwrap()); @@ -280,16 +280,18 @@ pub mod ping { //! }; //! ``` - use super::*; use core::net::{IpAddr, Ipv6Addr}; + use embassy_time::{Duration, Instant, Timer, WithTimeout}; + use super::*; + /// Error returned by [`ping()`](PingManager::ping). #[derive(PartialEq, Eq, Clone, Copy, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum PingError { /// The target did not respond. - /// + /// /// The packet was sent but the Reply packet has not been recieved /// in the timeout set by [`set_timeout()`](PingParams::set_timeout). DestinationHostUnreachable, @@ -339,7 +341,7 @@ pub mod ping { impl<'d> PingManager<'d> { /// Creates a new instance of [`PingManager`] with a [`Stack`] instance /// and the buffers used for RX and TX. - /// + /// /// **note**: This does not yet creates the ICMP socket. pub fn new( stack: Stack<'d>, @@ -387,7 +389,7 @@ pub mod ping { // Make sure each ping takes at least 1 second to respect standards let rate_limit_start = Instant::now(); - // make a single ping + // make a single ping // - shorts out errors // - select the ip version let ping_duration = match params.target().unwrap() { @@ -564,7 +566,6 @@ pub mod ping { } } - /// Parameters for configuring the ping operation. /// /// This struct provides various configuration options for performing ICMP ping operations, @@ -653,7 +654,7 @@ pub mod ping { } /// Sets the hop limit that will be used by the socket with [`set_hop_limit()`](IcmpSocket::set_hop_limit). - /// + /// /// **Note**: A hop limit of [`Some(0)`](Some()) is equivalent to a hop limit of [`None`]. pub fn set_hop_limit(&mut self, hop_limit: Option) -> &mut Self { let mut hop_limit = hop_limit; @@ -669,9 +670,9 @@ pub mod ping { self.hop_limit } - /// Sets the count used for specifying the number of pings done on one + /// Sets the count used for specifying the number of pings done on one /// [`ping()`](PingManager::ping) call. - /// + /// /// **Note**: A count of 0 will be set as 1. pub fn set_count(&mut self, count: u16) -> &mut Self { let mut count = count; @@ -682,7 +683,7 @@ pub mod ping { self } - /// Retrieve the count used for specifying the number of pings done on one + /// Retrieve the count used for specifying the number of pings done on one /// [`ping()`](PingManager::ping) call. pub fn count(&self) -> u16 { self.count diff --git a/embassy-net/src/lib.rs b/embassy-net/src/lib.rs index 1bb112252..693a39ed5 100644 --- a/embassy-net/src/lib.rs +++ b/embassy-net/src/lib.rs @@ -15,6 +15,8 @@ pub(crate) mod fmt; #[cfg(feature = "dns")] pub mod dns; mod driver_util; +#[cfg(feature = "icmp")] +pub mod icmp; #[cfg(feature = "raw")] pub mod raw; #[cfg(feature = "tcp")] @@ -22,8 +24,6 @@ pub mod tcp; mod time; #[cfg(feature = "udp")] pub mod udp; -#[cfg(feature = "icmp")] -pub mod icmp; use core::cell::RefCell; use core::future::{poll_fn, Future}; diff --git a/examples/rp/src/bin/ethernet_w5500_icmp.rs b/examples/rp/src/bin/ethernet_w5500_icmp.rs index a07cdf88d..5f336b579 100644 --- a/examples/rp/src/bin/ethernet_w5500_icmp.rs +++ b/examples/rp/src/bin/ethernet_w5500_icmp.rs @@ -1,5 +1,5 @@ //! This example implements an echo (ping) with an ICMP Socket and using defmt to report the results. -//! +//! //! Although there is a better way to execute pings using the child module ping of the icmp module, //! this example allows for other icmp messages like `Destination unreachable` to be sent aswell. //! @@ -106,16 +106,12 @@ async fn main(spawner: Spawner) { // Send the packet and store the starting instant to mesure latency later let start = socket - .send_to_with( - icmp_repr.buffer_len(), - cfg.gateway.unwrap(), - |buf| { - // Create and populate the packet buffer allocated by `send_to_with` - let mut icmp_packet = Icmpv4Packet::new_unchecked(buf); - icmp_repr.emit(&mut icmp_packet, &ChecksumCapabilities::default()); - Instant::now() // Return the instant where the packet was sent - }, - ) + .send_to_with(icmp_repr.buffer_len(), cfg.gateway.unwrap(), |buf| { + // Create and populate the packet buffer allocated by `send_to_with` + let mut icmp_packet = Icmpv4Packet::new_unchecked(buf); + icmp_repr.emit(&mut icmp_packet, &ChecksumCapabilities::default()); + Instant::now() // Return the instant where the packet was sent + }) .await .unwrap(); @@ -123,7 +119,12 @@ async fn main(spawner: Spawner) { socket .recv_with(|(buf, addr)| { let packet = Icmpv4Packet::new_checked(buf).unwrap(); - info!("Recieved {:?} from {} in {}ms", packet.data(), addr, start.elapsed().as_millis()); + info!( + "Recieved {:?} from {} in {}ms", + packet.data(), + addr, + start.elapsed().as_millis() + ); }) .await .unwrap(); diff --git a/examples/rp/src/bin/ethernet_w5500_icmp_ping.rs b/examples/rp/src/bin/ethernet_w5500_icmp_ping.rs index 0d83e3831..0724311f9 100644 --- a/examples/rp/src/bin/ethernet_w5500_icmp_ping.rs +++ b/examples/rp/src/bin/ethernet_w5500_icmp_ping.rs @@ -100,7 +100,7 @@ async fn main(spawner: Spawner) { // Create the ping manager instance let mut ping_manager = PingManager::new(stack, &mut rx_meta, &mut rx_buffer, &mut tx_meta, &mut tx_buffer); let addr = "192.168.8.1"; // Address to ping to - // Create the PingParams with the target address + // Create the PingParams with the target address let mut ping_params = PingParams::new(Ipv4Addr::from_str(addr).unwrap()); // (optional) Set custom properties of the ping ping_params.set_payload(b"Hello, Ping!"); // custom payload @@ -118,7 +118,7 @@ async fn main(spawner: Spawner) { Ok(time) => { info!("{} is online\n- latency: {}ms\n", ip_addr, time.as_millis()); total_online_hosts += 1; - }, + } _ => continue, } } From 6d7a5f949c7a9d3cc5933725baacb075c6af75f1 Mon Sep 17 00:00:00 2001 From: skkeye Date: Sun, 9 Feb 2025 23:16:14 -0500 Subject: [PATCH 0735/1217] feat: configurable rate_limit for the ping utility --- embassy-net/src/icmp.rs | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/embassy-net/src/icmp.rs b/embassy-net/src/icmp.rs index ba206a465..dafe6ed8a 100644 --- a/embassy-net/src/icmp.rs +++ b/embassy-net/src/icmp.rs @@ -407,8 +407,8 @@ pub mod ping { // 1 sec min per ping let rate_limit_end = rate_limit_start.elapsed(); - if rate_limit_end <= Duration::from_secs(1) { - Timer::after(Duration::from_secs(1).checked_sub(rate_limit_end).unwrap()).await; + if rate_limit_end <= params.rate_limit { + Timer::after(params.rate_limit.checked_sub(rate_limit_end).unwrap()).await; } } // calculate and return the average duration @@ -579,6 +579,7 @@ pub mod ping { /// * `hop_limit` - The hop limit to be used by the socket. /// * `count` - The number of pings to be sent in one ping operation. /// * `timeout` - The timeout duration before returning a [`PingError::DestinationHostUnreachable`] error. + /// * `rate_limit` - The minimum time per echo request pub struct PingParams<'a> { target: Option, #[cfg(feature = "proto-ipv6")] @@ -587,6 +588,7 @@ pub mod ping { hop_limit: Option, count: u16, timeout: Duration, + rate_limit: Duration, } impl Default for PingParams<'_> { @@ -599,6 +601,7 @@ pub mod ping { hop_limit: None, count: 4, timeout: Duration::from_secs(4), + rate_limit: Duration::from_secs(1), } } } @@ -614,6 +617,7 @@ pub mod ping { hop_limit: None, count: 4, timeout: Duration::from_secs(4), + rate_limit: Duration::from_secs(1), } } @@ -701,5 +705,16 @@ pub mod ping { pub fn timeout(&self) -> Duration { self.timeout } + + /// Sets the `rate_limit`: minimum time per echo request + pub fn set_rate_limit(&mut self, rate_limit: Duration) -> &mut Self { + self.rate_limit = rate_limit; + self + } + + /// Retrieve the rate_limit + pub fn rate_limit(&self) -> Duration { + self.rate_limit + } } } From 7d2ffa76e5a34868a25a84e09e1e9f169d2d951f Mon Sep 17 00:00:00 2001 From: skkeye Date: Sun, 9 Feb 2025 23:17:30 -0500 Subject: [PATCH 0736/1217] fix: forgot fmt --- embassy-net/src/icmp.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/embassy-net/src/icmp.rs b/embassy-net/src/icmp.rs index dafe6ed8a..68f6fd536 100644 --- a/embassy-net/src/icmp.rs +++ b/embassy-net/src/icmp.rs @@ -579,7 +579,7 @@ pub mod ping { /// * `hop_limit` - The hop limit to be used by the socket. /// * `count` - The number of pings to be sent in one ping operation. /// * `timeout` - The timeout duration before returning a [`PingError::DestinationHostUnreachable`] error. - /// * `rate_limit` - The minimum time per echo request + /// * `rate_limit` - The minimum time per echo request. pub struct PingParams<'a> { target: Option, #[cfg(feature = "proto-ipv6")] @@ -706,13 +706,13 @@ pub mod ping { self.timeout } - /// Sets the `rate_limit`: minimum time per echo request + /// Sets the `rate_limit`: minimum time per echo request. pub fn set_rate_limit(&mut self, rate_limit: Duration) -> &mut Self { self.rate_limit = rate_limit; self } - /// Retrieve the rate_limit + /// Retrieve the rate_limit. pub fn rate_limit(&self) -> Duration { self.rate_limit } From 7b352654653466063fd149a766e2deb14bcfc1ad Mon Sep 17 00:00:00 2001 From: skkeye Date: Mon, 10 Feb 2025 00:51:59 -0500 Subject: [PATCH 0737/1217] feat: Feature match udp sockets fix: fixed compile proto-ipv4/v6 edge cases in the ping module --- embassy-net/src/icmp.rs | 245 +++++++++++++++++++++++++++++++--------- 1 file changed, 192 insertions(+), 53 deletions(-) diff --git a/embassy-net/src/icmp.rs b/embassy-net/src/icmp.rs index 68f6fd536..22c31a589 100644 --- a/embassy-net/src/icmp.rs +++ b/embassy-net/src/icmp.rs @@ -1,8 +1,8 @@ //! ICMP sockets. -use core::future::poll_fn; +use core::future::{poll_fn, Future}; use core::mem; -use core::task::Poll; +use core::task::{Context, Poll}; use smoltcp::iface::{Interface, SocketHandle}; pub use smoltcp::phy::ChecksumCapabilities; @@ -36,6 +36,8 @@ pub enum SendError { NoRoute, /// Socket not bound to an outgoing port. SocketNotBound, + /// There is not enough transmit buffer capacity to ever send this packet. + PacketTooLarge, } /// Error returned by [`IcmpSocket::recv_from`]. @@ -109,25 +111,61 @@ impl<'a> IcmpSocket<'a> { }) } - /// Dequeue a packet received from a remote endpoint, copy the payload into the given slice, - /// and return the amount of octets copied as well as the `IpAddress` + /// Wait until the socket becomes readable. /// - /// **Note**: when the size of the provided buffer is smaller than the size of the payload, - /// the packet is dropped and a `RecvError::Truncated` error is returned. - pub async fn recv_from(&self, buf: &mut [u8]) -> Result<(usize, IpAddress), RecvError> { - poll_fn(move |cx| { - self.with_mut(|s, _| match s.recv_slice(buf) { - Ok(x) => Poll::Ready(Ok(x)), - // No data ready - Err(icmp::RecvError::Exhausted) => { - //s.register_recv_waker(cx.waker()); - cx.waker().wake_by_ref(); - Poll::Pending - } - Err(icmp::RecvError::Truncated) => Poll::Ready(Err(RecvError::Truncated)), - }) + /// A socket is readable when a packet has been received, or when there are queued packets in + /// the buffer. + pub fn wait_recv_ready(&self) -> impl Future + '_ { + poll_fn(move |cx| self.poll_recv_ready(cx)) + } + + /// Wait until a datagram can be read. + /// + /// When no datagram is readable, this method will return `Poll::Pending` and + /// register the current task to be notified when a datagram is received. + /// + /// When a datagram is received, this method will return `Poll::Ready`. + pub fn poll_recv_ready(&self, cx: &mut Context<'_>) -> Poll<()> { + self.with_mut(|s, _| { + if s.can_recv() { + Poll::Ready(()) + } else { + // socket buffer is empty wait until at least one byte has arrived + s.register_recv_waker(cx.waker()); + Poll::Pending + } + }) + } + + /// Receive a datagram. + /// + /// This method will wait until a datagram is received. + /// + /// Returns the number of bytes received and the remote endpoint. + pub fn recv_from<'s>( + &'s self, + buf: &'s mut [u8], + ) -> impl Future> + 's { + poll_fn(|cx| self.poll_recv_from(buf, cx)) + } + + /// Receive a datagram. + /// + /// When no datagram is available, this method will return `Poll::Pending` and + /// register the current task to be notified when a datagram is received. + /// + /// When a datagram is received, this method will return `Poll::Ready` with the + /// number of bytes received and the remote endpoint. + pub fn poll_recv_from(&self, buf: &mut [u8], cx: &mut Context<'_>) -> Poll> { + self.with_mut(|s, _| match s.recv_slice(buf) { + Ok((n, meta)) => Poll::Ready(Ok((n, meta))), + // No data ready + Err(icmp::RecvError::Truncated) => Poll::Ready(Err(RecvError::Truncated)), + Err(icmp::RecvError::Exhausted) => { + s.register_recv_waker(cx.waker()); + Poll::Pending + } }) - .await } /// Dequeue a packet received from a remote endpoint and calls the provided function with the @@ -136,7 +174,7 @@ impl<'a> IcmpSocket<'a> { /// /// **Note**: when the size of the provided buffer is smaller than the size of the payload, /// the packet is dropped and a `RecvError::Truncated` error is returned. - pub async fn recv_with(&self, f: F) -> Result + pub async fn recv_from_with(&self, f: F) -> Result where F: FnOnce((&[u8], IpAddress)) -> R, { @@ -154,16 +192,106 @@ impl<'a> IcmpSocket<'a> { .await } - /// Enqueue a packet to be sent to a given remote address, and fill it from a slice. + /// Wait until the socket becomes writable. + /// + /// A socket becomes writable when there is space in the buffer, from initial memory or after + /// dispatching datagrams on a full buffer. + pub fn wait_send_ready(&self) -> impl Future + '_ { + poll_fn(|cx| self.poll_send_ready(cx)) + } + + /// Wait until a datagram can be sent. + /// + /// When no datagram can be sent (i.e. the buffer is full), this method will return + /// `Poll::Pending` and register the current task to be notified when + /// space is freed in the buffer after a datagram has been dispatched. + /// + /// When a datagram can be sent, this method will return `Poll::Ready`. + pub fn poll_send_ready(&self, cx: &mut Context<'_>) -> Poll<()> { + self.with_mut(|s, _| { + if s.can_send() { + Poll::Ready(()) + } else { + // socket buffer is full wait until a datagram has been dispatched + s.register_send_waker(cx.waker()); + Poll::Pending + } + }) + } + + /// Send a datagram to the specified remote endpoint. + /// + /// This method will wait until the datagram has been sent. + /// + /// If the socket's send buffer is too small to fit `buf`, this method will return `Err(SendError::PacketTooLarge)` + /// + /// When the remote endpoint is not reachable, this method will return `Err(SendError::NoRoute)` pub async fn send_to(&self, buf: &[u8], remote_endpoint: T) -> Result<(), SendError> where T: Into, { + let remote_endpoint: IpAddress = remote_endpoint.into(); + poll_fn(move |cx| self.poll_send_to(buf, remote_endpoint, cx)).await + } + + /// Send a datagram to the specified remote endpoint. + /// + /// When the datagram has been sent, this method will return `Poll::Ready(Ok())`. + /// + /// When the socket's send buffer is full, this method will return `Poll::Pending` + /// and register the current task to be notified when the buffer has space available. + /// + /// If the socket's send buffer is too small to fit `buf`, this method will return `Poll::Ready(Err(SendError::PacketTooLarge))` + /// + /// When the remote endpoint is not reachable, this method will return `Poll::Ready(Err(Error::NoRoute))`. + pub fn poll_send_to(&self, buf: &[u8], remote_endpoint: T, cx: &mut Context<'_>) -> Poll> + where + T: Into, + { + // Don't need to wake waker in `with_mut` if the buffer will never fit the icmp tx_buffer. + let send_capacity_too_small = self.with(|s, _| s.payload_send_capacity() < buf.len()); + if send_capacity_too_small { + return Poll::Ready(Err(SendError::PacketTooLarge)); + } + + self.with_mut(|s, _| match s.send_slice(buf, remote_endpoint.into()) { + // Entire datagram has been sent + Ok(()) => Poll::Ready(Ok(())), + Err(icmp::SendError::BufferFull) => { + s.register_send_waker(cx.waker()); + Poll::Pending + } + Err(icmp::SendError::Unaddressable) => { + // If no sender/outgoing port is specified, there is not really "no route" + if s.is_open() { + Poll::Ready(Err(SendError::NoRoute)) + } else { + Poll::Ready(Err(SendError::SocketNotBound)) + } + } + }) + } + + /// Enqueue a packet to be sent to a given remote address with a zero-copy function. + /// + /// This method will wait until the buffer can fit the requested size before + /// calling the function to fill its contents. + pub async fn send_to_with(&mut self, size: usize, remote_endpoint: T, f: F) -> Result + where + T: Into, + F: FnOnce(&mut [u8]) -> R, + { + // Don't need to wake waker in `with_mut` if the buffer will never fit the icmp tx_buffer. + let send_capacity_too_small = self.with(|s, _| s.payload_send_capacity() < size); + if send_capacity_too_small { + return Err(SendError::PacketTooLarge); + } + + let mut f = Some(f); let remote_endpoint = remote_endpoint.into(); poll_fn(move |cx| { - self.with_mut(|s, _| match s.send_slice(buf, remote_endpoint) { - // Entire datagram has been sent - Ok(()) => Poll::Ready(Ok(())), + self.with_mut(|s, _| match s.send(size, remote_endpoint) { + Ok(buf) => Poll::Ready(Ok({ unwrap!(f.take())(buf) })), Err(icmp::SendError::BufferFull) => { s.register_send_waker(cx.waker()); Poll::Pending @@ -174,28 +302,20 @@ impl<'a> IcmpSocket<'a> { .await } - /// Enqueue a packet to be sent to a given remote address with a zero-copy function. + /// Flush the socket. /// - /// This method will wait until the buffer can fit the requested size before - /// calling the function to fill its contents. - pub async fn send_to_with(&self, size: usize, remote_endpoint: T, f: F) -> Result - where - T: Into, - F: FnOnce(&mut [u8]) -> R, - { - let mut f = Some(f); - let remote_endpoint = remote_endpoint.into(); - poll_fn(move |cx| { - self.with_mut(|s, _| match s.send(size, remote_endpoint) { - Ok(buf) => Poll::Ready(Ok(unwrap!(f.take())(buf))), - Err(icmp::SendError::BufferFull) => { + /// This method will wait until the socket is flushed. + pub fn flush(&mut self) -> impl Future + '_ { + poll_fn(|cx| { + self.with_mut(|s, _| { + if s.send_queue() == 0 { + Poll::Ready(()) + } else { s.register_send_waker(cx.waker()); Poll::Pending } - Err(icmp::SendError::Unaddressable) => Poll::Ready(Err(SendError::NoRoute)), }) }) - .await } /// Check whether the socket is open. @@ -280,9 +400,15 @@ pub mod ping { //! }; //! ``` - use core::net::{IpAddr, Ipv6Addr}; + use core::net::IpAddr; + #[cfg(feature = "proto-ipv6")] + use core::net::Ipv6Addr; use embassy_time::{Duration, Instant, Timer, WithTimeout}; + #[cfg(feature = "proto-ipv6")] + use smoltcp::wire::IpAddress; + #[cfg(feature = "proto-ipv6")] + use smoltcp::wire::Ipv6Address; use super::*; @@ -392,11 +518,11 @@ pub mod ping { // make a single ping // - shorts out errors // - select the ip version - let ping_duration = match params.target().unwrap() { + let ping_duration = match params.target.unwrap() { #[cfg(feature = "proto-ipv4")] - IpAddr::V4(_) => self.single_ping_v4(params, seq_no).await?, + IpAddress::Ipv4(_) => self.single_ping_v4(params, seq_no).await?, #[cfg(feature = "proto-ipv6")] - IpAddr::V6(_) => self.single_ping_v6(params, seq_no).await?, + IpAddress::Ipv6(_) => self.single_ping_v6(params, seq_no).await?, }; // safely add up the durations of each ping @@ -478,7 +604,7 @@ pub mod ping { // Helper function to recieve and return the correct echo reply when it finds it async fn recv_pong(socket: &IcmpSocket<'_>, seq_no: u16) -> Result<(), PingError> { - while match socket.recv_with(|(buf, _)| filter_pong(buf, seq_no)).await { + while match socket.recv_from_with(|(buf, _)| filter_pong(buf, seq_no)).await { Ok(b) => !b, Err(e) => return Err(PingError::SocketRecvError(e)), } {} @@ -548,7 +674,7 @@ pub mod ping { // Helper function to recieve and return the correct echo reply when it finds it async fn recv_pong(socket: &IcmpSocket<'_>, seq_no: u16) -> Result<(), PingError> { - while match socket.recv_with(|(buf, _)| filter_pong(buf, seq_no)).await { + while match socket.recv_from_with(|(buf, _)| filter_pong(buf, seq_no)).await { Ok(b) => !b, Err(e) => return Err(PingError::SocketRecvError(e)), } {} @@ -581,9 +707,9 @@ pub mod ping { /// * `timeout` - The timeout duration before returning a [`PingError::DestinationHostUnreachable`] error. /// * `rate_limit` - The minimum time per echo request. pub struct PingParams<'a> { - target: Option, + target: Option, #[cfg(feature = "proto-ipv6")] - source: Option, + source: Option, payload: &'a [u8], hop_limit: Option, count: u16, @@ -610,7 +736,7 @@ pub mod ping { /// Creates a new instance of [`PingParams`] with the specified target IP address. pub fn new>(target: T) -> Self { Self { - target: Some(target.into()), + target: Some(PingParams::ip_addr_to_smoltcp(target)), #[cfg(feature = "proto-ipv6")] source: None, payload: b"embassy-net", @@ -621,21 +747,34 @@ pub mod ping { } } + fn ip_addr_to_smoltcp>(ip_addr: T) -> IpAddress { + match ip_addr.into() { + #[cfg(feature = "proto-ipv4")] + IpAddr::V4(v4) => IpAddress::Ipv4(v4), + #[cfg(not(feature = "proto-ipv4"))] + IpAddr::V4(_) => unreachable!(), + #[cfg(feature = "proto-ipv6")] + IpAddr::V6(v6) => IpAddress::Ipv6(v6), + #[cfg(not(feature = "proto-ipv6"))] + IpAddr::V6(_) => unreachable!(), + } + } + /// Sets the target IP address for the ping. pub fn set_target>(&mut self, target: T) -> &mut Self { - self.target = Some(target.into()); + self.target = Some(PingParams::ip_addr_to_smoltcp(target)); self } /// Retrieves the target IP address for the ping. pub fn target(&self) -> Option { - self.target + self.target.map(|t| t.into()) } /// Sets the source IP address for the ping (IPv6 only). #[cfg(feature = "proto-ipv6")] - pub fn set_source(&mut self, source: Ipv6Addr) -> &mut Self { - self.source = Some(source); + pub fn set_source>(&mut self, source: T) -> &mut Self { + self.source = Some(source.into()); self } From 9b178facc95bc5fdcf43dddd0a2904e65fda41d6 Mon Sep 17 00:00:00 2001 From: skkeye Date: Mon, 10 Feb 2025 00:58:17 -0500 Subject: [PATCH 0738/1217] fix: update example --- examples/rp/src/bin/ethernet_w5500_icmp.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/rp/src/bin/ethernet_w5500_icmp.rs b/examples/rp/src/bin/ethernet_w5500_icmp.rs index 5f336b579..5c42b2dde 100644 --- a/examples/rp/src/bin/ethernet_w5500_icmp.rs +++ b/examples/rp/src/bin/ethernet_w5500_icmp.rs @@ -117,7 +117,7 @@ async fn main(spawner: Spawner) { // Recieve and log the data of the reply socket - .recv_with(|(buf, addr)| { + .recv_from_with(|(buf, addr)| { let packet = Icmpv4Packet::new_checked(buf).unwrap(); info!( "Recieved {:?} from {} in {}ms", From 610804f138708e616ed6a7d8324982b009a832d6 Mon Sep 17 00:00:00 2001 From: nikvoid Date: Thu, 13 Feb 2025 15:15:47 +0200 Subject: [PATCH 0739/1217] stm32: read microsecond from RTC --- embassy-stm32/src/rtc/datetime.rs | 21 ++++++++++++++++++++- embassy-stm32/src/rtc/mod.rs | 14 ++++++++++++-- examples/stm32g0/src/bin/rtc.rs | 2 +- 3 files changed, 33 insertions(+), 4 deletions(-) diff --git a/embassy-stm32/src/rtc/datetime.rs b/embassy-stm32/src/rtc/datetime.rs index 32732e96e..e18349e59 100644 --- a/embassy-stm32/src/rtc/datetime.rs +++ b/embassy-stm32/src/rtc/datetime.rs @@ -21,6 +21,8 @@ pub enum Error { InvalidMinute, /// The [DateTime] contains an invalid second value. Must be between `0..=59`. InvalidSecond, + /// The [DateTime] contains an invalid microsecond value. Must be between `0..=999_999`. + InvalidMicrosecond, } /// Structure containing date and time information @@ -39,6 +41,8 @@ pub struct DateTime { minute: u8, /// 0..59 second: u8, + /// 0..999_999 + usecond: u32, } impl DateTime { @@ -77,6 +81,11 @@ impl DateTime { self.second } + /// Get the microsecond (0..=999_999) + pub const fn microsecond(&self) -> u32 { + self.usecond + } + /// Create a new DateTime with the given information. pub fn from( year: u16, @@ -86,6 +95,7 @@ impl DateTime { hour: u8, minute: u8, second: u8, + usecond: u32, ) -> Result { if year > 4095 { Err(Error::InvalidYear) @@ -99,6 +109,8 @@ impl DateTime { Err(Error::InvalidMinute) } else if second > 59 { Err(Error::InvalidSecond) + } else if usecond > 999_999 { + Err(Error::InvalidMicrosecond) } else { Ok(Self { year, @@ -108,6 +120,7 @@ impl DateTime { hour, minute, second, + usecond, }) } } @@ -124,6 +137,7 @@ impl From for DateTime { hour: date_time.hour() as u8, minute: date_time.minute() as u8, second: date_time.second() as u8, + usecond: date_time.and_utc().timestamp_subsec_micros(), } } } @@ -133,7 +147,12 @@ impl From for chrono::NaiveDateTime { fn from(date_time: DateTime) -> Self { NaiveDate::from_ymd_opt(date_time.year as i32, date_time.month as u32, date_time.day as u32) .unwrap() - .and_hms_opt(date_time.hour as u32, date_time.minute as u32, date_time.second as u32) + .and_hms_micro_opt( + date_time.hour as u32, + date_time.minute as u32, + date_time.second as u32, + date_time.usecond, + ) .unwrap() } } diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs index 1a668cb37..875184c90 100644 --- a/embassy-stm32/src/rtc/mod.rs +++ b/embassy-stm32/src/rtc/mod.rs @@ -59,7 +59,7 @@ impl RtcTimeProvider { /// /// Will return an `RtcError::InvalidDateTime` if the stored value in the system is not a valid [`DayOfWeek`]. pub fn now(&self) -> Result { - self.read(|dr, tr, _| { + self.read(|dr, tr, _ss| { let second = bcd2_to_byte((tr.st(), tr.su())); let minute = bcd2_to_byte((tr.mnt(), tr.mnu())); let hour = bcd2_to_byte((tr.ht(), tr.hu())); @@ -69,7 +69,17 @@ impl RtcTimeProvider { let month = bcd2_to_byte((dr.mt() as u8, dr.mu())); let year = bcd2_to_byte((dr.yt(), dr.yu())) as u16 + 2000_u16; - DateTime::from(year, month, day, weekday, hour, minute, second).map_err(RtcError::InvalidDateTime) + // Calculate second fraction and multiply to microseconds + // Formula from RM0410 + #[cfg(not(rtc_v2f2))] + let us = { + let prediv = RTC::regs().prer().read().prediv_s() as f32; + (((prediv - _ss as f32) / (prediv + 1.0)) * 1e6).min(999_999.0) as u32 + }; + #[cfg(rtc_v2f2)] + let us = 0; + + DateTime::from(year, month, day, weekday, hour, minute, second, us).map_err(RtcError::InvalidDateTime) }) } diff --git a/examples/stm32g0/src/bin/rtc.rs b/examples/stm32g0/src/bin/rtc.rs index c02c1ecd7..50fb6398e 100644 --- a/examples/stm32g0/src/bin/rtc.rs +++ b/examples/stm32g0/src/bin/rtc.rs @@ -15,7 +15,7 @@ async fn main(_spawner: Spawner) { info!("Hello World!"); - let now = DateTime::from(2023, 6, 14, DayOfWeek::Friday, 15, 59, 10); + let now = DateTime::from(2023, 6, 14, DayOfWeek::Friday, 15, 59, 10, 0); let mut rtc = Rtc::new(p.RTC, RtcConfig::default()); From 29d05328f9b33953b8476ca3a5a7b1e3c9adeaf2 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Fri, 14 Feb 2025 06:47:59 +0100 Subject: [PATCH 0740/1217] chore: prepare embassy-net release --- embassy-net/CHANGELOG.md | 5 +++++ embassy-net/Cargo.toml | 2 +- examples/nrf52840/Cargo.toml | 2 +- examples/nrf5340/Cargo.toml | 2 +- examples/nrf9160/Cargo.toml | 2 +- examples/rp/Cargo.toml | 2 +- examples/rp23/Cargo.toml | 2 +- examples/std/Cargo.toml | 2 +- examples/stm32f4/Cargo.toml | 2 +- examples/stm32f7/Cargo.toml | 2 +- examples/stm32h5/Cargo.toml | 2 +- examples/stm32h7/Cargo.toml | 2 +- examples/stm32h755cm4/Cargo.toml | 2 +- examples/stm32h755cm7/Cargo.toml | 2 +- examples/stm32h7b0/Cargo.toml | 2 +- examples/stm32h7rs/Cargo.toml | 2 +- examples/stm32l4/Cargo.toml | 2 +- examples/stm32l5/Cargo.toml | 2 +- examples/stm32wb/Cargo.toml | 2 +- examples/stm32wba/Cargo.toml | 2 +- tests/nrf/Cargo.toml | 2 +- tests/perf-client/Cargo.toml | 2 +- tests/rp/Cargo.toml | 2 +- tests/stm32/Cargo.toml | 2 +- 24 files changed, 28 insertions(+), 23 deletions(-) diff --git a/embassy-net/CHANGELOG.md b/embassy-net/CHANGELOG.md index 0b98e213e..cfee5f3cf 100644 --- a/embassy-net/CHANGELOG.md +++ b/embassy-net/CHANGELOG.md @@ -9,6 +9,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 No unreleased changes yet... Quick, go send a PR! +## 0.7 - 2025-02-14 + +- don't infinite loop if udp::send methods receive a buffer too large to ever be sent +- add ICMP sockets and a ping utility + ## 0.6 - 2025-01-05 - Make `Config` constructors `const` diff --git a/embassy-net/Cargo.toml b/embassy-net/Cargo.toml index eda372cb6..f4e30e720 100644 --- a/embassy-net/Cargo.toml +++ b/embassy-net/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "embassy-net" -version = "0.6.0" +version = "0.7.0" edition = "2021" license = "MIT OR Apache-2.0" description = "Async TCP/IP network stack for embedded systems" diff --git a/examples/nrf52840/Cargo.toml b/examples/nrf52840/Cargo.toml index f48cbf586..f479d6af6 100644 --- a/examples/nrf52840/Cargo.toml +++ b/examples/nrf52840/Cargo.toml @@ -10,7 +10,7 @@ embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["de embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.3.1", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } -embassy-net = { version = "0.6.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } +embassy-net = { version = "0.7.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defmt"] } embedded-io = { version = "0.6.0", features = ["defmt-03"] } embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } diff --git a/examples/nrf5340/Cargo.toml b/examples/nrf5340/Cargo.toml index 93bec8668..2a83633b4 100644 --- a/examples/nrf5340/Cargo.toml +++ b/examples/nrf5340/Cargo.toml @@ -10,7 +10,7 @@ embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["de embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.3.1", path = "../../embassy-nrf", features = ["defmt", "nrf5340-app-s", "time-driver-rtc1", "gpiote", "unstable-pac"] } -embassy-net = { version = "0.6.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } +embassy-net = { version = "0.7.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defmt"] } embedded-io-async = { version = "0.6.1" } diff --git a/examples/nrf9160/Cargo.toml b/examples/nrf9160/Cargo.toml index 0ed8faf3b..6965ce202 100644 --- a/examples/nrf9160/Cargo.toml +++ b/examples/nrf9160/Cargo.toml @@ -9,7 +9,7 @@ embassy-executor = { version = "0.7.0", path = "../../embassy-executor", feature embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.3.1", path = "../../embassy-nrf", features = ["defmt", "nrf9160-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } embassy-net-nrf91 = { version = "0.1.0", path = "../../embassy-net-nrf91", features = ["defmt"] } -embassy-net = { version = "0.6.0", path = "../../embassy-net", features = ["defmt", "tcp", "proto-ipv4", "medium-ip"] } +embassy-net = { version = "0.7.0", path = "../../embassy-net", features = ["defmt", "tcp", "proto-ipv4", "medium-ip"] } defmt = "0.3" defmt-rtt = "0.4" diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index c7823a711..e05c88a9a 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml @@ -12,7 +12,7 @@ embassy-executor = { version = "0.7.0", path = "../../embassy-executor", feature embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-rp = { version = "0.3.0", path = "../../embassy-rp", features = ["defmt", "unstable-pac", "time-driver", "critical-section-impl", "rp2040"] } embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defmt"] } -embassy-net = { version = "0.6.0", path = "../../embassy-net", features = ["defmt", "icmp", "tcp", "udp", "raw", "dhcpv4", "medium-ethernet", "dns", "proto-ipv4", "proto-ipv6", "multicast"] } +embassy-net = { version = "0.7.0", path = "../../embassy-net", features = ["defmt", "icmp", "tcp", "udp", "raw", "dhcpv4", "medium-ethernet", "dns", "proto-ipv4", "proto-ipv6", "multicast"] } embassy-net-wiznet = { version = "0.2.0", path = "../../embassy-net-wiznet", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-usb-logger = { version = "0.4.0", path = "../../embassy-usb-logger" } diff --git a/examples/rp23/Cargo.toml b/examples/rp23/Cargo.toml index 9cfaf8a3f..b7e7dd69a 100644 --- a/examples/rp23/Cargo.toml +++ b/examples/rp23/Cargo.toml @@ -12,7 +12,7 @@ embassy-executor = { version = "0.7.0", path = "../../embassy-executor", feature embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-rp = { version = "0.3.0", path = "../../embassy-rp", features = ["defmt", "unstable-pac", "time-driver", "critical-section-impl", "rp235xa", "binary-info"] } embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defmt"] } -embassy-net = { version = "0.6.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "raw", "dhcpv4", "medium-ethernet", "dns"] } +embassy-net = { version = "0.7.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "raw", "dhcpv4", "medium-ethernet", "dns"] } embassy-net-wiznet = { version = "0.2.0", path = "../../embassy-net-wiznet", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-usb-logger = { version = "0.4.0", path = "../../embassy-usb-logger" } diff --git a/examples/std/Cargo.toml b/examples/std/Cargo.toml index b67e5e817..a32e75d08 100644 --- a/examples/std/Cargo.toml +++ b/examples/std/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["log"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-std", "executor-thread", "log"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["log", "std", ] } -embassy-net = { version = "0.6.0", path = "../../embassy-net", features=[ "log", "medium-ethernet", "medium-ip", "tcp", "udp", "dns", "dhcpv4", "proto-ipv6"] } +embassy-net = { version = "0.7.0", path = "../../embassy-net", features=[ "log", "medium-ethernet", "medium-ip", "tcp", "udp", "dns", "dhcpv4", "proto-ipv6"] } embassy-net-tuntap = { version = "0.1.0", path = "../../embassy-net-tuntap" } embassy-net-ppp = { version = "0.2.0", path = "../../embassy-net-ppp", features = ["log"]} embedded-io-async = { version = "0.6.1" } diff --git a/examples/stm32f4/Cargo.toml b/examples/stm32f4/Cargo.toml index 8b145a01e..e611564eb 100644 --- a/examples/stm32f4/Cargo.toml +++ b/examples/stm32f4/Cargo.toml @@ -11,7 +11,7 @@ embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["de embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defmt" ] } -embassy-net = { version = "0.6.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", ] } +embassy-net = { version = "0.7.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", ] } embassy-net-wiznet = { version = "0.2.0", path = "../../embassy-net-wiznet", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32f7/Cargo.toml b/examples/stm32f7/Cargo.toml index 1f2eae539..e8b246184 100644 --- a/examples/stm32f7/Cargo.toml +++ b/examples/stm32f7/Cargo.toml @@ -10,7 +10,7 @@ embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [" embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } -embassy-net = { version = "0.6.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } +embassy-net = { version = "0.7.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } embedded-io-async = { version = "0.6.1" } embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32h5/Cargo.toml b/examples/stm32h5/Cargo.toml index 99101144e..5b80e5486 100644 --- a/examples/stm32h5/Cargo.toml +++ b/examples/stm32h5/Cargo.toml @@ -10,7 +10,7 @@ embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [" embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } -embassy-net = { version = "0.6.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6"] } +embassy-net = { version = "0.7.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6"] } embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32h7/Cargo.toml b/examples/stm32h7/Cargo.toml index 8730693c8..4c18bb21c 100644 --- a/examples/stm32h7/Cargo.toml +++ b/examples/stm32h7/Cargo.toml @@ -11,7 +11,7 @@ embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["de embassy-embedded-hal = { version = "0.3.0", path = "../../embassy-embedded-hal" } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } -embassy-net = { version = "0.6.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } +embassy-net = { version = "0.7.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32h755cm4/Cargo.toml b/examples/stm32h755cm4/Cargo.toml index 01e7ffcbf..e3efa0aa2 100644 --- a/examples/stm32h755cm4/Cargo.toml +++ b/examples/stm32h755cm4/Cargo.toml @@ -11,7 +11,7 @@ embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["de embassy-embedded-hal = { version = "0.3.0", path = "../../embassy-embedded-hal" } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } -embassy-net = { version = "0.6.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } +embassy-net = { version = "0.7.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32h755cm7/Cargo.toml b/examples/stm32h755cm7/Cargo.toml index 67d270bdb..1f05c71b5 100644 --- a/examples/stm32h755cm7/Cargo.toml +++ b/examples/stm32h755cm7/Cargo.toml @@ -11,7 +11,7 @@ embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["de embassy-embedded-hal = { version = "0.3.0", path = "../../embassy-embedded-hal" } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } -embassy-net = { version = "0.6.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } +embassy-net = { version = "0.7.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32h7b0/Cargo.toml b/examples/stm32h7b0/Cargo.toml index 67ae54047..e0db3c0cd 100644 --- a/examples/stm32h7b0/Cargo.toml +++ b/examples/stm32h7b0/Cargo.toml @@ -10,7 +10,7 @@ embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["de embassy-embedded-hal = { version = "0.3.0", path = "../../embassy-embedded-hal" } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } -embassy-net = { version = "0.6.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } +embassy-net = { version = "0.7.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32h7rs/Cargo.toml b/examples/stm32h7rs/Cargo.toml index d53c546f2..6564fffbf 100644 --- a/examples/stm32h7rs/Cargo.toml +++ b/examples/stm32h7rs/Cargo.toml @@ -10,7 +10,7 @@ embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [" embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } -embassy-net = { version = "0.6.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } +embassy-net = { version = "0.7.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32l4/Cargo.toml b/examples/stm32l4/Cargo.toml index 76e2b1e6e..495c12936 100644 --- a/examples/stm32l4/Cargo.toml +++ b/examples/stm32l4/Cargo.toml @@ -13,7 +13,7 @@ embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["de embassy-embedded-hal = { version = "0.3.0", path = "../../embassy-embedded-hal" } embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defmt"] } embassy-net-adin1110 = { version = "0.3.0", path = "../../embassy-net-adin1110" } -embassy-net = { version = "0.6.0", path = "../../embassy-net", features = ["defmt", "udp", "tcp", "dhcpv4", "medium-ethernet"] } +embassy-net = { version = "0.7.0", path = "../../embassy-net", features = ["defmt", "udp", "tcp", "dhcpv4", "medium-ethernet"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } embedded-io = { version = "0.6.0", features = ["defmt-03"] } diff --git a/examples/stm32l5/Cargo.toml b/examples/stm32l5/Cargo.toml index 0fe5876c8..7894abb38 100644 --- a/examples/stm32l5/Cargo.toml +++ b/examples/stm32l5/Cargo.toml @@ -11,7 +11,7 @@ embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["de embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defmt"] } -embassy-net = { version = "0.6.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } +embassy-net = { version = "0.7.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } usbd-hid = "0.8.1" diff --git a/examples/stm32wb/Cargo.toml b/examples/stm32wb/Cargo.toml index 4a5c79053..e9959b905 100644 --- a/examples/stm32wb/Cargo.toml +++ b/examples/stm32wb/Cargo.toml @@ -11,7 +11,7 @@ embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", fea embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } -embassy-net = { version = "0.6.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", ], optional=true } +embassy-net = { version = "0.7.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", ], optional=true } defmt = "0.3" defmt-rtt = "0.4" diff --git a/examples/stm32wba/Cargo.toml b/examples/stm32wba/Cargo.toml index dd1ce21d9..0f55bee39 100644 --- a/examples/stm32wba/Cargo.toml +++ b/examples/stm32wba/Cargo.toml @@ -9,7 +9,7 @@ embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [ embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } -embassy-net = { version = "0.6.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", ], optional=true } +embassy-net = { version = "0.7.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", ], optional=true } defmt = "0.3" defmt-rtt = "0.4" diff --git a/tests/nrf/Cargo.toml b/tests/nrf/Cargo.toml index 3f76031f0..6aa5e2bcc 100644 --- a/tests/nrf/Cargo.toml +++ b/tests/nrf/Cargo.toml @@ -13,7 +13,7 @@ embassy-executor = { version = "0.7.0", path = "../../embassy-executor", feature embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.3.1", path = "../../embassy-nrf", features = ["defmt", "time-driver-rtc1", "gpiote", "unstable-pac"] } embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } -embassy-net = { version = "0.6.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", ] } +embassy-net = { version = "0.7.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", ] } embassy-net-esp-hosted = { version = "0.2.0", path = "../../embassy-net-esp-hosted", features = ["defmt"] } embassy-net-enc28j60 = { version = "0.2.0", path = "../../embassy-net-enc28j60", features = ["defmt"] } embedded-hal-async = { version = "1.0" } diff --git a/tests/perf-client/Cargo.toml b/tests/perf-client/Cargo.toml index 7af6a4af2..9620972c3 100644 --- a/tests/perf-client/Cargo.toml +++ b/tests/perf-client/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" edition = "2021" [dependencies] -embassy-net = { version = "0.6.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4"] } +embassy-net = { version = "0.7.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", ] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } defmt = "0.3" diff --git a/tests/rp/Cargo.toml b/tests/rp/Cargo.toml index 03e387886..5a6a6c75a 100644 --- a/tests/rp/Cargo.toml +++ b/tests/rp/Cargo.toml @@ -12,7 +12,7 @@ embassy-executor = { version = "0.7.0", path = "../../embassy-executor", feature embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", ] } embassy-rp = { version = "0.3.0", path = "../../embassy-rp", features = [ "defmt", "unstable-pac", "time-driver", "critical-section-impl", "intrinsics", "rom-v2-intrinsics", "run-from-ram", "rp2040"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } -embassy-net = { version = "0.6.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "dhcpv4", "medium-ethernet"] } +embassy-net = { version = "0.7.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "dhcpv4", "medium-ethernet"] } embassy-net-wiznet = { version = "0.2.0", path = "../../embassy-net-wiznet", features = ["defmt"] } embassy-embedded-hal = { version = "0.3.0", path = "../../embassy-embedded-hal/"} cyw43 = { path = "../../cyw43", features = ["defmt", "firmware-logs"] } diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml index 0b96ab503..9c3b2780a 100644 --- a/tests/stm32/Cargo.toml +++ b/tests/stm32/Cargo.toml @@ -65,7 +65,7 @@ embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["de embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "memory-x", "time-driver-any"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", optional = true, features = ["defmt", "stm32wb55rg", "ble"] } -embassy-net = { version = "0.6.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "dhcpv4", "medium-ethernet"] } +embassy-net = { version = "0.7.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "dhcpv4", "medium-ethernet"] } perf-client = { path = "../perf-client" } defmt = "0.3" From 2098500e051c19865423530d7954f1916a847848 Mon Sep 17 00:00:00 2001 From: Skkeye Date: Fri, 14 Feb 2025 12:48:53 -0500 Subject: [PATCH 0741/1217] fix: embassy-net icmp feature docs --- embassy-net/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-net/Cargo.toml b/embassy-net/Cargo.toml index f4e30e720..1e513a9ea 100644 --- a/embassy-net/Cargo.toml +++ b/embassy-net/Cargo.toml @@ -16,11 +16,11 @@ categories = [ [package.metadata.embassy_docs] src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-v$VERSION/embassy-net/src/" src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-net/src/" -features = ["defmt", "tcp", "udp", "raw", "dns", "dhcpv4", "proto-ipv6", "medium-ethernet", "medium-ip", "medium-ieee802154", "multicast", "dhcpv4-hostname"] +features = ["defmt", "tcp", "udp", "raw", "dns", "icmp", "dhcpv4", "proto-ipv6", "medium-ethernet", "medium-ip", "medium-ieee802154", "multicast", "dhcpv4-hostname"] target = "thumbv7em-none-eabi" [package.metadata.docs.rs] -features = ["defmt", "tcp", "udp", "raw", "dns", "dhcpv4", "proto-ipv6", "medium-ethernet", "medium-ip", "medium-ieee802154", "multicast", "dhcpv4-hostname"] +features = ["defmt", "tcp", "udp", "raw", "dns", "icmp", "dhcpv4", "proto-ipv6", "medium-ethernet", "medium-ip", "medium-ieee802154", "multicast", "dhcpv4-hostname"] [features] ## Enable defmt From b30ee6380b97569d9c044a01f2a3f5fa6ad6eecb Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Fri, 14 Feb 2025 22:30:33 +0100 Subject: [PATCH 0742/1217] tests/rp: Update cyw43 test to new firmware, new wifi network name. --- tests/rp/src/bin/cyw43-perf.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/tests/rp/src/bin/cyw43-perf.rs b/tests/rp/src/bin/cyw43-perf.rs index 34119722b..dba1058a8 100644 --- a/tests/rp/src/bin/cyw43-perf.rs +++ b/tests/rp/src/bin/cyw43-perf.rs @@ -21,7 +21,7 @@ bind_interrupts!(struct Irqs { teleprobe_meta::timeout!(120); // Test-only wifi network, no internet access! -const WIFI_NETWORK: &str = "EmbassyTest"; +const WIFI_NETWORK: &str = "EmbassyTestWPA2"; const WIFI_PASSWORD: &str = "V8YxhKt5CdIAJFud"; #[embassy_executor::task] @@ -47,9 +47,11 @@ async fn main(spawner: Spawner) { // cyw43 firmware needs to be flashed manually: // probe-rs download 43439A0.bin --binary-format bin --chip RP2040 --base-address 0x101b0000 + // probe-rs download 43439A0_btfw.bin --binary-format bin --chip RP2040 --base-address 0x101f0000 // probe-rs download 43439A0_clm.bin --binary-format bin --chip RP2040 --base-address 0x101f8000 - let fw = unsafe { core::slice::from_raw_parts(0x101b0000 as *const u8, 230321) }; - let clm = unsafe { core::slice::from_raw_parts(0x101f8000 as *const u8, 4752) }; + let fw = unsafe { core::slice::from_raw_parts(0x101b0000 as *const u8, 231077) }; + let _btfw = unsafe { core::slice::from_raw_parts(0x101f0000 as *const u8, 6164) }; + let clm = unsafe { core::slice::from_raw_parts(0x101f8000 as *const u8, 984) }; let pwr = Output::new(p.PIN_23, Level::Low); let cs = Output::new(p.PIN_25, Level::High); @@ -104,9 +106,9 @@ async fn main(spawner: Spawner) { perf_client::run( stack, perf_client::Expected { - down_kbps: 300, - up_kbps: 300, - updown_kbps: 300, + down_kbps: 200, + up_kbps: 200, + updown_kbps: 200, }, ) .await; From 7f4cce536aa14010b723885bdf632f0f22182cb1 Mon Sep 17 00:00:00 2001 From: Fredrik Reinholdsen Date: Sat, 15 Feb 2025 12:05:16 +0100 Subject: [PATCH 0743/1217] fix: Fix for async I2C v2 driver sequential read/write reads. Fixes #3887 For I2C devices that support variable length reads, sending chunks of data as long as the master keeps ACK:ing after each received byte, sequential reads will sometimes get out of sync, causing additional reads to return invalid data. This was caused by a delay between awaiting the DMA read and sending the software STOP signal, which may result in the slave to have time to send a byte of data in between, causing potential miss-alignment. This would then cause subsequent reads to return invalid data. Async write-reads now no longer send STOP after the initial write, matching the behaviour of the blocking version. --- embassy-stm32/src/i2c/v2.rs | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs index 05ac9afcc..8801fddf0 100644 --- a/embassy-stm32/src/i2c/v2.rs +++ b/embassy-stm32/src/i2c/v2.rs @@ -438,6 +438,7 @@ impl<'d> I2c<'d, Async> { write: &[u8], first_slice: bool, last_slice: bool, + send_stop: bool, timeout: Timeout, ) -> Result<(), Error> { let total_len = write.len(); @@ -505,10 +506,12 @@ impl<'d> I2c<'d, Async> { .await?; dma_transfer.await; - if last_slice { // This should be done already self.wait_tc(timeout)?; + } + + if last_slice & send_stop { self.master_stop(); } @@ -556,16 +559,16 @@ impl<'d> I2c<'d, Async> { self.info, address, total_len.min(255), - Stop::Software, + Stop::Automatic, total_len > 255, restart, timeout, )?; + } else if remaining_len == 0 { + return Poll::Ready(Ok(())); } else if !(isr.tcr() || isr.tc()) { // poll_fn was woken without an interrupt present return Poll::Pending; - } else if remaining_len == 0 { - return Poll::Ready(Ok(())); } else { let last_piece = remaining_len <= 255; @@ -581,11 +584,6 @@ impl<'d> I2c<'d, Async> { .await?; dma_transfer.await; - - // This should be done already - self.wait_tc(timeout)?; - self.master_stop(); - drop(on_drop); Ok(()) @@ -601,7 +599,7 @@ impl<'d> I2c<'d, Async> { self.write_internal(address, write, true, timeout) } else { timeout - .with(self.write_dma_internal(address, write, true, true, timeout)) + .with(self.write_dma_internal(address, write, true, true, true, timeout)) .await } } @@ -623,7 +621,7 @@ impl<'d> I2c<'d, Async> { let next = iter.next(); let is_last = next.is_none(); - let fut = self.write_dma_internal(address, c, first, is_last, timeout); + let fut = self.write_dma_internal(address, c, first, is_last, is_last, timeout); timeout.with(fut).await?; first = false; current = next; @@ -650,7 +648,7 @@ impl<'d> I2c<'d, Async> { if write.is_empty() { self.write_internal(address, write, false, timeout)?; } else { - let fut = self.write_dma_internal(address, write, true, true, timeout); + let fut = self.write_dma_internal(address, write, true, true, false, timeout); timeout.with(fut).await?; } From cb4fb6642498c424dc30df7fea939a55f14a31b6 Mon Sep 17 00:00:00 2001 From: 9names <60134748+9names@users.noreply.github.com> Date: Sun, 16 Feb 2025 13:07:34 +1100 Subject: [PATCH 0744/1217] Use probe-rs as default runner for rp23 examples --- examples/rp23/.cargo/config.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/rp23/.cargo/config.toml b/examples/rp23/.cargo/config.toml index 9a92b1ce2..40f245785 100644 --- a/examples/rp23/.cargo/config.toml +++ b/examples/rp23/.cargo/config.toml @@ -1,7 +1,7 @@ [target.'cfg(all(target_arch = "arm", target_os = "none"))'] -#runner = "probe-rs run --chip RP2040" +runner = "probe-rs run --chip RP235x" #runner = "elf2uf2-rs -d" -runner = "picotool load -u -v -x -t elf" +#runner = "picotool load -u -v -x -t elf" [build] target = "thumbv8m.main-none-eabihf" From 4cc5ab9474773148dd8976e22f3fb6f5e270cd3a Mon Sep 17 00:00:00 2001 From: 9names <60134748+9names@users.noreply.github.com> Date: Sun, 16 Feb 2025 12:34:48 +1100 Subject: [PATCH 0745/1217] Add rp235x imagedef features (based on rp2040 boot2 features) rp235x firmwares need an Image Definition if they want to be called from the rp235x bootrom. Currently this Image Definition is manually added to each project/example, but for most users it will always be the default (Secure Exe). This commit adds crate features to allow users to configure this, with the default of including a Secure Exe Image Definition in. Just like the boot2-* features, this includes an opt-out (imagedef-none) to allow the user to not make use of this included Image Definition. --- embassy-rp/Cargo.toml | 25 ++++++++++++++++++++++++- embassy-rp/src/lib.rs | 24 ++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index 4e5c66feb..d65e281ee 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml @@ -83,7 +83,7 @@ boot2-ram-memcpy = [] boot2-w25q080 = [] ## Use boot2 with support for Winbond W25X10CL SPI flash. boot2-w25x10cl = [] -## Have embassy not provide the boot2 so you can use your own. +## Have embassy-rp not provide the boot2 so you can use your own. ## Place your own in the ".boot2" section like: ## ``` ## #[link_section = ".boot2"] @@ -92,6 +92,29 @@ boot2-w25x10cl = [] ## ``` boot2-none = [] +#! ### Image Definition support +#! RP2350's internal bootloader will only execute firmware if it has a valid Image Definition. +#! There are other tags that can be used (for example, you can tag an image as "DATA") +#! but programs will want to have an exe header. "SECURE_EXE" is usually what you want. +#! Use imagedef-none if you want to configure the Image Definition manually +#! If none are selected, imagedef-secure-exe will be used + +## Image is executable and starts in Secure mode +imagedef-secure-exe = [] +## Image is executable and starts in Non-secure mode +imagedef-nonsecure-exe = [] + +## Have embassy-rp not provide the Image Definition so you can use your own. +## Place your own in the ".start_block" section like: +## ``` +## use embassy_rp::block::ImageDef; +## +## #[link_section = ".start_block"] +## #[used] +## static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); // Update this with your own implementation. +## ``` +imagedef-none = [] + ## Configure the hal for use with the rp2040 rp2040 = ["rp-pac/rp2040"] _rp235x = ["rp-pac/rp235x"] diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs index 80ee47802..de60af890 100644 --- a/embassy-rp/src/lib.rs +++ b/embassy-rp/src/lib.rs @@ -456,6 +456,30 @@ select_bootloader! { default => BOOT_LOADER_W25Q080 } +#[cfg(all(not(feature = "imagedef-none"), feature = "_rp235x"))] +macro_rules! select_imagedef { + ( $( $feature:literal => $imagedef:ident, )+ default => $default:ident ) => { + $( + #[cfg(feature = $feature)] + #[link_section = ".start_block"] + #[used] + static IMAGE_DEF: crate::block::ImageDef = crate::block::ImageDef::$imagedef(); + )* + + #[cfg(not(any( $( feature = $feature),* )))] + #[link_section = ".start_block"] + #[used] + static IMAGE_DEF: crate::block::ImageDef = crate::block::ImageDef::$default(); + } +} + +#[cfg(all(not(feature = "imagedef-none"), feature = "_rp235x"))] +select_imagedef! { + "imagedef-secure-exe" => secure_exe, + "imagedef-nonsecure-exe" => non_secure_exe, + default => secure_exe +} + /// Installs a stack guard for the CORE0 stack in MPU region 0. /// Will fail if the MPU is already configured. This function requires /// a `_stack_end` symbol to be defined by the linker script, and expects From 6b1706434dfeb80b3659f3d2a1bbe2871ec8ea55 Mon Sep 17 00:00:00 2001 From: 9names <60134748+9names@users.noreply.github.com> Date: Sun, 16 Feb 2025 13:04:59 +1100 Subject: [PATCH 0746/1217] Remove ImageDef from rp23 examples --- examples/rp23/src/bin/adc.rs | 5 ----- examples/rp23/src/bin/adc_dma.rs | 5 ----- examples/rp23/src/bin/assign_resources.rs | 5 ----- examples/rp23/src/bin/blinky.rs | 5 ----- examples/rp23/src/bin/blinky_two_channels.rs | 5 ----- examples/rp23/src/bin/blinky_two_tasks.rs | 5 ----- examples/rp23/src/bin/button.rs | 5 ----- examples/rp23/src/bin/debounce.rs | 5 ----- examples/rp23/src/bin/flash.rs | 5 ----- examples/rp23/src/bin/gpio_async.rs | 5 ----- examples/rp23/src/bin/gpout.rs | 5 ----- examples/rp23/src/bin/i2c_async.rs | 5 ----- examples/rp23/src/bin/i2c_async_embassy.rs | 5 ----- examples/rp23/src/bin/i2c_blocking.rs | 5 ----- examples/rp23/src/bin/i2c_slave.rs | 5 ----- examples/rp23/src/bin/interrupt.rs | 5 ----- examples/rp23/src/bin/multicore.rs | 5 ----- examples/rp23/src/bin/multiprio.rs | 5 ----- examples/rp23/src/bin/otp.rs | 5 ----- examples/rp23/src/bin/pio_async.rs | 5 ----- examples/rp23/src/bin/pio_dma.rs | 5 ----- examples/rp23/src/bin/pio_hd44780.rs | 5 ----- examples/rp23/src/bin/pio_i2s.rs | 5 ----- examples/rp23/src/bin/pio_onewire.rs | 5 ----- examples/rp23/src/bin/pio_pwm.rs | 5 ----- examples/rp23/src/bin/pio_rotary_encoder.rs | 5 ----- examples/rp23/src/bin/pio_rotary_encoder_rxf.rs | 5 ----- examples/rp23/src/bin/pio_servo.rs | 5 ----- examples/rp23/src/bin/pio_stepper.rs | 5 ----- examples/rp23/src/bin/pio_uart.rs | 5 ----- examples/rp23/src/bin/pio_ws2812.rs | 5 ----- examples/rp23/src/bin/pwm.rs | 5 ----- examples/rp23/src/bin/pwm_input.rs | 5 ----- examples/rp23/src/bin/pwm_tb6612fng_motor_driver.rs | 5 ----- examples/rp23/src/bin/rosc.rs | 5 ----- examples/rp23/src/bin/shared_bus.rs | 5 ----- examples/rp23/src/bin/sharing.rs | 5 ----- examples/rp23/src/bin/spi.rs | 5 ----- examples/rp23/src/bin/spi_async.rs | 5 ----- examples/rp23/src/bin/spi_display.rs | 5 ----- examples/rp23/src/bin/spi_sdmmc.rs | 5 ----- examples/rp23/src/bin/trng.rs | 5 ----- examples/rp23/src/bin/uart.rs | 5 ----- examples/rp23/src/bin/uart_buffered_split.rs | 5 ----- examples/rp23/src/bin/uart_r503.rs | 5 ----- examples/rp23/src/bin/uart_unidir.rs | 5 ----- examples/rp23/src/bin/usb_hid_keyboard.rs | 5 ----- examples/rp23/src/bin/usb_webusb.rs | 5 ----- examples/rp23/src/bin/watchdog.rs | 5 ----- examples/rp23/src/bin/wifi_blinky_pico_plus_2.rs | 5 ----- examples/rp23/src/bin/zerocopy.rs | 5 ----- 51 files changed, 255 deletions(-) diff --git a/examples/rp23/src/bin/adc.rs b/examples/rp23/src/bin/adc.rs index f7db9653a..b7324f755 100644 --- a/examples/rp23/src/bin/adc.rs +++ b/examples/rp23/src/bin/adc.rs @@ -8,15 +8,10 @@ use defmt::*; use embassy_executor::Spawner; use embassy_rp::adc::{Adc, Channel, Config, InterruptHandler}; use embassy_rp::bind_interrupts; -use embassy_rp::block::ImageDef; use embassy_rp::gpio::Pull; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; -#[link_section = ".start_block"] -#[used] -pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); - bind_interrupts!(struct Irqs { ADC_IRQ_FIFO => InterruptHandler; }); diff --git a/examples/rp23/src/bin/adc_dma.rs b/examples/rp23/src/bin/adc_dma.rs index a6814c23a..f755cf5bf 100644 --- a/examples/rp23/src/bin/adc_dma.rs +++ b/examples/rp23/src/bin/adc_dma.rs @@ -8,15 +8,10 @@ use defmt::*; use embassy_executor::Spawner; use embassy_rp::adc::{Adc, Channel, Config, InterruptHandler}; use embassy_rp::bind_interrupts; -use embassy_rp::block::ImageDef; use embassy_rp::gpio::Pull; use embassy_time::{Duration, Ticker}; use {defmt_rtt as _, panic_probe as _}; -#[link_section = ".start_block"] -#[used] -pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); - bind_interrupts!(struct Irqs { ADC_IRQ_FIFO => InterruptHandler; }); diff --git a/examples/rp23/src/bin/assign_resources.rs b/examples/rp23/src/bin/assign_resources.rs index 0d4ad8dc3..ff6eff4a2 100644 --- a/examples/rp23/src/bin/assign_resources.rs +++ b/examples/rp23/src/bin/assign_resources.rs @@ -14,16 +14,11 @@ use assign_resources::assign_resources; use defmt::*; use embassy_executor::Spawner; -use embassy_rp::block::ImageDef; use embassy_rp::gpio::{Level, Output}; use embassy_rp::peripherals::{self, PIN_20, PIN_21}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; -#[link_section = ".start_block"] -#[used] -pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); - #[embassy_executor::main] async fn main(spawner: Spawner) { // initialize the peripherals diff --git a/examples/rp23/src/bin/blinky.rs b/examples/rp23/src/bin/blinky.rs index c1ddbb7d2..2d962baca 100644 --- a/examples/rp23/src/bin/blinky.rs +++ b/examples/rp23/src/bin/blinky.rs @@ -7,16 +7,11 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_rp::block::ImageDef; use embassy_rp::gpio; use embassy_time::Timer; use gpio::{Level, Output}; use {defmt_rtt as _, panic_probe as _}; -#[link_section = ".start_block"] -#[used] -pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); - // Program metadata for `picotool info`. // This isn't needed, but it's recomended to have these minimal entries. #[link_section = ".bi_entries"] diff --git a/examples/rp23/src/bin/blinky_two_channels.rs b/examples/rp23/src/bin/blinky_two_channels.rs index ce482858e..b2eec2a21 100644 --- a/examples/rp23/src/bin/blinky_two_channels.rs +++ b/examples/rp23/src/bin/blinky_two_channels.rs @@ -7,7 +7,6 @@ /// [Link explaining it](https://www.physicsclassroom.com/class/sound/Lesson-3/Interference-and-Beats) use defmt::*; use embassy_executor::Spawner; -use embassy_rp::block::ImageDef; use embassy_rp::gpio; use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; use embassy_sync::channel::{Channel, Sender}; @@ -15,10 +14,6 @@ use embassy_time::{Duration, Ticker}; use gpio::{AnyPin, Level, Output}; use {defmt_rtt as _, panic_probe as _}; -#[link_section = ".start_block"] -#[used] -pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); - enum LedState { Toggle, } diff --git a/examples/rp23/src/bin/blinky_two_tasks.rs b/examples/rp23/src/bin/blinky_two_tasks.rs index 5dc62245d..a57b513d6 100644 --- a/examples/rp23/src/bin/blinky_two_tasks.rs +++ b/examples/rp23/src/bin/blinky_two_tasks.rs @@ -7,7 +7,6 @@ /// [Link explaining it](https://www.physicsclassroom.com/class/sound/Lesson-3/Interference-and-Beats) use defmt::*; use embassy_executor::Spawner; -use embassy_rp::block::ImageDef; use embassy_rp::gpio; use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; use embassy_sync::mutex::Mutex; @@ -15,10 +14,6 @@ use embassy_time::{Duration, Ticker}; use gpio::{AnyPin, Level, Output}; use {defmt_rtt as _, panic_probe as _}; -#[link_section = ".start_block"] -#[used] -pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); - type LedType = Mutex>>; static LED: LedType = Mutex::new(None); diff --git a/examples/rp23/src/bin/button.rs b/examples/rp23/src/bin/button.rs index 85f1bcae3..4ad2ca3b7 100644 --- a/examples/rp23/src/bin/button.rs +++ b/examples/rp23/src/bin/button.rs @@ -6,14 +6,9 @@ #![no_main] use embassy_executor::Spawner; -use embassy_rp::block::ImageDef; use embassy_rp::gpio::{Input, Level, Output, Pull}; use {defmt_rtt as _, panic_probe as _}; -#[link_section = ".start_block"] -#[used] -pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); - #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_rp::init(Default::default()); diff --git a/examples/rp23/src/bin/debounce.rs b/examples/rp23/src/bin/debounce.rs index 4c8b80d92..0077f19fc 100644 --- a/examples/rp23/src/bin/debounce.rs +++ b/examples/rp23/src/bin/debounce.rs @@ -6,15 +6,10 @@ use defmt::info; use embassy_executor::Spawner; -use embassy_rp::block::ImageDef; use embassy_rp::gpio::{Input, Level, Pull}; use embassy_time::{with_deadline, Duration, Instant, Timer}; use {defmt_rtt as _, panic_probe as _}; -#[link_section = ".start_block"] -#[used] -pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); - pub struct Debouncer<'a> { input: Input<'a>, debounce: Duration, diff --git a/examples/rp23/src/bin/flash.rs b/examples/rp23/src/bin/flash.rs index 42c226f5b..31ad4aafc 100644 --- a/examples/rp23/src/bin/flash.rs +++ b/examples/rp23/src/bin/flash.rs @@ -5,16 +5,11 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_rp::block::ImageDef; use embassy_rp::flash::{Async, ERASE_SIZE, FLASH_BASE}; use embassy_rp::peripherals::FLASH; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; -#[link_section = ".start_block"] -#[used] -pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); - const ADDR_OFFSET: u32 = 0x100000; const FLASH_SIZE: usize = 2 * 1024 * 1024; diff --git a/examples/rp23/src/bin/gpio_async.rs b/examples/rp23/src/bin/gpio_async.rs index bfb9a3f95..b79fb2a15 100644 --- a/examples/rp23/src/bin/gpio_async.rs +++ b/examples/rp23/src/bin/gpio_async.rs @@ -7,16 +7,11 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_rp::block::ImageDef; use embassy_rp::gpio; use embassy_time::Timer; use gpio::{Input, Level, Output, Pull}; use {defmt_rtt as _, panic_probe as _}; -#[link_section = ".start_block"] -#[used] -pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); - /// It requires an external signal to be manually triggered on PIN 16. For /// example, this could be accomplished using an external power source with a /// button so that it is possible to toggle the signal from low to high. diff --git a/examples/rp23/src/bin/gpout.rs b/examples/rp23/src/bin/gpout.rs index 3cc2ea938..011359253 100644 --- a/examples/rp23/src/bin/gpout.rs +++ b/examples/rp23/src/bin/gpout.rs @@ -7,15 +7,10 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_rp::block::ImageDef; use embassy_rp::clocks; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; -#[link_section = ".start_block"] -#[used] -pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); - #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_rp::init(Default::default()); diff --git a/examples/rp23/src/bin/i2c_async.rs b/examples/rp23/src/bin/i2c_async.rs index b30088bae..e31cc894c 100644 --- a/examples/rp23/src/bin/i2c_async.rs +++ b/examples/rp23/src/bin/i2c_async.rs @@ -9,17 +9,12 @@ use defmt::*; use embassy_executor::Spawner; use embassy_rp::bind_interrupts; -use embassy_rp::block::ImageDef; use embassy_rp::i2c::{self, Config, InterruptHandler}; use embassy_rp::peripherals::I2C1; use embassy_time::Timer; use embedded_hal_async::i2c::I2c; use {defmt_rtt as _, panic_probe as _}; -#[link_section = ".start_block"] -#[used] -pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); - bind_interrupts!(struct Irqs { I2C1_IRQ => InterruptHandler; }); diff --git a/examples/rp23/src/bin/i2c_async_embassy.rs b/examples/rp23/src/bin/i2c_async_embassy.rs index c783a80c5..a65b71b9f 100644 --- a/examples/rp23/src/bin/i2c_async_embassy.rs +++ b/examples/rp23/src/bin/i2c_async_embassy.rs @@ -7,14 +7,9 @@ #![no_main] use defmt::*; -use embassy_rp::block::ImageDef; use embassy_rp::i2c::InterruptHandler; use {defmt_rtt as _, panic_probe as _}; -#[link_section = ".start_block"] -#[used] -pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); - // Our anonymous hypotetical temperature sensor could be: // a 12-bit sensor, with 100ms startup time, range of -40*C - 125*C, and precision 0.25*C // It requires no configuration or calibration, works with all i2c bus speeds, diff --git a/examples/rp23/src/bin/i2c_blocking.rs b/examples/rp23/src/bin/i2c_blocking.rs index a68677311..c9c8a2760 100644 --- a/examples/rp23/src/bin/i2c_blocking.rs +++ b/examples/rp23/src/bin/i2c_blocking.rs @@ -8,16 +8,11 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_rp::block::ImageDef; use embassy_rp::i2c::{self, Config}; use embassy_time::Timer; use embedded_hal_1::i2c::I2c; use {defmt_rtt as _, panic_probe as _}; -#[link_section = ".start_block"] -#[used] -pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); - #[allow(dead_code)] mod mcp23017 { pub const ADDR: u8 = 0x20; // default addr diff --git a/examples/rp23/src/bin/i2c_slave.rs b/examples/rp23/src/bin/i2c_slave.rs index 8817538c0..9fffb4646 100644 --- a/examples/rp23/src/bin/i2c_slave.rs +++ b/examples/rp23/src/bin/i2c_slave.rs @@ -4,17 +4,12 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_rp::block::ImageDef; use embassy_rp::peripherals::{I2C0, I2C1}; use embassy_rp::{bind_interrupts, i2c, i2c_slave}; use embassy_time::Timer; use embedded_hal_async::i2c::I2c; use {defmt_rtt as _, panic_probe as _}; -#[link_section = ".start_block"] -#[used] -pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); - bind_interrupts!(struct Irqs { I2C0_IRQ => i2c::InterruptHandler; I2C1_IRQ => i2c::InterruptHandler; diff --git a/examples/rp23/src/bin/interrupt.rs b/examples/rp23/src/bin/interrupt.rs index d563e6ebe..e9ac76486 100644 --- a/examples/rp23/src/bin/interrupt.rs +++ b/examples/rp23/src/bin/interrupt.rs @@ -13,7 +13,6 @@ use core::cell::{Cell, RefCell}; use defmt::*; use embassy_executor::Spawner; use embassy_rp::adc::{self, Adc, Blocking}; -use embassy_rp::block::ImageDef; use embassy_rp::gpio::Pull; use embassy_rp::interrupt; use embassy_rp::pwm::{Config, Pwm}; @@ -25,10 +24,6 @@ use portable_atomic::{AtomicU32, Ordering}; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; -#[link_section = ".start_block"] -#[used] -pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); - static COUNTER: AtomicU32 = AtomicU32::new(0); static PWM: Mutex>> = Mutex::new(RefCell::new(None)); static ADC: Mutex, adc::Channel)>>> = diff --git a/examples/rp23/src/bin/multicore.rs b/examples/rp23/src/bin/multicore.rs index d4d470fa2..7cb546c91 100644 --- a/examples/rp23/src/bin/multicore.rs +++ b/examples/rp23/src/bin/multicore.rs @@ -7,7 +7,6 @@ use defmt::*; use embassy_executor::Executor; -use embassy_rp::block::ImageDef; use embassy_rp::gpio::{Level, Output}; use embassy_rp::multicore::{spawn_core1, Stack}; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; @@ -16,10 +15,6 @@ use embassy_time::Timer; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; -#[link_section = ".start_block"] -#[used] -pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); - static mut CORE1_STACK: Stack<4096> = Stack::new(); static EXECUTOR0: StaticCell = StaticCell::new(); static EXECUTOR1: StaticCell = StaticCell::new(); diff --git a/examples/rp23/src/bin/multiprio.rs b/examples/rp23/src/bin/multiprio.rs index 787854aa9..2b397f97d 100644 --- a/examples/rp23/src/bin/multiprio.rs +++ b/examples/rp23/src/bin/multiprio.rs @@ -59,17 +59,12 @@ use cortex_m_rt::entry; use defmt::{info, unwrap}; use embassy_executor::{Executor, InterruptExecutor}; -use embassy_rp::block::ImageDef; use embassy_rp::interrupt; use embassy_rp::interrupt::{InterruptExt, Priority}; use embassy_time::{Instant, Timer, TICK_HZ}; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; -#[link_section = ".start_block"] -#[used] -pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); - #[embassy_executor::task] async fn run_high() { loop { diff --git a/examples/rp23/src/bin/otp.rs b/examples/rp23/src/bin/otp.rs index c67c9821a..5ffbb7610 100644 --- a/examples/rp23/src/bin/otp.rs +++ b/examples/rp23/src/bin/otp.rs @@ -5,15 +5,10 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_rp::block::ImageDef; use embassy_rp::otp; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; -#[link_section = ".start_block"] -#[used] -pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); - #[embassy_executor::main] async fn main(_spawner: Spawner) { let _ = embassy_rp::init(Default::default()); diff --git a/examples/rp23/src/bin/pio_async.rs b/examples/rp23/src/bin/pio_async.rs index 896447e28..ee248591b 100644 --- a/examples/rp23/src/bin/pio_async.rs +++ b/examples/rp23/src/bin/pio_async.rs @@ -5,17 +5,12 @@ use defmt::info; use embassy_executor::Spawner; use embassy_rp::bind_interrupts; -use embassy_rp::block::ImageDef; use embassy_rp::peripherals::PIO0; use embassy_rp::pio::{Common, Config, InterruptHandler, Irq, Pio, PioPin, ShiftDirection, StateMachine}; use fixed::traits::ToFixed; use fixed_macro::types::U56F8; use {defmt_rtt as _, panic_probe as _}; -#[link_section = ".start_block"] -#[used] -pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); - bind_interrupts!(struct Irqs { PIO0_IRQ_0 => InterruptHandler; }); diff --git a/examples/rp23/src/bin/pio_dma.rs b/examples/rp23/src/bin/pio_dma.rs index b5f754798..02700269c 100644 --- a/examples/rp23/src/bin/pio_dma.rs +++ b/examples/rp23/src/bin/pio_dma.rs @@ -5,7 +5,6 @@ use defmt::info; use embassy_executor::Spawner; use embassy_futures::join::join; -use embassy_rp::block::ImageDef; use embassy_rp::peripherals::PIO0; use embassy_rp::pio::{Config, InterruptHandler, Pio, ShiftConfig, ShiftDirection}; use embassy_rp::{bind_interrupts, Peripheral}; @@ -13,10 +12,6 @@ use fixed::traits::ToFixed; use fixed_macro::types::U56F8; use {defmt_rtt as _, panic_probe as _}; -#[link_section = ".start_block"] -#[used] -pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); - bind_interrupts!(struct Irqs { PIO0_IRQ_0 => InterruptHandler; }); diff --git a/examples/rp23/src/bin/pio_hd44780.rs b/examples/rp23/src/bin/pio_hd44780.rs index c6f5f6db0..164e6f8d3 100644 --- a/examples/rp23/src/bin/pio_hd44780.rs +++ b/examples/rp23/src/bin/pio_hd44780.rs @@ -8,7 +8,6 @@ use core::fmt::Write; use embassy_executor::Spawner; use embassy_rp::bind_interrupts; -use embassy_rp::block::ImageDef; use embassy_rp::peripherals::PIO0; use embassy_rp::pio::{InterruptHandler, Pio}; use embassy_rp::pio_programs::hd44780::{PioHD44780, PioHD44780CommandSequenceProgram, PioHD44780CommandWordProgram}; @@ -16,10 +15,6 @@ use embassy_rp::pwm::{self, Pwm}; use embassy_time::{Instant, Timer}; use {defmt_rtt as _, panic_probe as _}; -#[link_section = ".start_block"] -#[used] -pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); - bind_interrupts!(pub struct Irqs { PIO0_IRQ_0 => InterruptHandler; }); diff --git a/examples/rp23/src/bin/pio_i2s.rs b/examples/rp23/src/bin/pio_i2s.rs index 1fd34357b..ae937a4ed 100644 --- a/examples/rp23/src/bin/pio_i2s.rs +++ b/examples/rp23/src/bin/pio_i2s.rs @@ -14,7 +14,6 @@ use core::mem; use embassy_executor::Spawner; use embassy_rp::bind_interrupts; -use embassy_rp::block::ImageDef; use embassy_rp::gpio::{Input, Pull}; use embassy_rp::peripherals::PIO0; use embassy_rp::pio::{InterruptHandler, Pio}; @@ -22,10 +21,6 @@ use embassy_rp::pio_programs::i2s::{PioI2sOut, PioI2sOutProgram}; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; -#[link_section = ".start_block"] -#[used] -pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); - bind_interrupts!(struct Irqs { PIO0_IRQ_0 => InterruptHandler; }); diff --git a/examples/rp23/src/bin/pio_onewire.rs b/examples/rp23/src/bin/pio_onewire.rs index 7f227d04b..991510851 100644 --- a/examples/rp23/src/bin/pio_onewire.rs +++ b/examples/rp23/src/bin/pio_onewire.rs @@ -5,17 +5,12 @@ use defmt::*; use embassy_executor::Spawner; use embassy_rp::bind_interrupts; -use embassy_rp::block::ImageDef; use embassy_rp::peripherals::PIO0; use embassy_rp::pio::{self, InterruptHandler, Pio}; use embassy_rp::pio_programs::onewire::{PioOneWire, PioOneWireProgram}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; -#[link_section = ".start_block"] -#[used] -pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); - bind_interrupts!(struct Irqs { PIO0_IRQ_0 => InterruptHandler; }); diff --git a/examples/rp23/src/bin/pio_pwm.rs b/examples/rp23/src/bin/pio_pwm.rs index 11af62a7a..7eabb2289 100644 --- a/examples/rp23/src/bin/pio_pwm.rs +++ b/examples/rp23/src/bin/pio_pwm.rs @@ -6,17 +6,12 @@ use core::time::Duration; use embassy_executor::Spawner; use embassy_rp::bind_interrupts; -use embassy_rp::block::ImageDef; use embassy_rp::peripherals::PIO0; use embassy_rp::pio::{InterruptHandler, Pio}; use embassy_rp::pio_programs::pwm::{PioPwm, PioPwmProgram}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; -#[link_section = ".start_block"] -#[used] -pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); - const REFRESH_INTERVAL: u64 = 20000; bind_interrupts!(struct Irqs { diff --git a/examples/rp23/src/bin/pio_rotary_encoder.rs b/examples/rp23/src/bin/pio_rotary_encoder.rs index 2bb0e67f9..2750f61ae 100644 --- a/examples/rp23/src/bin/pio_rotary_encoder.rs +++ b/examples/rp23/src/bin/pio_rotary_encoder.rs @@ -6,16 +6,11 @@ use defmt::info; use embassy_executor::Spawner; use embassy_rp::bind_interrupts; -use embassy_rp::block::ImageDef; use embassy_rp::peripherals::PIO0; use embassy_rp::pio::{InterruptHandler, Pio}; use embassy_rp::pio_programs::rotary_encoder::{Direction, PioEncoder, PioEncoderProgram}; use {defmt_rtt as _, panic_probe as _}; -#[link_section = ".start_block"] -#[used] -pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); - bind_interrupts!(struct Irqs { PIO0_IRQ_0 => InterruptHandler; }); diff --git a/examples/rp23/src/bin/pio_rotary_encoder_rxf.rs b/examples/rp23/src/bin/pio_rotary_encoder_rxf.rs index 7a1046610..ca6b5222b 100644 --- a/examples/rp23/src/bin/pio_rotary_encoder_rxf.rs +++ b/examples/rp23/src/bin/pio_rotary_encoder_rxf.rs @@ -6,7 +6,6 @@ use defmt::info; use embassy_executor::Spawner; -use embassy_rp::block::ImageDef; use embassy_rp::gpio::Pull; use embassy_rp::peripherals::PIO0; use embassy_rp::{bind_interrupts, pio}; @@ -15,10 +14,6 @@ use fixed::traits::ToFixed; use pio::{Common, Config, FifoJoin, Instance, InterruptHandler, Pio, PioPin, ShiftDirection, StateMachine}; use {defmt_rtt as _, panic_probe as _}; -#[link_section = ".start_block"] -#[used] -pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); - // Program metadata for `picotool info` #[link_section = ".bi_entries"] #[used] diff --git a/examples/rp23/src/bin/pio_servo.rs b/examples/rp23/src/bin/pio_servo.rs index 4e94103f1..c52ee7492 100644 --- a/examples/rp23/src/bin/pio_servo.rs +++ b/examples/rp23/src/bin/pio_servo.rs @@ -6,17 +6,12 @@ use core::time::Duration; use embassy_executor::Spawner; use embassy_rp::bind_interrupts; -use embassy_rp::block::ImageDef; use embassy_rp::peripherals::PIO0; use embassy_rp::pio::{Instance, InterruptHandler, Pio}; use embassy_rp::pio_programs::pwm::{PioPwm, PioPwmProgram}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; -#[link_section = ".start_block"] -#[used] -pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); - const DEFAULT_MIN_PULSE_WIDTH: u64 = 1000; // uncalibrated default, the shortest duty cycle sent to a servo const DEFAULT_MAX_PULSE_WIDTH: u64 = 2000; // uncalibrated default, the longest duty cycle sent to a servo const DEFAULT_MAX_DEGREE_ROTATION: u64 = 160; // 160 degrees is typical diff --git a/examples/rp23/src/bin/pio_stepper.rs b/examples/rp23/src/bin/pio_stepper.rs index 4fabe78ca..3862c248b 100644 --- a/examples/rp23/src/bin/pio_stepper.rs +++ b/examples/rp23/src/bin/pio_stepper.rs @@ -7,17 +7,12 @@ use defmt::info; use embassy_executor::Spawner; use embassy_rp::bind_interrupts; -use embassy_rp::block::ImageDef; use embassy_rp::peripherals::PIO0; use embassy_rp::pio::{InterruptHandler, Pio}; use embassy_rp::pio_programs::stepper::{PioStepper, PioStepperProgram}; use embassy_time::{with_timeout, Duration, Timer}; use {defmt_rtt as _, panic_probe as _}; -#[link_section = ".start_block"] -#[used] -pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); - bind_interrupts!(struct Irqs { PIO0_IRQ_0 => InterruptHandler; }); diff --git a/examples/rp23/src/bin/pio_uart.rs b/examples/rp23/src/bin/pio_uart.rs index 672732c5b..9712984f9 100644 --- a/examples/rp23/src/bin/pio_uart.rs +++ b/examples/rp23/src/bin/pio_uart.rs @@ -13,7 +13,6 @@ use defmt::{info, panic, trace}; use embassy_executor::Spawner; use embassy_futures::join::{join, join3}; -use embassy_rp::block::ImageDef; use embassy_rp::peripherals::{PIO0, USB}; use embassy_rp::pio_programs::uart::{PioUartRx, PioUartRxProgram, PioUartTx, PioUartTxProgram}; use embassy_rp::usb::{Driver, Instance, InterruptHandler}; @@ -26,10 +25,6 @@ use embassy_usb::{Builder, Config}; use embedded_io_async::{Read, Write}; use {defmt_rtt as _, panic_probe as _}; -#[link_section = ".start_block"] -#[used] -pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); - bind_interrupts!(struct Irqs { USBCTRL_IRQ => InterruptHandler; PIO0_IRQ_0 => pio::InterruptHandler; diff --git a/examples/rp23/src/bin/pio_ws2812.rs b/examples/rp23/src/bin/pio_ws2812.rs index 4d258234e..d1fcfc471 100644 --- a/examples/rp23/src/bin/pio_ws2812.rs +++ b/examples/rp23/src/bin/pio_ws2812.rs @@ -7,7 +7,6 @@ use defmt::*; use embassy_executor::Spawner; use embassy_rp::bind_interrupts; -use embassy_rp::block::ImageDef; use embassy_rp::peripherals::PIO0; use embassy_rp::pio::{InterruptHandler, Pio}; use embassy_rp::pio_programs::ws2812::{PioWs2812, PioWs2812Program}; @@ -15,10 +14,6 @@ use embassy_time::{Duration, Ticker}; use smart_leds::RGB8; use {defmt_rtt as _, panic_probe as _}; -#[link_section = ".start_block"] -#[used] -pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); - bind_interrupts!(struct Irqs { PIO0_IRQ_0 => InterruptHandler; }); diff --git a/examples/rp23/src/bin/pwm.rs b/examples/rp23/src/bin/pwm.rs index ed3c94f15..a3c0f7e49 100644 --- a/examples/rp23/src/bin/pwm.rs +++ b/examples/rp23/src/bin/pwm.rs @@ -9,16 +9,11 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_rp::block::ImageDef; use embassy_rp::peripherals::{PIN_25, PIN_4, PWM_SLICE2, PWM_SLICE4}; use embassy_rp::pwm::{Config, Pwm, SetDutyCycle}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; -#[link_section = ".start_block"] -#[used] -pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); - #[embassy_executor::main] async fn main(spawner: Spawner) { let p = embassy_rp::init(Default::default()); diff --git a/examples/rp23/src/bin/pwm_input.rs b/examples/rp23/src/bin/pwm_input.rs index ef87fe8b5..bf454a936 100644 --- a/examples/rp23/src/bin/pwm_input.rs +++ b/examples/rp23/src/bin/pwm_input.rs @@ -5,16 +5,11 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_rp::block::ImageDef; use embassy_rp::gpio::Pull; use embassy_rp::pwm::{Config, InputMode, Pwm}; use embassy_time::{Duration, Ticker}; use {defmt_rtt as _, panic_probe as _}; -#[link_section = ".start_block"] -#[used] -pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); - #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_rp::init(Default::default()); diff --git a/examples/rp23/src/bin/pwm_tb6612fng_motor_driver.rs b/examples/rp23/src/bin/pwm_tb6612fng_motor_driver.rs index 0682888e8..3b700884c 100644 --- a/examples/rp23/src/bin/pwm_tb6612fng_motor_driver.rs +++ b/examples/rp23/src/bin/pwm_tb6612fng_motor_driver.rs @@ -8,7 +8,6 @@ use assign_resources::assign_resources; use defmt::*; use embassy_executor::Spawner; -use embassy_rp::block::ImageDef; use embassy_rp::config::Config; use embassy_rp::gpio::Output; use embassy_rp::{gpio, peripherals, pwm}; @@ -16,10 +15,6 @@ use embassy_time::{Duration, Timer}; use tb6612fng::{DriveCommand, Motor, Tb6612fng}; use {defmt_rtt as _, panic_probe as _}; -#[link_section = ".start_block"] -#[used] -pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); - assign_resources! { motor: MotorResources { standby_pin: PIN_22, diff --git a/examples/rp23/src/bin/rosc.rs b/examples/rp23/src/bin/rosc.rs index a096f0b7a..942b72319 100644 --- a/examples/rp23/src/bin/rosc.rs +++ b/examples/rp23/src/bin/rosc.rs @@ -7,16 +7,11 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_rp::block::ImageDef; use embassy_rp::{clocks, gpio}; use embassy_time::Timer; use gpio::{Level, Output}; use {defmt_rtt as _, panic_probe as _}; -#[link_section = ".start_block"] -#[used] -pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); - #[embassy_executor::main] async fn main(_spawner: Spawner) { let mut config = embassy_rp::config::Config::default(); diff --git a/examples/rp23/src/bin/shared_bus.rs b/examples/rp23/src/bin/shared_bus.rs index 2151ccb56..c6cb5d64c 100644 --- a/examples/rp23/src/bin/shared_bus.rs +++ b/examples/rp23/src/bin/shared_bus.rs @@ -8,7 +8,6 @@ use embassy_embedded_hal::shared_bus::asynch::i2c::I2cDevice; use embassy_embedded_hal::shared_bus::asynch::spi::SpiDevice; use embassy_executor::Spawner; use embassy_rp::bind_interrupts; -use embassy_rp::block::ImageDef; use embassy_rp::gpio::{AnyPin, Level, Output}; use embassy_rp::i2c::{self, I2c, InterruptHandler}; use embassy_rp::peripherals::{I2C1, SPI1}; @@ -19,10 +18,6 @@ use embassy_time::Timer; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; -#[link_section = ".start_block"] -#[used] -pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); - type Spi1Bus = Mutex>; type I2c1Bus = Mutex>; diff --git a/examples/rp23/src/bin/sharing.rs b/examples/rp23/src/bin/sharing.rs index 68eb5d133..5416e20ce 100644 --- a/examples/rp23/src/bin/sharing.rs +++ b/examples/rp23/src/bin/sharing.rs @@ -19,7 +19,6 @@ use core::sync::atomic::{AtomicU32, Ordering}; use cortex_m_rt::entry; use defmt::info; use embassy_executor::{Executor, InterruptExecutor}; -use embassy_rp::block::ImageDef; use embassy_rp::clocks::RoscRng; use embassy_rp::interrupt::{InterruptExt, Priority}; use embassy_rp::peripherals::UART0; @@ -32,10 +31,6 @@ use rand::RngCore; use static_cell::{ConstStaticCell, StaticCell}; use {defmt_rtt as _, panic_probe as _}; -#[link_section = ".start_block"] -#[used] -pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); - type UartAsyncMutex = mutex::Mutex>; struct MyType { diff --git a/examples/rp23/src/bin/spi.rs b/examples/rp23/src/bin/spi.rs index aacb8c7db..4cc4f5210 100644 --- a/examples/rp23/src/bin/spi.rs +++ b/examples/rp23/src/bin/spi.rs @@ -7,16 +7,11 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_rp::block::ImageDef; use embassy_rp::spi::Spi; use embassy_rp::{gpio, spi}; use gpio::{Level, Output}; use {defmt_rtt as _, panic_probe as _}; -#[link_section = ".start_block"] -#[used] -pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); - #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_rp::init(Default::default()); diff --git a/examples/rp23/src/bin/spi_async.rs b/examples/rp23/src/bin/spi_async.rs index ac7f02fa8..266584efc 100644 --- a/examples/rp23/src/bin/spi_async.rs +++ b/examples/rp23/src/bin/spi_async.rs @@ -6,15 +6,10 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_rp::block::ImageDef; use embassy_rp::spi::{Config, Spi}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; -#[link_section = ".start_block"] -#[used] -pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); - #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_rp::init(Default::default()); diff --git a/examples/rp23/src/bin/spi_display.rs b/examples/rp23/src/bin/spi_display.rs index 6b7c0781f..9c524ab25 100644 --- a/examples/rp23/src/bin/spi_display.rs +++ b/examples/rp23/src/bin/spi_display.rs @@ -12,7 +12,6 @@ use defmt::*; use display_interface_spi::SPIInterface; use embassy_embedded_hal::shared_bus::blocking::spi::SpiDeviceWithConfig; use embassy_executor::Spawner; -use embassy_rp::block::ImageDef; use embassy_rp::gpio::{Level, Output}; use embassy_rp::spi; use embassy_rp::spi::{Blocking, Spi}; @@ -31,10 +30,6 @@ use mipidsi::options::{Orientation, Rotation}; use mipidsi::Builder; use {defmt_rtt as _, panic_probe as _}; -#[link_section = ".start_block"] -#[used] -pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); - use crate::touch::Touch; const DISPLAY_FREQ: u32 = 64_000_000; diff --git a/examples/rp23/src/bin/spi_sdmmc.rs b/examples/rp23/src/bin/spi_sdmmc.rs index 9fea035bc..9808b6a5d 100644 --- a/examples/rp23/src/bin/spi_sdmmc.rs +++ b/examples/rp23/src/bin/spi_sdmmc.rs @@ -9,7 +9,6 @@ use defmt::*; use embassy_embedded_hal::SetConfig; use embassy_executor::Spawner; -use embassy_rp::block::ImageDef; use embassy_rp::spi::Spi; use embassy_rp::{gpio, spi}; use embedded_hal_bus::spi::ExclusiveDevice; @@ -17,10 +16,6 @@ use embedded_sdmmc::sdcard::{DummyCsPin, SdCard}; use gpio::{Level, Output}; use {defmt_rtt as _, panic_probe as _}; -#[link_section = ".start_block"] -#[used] -pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); - struct DummyTimesource(); impl embedded_sdmmc::TimeSource for DummyTimesource { diff --git a/examples/rp23/src/bin/trng.rs b/examples/rp23/src/bin/trng.rs index 8251ebd8b..ad19aef3e 100644 --- a/examples/rp23/src/bin/trng.rs +++ b/examples/rp23/src/bin/trng.rs @@ -6,7 +6,6 @@ use defmt::*; use embassy_executor::Spawner; use embassy_rp::bind_interrupts; -use embassy_rp::block::ImageDef; use embassy_rp::gpio::{Level, Output}; use embassy_rp::peripherals::TRNG; use embassy_rp::trng::Trng; @@ -14,10 +13,6 @@ use embassy_time::Timer; use rand::RngCore; use {defmt_rtt as _, panic_probe as _}; -#[link_section = ".start_block"] -#[used] -pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); - bind_interrupts!(struct Irqs { TRNG_IRQ => embassy_rp::trng::InterruptHandler; }); diff --git a/examples/rp23/src/bin/uart.rs b/examples/rp23/src/bin/uart.rs index fe28bb046..a59f537bf 100644 --- a/examples/rp23/src/bin/uart.rs +++ b/examples/rp23/src/bin/uart.rs @@ -8,14 +8,9 @@ #![no_main] use embassy_executor::Spawner; -use embassy_rp::block::ImageDef; use embassy_rp::uart; use {defmt_rtt as _, panic_probe as _}; -#[link_section = ".start_block"] -#[used] -pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); - #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_rp::init(Default::default()); diff --git a/examples/rp23/src/bin/uart_buffered_split.rs b/examples/rp23/src/bin/uart_buffered_split.rs index 9ed130727..468d2b61a 100644 --- a/examples/rp23/src/bin/uart_buffered_split.rs +++ b/examples/rp23/src/bin/uart_buffered_split.rs @@ -10,7 +10,6 @@ use defmt::*; use embassy_executor::Spawner; use embassy_rp::bind_interrupts; -use embassy_rp::block::ImageDef; use embassy_rp::peripherals::UART0; use embassy_rp::uart::{BufferedInterruptHandler, BufferedUart, BufferedUartRx, Config}; use embassy_time::Timer; @@ -18,10 +17,6 @@ use embedded_io_async::{Read, Write}; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; -#[link_section = ".start_block"] -#[used] -pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); - bind_interrupts!(struct Irqs { UART0_IRQ => BufferedInterruptHandler; }); diff --git a/examples/rp23/src/bin/uart_r503.rs b/examples/rp23/src/bin/uart_r503.rs index 9aed42785..085be280b 100644 --- a/examples/rp23/src/bin/uart_r503.rs +++ b/examples/rp23/src/bin/uart_r503.rs @@ -4,17 +4,12 @@ use defmt::{debug, error, info}; use embassy_executor::Spawner; use embassy_rp::bind_interrupts; -use embassy_rp::block::ImageDef; use embassy_rp::peripherals::UART0; use embassy_rp::uart::{Config, DataBits, InterruptHandler as UARTInterruptHandler, Parity, StopBits, Uart}; use embassy_time::{with_timeout, Duration, Timer}; use heapless::Vec; use {defmt_rtt as _, panic_probe as _}; -#[link_section = ".start_block"] -#[used] -pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); - bind_interrupts!(pub struct Irqs { UART0_IRQ => UARTInterruptHandler; }); diff --git a/examples/rp23/src/bin/uart_unidir.rs b/examples/rp23/src/bin/uart_unidir.rs index 12214c4c2..a45f40756 100644 --- a/examples/rp23/src/bin/uart_unidir.rs +++ b/examples/rp23/src/bin/uart_unidir.rs @@ -11,16 +11,11 @@ use defmt::*; use embassy_executor::Spawner; use embassy_rp::bind_interrupts; -use embassy_rp::block::ImageDef; use embassy_rp::peripherals::UART1; use embassy_rp::uart::{Async, Config, InterruptHandler, UartRx, UartTx}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; -#[link_section = ".start_block"] -#[used] -pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); - bind_interrupts!(struct Irqs { UART1_IRQ => InterruptHandler; }); diff --git a/examples/rp23/src/bin/usb_hid_keyboard.rs b/examples/rp23/src/bin/usb_hid_keyboard.rs index ec1e88746..6f496e23a 100644 --- a/examples/rp23/src/bin/usb_hid_keyboard.rs +++ b/examples/rp23/src/bin/usb_hid_keyboard.rs @@ -7,7 +7,6 @@ use defmt::*; use embassy_executor::Spawner; use embassy_futures::join::join; use embassy_rp::bind_interrupts; -use embassy_rp::block::ImageDef; use embassy_rp::gpio::{Input, Pull}; use embassy_rp::peripherals::USB; use embassy_rp::usb::{Driver as UsbDriver, InterruptHandler}; @@ -17,10 +16,6 @@ use embassy_usb::{Builder, Config, Handler}; use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor}; use {defmt_rtt as _, panic_probe as _}; -#[link_section = ".start_block"] -#[used] -pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); - bind_interrupts!(struct Irqs { USBCTRL_IRQ => InterruptHandler; }); diff --git a/examples/rp23/src/bin/usb_webusb.rs b/examples/rp23/src/bin/usb_webusb.rs index 15279cabc..e73938ac9 100644 --- a/examples/rp23/src/bin/usb_webusb.rs +++ b/examples/rp23/src/bin/usb_webusb.rs @@ -21,7 +21,6 @@ use defmt::info; use embassy_executor::Spawner; use embassy_futures::join::join; use embassy_rp::bind_interrupts; -use embassy_rp::block::ImageDef; use embassy_rp::peripherals::USB; use embassy_rp::usb::{Driver as UsbDriver, InterruptHandler}; use embassy_usb::class::web_usb::{Config as WebUsbConfig, State, Url, WebUsb}; @@ -30,10 +29,6 @@ use embassy_usb::msos::{self, windows_version}; use embassy_usb::{Builder, Config}; use {defmt_rtt as _, panic_probe as _}; -#[link_section = ".start_block"] -#[used] -pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); - bind_interrupts!(struct Irqs { USBCTRL_IRQ => InterruptHandler; }); diff --git a/examples/rp23/src/bin/watchdog.rs b/examples/rp23/src/bin/watchdog.rs index efc24c4e3..b9d4ef22f 100644 --- a/examples/rp23/src/bin/watchdog.rs +++ b/examples/rp23/src/bin/watchdog.rs @@ -7,17 +7,12 @@ use defmt::info; use embassy_executor::Spawner; -use embassy_rp::block::ImageDef; use embassy_rp::gpio; use embassy_rp::watchdog::*; use embassy_time::{Duration, Timer}; use gpio::{Level, Output}; use {defmt_rtt as _, panic_probe as _}; -#[link_section = ".start_block"] -#[used] -pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); - #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_rp::init(Default::default()); diff --git a/examples/rp23/src/bin/wifi_blinky_pico_plus_2.rs b/examples/rp23/src/bin/wifi_blinky_pico_plus_2.rs index ebb3c4373..ab7d6a93e 100644 --- a/examples/rp23/src/bin/wifi_blinky_pico_plus_2.rs +++ b/examples/rp23/src/bin/wifi_blinky_pico_plus_2.rs @@ -8,7 +8,6 @@ use cyw43_pio::{PioSpi, RM2_CLOCK_DIVIDER}; use defmt::*; use embassy_executor::Spawner; -use embassy_rp::block::ImageDef; use embassy_rp::peripherals::{DMA_CH0, PIO0}; use embassy_rp::pio::{InterruptHandler, Pio}; use embassy_rp::{bind_interrupts, gpio}; @@ -17,10 +16,6 @@ use gpio::{Level, Output}; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; -#[link_section = ".start_block"] -#[used] -pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); - // Program metadata for `picotool info`. // This isn't needed, but it's recomended to have these minimal entries. #[link_section = ".bi_entries"] diff --git a/examples/rp23/src/bin/zerocopy.rs b/examples/rp23/src/bin/zerocopy.rs index d317c4b56..39f03c8e4 100644 --- a/examples/rp23/src/bin/zerocopy.rs +++ b/examples/rp23/src/bin/zerocopy.rs @@ -10,7 +10,6 @@ use defmt::*; use embassy_executor::Spawner; use embassy_rp::adc::{self, Adc, Async, Config, InterruptHandler}; use embassy_rp::bind_interrupts; -use embassy_rp::block::ImageDef; use embassy_rp::gpio::Pull; use embassy_rp::peripherals::DMA_CH0; use embassy_sync::blocking_mutex::raw::NoopRawMutex; @@ -19,10 +18,6 @@ use embassy_time::{Duration, Ticker, Timer}; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; -#[link_section = ".start_block"] -#[used] -pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); - type SampleBuffer = [u16; 512]; bind_interrupts!(struct Irqs { From 9495ec8ae435a1642c9f65b0967cd0a2accf1320 Mon Sep 17 00:00:00 2001 From: 9names <60134748+9names@users.noreply.github.com> Date: Sun, 16 Feb 2025 15:50:21 +1100 Subject: [PATCH 0747/1217] Don't try to run doc-example for imagedef-none --- embassy-rp/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index d65e281ee..d681af915 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml @@ -106,7 +106,7 @@ imagedef-nonsecure-exe = [] ## Have embassy-rp not provide the Image Definition so you can use your own. ## Place your own in the ".start_block" section like: -## ``` +## ```ignore ## use embassy_rp::block::ImageDef; ## ## #[link_section = ".start_block"] From 5d6877cbc6c8f5570cce7b311cc06e2667897afb Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Mon, 17 Feb 2025 13:38:31 +0800 Subject: [PATCH 0748/1217] otg: Allow exact out buffer size The existing check required N+1 buffer size. --- embassy-usb-synopsys-otg/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-usb-synopsys-otg/src/lib.rs b/embassy-usb-synopsys-otg/src/lib.rs index 44b2bd093..fc4428b54 100644 --- a/embassy-usb-synopsys-otg/src/lib.rs +++ b/embassy-usb-synopsys-otg/src/lib.rs @@ -357,7 +357,7 @@ impl<'d, const MAX_EP_COUNT: usize> Driver<'d, MAX_EP_COUNT> { ); if D::dir() == Direction::Out { - if self.ep_out_buffer_offset + max_packet_size as usize >= self.ep_out_buffer.len() { + if self.ep_out_buffer_offset + max_packet_size as usize > self.ep_out_buffer.len() { error!("Not enough endpoint out buffer capacity"); return Err(EndpointAllocError); } From 6f795d976cad49dacbe67173b50fd39098af618a Mon Sep 17 00:00:00 2001 From: Flamenco Date: Mon, 17 Feb 2025 08:15:09 -0500 Subject: [PATCH 0749/1217] Update control.rs Fix function name --- cyw43/src/control.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cyw43/src/control.rs b/cyw43/src/control.rs index 888cf4b90..f77b487e2 100644 --- a/cyw43/src/control.rs +++ b/cyw43/src/control.rs @@ -531,7 +531,7 @@ impl<'a> Control<'a> { } /// Retrieve the list of configured multicast hardware addresses. - pub async fn list_mulistcast_addresses(&mut self, result: &mut [[u8; 6]; 10]) -> usize { + pub async fn list_multicast_addresses(&mut self, result: &mut [[u8; 6]; 10]) -> usize { let mut buf = [0; 64]; self.get_iovar("mcast_list", &mut buf).await; From 5050b2fe8857644a7589b2b728bf32423b1c5089 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 17 Feb 2025 16:48:27 +0100 Subject: [PATCH 0750/1217] Update to Rust 1.84 --- .github/ci/build-xtensa.sh | 2 +- rust-toolchain.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/ci/build-xtensa.sh b/.github/ci/build-xtensa.sh index 88357a041..103575bc9 100755 --- a/.github/ci/build-xtensa.sh +++ b/.github/ci/build-xtensa.sh @@ -13,7 +13,7 @@ export CARGO_TARGET_DIR=/ci/cache/target export CARGO_NET_GIT_FETCH_WITH_CLI=true cargo install espup -/ci/cache/cargo/bin/espup install --toolchain-version 1.83.0.1 +/ci/cache/cargo/bin/espup install --toolchain-version 1.84.0.0 # Restore lockfiles if [ -f /ci/cache/lockfiles.tar ]; then diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 704d2e3a2..73c97872c 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,5 +1,5 @@ [toolchain] -channel = "1.83" +channel = "1.84" components = [ "rust-src", "rustfmt", "llvm-tools" ] targets = [ "thumbv7em-none-eabi", From 489abb1f8fef2767857bcd045d7cbf669a9a7ab3 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 17 Feb 2025 17:41:17 +0100 Subject: [PATCH 0751/1217] Update Rust nightly. --- rust-toolchain-nightly.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain-nightly.toml b/rust-toolchain-nightly.toml index 6efd98956..8faa1a073 100644 --- a/rust-toolchain-nightly.toml +++ b/rust-toolchain-nightly.toml @@ -1,5 +1,5 @@ [toolchain] -channel = "nightly-2024-12-10" +channel = "nightly-2025-02-17" components = [ "rust-src", "rustfmt", "llvm-tools", "miri" ] targets = [ "thumbv7em-none-eabi", From 89b5efc90059be1a47f3f068546c21d74b21c810 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 17 Feb 2025 17:57:50 +0100 Subject: [PATCH 0752/1217] Update cargo-batch. --- ci-nightly.sh | 2 +- ci.sh | 180 +++++++++++++++++++++++++------------------------- 2 files changed, 91 insertions(+), 91 deletions(-) diff --git a/ci-nightly.sh b/ci-nightly.sh index 1b69cc18e..e48ad2323 100755 --- a/ci-nightly.sh +++ b/ci-nightly.sh @@ -20,6 +20,6 @@ cargo batch \ --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,executor-thread,executor-interrupt \ --- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features nightly,arch-riscv32 \ --- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features nightly,arch-riscv32,executor-thread \ - --- build --release --manifest-path examples/nrf52840-rtic/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/nrf52840-rtic \ + --- build --release --manifest-path examples/nrf52840-rtic/Cargo.toml --target thumbv7em-none-eabi --artifact-dir out/examples/nrf52840-rtic \ cargo build --release --manifest-path embassy-executor/Cargo.toml --target avr-unknown-gnu-atmega328 -Z build-std=core,alloc --features nightly,arch-avr,avr-device/atmega328p diff --git a/ci.sh b/ci.sh index 56aa8b784..149999d58 100755 --- a/ci.sh +++ b/ci.sh @@ -20,7 +20,7 @@ TARGET=$(rustc -vV | sed -n 's|host: ||p') BUILD_EXTRA="" if [ $TARGET = "x86_64-unknown-linux-gnu" ]; then - BUILD_EXTRA="--- build --release --manifest-path examples/std/Cargo.toml --target $TARGET --out-dir out/examples/std" + BUILD_EXTRA="--- build --release --manifest-path examples/std/Cargo.toml --target $TARGET --artifact-dir out/examples/std" fi # CI intentionally does not use -eabihf on thumbv7em to minimize dep compile time. @@ -200,59 +200,59 @@ cargo batch \ --- build --release --manifest-path docs/examples/layer-by-layer/blinky-hal/Cargo.toml --target thumbv7em-none-eabi \ --- build --release --manifest-path docs/examples/layer-by-layer/blinky-irq/Cargo.toml --target thumbv7em-none-eabi \ --- build --release --manifest-path docs/examples/layer-by-layer/blinky-async/Cargo.toml --target thumbv7em-none-eabi \ - --- build --release --manifest-path examples/nrf52810/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/nrf52810 \ - --- build --release --manifest-path examples/nrf52840/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/nrf52840 \ - --- build --release --manifest-path examples/nrf5340/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/nrf5340 \ - --- build --release --manifest-path examples/nrf54l15/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/nrf54l15 \ - --- build --release --manifest-path examples/nrf9160/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/nrf9160 \ - --- build --release --manifest-path examples/nrf9151/s/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/nrf9151/s \ - --- build --release --manifest-path examples/nrf9151/ns/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/nrf9151/ns \ - --- build --release --manifest-path examples/nrf51/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/nrf51 \ - --- build --release --manifest-path examples/rp/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/rp \ - --- build --release --manifest-path examples/rp23/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/rp23 \ - --- build --release --manifest-path examples/stm32f0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/stm32f0 \ - --- build --release --manifest-path examples/stm32f1/Cargo.toml --target thumbv7m-none-eabi --out-dir out/examples/stm32f1 \ - --- build --release --manifest-path examples/stm32f2/Cargo.toml --target thumbv7m-none-eabi --out-dir out/examples/stm32f2 \ - --- build --release --manifest-path examples/stm32f3/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32f3 \ - --- build --release --manifest-path examples/stm32f334/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32f334 \ - --- build --release --manifest-path examples/stm32f4/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32f4 \ - --- build --release --manifest-path examples/stm32f469/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32f469 \ - --- build --release --manifest-path examples/stm32f7/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32f7 \ - --- build --release --manifest-path examples/stm32c0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/stm32c0 \ - --- build --release --manifest-path examples/stm32g0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/stm32g0 \ - --- build --release --manifest-path examples/stm32g4/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32g4 \ - --- build --release --manifest-path examples/stm32h5/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/stm32h5 \ - --- build --release --manifest-path examples/stm32h7/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32h7 \ - --- build --release --manifest-path examples/stm32h7b0/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32h7b0 \ - --- build --release --manifest-path examples/stm32h735/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32h735 \ - --- build --release --manifest-path examples/stm32h755cm4/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32h755cm4 \ - --- build --release --manifest-path examples/stm32h755cm7/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32h755cm7 \ - --- build --release --manifest-path examples/stm32h7rs/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32h7rs \ - --- build --release --manifest-path examples/stm32l0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/stm32l0 \ - --- build --release --manifest-path examples/stm32l1/Cargo.toml --target thumbv7m-none-eabi --out-dir out/examples/stm32l1 \ - --- build --release --manifest-path examples/stm32l4/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32l4 \ - --- build --release --manifest-path examples/stm32l432/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32l432 \ - --- build --release --manifest-path examples/stm32l5/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/stm32l5 \ - --- build --release --manifest-path examples/stm32u0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/stm32u0 \ - --- build --release --manifest-path examples/stm32u5/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/stm32u5 \ - --- build --release --manifest-path examples/stm32wb/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32wb \ - --- build --release --manifest-path examples/stm32wba/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/stm32wba \ - --- build --release --manifest-path examples/stm32wl/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32wl \ - --- build --release --manifest-path examples/lpc55s69/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/lpc55s69 \ - --- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840,skip-include --out-dir out/examples/boot/nrf52840 \ - --- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9160-ns,skip-include --out-dir out/examples/boot/nrf9160 \ - --- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9120-ns,skip-include --out-dir out/examples/boot/nrf9120 \ - --- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9151-ns,skip-include --out-dir out/examples/boot/nrf9151 \ - --- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9161-ns,skip-include --out-dir out/examples/boot/nrf9161 \ - --- build --release --manifest-path examples/boot/application/rp/Cargo.toml --target thumbv6m-none-eabi --features skip-include --out-dir out/examples/boot/rp \ - --- build --release --manifest-path examples/boot/application/stm32f3/Cargo.toml --target thumbv7em-none-eabi --features skip-include --out-dir out/examples/boot/stm32f3 \ - --- build --release --manifest-path examples/boot/application/stm32f7/Cargo.toml --target thumbv7em-none-eabi --features skip-include --out-dir out/examples/boot/stm32f7 \ - --- build --release --manifest-path examples/boot/application/stm32h7/Cargo.toml --target thumbv7em-none-eabi --features skip-include --out-dir out/examples/boot/stm32h7 \ - --- build --release --manifest-path examples/boot/application/stm32l0/Cargo.toml --target thumbv6m-none-eabi --features skip-include --out-dir out/examples/boot/stm32l0 \ - --- build --release --manifest-path examples/boot/application/stm32l1/Cargo.toml --target thumbv7m-none-eabi --features skip-include --out-dir out/examples/boot/stm32l1 \ - --- build --release --manifest-path examples/boot/application/stm32l4/Cargo.toml --target thumbv7em-none-eabi --features skip-include --out-dir out/examples/boot/stm32l4 \ - --- build --release --manifest-path examples/boot/application/stm32wl/Cargo.toml --target thumbv7em-none-eabi --features skip-include --out-dir out/examples/boot/stm32wl \ - --- build --release --manifest-path examples/boot/application/stm32wb-dfu/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/boot/stm32wb-dfu \ + --- build --release --manifest-path examples/nrf52810/Cargo.toml --target thumbv7em-none-eabi --artifact-dir out/examples/nrf52810 \ + --- build --release --manifest-path examples/nrf52840/Cargo.toml --target thumbv7em-none-eabi --artifact-dir out/examples/nrf52840 \ + --- build --release --manifest-path examples/nrf5340/Cargo.toml --target thumbv8m.main-none-eabihf --artifact-dir out/examples/nrf5340 \ + --- build --release --manifest-path examples/nrf54l15/Cargo.toml --target thumbv8m.main-none-eabihf --artifact-dir out/examples/nrf54l15 \ + --- build --release --manifest-path examples/nrf9160/Cargo.toml --target thumbv8m.main-none-eabihf --artifact-dir out/examples/nrf9160 \ + --- build --release --manifest-path examples/nrf9151/s/Cargo.toml --target thumbv8m.main-none-eabihf --artifact-dir out/examples/nrf9151/s \ + --- build --release --manifest-path examples/nrf9151/ns/Cargo.toml --target thumbv8m.main-none-eabihf --artifact-dir out/examples/nrf9151/ns \ + --- build --release --manifest-path examples/nrf51/Cargo.toml --target thumbv6m-none-eabi --artifact-dir out/examples/nrf51 \ + --- build --release --manifest-path examples/rp/Cargo.toml --target thumbv6m-none-eabi --artifact-dir out/examples/rp \ + --- build --release --manifest-path examples/rp23/Cargo.toml --target thumbv8m.main-none-eabihf --artifact-dir out/examples/rp23 \ + --- build --release --manifest-path examples/stm32f0/Cargo.toml --target thumbv6m-none-eabi --artifact-dir out/examples/stm32f0 \ + --- build --release --manifest-path examples/stm32f1/Cargo.toml --target thumbv7m-none-eabi --artifact-dir out/examples/stm32f1 \ + --- build --release --manifest-path examples/stm32f2/Cargo.toml --target thumbv7m-none-eabi --artifact-dir out/examples/stm32f2 \ + --- build --release --manifest-path examples/stm32f3/Cargo.toml --target thumbv7em-none-eabi --artifact-dir out/examples/stm32f3 \ + --- build --release --manifest-path examples/stm32f334/Cargo.toml --target thumbv7em-none-eabi --artifact-dir out/examples/stm32f334 \ + --- build --release --manifest-path examples/stm32f4/Cargo.toml --target thumbv7em-none-eabi --artifact-dir out/examples/stm32f4 \ + --- build --release --manifest-path examples/stm32f469/Cargo.toml --target thumbv7em-none-eabi --artifact-dir out/examples/stm32f469 \ + --- build --release --manifest-path examples/stm32f7/Cargo.toml --target thumbv7em-none-eabi --artifact-dir out/examples/stm32f7 \ + --- build --release --manifest-path examples/stm32c0/Cargo.toml --target thumbv6m-none-eabi --artifact-dir out/examples/stm32c0 \ + --- build --release --manifest-path examples/stm32g0/Cargo.toml --target thumbv6m-none-eabi --artifact-dir out/examples/stm32g0 \ + --- build --release --manifest-path examples/stm32g4/Cargo.toml --target thumbv7em-none-eabi --artifact-dir out/examples/stm32g4 \ + --- build --release --manifest-path examples/stm32h5/Cargo.toml --target thumbv8m.main-none-eabihf --artifact-dir out/examples/stm32h5 \ + --- build --release --manifest-path examples/stm32h7/Cargo.toml --target thumbv7em-none-eabi --artifact-dir out/examples/stm32h7 \ + --- build --release --manifest-path examples/stm32h7b0/Cargo.toml --target thumbv7em-none-eabi --artifact-dir out/examples/stm32h7b0 \ + --- build --release --manifest-path examples/stm32h735/Cargo.toml --target thumbv7em-none-eabi --artifact-dir out/examples/stm32h735 \ + --- build --release --manifest-path examples/stm32h755cm4/Cargo.toml --target thumbv7em-none-eabi --artifact-dir out/examples/stm32h755cm4 \ + --- build --release --manifest-path examples/stm32h755cm7/Cargo.toml --target thumbv7em-none-eabi --artifact-dir out/examples/stm32h755cm7 \ + --- build --release --manifest-path examples/stm32h7rs/Cargo.toml --target thumbv7em-none-eabi --artifact-dir out/examples/stm32h7rs \ + --- build --release --manifest-path examples/stm32l0/Cargo.toml --target thumbv6m-none-eabi --artifact-dir out/examples/stm32l0 \ + --- build --release --manifest-path examples/stm32l1/Cargo.toml --target thumbv7m-none-eabi --artifact-dir out/examples/stm32l1 \ + --- build --release --manifest-path examples/stm32l4/Cargo.toml --target thumbv7em-none-eabi --artifact-dir out/examples/stm32l4 \ + --- build --release --manifest-path examples/stm32l432/Cargo.toml --target thumbv7em-none-eabi --artifact-dir out/examples/stm32l432 \ + --- build --release --manifest-path examples/stm32l5/Cargo.toml --target thumbv8m.main-none-eabihf --artifact-dir out/examples/stm32l5 \ + --- build --release --manifest-path examples/stm32u0/Cargo.toml --target thumbv6m-none-eabi --artifact-dir out/examples/stm32u0 \ + --- build --release --manifest-path examples/stm32u5/Cargo.toml --target thumbv8m.main-none-eabihf --artifact-dir out/examples/stm32u5 \ + --- build --release --manifest-path examples/stm32wb/Cargo.toml --target thumbv7em-none-eabi --artifact-dir out/examples/stm32wb \ + --- build --release --manifest-path examples/stm32wba/Cargo.toml --target thumbv8m.main-none-eabihf --artifact-dir out/examples/stm32wba \ + --- build --release --manifest-path examples/stm32wl/Cargo.toml --target thumbv7em-none-eabi --artifact-dir out/examples/stm32wl \ + --- build --release --manifest-path examples/lpc55s69/Cargo.toml --target thumbv8m.main-none-eabihf --artifact-dir out/examples/lpc55s69 \ + --- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840,skip-include --artifact-dir out/examples/boot/nrf52840 \ + --- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9160-ns,skip-include --artifact-dir out/examples/boot/nrf9160 \ + --- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9120-ns,skip-include --artifact-dir out/examples/boot/nrf9120 \ + --- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9151-ns,skip-include --artifact-dir out/examples/boot/nrf9151 \ + --- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9161-ns,skip-include --artifact-dir out/examples/boot/nrf9161 \ + --- build --release --manifest-path examples/boot/application/rp/Cargo.toml --target thumbv6m-none-eabi --features skip-include --artifact-dir out/examples/boot/rp \ + --- build --release --manifest-path examples/boot/application/stm32f3/Cargo.toml --target thumbv7em-none-eabi --features skip-include --artifact-dir out/examples/boot/stm32f3 \ + --- build --release --manifest-path examples/boot/application/stm32f7/Cargo.toml --target thumbv7em-none-eabi --features skip-include --artifact-dir out/examples/boot/stm32f7 \ + --- build --release --manifest-path examples/boot/application/stm32h7/Cargo.toml --target thumbv7em-none-eabi --features skip-include --artifact-dir out/examples/boot/stm32h7 \ + --- build --release --manifest-path examples/boot/application/stm32l0/Cargo.toml --target thumbv6m-none-eabi --features skip-include --artifact-dir out/examples/boot/stm32l0 \ + --- build --release --manifest-path examples/boot/application/stm32l1/Cargo.toml --target thumbv7m-none-eabi --features skip-include --artifact-dir out/examples/boot/stm32l1 \ + --- build --release --manifest-path examples/boot/application/stm32l4/Cargo.toml --target thumbv7em-none-eabi --features skip-include --artifact-dir out/examples/boot/stm32l4 \ + --- build --release --manifest-path examples/boot/application/stm32wl/Cargo.toml --target thumbv7em-none-eabi --features skip-include --artifact-dir out/examples/boot/stm32wl \ + --- build --release --manifest-path examples/boot/application/stm32wb-dfu/Cargo.toml --target thumbv7em-none-eabi --artifact-dir out/examples/boot/stm32wb-dfu \ --- build --release --manifest-path examples/boot/bootloader/nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840 \ --- build --release --manifest-path examples/boot/bootloader/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9160-ns \ --- build --release --manifest-path examples/boot/bootloader/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9120-ns \ @@ -262,42 +262,42 @@ cargo batch \ --- build --release --manifest-path examples/boot/bootloader/stm32/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32l496zg \ --- build --release --manifest-path examples/boot/bootloader/stm32wb-dfu/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32wb55rg \ --- build --release --manifest-path examples/boot/bootloader/stm32-dual-bank/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32h743zi \ - --- build --release --manifest-path examples/wasm/Cargo.toml --target wasm32-unknown-unknown --out-dir out/examples/wasm \ - --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f103c8 --out-dir out/tests/stm32f103c8 \ - --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi --out-dir out/tests/stm32f429zi \ - --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f446re --out-dir out/tests/stm32f446re \ - --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32g491re --out-dir out/tests/stm32g491re \ - --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32g071rb --out-dir out/tests/stm32g071rb \ - --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32c031c6 --out-dir out/tests/stm32c031c6 \ - --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h755zi --out-dir out/tests/stm32h755zi \ - --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h753zi --out-dir out/tests/stm32h753zi \ - --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h7a3zi --out-dir out/tests/stm32h7a3zi \ - --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wb55rg --out-dir out/tests/stm32wb55rg \ - --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32h563zi --out-dir out/tests/stm32h563zi \ - --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32u585ai --out-dir out/tests/stm32u585ai \ - --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32u5a5zj --out-dir out/tests/stm32u5a5zj \ - --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32wba52cg --out-dir out/tests/stm32wba52cg \ - --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32l073rz --out-dir out/tests/stm32l073rz \ - --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32l152re --out-dir out/tests/stm32l152re \ - --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l4a6zg --out-dir out/tests/stm32l4a6zg \ - --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l4r5zi --out-dir out/tests/stm32l4r5zi \ - --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze --out-dir out/tests/stm32l552ze \ - --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f767zi --out-dir out/tests/stm32f767zi \ - --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f207zg --out-dir out/tests/stm32f207zg \ - --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f303ze --out-dir out/tests/stm32f303ze \ - --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l496zg --out-dir out/tests/stm32l496zg \ - --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wl55jc --out-dir out/tests/stm32wl55jc \ - --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h7s3l8 --out-dir out/tests/stm32h7s3l8 \ - --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32f091rc --out-dir out/tests/stm32f091rc \ - --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32h503rb --out-dir out/tests/stm32h503rb \ - --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32u083rc --out-dir out/tests/stm32u083rc \ - --- build --release --manifest-path tests/rp/Cargo.toml --target thumbv6m-none-eabi --out-dir out/tests/rpi-pico \ - --- build --release --manifest-path tests/nrf/Cargo.toml --target thumbv6m-none-eabi --features nrf51422 --out-dir out/tests/nrf51422-dk \ - --- build --release --manifest-path tests/nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52832 --out-dir out/tests/nrf52832-dk \ - --- build --release --manifest-path tests/nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52833 --out-dir out/tests/nrf52833-dk \ - --- build --release --manifest-path tests/nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52840 --out-dir out/tests/nrf52840-dk \ - --- build --release --manifest-path tests/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features nrf5340 --out-dir out/tests/nrf5340-dk \ - --- build --release --manifest-path tests/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features nrf9160 --out-dir out/tests/nrf9160-dk \ + --- build --release --manifest-path examples/wasm/Cargo.toml --target wasm32-unknown-unknown --artifact-dir out/examples/wasm \ + --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f103c8 --artifact-dir out/tests/stm32f103c8 \ + --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi --artifact-dir out/tests/stm32f429zi \ + --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f446re --artifact-dir out/tests/stm32f446re \ + --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32g491re --artifact-dir out/tests/stm32g491re \ + --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32g071rb --artifact-dir out/tests/stm32g071rb \ + --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32c031c6 --artifact-dir out/tests/stm32c031c6 \ + --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h755zi --artifact-dir out/tests/stm32h755zi \ + --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h753zi --artifact-dir out/tests/stm32h753zi \ + --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h7a3zi --artifact-dir out/tests/stm32h7a3zi \ + --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wb55rg --artifact-dir out/tests/stm32wb55rg \ + --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32h563zi --artifact-dir out/tests/stm32h563zi \ + --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32u585ai --artifact-dir out/tests/stm32u585ai \ + --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32u5a5zj --artifact-dir out/tests/stm32u5a5zj \ + --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32wba52cg --artifact-dir out/tests/stm32wba52cg \ + --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32l073rz --artifact-dir out/tests/stm32l073rz \ + --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32l152re --artifact-dir out/tests/stm32l152re \ + --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l4a6zg --artifact-dir out/tests/stm32l4a6zg \ + --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l4r5zi --artifact-dir out/tests/stm32l4r5zi \ + --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze --artifact-dir out/tests/stm32l552ze \ + --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f767zi --artifact-dir out/tests/stm32f767zi \ + --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f207zg --artifact-dir out/tests/stm32f207zg \ + --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f303ze --artifact-dir out/tests/stm32f303ze \ + --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l496zg --artifact-dir out/tests/stm32l496zg \ + --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wl55jc --artifact-dir out/tests/stm32wl55jc \ + --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h7s3l8 --artifact-dir out/tests/stm32h7s3l8 \ + --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32f091rc --artifact-dir out/tests/stm32f091rc \ + --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32h503rb --artifact-dir out/tests/stm32h503rb \ + --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32u083rc --artifact-dir out/tests/stm32u083rc \ + --- build --release --manifest-path tests/rp/Cargo.toml --target thumbv6m-none-eabi --artifact-dir out/tests/rpi-pico \ + --- build --release --manifest-path tests/nrf/Cargo.toml --target thumbv6m-none-eabi --features nrf51422 --artifact-dir out/tests/nrf51422-dk \ + --- build --release --manifest-path tests/nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52832 --artifact-dir out/tests/nrf52832-dk \ + --- build --release --manifest-path tests/nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52833 --artifact-dir out/tests/nrf52833-dk \ + --- build --release --manifest-path tests/nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52840 --artifact-dir out/tests/nrf52840-dk \ + --- build --release --manifest-path tests/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features nrf5340 --artifact-dir out/tests/nrf5340-dk \ + --- build --release --manifest-path tests/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features nrf9160 --artifact-dir out/tests/nrf9160-dk \ --- build --release --manifest-path tests/riscv32/Cargo.toml --target riscv32imac-unknown-none-elf \ $BUILD_EXTRA From 9e785438eecc3a0645e4d3b99d2708f3c2e329b6 Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Tue, 18 Feb 2025 09:58:20 -0500 Subject: [PATCH 0753/1217] Inital rp23 ci tests Some tests need more work. * The adc test builds, but isn't set up correctly for the 2350 hardware yet. * The multicore and gpio_multicore tests only work from flash, seems to be a probe-rs issue. * The i2c and flash tests also only works from flash, these are probably bugs but I don't have time to run them down now. * The 2350 gpio test skips anything with pull downs. I think these fail because of E9. The float, bootsel, cyw43, and ethernet tests don't have 2350 equivalents. There's no reason to use the float romfuncs, use the FPU. Bootsel as a button isn't supported on the 2350 yet. The wifi and eth tests don't have appropriate hardware. The i2c test has also been tweaked to run on one core. --- ci.sh | 12 +++++- tests/rp/.cargo/config.toml | 6 ++- tests/rp/Cargo.toml | 31 +++++++++++++- tests/rp/readme.md | 8 ++++ tests/rp/src/bin/adc.rs | 65 ++++++++++++++---------------- tests/rp/src/bin/dma_copy_async.rs | 3 ++ tests/rp/src/bin/flash.rs | 19 ++++++--- tests/rp/src/bin/gpio.rs | 10 ++++- tests/rp/src/bin/gpio_async.rs | 3 ++ tests/rp/src/bin/gpio_multicore.rs | 5 ++- tests/rp/src/bin/i2c.rs | 25 ++++-------- tests/rp/src/bin/multicore.rs | 3 ++ tests/rp/src/bin/pio_irq.rs | 3 ++ tests/rp/src/bin/pio_multi_load.rs | 3 ++ tests/rp/src/bin/pwm.rs | 11 ++++- tests/rp/src/bin/spi.rs | 3 ++ tests/rp/src/bin/spi_async.rs | 3 ++ tests/rp/src/bin/timer.rs | 3 ++ tests/rp/src/bin/uart.rs | 3 ++ tests/rp/src/bin/uart_buffered.rs | 3 ++ tests/rp/src/bin/uart_dma.rs | 3 ++ tests/rp/src/bin/uart_upgrade.rs | 3 ++ 22 files changed, 164 insertions(+), 64 deletions(-) create mode 100644 tests/rp/readme.md diff --git a/ci.sh b/ci.sh index 149999d58..5e01805ef 100755 --- a/ci.sh +++ b/ci.sh @@ -291,7 +291,8 @@ cargo batch \ --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32f091rc --artifact-dir out/tests/stm32f091rc \ --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32h503rb --artifact-dir out/tests/stm32h503rb \ --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32u083rc --artifact-dir out/tests/stm32u083rc \ - --- build --release --manifest-path tests/rp/Cargo.toml --target thumbv6m-none-eabi --artifact-dir out/tests/rpi-pico \ + --- build --release --manifest-path tests/rp/Cargo.toml --target thumbv6m-none-eabi --features rp2040 --artifact-dir out/tests/rpi-pico \ + --- build --release --manifest-path tests/rp/Cargo.toml --target thumbv8m.main-none-eabihf --features rp235xb --artifact-dir out/tests/pimoroni-pico-plus-2 \ --- build --release --manifest-path tests/nrf/Cargo.toml --target thumbv6m-none-eabi --features nrf51422 --artifact-dir out/tests/nrf51422-dk \ --- build --release --manifest-path tests/nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52832 --artifact-dir out/tests/nrf52832-dk \ --- build --release --manifest-path tests/nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52833 --artifact-dir out/tests/nrf52833-dk \ @@ -319,6 +320,15 @@ rm out/tests/stm32f207zg/usart_rx_ringbuffered # doesn't work, gives "noise error", no idea why. usart_dma does pass. rm out/tests/stm32u5a5zj/usart +# probe-rs error: "multi-core ram flash start not implemented yet" +# As of 2025-02-17 these tests work when run from flash +rm out/tests/pimoroni-pico-plus-2/multicore +rm out/tests/pimoroni-pico-plus-2/gpio_multicore +# Doesn't work when run from ram on the 2350 +rm out/tests/pimoroni-pico-plus-2/flash +# This test passes locally but fails on the HIL, no idea why +rm out/tests/pimoroni-pico-plus-2/i2c + if [[ -z "${TELEPROBE_TOKEN-}" ]]; then echo No teleprobe token found, skipping running HIL tests exit diff --git a/tests/rp/.cargo/config.toml b/tests/rp/.cargo/config.toml index 4337924cc..649c15048 100644 --- a/tests/rp/.cargo/config.toml +++ b/tests/rp/.cargo/config.toml @@ -5,8 +5,9 @@ #build-std-features = ["panic_immediate_abort"] [target.'cfg(all(target_arch = "arm", target_os = "none"))'] -runner = "teleprobe client run" +#runner = "teleprobe client run" #runner = "teleprobe local run --chip RP2040 --elf" +runner = "teleprobe local run --chip RP235X --elf" rustflags = [ # Code-size optimizations. @@ -15,7 +16,8 @@ rustflags = [ ] [build] -target = "thumbv6m-none-eabi" +#target = "thumbv6m-none-eabi" +target = "thumbv8m.main-none-eabihf" [env] DEFMT_LOG = "trace,embassy_hal_internal=debug,embassy_net_esp_hosted=debug,cyw43=info,cyw43_pio=info,smoltcp=info" diff --git a/tests/rp/Cargo.toml b/tests/rp/Cargo.toml index 5a6a6c75a..22e3d32a2 100644 --- a/tests/rp/Cargo.toml +++ b/tests/rp/Cargo.toml @@ -4,13 +4,18 @@ name = "embassy-rp-tests" version = "0.1.0" license = "MIT OR Apache-2.0" +[features] +rp2040 = ["embassy-rp/rp2040"] +rp235xa = ["embassy-rp/rp235xa"] +rp235xb = ["embassy-rp/rp235xb"] + [dependencies] teleprobe-meta = "1.1" embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", ] } -embassy-rp = { version = "0.3.0", path = "../../embassy-rp", features = [ "defmt", "unstable-pac", "time-driver", "critical-section-impl", "intrinsics", "rom-v2-intrinsics", "run-from-ram", "rp2040"] } +embassy-rp = { version = "0.3.0", path = "../../embassy-rp", features = [ "defmt", "unstable-pac", "time-driver", "critical-section-impl", "intrinsics", "rom-v2-intrinsics", "run-from-ram"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-net = { version = "0.7.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "dhcpv4", "medium-ethernet"] } embassy-net-wiznet = { version = "0.2.0", path = "../../embassy-net-wiznet", features = ["defmt"] } @@ -37,6 +42,30 @@ pio-proc = { git = "https://github.com/rp-rs/pio-rs", rev = "fa586448b0b223217ee pio = { git = "https://github.com/rp-rs/pio-rs", rev = "fa586448b0b223217eec8c92c19fe6823dd04cc4" } rand = { version = "0.8.5", default-features = false } +# bootsel not currently supported on 2350 +[[bin]] +name = "bootsel" +path = "src/bin/bootsel.rs" +required-features = [ "rp2040",] + +# 2350 devboard isn't a W +[[bin]] +name = "cyw43-perf" +path = "src/bin/cyw43-perf.rs" +required-features = [ "rp2040",] + +# Eth test only for the w5100s-evb-pico +[[bin]] +name = "ethernet_w5100s_perf" +path = "src/bin/ethernet_w5100s_perf.rs" +required-features = [ "rp2040",] + +# Float intrinsics are only relevant for the 2040 +[[bin]] +name = "float" +path = "src/bin/float.rs" +required-features = [ "rp2040",] + [profile.dev] debug = 2 debug-assertions = true diff --git a/tests/rp/readme.md b/tests/rp/readme.md new file mode 100644 index 000000000..f8192a95a --- /dev/null +++ b/tests/rp/readme.md @@ -0,0 +1,8 @@ +# Pico and Pico 2 Plus connections + +GP0-GP1 +GP3-GP4 +GP6-GP9 +GP7-GP11 +GP18-GP20 with 10k pullup +GP19-GP21 with 10k pullup diff --git a/tests/rp/src/bin/adc.rs b/tests/rp/src/bin/adc.rs index 65c246472..8eeaad95d 100644 --- a/tests/rp/src/bin/adc.rs +++ b/tests/rp/src/bin/adc.rs @@ -1,12 +1,17 @@ #![no_std] #![no_main] +#[cfg(feature = "rp2040")] teleprobe_meta::target!(b"rpi-pico"); +#[cfg(feature = "rp235xb")] +teleprobe_meta::target!(b"pimoroni-pico-plus-2"); use defmt::*; use embassy_executor::Spawner; -use embassy_rp::adc::{Adc, Channel, Config, InterruptHandler, Sample}; +use embassy_rp::adc::Sample; +use embassy_rp::adc::{Adc, Channel, Config, InterruptHandler}; use embassy_rp::bind_interrupts; -use embassy_rp::gpio::{Level, Output, Pull}; +use embassy_rp::gpio::Pull; +use embassy_rp::gpio::{Level, Output}; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { @@ -20,14 +25,19 @@ async fn main(_spawner: Spawner) { let _wifi_off = Output::new(p.PIN_25, Level::High); let mut adc = Adc::new(p.ADC, Irqs, Config::default()); + #[cfg(any(feature = "rp2040", feature = "rp235xa"))] + let (mut a, mut b, mut c, mut d) = (p.PIN_26, p.PIN_27, p.PIN_28, p.PIN_29); + #[cfg(feature = "rp235xb")] + let (mut a, mut b, mut c, mut d) = (p.PIN_44, p.PIN_45, p.PIN_46, p.PIN_47); + { { - let mut p = Channel::new_pin(&mut p.PIN_26, Pull::Down); + let mut p = Channel::new_pin(&mut a, Pull::Down); defmt::assert!(adc.blocking_read(&mut p).unwrap() < 0b01_0000_0000); defmt::assert!(adc.read(&mut p).await.unwrap() < 0b01_0000_0000); } { - let mut p = Channel::new_pin(&mut p.PIN_26, Pull::Up); + let mut p = Channel::new_pin(&mut a, Pull::Up); defmt::assert!(adc.blocking_read(&mut p).unwrap() > 0b11_0000_0000); defmt::assert!(adc.read(&mut p).await.unwrap() > 0b11_0000_0000); } @@ -35,21 +45,21 @@ async fn main(_spawner: Spawner) { // not bothering with async reads from now on { { - let mut p = Channel::new_pin(&mut p.PIN_27, Pull::Down); + let mut p = Channel::new_pin(&mut b, Pull::Down); defmt::assert!(adc.blocking_read(&mut p).unwrap() < 0b01_0000_0000); } { - let mut p = Channel::new_pin(&mut p.PIN_27, Pull::Up); + let mut p = Channel::new_pin(&mut b, Pull::Up); defmt::assert!(adc.blocking_read(&mut p).unwrap() > 0b11_0000_0000); } } { { - let mut p = Channel::new_pin(&mut p.PIN_28, Pull::Down); + let mut p = Channel::new_pin(&mut c, Pull::Down); defmt::assert!(adc.blocking_read(&mut p).unwrap() < 0b01_0000_0000); } { - let mut p = Channel::new_pin(&mut p.PIN_28, Pull::Up); + let mut p = Channel::new_pin(&mut c, Pull::Up); defmt::assert!(adc.blocking_read(&mut p).unwrap() > 0b11_0000_0000); } } @@ -57,15 +67,15 @@ async fn main(_spawner: Spawner) { // gp29 is connected to vsys through a 200k/100k divider, // adding pulls should change the value let low = { - let mut p = Channel::new_pin(&mut p.PIN_29, Pull::Down); + let mut p = Channel::new_pin(&mut d, Pull::Down); adc.blocking_read(&mut p).unwrap() }; let none = { - let mut p = Channel::new_pin(&mut p.PIN_29, Pull::None); + let mut p = Channel::new_pin(&mut d, Pull::None); adc.blocking_read(&mut p).unwrap() }; let up = { - let mut p = Channel::new_pin(&mut p.PIN_29, Pull::Up); + let mut p = Channel::new_pin(&mut d, Pull::Up); adc.blocking_read(&mut p).unwrap() }; defmt::assert!(low < none); @@ -89,29 +99,14 @@ async fn main(_spawner: Spawner) { let mut low = [0u16; 16]; let mut none = [0u8; 16]; let mut up = [Sample::default(); 16]; - adc.read_many( - &mut Channel::new_pin(&mut p.PIN_29, Pull::Down), - &mut low, - 1, - &mut p.DMA_CH0, - ) - .await - .unwrap(); - adc.read_many( - &mut Channel::new_pin(&mut p.PIN_29, Pull::None), - &mut none, - 1, - &mut p.DMA_CH0, - ) - .await - .unwrap(); - adc.read_many_raw( - &mut Channel::new_pin(&mut p.PIN_29, Pull::Up), - &mut up, - 1, - &mut p.DMA_CH0, - ) - .await; + adc.read_many(&mut Channel::new_pin(&mut d, Pull::Down), &mut low, 1, &mut p.DMA_CH0) + .await + .unwrap(); + adc.read_many(&mut Channel::new_pin(&mut d, Pull::None), &mut none, 1, &mut p.DMA_CH0) + .await + .unwrap(); + adc.read_many_raw(&mut Channel::new_pin(&mut d, Pull::Up), &mut up, 1, &mut p.DMA_CH0) + .await; defmt::assert!(low.iter().zip(none.iter()).all(|(l, n)| *l >> 4 < *n as u16)); defmt::assert!(up.iter().all(|s| s.good())); defmt::assert!(none.iter().zip(up.iter()).all(|(n, u)| (*n as u16) < u.value())); @@ -133,7 +128,7 @@ async fn main(_spawner: Spawner) { { let mut multi = [0u16; 2]; let mut channels = [ - Channel::new_pin(&mut p.PIN_26, Pull::Up), + Channel::new_pin(&mut a, Pull::Up), Channel::new_temp_sensor(&mut p.ADC_TEMP_SENSOR), ]; adc.read_many_multichannel(&mut channels, &mut multi, 1, &mut p.DMA_CH0) diff --git a/tests/rp/src/bin/dma_copy_async.rs b/tests/rp/src/bin/dma_copy_async.rs index 7c64bc396..3dcf4f4d8 100644 --- a/tests/rp/src/bin/dma_copy_async.rs +++ b/tests/rp/src/bin/dma_copy_async.rs @@ -1,6 +1,9 @@ #![no_std] #![no_main] +#[cfg(feature = "rp2040")] teleprobe_meta::target!(b"rpi-pico"); +#[cfg(feature = "rp235xb")] +teleprobe_meta::target!(b"pimoroni-pico-plus-2"); use defmt::{assert_eq, *}; use embassy_executor::Spawner; diff --git a/tests/rp/src/bin/flash.rs b/tests/rp/src/bin/flash.rs index 310f0d586..548a6ee72 100644 --- a/tests/rp/src/bin/flash.rs +++ b/tests/rp/src/bin/flash.rs @@ -1,6 +1,9 @@ #![no_std] #![no_main] +#[cfg(feature = "rp2040")] teleprobe_meta::target!(b"rpi-pico"); +#[cfg(feature = "rp235xb")] +teleprobe_meta::target!(b"pimoroni-pico-plus-2"); use defmt::*; use embassy_executor::Spawner; @@ -24,13 +27,19 @@ async fn main(_spawner: Spawner) { let mut flash = embassy_rp::flash::Flash::<_, Async, { 2 * 1024 * 1024 }>::new(p.FLASH, p.DMA_CH0); // Get JEDEC id - let jedec = defmt::unwrap!(flash.blocking_jedec_id()); - info!("jedec id: 0x{:x}", jedec); + #[cfg(feature = "rp2040")] + { + let jedec = defmt::unwrap!(flash.blocking_jedec_id()); + info!("jedec id: 0x{:x}", jedec); + } // Get unique id - let mut uid = [0; 8]; - defmt::unwrap!(flash.blocking_unique_id(&mut uid)); - info!("unique id: {:?}", uid); + #[cfg(feature = "rp2040")] + { + let mut uid = [0; 8]; + defmt::unwrap!(flash.blocking_unique_id(&mut uid)); + info!("unique id: {:?}", uid); + } let mut buf = [0u8; ERASE_SIZE]; defmt::unwrap!(flash.blocking_read(ADDR_OFFSET, &mut buf)); diff --git a/tests/rp/src/bin/gpio.rs b/tests/rp/src/bin/gpio.rs index e0c309887..6c37ac5be 100644 --- a/tests/rp/src/bin/gpio.rs +++ b/tests/rp/src/bin/gpio.rs @@ -1,10 +1,15 @@ #![no_std] #![no_main] +#[cfg(feature = "rp2040")] teleprobe_meta::target!(b"rpi-pico"); +#[cfg(feature = "rp235xb")] +teleprobe_meta::target!(b"pimoroni-pico-plus-2"); use defmt::{assert, *}; use embassy_executor::Spawner; -use embassy_rp::gpio::{Flex, Input, Level, Output, OutputOpenDrain, Pull}; +#[cfg(feature = "rp2040")] +use embassy_rp::gpio::OutputOpenDrain; +use embassy_rp::gpio::{Flex, Input, Level, Output, Pull}; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] @@ -76,6 +81,7 @@ async fn main(_spawner: Spawner) { } // Test input pulldown + #[cfg(feature = "rp2040")] { let b = Input::new(&mut b, Pull::Down); delay(); @@ -104,6 +110,7 @@ async fn main(_spawner: Spawner) { } // OUTPUT OPEN DRAIN + #[cfg(feature = "rp2040")] { let mut b = OutputOpenDrain::new(&mut b, Level::High); let mut a = Flex::new(&mut a); @@ -202,6 +209,7 @@ async fn main(_spawner: Spawner) { } // Test input pulldown + #[cfg(feature = "rp2040")] { let mut b = Flex::new(&mut b); b.set_as_input(); diff --git a/tests/rp/src/bin/gpio_async.rs b/tests/rp/src/bin/gpio_async.rs index 40a304464..39e3d6337 100644 --- a/tests/rp/src/bin/gpio_async.rs +++ b/tests/rp/src/bin/gpio_async.rs @@ -1,6 +1,9 @@ #![no_std] #![no_main] +#[cfg(feature = "rp2040")] teleprobe_meta::target!(b"rpi-pico"); +#[cfg(feature = "rp235xb")] +teleprobe_meta::target!(b"pimoroni-pico-plus-2"); use defmt::{assert, *}; use embassy_executor::Spawner; diff --git a/tests/rp/src/bin/gpio_multicore.rs b/tests/rp/src/bin/gpio_multicore.rs index e9c6f3122..3caa8ef35 100644 --- a/tests/rp/src/bin/gpio_multicore.rs +++ b/tests/rp/src/bin/gpio_multicore.rs @@ -1,6 +1,9 @@ #![no_std] #![no_main] +#[cfg(feature = "rp2040")] teleprobe_meta::target!(b"rpi-pico"); +#[cfg(feature = "rp235xb")] +teleprobe_meta::target!(b"pimoroni-pico-plus-2"); use defmt::{info, unwrap}; use embassy_executor::Executor; @@ -56,7 +59,7 @@ async fn core1_task(p: PIN_1) { CHANNEL0.receive().await; - let mut pin = Input::new(p, Pull::Down); + let mut pin = Input::new(p, Pull::None); let wait = pin.wait_for_rising_edge(); CHANNEL1.send(()).await; diff --git a/tests/rp/src/bin/i2c.rs b/tests/rp/src/bin/i2c.rs index 9615007bd..2c835bd5a 100644 --- a/tests/rp/src/bin/i2c.rs +++ b/tests/rp/src/bin/i2c.rs @@ -1,23 +1,21 @@ #![no_std] #![no_main] +#[cfg(feature = "rp2040")] teleprobe_meta::target!(b"rpi-pico"); +#[cfg(feature = "rp235xb")] +teleprobe_meta::target!(b"pimoroni-pico-plus-2"); -use defmt::{assert_eq, info, panic, unwrap}; +use defmt::{assert_eq, info, panic}; use embassy_embedded_hal::SetConfig; -use embassy_executor::{Executor, Spawner}; +use embassy_executor::Spawner; use embassy_rp::clocks::{PllConfig, XoscConfig}; use embassy_rp::config::Config as rpConfig; -use embassy_rp::multicore::{spawn_core1, Stack}; use embassy_rp::peripherals::{I2C0, I2C1}; use embassy_rp::{bind_interrupts, i2c, i2c_slave}; use embedded_hal_1::i2c::Operation; use embedded_hal_async::i2c::I2c; -use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _, panic_probe as _, panic_probe as _}; -static mut CORE1_STACK: Stack<1024> = Stack::new(); -static EXECUTOR1: StaticCell = StaticCell::new(); - use crate::i2c::AbortReason; bind_interrupts!(struct Irqs { @@ -106,7 +104,7 @@ async fn device_task(mut dev: i2c_slave::I2cSlave<'static, I2C1>) -> ! { } async fn controller_task(con: &mut i2c::I2c<'static, I2C0, i2c::Async>) { - info!("Device start"); + info!("Controller start"); { let buf = [0xCA, 0x11]; @@ -180,7 +178,7 @@ async fn controller_task(con: &mut i2c::I2c<'static, I2C0, i2c::Async>) { } #[embassy_executor::main] - async fn main(_core0_spawner: Spawner) { + async fn main(spawner: Spawner) { let mut config = rpConfig::default(); // Configure clk_sys to 48MHz to support 1kHz scl. // In theory it can go lower, but we won't bother to test below 1kHz. @@ -210,14 +208,7 @@ async fn controller_task(con: &mut i2c::I2c<'static, I2C0, i2c::Async>) { config.addr = DEV_ADDR as u16; let device = i2c_slave::I2cSlave::new(p.I2C1, d_sda, d_scl, Irqs, config); - spawn_core1( - p.CORE1, - unsafe { &mut *core::ptr::addr_of_mut!(CORE1_STACK) }, - move || { - let executor1 = EXECUTOR1.init(Executor::new()); - executor1.run(|spawner| unwrap!(spawner.spawn(device_task(device)))); - }, - ); + spawner.must_spawn(device_task(device)); let c_sda = p.PIN_21; let c_scl = p.PIN_20; diff --git a/tests/rp/src/bin/multicore.rs b/tests/rp/src/bin/multicore.rs index 783ea0f27..902169c40 100644 --- a/tests/rp/src/bin/multicore.rs +++ b/tests/rp/src/bin/multicore.rs @@ -1,6 +1,9 @@ #![no_std] #![no_main] +#[cfg(feature = "rp2040")] teleprobe_meta::target!(b"rpi-pico"); +#[cfg(feature = "rp235xb")] +teleprobe_meta::target!(b"pimoroni-pico-plus-2"); use defmt::{info, unwrap}; use embassy_executor::Executor; diff --git a/tests/rp/src/bin/pio_irq.rs b/tests/rp/src/bin/pio_irq.rs index 33cdaaac9..512c7f799 100644 --- a/tests/rp/src/bin/pio_irq.rs +++ b/tests/rp/src/bin/pio_irq.rs @@ -1,6 +1,9 @@ #![no_std] #![no_main] +#[cfg(feature = "rp2040")] teleprobe_meta::target!(b"rpi-pico"); +#[cfg(feature = "rp235xb")] +teleprobe_meta::target!(b"pimoroni-pico-plus-2"); use defmt::info; use embassy_executor::Spawner; diff --git a/tests/rp/src/bin/pio_multi_load.rs b/tests/rp/src/bin/pio_multi_load.rs index cd28f99b6..b584bc34e 100644 --- a/tests/rp/src/bin/pio_multi_load.rs +++ b/tests/rp/src/bin/pio_multi_load.rs @@ -1,6 +1,9 @@ #![no_std] #![no_main] +#[cfg(feature = "rp2040")] teleprobe_meta::target!(b"rpi-pico"); +#[cfg(feature = "rp235xb")] +teleprobe_meta::target!(b"pimoroni-pico-plus-2"); use defmt::info; use embassy_executor::Spawner; diff --git a/tests/rp/src/bin/pwm.rs b/tests/rp/src/bin/pwm.rs index c05197000..d8ee78dcd 100644 --- a/tests/rp/src/bin/pwm.rs +++ b/tests/rp/src/bin/pwm.rs @@ -1,10 +1,15 @@ #![no_std] #![no_main] +#[cfg(feature = "rp2040")] teleprobe_meta::target!(b"rpi-pico"); +#[cfg(feature = "rp235xb")] +teleprobe_meta::target!(b"pimoroni-pico-plus-2"); use defmt::{assert, assert_eq, assert_ne, *}; use embassy_executor::Spawner; -use embassy_rp::gpio::{Input, Level, Output, Pull}; +use embassy_rp::gpio::{Input, Pull}; +#[cfg(feature = "rp2040")] +use embassy_rp::gpio::{Level, Output}; use embassy_rp::pwm::{Config, InputMode, Pwm}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; @@ -92,6 +97,7 @@ async fn main(_spawner: Spawner) { } // Test level-gated + #[cfg(feature = "rp2040")] { let mut pin2 = Output::new(&mut p11, Level::Low); let pwm = Pwm::new_input(&mut p.PWM_SLICE3, &mut p7, Pull::None, InputMode::Level, cfg.clone()); @@ -102,12 +108,14 @@ async fn main(_spawner: Spawner) { Timer::after_millis(1).await; pin2.set_low(); let ctr = pwm.counter(); + info!("ctr: {}", ctr); assert!(ctr >= 1000); Timer::after_millis(1).await; assert_eq!(pwm.counter(), ctr); } // Test rising-gated + #[cfg(feature = "rp2040")] { let mut pin2 = Output::new(&mut p11, Level::Low); let pwm = Pwm::new_input( @@ -129,6 +137,7 @@ async fn main(_spawner: Spawner) { } // Test falling-gated + #[cfg(feature = "rp2040")] { let mut pin2 = Output::new(&mut p11, Level::High); let pwm = Pwm::new_input( diff --git a/tests/rp/src/bin/spi.rs b/tests/rp/src/bin/spi.rs index 4b02942a7..6802bfc99 100644 --- a/tests/rp/src/bin/spi.rs +++ b/tests/rp/src/bin/spi.rs @@ -1,6 +1,9 @@ #![no_std] #![no_main] +#[cfg(feature = "rp2040")] teleprobe_meta::target!(b"rpi-pico"); +#[cfg(feature = "rp235xb")] +teleprobe_meta::target!(b"pimoroni-pico-plus-2"); use defmt::{assert_eq, *}; use embassy_executor::Spawner; diff --git a/tests/rp/src/bin/spi_async.rs b/tests/rp/src/bin/spi_async.rs index efdc80b53..e50667435 100644 --- a/tests/rp/src/bin/spi_async.rs +++ b/tests/rp/src/bin/spi_async.rs @@ -3,7 +3,10 @@ //! #![no_std] #![no_main] +#[cfg(feature = "rp2040")] teleprobe_meta::target!(b"rpi-pico"); +#[cfg(feature = "rp235xb")] +teleprobe_meta::target!(b"pimoroni-pico-plus-2"); use defmt::{assert_eq, *}; use embassy_executor::Spawner; diff --git a/tests/rp/src/bin/timer.rs b/tests/rp/src/bin/timer.rs index be9242144..12a4d7daa 100644 --- a/tests/rp/src/bin/timer.rs +++ b/tests/rp/src/bin/timer.rs @@ -1,6 +1,9 @@ #![no_std] #![no_main] +#[cfg(feature = "rp2040")] teleprobe_meta::target!(b"rpi-pico"); +#[cfg(feature = "rp235xb")] +teleprobe_meta::target!(b"pimoroni-pico-plus-2"); use defmt::{assert, *}; use embassy_executor::Spawner; diff --git a/tests/rp/src/bin/uart.rs b/tests/rp/src/bin/uart.rs index 6e6e5517b..67cfa6bc8 100644 --- a/tests/rp/src/bin/uart.rs +++ b/tests/rp/src/bin/uart.rs @@ -1,6 +1,9 @@ #![no_std] #![no_main] +#[cfg(feature = "rp2040")] teleprobe_meta::target!(b"rpi-pico"); +#[cfg(feature = "rp235xb")] +teleprobe_meta::target!(b"pimoroni-pico-plus-2"); use defmt::{assert_eq, *}; use embassy_executor::Spawner; diff --git a/tests/rp/src/bin/uart_buffered.rs b/tests/rp/src/bin/uart_buffered.rs index d68c23cbd..a543320e0 100644 --- a/tests/rp/src/bin/uart_buffered.rs +++ b/tests/rp/src/bin/uart_buffered.rs @@ -1,6 +1,9 @@ #![no_std] #![no_main] +#[cfg(feature = "rp2040")] teleprobe_meta::target!(b"rpi-pico"); +#[cfg(feature = "rp235xb")] +teleprobe_meta::target!(b"pimoroni-pico-plus-2"); use defmt::{assert_eq, panic, *}; use embassy_executor::Spawner; diff --git a/tests/rp/src/bin/uart_dma.rs b/tests/rp/src/bin/uart_dma.rs index edc87175a..bdf94e78c 100644 --- a/tests/rp/src/bin/uart_dma.rs +++ b/tests/rp/src/bin/uart_dma.rs @@ -1,6 +1,9 @@ #![no_std] #![no_main] +#[cfg(feature = "rp2040")] teleprobe_meta::target!(b"rpi-pico"); +#[cfg(feature = "rp235xb")] +teleprobe_meta::target!(b"pimoroni-pico-plus-2"); use defmt::{assert_eq, *}; use embassy_executor::Spawner; diff --git a/tests/rp/src/bin/uart_upgrade.rs b/tests/rp/src/bin/uart_upgrade.rs index 603e20f2f..f658b6b8c 100644 --- a/tests/rp/src/bin/uart_upgrade.rs +++ b/tests/rp/src/bin/uart_upgrade.rs @@ -1,6 +1,9 @@ #![no_std] #![no_main] +#[cfg(feature = "rp2040")] teleprobe_meta::target!(b"rpi-pico"); +#[cfg(feature = "rp235xb")] +teleprobe_meta::target!(b"pimoroni-pico-plus-2"); use defmt::{assert_eq, *}; use embassy_executor::Spawner; From 52f64827be4d30960ae1457b1c9e03f2fd95d19a Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Tue, 18 Feb 2025 10:38:19 -0500 Subject: [PATCH 0754/1217] rustfmt fixup --- tests/rp/src/bin/adc.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/rp/src/bin/adc.rs b/tests/rp/src/bin/adc.rs index 8eeaad95d..c1808a011 100644 --- a/tests/rp/src/bin/adc.rs +++ b/tests/rp/src/bin/adc.rs @@ -7,8 +7,7 @@ teleprobe_meta::target!(b"pimoroni-pico-plus-2"); use defmt::*; use embassy_executor::Spawner; -use embassy_rp::adc::Sample; -use embassy_rp::adc::{Adc, Channel, Config, InterruptHandler}; +use embassy_rp::adc::{Adc, Channel, Config, InterruptHandler, Sample}; use embassy_rp::bind_interrupts; use embassy_rp::gpio::Pull; use embassy_rp::gpio::{Level, Output}; From f1e6b7027971b00fa733aca1b327300708c81cb9 Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Tue, 18 Feb 2025 10:39:58 -0500 Subject: [PATCH 0755/1217] rustfmt again --- tests/rp/src/bin/adc.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/rp/src/bin/adc.rs b/tests/rp/src/bin/adc.rs index c1808a011..87e9709cc 100644 --- a/tests/rp/src/bin/adc.rs +++ b/tests/rp/src/bin/adc.rs @@ -9,8 +9,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_rp::adc::{Adc, Channel, Config, InterruptHandler, Sample}; use embassy_rp::bind_interrupts; -use embassy_rp::gpio::Pull; -use embassy_rp::gpio::{Level, Output}; +use embassy_rp::gpio::{Level, Output, Pull}; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { From e3edd671b6653325f9425886e008f6f37860f1b4 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sun, 9 Feb 2025 23:23:35 +0100 Subject: [PATCH 0756/1217] rp/pio: move instructions to methods of the SM. --- cyw43-pio/src/lib.rs | 18 ++-- embassy-rp/src/pio/instr.rs | 158 ++++++++++++++++++------------------ embassy-rp/src/pio/mod.rs | 4 +- 3 files changed, 91 insertions(+), 89 deletions(-) diff --git a/cyw43-pio/src/lib.rs b/cyw43-pio/src/lib.rs index 5fe7af95d..b08e68307 100644 --- a/cyw43-pio/src/lib.rs +++ b/cyw43-pio/src/lib.rs @@ -8,7 +8,7 @@ use core::slice; use cyw43::SpiBusCyw43; use embassy_rp::dma::Channel; use embassy_rp::gpio::{Drive, Level, Output, Pull, SlewRate}; -use embassy_rp::pio::{instr, Common, Config, Direction, Instance, Irq, PioPin, ShiftDirection, StateMachine}; +use embassy_rp::pio::{Common, Config, Direction, Instance, Irq, PioPin, ShiftDirection, StateMachine}; use embassy_rp::{Peripheral, PeripheralRef}; use fixed::types::extra::U8; use fixed::FixedU32; @@ -161,10 +161,10 @@ where defmt::trace!("write={} read={}", write_bits, read_bits); unsafe { - instr::set_x(&mut self.sm, write_bits as u32); - instr::set_y(&mut self.sm, read_bits as u32); - instr::set_pindir(&mut self.sm, 0b1); - instr::exec_jmp(&mut self.sm, self.wrap_target); + self.sm.set_x(write_bits as u32); + self.sm.set_y(read_bits as u32); + self.sm.set_pindir(0b1); + self.sm.exec_jmp(self.wrap_target); } self.sm.set_enable(true); @@ -192,10 +192,10 @@ where defmt::trace!("cmd_read cmd = {:02x} len = {}", cmd, read.len()); unsafe { - instr::set_y(&mut self.sm, read_bits as u32); - instr::set_x(&mut self.sm, write_bits as u32); - instr::set_pindir(&mut self.sm, 0b1); - instr::exec_jmp(&mut self.sm, self.wrap_target); + self.sm.set_y(read_bits as u32); + self.sm.set_x(write_bits as u32); + self.sm.set_pindir(0b1); + self.sm.exec_jmp(self.wrap_target); } // self.cs.set_low(); diff --git a/embassy-rp/src/pio/instr.rs b/embassy-rp/src/pio/instr.rs index 9a44088c6..b15d507de 100644 --- a/embassy-rp/src/pio/instr.rs +++ b/embassy-rp/src/pio/instr.rs @@ -3,99 +3,101 @@ use pio::{InSource, InstructionOperands, JmpCondition, OutDestination, SetDestin use crate::pio::{Instance, StateMachine}; -/// Set value of scratch register X. -pub unsafe fn set_x(sm: &mut StateMachine, value: u32) { - const OUT: u16 = InstructionOperands::OUT { - destination: OutDestination::X, - bit_count: 32, +impl<'d, PIO: Instance, const SM: usize> StateMachine<'d, PIO, SM> { + /// Set value of scratch register X. + pub unsafe fn set_x(&mut self, value: u32) { + const OUT: u16 = InstructionOperands::OUT { + destination: OutDestination::X, + bit_count: 32, + } + .encode(); + self.tx().push(value); + self.exec_instr(OUT); } - .encode(); - sm.tx().push(value); - sm.exec_instr(OUT); -} -/// Get value of scratch register X. -pub unsafe fn get_x(sm: &mut StateMachine) -> u32 { - const IN: u16 = InstructionOperands::IN { - source: InSource::X, - bit_count: 32, + /// Get value of scratch register X. + pub unsafe fn get_x(&mut self) -> u32 { + const IN: u16 = InstructionOperands::IN { + source: InSource::X, + bit_count: 32, + } + .encode(); + self.exec_instr(IN); + self.rx().pull() } - .encode(); - sm.exec_instr(IN); - sm.rx().pull() -} -/// Set value of scratch register Y. -pub unsafe fn set_y(sm: &mut StateMachine, value: u32) { - const OUT: u16 = InstructionOperands::OUT { - destination: OutDestination::Y, - bit_count: 32, + /// Set value of scratch register Y. + pub unsafe fn set_y(&mut self, value: u32) { + const OUT: u16 = InstructionOperands::OUT { + destination: OutDestination::Y, + bit_count: 32, + } + .encode(); + self.tx().push(value); + self.exec_instr(OUT); } - .encode(); - sm.tx().push(value); - sm.exec_instr(OUT); -} -/// Get value of scratch register Y. -pub unsafe fn get_y(sm: &mut StateMachine) -> u32 { - const IN: u16 = InstructionOperands::IN { - source: InSource::Y, - bit_count: 32, + /// Get value of scratch register Y. + pub unsafe fn get_y(&mut self) -> u32 { + const IN: u16 = InstructionOperands::IN { + source: InSource::Y, + bit_count: 32, + } + .encode(); + self.exec_instr(IN); + + self.rx().pull() } - .encode(); - sm.exec_instr(IN); - sm.rx().pull() -} - -/// Set instruction for pindir destination. -pub unsafe fn set_pindir(sm: &mut StateMachine, data: u8) { - let set: u16 = InstructionOperands::SET { - destination: SetDestination::PINDIRS, - data, + /// Set instruction for pindir destination. + pub unsafe fn set_pindir(&mut self, data: u8) { + let set: u16 = InstructionOperands::SET { + destination: SetDestination::PINDIRS, + data, + } + .encode(); + self.exec_instr(set); } - .encode(); - sm.exec_instr(set); -} -/// Set instruction for pin destination. -pub unsafe fn set_pin(sm: &mut StateMachine, data: u8) { - let set: u16 = InstructionOperands::SET { - destination: SetDestination::PINS, - data, + /// Set instruction for pin destination. + pub unsafe fn set_pin(&mut self, data: u8) { + let set: u16 = InstructionOperands::SET { + destination: SetDestination::PINS, + data, + } + .encode(); + self.exec_instr(set); } - .encode(); - sm.exec_instr(set); -} -/// Out instruction for pin destination. -pub unsafe fn set_out_pin(sm: &mut StateMachine, data: u32) { - const OUT: u16 = InstructionOperands::OUT { - destination: OutDestination::PINS, - bit_count: 32, + /// Out instruction for pin destination. + pub unsafe fn set_out_pin(&mut self, data: u32) { + const OUT: u16 = InstructionOperands::OUT { + destination: OutDestination::PINS, + bit_count: 32, + } + .encode(); + self.tx().push(data); + self.exec_instr(OUT); } - .encode(); - sm.tx().push(data); - sm.exec_instr(OUT); -} -/// Out instruction for pindir destination. -pub unsafe fn set_out_pindir(sm: &mut StateMachine, data: u32) { - const OUT: u16 = InstructionOperands::OUT { - destination: OutDestination::PINDIRS, - bit_count: 32, + /// Out instruction for pindir destination. + pub unsafe fn set_out_pindir(&mut self, data: u32) { + const OUT: u16 = InstructionOperands::OUT { + destination: OutDestination::PINDIRS, + bit_count: 32, + } + .encode(); + self.tx().push(data); + self.exec_instr(OUT); } - .encode(); - sm.tx().push(data); - sm.exec_instr(OUT); -} -/// Jump instruction to address. -pub unsafe fn exec_jmp(sm: &mut StateMachine, to_addr: u8) { - let jmp: u16 = InstructionOperands::JMP { - address: to_addr, - condition: JmpCondition::Always, + /// Jump instruction to address. + pub unsafe fn exec_jmp(&mut self, to_addr: u8) { + let jmp: u16 = InstructionOperands::JMP { + address: to_addr, + condition: JmpCondition::Always, + } + .encode(); + self.exec_instr(jmp); } - .encode(); - sm.exec_instr(jmp); } diff --git a/embassy-rp/src/pio/mod.rs b/embassy-rp/src/pio/mod.rs index 2776f9e3c..d4c0af55e 100644 --- a/embassy-rp/src/pio/mod.rs +++ b/embassy-rp/src/pio/mod.rs @@ -18,7 +18,7 @@ use crate::interrupt::typelevel::{Binding, Handler, Interrupt}; use crate::relocate::RelocatedProgram; use crate::{pac, peripherals, RegExt}; -pub mod instr; +mod instr; /// Wakers for interrupts and FIFOs. pub struct Wakers([AtomicWaker; 12]); @@ -812,7 +812,7 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> { } if let Some(origin) = config.origin { - unsafe { instr::exec_jmp(self, origin) } + unsafe { self.exec_jmp(origin) } } } From dcf0868dd017c6df0c82e504864956374019f484 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 10 Feb 2025 00:00:11 +0100 Subject: [PATCH 0757/1217] rp: remove typo'd `feature` that was doing nothing. --- embassy-rp/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index d681af915..5d4c4e9b5 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml @@ -157,7 +157,7 @@ embedded-storage-async = { version = "0.4.1" } rand_core = "0.6.4" fixed = "1.28.0" -rp-pac = { version = "7.0.0", feature = ["rt"] } +rp-pac = { version = "7.0.0" } embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } embedded-hal-1 = { package = "embedded-hal", version = "1.0" } From 52dfefb63242ad49fd126470042411f464fe624d Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 10 Feb 2025 00:03:49 +0100 Subject: [PATCH 0758/1217] rp/pio: update pio-rs crate, reexport it so users don't get version mismatches. --- cyw43-pio/Cargo.toml | 2 -- cyw43-pio/src/lib.rs | 2 +- embassy-rp/Cargo.toml | 3 +-- embassy-rp/src/pio/mod.rs | 3 +++ embassy-rp/src/pio_programs/hd44780.rs | 4 ++-- embassy-rp/src/pio_programs/i2s.rs | 2 +- embassy-rp/src/pio_programs/onewire.rs | 8 ++++---- embassy-rp/src/pio_programs/pwm.rs | 2 +- embassy-rp/src/pio_programs/rotary_encoder.rs | 8 +++++--- embassy-rp/src/pio_programs/stepper.rs | 2 +- embassy-rp/src/pio_programs/uart.rs | 4 ++-- examples/rp/Cargo.toml | 2 -- examples/rp/src/bin/pio_async.rs | 7 ++++--- examples/rp/src/bin/pio_dma.rs | 3 ++- examples/rp23/Cargo.toml | 2 -- examples/rp23/src/bin/pio_async.rs | 7 ++++--- examples/rp23/src/bin/pio_dma.rs | 3 ++- examples/rp23/src/bin/pio_rotary_encoder_rxf.rs | 3 ++- tests/rp/Cargo.toml | 2 -- tests/rp/src/bin/pio_irq.rs | 3 ++- tests/rp/src/bin/pio_multi_load.rs | 16 ++++++++-------- 21 files changed, 45 insertions(+), 43 deletions(-) diff --git a/cyw43-pio/Cargo.toml b/cyw43-pio/Cargo.toml index f52788ba3..2397c76d3 100644 --- a/cyw43-pio/Cargo.toml +++ b/cyw43-pio/Cargo.toml @@ -12,8 +12,6 @@ documentation = "https://docs.embassy.dev/cyw43-pio" [dependencies] cyw43 = { version = "0.3.0", path = "../cyw43" } embassy-rp = { version = "0.3.0", path = "../embassy-rp" } -pio-proc = { git = "https://github.com/rp-rs/pio-rs", rev = "fa586448b0b223217eec8c92c19fe6823dd04cc4" } -pio = { git = "https://github.com/rp-rs/pio-rs", rev = "fa586448b0b223217eec8c92c19fe6823dd04cc4" } fixed = "1.23.1" defmt = { version = "0.3", optional = true } diff --git a/cyw43-pio/src/lib.rs b/cyw43-pio/src/lib.rs index b08e68307..d0d504395 100644 --- a/cyw43-pio/src/lib.rs +++ b/cyw43-pio/src/lib.rs @@ -8,11 +8,11 @@ use core::slice; use cyw43::SpiBusCyw43; use embassy_rp::dma::Channel; use embassy_rp::gpio::{Drive, Level, Output, Pull, SlewRate}; +use embassy_rp::pio::program::pio_asm; use embassy_rp::pio::{Common, Config, Direction, Instance, Irq, PioPin, ShiftDirection, StateMachine}; use embassy_rp::{Peripheral, PeripheralRef}; use fixed::types::extra::U8; use fixed::FixedU32; -use pio_proc::pio_asm; /// SPI comms driven by PIO. pub struct PioSpi<'d, PIO: Instance, const SM: usize, DMA> { diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index 5d4c4e9b5..539c579a3 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml @@ -164,8 +164,7 @@ embedded-hal-1 = { package = "embedded-hal", version = "1.0" } embedded-hal-async = { version = "1.0" } embedded-hal-nb = { version = "1.0" } -pio-proc = { git = "https://github.com/rp-rs/pio-rs", rev = "fa586448b0b223217eec8c92c19fe6823dd04cc4" } -pio = { git = "https://github.com/rp-rs/pio-rs", rev = "fa586448b0b223217eec8c92c19fe6823dd04cc4" } +pio = { git = "https://github.com/rp-rs/pio-rs", rev = "506a51b9bc135845e8544a0debd75847b73754dc" } rp2040-boot2 = "0.3" document-features = "0.2.10" sha2-const-stable = "0.1" diff --git a/embassy-rp/src/pio/mod.rs b/embassy-rp/src/pio/mod.rs index d4c0af55e..880d6effd 100644 --- a/embassy-rp/src/pio/mod.rs +++ b/embassy-rp/src/pio/mod.rs @@ -20,6 +20,9 @@ use crate::{pac, peripherals, RegExt}; mod instr; +#[doc(inline)] +pub use pio as program; + /// Wakers for interrupts and FIFOs. pub struct Wakers([AtomicWaker; 12]); diff --git a/embassy-rp/src/pio_programs/hd44780.rs b/embassy-rp/src/pio_programs/hd44780.rs index 9bbf44fc4..70129318b 100644 --- a/embassy-rp/src/pio_programs/hd44780.rs +++ b/embassy-rp/src/pio_programs/hd44780.rs @@ -15,7 +15,7 @@ pub struct PioHD44780CommandWordProgram<'a, PIO: Instance> { impl<'a, PIO: Instance> PioHD44780CommandWordProgram<'a, PIO> { /// Load the program into the given pio pub fn new(common: &mut Common<'a, PIO>) -> Self { - let prg = pio_proc::pio_asm!( + let prg = pio::pio_asm!( r#" .side_set 1 opt .origin 20 @@ -46,7 +46,7 @@ impl<'a, PIO: Instance> PioHD44780CommandSequenceProgram<'a, PIO> { /// Load the program into the given pio pub fn new(common: &mut Common<'a, PIO>) -> Self { // many side sets are only there to free up a delay bit! - let prg = pio_proc::pio_asm!( + let prg = pio::pio_asm!( r#" .origin 27 .side_set 1 diff --git a/embassy-rp/src/pio_programs/i2s.rs b/embassy-rp/src/pio_programs/i2s.rs index 87fb2e19f..a7b4f46a6 100644 --- a/embassy-rp/src/pio_programs/i2s.rs +++ b/embassy-rp/src/pio_programs/i2s.rs @@ -16,7 +16,7 @@ pub struct PioI2sOutProgram<'a, PIO: Instance> { impl<'a, PIO: Instance> PioI2sOutProgram<'a, PIO> { /// Load the program into the given pio pub fn new(common: &mut Common<'a, PIO>) -> Self { - let prg = pio_proc::pio_asm!( + let prg = pio::pio_asm!( ".side_set 2", " set x, 14 side 0b01", // side 0bWB - W = Word Clock, B = Bit Clock "left_data:", diff --git a/embassy-rp/src/pio_programs/onewire.rs b/embassy-rp/src/pio_programs/onewire.rs index f3bc5fcd7..040333e76 100644 --- a/embassy-rp/src/pio_programs/onewire.rs +++ b/embassy-rp/src/pio_programs/onewire.rs @@ -1,6 +1,6 @@ //! OneWire pio driver -use crate::pio::{self, Common, Config, Instance, LoadedProgram, PioPin, ShiftConfig, ShiftDirection, StateMachine}; +use crate::pio::{Common, Config, Instance, LoadedProgram, PioPin, ShiftConfig, ShiftDirection, StateMachine}; /// This struct represents an onewire driver program pub struct PioOneWireProgram<'a, PIO: Instance> { @@ -10,7 +10,7 @@ pub struct PioOneWireProgram<'a, PIO: Instance> { impl<'a, PIO: Instance> PioOneWireProgram<'a, PIO> { /// Load the program into the given pio pub fn new(common: &mut Common<'a, PIO>) -> Self { - let prg = pio_proc::pio_asm!( + let prg = pio::pio_asm!( r#" .wrap_target again: @@ -60,11 +60,11 @@ impl<'a, PIO: Instance> PioOneWireProgram<'a, PIO> { } /// Pio backed OneWire driver -pub struct PioOneWire<'d, PIO: pio::Instance, const SM: usize> { +pub struct PioOneWire<'d, PIO: Instance, const SM: usize> { sm: StateMachine<'d, PIO, SM>, } -impl<'d, PIO: pio::Instance, const SM: usize> PioOneWire<'d, PIO, SM> { +impl<'d, PIO: Instance, const SM: usize> PioOneWire<'d, PIO, SM> { /// Create a new instance the driver pub fn new( common: &mut Common<'d, PIO>, diff --git a/embassy-rp/src/pio_programs/pwm.rs b/embassy-rp/src/pio_programs/pwm.rs index c6502387a..01ffe012a 100644 --- a/embassy-rp/src/pio_programs/pwm.rs +++ b/embassy-rp/src/pio_programs/pwm.rs @@ -21,7 +21,7 @@ pub struct PioPwmProgram<'a, PIO: Instance> { impl<'a, PIO: Instance> PioPwmProgram<'a, PIO> { /// Load the program into the given pio pub fn new(common: &mut Common<'a, PIO>) -> Self { - let prg = pio_proc::pio_asm!( + let prg = pio::pio_asm!( ".side_set 1 opt" "pull noblock side 0" "mov x, osr" diff --git a/embassy-rp/src/pio_programs/rotary_encoder.rs b/embassy-rp/src/pio_programs/rotary_encoder.rs index 86423fd31..f2fb02aca 100644 --- a/embassy-rp/src/pio_programs/rotary_encoder.rs +++ b/embassy-rp/src/pio_programs/rotary_encoder.rs @@ -3,7 +3,9 @@ use fixed::traits::ToFixed; use crate::gpio::Pull; -use crate::pio::{self, Common, Config, FifoJoin, Instance, LoadedProgram, PioPin, ShiftDirection, StateMachine}; +use crate::pio::{ + Common, Config, Direction as PioDirection, FifoJoin, Instance, LoadedProgram, PioPin, ShiftDirection, StateMachine, +}; /// This struct represents an Encoder program loaded into pio instruction memory. pub struct PioEncoderProgram<'a, PIO: Instance> { @@ -13,7 +15,7 @@ pub struct PioEncoderProgram<'a, PIO: Instance> { impl<'a, PIO: Instance> PioEncoderProgram<'a, PIO> { /// Load the program into the given pio pub fn new(common: &mut Common<'a, PIO>) -> Self { - let prg = pio_proc::pio_asm!("wait 1 pin 1", "wait 0 pin 1", "in pins, 2", "push",); + let prg = pio::pio_asm!("wait 1 pin 1", "wait 0 pin 1", "in pins, 2", "push",); let prg = common.load_program(&prg.program); @@ -39,7 +41,7 @@ impl<'d, T: Instance, const SM: usize> PioEncoder<'d, T, SM> { let mut pin_b = pio.make_pio_pin(pin_b); pin_a.set_pull(Pull::Up); pin_b.set_pull(Pull::Up); - sm.set_pin_dirs(pio::Direction::In, &[&pin_a, &pin_b]); + sm.set_pin_dirs(PioDirection::In, &[&pin_a, &pin_b]); let mut cfg = Config::default(); cfg.set_in_pins(&[&pin_a, &pin_b]); diff --git a/embassy-rp/src/pio_programs/stepper.rs b/embassy-rp/src/pio_programs/stepper.rs index 0d58c754c..c8f74167d 100644 --- a/embassy-rp/src/pio_programs/stepper.rs +++ b/embassy-rp/src/pio_programs/stepper.rs @@ -16,7 +16,7 @@ pub struct PioStepperProgram<'a, PIO: Instance> { impl<'a, PIO: Instance> PioStepperProgram<'a, PIO> { /// Load the program into the given pio pub fn new(common: &mut Common<'a, PIO>) -> Self { - let prg = pio_proc::pio_asm!( + let prg = pio::pio_asm!( "pull block", "mov x, osr", "pull block", diff --git a/embassy-rp/src/pio_programs/uart.rs b/embassy-rp/src/pio_programs/uart.rs index c643f1063..641daca61 100644 --- a/embassy-rp/src/pio_programs/uart.rs +++ b/embassy-rp/src/pio_programs/uart.rs @@ -19,7 +19,7 @@ pub struct PioUartTxProgram<'a, PIO: Instance> { impl<'a, PIO: Instance> PioUartTxProgram<'a, PIO> { /// Load the uart tx program into the given pio pub fn new(common: &mut Common<'a, PIO>) -> Self { - let prg = pio_proc::pio_asm!( + let prg = pio::pio_asm!( r#" .side_set 1 opt @@ -99,7 +99,7 @@ pub struct PioUartRxProgram<'a, PIO: Instance> { impl<'a, PIO: Instance> PioUartRxProgram<'a, PIO> { /// Load the uart rx program into the given pio pub fn new(common: &mut Common<'a, PIO>) -> Self { - let prg = pio_proc::pio_asm!( + let prg = pio::pio_asm!( r#" ; Slightly more fleshed-out 8n1 UART receiver which handles framing errors and ; break conditions more gracefully. diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index e05c88a9a..a81166067 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml @@ -55,8 +55,6 @@ embedded-storage = { version = "0.3" } static_cell = "2.1" portable-atomic = { version = "1.5", features = ["critical-section"] } log = "0.4" -pio-proc = { git = "https://github.com/rp-rs/pio-rs", rev = "fa586448b0b223217eec8c92c19fe6823dd04cc4" } -pio = { git = "https://github.com/rp-rs/pio-rs", rev = "fa586448b0b223217eec8c92c19fe6823dd04cc4" } rand = { version = "0.8.5", default-features = false } embedded-sdmmc = "0.7.0" diff --git a/examples/rp/src/bin/pio_async.rs b/examples/rp/src/bin/pio_async.rs index ee248591b..08c702347 100644 --- a/examples/rp/src/bin/pio_async.rs +++ b/examples/rp/src/bin/pio_async.rs @@ -6,6 +6,7 @@ use defmt::info; use embassy_executor::Spawner; use embassy_rp::bind_interrupts; use embassy_rp::peripherals::PIO0; +use embassy_rp::pio::program::pio_asm; use embassy_rp::pio::{Common, Config, InterruptHandler, Irq, Pio, PioPin, ShiftDirection, StateMachine}; use fixed::traits::ToFixed; use fixed_macro::types::U56F8; @@ -19,7 +20,7 @@ fn setup_pio_task_sm0<'a>(pio: &mut Common<'a, PIO0>, sm: &mut StateMachine<'a, // Setup sm0 // Send data serially to pin - let prg = pio_proc::pio_asm!( + let prg = pio_asm!( ".origin 16", "set pindirs, 1", ".wrap_target", @@ -53,7 +54,7 @@ fn setup_pio_task_sm1<'a>(pio: &mut Common<'a, PIO0>, sm: &mut StateMachine<'a, // Setupm sm1 // Read 0b10101 repeatedly until ISR is full - let prg = pio_proc::pio_asm!( + let prg = pio_asm!( // ".origin 8", "set x, 0x15", @@ -83,7 +84,7 @@ fn setup_pio_task_sm2<'a>(pio: &mut Common<'a, PIO0>, sm: &mut StateMachine<'a, // Setup sm2 // Repeatedly trigger IRQ 3 - let prg = pio_proc::pio_asm!( + let prg = pio_asm!( ".origin 0", ".wrap_target", "set x,10", diff --git a/examples/rp/src/bin/pio_dma.rs b/examples/rp/src/bin/pio_dma.rs index 02700269c..d00ed2142 100644 --- a/examples/rp/src/bin/pio_dma.rs +++ b/examples/rp/src/bin/pio_dma.rs @@ -6,6 +6,7 @@ use defmt::info; use embassy_executor::Spawner; use embassy_futures::join::join; use embassy_rp::peripherals::PIO0; +use embassy_rp::pio::program::pio_asm; use embassy_rp::pio::{Config, InterruptHandler, Pio, ShiftConfig, ShiftDirection}; use embassy_rp::{bind_interrupts, Peripheral}; use fixed::traits::ToFixed; @@ -32,7 +33,7 @@ async fn main(_spawner: Spawner) { .. } = Pio::new(pio, Irqs); - let prg = pio_proc::pio_asm!( + let prg = pio_asm!( ".origin 0", "set pindirs,1", ".wrap_target", diff --git a/examples/rp23/Cargo.toml b/examples/rp23/Cargo.toml index b7e7dd69a..f4dfae773 100644 --- a/examples/rp23/Cargo.toml +++ b/examples/rp23/Cargo.toml @@ -55,8 +55,6 @@ embedded-storage = { version = "0.3" } static_cell = "2.1" portable-atomic = { version = "1.5", features = ["critical-section"] } log = "0.4" -pio-proc = { git = "https://github.com/rp-rs/pio-rs", rev = "fa586448b0b223217eec8c92c19fe6823dd04cc4" } -pio = { git = "https://github.com/rp-rs/pio-rs", rev = "fa586448b0b223217eec8c92c19fe6823dd04cc4" } rand = { version = "0.8.5", default-features = false } embedded-sdmmc = "0.7.0" diff --git a/examples/rp23/src/bin/pio_async.rs b/examples/rp23/src/bin/pio_async.rs index ee248591b..08c702347 100644 --- a/examples/rp23/src/bin/pio_async.rs +++ b/examples/rp23/src/bin/pio_async.rs @@ -6,6 +6,7 @@ use defmt::info; use embassy_executor::Spawner; use embassy_rp::bind_interrupts; use embassy_rp::peripherals::PIO0; +use embassy_rp::pio::program::pio_asm; use embassy_rp::pio::{Common, Config, InterruptHandler, Irq, Pio, PioPin, ShiftDirection, StateMachine}; use fixed::traits::ToFixed; use fixed_macro::types::U56F8; @@ -19,7 +20,7 @@ fn setup_pio_task_sm0<'a>(pio: &mut Common<'a, PIO0>, sm: &mut StateMachine<'a, // Setup sm0 // Send data serially to pin - let prg = pio_proc::pio_asm!( + let prg = pio_asm!( ".origin 16", "set pindirs, 1", ".wrap_target", @@ -53,7 +54,7 @@ fn setup_pio_task_sm1<'a>(pio: &mut Common<'a, PIO0>, sm: &mut StateMachine<'a, // Setupm sm1 // Read 0b10101 repeatedly until ISR is full - let prg = pio_proc::pio_asm!( + let prg = pio_asm!( // ".origin 8", "set x, 0x15", @@ -83,7 +84,7 @@ fn setup_pio_task_sm2<'a>(pio: &mut Common<'a, PIO0>, sm: &mut StateMachine<'a, // Setup sm2 // Repeatedly trigger IRQ 3 - let prg = pio_proc::pio_asm!( + let prg = pio_asm!( ".origin 0", ".wrap_target", "set x,10", diff --git a/examples/rp23/src/bin/pio_dma.rs b/examples/rp23/src/bin/pio_dma.rs index 02700269c..d00ed2142 100644 --- a/examples/rp23/src/bin/pio_dma.rs +++ b/examples/rp23/src/bin/pio_dma.rs @@ -6,6 +6,7 @@ use defmt::info; use embassy_executor::Spawner; use embassy_futures::join::join; use embassy_rp::peripherals::PIO0; +use embassy_rp::pio::program::pio_asm; use embassy_rp::pio::{Config, InterruptHandler, Pio, ShiftConfig, ShiftDirection}; use embassy_rp::{bind_interrupts, Peripheral}; use fixed::traits::ToFixed; @@ -32,7 +33,7 @@ async fn main(_spawner: Spawner) { .. } = Pio::new(pio, Irqs); - let prg = pio_proc::pio_asm!( + let prg = pio_asm!( ".origin 0", "set pindirs,1", ".wrap_target", diff --git a/examples/rp23/src/bin/pio_rotary_encoder_rxf.rs b/examples/rp23/src/bin/pio_rotary_encoder_rxf.rs index ca6b5222b..0216c131b 100644 --- a/examples/rp23/src/bin/pio_rotary_encoder_rxf.rs +++ b/examples/rp23/src/bin/pio_rotary_encoder_rxf.rs @@ -8,6 +8,7 @@ use defmt::info; use embassy_executor::Spawner; use embassy_rp::gpio::Pull; use embassy_rp::peripherals::PIO0; +use embassy_rp::pio::program::pio_asm; use embassy_rp::{bind_interrupts, pio}; use embassy_time::Timer; use fixed::traits::ToFixed; @@ -46,7 +47,7 @@ impl<'d, T: Instance, const SM: usize> PioEncoder<'d, T, SM> { sm.set_pin_dirs(pio::Direction::In, &[&pin_a, &pin_b]); - let prg = pio_proc::pio_asm!( + let prg = pio_asm!( "start:" // encoder count is stored in X "mov isr, x" diff --git a/tests/rp/Cargo.toml b/tests/rp/Cargo.toml index 5a6a6c75a..3d6cd6ab8 100644 --- a/tests/rp/Cargo.toml +++ b/tests/rp/Cargo.toml @@ -33,8 +33,6 @@ embedded-io-async = { version = "0.6.1" } embedded-storage = { version = "0.3" } static_cell = "2" portable-atomic = { version = "1.5", features = ["critical-section"] } -pio-proc = { git = "https://github.com/rp-rs/pio-rs", rev = "fa586448b0b223217eec8c92c19fe6823dd04cc4" } -pio = { git = "https://github.com/rp-rs/pio-rs", rev = "fa586448b0b223217eec8c92c19fe6823dd04cc4" } rand = { version = "0.8.5", default-features = false } [profile.dev] diff --git a/tests/rp/src/bin/pio_irq.rs b/tests/rp/src/bin/pio_irq.rs index 33cdaaac9..1fee6dc2f 100644 --- a/tests/rp/src/bin/pio_irq.rs +++ b/tests/rp/src/bin/pio_irq.rs @@ -6,6 +6,7 @@ use defmt::info; use embassy_executor::Spawner; use embassy_rp::bind_interrupts; use embassy_rp::peripherals::PIO0; +use embassy_rp::pio::program::pio_asm; use embassy_rp::pio::{Config, InterruptHandler, Pio}; use {defmt_rtt as _, panic_probe as _}; @@ -24,7 +25,7 @@ async fn main(_spawner: Spawner) { .. } = Pio::new(pio, Irqs); - let prg = pio_proc::pio_asm!( + let prg = pio_asm!( "irq set 0", "irq wait 0", "irq set 1", diff --git a/tests/rp/src/bin/pio_multi_load.rs b/tests/rp/src/bin/pio_multi_load.rs index cd28f99b6..71321015b 100644 --- a/tests/rp/src/bin/pio_multi_load.rs +++ b/tests/rp/src/bin/pio_multi_load.rs @@ -6,6 +6,7 @@ use defmt::info; use embassy_executor::Spawner; use embassy_rp::bind_interrupts; use embassy_rp::peripherals::PIO0; +use embassy_rp::pio::program::pio_asm; use embassy_rp::pio::{Config, InterruptHandler, LoadError, Pio}; use {defmt_rtt as _, panic_probe as _}; @@ -27,7 +28,7 @@ async fn main(_spawner: Spawner) { } = Pio::new(pio, Irqs); // load with explicit origin works - let prg1 = pio_proc::pio_asm!( + let prg1 = pio_asm!( ".origin 4" "nop", "nop", @@ -46,15 +47,14 @@ async fn main(_spawner: Spawner) { assert_eq!(loaded1.wrap.target, 4); // load without origin chooses a free space - let prg2 = pio_proc::pio_asm!("nop", "nop", "nop", "nop", "nop", "nop", "nop", "irq 1", "nop", "nop",); + let prg2 = pio_asm!("nop", "nop", "nop", "nop", "nop", "nop", "nop", "irq 1", "nop", "nop",); let loaded2 = common.load_program(&prg2.program); assert_eq!(loaded2.origin, 14); assert_eq!(loaded2.wrap.source, 23); assert_eq!(loaded2.wrap.target, 14); // wrapping around the end of program space automatically works - let prg3 = - pio_proc::pio_asm!("nop", "nop", "nop", "nop", "nop", "nop", "nop", "nop", "nop", "nop", "nop", "irq 2",); + let prg3 = pio_asm!("nop", "nop", "nop", "nop", "nop", "nop", "nop", "nop", "nop", "nop", "nop", "irq 2",); let loaded3 = common.load_program(&prg3.program); assert_eq!(loaded3.origin, 24); assert_eq!(loaded3.wrap.source, 3); @@ -88,13 +88,13 @@ async fn main(_spawner: Spawner) { // instruction memory is full now. all loads should fail. { - let prg = pio_proc::pio_asm!(".origin 0", "nop"); + let prg = pio_asm!(".origin 0", "nop"); match common.try_load_program(&prg.program) { Err(LoadError::AddressInUse(0)) => (), _ => panic!("program loaded when it shouldn't"), }; - let prg = pio_proc::pio_asm!("nop"); + let prg = pio_asm!("nop"); match common.try_load_program(&prg.program) { Err(LoadError::InsufficientSpace) => (), _ => panic!("program loaded when it shouldn't"), @@ -106,13 +106,13 @@ async fn main(_spawner: Spawner) { common.free_instr(loaded3.used_memory); } { - let prg = pio_proc::pio_asm!(".origin 0", "nop"); + let prg = pio_asm!(".origin 0", "nop"); match common.try_load_program(&prg.program) { Ok(_) => (), _ => panic!("program didn't loaded when it shouldn"), }; - let prg = pio_proc::pio_asm!("nop"); + let prg = pio_asm!("nop"); match common.try_load_program(&prg.program) { Ok(_) => (), _ => panic!("program didn't loaded when it shouldn"), From 28e2789aeb4576fefae7acbd20c82dcffb92cf01 Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Tue, 18 Feb 2025 22:17:49 -0500 Subject: [PATCH 0759/1217] Forgot to actually skip the adc test. It worked once, which is very surprising. --- ci.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ci.sh b/ci.sh index 5e01805ef..ae0a56032 100755 --- a/ci.sh +++ b/ci.sh @@ -328,6 +328,8 @@ rm out/tests/pimoroni-pico-plus-2/gpio_multicore rm out/tests/pimoroni-pico-plus-2/flash # This test passes locally but fails on the HIL, no idea why rm out/tests/pimoroni-pico-plus-2/i2c +# The pico2 plus doesn't have the adcs hooked up like the picoW does. +rm out/tests/pimoroni-pico-plus-2/adc if [[ -z "${TELEPROBE_TOKEN-}" ]]; then echo No teleprobe token found, skipping running HIL tests From 7a2f038800e336f4b823afca9d3eb2e70e90b1e0 Mon Sep 17 00:00:00 2001 From: Ronald Weber Date: Wed, 19 Feb 2025 17:29:21 +0100 Subject: [PATCH 0760/1217] doc: Fix "the the" --- docs/pages/new_project.adoc | 2 +- embassy-net-esp-hosted/README.md | 2 +- embassy-rp/src/float/div.rs | 2 +- embassy-rp/src/intrinsics.rs | 7 +++---- embassy-stm32/src/sdmmc/mod.rs | 2 +- embassy-stm32/src/usart/buffered.rs | 4 ++-- embassy-usb/src/class/web_usb.rs | 2 +- embassy-usb/src/lib.rs | 4 ++-- 8 files changed, 12 insertions(+), 13 deletions(-) diff --git a/docs/pages/new_project.adoc b/docs/pages/new_project.adoc index 63340016b..af1cb75c5 100644 --- a/docs/pages/new_project.adoc +++ b/docs/pages/new_project.adoc @@ -109,7 +109,7 @@ embassy-executor = { git = "https://github.com/embassy-rs/embassy", rev = "7703f embassy-stm32 = { git = "https://github.com/embassy-rs/embassy", rev = "7703f47c1ecac029f603033b7977d9a2becef48c" } ---- -There are a few other dependencies we need to build the project, but fortunately they’re much simpler to install. Copy their lines from the example `Cargo.toml` to the the `[dependencies]` section in the new `Cargo.toml`: +There are a few other dependencies we need to build the project, but fortunately they’re much simpler to install. Copy their lines from the example `Cargo.toml` to the `[dependencies]` section in the new `Cargo.toml`: [source,toml] ---- diff --git a/embassy-net-esp-hosted/README.md b/embassy-net-esp-hosted/README.md index 524231e6c..e1afb1483 100644 --- a/embassy-net-esp-hosted/README.md +++ b/embassy-net-esp-hosted/README.md @@ -1,6 +1,6 @@ # ESP-Hosted `embassy-net` integration -[`embassy-net`](https://crates.io/crates/embassy-net) integration for Espressif SoCs running the the [ESP-Hosted](https://github.com/espressif/esp-hosted) stack. +[`embassy-net`](https://crates.io/crates/embassy-net) integration for Espressif SoCs running the [ESP-Hosted](https://github.com/espressif/esp-hosted) stack. See [`examples`](https://github.com/embassy-rs/embassy/tree/main/examples/nrf52840) directory for usage examples with the nRF52840. diff --git a/embassy-rp/src/float/div.rs b/embassy-rp/src/float/div.rs index aff0dcb07..87d1e38e5 100644 --- a/embassy-rp/src/float/div.rs +++ b/embassy-rp/src/float/div.rs @@ -40,7 +40,7 @@ where // using a wrong divisor, but we'll restore the divisor and result ourselves correctly. // This sets DIRTY, so any interruptor will save the state. sio.div().udividend().write_value(dividend); - // If we are interrupted here, the the interruptor may start the calculation using + // If we are interrupted here, the interruptor may start the calculation using // incorrectly signed inputs, but we'll restore the result ourselves. // This sets DIRTY, so any interruptor will save the state. sio.div().udivisor().write_value(divisor); diff --git a/embassy-rp/src/intrinsics.rs b/embassy-rp/src/intrinsics.rs index 5b9c127ba..69d5d92de 100644 --- a/embassy-rp/src/intrinsics.rs +++ b/embassy-rp/src/intrinsics.rs @@ -335,10 +335,9 @@ core::arch::global_asm!( // result ourselves correctly. This sets DIRTY, so any interruptor will // save the state. "str r3, [r2, #0x060]", // DIV_UDIVIDEND - // If we are interrupted here, the the interruptor may start the - // calculation using incorrectly signed inputs, but we'll restore the - // result ourselves. This sets DIRTY, so any interruptor will save the - // state. + // If we are interrupted here, the interruptor may start the calculation + // using incorrectly signed inputs, but we'll restore the result ourselves. + // This sets DIRTY, so any interruptor will save the state. "str r4, [r2, #0x064]", // DIV_UDIVISOR // If we are interrupted here, the interruptor will have restored // everything but the quotient may be wrongly signed. If the calculation diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs index ed344c412..8af2f8381 100644 --- a/embassy-stm32/src/sdmmc/mod.rs +++ b/embassy-stm32/src/sdmmc/mod.rs @@ -910,7 +910,7 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { } async fn get_scr(&mut self, card: &mut Card) -> Result<(), Error> { - // Read the the 64-bit SCR register + // Read the 64-bit SCR register Self::cmd(Cmd::set_block_length(8), false)?; // CMD16 Self::cmd(Cmd::app_cmd(card.rca << 16), false)?; diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs index 7bbe01a00..b0e0aed80 100644 --- a/embassy-stm32/src/usart/buffered.rs +++ b/embassy-stm32/src/usart/buffered.rs @@ -747,7 +747,7 @@ impl<'d> Drop for BufferedUartRx<'d> { unsafe { state.rx_buf.deinit(); - // TX is inactive if the the buffer is not available. + // TX is inactive if the buffer is not available. // We can now unregister the interrupt handler if state.tx_buf.len() == 0 { self.info.interrupt.disable(); @@ -768,7 +768,7 @@ impl<'d> Drop for BufferedUartTx<'d> { unsafe { state.tx_buf.deinit(); - // RX is inactive if the the buffer is not available. + // RX is inactive if the buffer is not available. // We can now unregister the interrupt handler if state.rx_buf.len() == 0 { self.info.interrupt.disable(); diff --git a/embassy-usb/src/class/web_usb.rs b/embassy-usb/src/class/web_usb.rs index 10ebf318d..405944f14 100644 --- a/embassy-usb/src/class/web_usb.rs +++ b/embassy-usb/src/class/web_usb.rs @@ -140,7 +140,7 @@ pub struct WebUsb<'d, D: Driver<'d>> { impl<'d, D: Driver<'d>> WebUsb<'d, D> { /// Builder for the WebUSB capability implementation. /// - /// Pass in a USB `Builder`, a `State`, which holds the the control endpoint state, and a `Config` for the WebUSB configuration. + /// Pass in a USB `Builder`, a `State`, which holds the control endpoint state, and a `Config` for the WebUSB configuration. pub fn configure(builder: &mut Builder<'d, D>, state: &'d mut State<'d>, config: &'d Config<'d>) { let mut func = builder.function(USB_CLASS_VENDOR, USB_SUBCLASS_NONE, USB_PROTOCOL_NONE); let mut iface = func.interface(); diff --git a/embassy-usb/src/lib.rs b/embassy-usb/src/lib.rs index 93dd6b4d2..0638fd0a2 100644 --- a/embassy-usb/src/lib.rs +++ b/embassy-usb/src/lib.rs @@ -120,7 +120,7 @@ pub trait Handler { /// # Returns /// /// If you didn't handle this request (for example if it's for the wrong interface), return - /// `None`. In this case, the the USB stack will continue calling the other handlers, to see + /// `None`. In this case, the USB stack will continue calling the other handlers, to see /// if another handles it. /// /// If you did, return `Some` with either `Accepted` or `Rejected`. This will make the USB stack @@ -142,7 +142,7 @@ pub trait Handler { /// # Returns /// /// If you didn't handle this request (for example if it's for the wrong interface), return - /// `None`. In this case, the the USB stack will continue calling the other handlers, to see + /// `None`. In this case, the USB stack will continue calling the other handlers, to see /// if another handles it. /// /// If you did, return `Some` with either `Accepted` or `Rejected`. This will make the USB stack From 1b4f7884271faf79c9f92f940e9fc7d4c83ca644 Mon Sep 17 00:00:00 2001 From: Matthew Tran <0e4ef622@gmail.com> Date: Fri, 21 Feb 2025 23:40:53 -0600 Subject: [PATCH 0761/1217] nrf5340: configure LFCLK --- embassy-nrf/Cargo.toml | 3 ++ embassy-nrf/src/chips/nrf5340_app.rs | 4 ++ embassy-nrf/src/lib.rs | 61 ++++++++++++++++++++++++++-- 3 files changed, 65 insertions(+), 3 deletions(-) diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml index 1d5485f2a..405115dd7 100644 --- a/embassy-nrf/Cargo.toml +++ b/embassy-nrf/Cargo.toml @@ -57,6 +57,9 @@ nfc-pins-as-gpio = [] ## * nRF52820, nRF52833, nRF52840: P0_18 reset-pin-as-gpio = [] +## Allow using the LFXO pins as regular GPIO pins (P0_00/P0_01 on nRF53) +lfxo-pins-as-gpio = [] + ## Implements the MultiwriteNorFlash trait for QSPI. Should only be enabled if your external ## flash supports the semantics described [here](https://docs.rs/embedded-storage/0.3.1/embedded_storage/nor_flash/trait.MultiwriteNorFlash.html) qspi-multiwrite-flash = [] diff --git a/embassy-nrf/src/chips/nrf5340_app.rs b/embassy-nrf/src/chips/nrf5340_app.rs index bc613e351..b33a19df7 100644 --- a/embassy-nrf/src/chips/nrf5340_app.rs +++ b/embassy-nrf/src/chips/nrf5340_app.rs @@ -262,7 +262,9 @@ embassy_hal_internal::peripherals! { PPI_GROUP5, // GPIO port 0 + #[cfg(any(not(feature = "_nrf5340"), feature = "lfxo-pins-as-gpio"))] P0_00, + #[cfg(any(not(feature = "_nrf5340"), feature = "lfxo-pins-as-gpio"))] P0_01, #[cfg(feature = "nfc-pins-as-gpio")] P0_02, @@ -368,7 +370,9 @@ impl_pdm!(PDM0, PDM0, PDM0); impl_qdec!(QDEC0, QDEC0, QDEC0); impl_qdec!(QDEC1, QDEC1, QDEC1); +#[cfg(any(not(feature = "_nrf5340"), feature = "lfxo-pins-as-gpio"))] impl_pin!(P0_00, 0, 0); +#[cfg(any(not(feature = "_nrf5340"), feature = "lfxo-pins-as-gpio"))] impl_pin!(P0_01, 0, 1); #[cfg(feature = "nfc-pins-as-gpio")] impl_pin!(P0_02, 0, 2); diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index 9a9485f04..4241f90b1 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs @@ -65,6 +65,9 @@ compile_error!("feature `reset-pin-as-gpio` is only valid for nRF52 series chips #[cfg(all(feature = "nfc-pins-as-gpio", not(any(feature = "_nrf52", feature = "_nrf5340-app"))))] compile_error!("feature `nfc-pins-as-gpio` is only valid for nRF52, or nRF53's application core."); +#[cfg(all(feature = "lfxo-pins-as-gpio", not(any(feature = "_nrf5340"))))] +compile_error!("feature `lfxo-pins-as-gpio` is only valid for nRF53 series chips."); + // This mod MUST go first, so that the others see its macros. pub(crate) mod fmt; pub(crate) mod util; @@ -282,15 +285,24 @@ pub mod config { /// Internal RC oscillator InternalRC, /// Synthesized from the high frequency clock source. - #[cfg(not(any(feature = "_nrf5340", feature = "_nrf91")))] + #[cfg(not(any(feature = "_nrf91")))] Synthesized, /// External source from xtal. + #[cfg(not(all(feature = "_nrf5340", feature = "lfxo-pins-as-gpio")))] ExternalXtal, /// External source from xtal with low swing applied. - #[cfg(not(any(feature = "_nrf5340", feature = "_nrf91", feature = "_nrf54l")))] + #[cfg(not(any( + all(feature = "_nrf5340", feature = "lfxo-pins-as-gpio"), + feature = "_nrf91", + feature = "_nrf54l" + )))] ExternalLowSwing, /// External source from xtal with full swing applied. - #[cfg(not(any(feature = "_nrf5340", feature = "_nrf91", feature = "_nrf54l")))] + #[cfg(not(any( + all(feature = "_nrf5340", feature = "lfxo-pins-as-gpio"), + feature = "_nrf91", + feature = "_nrf54l" + )))] ExternalFullSwing, } @@ -706,6 +718,19 @@ pub fn init(config: config::Config) -> Peripherals { } } + // Workaround for anomaly 140 + #[cfg(feature = "nrf5340-app-s")] + if unsafe { (0x50032420 as *mut u32).read_volatile() } & 0x80000000 != 0 { + r.events_lfclkstarted().write_value(0); + r.lfclksrc() + .write(|w| w.set_src(nrf_pac::clock::vals::Lfclksrc::LFSYNT)); + r.tasks_lfclkstart().write_value(1); + while r.events_lfclkstarted().read() == 0 {} + r.events_lfclkstarted().write_value(0); + r.tasks_lfclkstop().write_value(1); + r.lfclksrc().write(|w| w.set_src(nrf_pac::clock::vals::Lfclksrc::LFRC)); + } + // Configure LFCLK. #[cfg(not(any(feature = "_nrf51", feature = "_nrf5340", feature = "_nrf91", feature = "_nrf54l")))] match config.lfclk_source { @@ -723,6 +748,36 @@ pub fn init(config: config::Config) -> Peripherals { w.set_bypass(true); }), } + #[cfg(feature = "_nrf5340")] + { + #[allow(unused_mut)] + let mut lfxo = false; + match config.lfclk_source { + config::LfclkSource::InternalRC => r.lfclksrc().write(|w| w.set_src(pac::clock::vals::Lfclksrc::LFRC)), + config::LfclkSource::Synthesized => r.lfclksrc().write(|w| w.set_src(pac::clock::vals::Lfclksrc::LFSYNT)), + #[cfg(not(feature = "lfxo-pins-as-gpio"))] + config::LfclkSource::ExternalXtal => lfxo = true, + #[cfg(not(feature = "lfxo-pins-as-gpio"))] + config::LfclkSource::ExternalLowSwing => lfxo = true, + #[cfg(not(feature = "lfxo-pins-as-gpio"))] + config::LfclkSource::ExternalFullSwing => { + #[cfg(all(feature = "_nrf5340-app"))] + pac::OSCILLATORS.xosc32ki().bypass().write(|w| w.set_bypass(true)); + lfxo = true; + } + } + if lfxo { + if cfg!(feature = "_s") { + // MCUSEL is only accessible from secure code. + let p0 = pac::P0; + p0.pin_cnf(0) + .write(|w| w.set_mcusel(pac::gpio::vals::Mcusel::PERIPHERAL)); + p0.pin_cnf(1) + .write(|w| w.set_mcusel(pac::gpio::vals::Mcusel::PERIPHERAL)); + } + r.lfclksrc().write(|w| w.set_src(pac::clock::vals::Lfclksrc::LFXO)); + } + } #[cfg(feature = "_nrf91")] match config.lfclk_source { config::LfclkSource::InternalRC => r.lfclksrc().write(|w| w.set_src(pac::clock::vals::Lfclksrc::LFRC)), From def1cf58abf386b0a83971cc9c66b00cedd64c83 Mon Sep 17 00:00:00 2001 From: Matthew Tran <0e4ef622@gmail.com> Date: Sat, 22 Feb 2025 08:45:11 -0600 Subject: [PATCH 0762/1217] remove redundant cfg --- embassy-nrf/src/chips/nrf5340_app.rs | 8 ++++---- embassy-nrf/src/lib.rs | 18 +++++------------- 2 files changed, 9 insertions(+), 17 deletions(-) diff --git a/embassy-nrf/src/chips/nrf5340_app.rs b/embassy-nrf/src/chips/nrf5340_app.rs index b33a19df7..86274bf48 100644 --- a/embassy-nrf/src/chips/nrf5340_app.rs +++ b/embassy-nrf/src/chips/nrf5340_app.rs @@ -262,9 +262,9 @@ embassy_hal_internal::peripherals! { PPI_GROUP5, // GPIO port 0 - #[cfg(any(not(feature = "_nrf5340"), feature = "lfxo-pins-as-gpio"))] + #[cfg(feature = "lfxo-pins-as-gpio")] P0_00, - #[cfg(any(not(feature = "_nrf5340"), feature = "lfxo-pins-as-gpio"))] + #[cfg(feature = "lfxo-pins-as-gpio")] P0_01, #[cfg(feature = "nfc-pins-as-gpio")] P0_02, @@ -370,9 +370,9 @@ impl_pdm!(PDM0, PDM0, PDM0); impl_qdec!(QDEC0, QDEC0, QDEC0); impl_qdec!(QDEC1, QDEC1, QDEC1); -#[cfg(any(not(feature = "_nrf5340"), feature = "lfxo-pins-as-gpio"))] +#[cfg(feature = "lfxo-pins-as-gpio")] impl_pin!(P0_00, 0, 0); -#[cfg(any(not(feature = "_nrf5340"), feature = "lfxo-pins-as-gpio"))] +#[cfg(feature = "lfxo-pins-as-gpio")] impl_pin!(P0_01, 0, 1); #[cfg(feature = "nfc-pins-as-gpio")] impl_pin!(P0_02, 0, 2); diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index 4241f90b1..23888b390 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs @@ -65,7 +65,7 @@ compile_error!("feature `reset-pin-as-gpio` is only valid for nRF52 series chips #[cfg(all(feature = "nfc-pins-as-gpio", not(any(feature = "_nrf52", feature = "_nrf5340-app"))))] compile_error!("feature `nfc-pins-as-gpio` is only valid for nRF52, or nRF53's application core."); -#[cfg(all(feature = "lfxo-pins-as-gpio", not(any(feature = "_nrf5340"))))] +#[cfg(all(feature = "lfxo-pins-as-gpio", not(feature = "_nrf5340")))] compile_error!("feature `lfxo-pins-as-gpio` is only valid for nRF53 series chips."); // This mod MUST go first, so that the others see its macros. @@ -285,24 +285,16 @@ pub mod config { /// Internal RC oscillator InternalRC, /// Synthesized from the high frequency clock source. - #[cfg(not(any(feature = "_nrf91")))] + #[cfg(not(feature = "_nrf91"))] Synthesized, /// External source from xtal. - #[cfg(not(all(feature = "_nrf5340", feature = "lfxo-pins-as-gpio")))] + #[cfg(not(feature = "lfxo-pins-as-gpio"))] ExternalXtal, /// External source from xtal with low swing applied. - #[cfg(not(any( - all(feature = "_nrf5340", feature = "lfxo-pins-as-gpio"), - feature = "_nrf91", - feature = "_nrf54l" - )))] + #[cfg(not(any(feature = "lfxo-pins-as-gpio", feature = "_nrf91", feature = "_nrf54l")))] ExternalLowSwing, /// External source from xtal with full swing applied. - #[cfg(not(any( - all(feature = "_nrf5340", feature = "lfxo-pins-as-gpio"), - feature = "_nrf91", - feature = "_nrf54l" - )))] + #[cfg(not(any(feature = "lfxo-pins-as-gpio", feature = "_nrf91", feature = "_nrf54l")))] ExternalFullSwing, } From c3c67db93e627a4fafe5e1a1123e5cbb4abafe47 Mon Sep 17 00:00:00 2001 From: Curly Date: Sat, 22 Feb 2025 18:17:52 -0800 Subject: [PATCH 0763/1217] add JetBrains editor artifacts to `.gitignore` --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 352c1f1af..2d7cbc4fe 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ out/ .zed .neoconf.json *.vim +**/.idea \ No newline at end of file From 3932835998802fc3abf7cce4f736e072858ebfd1 Mon Sep 17 00:00:00 2001 From: Curly Date: Sun, 23 Feb 2025 07:33:58 -0800 Subject: [PATCH 0764/1217] rename `rp23` (?) folder to `rp235x`; fix `ci.sh` to use `rp235x` folder --- ci.sh | 2 +- examples/{rp23 => rp235x}/.cargo/config.toml | 0 examples/{rp23 => rp235x}/Cargo.toml | 0 examples/{rp23 => rp235x}/assets/ferris.raw | Bin examples/{rp23 => rp235x}/build.rs | 0 examples/{rp23 => rp235x}/memory.x | 0 examples/{rp23 => rp235x}/src/bin/adc.rs | 0 examples/{rp23 => rp235x}/src/bin/adc_dma.rs | 0 .../{rp23 => rp235x}/src/bin/assign_resources.rs | 0 examples/{rp23 => rp235x}/src/bin/blinky.rs | 0 .../{rp23 => rp235x}/src/bin/blinky_two_channels.rs | 0 .../{rp23 => rp235x}/src/bin/blinky_two_tasks.rs | 0 examples/{rp23 => rp235x}/src/bin/button.rs | 0 examples/{rp23 => rp235x}/src/bin/debounce.rs | 0 examples/{rp23 => rp235x}/src/bin/flash.rs | 0 examples/{rp23 => rp235x}/src/bin/gpio_async.rs | 0 examples/{rp23 => rp235x}/src/bin/gpout.rs | 0 examples/{rp23 => rp235x}/src/bin/i2c_async.rs | 0 .../{rp23 => rp235x}/src/bin/i2c_async_embassy.rs | 0 examples/{rp23 => rp235x}/src/bin/i2c_blocking.rs | 0 examples/{rp23 => rp235x}/src/bin/i2c_slave.rs | 0 examples/{rp23 => rp235x}/src/bin/interrupt.rs | 0 examples/{rp23 => rp235x}/src/bin/multicore.rs | 0 examples/{rp23 => rp235x}/src/bin/multiprio.rs | 0 examples/{rp23 => rp235x}/src/bin/otp.rs | 0 examples/{rp23 => rp235x}/src/bin/pio_async.rs | 0 examples/{rp23 => rp235x}/src/bin/pio_dma.rs | 0 examples/{rp23 => rp235x}/src/bin/pio_hd44780.rs | 0 examples/{rp23 => rp235x}/src/bin/pio_i2s.rs | 0 examples/{rp23 => rp235x}/src/bin/pio_onewire.rs | 0 examples/{rp23 => rp235x}/src/bin/pio_pwm.rs | 0 .../{rp23 => rp235x}/src/bin/pio_rotary_encoder.rs | 0 .../src/bin/pio_rotary_encoder_rxf.rs | 0 examples/{rp23 => rp235x}/src/bin/pio_servo.rs | 0 examples/{rp23 => rp235x}/src/bin/pio_stepper.rs | 0 examples/{rp23 => rp235x}/src/bin/pio_uart.rs | 0 examples/{rp23 => rp235x}/src/bin/pio_ws2812.rs | 0 examples/{rp23 => rp235x}/src/bin/pwm.rs | 0 examples/{rp23 => rp235x}/src/bin/pwm_input.rs | 0 .../src/bin/pwm_tb6612fng_motor_driver.rs | 0 examples/{rp23 => rp235x}/src/bin/rosc.rs | 0 examples/{rp23 => rp235x}/src/bin/shared_bus.rs | 0 examples/{rp23 => rp235x}/src/bin/sharing.rs | 0 examples/{rp23 => rp235x}/src/bin/spi.rs | 0 examples/{rp23 => rp235x}/src/bin/spi_async.rs | 0 examples/{rp23 => rp235x}/src/bin/spi_display.rs | 0 examples/{rp23 => rp235x}/src/bin/spi_sdmmc.rs | 0 examples/{rp23 => rp235x}/src/bin/trng.rs | 0 examples/{rp23 => rp235x}/src/bin/uart.rs | 0 .../{rp23 => rp235x}/src/bin/uart_buffered_split.rs | 0 examples/{rp23 => rp235x}/src/bin/uart_r503.rs | 0 examples/{rp23 => rp235x}/src/bin/uart_unidir.rs | 0 .../{rp23 => rp235x}/src/bin/usb_hid_keyboard.rs | 0 examples/{rp23 => rp235x}/src/bin/usb_webusb.rs | 0 examples/{rp23 => rp235x}/src/bin/watchdog.rs | 0 .../src/bin/wifi_blinky_pico_plus_2.rs | 0 examples/{rp23 => rp235x}/src/bin/zerocopy.rs | 0 57 files changed, 1 insertion(+), 1 deletion(-) rename examples/{rp23 => rp235x}/.cargo/config.toml (100%) rename examples/{rp23 => rp235x}/Cargo.toml (100%) rename examples/{rp23 => rp235x}/assets/ferris.raw (100%) rename examples/{rp23 => rp235x}/build.rs (100%) rename examples/{rp23 => rp235x}/memory.x (100%) rename examples/{rp23 => rp235x}/src/bin/adc.rs (100%) rename examples/{rp23 => rp235x}/src/bin/adc_dma.rs (100%) rename examples/{rp23 => rp235x}/src/bin/assign_resources.rs (100%) rename examples/{rp23 => rp235x}/src/bin/blinky.rs (100%) rename examples/{rp23 => rp235x}/src/bin/blinky_two_channels.rs (100%) rename examples/{rp23 => rp235x}/src/bin/blinky_two_tasks.rs (100%) rename examples/{rp23 => rp235x}/src/bin/button.rs (100%) rename examples/{rp23 => rp235x}/src/bin/debounce.rs (100%) rename examples/{rp23 => rp235x}/src/bin/flash.rs (100%) rename examples/{rp23 => rp235x}/src/bin/gpio_async.rs (100%) rename examples/{rp23 => rp235x}/src/bin/gpout.rs (100%) rename examples/{rp23 => rp235x}/src/bin/i2c_async.rs (100%) rename examples/{rp23 => rp235x}/src/bin/i2c_async_embassy.rs (100%) rename examples/{rp23 => rp235x}/src/bin/i2c_blocking.rs (100%) rename examples/{rp23 => rp235x}/src/bin/i2c_slave.rs (100%) rename examples/{rp23 => rp235x}/src/bin/interrupt.rs (100%) rename examples/{rp23 => rp235x}/src/bin/multicore.rs (100%) rename examples/{rp23 => rp235x}/src/bin/multiprio.rs (100%) rename examples/{rp23 => rp235x}/src/bin/otp.rs (100%) rename examples/{rp23 => rp235x}/src/bin/pio_async.rs (100%) rename examples/{rp23 => rp235x}/src/bin/pio_dma.rs (100%) rename examples/{rp23 => rp235x}/src/bin/pio_hd44780.rs (100%) rename examples/{rp23 => rp235x}/src/bin/pio_i2s.rs (100%) rename examples/{rp23 => rp235x}/src/bin/pio_onewire.rs (100%) rename examples/{rp23 => rp235x}/src/bin/pio_pwm.rs (100%) rename examples/{rp23 => rp235x}/src/bin/pio_rotary_encoder.rs (100%) rename examples/{rp23 => rp235x}/src/bin/pio_rotary_encoder_rxf.rs (100%) rename examples/{rp23 => rp235x}/src/bin/pio_servo.rs (100%) rename examples/{rp23 => rp235x}/src/bin/pio_stepper.rs (100%) rename examples/{rp23 => rp235x}/src/bin/pio_uart.rs (100%) rename examples/{rp23 => rp235x}/src/bin/pio_ws2812.rs (100%) rename examples/{rp23 => rp235x}/src/bin/pwm.rs (100%) rename examples/{rp23 => rp235x}/src/bin/pwm_input.rs (100%) rename examples/{rp23 => rp235x}/src/bin/pwm_tb6612fng_motor_driver.rs (100%) rename examples/{rp23 => rp235x}/src/bin/rosc.rs (100%) rename examples/{rp23 => rp235x}/src/bin/shared_bus.rs (100%) rename examples/{rp23 => rp235x}/src/bin/sharing.rs (100%) rename examples/{rp23 => rp235x}/src/bin/spi.rs (100%) rename examples/{rp23 => rp235x}/src/bin/spi_async.rs (100%) rename examples/{rp23 => rp235x}/src/bin/spi_display.rs (100%) rename examples/{rp23 => rp235x}/src/bin/spi_sdmmc.rs (100%) rename examples/{rp23 => rp235x}/src/bin/trng.rs (100%) rename examples/{rp23 => rp235x}/src/bin/uart.rs (100%) rename examples/{rp23 => rp235x}/src/bin/uart_buffered_split.rs (100%) rename examples/{rp23 => rp235x}/src/bin/uart_r503.rs (100%) rename examples/{rp23 => rp235x}/src/bin/uart_unidir.rs (100%) rename examples/{rp23 => rp235x}/src/bin/usb_hid_keyboard.rs (100%) rename examples/{rp23 => rp235x}/src/bin/usb_webusb.rs (100%) rename examples/{rp23 => rp235x}/src/bin/watchdog.rs (100%) rename examples/{rp23 => rp235x}/src/bin/wifi_blinky_pico_plus_2.rs (100%) rename examples/{rp23 => rp235x}/src/bin/zerocopy.rs (100%) diff --git a/ci.sh b/ci.sh index ae0a56032..e32105b16 100755 --- a/ci.sh +++ b/ci.sh @@ -209,7 +209,7 @@ cargo batch \ --- build --release --manifest-path examples/nrf9151/ns/Cargo.toml --target thumbv8m.main-none-eabihf --artifact-dir out/examples/nrf9151/ns \ --- build --release --manifest-path examples/nrf51/Cargo.toml --target thumbv6m-none-eabi --artifact-dir out/examples/nrf51 \ --- build --release --manifest-path examples/rp/Cargo.toml --target thumbv6m-none-eabi --artifact-dir out/examples/rp \ - --- build --release --manifest-path examples/rp23/Cargo.toml --target thumbv8m.main-none-eabihf --artifact-dir out/examples/rp23 \ + --- build --release --manifest-path examples/rp235x/Cargo.toml --target thumbv8m.main-none-eabihf --artifact-dir out/examples/rp235x \ --- build --release --manifest-path examples/stm32f0/Cargo.toml --target thumbv6m-none-eabi --artifact-dir out/examples/stm32f0 \ --- build --release --manifest-path examples/stm32f1/Cargo.toml --target thumbv7m-none-eabi --artifact-dir out/examples/stm32f1 \ --- build --release --manifest-path examples/stm32f2/Cargo.toml --target thumbv7m-none-eabi --artifact-dir out/examples/stm32f2 \ diff --git a/examples/rp23/.cargo/config.toml b/examples/rp235x/.cargo/config.toml similarity index 100% rename from examples/rp23/.cargo/config.toml rename to examples/rp235x/.cargo/config.toml diff --git a/examples/rp23/Cargo.toml b/examples/rp235x/Cargo.toml similarity index 100% rename from examples/rp23/Cargo.toml rename to examples/rp235x/Cargo.toml diff --git a/examples/rp23/assets/ferris.raw b/examples/rp235x/assets/ferris.raw similarity index 100% rename from examples/rp23/assets/ferris.raw rename to examples/rp235x/assets/ferris.raw diff --git a/examples/rp23/build.rs b/examples/rp235x/build.rs similarity index 100% rename from examples/rp23/build.rs rename to examples/rp235x/build.rs diff --git a/examples/rp23/memory.x b/examples/rp235x/memory.x similarity index 100% rename from examples/rp23/memory.x rename to examples/rp235x/memory.x diff --git a/examples/rp23/src/bin/adc.rs b/examples/rp235x/src/bin/adc.rs similarity index 100% rename from examples/rp23/src/bin/adc.rs rename to examples/rp235x/src/bin/adc.rs diff --git a/examples/rp23/src/bin/adc_dma.rs b/examples/rp235x/src/bin/adc_dma.rs similarity index 100% rename from examples/rp23/src/bin/adc_dma.rs rename to examples/rp235x/src/bin/adc_dma.rs diff --git a/examples/rp23/src/bin/assign_resources.rs b/examples/rp235x/src/bin/assign_resources.rs similarity index 100% rename from examples/rp23/src/bin/assign_resources.rs rename to examples/rp235x/src/bin/assign_resources.rs diff --git a/examples/rp23/src/bin/blinky.rs b/examples/rp235x/src/bin/blinky.rs similarity index 100% rename from examples/rp23/src/bin/blinky.rs rename to examples/rp235x/src/bin/blinky.rs diff --git a/examples/rp23/src/bin/blinky_two_channels.rs b/examples/rp235x/src/bin/blinky_two_channels.rs similarity index 100% rename from examples/rp23/src/bin/blinky_two_channels.rs rename to examples/rp235x/src/bin/blinky_two_channels.rs diff --git a/examples/rp23/src/bin/blinky_two_tasks.rs b/examples/rp235x/src/bin/blinky_two_tasks.rs similarity index 100% rename from examples/rp23/src/bin/blinky_two_tasks.rs rename to examples/rp235x/src/bin/blinky_two_tasks.rs diff --git a/examples/rp23/src/bin/button.rs b/examples/rp235x/src/bin/button.rs similarity index 100% rename from examples/rp23/src/bin/button.rs rename to examples/rp235x/src/bin/button.rs diff --git a/examples/rp23/src/bin/debounce.rs b/examples/rp235x/src/bin/debounce.rs similarity index 100% rename from examples/rp23/src/bin/debounce.rs rename to examples/rp235x/src/bin/debounce.rs diff --git a/examples/rp23/src/bin/flash.rs b/examples/rp235x/src/bin/flash.rs similarity index 100% rename from examples/rp23/src/bin/flash.rs rename to examples/rp235x/src/bin/flash.rs diff --git a/examples/rp23/src/bin/gpio_async.rs b/examples/rp235x/src/bin/gpio_async.rs similarity index 100% rename from examples/rp23/src/bin/gpio_async.rs rename to examples/rp235x/src/bin/gpio_async.rs diff --git a/examples/rp23/src/bin/gpout.rs b/examples/rp235x/src/bin/gpout.rs similarity index 100% rename from examples/rp23/src/bin/gpout.rs rename to examples/rp235x/src/bin/gpout.rs diff --git a/examples/rp23/src/bin/i2c_async.rs b/examples/rp235x/src/bin/i2c_async.rs similarity index 100% rename from examples/rp23/src/bin/i2c_async.rs rename to examples/rp235x/src/bin/i2c_async.rs diff --git a/examples/rp23/src/bin/i2c_async_embassy.rs b/examples/rp235x/src/bin/i2c_async_embassy.rs similarity index 100% rename from examples/rp23/src/bin/i2c_async_embassy.rs rename to examples/rp235x/src/bin/i2c_async_embassy.rs diff --git a/examples/rp23/src/bin/i2c_blocking.rs b/examples/rp235x/src/bin/i2c_blocking.rs similarity index 100% rename from examples/rp23/src/bin/i2c_blocking.rs rename to examples/rp235x/src/bin/i2c_blocking.rs diff --git a/examples/rp23/src/bin/i2c_slave.rs b/examples/rp235x/src/bin/i2c_slave.rs similarity index 100% rename from examples/rp23/src/bin/i2c_slave.rs rename to examples/rp235x/src/bin/i2c_slave.rs diff --git a/examples/rp23/src/bin/interrupt.rs b/examples/rp235x/src/bin/interrupt.rs similarity index 100% rename from examples/rp23/src/bin/interrupt.rs rename to examples/rp235x/src/bin/interrupt.rs diff --git a/examples/rp23/src/bin/multicore.rs b/examples/rp235x/src/bin/multicore.rs similarity index 100% rename from examples/rp23/src/bin/multicore.rs rename to examples/rp235x/src/bin/multicore.rs diff --git a/examples/rp23/src/bin/multiprio.rs b/examples/rp235x/src/bin/multiprio.rs similarity index 100% rename from examples/rp23/src/bin/multiprio.rs rename to examples/rp235x/src/bin/multiprio.rs diff --git a/examples/rp23/src/bin/otp.rs b/examples/rp235x/src/bin/otp.rs similarity index 100% rename from examples/rp23/src/bin/otp.rs rename to examples/rp235x/src/bin/otp.rs diff --git a/examples/rp23/src/bin/pio_async.rs b/examples/rp235x/src/bin/pio_async.rs similarity index 100% rename from examples/rp23/src/bin/pio_async.rs rename to examples/rp235x/src/bin/pio_async.rs diff --git a/examples/rp23/src/bin/pio_dma.rs b/examples/rp235x/src/bin/pio_dma.rs similarity index 100% rename from examples/rp23/src/bin/pio_dma.rs rename to examples/rp235x/src/bin/pio_dma.rs diff --git a/examples/rp23/src/bin/pio_hd44780.rs b/examples/rp235x/src/bin/pio_hd44780.rs similarity index 100% rename from examples/rp23/src/bin/pio_hd44780.rs rename to examples/rp235x/src/bin/pio_hd44780.rs diff --git a/examples/rp23/src/bin/pio_i2s.rs b/examples/rp235x/src/bin/pio_i2s.rs similarity index 100% rename from examples/rp23/src/bin/pio_i2s.rs rename to examples/rp235x/src/bin/pio_i2s.rs diff --git a/examples/rp23/src/bin/pio_onewire.rs b/examples/rp235x/src/bin/pio_onewire.rs similarity index 100% rename from examples/rp23/src/bin/pio_onewire.rs rename to examples/rp235x/src/bin/pio_onewire.rs diff --git a/examples/rp23/src/bin/pio_pwm.rs b/examples/rp235x/src/bin/pio_pwm.rs similarity index 100% rename from examples/rp23/src/bin/pio_pwm.rs rename to examples/rp235x/src/bin/pio_pwm.rs diff --git a/examples/rp23/src/bin/pio_rotary_encoder.rs b/examples/rp235x/src/bin/pio_rotary_encoder.rs similarity index 100% rename from examples/rp23/src/bin/pio_rotary_encoder.rs rename to examples/rp235x/src/bin/pio_rotary_encoder.rs diff --git a/examples/rp23/src/bin/pio_rotary_encoder_rxf.rs b/examples/rp235x/src/bin/pio_rotary_encoder_rxf.rs similarity index 100% rename from examples/rp23/src/bin/pio_rotary_encoder_rxf.rs rename to examples/rp235x/src/bin/pio_rotary_encoder_rxf.rs diff --git a/examples/rp23/src/bin/pio_servo.rs b/examples/rp235x/src/bin/pio_servo.rs similarity index 100% rename from examples/rp23/src/bin/pio_servo.rs rename to examples/rp235x/src/bin/pio_servo.rs diff --git a/examples/rp23/src/bin/pio_stepper.rs b/examples/rp235x/src/bin/pio_stepper.rs similarity index 100% rename from examples/rp23/src/bin/pio_stepper.rs rename to examples/rp235x/src/bin/pio_stepper.rs diff --git a/examples/rp23/src/bin/pio_uart.rs b/examples/rp235x/src/bin/pio_uart.rs similarity index 100% rename from examples/rp23/src/bin/pio_uart.rs rename to examples/rp235x/src/bin/pio_uart.rs diff --git a/examples/rp23/src/bin/pio_ws2812.rs b/examples/rp235x/src/bin/pio_ws2812.rs similarity index 100% rename from examples/rp23/src/bin/pio_ws2812.rs rename to examples/rp235x/src/bin/pio_ws2812.rs diff --git a/examples/rp23/src/bin/pwm.rs b/examples/rp235x/src/bin/pwm.rs similarity index 100% rename from examples/rp23/src/bin/pwm.rs rename to examples/rp235x/src/bin/pwm.rs diff --git a/examples/rp23/src/bin/pwm_input.rs b/examples/rp235x/src/bin/pwm_input.rs similarity index 100% rename from examples/rp23/src/bin/pwm_input.rs rename to examples/rp235x/src/bin/pwm_input.rs diff --git a/examples/rp23/src/bin/pwm_tb6612fng_motor_driver.rs b/examples/rp235x/src/bin/pwm_tb6612fng_motor_driver.rs similarity index 100% rename from examples/rp23/src/bin/pwm_tb6612fng_motor_driver.rs rename to examples/rp235x/src/bin/pwm_tb6612fng_motor_driver.rs diff --git a/examples/rp23/src/bin/rosc.rs b/examples/rp235x/src/bin/rosc.rs similarity index 100% rename from examples/rp23/src/bin/rosc.rs rename to examples/rp235x/src/bin/rosc.rs diff --git a/examples/rp23/src/bin/shared_bus.rs b/examples/rp235x/src/bin/shared_bus.rs similarity index 100% rename from examples/rp23/src/bin/shared_bus.rs rename to examples/rp235x/src/bin/shared_bus.rs diff --git a/examples/rp23/src/bin/sharing.rs b/examples/rp235x/src/bin/sharing.rs similarity index 100% rename from examples/rp23/src/bin/sharing.rs rename to examples/rp235x/src/bin/sharing.rs diff --git a/examples/rp23/src/bin/spi.rs b/examples/rp235x/src/bin/spi.rs similarity index 100% rename from examples/rp23/src/bin/spi.rs rename to examples/rp235x/src/bin/spi.rs diff --git a/examples/rp23/src/bin/spi_async.rs b/examples/rp235x/src/bin/spi_async.rs similarity index 100% rename from examples/rp23/src/bin/spi_async.rs rename to examples/rp235x/src/bin/spi_async.rs diff --git a/examples/rp23/src/bin/spi_display.rs b/examples/rp235x/src/bin/spi_display.rs similarity index 100% rename from examples/rp23/src/bin/spi_display.rs rename to examples/rp235x/src/bin/spi_display.rs diff --git a/examples/rp23/src/bin/spi_sdmmc.rs b/examples/rp235x/src/bin/spi_sdmmc.rs similarity index 100% rename from examples/rp23/src/bin/spi_sdmmc.rs rename to examples/rp235x/src/bin/spi_sdmmc.rs diff --git a/examples/rp23/src/bin/trng.rs b/examples/rp235x/src/bin/trng.rs similarity index 100% rename from examples/rp23/src/bin/trng.rs rename to examples/rp235x/src/bin/trng.rs diff --git a/examples/rp23/src/bin/uart.rs b/examples/rp235x/src/bin/uart.rs similarity index 100% rename from examples/rp23/src/bin/uart.rs rename to examples/rp235x/src/bin/uart.rs diff --git a/examples/rp23/src/bin/uart_buffered_split.rs b/examples/rp235x/src/bin/uart_buffered_split.rs similarity index 100% rename from examples/rp23/src/bin/uart_buffered_split.rs rename to examples/rp235x/src/bin/uart_buffered_split.rs diff --git a/examples/rp23/src/bin/uart_r503.rs b/examples/rp235x/src/bin/uart_r503.rs similarity index 100% rename from examples/rp23/src/bin/uart_r503.rs rename to examples/rp235x/src/bin/uart_r503.rs diff --git a/examples/rp23/src/bin/uart_unidir.rs b/examples/rp235x/src/bin/uart_unidir.rs similarity index 100% rename from examples/rp23/src/bin/uart_unidir.rs rename to examples/rp235x/src/bin/uart_unidir.rs diff --git a/examples/rp23/src/bin/usb_hid_keyboard.rs b/examples/rp235x/src/bin/usb_hid_keyboard.rs similarity index 100% rename from examples/rp23/src/bin/usb_hid_keyboard.rs rename to examples/rp235x/src/bin/usb_hid_keyboard.rs diff --git a/examples/rp23/src/bin/usb_webusb.rs b/examples/rp235x/src/bin/usb_webusb.rs similarity index 100% rename from examples/rp23/src/bin/usb_webusb.rs rename to examples/rp235x/src/bin/usb_webusb.rs diff --git a/examples/rp23/src/bin/watchdog.rs b/examples/rp235x/src/bin/watchdog.rs similarity index 100% rename from examples/rp23/src/bin/watchdog.rs rename to examples/rp235x/src/bin/watchdog.rs diff --git a/examples/rp23/src/bin/wifi_blinky_pico_plus_2.rs b/examples/rp235x/src/bin/wifi_blinky_pico_plus_2.rs similarity index 100% rename from examples/rp23/src/bin/wifi_blinky_pico_plus_2.rs rename to examples/rp235x/src/bin/wifi_blinky_pico_plus_2.rs diff --git a/examples/rp23/src/bin/zerocopy.rs b/examples/rp235x/src/bin/zerocopy.rs similarity index 100% rename from examples/rp23/src/bin/zerocopy.rs rename to examples/rp235x/src/bin/zerocopy.rs From 2d0e0f51f84bd5a2de9cbb82b6fc17d946299172 Mon Sep 17 00:00:00 2001 From: Curly Date: Sun, 23 Feb 2025 07:37:34 -0800 Subject: [PATCH 0765/1217] add `rp235x` blinky_wifi.rs` to support RPi Pico 2 W --- examples/rp235x/src/bin/blinky_wifi.rs | 89 ++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 examples/rp235x/src/bin/blinky_wifi.rs diff --git a/examples/rp235x/src/bin/blinky_wifi.rs b/examples/rp235x/src/bin/blinky_wifi.rs new file mode 100644 index 000000000..7aeb38f1e --- /dev/null +++ b/examples/rp235x/src/bin/blinky_wifi.rs @@ -0,0 +1,89 @@ +//! This example tests the RP Pico 2 W onboard LED. +//! +//! It does not work with the RP Pico 2 board. See `blinky.rs`. + +#![no_std] +#![no_main] + +use cyw43_pio::{PioSpi, DEFAULT_CLOCK_DIVIDER}; +use defmt::*; +use embassy_executor::Spawner; +use embassy_rp::bind_interrupts; +use embassy_rp::gpio::{Level, Output}; +use embassy_rp::peripherals::{DMA_CH0, PIO0}; +use embassy_rp::pio::{InterruptHandler, Pio}; +use embassy_time::{Duration, Timer}; +use static_cell::StaticCell; +use {defmt_rtt as _, panic_probe as _}; + +// Program metadata for `picotool info`. +// This isn't needed, but it's recommended to have these minimal entries. +#[link_section = ".bi_entries"] +#[used] +pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ + embassy_rp::binary_info::rp_program_name!(c"Blinky Example"), + embassy_rp::binary_info::rp_program_description!( + c"This example tests the RP Pico 2 W's onboard LED, connected to GPIO 0 of the cyw43 \ + (WiFi chip) via PIO 0 over the SPI bus." + ), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_build_attribute!(), +]; + +bind_interrupts!(struct Irqs { + PIO0_IRQ_0 => InterruptHandler; +}); + +#[embassy_executor::task] +async fn cyw43_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>) -> ! { + runner.run().await +} + +#[embassy_executor::main] +async fn main(spawner: Spawner) { + let p = embassy_rp::init(Default::default()); + let fw = include_bytes!("../../../../cyw43-firmware/43439A0.bin"); + let clm = include_bytes!("../../../../cyw43-firmware/43439A0_clm.bin"); + + // To make flashing faster for development, you may want to flash the firmwares independently + // at hardcoded addresses, instead of baking them into the program with `include_bytes!`: + // probe-rs download ../../cyw43-firmware/43439A0.bin --binary-format bin --chip RP2040 --base-address 0x10100000 + // probe-rs download ../../cyw43-firmware/43439A0_clm.bin --binary-format bin --chip RP2040 --base-address 0x10140000 + //let fw = unsafe { core::slice::from_raw_parts(0x10100000 as *const u8, 230321) }; + //let clm = unsafe { core::slice::from_raw_parts(0x10140000 as *const u8, 4752) }; + + let pwr = Output::new(p.PIN_23, Level::Low); + let cs = Output::new(p.PIN_25, Level::High); + let mut pio = Pio::new(p.PIO0, Irqs); + let spi = PioSpi::new( + &mut pio.common, + pio.sm0, + DEFAULT_CLOCK_DIVIDER, + pio.irq0, + cs, + p.PIN_24, + p.PIN_29, + p.DMA_CH0, + ); + + static STATE: StaticCell = StaticCell::new(); + let state = STATE.init(cyw43::State::new()); + let (_net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await; + unwrap!(spawner.spawn(cyw43_task(runner))); + + control.init(clm).await; + control + .set_power_management(cyw43::PowerManagementMode::PowerSave) + .await; + + let delay = Duration::from_millis(250); + loop { + info!("led on!"); + control.gpio_set(0, true).await; + Timer::after(delay).await; + + info!("led off!"); + control.gpio_set(0, false).await; + Timer::after(delay).await; + } +} From 9d92d03c823e864759166cc406b7393ba524b0d9 Mon Sep 17 00:00:00 2001 From: Curly Date: Sun, 23 Feb 2025 07:39:25 -0800 Subject: [PATCH 0766/1217] rename `Pimoroni Pico Plus 2` example to group alphabetically with other `blinky` projects --- .../{wifi_blinky_pico_plus_2.rs => blinky_wifi_pico_plus_2.rs} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename examples/rp235x/src/bin/{wifi_blinky_pico_plus_2.rs => blinky_wifi_pico_plus_2.rs} (97%) diff --git a/examples/rp235x/src/bin/wifi_blinky_pico_plus_2.rs b/examples/rp235x/src/bin/blinky_wifi_pico_plus_2.rs similarity index 97% rename from examples/rp235x/src/bin/wifi_blinky_pico_plus_2.rs rename to examples/rp235x/src/bin/blinky_wifi_pico_plus_2.rs index ab7d6a93e..d49d2e34f 100644 --- a/examples/rp235x/src/bin/wifi_blinky_pico_plus_2.rs +++ b/examples/rp235x/src/bin/blinky_wifi_pico_plus_2.rs @@ -1,6 +1,6 @@ //! This example test the Pimoroni Pico Plus 2 on board LED. //! -//! It does not work with the RP Pico board. See blinky.rs. +//! It does not work with the RP Pico 2 board. See `blinky.rs`. #![no_std] #![no_main] From 76756ee702c76f925b6c0e1c28d5695ce321c894 Mon Sep 17 00:00:00 2001 From: Maximilian Rozwora Date: Mon, 24 Feb 2025 14:34:41 +0100 Subject: [PATCH 0767/1217] fix: BufferedUartRx embedded_hal_nb::serial::Read impl --- embassy-stm32/src/usart/buffered.rs | 28 +++++++++------------------- 1 file changed, 9 insertions(+), 19 deletions(-) diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs index 7bbe01a00..3d8268de7 100644 --- a/embassy-stm32/src/usart/buffered.rs +++ b/embassy-stm32/src/usart/buffered.rs @@ -908,26 +908,16 @@ impl<'d> embedded_hal_02::serial::Read for BufferedUartRx<'d> { type Error = Error; fn read(&mut self) -> Result> { - let r = self.info.regs; - unsafe { - let sr = sr(r).read(); - if sr.pe() { - rdr(r).read_volatile(); - Err(nb::Error::Other(Error::Parity)) - } else if sr.fe() { - rdr(r).read_volatile(); - Err(nb::Error::Other(Error::Framing)) - } else if sr.ne() { - rdr(r).read_volatile(); - Err(nb::Error::Other(Error::Noise)) - } else if sr.ore() { - rdr(r).read_volatile(); - Err(nb::Error::Other(Error::Overrun)) - } else if sr.rxne() { - Ok(rdr(r).read_volatile()) - } else { - Err(nb::Error::WouldBlock) + let state = self.state; + let mut rx_reader = unsafe { state.rx_buf.reader() }; + + if let Some(data) = rx_reader.pop_one() { + Ok(data) + } else { + if state.rx_buf.is_full() { + self.info.interrupt.pend(); } + Err(nb::Error::WouldBlock) } } } From c52f56785fbc4ad7feb7a0f61bd40f0d3563a845 Mon Sep 17 00:00:00 2001 From: Maximilian Rozwora Date: Mon, 24 Feb 2025 14:48:32 +0100 Subject: [PATCH 0768/1217] Apply cargo format --- embassy-stm32/src/usart/buffered.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs index 3d8268de7..1cb9616d9 100644 --- a/embassy-stm32/src/usart/buffered.rs +++ b/embassy-stm32/src/usart/buffered.rs @@ -910,7 +910,7 @@ impl<'d> embedded_hal_02::serial::Read for BufferedUartRx<'d> { fn read(&mut self) -> Result> { let state = self.state; let mut rx_reader = unsafe { state.rx_buf.reader() }; - + if let Some(data) = rx_reader.pop_one() { Ok(data) } else { From 519bd8646769899040b33a42ab57ddbd869d31ae Mon Sep 17 00:00:00 2001 From: Maximilian Rozwora Date: Mon, 24 Feb 2025 15:11:14 +0100 Subject: [PATCH 0769/1217] fix: Check buffer full before pop_done() --- embassy-stm32/src/usart/buffered.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs index 1cb9616d9..e61558b58 100644 --- a/embassy-stm32/src/usart/buffered.rs +++ b/embassy-stm32/src/usart/buffered.rs @@ -911,12 +911,13 @@ impl<'d> embedded_hal_02::serial::Read for BufferedUartRx<'d> { let state = self.state; let mut rx_reader = unsafe { state.rx_buf.reader() }; + let do_pend = state.rx_buf.is_full(); if let Some(data) = rx_reader.pop_one() { - Ok(data) - } else { - if state.rx_buf.is_full() { + if do_pend { self.info.interrupt.pend(); } + Ok(data) + } else { Err(nb::Error::WouldBlock) } } From f1c7e388e61bd9ba2362032dd45c9ab91cf3882f Mon Sep 17 00:00:00 2001 From: "antonello.contini" Date: Tue, 25 Feb 2025 19:59:57 +0100 Subject: [PATCH 0770/1217] do not use pllsrc for i2s; added field for plli2ssrc selection --- embassy-stm32/src/rcc/f247.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/embassy-stm32/src/rcc/f247.rs b/embassy-stm32/src/rcc/f247.rs index 79d793dcc..7426b6792 100644 --- a/embassy-stm32/src/rcc/f247.rs +++ b/embassy-stm32/src/rcc/f247.rs @@ -4,6 +4,9 @@ pub use crate::pac::rcc::vals::{ Hpre as AHBPrescaler, Pllm as PllPreDiv, Plln as PllMul, Pllp as PllPDiv, Pllq as PllQDiv, Pllr as PllRDiv, Pllsrc as PllSource, Ppre as APBPrescaler, Sw as Sysclk, }; + +#[cfg(any(stm32f413, stm32f423, stm32f412))] +pub use crate::pac::rcc::vals::Plli2ssrc as Plli2sSource; #[cfg(any(stm32f4, stm32f7))] use crate::pac::PWR; use crate::pac::{FLASH, RCC}; @@ -84,6 +87,8 @@ pub struct Config { pub sys: Sysclk, pub pll_src: PllSource, + #[cfg(any(stm32f413, stm32f423, stm32f412))] + pub plli2s_src: Plli2sSource, pub pll: Option, #[cfg(any(stm32f2, all(stm32f4, not(stm32f410)), stm32f7))] @@ -111,6 +116,8 @@ impl Default for Config { hse: None, sys: Sysclk::HSI, pll_src: PllSource::HSI, + #[cfg(any(stm32f413, stm32f423, stm32f412))] + plli2s_src: Plli2sSource::HSE_HSI, pll: None, #[cfg(any(stm32f2, all(stm32f4, not(stm32f410)), stm32f7))] plli2s: None, @@ -417,7 +424,7 @@ fn init_pll(instance: PllInstance, config: Option, input: &PllInput) -> Pll #[cfg(any(stm32f411, stm32f412, stm32f413, stm32f423, stm32f446))] w.set_pllm(pll.prediv); #[cfg(any(stm32f412, stm32f413, stm32f423))] - w.set_pllsrc(input.source); + w.set_plli2ssrc(Plli2sSource::HSE_HSI); write_fields!(w); }), From 51085a5e949317a578e5253d8eaccf247ccc47cc Mon Sep 17 00:00:00 2001 From: "antonello.contini" Date: Tue, 25 Feb 2025 21:21:23 +0100 Subject: [PATCH 0771/1217] let user set external i2s clock frequency --- embassy-stm32/src/rcc/f247.rs | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/embassy-stm32/src/rcc/f247.rs b/embassy-stm32/src/rcc/f247.rs index 7426b6792..52d093609 100644 --- a/embassy-stm32/src/rcc/f247.rs +++ b/embassy-stm32/src/rcc/f247.rs @@ -89,6 +89,8 @@ pub struct Config { pub pll_src: PllSource, #[cfg(any(stm32f413, stm32f423, stm32f412))] pub plli2s_src: Plli2sSource, + #[cfg(any(stm32f412, stm32f413, stm32f423))] + pub external_clock: Option, pub pll: Option, #[cfg(any(stm32f2, all(stm32f4, not(stm32f410)), stm32f7))] @@ -118,6 +120,8 @@ impl Default for Config { pll_src: PllSource::HSI, #[cfg(any(stm32f413, stm32f423, stm32f412))] plli2s_src: Plli2sSource::HSE_HSI, + #[cfg(any(stm32f412, stm32f413, stm32f423))] + external_clock: None, pll: None, #[cfg(any(stm32f2, all(stm32f4, not(stm32f410)), stm32f7))] plli2s: None, @@ -192,6 +196,8 @@ pub(crate) unsafe fn init(config: Config) { let pll_input = PllInput { hse, hsi, + #[cfg(any(stm32f412, stm32f413, stm32f423))] + external: config.external_clock, source: config.pll_src, }; let pll = init_pll(PllInstance::Pll, config.pll, &pll_input); @@ -325,6 +331,8 @@ struct PllInput { source: PllSource, hsi: Option, hse: Option, + #[cfg(any(stm32f412, stm32f413, stm32f423))] + external: Option, } #[derive(Default)] @@ -369,10 +377,17 @@ fn init_pll(instance: PllInstance, config: Option, input: &PllInput) -> Pll let Some(pll) = config else { return PllOutput::default() }; + #[cfg(not(any(stm32f412, stm32f413, stm32f423)))] let pll_src = match input.source { PllSource::HSE => input.hse, PllSource::HSI => input.hsi, }; + #[cfg(any(stm32f412, stm32f413, stm32f423))] + let pll_src = match (input.source, input.external) { + (PllSource::HSE, None) => input.hse, + (PllSource::HSI, None) => input.hsi, + (_, Some(ext)) => Some(ext), + }; let pll_src = pll_src.unwrap(); @@ -424,7 +439,13 @@ fn init_pll(instance: PllInstance, config: Option, input: &PllInput) -> Pll #[cfg(any(stm32f411, stm32f412, stm32f413, stm32f423, stm32f446))] w.set_pllm(pll.prediv); #[cfg(any(stm32f412, stm32f413, stm32f423))] - w.set_plli2ssrc(Plli2sSource::HSE_HSI); + { + let plli2ssource = match input.external { + Some(_) => Plli2sSource::EXTERNAL, + None => Plli2sSource::HSE_HSI, + }; + w.set_plli2ssrc(plli2ssource); + } write_fields!(w); }), From 724e1a34e57c283bc59068f3ac69f19bf3d2a72a Mon Sep 17 00:00:00 2001 From: "antonello.contini" Date: Tue, 25 Feb 2025 21:37:01 +0100 Subject: [PATCH 0772/1217] simpler configuration --- embassy-stm32/src/rcc/f247.rs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/embassy-stm32/src/rcc/f247.rs b/embassy-stm32/src/rcc/f247.rs index 52d093609..8c5307409 100644 --- a/embassy-stm32/src/rcc/f247.rs +++ b/embassy-stm32/src/rcc/f247.rs @@ -87,10 +87,8 @@ pub struct Config { pub sys: Sysclk, pub pll_src: PllSource, - #[cfg(any(stm32f413, stm32f423, stm32f412))] - pub plli2s_src: Plli2sSource, #[cfg(any(stm32f412, stm32f413, stm32f423))] - pub external_clock: Option, + pub external_i2s_clock: Option, pub pll: Option, #[cfg(any(stm32f2, all(stm32f4, not(stm32f410)), stm32f7))] @@ -118,10 +116,8 @@ impl Default for Config { hse: None, sys: Sysclk::HSI, pll_src: PllSource::HSI, - #[cfg(any(stm32f413, stm32f423, stm32f412))] - plli2s_src: Plli2sSource::HSE_HSI, #[cfg(any(stm32f412, stm32f413, stm32f423))] - external_clock: None, + external_i2s_clock: None, pll: None, #[cfg(any(stm32f2, all(stm32f4, not(stm32f410)), stm32f7))] plli2s: None, @@ -197,7 +193,7 @@ pub(crate) unsafe fn init(config: Config) { hse, hsi, #[cfg(any(stm32f412, stm32f413, stm32f423))] - external: config.external_clock, + external: config.external_i2s_clock, source: config.pll_src, }; let pll = init_pll(PllInstance::Pll, config.pll, &pll_input); From 0c1601651bc04fcfb174002d50e1c86110e1bfff Mon Sep 17 00:00:00 2001 From: "antonello.contini" Date: Tue, 25 Feb 2025 22:02:23 +0100 Subject: [PATCH 0773/1217] cargo fmt --- embassy-stm32/src/rcc/f247.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/embassy-stm32/src/rcc/f247.rs b/embassy-stm32/src/rcc/f247.rs index 8c5307409..8ce9d5f5b 100644 --- a/embassy-stm32/src/rcc/f247.rs +++ b/embassy-stm32/src/rcc/f247.rs @@ -1,12 +1,11 @@ use stm32_metapac::flash::vals::Latency; +#[cfg(any(stm32f413, stm32f423, stm32f412))] +pub use crate::pac::rcc::vals::Plli2ssrc as Plli2sSource; pub use crate::pac::rcc::vals::{ Hpre as AHBPrescaler, Pllm as PllPreDiv, Plln as PllMul, Pllp as PllPDiv, Pllq as PllQDiv, Pllr as PllRDiv, Pllsrc as PllSource, Ppre as APBPrescaler, Sw as Sysclk, }; - -#[cfg(any(stm32f413, stm32f423, stm32f412))] -pub use crate::pac::rcc::vals::Plli2ssrc as Plli2sSource; #[cfg(any(stm32f4, stm32f7))] use crate::pac::PWR; use crate::pac::{FLASH, RCC}; From 27709df94ad0662a262aa2465b41554ce0d88d87 Mon Sep 17 00:00:00 2001 From: Guy Marino Date: Wed, 26 Feb 2025 14:14:16 -0800 Subject: [PATCH 0774/1217] Implement `core::error::Error` for STM32 Serial Devices --- embassy-stm32/src/i2c/mod.rs | 18 ++++++++++++++++++ embassy-stm32/src/spi/mod.rs | 15 +++++++++++++++ embassy-stm32/src/usart/mod.rs | 16 ++++++++++++++++ 3 files changed, 49 insertions(+) diff --git a/embassy-stm32/src/i2c/mod.rs b/embassy-stm32/src/i2c/mod.rs index 1fc91f1ef..3a9954663 100644 --- a/embassy-stm32/src/i2c/mod.rs +++ b/embassy-stm32/src/i2c/mod.rs @@ -44,6 +44,24 @@ pub enum Error { ZeroLengthTransfer, } +impl core::fmt::Display for Error { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let message = match self { + Self::Bus => "Bus Error", + Self::Arbitration => "Arbitration Lost", + Self::Nack => "ACK Not Received", + Self::Timeout => "Request Timed Out", + Self::Crc => "CRC Mismatch", + Self::Overrun => "Buffer Overrun", + Self::ZeroLengthTransfer => "Zero-Length Transfers are not allowed", + }; + + write!(f, "{}", message) + } +} + +impl core::error::Error for Error {} + /// I2C config #[non_exhaustive] #[derive(Copy, Clone)] diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs index 45893d24b..44dda6a9e 100644 --- a/embassy-stm32/src/spi/mod.rs +++ b/embassy-stm32/src/spi/mod.rs @@ -31,6 +31,21 @@ pub enum Error { Overrun, } +impl core::fmt::Display for Error { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let message = match self { + Self::Framing => "Invalid Framing", + Self::Crc => "Hardware CRC Check Failed", + Self::ModeFault => "Mode Fault", + Self::Overrun => "Buffer Overrun", + }; + + write!(f, "{}", message) + } +} + +impl core::error::Error for Error {} + /// SPI bit order #[derive(Copy, Clone)] pub enum BitOrder { diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index 48cc4f6d6..de7b3c8df 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -293,6 +293,22 @@ pub enum Error { BufferTooLong, } +impl core::fmt::Display for Error { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let message = match self { + Self::Framing => "Framing Error", + Self::Noise => "Noise Error", + Self::Overrun => "RX Buffer Overrun", + Self::Parity => "Parity Check Error", + Self::BufferTooLong => "Buffer too large for DMA", + }; + + write!(f, "{}", message) + } +} + +impl core::error::Error for Error {} + enum ReadCompletionEvent { // DMA Read transfer completed first DmaCompleted, From 03f73ce339c31b2cd222a7e96e66ee78f37e2ce3 Mon Sep 17 00:00:00 2001 From: Aaron Griffith Date: Thu, 27 Feb 2025 06:50:01 -0500 Subject: [PATCH 0775/1217] stm32/i2c: disable peripheral when changing timings --- embassy-stm32/src/i2c/v2.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs index 71769bbc1..1f53a995d 100644 --- a/embassy-stm32/src/i2c/v2.rs +++ b/embassy-stm32/src/i2c/v2.rs @@ -855,7 +855,12 @@ impl<'d, M: Mode> SetConfig for I2c<'d, M> { type Config = Hertz; type ConfigError = (); fn set_config(&mut self, config: &Self::Config) -> Result<(), ()> { + self.info.regs.cr1().modify(|reg| { + reg.set_pe(false); + }); + let timings = Timings::new(self.kernel_clock, *config); + self.info.regs.timingr().write(|reg| { reg.set_presc(timings.prescale); reg.set_scll(timings.scll); @@ -864,6 +869,10 @@ impl<'d, M: Mode> SetConfig for I2c<'d, M> { reg.set_scldel(timings.scldel); }); + self.info.regs.cr1().modify(|reg| { + reg.set_pe(true); + }); + Ok(()) } } From 3b37c79331c191a5153bbe4ac7e464150c714f13 Mon Sep 17 00:00:00 2001 From: Rogan Morrow Date: Fri, 28 Feb 2025 12:28:57 +1100 Subject: [PATCH 0776/1217] only clear idle flag --- embassy-stm32/src/usart/ringbuffered.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/embassy-stm32/src/usart/ringbuffered.rs b/embassy-stm32/src/usart/ringbuffered.rs index 560ce4e8f..2a59cdcb4 100644 --- a/embassy-stm32/src/usart/ringbuffered.rs +++ b/embassy-stm32/src/usart/ringbuffered.rs @@ -254,7 +254,9 @@ fn clear_idle_flag(r: Regs) -> Sr { // This read also clears the error and idle interrupt flags on v1. unsafe { rdr(r).read_volatile() }; - clear_interrupt_flags(r, sr); + let mut clear_idle = regs::Icr(0); + clear_idle.set_idle(true); + r.icr().write_value(clear_idle); r.cr1().modify(|w| w.set_idleie(true)); From 065071b4672e1223be22c5c746b5d97856ba8079 Mon Sep 17 00:00:00 2001 From: Rogan Morrow Date: Fri, 28 Feb 2025 12:30:23 +1100 Subject: [PATCH 0777/1217] add separate tx waker --- embassy-stm32/src/usart/mod.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index de7b3c8df..568067360 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -85,6 +85,7 @@ unsafe fn on_interrupt(r: Regs, s: &'static State) { compiler_fence(Ordering::SeqCst); s.rx_waker.wake(); + s.tx_waker.wake(); } #[derive(Clone, Copy, PartialEq, Eq, Debug)] @@ -592,7 +593,7 @@ async fn flush(info: &Info, state: &State) -> Result<(), Error> { // future which completes when Transmission complete is detected let abort = poll_fn(move |cx| { - state.rx_waker.register(cx.waker()); + state.tx_waker.register(cx.waker()); let sr = sr(r).read(); if sr.tc() { @@ -2019,6 +2020,7 @@ enum Kind { struct State { rx_waker: AtomicWaker, + tx_waker: AtomicWaker, tx_rx_refcount: AtomicU8, } @@ -2026,6 +2028,7 @@ impl State { const fn new() -> Self { Self { rx_waker: AtomicWaker::new(), + tx_waker: AtomicWaker::new(), tx_rx_refcount: AtomicU8::new(0), } } From 2cc21d488343228aea3294dc9cd223ac2e145898 Mon Sep 17 00:00:00 2001 From: Rogan Morrow Date: Fri, 28 Feb 2025 12:40:01 +1100 Subject: [PATCH 0778/1217] feature flag --- embassy-stm32/src/usart/ringbuffered.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/embassy-stm32/src/usart/ringbuffered.rs b/embassy-stm32/src/usart/ringbuffered.rs index 2a59cdcb4..85aeb515f 100644 --- a/embassy-stm32/src/usart/ringbuffered.rs +++ b/embassy-stm32/src/usart/ringbuffered.rs @@ -254,9 +254,12 @@ fn clear_idle_flag(r: Regs) -> Sr { // This read also clears the error and idle interrupt flags on v1. unsafe { rdr(r).read_volatile() }; - let mut clear_idle = regs::Icr(0); - clear_idle.set_idle(true); - r.icr().write_value(clear_idle); + #[cfg(any(usart_v3, usart_v4))] + { + let mut clear_idle = regs::Icr(0); + clear_idle.set_idle(true); + r.icr().write_value(clear_idle); + } r.cr1().modify(|w| w.set_idleie(true)); From 32f6f1513d8e5b98f02a0833f9e5211c7bab2f51 Mon Sep 17 00:00:00 2001 From: Rogan Morrow Date: Fri, 28 Feb 2025 12:41:44 +1100 Subject: [PATCH 0779/1217] add missing module --- embassy-stm32/src/usart/ringbuffered.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/embassy-stm32/src/usart/ringbuffered.rs b/embassy-stm32/src/usart/ringbuffered.rs index 85aeb515f..e2cd11b1b 100644 --- a/embassy-stm32/src/usart/ringbuffered.rs +++ b/embassy-stm32/src/usart/ringbuffered.rs @@ -16,6 +16,7 @@ use crate::gpio::{AnyPin, SealedPin as _}; use crate::mode::Async; use crate::time::Hertz; use crate::usart::{Regs, Sr}; +use crate::pac::usart::regs; /// Rx-only Ring-buffered UART Driver /// From 5512e3a5402b8ca5712914b3f53b78ed22db5fe3 Mon Sep 17 00:00:00 2001 From: Rogan Morrow Date: Fri, 28 Feb 2025 12:49:28 +1100 Subject: [PATCH 0780/1217] fix --- embassy-stm32/src/usart/ringbuffered.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/usart/ringbuffered.rs b/embassy-stm32/src/usart/ringbuffered.rs index e2cd11b1b..3e14cf3cb 100644 --- a/embassy-stm32/src/usart/ringbuffered.rs +++ b/embassy-stm32/src/usart/ringbuffered.rs @@ -9,14 +9,15 @@ use embedded_io_async::ReadReady; use futures_util::future::{select, Either}; use super::{ - clear_interrupt_flags, rdr, reconfigure, set_baudrate, sr, Config, ConfigError, Error, Info, State, UartRx, + rdr, reconfigure, set_baudrate, sr, Config, ConfigError, Error, Info, State, UartRx, }; use crate::dma::ReadableRingBuffer; use crate::gpio::{AnyPin, SealedPin as _}; use crate::mode::Async; +#[cfg(any(usart_v3, usart_v4))] +use crate::pac::usart::regs; use crate::time::Hertz; use crate::usart::{Regs, Sr}; -use crate::pac::usart::regs; /// Rx-only Ring-buffered UART Driver /// From db44679e7541e67360d92a5e576d97a75c93ea67 Mon Sep 17 00:00:00 2001 From: Rogan Morrow Date: Fri, 28 Feb 2025 12:50:15 +1100 Subject: [PATCH 0781/1217] fix --- embassy-stm32/src/usart/ringbuffered.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/embassy-stm32/src/usart/ringbuffered.rs b/embassy-stm32/src/usart/ringbuffered.rs index 3e14cf3cb..3631888e4 100644 --- a/embassy-stm32/src/usart/ringbuffered.rs +++ b/embassy-stm32/src/usart/ringbuffered.rs @@ -8,9 +8,7 @@ use embassy_hal_internal::PeripheralRef; use embedded_io_async::ReadReady; use futures_util::future::{select, Either}; -use super::{ - rdr, reconfigure, set_baudrate, sr, Config, ConfigError, Error, Info, State, UartRx, -}; +use super::{rdr, reconfigure, set_baudrate, sr, Config, ConfigError, Error, Info, State, UartRx}; use crate::dma::ReadableRingBuffer; use crate::gpio::{AnyPin, SealedPin as _}; use crate::mode::Async; From 4c01f033eaa946db3ec458ee189e4bd33f3f90ab Mon Sep 17 00:00:00 2001 From: "Hendrik v. Raven" Date: Fri, 28 Feb 2025 09:06:18 +0100 Subject: [PATCH 0782/1217] stm32: do not use private constructor --- embassy-stm32/src/sai/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/src/sai/mod.rs b/embassy-stm32/src/sai/mod.rs index 0dc8b62d0..39ed44712 100644 --- a/embassy-stm32/src/sai/mod.rs +++ b/embassy-stm32/src/sai/mod.rs @@ -936,7 +936,7 @@ impl<'d, T: Instance, W: word::Word> Sai<'d, T, W> { w.set_nbslot(config.slot_count.0 as u8 - 1); w.set_slotsz(config.slot_size.slotsz()); w.set_fboff(config.first_bit_offset.0 as u8); - w.set_sloten(vals::Sloten(config.slot_enable as u16)); + w.set_sloten(vals::Sloten::from_bits(config.slot_enable as u16)); }); ch.cr1().modify(|w| w.set_saien(true)); From 025d9f6e98086e52cf8025ca475f64899b3d7567 Mon Sep 17 00:00:00 2001 From: Alix ANNERAUD Date: Fri, 28 Feb 2025 15:52:07 +0100 Subject: [PATCH 0783/1217] Add RwLock to embassy-sync Fixes #1394 --- For more details, open the [Copilot Workspace session](https://copilot-workspace.githubnext.com/embassy-rs/embassy/issues/1394?shareId=XXXX-XXXX-XXXX-XXXX). --- embassy-sync/src/lib.rs | 1 + embassy-sync/src/rwlock.rs | 256 +++++++++++++++++++++++++++++++++++ embassy-sync/tests/rwlock.rs | 81 +++++++++++ 3 files changed, 338 insertions(+) create mode 100644 embassy-sync/src/rwlock.rs create mode 100644 embassy-sync/tests/rwlock.rs diff --git a/embassy-sync/src/lib.rs b/embassy-sync/src/lib.rs index df0f5e815..5d91b4d9c 100644 --- a/embassy-sync/src/lib.rs +++ b/embassy-sync/src/lib.rs @@ -18,6 +18,7 @@ pub mod once_lock; pub mod pipe; pub mod priority_channel; pub mod pubsub; +pub mod rwlock; pub mod semaphore; pub mod signal; pub mod waitqueue; diff --git a/embassy-sync/src/rwlock.rs b/embassy-sync/src/rwlock.rs new file mode 100644 index 000000000..15ea8468e --- /dev/null +++ b/embassy-sync/src/rwlock.rs @@ -0,0 +1,256 @@ +use core::cell::RefCell; +use core::future::{poll_fn, Future}; +use core::ops::{Deref, DerefMut}; +use core::task::Poll; + +use crate::blocking_mutex::raw::RawMutex; +use crate::blocking_mutex::Mutex as BlockingMutex; +use crate::waitqueue::MultiWakerRegistration; + +/// Error returned by [`RwLock::try_read`] and [`RwLock::try_write`] +#[derive(PartialEq, Eq, Clone, Copy, Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct TryLockError; + +/// Async read-write lock. +/// +/// The lock is generic over a blocking [`RawMutex`](crate::blocking_mutex::raw::RawMutex). +/// The raw mutex is used to guard access to the internal state. It +/// is held for very short periods only, while locking and unlocking. It is *not* held +/// for the entire time the async RwLock is locked. +/// +/// Which implementation you select depends on the context in which you're using the lock. +/// +/// Use [`CriticalSectionRawMutex`](crate::blocking_mutex::raw::CriticalSectionRawMutex) when data can be shared between threads and interrupts. +/// +/// Use [`NoopRawMutex`](crate::blocking_mutex::raw::NoopRawMutex) when data is only shared between tasks running on the same executor. +/// +/// Use [`ThreadModeRawMutex`](crate::blocking_mutex::raw::ThreadModeRawMutex) when data is shared between tasks running on the same executor but you want a singleton. +/// +pub struct RwLock +where + M: RawMutex, + T: ?Sized, +{ + state: BlockingMutex>, + inner: RefCell, +} + +struct State { + readers: usize, + writer: bool, + writer_waker: MultiWakerRegistration<1>, + reader_wakers: MultiWakerRegistration<8>, +} + +impl State { + fn new() -> Self { + Self { + readers: 0, + writer: false, + writer_waker: MultiWakerRegistration::new(), + reader_wakers: MultiWakerRegistration::new(), + } + } +} + +impl RwLock +where + M: RawMutex, +{ + /// Create a new read-write lock with the given value. + pub const fn new(value: T) -> Self { + Self { + inner: RefCell::new(value), + state: BlockingMutex::new(RefCell::new(State::new())), + } + } +} + +impl RwLock +where + M: RawMutex, + T: ?Sized, +{ + /// Acquire a read lock. + /// + /// This will wait for the lock to be available if it's already locked for writing. + pub fn read(&self) -> impl Future> { + poll_fn(|cx| { + let mut state = self.state.lock(|s| s.borrow_mut()); + if state.writer { + state.reader_wakers.register(cx.waker()); + Poll::Pending + } else { + state.readers += 1; + Poll::Ready(RwLockReadGuard { lock: self }) + } + }) + } + + /// Acquire a write lock. + /// + /// This will wait for the lock to be available if it's already locked for reading or writing. + pub fn write(&self) -> impl Future> { + poll_fn(|cx| { + let mut state = self.state.lock(|s| s.borrow_mut()); + if state.writer || state.readers > 0 { + state.writer_waker.register(cx.waker()); + Poll::Pending + } else { + state.writer = true; + Poll::Ready(RwLockWriteGuard { lock: self }) + } + }) + } + + /// Attempt to immediately acquire a read lock. + /// + /// If the lock is already locked for writing, this will return an error instead of waiting. + pub fn try_read(&self) -> Result, TryLockError> { + let mut state = self.state.lock(|s| s.borrow_mut()); + if state.writer { + Err(TryLockError) + } else { + state.readers += 1; + Ok(RwLockReadGuard { lock: self }) + } + } + + /// Attempt to immediately acquire a write lock. + /// + /// If the lock is already locked for reading or writing, this will return an error instead of waiting. + pub fn try_write(&self) -> Result, TryLockError> { + let mut state = self.state.lock(|s| s.borrow_mut()); + if state.writer || state.readers > 0 { + Err(TryLockError) + } else { + state.writer = true; + Ok(RwLockWriteGuard { lock: self }) + } + } + + /// Consumes this lock, returning the underlying data. + pub fn into_inner(self) -> T + where + T: Sized, + { + self.inner.into_inner() + } + + /// Returns a mutable reference to the underlying data. + /// + /// Since this call borrows the RwLock mutably, no actual locking needs to + /// take place -- the mutable borrow statically guarantees no locks exist. + pub fn get_mut(&mut self) -> &mut T { + self.inner.get_mut() + } +} + +impl From for RwLock +where + M: RawMutex, +{ + fn from(from: T) -> Self { + Self::new(from) + } +} + +impl Default for RwLock +where + M: RawMutex, + T: Default, +{ + fn default() -> Self { + Self::new(Default::default()) + } +} + +/// Async read lock guard. +/// +/// Owning an instance of this type indicates having +/// successfully locked the RwLock for reading, and grants access to the contents. +/// +/// Dropping it unlocks the RwLock. +#[must_use = "if unused the RwLock will immediately unlock"] +pub struct RwLockReadGuard<'a, M, T> +where + M: RawMutex, + T: ?Sized, +{ + lock: &'a RwLock, +} + +impl<'a, M, T> Drop for RwLockReadGuard<'a, M, T> +where + M: RawMutex, + T: ?Sized, +{ + fn drop(&mut self) { + let mut state = self.lock.state.lock(|s| s.borrow_mut()); + state.readers -= 1; + if state.readers == 0 { + state.writer_waker.wake(); + } + } +} + +impl<'a, M, T> Deref for RwLockReadGuard<'a, M, T> +where + M: RawMutex, + T: ?Sized, +{ + type Target = T; + fn deref(&self) -> &Self::Target { + self.lock.inner.borrow() + } +} + +/// Async write lock guard. +/// +/// Owning an instance of this type indicates having +/// successfully locked the RwLock for writing, and grants access to the contents. +/// +/// Dropping it unlocks the RwLock. +#[must_use = "if unused the RwLock will immediately unlock"] +pub struct RwLockWriteGuard<'a, M, T> +where + M: RawMutex, + T: ?Sized, +{ + lock: &'a RwLock, +} + +impl<'a, M, T> Drop for RwLockWriteGuard<'a, M, T> +where + M: RawMutex, + T: ?Sized, +{ + fn drop(&mut self) { + let mut state = self.lock.state.lock(|s| s.borrow_mut()); + state.writer = false; + state.reader_wakers.wake(); + state.writer_waker.wake(); + } +} + +impl<'a, M, T> Deref for RwLockWriteGuard<'a, M, T> +where + M: RawMutex, + T: ?Sized, +{ + type Target = T; + fn deref(&self) -> &Self::Target { + self.lock.inner.borrow() + } +} + +impl<'a, M, T> DerefMut for RwLockWriteGuard<'a, M, T> +where + M: RawMutex, + T: ?Sized, +{ + fn deref_mut(&mut self) -> &mut Self::Target { + self.lock.inner.borrow_mut() + } +} diff --git a/embassy-sync/tests/rwlock.rs b/embassy-sync/tests/rwlock.rs new file mode 100644 index 000000000..301cb0492 --- /dev/null +++ b/embassy-sync/tests/rwlock.rs @@ -0,0 +1,81 @@ +use embassy_sync::blocking_mutex::raw::NoopRawMutex; +use embassy_sync::rwlock::RwLock; +use futures_executor::block_on; + +#[futures_test::test] +async fn test_rwlock_read() { + let lock = RwLock::::new(5); + + { + let read_guard = lock.read().await; + assert_eq!(*read_guard, 5); + } + + { + let read_guard = lock.read().await; + assert_eq!(*read_guard, 5); + } +} + +#[futures_test::test] +async fn test_rwlock_write() { + let lock = RwLock::::new(5); + + { + let mut write_guard = lock.write().await; + *write_guard = 10; + } + + { + let read_guard = lock.read().await; + assert_eq!(*read_guard, 10); + } +} + +#[futures_test::test] +async fn test_rwlock_try_read() { + let lock = RwLock::::new(5); + + { + let read_guard = lock.try_read().unwrap(); + assert_eq!(*read_guard, 5); + } + + { + let read_guard = lock.try_read().unwrap(); + assert_eq!(*read_guard, 5); + } +} + +#[futures_test::test] +async fn test_rwlock_try_write() { + let lock = RwLock::::new(5); + + { + let mut write_guard = lock.try_write().unwrap(); + *write_guard = 10; + } + + { + let read_guard = lock.try_read().unwrap(); + assert_eq!(*read_guard, 10); + } +} + +#[futures_test::test] +async fn test_rwlock_fairness() { + let lock = RwLock::::new(5); + + let read1 = lock.read().await; + let read2 = lock.read().await; + + let write_fut = lock.write(); + futures_util::pin_mut!(write_fut); + + assert!(futures_util::poll!(write_fut.as_mut()).is_pending()); + + drop(read1); + drop(read2); + + assert!(futures_util::poll!(write_fut.as_mut()).is_ready()); +} From 6904b0cc6409aead1a2f49f4c821dffd7fd61ce4 Mon Sep 17 00:00:00 2001 From: Alix ANNERAUD Date: Fri, 28 Feb 2025 16:10:15 +0100 Subject: [PATCH 0784/1217] --- embassy-sync/src/raw_rwlock.rs | 86 ++++++++++ embassy-sync/src/rwlock.rs | 295 +++++++++++++++++---------------- 2 files changed, 235 insertions(+), 146 deletions(-) create mode 100644 embassy-sync/src/raw_rwlock.rs diff --git a/embassy-sync/src/raw_rwlock.rs b/embassy-sync/src/raw_rwlock.rs new file mode 100644 index 000000000..de4bd1dc5 --- /dev/null +++ b/embassy-sync/src/raw_rwlock.rs @@ -0,0 +1,86 @@ +use core::sync::atomic::{AtomicUsize, Ordering}; +use core::task::Waker; +use core::cell::UnsafeCell; + +pub trait RawRwLock { + fn lock_read(&self); + fn try_lock_read(&self) -> bool; + fn unlock_read(&self); + fn lock_write(&self); + fn try_lock_write(&self) -> bool; + fn unlock_write(&self); +} + +pub struct RawRwLockImpl { + state: AtomicUsize, + waker: UnsafeCell>, +} + +impl RawRwLockImpl { + pub const fn new() -> Self { + Self { + state: AtomicUsize::new(0), + waker: UnsafeCell::new(None), + } + } +} + +unsafe impl Send for RawRwLockImpl {} +unsafe impl Sync for RawRwLockImpl {} + +impl RawRwLock for RawRwLockImpl { + fn lock_read(&self) { + loop { + let state = self.state.load(Ordering::Acquire); + if state & 1 == 0 { + if self.state.compare_and_swap(state, state + 2, Ordering::AcqRel) == state { + break; + } + } + } + } + + fn try_lock_read(&self) -> bool { + let state = self.state.load(Ordering::Acquire); + if state & 1 == 0 { + if self.state.compare_and_swap(state, state + 2, Ordering::AcqRel) == state { + return true; + } + } + false + } + + fn unlock_read(&self) { + self.state.fetch_sub(2, Ordering::Release); + if self.state.load(Ordering::Acquire) == 0 { + if let Some(waker) = unsafe { &*self.waker.get() } { + waker.wake_by_ref(); + } + } + } + + fn lock_write(&self) { + loop { + let state = self.state.load(Ordering::Acquire); + if state == 0 { + if self.state.compare_and_swap(0, 1, Ordering::AcqRel) == 0 { + break; + } + } + } + } + + fn try_lock_write(&self) -> bool { + if self.state.compare_and_swap(0, 1, Ordering::AcqRel) == 0 { + return true; + } + false + } + + fn unlock_write(&self) { + self.state.store(0, Ordering::Release); + if let Some(waker) = unsafe { &*self.waker.get() } { + waker.wake_by_ref(); + } + } +} diff --git a/embassy-sync/src/rwlock.rs b/embassy-sync/src/rwlock.rs index 15ea8468e..30e1e74ad 100644 --- a/embassy-sync/src/rwlock.rs +++ b/embassy-sync/src/rwlock.rs @@ -1,136 +1,134 @@ -use core::cell::RefCell; -use core::future::{poll_fn, Future}; +use core::cell::UnsafeCell; +use core::future::poll_fn; use core::ops::{Deref, DerefMut}; use core::task::Poll; -use crate::blocking_mutex::raw::RawMutex; use crate::blocking_mutex::Mutex as BlockingMutex; -use crate::waitqueue::MultiWakerRegistration; +use crate::waitqueue::WakerRegistration; +use crate::raw_rwlock::RawRwLock; -/// Error returned by [`RwLock::try_read`] and [`RwLock::try_write`] -#[derive(PartialEq, Eq, Clone, Copy, Debug)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct TryLockError; - -/// Async read-write lock. -/// -/// The lock is generic over a blocking [`RawMutex`](crate::blocking_mutex::raw::RawMutex). -/// The raw mutex is used to guard access to the internal state. It -/// is held for very short periods only, while locking and unlocking. It is *not* held -/// for the entire time the async RwLock is locked. -/// -/// Which implementation you select depends on the context in which you're using the lock. -/// -/// Use [`CriticalSectionRawMutex`](crate::blocking_mutex::raw::CriticalSectionRawMutex) when data can be shared between threads and interrupts. -/// -/// Use [`NoopRawMutex`](crate::blocking_mutex::raw::NoopRawMutex) when data is only shared between tasks running on the same executor. -/// -/// Use [`ThreadModeRawMutex`](crate::blocking_mutex::raw::ThreadModeRawMutex) when data is shared between tasks running on the same executor but you want a singleton. -/// pub struct RwLock where - M: RawMutex, + M: RawRwLock, T: ?Sized, { - state: BlockingMutex>, - inner: RefCell, + state: BlockingMutex, + inner: UnsafeCell, } -struct State { - readers: usize, - writer: bool, - writer_waker: MultiWakerRegistration<1>, - reader_wakers: MultiWakerRegistration<8>, -} - -impl State { - fn new() -> Self { - Self { - readers: 0, - writer: false, - writer_waker: MultiWakerRegistration::new(), - reader_wakers: MultiWakerRegistration::new(), - } - } -} +unsafe impl Send for RwLock {} +unsafe impl Sync for RwLock {} impl RwLock where - M: RawMutex, + M: RawRwLock, { - /// Create a new read-write lock with the given value. pub const fn new(value: T) -> Self { Self { - inner: RefCell::new(value), - state: BlockingMutex::new(RefCell::new(State::new())), + inner: UnsafeCell::new(value), + state: BlockingMutex::new(RwLockState { + locked: LockedState::Unlocked, + writer_pending: 0, + readers_pending: 0, + waker: WakerRegistration::new(), + }), } } } impl RwLock where - M: RawMutex, + M: RawRwLock, T: ?Sized, { - /// Acquire a read lock. - /// - /// This will wait for the lock to be available if it's already locked for writing. pub fn read(&self) -> impl Future> { poll_fn(|cx| { - let mut state = self.state.lock(|s| s.borrow_mut()); - if state.writer { - state.reader_wakers.register(cx.waker()); - Poll::Pending - } else { - state.readers += 1; + let ready = self.state.lock(|s| { + let mut s = s.borrow_mut(); + match s.locked { + LockedState::Unlocked => { + s.locked = LockedState::ReadLocked(1); + true + } + LockedState::ReadLocked(ref mut count) => { + *count += 1; + true + } + LockedState::WriteLocked => { + s.readers_pending += 1; + s.waker.register(cx.waker()); + false + } + } + }); + + if ready { Poll::Ready(RwLockReadGuard { lock: self }) + } else { + Poll::Pending } }) } - /// Acquire a write lock. - /// - /// This will wait for the lock to be available if it's already locked for reading or writing. pub fn write(&self) -> impl Future> { poll_fn(|cx| { - let mut state = self.state.lock(|s| s.borrow_mut()); - if state.writer || state.readers > 0 { - state.writer_waker.register(cx.waker()); - Poll::Pending - } else { - state.writer = true; + let ready = self.state.lock(|s| { + let mut s = s.borrow_mut(); + match s.locked { + LockedState::Unlocked => { + s.locked = LockedState::WriteLocked; + true + } + _ => { + s.writer_pending += 1; + s.waker.register(cx.waker()); + false + } + } + }); + + if ready { Poll::Ready(RwLockWriteGuard { lock: self }) + } else { + Poll::Pending } }) } - /// Attempt to immediately acquire a read lock. - /// - /// If the lock is already locked for writing, this will return an error instead of waiting. pub fn try_read(&self) -> Result, TryLockError> { - let mut state = self.state.lock(|s| s.borrow_mut()); - if state.writer { - Err(TryLockError) - } else { - state.readers += 1; - Ok(RwLockReadGuard { lock: self }) - } + self.state.lock(|s| { + let mut s = s.borrow_mut(); + match s.locked { + LockedState::Unlocked => { + s.locked = LockedState::ReadLocked(1); + Ok(()) + } + LockedState::ReadLocked(ref mut count) => { + *count += 1; + Ok(()) + } + LockedState::WriteLocked => Err(TryLockError), + } + })?; + + Ok(RwLockReadGuard { lock: self }) } - /// Attempt to immediately acquire a write lock. - /// - /// If the lock is already locked for reading or writing, this will return an error instead of waiting. pub fn try_write(&self) -> Result, TryLockError> { - let mut state = self.state.lock(|s| s.borrow_mut()); - if state.writer || state.readers > 0 { - Err(TryLockError) - } else { - state.writer = true; - Ok(RwLockWriteGuard { lock: self }) - } + self.state.lock(|s| { + let mut s = s.borrow_mut(); + match s.locked { + LockedState::Unlocked => { + s.locked = LockedState::WriteLocked; + Ok(()) + } + _ => Err(TryLockError), + } + })?; + + Ok(RwLockWriteGuard { lock: self }) } - /// Consumes this lock, returning the underlying data. pub fn into_inner(self) -> T where T: Sized, @@ -138,19 +136,12 @@ where self.inner.into_inner() } - /// Returns a mutable reference to the underlying data. - /// - /// Since this call borrows the RwLock mutably, no actual locking needs to - /// take place -- the mutable borrow statically guarantees no locks exist. pub fn get_mut(&mut self) -> &mut T { self.inner.get_mut() } } -impl From for RwLock -where - M: RawMutex, -{ +impl From for RwLock { fn from(from: T) -> Self { Self::new(from) } @@ -158,7 +149,7 @@ where impl Default for RwLock where - M: RawMutex, + M: RawRwLock, T: Default, { fn default() -> Self { @@ -166,91 +157,103 @@ where } } -/// Async read lock guard. -/// -/// Owning an instance of this type indicates having -/// successfully locked the RwLock for reading, and grants access to the contents. -/// -/// Dropping it unlocks the RwLock. -#[must_use = "if unused the RwLock will immediately unlock"] pub struct RwLockReadGuard<'a, M, T> where - M: RawMutex, + M: RawRwLock, T: ?Sized, { lock: &'a RwLock, } -impl<'a, M, T> Drop for RwLockReadGuard<'a, M, T> -where - M: RawMutex, - T: ?Sized, -{ - fn drop(&mut self) { - let mut state = self.lock.state.lock(|s| s.borrow_mut()); - state.readers -= 1; - if state.readers == 0 { - state.writer_waker.wake(); - } - } -} - impl<'a, M, T> Deref for RwLockReadGuard<'a, M, T> where - M: RawMutex, + M: RawRwLock, T: ?Sized, { type Target = T; + fn deref(&self) -> &Self::Target { - self.lock.inner.borrow() + unsafe { &*self.lock.inner.get() } + } +} + +impl<'a, M, T> Drop for RwLockReadGuard<'a, M, T> +where + M: RawRwLock, + T: ?Sized, +{ + fn drop(&mut self) { + self.lock.state.lock(|s| { + let mut s = s.borrow_mut(); + match s.locked { + LockedState::ReadLocked(ref mut count) => { + *count -= 1; + if *count == 0 { + s.locked = LockedState::Unlocked; + s.waker.wake(); + } + } + _ => unreachable!(), + } + }); } } -/// Async write lock guard. -/// -/// Owning an instance of this type indicates having -/// successfully locked the RwLock for writing, and grants access to the contents. -/// -/// Dropping it unlocks the RwLock. -#[must_use = "if unused the RwLock will immediately unlock"] pub struct RwLockWriteGuard<'a, M, T> where - M: RawMutex, + M: RawRwLock, T: ?Sized, { lock: &'a RwLock, } -impl<'a, M, T> Drop for RwLockWriteGuard<'a, M, T> -where - M: RawMutex, - T: ?Sized, -{ - fn drop(&mut self) { - let mut state = self.lock.state.lock(|s| s.borrow_mut()); - state.writer = false; - state.reader_wakers.wake(); - state.writer_waker.wake(); - } -} - impl<'a, M, T> Deref for RwLockWriteGuard<'a, M, T> where - M: RawMutex, + M: RawRwLock, T: ?Sized, { type Target = T; + fn deref(&self) -> &Self::Target { - self.lock.inner.borrow() + unsafe { &*self.lock.inner.get() } } } impl<'a, M, T> DerefMut for RwLockWriteGuard<'a, M, T> where - M: RawMutex, + M: RawRwLock, T: ?Sized, { fn deref_mut(&mut self) -> &mut Self::Target { - self.lock.inner.borrow_mut() + unsafe { &mut *self.lock.inner.get() } } } + +impl<'a, M, T> Drop for RwLockWriteGuard<'a, M, T> +where + M: RawRwLock, + T: ?Sized, +{ + fn drop(&mut self) { + self.lock.state.lock(|s| { + let mut s = s.borrow_mut(); + s.locked = LockedState::Unlocked; + s.waker.wake(); + }); + } +} + +struct RwLockState { + locked: LockedState, + writer_pending: usize, + readers_pending: usize, + waker: WakerRegistration, +} + +enum LockedState { + Unlocked, + ReadLocked(usize), + WriteLocked, +} + +pub struct TryLockError; From 114cfdd86b19640ca109488fb960020de673ec57 Mon Sep 17 00:00:00 2001 From: Alix ANNERAUD Date: Fri, 28 Feb 2025 16:22:16 +0100 Subject: [PATCH 0785/1217] Add `RawRwLock` trait and `RawRwLockImpl` struct implementation * Implement `RawRwLock` trait with methods for read and write locking * Implement `RawRwLockImpl` struct with atomic state and waker * Implement `RawRwLockImpl::lock_read`, `RawRwLockImpl::try_lock_read`, and `RawRwLockImpl::unlock_read` methods * Implement `RawRwLockImpl::lock_write`, `RawRwLockImpl::try_lock_write`, and `RawRwLockImpl::unlock_write` methods --- embassy-sync/src/blocking_mutex/raw_rwlock.rs | 86 +++++++++++++++++++ embassy-sync/src/raw_rwlock.rs | 86 ------------------- 2 files changed, 86 insertions(+), 86 deletions(-) create mode 100644 embassy-sync/src/blocking_mutex/raw_rwlock.rs diff --git a/embassy-sync/src/blocking_mutex/raw_rwlock.rs b/embassy-sync/src/blocking_mutex/raw_rwlock.rs new file mode 100644 index 000000000..de4bd1dc5 --- /dev/null +++ b/embassy-sync/src/blocking_mutex/raw_rwlock.rs @@ -0,0 +1,86 @@ +use core::sync::atomic::{AtomicUsize, Ordering}; +use core::task::Waker; +use core::cell::UnsafeCell; + +pub trait RawRwLock { + fn lock_read(&self); + fn try_lock_read(&self) -> bool; + fn unlock_read(&self); + fn lock_write(&self); + fn try_lock_write(&self) -> bool; + fn unlock_write(&self); +} + +pub struct RawRwLockImpl { + state: AtomicUsize, + waker: UnsafeCell>, +} + +impl RawRwLockImpl { + pub const fn new() -> Self { + Self { + state: AtomicUsize::new(0), + waker: UnsafeCell::new(None), + } + } +} + +unsafe impl Send for RawRwLockImpl {} +unsafe impl Sync for RawRwLockImpl {} + +impl RawRwLock for RawRwLockImpl { + fn lock_read(&self) { + loop { + let state = self.state.load(Ordering::Acquire); + if state & 1 == 0 { + if self.state.compare_and_swap(state, state + 2, Ordering::AcqRel) == state { + break; + } + } + } + } + + fn try_lock_read(&self) -> bool { + let state = self.state.load(Ordering::Acquire); + if state & 1 == 0 { + if self.state.compare_and_swap(state, state + 2, Ordering::AcqRel) == state { + return true; + } + } + false + } + + fn unlock_read(&self) { + self.state.fetch_sub(2, Ordering::Release); + if self.state.load(Ordering::Acquire) == 0 { + if let Some(waker) = unsafe { &*self.waker.get() } { + waker.wake_by_ref(); + } + } + } + + fn lock_write(&self) { + loop { + let state = self.state.load(Ordering::Acquire); + if state == 0 { + if self.state.compare_and_swap(0, 1, Ordering::AcqRel) == 0 { + break; + } + } + } + } + + fn try_lock_write(&self) -> bool { + if self.state.compare_and_swap(0, 1, Ordering::AcqRel) == 0 { + return true; + } + false + } + + fn unlock_write(&self) { + self.state.store(0, Ordering::Release); + if let Some(waker) = unsafe { &*self.waker.get() } { + waker.wake_by_ref(); + } + } +} diff --git a/embassy-sync/src/raw_rwlock.rs b/embassy-sync/src/raw_rwlock.rs index de4bd1dc5..e69de29bb 100644 --- a/embassy-sync/src/raw_rwlock.rs +++ b/embassy-sync/src/raw_rwlock.rs @@ -1,86 +0,0 @@ -use core::sync::atomic::{AtomicUsize, Ordering}; -use core::task::Waker; -use core::cell::UnsafeCell; - -pub trait RawRwLock { - fn lock_read(&self); - fn try_lock_read(&self) -> bool; - fn unlock_read(&self); - fn lock_write(&self); - fn try_lock_write(&self) -> bool; - fn unlock_write(&self); -} - -pub struct RawRwLockImpl { - state: AtomicUsize, - waker: UnsafeCell>, -} - -impl RawRwLockImpl { - pub const fn new() -> Self { - Self { - state: AtomicUsize::new(0), - waker: UnsafeCell::new(None), - } - } -} - -unsafe impl Send for RawRwLockImpl {} -unsafe impl Sync for RawRwLockImpl {} - -impl RawRwLock for RawRwLockImpl { - fn lock_read(&self) { - loop { - let state = self.state.load(Ordering::Acquire); - if state & 1 == 0 { - if self.state.compare_and_swap(state, state + 2, Ordering::AcqRel) == state { - break; - } - } - } - } - - fn try_lock_read(&self) -> bool { - let state = self.state.load(Ordering::Acquire); - if state & 1 == 0 { - if self.state.compare_and_swap(state, state + 2, Ordering::AcqRel) == state { - return true; - } - } - false - } - - fn unlock_read(&self) { - self.state.fetch_sub(2, Ordering::Release); - if self.state.load(Ordering::Acquire) == 0 { - if let Some(waker) = unsafe { &*self.waker.get() } { - waker.wake_by_ref(); - } - } - } - - fn lock_write(&self) { - loop { - let state = self.state.load(Ordering::Acquire); - if state == 0 { - if self.state.compare_and_swap(0, 1, Ordering::AcqRel) == 0 { - break; - } - } - } - } - - fn try_lock_write(&self) -> bool { - if self.state.compare_and_swap(0, 1, Ordering::AcqRel) == 0 { - return true; - } - false - } - - fn unlock_write(&self) { - self.state.store(0, Ordering::Release); - if let Some(waker) = unsafe { &*self.waker.get() } { - waker.wake_by_ref(); - } - } -} From a7ecf14259591ff5b324ec1c7d7c521fabebe7d3 Mon Sep 17 00:00:00 2001 From: Alix ANNERAUD Date: Fri, 28 Feb 2025 16:28:10 +0100 Subject: [PATCH 0786/1217] Add blocking read-write lock implementation and remove obsolete tests --- embassy-sync/src/blocking_mutex/raw_rwlock.rs | 86 ------- embassy-sync/src/blocking_rwlock/mod.rs | 221 ++++++++++++++++++ embassy-sync/src/blocking_rwlock/raw.rs | 159 +++++++++++++ embassy-sync/src/lib.rs | 1 + embassy-sync/tests/rwlock.rs | 81 ------- 5 files changed, 381 insertions(+), 167 deletions(-) delete mode 100644 embassy-sync/src/blocking_mutex/raw_rwlock.rs create mode 100644 embassy-sync/src/blocking_rwlock/mod.rs create mode 100644 embassy-sync/src/blocking_rwlock/raw.rs delete mode 100644 embassy-sync/tests/rwlock.rs diff --git a/embassy-sync/src/blocking_mutex/raw_rwlock.rs b/embassy-sync/src/blocking_mutex/raw_rwlock.rs deleted file mode 100644 index de4bd1dc5..000000000 --- a/embassy-sync/src/blocking_mutex/raw_rwlock.rs +++ /dev/null @@ -1,86 +0,0 @@ -use core::sync::atomic::{AtomicUsize, Ordering}; -use core::task::Waker; -use core::cell::UnsafeCell; - -pub trait RawRwLock { - fn lock_read(&self); - fn try_lock_read(&self) -> bool; - fn unlock_read(&self); - fn lock_write(&self); - fn try_lock_write(&self) -> bool; - fn unlock_write(&self); -} - -pub struct RawRwLockImpl { - state: AtomicUsize, - waker: UnsafeCell>, -} - -impl RawRwLockImpl { - pub const fn new() -> Self { - Self { - state: AtomicUsize::new(0), - waker: UnsafeCell::new(None), - } - } -} - -unsafe impl Send for RawRwLockImpl {} -unsafe impl Sync for RawRwLockImpl {} - -impl RawRwLock for RawRwLockImpl { - fn lock_read(&self) { - loop { - let state = self.state.load(Ordering::Acquire); - if state & 1 == 0 { - if self.state.compare_and_swap(state, state + 2, Ordering::AcqRel) == state { - break; - } - } - } - } - - fn try_lock_read(&self) -> bool { - let state = self.state.load(Ordering::Acquire); - if state & 1 == 0 { - if self.state.compare_and_swap(state, state + 2, Ordering::AcqRel) == state { - return true; - } - } - false - } - - fn unlock_read(&self) { - self.state.fetch_sub(2, Ordering::Release); - if self.state.load(Ordering::Acquire) == 0 { - if let Some(waker) = unsafe { &*self.waker.get() } { - waker.wake_by_ref(); - } - } - } - - fn lock_write(&self) { - loop { - let state = self.state.load(Ordering::Acquire); - if state == 0 { - if self.state.compare_and_swap(0, 1, Ordering::AcqRel) == 0 { - break; - } - } - } - } - - fn try_lock_write(&self) -> bool { - if self.state.compare_and_swap(0, 1, Ordering::AcqRel) == 0 { - return true; - } - false - } - - fn unlock_write(&self) { - self.state.store(0, Ordering::Release); - if let Some(waker) = unsafe { &*self.waker.get() } { - waker.wake_by_ref(); - } - } -} diff --git a/embassy-sync/src/blocking_rwlock/mod.rs b/embassy-sync/src/blocking_rwlock/mod.rs new file mode 100644 index 000000000..a304b77d6 --- /dev/null +++ b/embassy-sync/src/blocking_rwlock/mod.rs @@ -0,0 +1,221 @@ +//! Blocking read-write lock. +//! +//! This module provides a blocking read-write lock that can be used to synchronize data. +pub mod raw_rwlock; + +use core::cell::UnsafeCell; + +use self::raw_rwlock::RawRwLock; + +/// Blocking read-write lock (not async) +/// +/// Provides a blocking read-write lock primitive backed by an implementation of [`raw_rwlock::RawRwLock`]. +/// +/// Which implementation you select depends on the context in which you're using the read-write lock, and you can choose which kind +/// of interior mutability fits your use case. +/// +/// Use [`CriticalSectionRwLock`] when data can be shared between threads and interrupts. +/// +/// Use [`NoopRwLock`] when data is only shared between tasks running on the same executor. +/// +/// Use [`ThreadModeRwLock`] when data is shared between tasks running on the same executor but you want a global singleton. +/// +/// In all cases, the blocking read-write lock is intended to be short lived and not held across await points. +/// Use the async [`RwLock`](crate::rwlock::RwLock) if you need a lock that is held across await points. +pub struct RwLock { + // NOTE: `raw` must be FIRST, so when using ThreadModeRwLock the "can't drop in non-thread-mode" gets + // to run BEFORE dropping `data`. + raw: R, + data: UnsafeCell, +} + +unsafe impl Send for RwLock {} +unsafe impl Sync for RwLock {} + +impl RwLock { + /// Creates a new read-write lock in an unlocked state ready for use. + #[inline] + pub const fn new(val: T) -> RwLock { + RwLock { + raw: R::INIT, + data: UnsafeCell::new(val), + } + } + + /// Creates a critical section and grants temporary read access to the protected data. + pub fn read_lock(&self, f: impl FnOnce(&T) -> U) -> U { + self.raw.read_lock(|| { + let ptr = self.data.get() as *const T; + let inner = unsafe { &*ptr }; + f(inner) + }) + } + + /// Creates a critical section and grants temporary write access to the protected data. + pub fn write_lock(&self, f: impl FnOnce(&mut T) -> U) -> U { + self.raw.write_lock(|| { + let ptr = self.data.get() as *mut T; + let inner = unsafe { &mut *ptr }; + f(inner) + }) + } +} + +impl RwLock { + /// Creates a new read-write lock based on a pre-existing raw read-write lock. + /// + /// This allows creating a read-write lock in a constant context on stable Rust. + #[inline] + pub const fn const_new(raw_rwlock: R, val: T) -> RwLock { + RwLock { + raw: raw_rwlock, + data: UnsafeCell::new(val), + } + } + + /// Consumes this read-write lock, returning the underlying data. + #[inline] + pub fn into_inner(self) -> T { + self.data.into_inner() + } + + /// Returns a mutable reference to the underlying data. + /// + /// Since this call borrows the `RwLock` mutably, no actual locking needs to + /// take place---the mutable borrow statically guarantees no locks exist. + #[inline] + pub fn get_mut(&mut self) -> &mut T { + unsafe { &mut *self.data.get() } + } +} + +/// A read-write lock that allows borrowing data across executors and interrupts. +/// +/// # Safety +/// +/// This read-write lock is safe to share between different executors and interrupts. +pub type CriticalSectionRwLock = RwLock; + +/// A read-write lock that allows borrowing data in the context of a single executor. +/// +/// # Safety +/// +/// **This Read-Write Lock is only safe within a single executor.** +pub type NoopRwLock = RwLock; + +impl RwLock { + /// Borrows the data for the duration of the critical section + pub fn borrow<'cs>(&'cs self, _cs: critical_section::CriticalSection<'cs>) -> &'cs T { + let ptr = self.data.get() as *const T; + unsafe { &*ptr } + } +} + +impl RwLock { + /// Borrows the data + #[allow(clippy::should_implement_trait)] + pub fn borrow(&self) -> &T { + let ptr = self.data.get() as *const T; + unsafe { &*ptr } + } +} + +// ThreadModeRwLock does NOT use the generic read-write lock from above because it's special: +// it's Send+Sync even if T: !Send. There's no way to do that without specialization (I think?). +// +// There's still a ThreadModeRawRwLock for use with the generic RwLock (handy with Channel, for example), +// but that will require T: Send even though it shouldn't be needed. + +#[cfg(any(cortex_m, feature = "std"))] +pub use thread_mode_rwlock::*; +#[cfg(any(cortex_m, feature = "std"))] +mod thread_mode_rwlock { + use super::*; + + /// A "read-write lock" that only allows borrowing from thread mode. + /// + /// # Safety + /// + /// **This Read-Write Lock is only safe on single-core systems.** + /// + /// On multi-core systems, a `ThreadModeRwLock` **is not sufficient** to ensure exclusive access. + pub struct ThreadModeRwLock { + inner: UnsafeCell, + } + + // NOTE: ThreadModeRwLock only allows borrowing from one execution context ever: thread mode. + // Therefore it cannot be used to send non-sendable stuff between execution contexts, so it can + // be Send+Sync even if T is not Send (unlike CriticalSectionRwLock) + unsafe impl Sync for ThreadModeRwLock {} + unsafe impl Send for ThreadModeRwLock {} + + impl ThreadModeRwLock { + /// Creates a new read-write lock + pub const fn new(value: T) -> Self { + ThreadModeRwLock { + inner: UnsafeCell::new(value), + } + } + } + + impl ThreadModeRwLock { + /// Lock the `ThreadModeRwLock` for reading, granting access to the data. + /// + /// # Panics + /// + /// This will panic if not currently running in thread mode. + pub fn read_lock(&self, f: impl FnOnce(&T) -> R) -> R { + f(self.borrow()) + } + + /// Lock the `ThreadModeRwLock` for writing, granting access to the data. + /// + /// # Panics + /// + /// This will panic if not currently running in thread mode. + pub fn write_lock(&self, f: impl FnOnce(&mut T) -> R) -> R { + f(self.borrow_mut()) + } + + /// Borrows the data + /// + /// # Panics + /// + /// This will panic if not currently running in thread mode. + pub fn borrow(&self) -> &T { + assert!( + raw_rwlock::in_thread_mode(), + "ThreadModeRwLock can only be borrowed from thread mode." + ); + unsafe { &*self.inner.get() } + } + + /// Mutably borrows the data + /// + /// # Panics + /// + /// This will panic if not currently running in thread mode. + pub fn borrow_mut(&self) -> &mut T { + assert!( + raw_rwlock::in_thread_mode(), + "ThreadModeRwLock can only be borrowed from thread mode." + ); + unsafe { &mut *self.inner.get() } + } + } + + impl Drop for ThreadModeRwLock { + fn drop(&mut self) { + // Only allow dropping from thread mode. Dropping calls drop on the inner `T`, so + // `drop` needs the same guarantees as `lock`. `ThreadModeRwLock` is Send even if + // T isn't, so without this check a user could create a ThreadModeRwLock in thread mode, + // send it to interrupt context and drop it there, which would "send" a T even if T is not Send. + assert!( + raw_rwlock::in_thread_mode(), + "ThreadModeRwLock can only be dropped from thread mode." + ); + + // Drop of the inner `T` happens after this. + } + } +} \ No newline at end of file diff --git a/embassy-sync/src/blocking_rwlock/raw.rs b/embassy-sync/src/blocking_rwlock/raw.rs new file mode 100644 index 000000000..85e8374b5 --- /dev/null +++ b/embassy-sync/src/blocking_rwlock/raw.rs @@ -0,0 +1,159 @@ +//! Read-Write Lock primitives. +//! +//! This module provides a trait for read-write locks that can be used in different contexts. +use core::marker::PhantomData; + +/// Raw read-write lock trait. +/// +/// This read-write lock is "raw", which means it does not actually contain the protected data, it +/// just implements the read-write lock mechanism. For most uses you should use [`super::RwLock`] instead, +/// which is generic over a RawRwLock and contains the protected data. +/// +/// Note that, unlike other read-write locks, implementations only guarantee no +/// concurrent access from other threads: concurrent access from the current +/// thread is allowed. For example, it's possible to lock the same read-write lock multiple times reentrantly. +/// +/// Therefore, locking a `RawRwLock` is only enough to guarantee safe shared (`&`) access +/// to the data, it is not enough to guarantee exclusive (`&mut`) access. +/// +/// # Safety +/// +/// RawRwLock implementations must ensure that, while locked, no other thread can lock +/// the RawRwLock concurrently. +/// +/// Unsafe code is allowed to rely on this fact, so incorrect implementations will cause undefined behavior. +pub unsafe trait RawRwLock { + /// Create a new `RawRwLock` instance. + /// + /// This is a const instead of a method to allow creating instances in const context. + const INIT: Self; + + /// Lock this `RawRwLock` for reading. + fn read_lock(&self, f: impl FnOnce() -> R) -> R; + + /// Lock this `RawRwLock` for writing. + fn write_lock(&self, f: impl FnOnce() -> R) -> R; +} + +/// A read-write lock that allows borrowing data across executors and interrupts. +/// +/// # Safety +/// +/// This read-write lock is safe to share between different executors and interrupts. +pub struct CriticalSectionRawRwLock { + _phantom: PhantomData<()>, +} +unsafe impl Send for CriticalSectionRawRwLock {} +unsafe impl Sync for CriticalSectionRawRwLock {} + +impl CriticalSectionRawRwLock { + /// Create a new `CriticalSectionRawRwLock`. + pub const fn new() -> Self { + Self { _phantom: PhantomData } + } +} + +unsafe impl RawRwLock for CriticalSectionRawRwLock { + const INIT: Self = Self::new(); + + fn read_lock(&self, f: impl FnOnce() -> R) -> R { + critical_section::with(|_| f()) + } + + fn write_lock(&self, f: impl FnOnce() -> R) -> R { + critical_section::with(|_| f()) + } +} + +// ================ + +/// A read-write lock that allows borrowing data in the context of a single executor. +/// +/// # Safety +/// +/// **This Read-Write Lock is only safe within a single executor.** +pub struct NoopRawRwLock { + _phantom: PhantomData<*mut ()>, +} + +unsafe impl Send for NoopRawRwLock {} + +impl NoopRawRwLock { + /// Create a new `NoopRawRwLock`. + pub const fn new() -> Self { + Self { _phantom: PhantomData } + } +} + +unsafe impl RawRwLock for NoopRawRwLock { + const INIT: Self = Self::new(); + fn read_lock(&self, f: impl FnOnce() -> R) -> R { + f() + } + + fn write_lock(&self, f: impl FnOnce() -> R) -> R { + f() + } +} + +// ================ + +#[cfg(any(cortex_m, feature = "std"))] +mod thread_mode { + use super::*; + + /// A "read-write lock" that only allows borrowing from thread mode. + /// + /// # Safety + /// + /// **This Read-Write Lock is only safe on single-core systems.** + /// + /// On multi-core systems, a `ThreadModeRawRwLock` **is not sufficient** to ensure exclusive access. + pub struct ThreadModeRawRwLock { + _phantom: PhantomData<()>, + } + + unsafe impl Send for ThreadModeRawRwLock {} + unsafe impl Sync for ThreadModeRawRwLock {} + + impl ThreadModeRawRwLock { + /// Create a new `ThreadModeRawRwLock`. + pub const fn new() -> Self { + Self { _phantom: PhantomData } + } + } + + unsafe impl RawRwLock for ThreadModeRawRwLock { + const INIT: Self = Self::new(); + fn read_lock(&self, f: impl FnOnce() -> R) -> R { + assert!(in_thread_mode(), "ThreadModeRwLock can only be locked from thread mode."); + + f() + } + + fn write_lock(&self, f: impl FnOnce() -> R) -> R { + assert!(in_thread_mode(), "ThreadModeRwLock can only be locked from thread mode."); + + f() + } + } + + impl Drop for ThreadModeRawRwLock { + fn drop(&mut self) { + assert!( + in_thread_mode(), + "ThreadModeRwLock can only be dropped from thread mode." + ); + } + } + + pub(crate) fn in_thread_mode() -> bool { + #[cfg(feature = "std")] + return Some("main") == std::thread::current().name(); + + #[cfg(not(feature = "std"))] + return unsafe { (0xE000ED04 as *const u32).read_volatile() } & 0x1FF == 0; + } +} +#[cfg(any(cortex_m, feature = "std"))] +pub use thread_mode::*; \ No newline at end of file diff --git a/embassy-sync/src/lib.rs b/embassy-sync/src/lib.rs index 5d91b4d9c..b9ead5f79 100644 --- a/embassy-sync/src/lib.rs +++ b/embassy-sync/src/lib.rs @@ -11,6 +11,7 @@ pub(crate) mod fmt; mod ring_buffer; pub mod blocking_mutex; +pub mod blocking_rwlock; pub mod channel; pub mod lazy_lock; pub mod mutex; diff --git a/embassy-sync/tests/rwlock.rs b/embassy-sync/tests/rwlock.rs deleted file mode 100644 index 301cb0492..000000000 --- a/embassy-sync/tests/rwlock.rs +++ /dev/null @@ -1,81 +0,0 @@ -use embassy_sync::blocking_mutex::raw::NoopRawMutex; -use embassy_sync::rwlock::RwLock; -use futures_executor::block_on; - -#[futures_test::test] -async fn test_rwlock_read() { - let lock = RwLock::::new(5); - - { - let read_guard = lock.read().await; - assert_eq!(*read_guard, 5); - } - - { - let read_guard = lock.read().await; - assert_eq!(*read_guard, 5); - } -} - -#[futures_test::test] -async fn test_rwlock_write() { - let lock = RwLock::::new(5); - - { - let mut write_guard = lock.write().await; - *write_guard = 10; - } - - { - let read_guard = lock.read().await; - assert_eq!(*read_guard, 10); - } -} - -#[futures_test::test] -async fn test_rwlock_try_read() { - let lock = RwLock::::new(5); - - { - let read_guard = lock.try_read().unwrap(); - assert_eq!(*read_guard, 5); - } - - { - let read_guard = lock.try_read().unwrap(); - assert_eq!(*read_guard, 5); - } -} - -#[futures_test::test] -async fn test_rwlock_try_write() { - let lock = RwLock::::new(5); - - { - let mut write_guard = lock.try_write().unwrap(); - *write_guard = 10; - } - - { - let read_guard = lock.try_read().unwrap(); - assert_eq!(*read_guard, 10); - } -} - -#[futures_test::test] -async fn test_rwlock_fairness() { - let lock = RwLock::::new(5); - - let read1 = lock.read().await; - let read2 = lock.read().await; - - let write_fut = lock.write(); - futures_util::pin_mut!(write_fut); - - assert!(futures_util::poll!(write_fut.as_mut()).is_pending()); - - drop(read1); - drop(read2); - - assert!(futures_util::poll!(write_fut.as_mut()).is_ready()); -} From 33cf27adf646bacd758b7289ebbf460b24c26fa5 Mon Sep 17 00:00:00 2001 From: Alix ANNERAUD Date: Fri, 28 Feb 2025 16:32:12 +0100 Subject: [PATCH 0787/1217] Refactor blocking read-write lock module structure and improve assertions in ThreadModeRawRwLock --- embassy-sync/src/blocking_rwlock/mod.rs | 6 +- embassy-sync/src/blocking_rwlock/raw.rs | 12 +- embassy-sync/src/rwlock.rs | 394 ++++++++++++++++-------- 3 files changed, 274 insertions(+), 138 deletions(-) diff --git a/embassy-sync/src/blocking_rwlock/mod.rs b/embassy-sync/src/blocking_rwlock/mod.rs index a304b77d6..a8fb7d6bc 100644 --- a/embassy-sync/src/blocking_rwlock/mod.rs +++ b/embassy-sync/src/blocking_rwlock/mod.rs @@ -1,11 +1,11 @@ //! Blocking read-write lock. //! //! This module provides a blocking read-write lock that can be used to synchronize data. -pub mod raw_rwlock; +pub mod raw; use core::cell::UnsafeCell; -use self::raw_rwlock::RawRwLock; +use self::raw::RawRwLock; /// Blocking read-write lock (not async) /// @@ -218,4 +218,4 @@ mod thread_mode_rwlock { // Drop of the inner `T` happens after this. } } -} \ No newline at end of file +} diff --git a/embassy-sync/src/blocking_rwlock/raw.rs b/embassy-sync/src/blocking_rwlock/raw.rs index 85e8374b5..7725edfa5 100644 --- a/embassy-sync/src/blocking_rwlock/raw.rs +++ b/embassy-sync/src/blocking_rwlock/raw.rs @@ -126,13 +126,19 @@ mod thread_mode { unsafe impl RawRwLock for ThreadModeRawRwLock { const INIT: Self = Self::new(); fn read_lock(&self, f: impl FnOnce() -> R) -> R { - assert!(in_thread_mode(), "ThreadModeRwLock can only be locked from thread mode."); + assert!( + in_thread_mode(), + "ThreadModeRwLock can only be locked from thread mode." + ); f() } fn write_lock(&self, f: impl FnOnce() -> R) -> R { - assert!(in_thread_mode(), "ThreadModeRwLock can only be locked from thread mode."); + assert!( + in_thread_mode(), + "ThreadModeRwLock can only be locked from thread mode." + ); f() } @@ -156,4 +162,4 @@ mod thread_mode { } } #[cfg(any(cortex_m, feature = "std"))] -pub use thread_mode::*; \ No newline at end of file +pub use thread_mode::*; diff --git a/embassy-sync/src/rwlock.rs b/embassy-sync/src/rwlock.rs index 30e1e74ad..365f6fda5 100644 --- a/embassy-sync/src/rwlock.rs +++ b/embassy-sync/src/rwlock.rs @@ -1,134 +1,160 @@ -use core::cell::UnsafeCell; -use core::future::poll_fn; +//! Async read-write lock. +//! +//! This module provides a read-write lock that can be used to synchronize data between asynchronous tasks. +use core::cell::{RefCell, UnsafeCell}; +use core::future::{poll_fn, Future}; use core::ops::{Deref, DerefMut}; use core::task::Poll; +use core::{fmt, mem}; -use crate::blocking_mutex::Mutex as BlockingMutex; +use crate::blocking_mutex::raw::RawRwLock; +use crate::blocking_mutex::RwLock as BlockingRwLock; use crate::waitqueue::WakerRegistration; -use crate::raw_rwlock::RawRwLock; -pub struct RwLock +/// Error returned by [`RwLock::try_read_lock`] and [`RwLock::try_write_lock`] +#[derive(PartialEq, Eq, Clone, Copy, Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct TryLockError; + +struct State { + readers: usize, + writer: bool, + waker: WakerRegistration, +} + +/// Async read-write lock. +/// +/// The read-write lock is generic over a blocking [`RawRwLock`](crate::blocking_mutex::raw_rwlock::RawRwLock). +/// The raw read-write lock is used to guard access to the internal state. It +/// is held for very short periods only, while locking and unlocking. It is *not* held +/// for the entire time the async RwLock is locked. +/// +/// Which implementation you select depends on the context in which you're using the read-write lock. +/// +/// Use [`CriticalSectionRawRwLock`](crate::blocking_mutex::raw_rwlock::CriticalSectionRawRwLock) when data can be shared between threads and interrupts. +/// +/// Use [`NoopRawRwLock`](crate::blocking_mutex::raw_rwlock::NoopRawRwLock) when data is only shared between tasks running on the same executor. +/// +/// Use [`ThreadModeRawRwLock`](crate::blocking_mutex::raw_rwlock::ThreadModeRawRwLock) when data is shared between tasks running on the same executor but you want a singleton. +/// +pub struct RwLock where - M: RawRwLock, + R: RawRwLock, T: ?Sized, { - state: BlockingMutex, + state: BlockingRwLock>, inner: UnsafeCell, } -unsafe impl Send for RwLock {} -unsafe impl Sync for RwLock {} +unsafe impl Send for RwLock {} +unsafe impl Sync for RwLock {} -impl RwLock +/// Async read-write lock. +impl RwLock where - M: RawRwLock, + R: RawRwLock, { + /// Create a new read-write lock with the given value. pub const fn new(value: T) -> Self { Self { inner: UnsafeCell::new(value), - state: BlockingMutex::new(RwLockState { - locked: LockedState::Unlocked, - writer_pending: 0, - readers_pending: 0, + state: BlockingRwLock::new(RefCell::new(State { + readers: 0, + writer: false, waker: WakerRegistration::new(), - }), + })), } } } -impl RwLock +impl RwLock where - M: RawRwLock, + R: RawRwLock, T: ?Sized, { - pub fn read(&self) -> impl Future> { + /// Lock the read-write lock for reading. + /// + /// This will wait for the lock to be available if it's already locked for writing. + pub fn read_lock(&self) -> impl Future> { poll_fn(|cx| { let ready = self.state.lock(|s| { let mut s = s.borrow_mut(); - match s.locked { - LockedState::Unlocked => { - s.locked = LockedState::ReadLocked(1); - true - } - LockedState::ReadLocked(ref mut count) => { - *count += 1; - true - } - LockedState::WriteLocked => { - s.readers_pending += 1; - s.waker.register(cx.waker()); - false - } + if s.writer { + s.waker.register(cx.waker()); + false + } else { + s.readers += 1; + true } }); if ready { - Poll::Ready(RwLockReadGuard { lock: self }) + Poll::Ready(RwLockReadGuard { rwlock: self }) } else { Poll::Pending } }) } - pub fn write(&self) -> impl Future> { + /// Lock the read-write lock for writing. + /// + /// This will wait for the lock to be available if it's already locked for reading or writing. + pub fn write_lock(&self) -> impl Future> { poll_fn(|cx| { let ready = self.state.lock(|s| { let mut s = s.borrow_mut(); - match s.locked { - LockedState::Unlocked => { - s.locked = LockedState::WriteLocked; - true - } - _ => { - s.writer_pending += 1; - s.waker.register(cx.waker()); - false - } + if s.readers > 0 || s.writer { + s.waker.register(cx.waker()); + false + } else { + s.writer = true; + true } }); if ready { - Poll::Ready(RwLockWriteGuard { lock: self }) + Poll::Ready(RwLockWriteGuard { rwlock: self }) } else { Poll::Pending } }) } - pub fn try_read(&self) -> Result, TryLockError> { + /// Attempt to immediately lock the read-write lock for reading. + /// + /// If the lock is already locked for writing, this will return an error instead of waiting. + pub fn try_read_lock(&self) -> Result, TryLockError> { self.state.lock(|s| { let mut s = s.borrow_mut(); - match s.locked { - LockedState::Unlocked => { - s.locked = LockedState::ReadLocked(1); - Ok(()) - } - LockedState::ReadLocked(ref mut count) => { - *count += 1; - Ok(()) - } - LockedState::WriteLocked => Err(TryLockError), + if s.writer { + Err(TryLockError) + } else { + s.readers += 1; + Ok(()) } })?; - Ok(RwLockReadGuard { lock: self }) + Ok(RwLockReadGuard { rwlock: self }) } - pub fn try_write(&self) -> Result, TryLockError> { + /// Attempt to immediately lock the read-write lock for writing. + /// + /// If the lock is already locked for reading or writing, this will return an error instead of waiting. + pub fn try_write_lock(&self) -> Result, TryLockError> { self.state.lock(|s| { let mut s = s.borrow_mut(); - match s.locked { - LockedState::Unlocked => { - s.locked = LockedState::WriteLocked; - Ok(()) - } - _ => Err(TryLockError), + if s.readers > 0 || s.writer { + Err(TryLockError) + } else { + s.writer = true; + Ok(()) } })?; - Ok(RwLockWriteGuard { lock: self }) + Ok(RwLockWriteGuard { rwlock: self }) } + /// Consumes this read-write lock, returning the underlying data. pub fn into_inner(self) -> T where T: Sized, @@ -136,20 +162,24 @@ where self.inner.into_inner() } + /// Returns a mutable reference to the underlying data. + /// + /// Since this call borrows the RwLock mutably, no actual locking needs to + /// take place -- the mutable borrow statically guarantees no locks exist. pub fn get_mut(&mut self) -> &mut T { self.inner.get_mut() } } -impl From for RwLock { +impl From for RwLock { fn from(from: T) -> Self { Self::new(from) } } -impl Default for RwLock +impl Default for RwLock where - M: RawRwLock, + R: RawRwLock, T: Default, { fn default() -> Self { @@ -157,103 +187,203 @@ where } } -pub struct RwLockReadGuard<'a, M, T> +impl fmt::Debug for RwLock where - M: RawRwLock, - T: ?Sized, + R: RawRwLock, + T: ?Sized + fmt::Debug, { - lock: &'a RwLock, -} + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut d = f.debug_struct("RwLock"); + match self.try_write_lock() { + Ok(value) => { + d.field("inner", &&*value); + } + Err(TryLockError) => { + d.field("inner", &format_args!("")); + } + } -impl<'a, M, T> Deref for RwLockReadGuard<'a, M, T> -where - M: RawRwLock, - T: ?Sized, -{ - type Target = T; - - fn deref(&self) -> &Self::Target { - unsafe { &*self.lock.inner.get() } + d.finish_non_exhaustive() } } -impl<'a, M, T> Drop for RwLockReadGuard<'a, M, T> +/// Async read lock guard. +/// +/// Owning an instance of this type indicates having +/// successfully locked the read-write lock for reading, and grants access to the contents. +/// +/// Dropping it unlocks the read-write lock. +#[clippy::has_significant_drop] +#[must_use = "if unused the RwLock will immediately unlock"] +pub struct RwLockReadGuard<'a, R, T> where - M: RawRwLock, + R: RawRwLock, + T: ?Sized, +{ + rwlock: &'a RwLock, +} + +impl<'a, R, T> Drop for RwLockReadGuard<'a, R, T> +where + R: RawRwLock, T: ?Sized, { fn drop(&mut self) { - self.lock.state.lock(|s| { - let mut s = s.borrow_mut(); - match s.locked { - LockedState::ReadLocked(ref mut count) => { - *count -= 1; - if *count == 0 { - s.locked = LockedState::Unlocked; - s.waker.wake(); - } - } - _ => unreachable!(), + self.rwlock.state.lock(|s| { + let mut s = unwrap!(s.try_borrow_mut()); + s.readers -= 1; + if s.readers == 0 { + s.waker.wake(); } - }); + }) } } -pub struct RwLockWriteGuard<'a, M, T> +impl<'a, R, T> Deref for RwLockReadGuard<'a, R, T> where - M: RawRwLock, - T: ?Sized, -{ - lock: &'a RwLock, -} - -impl<'a, M, T> Deref for RwLockWriteGuard<'a, M, T> -where - M: RawRwLock, + R: RawRwLock, T: ?Sized, { type Target = T; - fn deref(&self) -> &Self::Target { - unsafe { &*self.lock.inner.get() } + // Safety: the RwLockReadGuard represents shared access to the contents + // of the read-write lock, so it's OK to get it. + unsafe { &*(self.rwlock.inner.get() as *const T) } } } -impl<'a, M, T> DerefMut for RwLockWriteGuard<'a, M, T> +impl<'a, R, T> fmt::Debug for RwLockReadGuard<'a, R, T> where - M: RawRwLock, + R: RawRwLock, + T: ?Sized + fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&**self, f) + } +} + +impl<'a, R, T> fmt::Display for RwLockReadGuard<'a, R, T> +where + R: RawRwLock, + T: ?Sized + fmt::Display, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(&**self, f) + } +} + +/// Async write lock guard. +/// +/// Owning an instance of this type indicates having +/// successfully locked the read-write lock for writing, and grants access to the contents. +/// +/// Dropping it unlocks the read-write lock. +#[clippy::has_significant_drop] +#[must_use = "if unused the RwLock will immediately unlock"] +pub struct RwLockWriteGuard<'a, R, T> +where + R: RawRwLock, + T: ?Sized, +{ + rwlock: &'a RwLock, +} + +impl<'a, R, T> Drop for RwLockWriteGuard<'a, R, T> +where + R: RawRwLock, + T: ?Sized, +{ + fn drop(&mut self) { + self.rwlock.state.lock(|s| { + let mut s = unwrap!(s.try_borrow_mut()); + s.writer = false; + s.waker.wake(); + }) + } +} + +impl<'a, R, T> Deref for RwLockWriteGuard<'a, R, T> +where + R: RawRwLock, + T: ?Sized, +{ + type Target = T; + fn deref(&self) -> &Self::Target { + // Safety: the RwLockWriteGuard represents exclusive access to the contents + // of the read-write lock, so it's OK to get it. + unsafe { &*(self.rwlock.inner.get() as *mut T) } + } +} + +impl<'a, R, T> DerefMut for RwLockWriteGuard<'a, R, T> +where + R: RawRwLock, T: ?Sized, { fn deref_mut(&mut self) -> &mut Self::Target { - unsafe { &mut *self.lock.inner.get() } + // Safety: the RwLockWriteGuard represents exclusive access to the contents + // of the read-write lock, so it's OK to get it. + unsafe { &mut *(self.rwlock.inner.get()) } } } -impl<'a, M, T> Drop for RwLockWriteGuard<'a, M, T> +impl<'a, R, T> fmt::Debug for RwLockWriteGuard<'a, R, T> where - M: RawRwLock, - T: ?Sized, + R: RawRwLock, + T: ?Sized + fmt::Debug, { - fn drop(&mut self) { - self.lock.state.lock(|s| { - let mut s = s.borrow_mut(); - s.locked = LockedState::Unlocked; - s.waker.wake(); - }); + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&**self, f) } } -struct RwLockState { - locked: LockedState, - writer_pending: usize, - readers_pending: usize, - waker: WakerRegistration, +impl<'a, R, T> fmt::Display for RwLockWriteGuard<'a, R, T> +where + R: RawRwLock, + T: ?Sized + fmt::Display, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(&**self, f) + } } -enum LockedState { - Unlocked, - ReadLocked(usize), - WriteLocked, -} +#[cfg(test)] +mod tests { + use crate::blocking_mutex::raw_rwlock::NoopRawRwLock; + use crate::rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard}; -pub struct TryLockError; + #[futures_test::test] + async fn read_guard_releases_lock_when_dropped() { + let rwlock: RwLock = RwLock::new([0, 1]); + + { + let guard = rwlock.read_lock().await; + assert_eq!(*guard, [0, 1]); + } + + { + let guard = rwlock.read_lock().await; + assert_eq!(*guard, [0, 1]); + } + + assert_eq!(*rwlock.read_lock().await, [0, 1]); + } + + #[futures_test::test] + async fn write_guard_releases_lock_when_dropped() { + let rwlock: RwLock = RwLock::new([0, 1]); + + { + let mut guard = rwlock.write_lock().await; + assert_eq!(*guard, [0, 1]); + guard[1] = 2; + } + + { + let guard = rwlock.read_lock().await; + assert_eq!(*guard, [0, 2]); + } + + assert_eq!(*rwlock.read_lock().await, [0, 2]); + } +} From 55684782258b0241ede93ac6e43a07a3075ad028 Mon Sep 17 00:00:00 2001 From: Alix ANNERAUD Date: Fri, 28 Feb 2025 16:41:41 +0100 Subject: [PATCH 0788/1217] Fix module references in blocking read-write lock implementation --- embassy-sync/src/blocking_rwlock/mod.rs | 16 ++++++++-------- embassy-sync/src/rwlock.rs | 20 ++++++++++---------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/embassy-sync/src/blocking_rwlock/mod.rs b/embassy-sync/src/blocking_rwlock/mod.rs index a8fb7d6bc..88cd2164b 100644 --- a/embassy-sync/src/blocking_rwlock/mod.rs +++ b/embassy-sync/src/blocking_rwlock/mod.rs @@ -9,7 +9,7 @@ use self::raw::RawRwLock; /// Blocking read-write lock (not async) /// -/// Provides a blocking read-write lock primitive backed by an implementation of [`raw_rwlock::RawRwLock`]. +/// Provides a blocking read-write lock primitive backed by an implementation of [`raw::RawRwLock`]. /// /// Which implementation you select depends on the context in which you're using the read-write lock, and you can choose which kind /// of interior mutability fits your use case. @@ -94,16 +94,16 @@ impl RwLock { /// # Safety /// /// This read-write lock is safe to share between different executors and interrupts. -pub type CriticalSectionRwLock = RwLock; +pub type CriticalSectionRwLock = RwLock; /// A read-write lock that allows borrowing data in the context of a single executor. /// /// # Safety /// /// **This Read-Write Lock is only safe within a single executor.** -pub type NoopRwLock = RwLock; +pub type NoopRwLock = RwLock; -impl RwLock { +impl RwLock { /// Borrows the data for the duration of the critical section pub fn borrow<'cs>(&'cs self, _cs: critical_section::CriticalSection<'cs>) -> &'cs T { let ptr = self.data.get() as *const T; @@ -111,7 +111,7 @@ impl RwLock { } } -impl RwLock { +impl RwLock { /// Borrows the data #[allow(clippy::should_implement_trait)] pub fn borrow(&self) -> &T { @@ -184,7 +184,7 @@ mod thread_mode_rwlock { /// This will panic if not currently running in thread mode. pub fn borrow(&self) -> &T { assert!( - raw_rwlock::in_thread_mode(), + raw::in_thread_mode(), "ThreadModeRwLock can only be borrowed from thread mode." ); unsafe { &*self.inner.get() } @@ -197,7 +197,7 @@ mod thread_mode_rwlock { /// This will panic if not currently running in thread mode. pub fn borrow_mut(&self) -> &mut T { assert!( - raw_rwlock::in_thread_mode(), + raw::in_thread_mode(), "ThreadModeRwLock can only be borrowed from thread mode." ); unsafe { &mut *self.inner.get() } @@ -211,7 +211,7 @@ mod thread_mode_rwlock { // T isn't, so without this check a user could create a ThreadModeRwLock in thread mode, // send it to interrupt context and drop it there, which would "send" a T even if T is not Send. assert!( - raw_rwlock::in_thread_mode(), + raw::in_thread_mode(), "ThreadModeRwLock can only be dropped from thread mode." ); diff --git a/embassy-sync/src/rwlock.rs b/embassy-sync/src/rwlock.rs index 365f6fda5..9fa61ee56 100644 --- a/embassy-sync/src/rwlock.rs +++ b/embassy-sync/src/rwlock.rs @@ -2,13 +2,13 @@ //! //! This module provides a read-write lock that can be used to synchronize data between asynchronous tasks. use core::cell::{RefCell, UnsafeCell}; +use core::fmt; use core::future::{poll_fn, Future}; use core::ops::{Deref, DerefMut}; use core::task::Poll; -use core::{fmt, mem}; -use crate::blocking_mutex::raw::RawRwLock; -use crate::blocking_mutex::RwLock as BlockingRwLock; +use crate::blocking_rwlock::raw::RawRwLock; +use crate::blocking_rwlock::RwLock as BlockingRwLock; use crate::waitqueue::WakerRegistration; /// Error returned by [`RwLock::try_read_lock`] and [`RwLock::try_write_lock`] @@ -77,7 +77,7 @@ where /// This will wait for the lock to be available if it's already locked for writing. pub fn read_lock(&self) -> impl Future> { poll_fn(|cx| { - let ready = self.state.lock(|s| { + let ready = self.state.write_lock(|s| { let mut s = s.borrow_mut(); if s.writer { s.waker.register(cx.waker()); @@ -101,7 +101,7 @@ where /// This will wait for the lock to be available if it's already locked for reading or writing. pub fn write_lock(&self) -> impl Future> { poll_fn(|cx| { - let ready = self.state.lock(|s| { + let ready = self.state.write_lock(|s| { let mut s = s.borrow_mut(); if s.readers > 0 || s.writer { s.waker.register(cx.waker()); @@ -124,7 +124,7 @@ where /// /// If the lock is already locked for writing, this will return an error instead of waiting. pub fn try_read_lock(&self) -> Result, TryLockError> { - self.state.lock(|s| { + self.state.read_lock(|s| { let mut s = s.borrow_mut(); if s.writer { Err(TryLockError) @@ -141,7 +141,7 @@ where /// /// If the lock is already locked for reading or writing, this will return an error instead of waiting. pub fn try_write_lock(&self) -> Result, TryLockError> { - self.state.lock(|s| { + self.state.write_lock(|s| { let mut s = s.borrow_mut(); if s.readers > 0 || s.writer { Err(TryLockError) @@ -229,7 +229,7 @@ where T: ?Sized, { fn drop(&mut self) { - self.rwlock.state.lock(|s| { + self.rwlock.state.write_lock(|s| { let mut s = unwrap!(s.try_borrow_mut()); s.readers -= 1; if s.readers == 0 { @@ -294,7 +294,7 @@ where T: ?Sized, { fn drop(&mut self) { - self.rwlock.state.lock(|s| { + self.rwlock.state.write_lock(|s| { let mut s = unwrap!(s.try_borrow_mut()); s.writer = false; s.waker.wake(); @@ -349,7 +349,7 @@ where #[cfg(test)] mod tests { - use crate::blocking_mutex::raw_rwlock::NoopRawRwLock; + use crate::blocking_rwlock::raw::NoopRawRwLock; use crate::rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard}; #[futures_test::test] From 9cbdc9f11d8e0b857ed9bf483120da03ed3a878c Mon Sep 17 00:00:00 2001 From: Alix ANNERAUD Date: Fri, 28 Feb 2025 23:26:59 +0100 Subject: [PATCH 0789/1217] Implement read-write lock methods in CriticalSectionRawRwLock and update tests --- embassy-sync/src/blocking_rwlock/raw.rs | 57 ++++++++++++++++++++++--- embassy-sync/src/rwlock.rs | 2 +- 2 files changed, 52 insertions(+), 7 deletions(-) diff --git a/embassy-sync/src/blocking_rwlock/raw.rs b/embassy-sync/src/blocking_rwlock/raw.rs index 7725edfa5..dc25e6305 100644 --- a/embassy-sync/src/blocking_rwlock/raw.rs +++ b/embassy-sync/src/blocking_rwlock/raw.rs @@ -1,7 +1,7 @@ //! Read-Write Lock primitives. //! //! This module provides a trait for read-write locks that can be used in different contexts. -use core::marker::PhantomData; +use core::{cell::RefCell, marker::PhantomData}; /// Raw read-write lock trait. /// @@ -41,15 +41,50 @@ pub unsafe trait RawRwLock { /// /// This read-write lock is safe to share between different executors and interrupts. pub struct CriticalSectionRawRwLock { - _phantom: PhantomData<()>, + state: RefCell, } + unsafe impl Send for CriticalSectionRawRwLock {} unsafe impl Sync for CriticalSectionRawRwLock {} impl CriticalSectionRawRwLock { - /// Create a new `CriticalSectionRawRwLock`. + /// Creates a new [`CriticalSectionRawRwLock`]. pub const fn new() -> Self { - Self { _phantom: PhantomData } + Self { state: RefCell::new(0) } + } + + fn lock_read(&self) { + critical_section::with(|_| { + let mut state = self.state.borrow_mut(); + + while *state & WRITER != 0 { + // Spin until the writer releases the lock + } + *state += 1; + }); + } + + fn unlock_read(&self) { + critical_section::with(|_| { + *self.state.borrow_mut() -= 1; + }); + } + + fn lock_write(&self) { + critical_section::with(|_| { + let mut state = self.state.borrow_mut(); + + while *state != 0 { + // Spin until all readers and writers release the lock + } + *state = WRITER; + }); + } + + fn unlock_write(&self) { + critical_section::with(|_| { + *self.state.borrow_mut() = 0; + }); } } @@ -57,14 +92,24 @@ unsafe impl RawRwLock for CriticalSectionRawRwLock { const INIT: Self = Self::new(); fn read_lock(&self, f: impl FnOnce() -> R) -> R { - critical_section::with(|_| f()) + self.lock_read(); + let result = f(); + self.unlock_read(); + result } fn write_lock(&self, f: impl FnOnce() -> R) -> R { - critical_section::with(|_| f()) + self.lock_write(); + let result = f(); + self.unlock_write(); + result } } +const WRITER: isize = -1; + +// The rest of the file remains unchanged + // ================ /// A read-write lock that allows borrowing data in the context of a single executor. diff --git a/embassy-sync/src/rwlock.rs b/embassy-sync/src/rwlock.rs index 9fa61ee56..0ad5d5864 100644 --- a/embassy-sync/src/rwlock.rs +++ b/embassy-sync/src/rwlock.rs @@ -350,7 +350,7 @@ where #[cfg(test)] mod tests { use crate::blocking_rwlock::raw::NoopRawRwLock; - use crate::rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard}; + use crate::rwlock::RwLock; #[futures_test::test] async fn read_guard_releases_lock_when_dropped() { From f2afcecfa8cb07df8903412e5eed602c4447e4a8 Mon Sep 17 00:00:00 2001 From: Alix ANNERAUD Date: Fri, 28 Feb 2025 23:29:57 +0100 Subject: [PATCH 0790/1217] Remove obsolete `raw_rwlock.rs` file --- embassy-sync/src/raw_rwlock.rs | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 embassy-sync/src/raw_rwlock.rs diff --git a/embassy-sync/src/raw_rwlock.rs b/embassy-sync/src/raw_rwlock.rs deleted file mode 100644 index e69de29bb..000000000 From 10fd6d13213b88c50cab77cbbbb1d81bdaa5b391 Mon Sep 17 00:00:00 2001 From: Alix ANNERAUD Date: Fri, 28 Feb 2025 23:30:01 +0100 Subject: [PATCH 0791/1217] Refactor imports in raw read-write lock module for clarity --- embassy-sync/src/blocking_rwlock/raw.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/embassy-sync/src/blocking_rwlock/raw.rs b/embassy-sync/src/blocking_rwlock/raw.rs index dc25e6305..91fa773c4 100644 --- a/embassy-sync/src/blocking_rwlock/raw.rs +++ b/embassy-sync/src/blocking_rwlock/raw.rs @@ -1,7 +1,8 @@ //! Read-Write Lock primitives. //! //! This module provides a trait for read-write locks that can be used in different contexts. -use core::{cell::RefCell, marker::PhantomData}; +use core::cell::RefCell; +use core::marker::PhantomData; /// Raw read-write lock trait. /// From 82c0ab01f19bebc82f2edbf60b8edac7b17050d6 Mon Sep 17 00:00:00 2001 From: Alix ANNERAUD Date: Fri, 28 Feb 2025 23:32:58 +0100 Subject: [PATCH 0792/1217] Remove unnecessary comment in CriticalSectionRawRwLock implementation --- embassy-sync/src/blocking_rwlock/raw.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/embassy-sync/src/blocking_rwlock/raw.rs b/embassy-sync/src/blocking_rwlock/raw.rs index 91fa773c4..2fb9ce9d1 100644 --- a/embassy-sync/src/blocking_rwlock/raw.rs +++ b/embassy-sync/src/blocking_rwlock/raw.rs @@ -109,8 +109,6 @@ unsafe impl RawRwLock for CriticalSectionRawRwLock { const WRITER: isize = -1; -// The rest of the file remains unchanged - // ================ /// A read-write lock that allows borrowing data in the context of a single executor. From 24941212e8130cddef974aab865bce4c7e294c33 Mon Sep 17 00:00:00 2001 From: eden barby <> Date: Sat, 1 Mar 2025 17:23:04 +1000 Subject: [PATCH 0793/1217] Added access to the byte swap flag for RP2*** chips for the PIO state machine DMA calls. --- cyw43-pio/src/lib.rs | 13 ++++++++----- embassy-rp/src/pio/mod.rs | 10 +++++++++- embassy-rp/src/pio_programs/hd44780.rs | 4 ++-- embassy-rp/src/pio_programs/i2s.rs | 2 +- embassy-rp/src/pio_programs/ws2812.rs | 2 +- examples/rp/src/bin/pio_dma.rs | 4 ++-- examples/rp235x/src/bin/pio_dma.rs | 4 ++-- 7 files changed, 25 insertions(+), 14 deletions(-) diff --git a/cyw43-pio/src/lib.rs b/cyw43-pio/src/lib.rs index d0d504395..c1b301547 100644 --- a/cyw43-pio/src/lib.rs +++ b/cyw43-pio/src/lib.rs @@ -169,12 +169,12 @@ where self.sm.set_enable(true); - self.sm.tx().dma_push(self.dma.reborrow(), write).await; + self.sm.tx().dma_push(self.dma.reborrow(), write, false).await; let mut status = 0; self.sm .rx() - .dma_pull(self.dma.reborrow(), slice::from_mut(&mut status)) + .dma_pull(self.dma.reborrow(), slice::from_mut(&mut status), false) .await; status } @@ -201,13 +201,16 @@ where // self.cs.set_low(); self.sm.set_enable(true); - self.sm.tx().dma_push(self.dma.reborrow(), slice::from_ref(&cmd)).await; - self.sm.rx().dma_pull(self.dma.reborrow(), read).await; + self.sm + .tx() + .dma_push(self.dma.reborrow(), slice::from_ref(&cmd), false) + .await; + self.sm.rx().dma_pull(self.dma.reborrow(), read, false).await; let mut status = 0; self.sm .rx() - .dma_pull(self.dma.reborrow(), slice::from_mut(&mut status)) + .dma_pull(self.dma.reborrow(), slice::from_mut(&mut status), false) .await; #[cfg(feature = "defmt")] diff --git a/embassy-rp/src/pio/mod.rs b/embassy-rp/src/pio/mod.rs index 880d6effd..fd09d4bba 100644 --- a/embassy-rp/src/pio/mod.rs +++ b/embassy-rp/src/pio/mod.rs @@ -362,6 +362,7 @@ impl<'d, PIO: Instance, const SM: usize> StateMachineRx<'d, PIO, SM> { &'a mut self, ch: PeripheralRef<'a, C>, data: &'a mut [W], + bswap: bool, ) -> Transfer<'a, C> { let pio_no = PIO::PIO_NO; let p = ch.regs(); @@ -379,6 +380,7 @@ impl<'d, PIO: Instance, const SM: usize> StateMachineRx<'d, PIO, SM> { w.set_chain_to(ch.number()); w.set_incr_read(false); w.set_incr_write(true); + w.set_bswap(bswap); w.set_en(true); }); compiler_fence(Ordering::SeqCst); @@ -447,7 +449,12 @@ impl<'d, PIO: Instance, const SM: usize> StateMachineTx<'d, PIO, SM> { } /// Prepare a DMA transfer to TX FIFO. - pub fn dma_push<'a, C: Channel, W: Word>(&'a mut self, ch: PeripheralRef<'a, C>, data: &'a [W]) -> Transfer<'a, C> { + pub fn dma_push<'a, C: Channel, W: Word>( + &'a mut self, + ch: PeripheralRef<'a, C>, + data: &'a [W], + bswap: bool, + ) -> Transfer<'a, C> { let pio_no = PIO::PIO_NO; let p = ch.regs(); p.read_addr().write_value(data.as_ptr() as u32); @@ -464,6 +471,7 @@ impl<'d, PIO: Instance, const SM: usize> StateMachineTx<'d, PIO, SM> { w.set_chain_to(ch.number()); w.set_incr_read(true); w.set_incr_write(false); + w.set_bswap(bswap); w.set_en(true); }); compiler_fence(Ordering::SeqCst); diff --git a/embassy-rp/src/pio_programs/hd44780.rs b/embassy-rp/src/pio_programs/hd44780.rs index 70129318b..6997b91f3 100644 --- a/embassy-rp/src/pio_programs/hd44780.rs +++ b/embassy-rp/src/pio_programs/hd44780.rs @@ -173,7 +173,7 @@ impl<'l, P: Instance, const S: usize> PioHD44780<'l, P, S> { sm.set_enable(true); // display on and cursor on and blinking, reset display - sm.tx().dma_push(dma.reborrow(), &[0x81u8, 0x0f, 1]).await; + sm.tx().dma_push(dma.reborrow(), &[0x81u8, 0x0f, 1], false).await; Self { dma: dma.map_into(), @@ -198,6 +198,6 @@ impl<'l, P: Instance, const S: usize> PioHD44780<'l, P, S> { // set cursor to 1:15 self.buf[38..].copy_from_slice(&[0x80, 0xcf]); - self.sm.tx().dma_push(self.dma.reborrow(), &self.buf).await; + self.sm.tx().dma_push(self.dma.reborrow(), &self.buf, false).await; } } diff --git a/embassy-rp/src/pio_programs/i2s.rs b/embassy-rp/src/pio_programs/i2s.rs index a7b4f46a6..17e321405 100644 --- a/embassy-rp/src/pio_programs/i2s.rs +++ b/embassy-rp/src/pio_programs/i2s.rs @@ -90,6 +90,6 @@ impl<'a, P: Instance, const S: usize> PioI2sOut<'a, P, S> { /// Return an in-prograss dma transfer future. Awaiting it will guarentee a complete transfer. pub fn write<'b>(&'b mut self, buff: &'b [u32]) -> Transfer<'b, AnyChannel> { - self.sm.tx().dma_push(self.dma.reborrow(), buff) + self.sm.tx().dma_push(self.dma.reborrow(), buff, false) } } diff --git a/embassy-rp/src/pio_programs/ws2812.rs b/embassy-rp/src/pio_programs/ws2812.rs index 875f0209f..2462a64e6 100644 --- a/embassy-rp/src/pio_programs/ws2812.rs +++ b/embassy-rp/src/pio_programs/ws2812.rs @@ -111,7 +111,7 @@ impl<'d, P: Instance, const S: usize, const N: usize> PioWs2812<'d, P, S, N> { } // DMA transfer - self.sm.tx().dma_push(self.dma.reborrow(), &words).await; + self.sm.tx().dma_push(self.dma.reborrow(), &words, false).await; Timer::after_micros(55).await; } diff --git a/examples/rp/src/bin/pio_dma.rs b/examples/rp/src/bin/pio_dma.rs index d00ed2142..da6e47a1b 100644 --- a/examples/rp/src/bin/pio_dma.rs +++ b/examples/rp/src/bin/pio_dma.rs @@ -72,8 +72,8 @@ async fn main(_spawner: Spawner) { loop { let (rx, tx) = sm.rx_tx(); join( - tx.dma_push(dma_out_ref.reborrow(), &dout), - rx.dma_pull(dma_in_ref.reborrow(), &mut din), + tx.dma_push(dma_out_ref.reborrow(), &dout, false), + rx.dma_pull(dma_in_ref.reborrow(), &mut din, false), ) .await; for i in 0..din.len() { diff --git a/examples/rp235x/src/bin/pio_dma.rs b/examples/rp235x/src/bin/pio_dma.rs index d00ed2142..da6e47a1b 100644 --- a/examples/rp235x/src/bin/pio_dma.rs +++ b/examples/rp235x/src/bin/pio_dma.rs @@ -72,8 +72,8 @@ async fn main(_spawner: Spawner) { loop { let (rx, tx) = sm.rx_tx(); join( - tx.dma_push(dma_out_ref.reborrow(), &dout), - rx.dma_pull(dma_in_ref.reborrow(), &mut din), + tx.dma_push(dma_out_ref.reborrow(), &dout, false), + rx.dma_pull(dma_in_ref.reborrow(), &mut din, false), ) .await; for i in 0..din.len() { From 26c689db3e62d6c72063ee34e6fc3b7f7f6d310f Mon Sep 17 00:00:00 2001 From: Matthew Tran <0e4ef622@gmail.com> Date: Sat, 1 Mar 2025 17:32:55 -0600 Subject: [PATCH 0794/1217] nrf5340: add regh_voltage config --- embassy-nrf/src/lib.rs | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index 23888b390..dad975470 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs @@ -347,12 +347,33 @@ pub mod config { pub struct DcdcConfig { /// Config for the high voltage stage, if disabled LDO will be used. pub regh: bool, + /// Configure the voltage of the high voltage stage. It is stored in non-volatile memory (UICR.VREGHVOUT register); pass None to not touch it. + #[cfg(feature = "nrf5340-app-s")] + pub regh_voltage: Option, /// Config for the main rail, if disabled LDO will be used. pub regmain: bool, /// Config for the radio rail, if disabled LDO will be used. pub regradio: bool, } + /// Output voltage setting for VREGH regulator stage. + #[cfg(feature = "nrf5340-app-s")] + pub enum ReghVoltage { + /// 1.8 V + _1V8 = 0, + /// 2.1 V + _2V1 = 1, + /// 2.4 V + _2V4 = 2, + /// 2.7 V + _2V7 = 3, + /// 3.0 V + _3V0 = 4, + /// 3.3 V + _3v3 = 5, + //ERASED = 7, means 1.8V + } + /// Settings for enabling the built in DCDC converter. #[cfg(feature = "_nrf91")] pub struct DcdcConfig { @@ -399,6 +420,8 @@ pub mod config { #[cfg(feature = "_nrf5340-app")] dcdc: DcdcConfig { regh: false, + #[cfg(feature = "nrf5340-app-s")] + regh_voltage: None, regmain: false, regradio: false, }, @@ -431,6 +454,7 @@ mod consts { #[allow(unused)] mod consts { pub const UICR_APPROTECT: *mut u32 = 0x00FF8000 as *mut u32; + pub const UICR_VREGHVOUT: *mut u32 = 0x00FF8010 as *mut u32; pub const UICR_SECUREAPPROTECT: *mut u32 = 0x00FF801C as *mut u32; pub const UICR_NFCPINS: *mut u32 = 0x00FF8028 as *mut u32; pub const APPROTECT_ENABLED: u32 = 0x0000_0000; @@ -683,6 +707,21 @@ pub fn init(config: config::Config) -> Peripherals { } } + #[cfg(feature = "nrf5340-app-s")] + unsafe { + if let Some(value) = config.dcdc.regh_voltage { + let value = value as u32; + let res = uicr_write_masked(consts::UICR_VREGHVOUT, value, 0b00000000_00000000_00000000_00000111); + needs_reset |= res == WriteResult::Written; + if res == WriteResult::Failed { + warn!( + "Failed to set regulator voltage, as UICR is already programmed to some other setting, and can't be changed without erasing it.\n\ + To fix this, erase UICR manually, for example using `probe-rs erase` or `nrfjprog --eraseuicr`." + ); + } + } + } + if needs_reset { cortex_m::peripheral::SCB::sys_reset(); } From 4f6762ead98047d4fdaf804f1e5a2a1b513fe281 Mon Sep 17 00:00:00 2001 From: 9names <60134748+9names@users.noreply.github.com> Date: Sun, 2 Mar 2025 15:30:54 +1100 Subject: [PATCH 0795/1217] rp: Add unreleased changes to changelog --- embassy-rp/CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/embassy-rp/CHANGELOG.md b/embassy-rp/CHANGELOG.md index df591fdf8..3d8a659f9 100644 --- a/embassy-rp/CHANGELOG.md +++ b/embassy-rp/CHANGELOG.md @@ -7,6 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +- Add PIO functions. ([#3857](https://github.com/embassy-rs/embassy/pull/3857)) + The functions added in this change are `get_addr` `get_tx_threshold`, `set_tx_threshold`, `get_rx_threshold`, `set_rx_threshold`, `set_thresholds`. +- Expose the watchdog reset reason. ([#3877](https://github.com/embassy-rs/embassy/pull/3877)) +- Update pio-rs, reexport, move instr methods to SM. ([#3865](https://github.com/embassy-rs/embassy/pull/3865)) +- rp235x: add ImageDef features. ([#3890](https://github.com/embassy-rs/embassy/pull/3890)) +- doc: Fix "the the" ([#3903](https://github.com/embassy-rs/embassy/pull/3903)) + ## 0.3.1 - 2025-02-06 Small release fixing a few gnarly bugs, upgrading is strongly recommended. From ec30e3ef91f0dfa9983990c710ad3a4574847634 Mon Sep 17 00:00:00 2001 From: Matthew Tran <0e4ef622@gmail.com> Date: Sat, 1 Mar 2025 23:01:06 -0600 Subject: [PATCH 0796/1217] nrf5340: add internal capacitor config --- embassy-nrf/src/lib.rs | 156 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 155 insertions(+), 1 deletion(-) diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index 23888b390..f2cf0d77e 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs @@ -360,6 +360,133 @@ pub mod config { pub regmain: bool, } + /// Settings for the internal capacitors. + #[cfg(feature = "nrf5340-app-s")] + pub struct InternalCapacitors { + /// Config for the internal capacitors on pins XC1 and XC2. + pub hfxo: Option, + /// Config for the internal capacitors between pins XL1 and XL2. + pub lfxo: Option, + } + + /// Internal capacitance value for the HFXO. + #[cfg(feature = "nrf5340-app-s")] + #[derive(Copy, Clone)] + pub enum HfxoCapacitance { + /// 7.0 pF + _7_0pF, + /// 7.5 pF + _7_5pF, + /// 8.0 pF + _8_0pF, + /// 8.5 pF + _8_5pF, + /// 9.0 pF + _9_0pF, + /// 9.5 pF + _9_5pF, + /// 10.0 pF + _10_0pF, + /// 10.5 pF + _10_5pF, + /// 11.0 pF + _11_0pF, + /// 11.5 pF + _11_5pF, + /// 12.0 pF + _12_0pF, + /// 12.5 pF + _12_5pF, + /// 13.0 pF + _13_0pF, + /// 13.5 pF + _13_5pF, + /// 14.0 pF + _14_0pF, + /// 14.5 pF + _14_5pF, + /// 15.0 pF + _15_0pF, + /// 15.5 pF + _15_5pF, + /// 16.0 pF + _16_0pF, + /// 16.5 pF + _16_5pF, + /// 17.0 pF + _17_0pF, + /// 17.5 pF + _17_5pF, + /// 18.0 pF + _18_0pF, + /// 18.5 pF + _18_5pF, + /// 19.0 pF + _19_0pF, + /// 19.5 pF + _19_5pF, + /// 20.0 pF + _20_0pF, + } + + #[cfg(feature = "nrf5340-app-s")] + impl HfxoCapacitance { + /// The capacitance value times two. + pub(crate) const fn value2(self) -> i32 { + match self { + HfxoCapacitance::_7_0pF => 14, + HfxoCapacitance::_7_5pF => 15, + HfxoCapacitance::_8_0pF => 16, + HfxoCapacitance::_8_5pF => 17, + HfxoCapacitance::_9_0pF => 18, + HfxoCapacitance::_9_5pF => 19, + HfxoCapacitance::_10_0pF => 20, + HfxoCapacitance::_10_5pF => 21, + HfxoCapacitance::_11_0pF => 22, + HfxoCapacitance::_11_5pF => 23, + HfxoCapacitance::_12_0pF => 24, + HfxoCapacitance::_12_5pF => 25, + HfxoCapacitance::_13_0pF => 26, + HfxoCapacitance::_13_5pF => 27, + HfxoCapacitance::_14_0pF => 28, + HfxoCapacitance::_14_5pF => 29, + HfxoCapacitance::_15_0pF => 30, + HfxoCapacitance::_15_5pF => 31, + HfxoCapacitance::_16_0pF => 32, + HfxoCapacitance::_16_5pF => 33, + HfxoCapacitance::_17_0pF => 34, + HfxoCapacitance::_17_5pF => 35, + HfxoCapacitance::_18_0pF => 36, + HfxoCapacitance::_18_5pF => 37, + HfxoCapacitance::_19_0pF => 38, + HfxoCapacitance::_19_5pF => 39, + HfxoCapacitance::_20_0pF => 40, + } + } + } + + /// Internal capacitance value for the LFXO. + #[cfg(feature = "nrf5340-app-s")] + pub enum LfxoCapacitance { + /// 6 pF + _6pF = 1, + /// 7 pF + _7pF = 2, + /// 9 pF + _9pF = 3, + } + + #[cfg(feature = "nrf5340-app-s")] + impl From for super::pac::oscillators::vals::Intcap { + fn from(t: LfxoCapacitance) -> Self { + match t { + LfxoCapacitance::_6pF => Self::C6PF, + LfxoCapacitance::_7pF => Self::C7PF, + LfxoCapacitance::_9pF => Self::C9PF, + } + } + } + /// Configuration for peripherals. Default configuration should work on any nRF chip. #[non_exhaustive] pub struct Config { @@ -367,6 +494,10 @@ pub mod config { pub hfclk_source: HfclkSource, /// Low frequency clock source. pub lfclk_source: LfclkSource, + #[cfg(feature = "nrf5340-app-s")] + /// Internal capacitor configuration, for use with the `ExternalXtal` clock source. See + /// nrf5340-PS §4.12. + pub internal_capacitors: InternalCapacitors, #[cfg(not(any(feature = "_nrf5340-net", feature = "_nrf54l")))] /// DCDC configuration. pub dcdc: DcdcConfig, @@ -388,6 +519,8 @@ pub mod config { // xtals if they know they have them. hfclk_source: HfclkSource::Internal, lfclk_source: LfclkSource::InternalRC, + #[cfg(feature = "nrf5340-app-s")] + internal_capacitors: InternalCapacitors { hfxo: None, lfxo: None }, #[cfg(not(any(feature = "_nrf5340", feature = "_nrf91", feature = "_nrf54l")))] dcdc: DcdcConfig { #[cfg(feature = "nrf52840")] @@ -687,6 +820,27 @@ pub fn init(config: config::Config) -> Peripherals { cortex_m::peripheral::SCB::sys_reset(); } + // Configure internal capacitors + #[cfg(feature = "nrf5340-app-s")] + { + if let Some(cap) = config.internal_capacitors.hfxo { + let mut slope = pac::FICR.xosc32mtrim().read().slope() as i32; + let offset = pac::FICR.xosc32mtrim().read().offset() as i32; + // slope is a signed 5-bit integer + if slope >= 16 { + slope -= 32; + } + let capvalue = (((slope + 56) * (cap.value2() - 14)) + ((offset - 8) << 4) + 32) >> 6; + pac::OSCILLATORS.xosc32mcaps().write(|w| { + w.set_capvalue(capvalue as u8); + w.set_enable(true); + }); + } + if let Some(cap) = config.internal_capacitors.lfxo { + pac::OSCILLATORS.xosc32ki().intcap().write(|w| w.set_intcap(cap.into())); + } + } + let r = pac::CLOCK; // Start HFCLK. @@ -753,7 +907,7 @@ pub fn init(config: config::Config) -> Peripherals { config::LfclkSource::ExternalLowSwing => lfxo = true, #[cfg(not(feature = "lfxo-pins-as-gpio"))] config::LfclkSource::ExternalFullSwing => { - #[cfg(all(feature = "_nrf5340-app"))] + #[cfg(feature = "_nrf5340-app")] pac::OSCILLATORS.xosc32ki().bypass().write(|w| w.set_bypass(true)); lfxo = true; } From 8b3460fd4ef0157b1111bca115667966d602ca40 Mon Sep 17 00:00:00 2001 From: Alex Charlton Date: Mon, 3 Mar 2025 14:09:14 -0800 Subject: [PATCH 0797/1217] Update README.md to include a reference to mpfs-hal --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 374133c4b..ee5c42245 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,7 @@ Rust's async/await allows - esp-rs, for the Espressif Systems ESP32 series of chips. - Embassy HAL support for Espressif chips, as well as Async WiFi, Bluetooth and ESP-NOW, is being developed in the [esp-rs/esp-hal](https://github.com/esp-rs/esp-hal) repository. - ch32-hal, for the WCH 32-bit RISC-V(CH32V) series of chips. + - mpfs-hal, for the Microchip PolarFire SoC. - **Time that Just Works** - No more messing with hardware timers. embassy_time provides Instant, Duration and Timer types that are globally available and never overflow. From f22649e0082a9e9886d7fc2f1f8986682b4cc921 Mon Sep 17 00:00:00 2001 From: Matt Allen Date: Wed, 5 Mar 2025 22:10:00 -0500 Subject: [PATCH 0798/1217] Added function to channel_impl to allow full configuration of the pin --- embassy-stm32/src/lptim/pwm.rs | 29 ++++++++++++++++++++++++++- embassy-stm32/src/timer/simple_pwm.rs | 29 ++++++++++++++++++++++++++- 2 files changed, 56 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/lptim/pwm.rs b/embassy-stm32/src/lptim/pwm.rs index 1f43eb6ee..9f3803cd6 100644 --- a/embassy-stm32/src/lptim/pwm.rs +++ b/embassy-stm32/src/lptim/pwm.rs @@ -10,7 +10,7 @@ use super::OutputPin; #[cfg(any(lptim_v2a, lptim_v2b))] use super::{channel::Channel, timer::ChannelDirection, Channel1Pin, Channel2Pin}; use super::{BasicInstance, Instance}; -use crate::gpio::{AfType, AnyPin, OutputType, Speed}; +use crate::gpio::{AfType, AnyPin, OutputType, Pull, Speed}; use crate::time::Hertz; use crate::Peripheral; @@ -29,6 +29,15 @@ pub struct PwmPin<'d, T, C> { phantom: PhantomData<(T, C)>, } +/// PWM pin config +/// +/// This configures the pwm pin settings +pub struct PwmPinConfig { + pub output_type: OutputType, + pub speed: Speed, + pub pull: Pull, +} + macro_rules! channel_impl { ($new_chx:ident, $channel:ident, $pin_trait:ident) => { impl<'d, T: BasicInstance> PwmPin<'d, T, $channel> { @@ -47,6 +56,24 @@ macro_rules! channel_impl { phantom: PhantomData, } } + #[doc = concat!("Create a new ", stringify!($channel), "_with_config PWM pin instance.")] + pub fn $new_chx_with_config( + pin: impl Peripheral

> + 'd, + pin_config: PwmPinConfig, + ) -> Self { + into_ref!(pin); + critical_section::with(|_| { + pin.set_low(); + pin.set_as_af( + pin.af_num(), + AfType::output_pull(pin_config.output_type, pin_config.speed, pin_config.pull), + ); + }); + PwmPin { + _pin: pin.map_into(), + phantom: PhantomData, + } + } } }; } diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs index 1dff3f9ae..7664a4dc0 100644 --- a/embassy-stm32/src/timer/simple_pwm.rs +++ b/embassy-stm32/src/timer/simple_pwm.rs @@ -7,7 +7,7 @@ use embassy_hal_internal::{into_ref, PeripheralRef}; use super::low_level::{CountingMode, OutputCompareMode, OutputPolarity, Timer}; use super::{Channel, Channel1Pin, Channel2Pin, Channel3Pin, Channel4Pin, GeneralInstance4Channel, TimerBits}; -use crate::gpio::{AfType, AnyPin, OutputType, Speed}; +use crate::gpio::{AfType, AnyPin, OutputType, Pull, Speed}; use crate::time::Hertz; use crate::Peripheral; @@ -28,6 +28,15 @@ pub struct PwmPin<'d, T, C> { phantom: PhantomData<(T, C)>, } +/// PWM pin config +/// +/// This configures the pwm pin settings +pub struct PwmPinConfig { + pub output_type: OutputType, + pub speed: Speed, + pub pull: Pull, +} + macro_rules! channel_impl { ($new_chx:ident, $channel:ident, $pin_trait:ident) => { impl<'d, T: GeneralInstance4Channel> PwmPin<'d, T, $channel> { @@ -43,6 +52,24 @@ macro_rules! channel_impl { phantom: PhantomData, } } + #[doc = concat!("Create a new ", stringify!($channel), "_with_config PWM pin instance.")] + pub fn $new_chx_with_config( + pin: impl Peripheral

> + 'd, + pin_config: PwmPinConfig, + ) -> Self { + into_ref!(pin); + critical_section::with(|_| { + pin.set_low(); + pin.set_as_af( + pin.af_num(), + AfType::output_pull(pin_config.output_type, pin_config.speed, pin_config.pull), + ); + }); + PwmPin { + _pin: pin.map_into(), + phantom: PhantomData, + } + } } }; } From 1646dc36f2cd85f41a8ad8370912ec33fa4cf5e9 Mon Sep 17 00:00:00 2001 From: Matt Allen Date: Thu, 6 Mar 2025 09:41:07 -0500 Subject: [PATCH 0799/1217] Added gpio version specific code --- embassy-stm32/src/lptim/pwm.rs | 19 ++++++++++++++----- embassy-stm32/src/timer/simple_pwm.rs | 22 ++++++++++++++++------ 2 files changed, 30 insertions(+), 11 deletions(-) diff --git a/embassy-stm32/src/lptim/pwm.rs b/embassy-stm32/src/lptim/pwm.rs index 9f3803cd6..43ef178ef 100644 --- a/embassy-stm32/src/lptim/pwm.rs +++ b/embassy-stm32/src/lptim/pwm.rs @@ -10,7 +10,9 @@ use super::OutputPin; #[cfg(any(lptim_v2a, lptim_v2b))] use super::{channel::Channel, timer::ChannelDirection, Channel1Pin, Channel2Pin}; use super::{BasicInstance, Instance}; -use crate::gpio::{AfType, AnyPin, OutputType, Pull, Speed}; +#[cfg(gpio_v2)] +use crate::gpio::Pull; +use crate::gpio::{AfType, AnyPin, OutputType, Speed}; use crate::time::Hertz; use crate::Peripheral; @@ -33,13 +35,17 @@ pub struct PwmPin<'d, T, C> { /// /// This configures the pwm pin settings pub struct PwmPinConfig { + /// PWM Pin output type pub output_type: OutputType, + /// PWM Pin speed pub speed: Speed, + /// PWM Pin pull type + #[cfg(gpio_v2)] pub pull: Pull, } macro_rules! channel_impl { - ($new_chx:ident, $channel:ident, $pin_trait:ident) => { + ($new_chx:ident, $new_chx_with_config:ident, $channel:ident, $pin_trait:ident) => { impl<'d, T: BasicInstance> PwmPin<'d, T, $channel> { #[doc = concat!("Create a new ", stringify!($channel), " PWM pin instance.")] pub fn $new_chx(pin: impl Peripheral

> + 'd) -> Self { @@ -66,6 +72,9 @@ macro_rules! channel_impl { pin.set_low(); pin.set_as_af( pin.af_num(), + #[cfg(gpio_v1)] + AfType::output(pin_config.output_type, pin_config.speed), + #[cfg(gpio_v2)] AfType::output_pull(pin_config.output_type, pin_config.speed, pin_config.pull), ); }); @@ -79,11 +88,11 @@ macro_rules! channel_impl { } #[cfg(not(any(lptim_v2a, lptim_v2b)))] -channel_impl!(new, Output, OutputPin); +channel_impl!(new, new_with_config, Output, OutputPin); #[cfg(any(lptim_v2a, lptim_v2b))] -channel_impl!(new_ch1, Ch1, Channel1Pin); +channel_impl!(new_ch1, new_ch1_with_config, Ch1, Channel1Pin); #[cfg(any(lptim_v2a, lptim_v2b))] -channel_impl!(new_ch2, Ch2, Channel2Pin); +channel_impl!(new_ch2, new_ch2_with_config, Ch2, Channel2Pin); /// PWM driver. pub struct Pwm<'d, T: Instance> { diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs index 7664a4dc0..5906df635 100644 --- a/embassy-stm32/src/timer/simple_pwm.rs +++ b/embassy-stm32/src/timer/simple_pwm.rs @@ -7,7 +7,9 @@ use embassy_hal_internal::{into_ref, PeripheralRef}; use super::low_level::{CountingMode, OutputCompareMode, OutputPolarity, Timer}; use super::{Channel, Channel1Pin, Channel2Pin, Channel3Pin, Channel4Pin, GeneralInstance4Channel, TimerBits}; -use crate::gpio::{AfType, AnyPin, OutputType, Pull, Speed}; +#[cfg(gpio_v2)] +use crate::gpio::Pull; +use crate::gpio::{AfType, AnyPin, OutputType, Speed}; use crate::time::Hertz; use crate::Peripheral; @@ -32,13 +34,17 @@ pub struct PwmPin<'d, T, C> { /// /// This configures the pwm pin settings pub struct PwmPinConfig { + /// PWM Pin output type pub output_type: OutputType, + /// PWM Pin speed pub speed: Speed, + /// PWM Pin pull type + #[cfg(gpio_v2)] pub pull: Pull, } macro_rules! channel_impl { - ($new_chx:ident, $channel:ident, $pin_trait:ident) => { + ($new_chx:ident, $new_chx_with_config:ident, $channel:ident, $pin_trait:ident) => { impl<'d, T: GeneralInstance4Channel> PwmPin<'d, T, $channel> { #[doc = concat!("Create a new ", stringify!($channel), " PWM pin instance.")] pub fn $new_chx(pin: impl Peripheral

> + 'd, output_type: OutputType) -> Self { @@ -52,6 +58,7 @@ macro_rules! channel_impl { phantom: PhantomData, } } + #[doc = concat!("Create a new ", stringify!($channel), "_with_config PWM pin instance.")] pub fn $new_chx_with_config( pin: impl Peripheral

> + 'd, @@ -62,6 +69,9 @@ macro_rules! channel_impl { pin.set_low(); pin.set_as_af( pin.af_num(), + #[cfg(gpio_v1)] + AfType::output(pin_config.output_type, pin_config.speed), + #[cfg(gpio_v2)] AfType::output_pull(pin_config.output_type, pin_config.speed, pin_config.pull), ); }); @@ -74,10 +84,10 @@ macro_rules! channel_impl { }; } -channel_impl!(new_ch1, Ch1, Channel1Pin); -channel_impl!(new_ch2, Ch2, Channel2Pin); -channel_impl!(new_ch3, Ch3, Channel3Pin); -channel_impl!(new_ch4, Ch4, Channel4Pin); +channel_impl!(new_ch1, new_ch1_with_config, Ch1, Channel1Pin); +channel_impl!(new_ch2, new_ch2_with_config, Ch2, Channel2Pin); +channel_impl!(new_ch3, new_ch3_with_config, Ch3, Channel3Pin); +channel_impl!(new_ch4, new_ch4_with_config, Ch4, Channel4Pin); /// A single channel of a pwm, obtained from [`SimplePwm::split`], /// [`SimplePwm::channel`], [`SimplePwm::ch1`], etc. From 91d8175f6270530203b073d754ea1200243dc08f Mon Sep 17 00:00:00 2001 From: Matt Allen Date: Thu, 6 Mar 2025 09:44:06 -0500 Subject: [PATCH 0800/1217] Fixed documentation --- embassy-stm32/src/lptim/pwm.rs | 2 +- embassy-stm32/src/timer/simple_pwm.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/lptim/pwm.rs b/embassy-stm32/src/lptim/pwm.rs index 43ef178ef..132f5815e 100644 --- a/embassy-stm32/src/lptim/pwm.rs +++ b/embassy-stm32/src/lptim/pwm.rs @@ -62,7 +62,7 @@ macro_rules! channel_impl { phantom: PhantomData, } } - #[doc = concat!("Create a new ", stringify!($channel), "_with_config PWM pin instance.")] + #[doc = concat!("Create a new ", stringify!($channel), " PWM pin instance with config.")] pub fn $new_chx_with_config( pin: impl Peripheral

> + 'd, pin_config: PwmPinConfig, diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs index 5906df635..c5a366cd5 100644 --- a/embassy-stm32/src/timer/simple_pwm.rs +++ b/embassy-stm32/src/timer/simple_pwm.rs @@ -59,7 +59,7 @@ macro_rules! channel_impl { } } - #[doc = concat!("Create a new ", stringify!($channel), "_with_config PWM pin instance.")] + #[doc = concat!("Create a new ", stringify!($channel), " PWM pin instance with config.")] pub fn $new_chx_with_config( pin: impl Peripheral

> + 'd, pin_config: PwmPinConfig, From 3525771e847ebcc14e5ce23b5f71f3f6098ae8e6 Mon Sep 17 00:00:00 2001 From: Alex Charlton Date: Thu, 6 Mar 2025 11:57:07 -0800 Subject: [PATCH 0801/1217] Add mpfs-hal references to docs --- docs/pages/hal.adoc | 2 ++ docs/pages/overview.adoc | 1 + 2 files changed, 3 insertions(+) diff --git a/docs/pages/hal.adoc b/docs/pages/hal.adoc index 14b85e1f1..e1a29751e 100644 --- a/docs/pages/hal.adoc +++ b/docs/pages/hal.adoc @@ -12,3 +12,5 @@ async traits in `embedded-hal` and `embedded-hal-async`. You can also use these For the ESP32 series, there is an link:https://github.com/esp-rs/esp-hal[esp-hal] which you can use. For the WCH 32-bit RISC-V series, there is an link:https://github.com/ch32-rs/ch32-hal[ch32-hal], which you can use. + +For the Microchip PolarFire SoC, there is link:https://github.com/AlexCharlton/mpfs-hal[mpfs-hal]. \ No newline at end of file diff --git a/docs/pages/overview.adoc b/docs/pages/overview.adoc index a1bf180cd..9b93ba10c 100644 --- a/docs/pages/overview.adoc +++ b/docs/pages/overview.adoc @@ -31,6 +31,7 @@ The Embassy project maintains HALs for select hardware, but you can still use HA * link:https://docs.embassy.dev/embassy-rp/[embassy-rp], for the Raspberry Pi RP2040 microcontroller. * link:https://github.com/esp-rs[esp-rs], for the Espressif Systems ESP32 series of chips. * link:https://github.com/ch32-rs/ch32-hal[ch32-hal], for the WCH 32-bit RISC-V(CH32V) series of chips. +* link:https://github.com/AlexCharlton/mpfs-hal[mpfs-hal], for the Microchip PolarFire SoC. NOTE: A common question is if one can use the Embassy HALs standalone. Yes, it is possible! There are no dependency on the executor within the HALs. You can even use them without async, as they implement both the link:https://github.com/rust-embedded/embedded-hal[Embedded HAL] blocking and async traits. From 2ceb3a721c07ce4154e431f5ca4eb3d2632c95e2 Mon Sep 17 00:00:00 2001 From: Sebastian Scholz Date: Fri, 7 Mar 2025 19:32:42 +0100 Subject: [PATCH 0802/1217] Add Instant::try_from_* constructor functions --- embassy-time/src/instant.rs | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/embassy-time/src/instant.rs b/embassy-time/src/instant.rs index 7fc93c2ec..6571bea62 100644 --- a/embassy-time/src/instant.rs +++ b/embassy-time/src/instant.rs @@ -50,6 +50,37 @@ impl Instant { } } + /// Try to create an Instant from a microsecond count since system boot. + /// Fails if the number of microseconds is too large. + pub const fn try_from_micros(micros: u64) -> Option { + let Some(value) = micros.checked_mul(TICK_HZ / GCD_1M) else { + return None; + }; + Some(Self { + ticks: value / (1_000_000 / GCD_1M), + }) + } + + /// Try to create an Instant from a millisecond count since system boot. + /// Fails if the number of milliseconds is too large. + pub const fn try_from_millis(millis: u64) -> Option { + let Some(value) = millis.checked_mul(TICK_HZ / GCD_1K) else { + return None; + }; + Some(Self { + ticks: value / (1000 / GCD_1K), + }) + } + + /// Try to create an Instant from a second count since system boot. + /// Fails if the number of seconds is too large. + pub const fn try_from_secs(seconds: u64) -> Option { + let Some(ticks) = seconds.checked_mul(TICK_HZ) else { + return None; + }; + Some(Self { ticks }) + } + /// Tick count since system boot. pub const fn as_ticks(&self) -> u64 { self.ticks From f2e14303a6200fd6a52d233c6b8a7bbd4d929d03 Mon Sep 17 00:00:00 2001 From: 9names <60134748+9names@users.noreply.github.com> Date: Sun, 9 Mar 2025 10:52:57 +1100 Subject: [PATCH 0803/1217] rp/pio: Use crates.io version of pio in embassy-rp --- embassy-rp/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index 539c579a3..3c9e466a4 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml @@ -164,7 +164,7 @@ embedded-hal-1 = { package = "embedded-hal", version = "1.0" } embedded-hal-async = { version = "1.0" } embedded-hal-nb = { version = "1.0" } -pio = { git = "https://github.com/rp-rs/pio-rs", rev = "506a51b9bc135845e8544a0debd75847b73754dc" } +pio = { version = "0.3" } rp2040-boot2 = "0.3" document-features = "0.2.10" sha2-const-stable = "0.1" From e1b24a8efd77e5ee3b865e262814d9a90139d7f0 Mon Sep 17 00:00:00 2001 From: 9names <60134748+9names@users.noreply.github.com> Date: Sun, 9 Mar 2025 10:53:18 +1100 Subject: [PATCH 0804/1217] rp: Bump embassy-rp version number for release --- embassy-rp/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index 3c9e466a4..4e5ef2813 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "embassy-rp" -version = "0.3.0" +version = "0.4.0" edition = "2021" license = "MIT OR Apache-2.0" description = "Embassy Hardware Abstraction Layer (HAL) for the Raspberry Pi RP2040 microcontroller" From 430377138b002ec44c49c538b10c55474abc8288 Mon Sep 17 00:00:00 2001 From: 9names <60134748+9names@users.noreply.github.com> Date: Sun, 9 Mar 2025 11:02:52 +1100 Subject: [PATCH 0805/1217] rp: Update embassy-rp version in examples and tests --- examples/rp/Cargo.toml | 2 +- examples/rp235x/Cargo.toml | 2 +- tests/rp/Cargo.toml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index a81166067..ad185f52a 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml @@ -10,7 +10,7 @@ embassy-embedded-hal = { version = "0.3.0", path = "../../embassy-embedded-hal", embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-98304", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } -embassy-rp = { version = "0.3.0", path = "../../embassy-rp", features = ["defmt", "unstable-pac", "time-driver", "critical-section-impl", "rp2040"] } +embassy-rp = { version = "0.4.0", path = "../../embassy-rp", features = ["defmt", "unstable-pac", "time-driver", "critical-section-impl", "rp2040"] } embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defmt"] } embassy-net = { version = "0.7.0", path = "../../embassy-net", features = ["defmt", "icmp", "tcp", "udp", "raw", "dhcpv4", "medium-ethernet", "dns", "proto-ipv4", "proto-ipv6", "multicast"] } embassy-net-wiznet = { version = "0.2.0", path = "../../embassy-net-wiznet", features = ["defmt"] } diff --git a/examples/rp235x/Cargo.toml b/examples/rp235x/Cargo.toml index f4dfae773..b8d4a62e9 100644 --- a/examples/rp235x/Cargo.toml +++ b/examples/rp235x/Cargo.toml @@ -10,7 +10,7 @@ embassy-embedded-hal = { version = "0.3.0", path = "../../embassy-embedded-hal", embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-98304", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } -embassy-rp = { version = "0.3.0", path = "../../embassy-rp", features = ["defmt", "unstable-pac", "time-driver", "critical-section-impl", "rp235xa", "binary-info"] } +embassy-rp = { version = "0.4.0", path = "../../embassy-rp", features = ["defmt", "unstable-pac", "time-driver", "critical-section-impl", "rp235xa", "binary-info"] } embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defmt"] } embassy-net = { version = "0.7.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "raw", "dhcpv4", "medium-ethernet", "dns"] } embassy-net-wiznet = { version = "0.2.0", path = "../../embassy-net-wiznet", features = ["defmt"] } diff --git a/tests/rp/Cargo.toml b/tests/rp/Cargo.toml index 7b6fb24f2..503c4d67b 100644 --- a/tests/rp/Cargo.toml +++ b/tests/rp/Cargo.toml @@ -15,7 +15,7 @@ teleprobe-meta = "1.1" embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", ] } -embassy-rp = { version = "0.3.0", path = "../../embassy-rp", features = [ "defmt", "unstable-pac", "time-driver", "critical-section-impl", "intrinsics", "rom-v2-intrinsics", "run-from-ram"] } +embassy-rp = { version = "0.4.0", path = "../../embassy-rp", features = [ "defmt", "unstable-pac", "time-driver", "critical-section-impl", "intrinsics", "rom-v2-intrinsics", "run-from-ram"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-net = { version = "0.7.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "dhcpv4", "medium-ethernet"] } embassy-net-wiznet = { version = "0.2.0", path = "../../embassy-net-wiznet", features = ["defmt"] } From 37291399152ccf58049484c875a5171257c3286b Mon Sep 17 00:00:00 2001 From: 9names <60134748+9names@users.noreply.github.com> Date: Sun, 9 Mar 2025 11:07:04 +1100 Subject: [PATCH 0806/1217] rp: Update changelog for embassy-rp 0.4.0 release --- embassy-rp/CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/embassy-rp/CHANGELOG.md b/embassy-rp/CHANGELOG.md index 3d8a659f9..8ad3b0b76 100644 --- a/embassy-rp/CHANGELOG.md +++ b/embassy-rp/CHANGELOG.md @@ -7,12 +7,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +## 0.4.0 - 2025-03-09 + - Add PIO functions. ([#3857](https://github.com/embassy-rs/embassy/pull/3857)) The functions added in this change are `get_addr` `get_tx_threshold`, `set_tx_threshold`, `get_rx_threshold`, `set_rx_threshold`, `set_thresholds`. - Expose the watchdog reset reason. ([#3877](https://github.com/embassy-rs/embassy/pull/3877)) - Update pio-rs, reexport, move instr methods to SM. ([#3865](https://github.com/embassy-rs/embassy/pull/3865)) - rp235x: add ImageDef features. ([#3890](https://github.com/embassy-rs/embassy/pull/3890)) - doc: Fix "the the" ([#3903](https://github.com/embassy-rs/embassy/pull/3903)) +- pio: Add access to DMA engine byte swapping ([#3935](https://github.com/embassy-rs/embassy/pull/3935)) ## 0.3.1 - 2025-02-06 From b00daafd3e9cba888d4b782d06fddc5363b3197d Mon Sep 17 00:00:00 2001 From: 9names <60134748+9names@users.noreply.github.com> Date: Sun, 9 Mar 2025 11:43:10 +1100 Subject: [PATCH 0807/1217] rp/pio: Update cyw43-pio to use new version of embassy-rp --- cyw43-pio/CHANGELOG.md | 2 ++ cyw43-pio/Cargo.toml | 4 ++-- examples/rp/Cargo.toml | 2 +- examples/rp235x/Cargo.toml | 2 +- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/cyw43-pio/CHANGELOG.md b/cyw43-pio/CHANGELOG.md index e65ca5679..4d56973df 100644 --- a/cyw43-pio/CHANGELOG.md +++ b/cyw43-pio/CHANGELOG.md @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +- Update embassy-rp to 0.4.0 + ## 0.3.0 - 2025-01-05 - Update embassy-time to 0.4.0 diff --git a/cyw43-pio/Cargo.toml b/cyw43-pio/Cargo.toml index 2397c76d3..600caf5ed 100644 --- a/cyw43-pio/Cargo.toml +++ b/cyw43-pio/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cyw43-pio" -version = "0.3.0" +version = "0.4.0" edition = "2021" description = "RP2040 PIO SPI implementation for cyw43" keywords = ["embedded", "cyw43", "embassy-net", "embedded-hal-async", "wifi"] @@ -11,7 +11,7 @@ documentation = "https://docs.embassy.dev/cyw43-pio" [dependencies] cyw43 = { version = "0.3.0", path = "../cyw43" } -embassy-rp = { version = "0.3.0", path = "../embassy-rp" } +embassy-rp = { version = "0.4.0", path = "../embassy-rp" } fixed = "1.23.1" defmt = { version = "0.3", optional = true } diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index ad185f52a..cde804a15 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml @@ -17,7 +17,7 @@ embassy-net-wiznet = { version = "0.2.0", path = "../../embassy-net-wiznet", fea embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-usb-logger = { version = "0.4.0", path = "../../embassy-usb-logger" } cyw43 = { version = "0.3.0", path = "../../cyw43", features = ["defmt", "firmware-logs"] } -cyw43-pio = { version = "0.3.0", path = "../../cyw43-pio", features = ["defmt"] } +cyw43-pio = { version = "0.4.0", path = "../../cyw43-pio", features = ["defmt"] } defmt = "0.3" defmt-rtt = "0.4" diff --git a/examples/rp235x/Cargo.toml b/examples/rp235x/Cargo.toml index b8d4a62e9..4e9c93e7c 100644 --- a/examples/rp235x/Cargo.toml +++ b/examples/rp235x/Cargo.toml @@ -17,7 +17,7 @@ embassy-net-wiznet = { version = "0.2.0", path = "../../embassy-net-wiznet", fea embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-usb-logger = { version = "0.4.0", path = "../../embassy-usb-logger" } cyw43 = { version = "0.3.0", path = "../../cyw43", features = ["defmt", "firmware-logs"] } -cyw43-pio = { version = "0.3.0", path = "../../cyw43-pio", features = ["defmt"] } +cyw43-pio = { version = "0.4.0", path = "../../cyw43-pio", features = ["defmt"] } defmt = "0.3" defmt-rtt = "0.4" From f046fa24b64537cdbe2eeb60c6f4b7ec533c105d Mon Sep 17 00:00:00 2001 From: 9names <60134748+9names@users.noreply.github.com> Date: Sun, 9 Mar 2025 14:33:04 +1100 Subject: [PATCH 0808/1217] rp: Update embassy-boot-rp to use embassy-rp 0.4.0 --- embassy-boot-rp/Cargo.toml | 2 +- examples/boot/application/rp/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-boot-rp/Cargo.toml b/embassy-boot-rp/Cargo.toml index 8f6499a7b..b1c787e6b 100644 --- a/embassy-boot-rp/Cargo.toml +++ b/embassy-boot-rp/Cargo.toml @@ -25,7 +25,7 @@ defmt = { version = "0.3", optional = true } log = { version = "0.4", optional = true } embassy-sync = { version = "0.6.2", path = "../embassy-sync" } -embassy-rp = { version = "0.3.0", path = "../embassy-rp", default-features = false } +embassy-rp = { version = "0.4.0", path = "../embassy-rp", default-features = false } embassy-boot = { version = "0.4.0", path = "../embassy-boot" } embassy-time = { version = "0.4.0", path = "../embassy-time" } diff --git a/examples/boot/application/rp/Cargo.toml b/examples/boot/application/rp/Cargo.toml index ee0247c17..96ecf375f 100644 --- a/examples/boot/application/rp/Cargo.toml +++ b/examples/boot/application/rp/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" embassy-sync = { version = "0.6.2", path = "../../../../embassy-sync" } embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["task-arena-size-16384", "arch-cortex-m", "executor-thread", "arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [] } -embassy-rp = { version = "0.3.0", path = "../../../../embassy-rp", features = ["time-driver", "rp2040"] } +embassy-rp = { version = "0.4.0", path = "../../../../embassy-rp", features = ["time-driver", "rp2040"] } embassy-boot-rp = { version = "0.4.0", path = "../../../../embassy-boot-rp", features = [] } embassy-embedded-hal = { version = "0.3.0", path = "../../../../embassy-embedded-hal" } From 8f41a4dfad76277eb203c9f1aa9a345ce4763315 Mon Sep 17 00:00:00 2001 From: 9names <60134748+9names@users.noreply.github.com> Date: Sun, 9 Mar 2025 14:34:15 +1100 Subject: [PATCH 0809/1217] boot/rp: Bump version number --- embassy-boot-rp/Cargo.toml | 2 +- examples/boot/application/rp/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-boot-rp/Cargo.toml b/embassy-boot-rp/Cargo.toml index b1c787e6b..284ac654c 100644 --- a/embassy-boot-rp/Cargo.toml +++ b/embassy-boot-rp/Cargo.toml @@ -1,7 +1,7 @@ [package] edition = "2021" name = "embassy-boot-rp" -version = "0.4.0" +version = "0.5.0" description = "Bootloader lib for RP2040 chips" license = "MIT OR Apache-2.0" repository = "https://github.com/embassy-rs/embassy" diff --git a/examples/boot/application/rp/Cargo.toml b/examples/boot/application/rp/Cargo.toml index 96ecf375f..3f0d4cd78 100644 --- a/examples/boot/application/rp/Cargo.toml +++ b/examples/boot/application/rp/Cargo.toml @@ -9,7 +9,7 @@ embassy-sync = { version = "0.6.2", path = "../../../../embassy-sync" } embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["task-arena-size-16384", "arch-cortex-m", "executor-thread", "arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [] } embassy-rp = { version = "0.4.0", path = "../../../../embassy-rp", features = ["time-driver", "rp2040"] } -embassy-boot-rp = { version = "0.4.0", path = "../../../../embassy-boot-rp", features = [] } +embassy-boot-rp = { version = "0.5.0", path = "../../../../embassy-boot-rp", features = [] } embassy-embedded-hal = { version = "0.3.0", path = "../../../../embassy-embedded-hal" } defmt = "0.3" From 424d20727eb3d2b2bda6b6a8f42306a57e93c9f2 Mon Sep 17 00:00:00 2001 From: Corey Schuhen Date: Sun, 9 Mar 2025 13:17:39 +1000 Subject: [PATCH 0810/1217] Reference count senders and receivers so that we don't close down early. --- embassy-stm32/src/can/bxcan/mod.rs | 64 +++++++++++++----- embassy-stm32/src/can/common.rs | 86 ++++++++++++++++++++++-- embassy-stm32/src/can/enums.rs | 14 ++++ embassy-stm32/src/can/fdcan.rs | 104 ++++++++++++++++------------- 4 files changed, 199 insertions(+), 69 deletions(-) diff --git a/embassy-stm32/src/can/bxcan/mod.rs b/embassy-stm32/src/can/bxcan/mod.rs index 8165364f5..c0b3c730b 100644 --- a/embassy-stm32/src/can/bxcan/mod.rs +++ b/embassy-stm32/src/can/bxcan/mod.rs @@ -17,7 +17,7 @@ use self::registers::{Registers, RxFifo}; pub use super::common::{BufferedCanReceiver, BufferedCanSender}; use super::frame::{Envelope, Frame}; use super::util; -use crate::can::enums::{BusError, TryReadError}; +use crate::can::enums::{BusError, InternalOperation, TryReadError}; use crate::gpio::{AfType, OutputType, Pull, Speed}; use crate::interrupt::typelevel::Interrupt; use crate::rcc::{self, RccPeripheral}; @@ -685,22 +685,18 @@ impl<'d, const TX_BUF_SIZE: usize> BufferedCanTx<'d, TX_BUF_SIZE> { /// Returns a sender that can be used for sending CAN frames. pub fn writer(&self) -> BufferedCanSender { + (self.info.internal_operation)(InternalOperation::NotifySenderCreated); BufferedCanSender { tx_buf: self.tx_buf.sender().into(), waker: self.info.tx_waker, + internal_operation: self.info.internal_operation, } } } impl<'d, const TX_BUF_SIZE: usize> Drop for BufferedCanTx<'d, TX_BUF_SIZE> { fn drop(&mut self) { - critical_section::with(|_| { - let state = self.state as *const State; - unsafe { - let mut_state = state as *mut State; - (*mut_state).tx_mode = TxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new()); - } - }); + (self.info.internal_operation)(InternalOperation::NotifySenderDestroyed); } } @@ -825,7 +821,11 @@ impl<'d, const RX_BUF_SIZE: usize> BufferedCanRx<'d, RX_BUF_SIZE> { /// Returns a receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver. pub fn reader(&self) -> BufferedCanReceiver { - self.rx_buf.receiver().into() + (self.info.internal_operation)(InternalOperation::NotifyReceiverCreated); + BufferedCanReceiver { + rx_buf: self.rx_buf.receiver().into(), + internal_operation: self.info.internal_operation, + } } /// Accesses the filter banks owned by this CAN peripheral. @@ -839,13 +839,7 @@ impl<'d, const RX_BUF_SIZE: usize> BufferedCanRx<'d, RX_BUF_SIZE> { impl<'d, const RX_BUF_SIZE: usize> Drop for BufferedCanRx<'d, RX_BUF_SIZE> { fn drop(&mut self) { - critical_section::with(|_| { - let state = self.state as *const State; - unsafe { - let mut_state = state as *mut State; - (*mut_state).rx_mode = RxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new()); - } - }); + (self.info.internal_operation)(InternalOperation::NotifyReceiverDestroyed); } } @@ -1048,6 +1042,8 @@ pub(crate) struct State { pub(crate) rx_mode: RxMode, pub(crate) tx_mode: TxMode, pub err_waker: AtomicWaker, + receiver_instance_count: usize, + sender_instance_count: usize, } impl State { @@ -1056,6 +1052,8 @@ impl State { rx_mode: RxMode::NonBuffered(AtomicWaker::new()), tx_mode: TxMode::NonBuffered(AtomicWaker::new()), err_waker: AtomicWaker::new(), + receiver_instance_count: 1, + sender_instance_count: 1, } } } @@ -1067,6 +1065,7 @@ pub(crate) struct Info { rx1_interrupt: crate::interrupt::Interrupt, sce_interrupt: crate::interrupt::Interrupt, tx_waker: fn(), + internal_operation: fn(InternalOperation), /// The total number of filter banks available to the instance. /// @@ -1079,6 +1078,7 @@ trait SealedInstance { fn regs() -> crate::pac::can::Can; fn state() -> &'static State; unsafe fn mut_state() -> &'static mut State; + fn internal_operation(val: InternalOperation); } /// CAN instance trait. @@ -1136,6 +1136,7 @@ foreach_peripheral!( rx1_interrupt: crate::_generated::peripheral_interrupts::$inst::RX1::IRQ, sce_interrupt: crate::_generated::peripheral_interrupts::$inst::SCE::IRQ, tx_waker: crate::_generated::peripheral_interrupts::$inst::TX::pend, + internal_operation: peripherals::$inst::internal_operation, num_filter_banks: peripherals::$inst::NUM_FILTER_BANKS, }; &INFO @@ -1151,6 +1152,37 @@ foreach_peripheral!( fn state() -> &'static State { unsafe { peripherals::$inst::mut_state() } } + + + fn internal_operation(val: InternalOperation) { + critical_section::with(|_| { + //let state = self.state as *const State; + unsafe { + //let mut_state = state as *mut State; + let mut_state = peripherals::$inst::mut_state(); + match val { + InternalOperation::NotifySenderCreated => { + mut_state.sender_instance_count += 1; + } + InternalOperation::NotifySenderDestroyed => { + mut_state.sender_instance_count -= 1; + if ( 0 == mut_state.sender_instance_count) { + (*mut_state).tx_mode = TxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new()); + } + } + InternalOperation::NotifyReceiverCreated => { + mut_state.receiver_instance_count += 1; + } + InternalOperation::NotifyReceiverDestroyed => { + mut_state.receiver_instance_count -= 1; + if ( 0 == mut_state.receiver_instance_count) { + (*mut_state).rx_mode = RxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new()); + } + } + } + } + }); + } } impl Instance for peripherals::$inst { diff --git a/embassy-stm32/src/can/common.rs b/embassy-stm32/src/can/common.rs index a54b54f6e..e12111910 100644 --- a/embassy-stm32/src/can/common.rs +++ b/embassy-stm32/src/can/common.rs @@ -22,22 +22,22 @@ pub(crate) struct FdBufferedTxInner { } /// Sender that can be used for sending CAN frames. -#[derive(Copy, Clone)] -pub struct BufferedCanSender { - pub(crate) tx_buf: embassy_sync::channel::DynamicSender<'static, Frame>, +pub struct BufferedSender<'ch, FRAME> { + pub(crate) tx_buf: embassy_sync::channel::DynamicSender<'ch, FRAME>, pub(crate) waker: fn(), + pub(crate) internal_operation: fn(InternalOperation), } -impl BufferedCanSender { +impl<'ch, FRAME> BufferedSender<'ch, FRAME> { /// Async write frame to TX buffer. - pub fn try_write(&mut self, frame: Frame) -> Result<(), embassy_sync::channel::TrySendError> { + pub fn try_write(&mut self, frame: FRAME) -> Result<(), embassy_sync::channel::TrySendError> { self.tx_buf.try_send(frame)?; (self.waker)(); Ok(()) } /// Async write frame to TX buffer. - pub async fn write(&mut self, frame: Frame) { + pub async fn write(&mut self, frame: FRAME) { self.tx_buf.send(frame).await; (self.waker)(); } @@ -48,5 +48,77 @@ impl BufferedCanSender { } } +impl<'ch, FRAME> Clone for BufferedSender<'ch, FRAME> { + fn clone(&self) -> Self { + (self.internal_operation)(InternalOperation::NotifySenderCreated); + Self { + tx_buf: self.tx_buf, + waker: self.waker, + internal_operation: self.internal_operation, + } + } +} + +impl<'ch, FRAME> Drop for BufferedSender<'ch, FRAME> { + fn drop(&mut self) { + (self.internal_operation)(InternalOperation::NotifySenderDestroyed); + } +} + +/// Sender that can be used for sending Classic CAN frames. +pub type BufferedCanSender = BufferedSender<'static, Frame>; + /// Receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver. -pub type BufferedCanReceiver = embassy_sync::channel::DynamicReceiver<'static, Result>; +pub struct BufferedReceiver<'ch, ENVELOPE> { + pub(crate) rx_buf: embassy_sync::channel::DynamicReceiver<'ch, Result>, + pub(crate) internal_operation: fn(InternalOperation), +} + +impl<'ch, ENVELOPE> BufferedReceiver<'ch, ENVELOPE> { + /// Receive the next frame. + /// + /// See [`Channel::receive()`]. + pub fn receive(&self) -> embassy_sync::channel::DynamicReceiveFuture<'_, Result> { + self.rx_buf.receive() + } + + /// Attempt to immediately receive the next frame. + /// + /// See [`Channel::try_receive()`] + pub fn try_receive(&self) -> Result, embassy_sync::channel::TryReceiveError> { + self.rx_buf.try_receive() + } + + /// Allows a poll_fn to poll until the channel is ready to receive + /// + /// See [`Channel::poll_ready_to_receive()`] + pub fn poll_ready_to_receive(&self, cx: &mut core::task::Context<'_>) -> core::task::Poll<()> { + self.rx_buf.poll_ready_to_receive(cx) + } + + /// Poll the channel for the next frame + /// + /// See [`Channel::poll_receive()`] + pub fn poll_receive(&self, cx: &mut core::task::Context<'_>) -> core::task::Poll> { + self.rx_buf.poll_receive(cx) + } +} + +impl<'ch, ENVELOPE> Clone for BufferedReceiver<'ch, ENVELOPE> { + fn clone(&self) -> Self { + (self.internal_operation)(InternalOperation::NotifyReceiverCreated); + Self { + rx_buf: self.rx_buf, + internal_operation: self.internal_operation, + } + } +} + +impl<'ch, ENVELOPE> Drop for BufferedReceiver<'ch, ENVELOPE> { + fn drop(&mut self) { + (self.internal_operation)(InternalOperation::NotifyReceiverDestroyed); + } +} + +/// A BufferedCanReceiver for Classic CAN frames. +pub type BufferedCanReceiver = BufferedReceiver<'static, Envelope>; diff --git a/embassy-stm32/src/can/enums.rs b/embassy-stm32/src/can/enums.rs index a5cca424d..97cb47640 100644 --- a/embassy-stm32/src/can/enums.rs +++ b/embassy-stm32/src/can/enums.rs @@ -68,3 +68,17 @@ pub enum TryReadError { /// Receive buffer is empty Empty, } + +/// Internal Operation +#[derive(Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum InternalOperation { + /// Notify receiver created + NotifyReceiverCreated, + /// Notify receiver destroyed + NotifyReceiverDestroyed, + /// Notify sender created + NotifySenderCreated, + /// Notify sender destroyed + NotifySenderDestroyed, +} diff --git a/embassy-stm32/src/can/fdcan.rs b/embassy-stm32/src/can/fdcan.rs index c549313f3..f950b6f99 100644 --- a/embassy-stm32/src/can/fdcan.rs +++ b/embassy-stm32/src/can/fdcan.rs @@ -6,7 +6,7 @@ use core::task::Poll; use embassy_hal_internal::interrupt::InterruptExt; use embassy_hal_internal::{into_ref, PeripheralRef}; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; -use embassy_sync::channel::{Channel, DynamicReceiver, DynamicSender}; +use embassy_sync::channel::Channel; use embassy_sync::waitqueue::AtomicWaker; use crate::can::fd::peripheral::Registers; @@ -478,28 +478,28 @@ impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCan<'d, /// Returns a sender that can be used for sending CAN frames. pub fn writer(&self) -> BufferedCanSender { + (self.info.internal_operation)(InternalOperation::NotifySenderCreated); BufferedCanSender { tx_buf: self.tx_buf.sender().into(), waker: self.info.tx_waker, + internal_operation: self.info.internal_operation, } } /// Returns a receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver. pub fn reader(&self) -> BufferedCanReceiver { - self.rx_buf.receiver().into() + (self.info.internal_operation)(InternalOperation::NotifyReceiverCreated); + BufferedCanReceiver { + rx_buf: self.rx_buf.receiver().into(), + internal_operation: self.info.internal_operation, + } } } impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> Drop for BufferedCan<'d, TX_BUF_SIZE, RX_BUF_SIZE> { fn drop(&mut self) { - critical_section::with(|_| { - let state = self.state as *const State; - unsafe { - let mut_state = state as *mut State; - (*mut_state).rx_mode = RxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new()); - (*mut_state).tx_mode = TxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new()); - } - }); + (self.info.internal_operation)(InternalOperation::NotifySenderDestroyed); + (self.info.internal_operation)(InternalOperation::NotifyReceiverDestroyed); } } @@ -509,35 +509,11 @@ pub type RxFdBuf = Channel = Channel; -/// Sender that can be used for sending CAN frames. -#[derive(Copy, Clone)] -pub struct BufferedFdCanSender { - tx_buf: DynamicSender<'static, FdFrame>, - waker: fn(), -} - -impl BufferedFdCanSender { - /// Async write frame to TX buffer. - pub fn try_write(&mut self, frame: FdFrame) -> Result<(), embassy_sync::channel::TrySendError> { - self.tx_buf.try_send(frame)?; - (self.waker)(); - Ok(()) - } - - /// Async write frame to TX buffer. - pub async fn write(&mut self, frame: FdFrame) { - self.tx_buf.send(frame).await; - (self.waker)(); - } - - /// Allows a poll_fn to poll until the channel is ready to write - pub fn poll_ready_to_send(&self, cx: &mut core::task::Context<'_>) -> core::task::Poll<()> { - self.tx_buf.poll_ready_to_send(cx) - } -} +/// Sender that can be used for sending Classic CAN frames. +pub type BufferedFdCanSender = super::common::BufferedSender<'static, FdFrame>; /// Receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver. -pub type BufferedFdCanReceiver = DynamicReceiver<'static, Result>; +pub type BufferedFdCanReceiver = super::common::BufferedReceiver<'static, FdEnvelope>; /// Buffered FDCAN Instance pub struct BufferedCanFd<'d, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> { @@ -608,28 +584,28 @@ impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCanFd<' /// Returns a sender that can be used for sending CAN frames. pub fn writer(&self) -> BufferedFdCanSender { + (self.info.internal_operation)(InternalOperation::NotifySenderCreated); BufferedFdCanSender { tx_buf: self.tx_buf.sender().into(), waker: self.info.tx_waker, + internal_operation: self.info.internal_operation, } } /// Returns a receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver. pub fn reader(&self) -> BufferedFdCanReceiver { - self.rx_buf.receiver().into() + (self.info.internal_operation)(InternalOperation::NotifyReceiverCreated); + BufferedFdCanReceiver { + rx_buf: self.rx_buf.receiver().into(), + internal_operation: self.info.internal_operation, + } } } impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> Drop for BufferedCanFd<'d, TX_BUF_SIZE, RX_BUF_SIZE> { fn drop(&mut self) { - critical_section::with(|_| { - let state = self.state as *const State; - unsafe { - let mut_state = state as *mut State; - (*mut_state).rx_mode = RxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new()); - (*mut_state).tx_mode = TxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new()); - } - }); + (self.info.internal_operation)(InternalOperation::NotifySenderDestroyed); + (self.info.internal_operation)(InternalOperation::NotifyReceiverDestroyed); } } @@ -922,6 +898,8 @@ struct State { pub rx_mode: RxMode, pub tx_mode: TxMode, pub ns_per_timer_tick: u64, + receiver_instance_count: usize, + sender_instance_count: usize, pub err_waker: AtomicWaker, } @@ -933,6 +911,8 @@ impl State { tx_mode: TxMode::NonBuffered(AtomicWaker::new()), ns_per_timer_tick: 0, err_waker: AtomicWaker::new(), + receiver_instance_count: 1, + sender_instance_count: 1, } } } @@ -942,6 +922,7 @@ struct Info { interrupt0: crate::interrupt::Interrupt, _interrupt1: crate::interrupt::Interrupt, tx_waker: fn(), + internal_operation: fn(InternalOperation), } impl Info { @@ -970,6 +951,7 @@ trait SealedInstance { fn registers() -> crate::can::fd::peripheral::Registers; fn state() -> &'static State; unsafe fn mut_state() -> &'static mut State; + fn internal_operation(val: InternalOperation); fn calc_timestamp(ns_per_timer_tick: u64, ts_val: u16) -> Timestamp; } @@ -992,12 +974,42 @@ macro_rules! impl_fdcan { impl SealedInstance for peripherals::$inst { const MSG_RAM_OFFSET: usize = $msg_ram_offset; + fn internal_operation(val: InternalOperation) { + critical_section::with(|_| { + //let state = self.state as *const State; + unsafe { + //let mut_state = state as *mut State; + let mut_state = peripherals::$inst::mut_state(); + match val { + InternalOperation::NotifySenderCreated => { + mut_state.sender_instance_count += 1; + } + InternalOperation::NotifySenderDestroyed => { + mut_state.sender_instance_count -= 1; + if ( 0 == mut_state.sender_instance_count) { + (*mut_state).tx_mode = TxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new()); + } + } + InternalOperation::NotifyReceiverCreated => { + mut_state.receiver_instance_count += 1; + } + InternalOperation::NotifyReceiverDestroyed => { + mut_state.receiver_instance_count -= 1; + if ( 0 == mut_state.receiver_instance_count) { + (*mut_state).rx_mode = RxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new()); + } + } + } + } + }); + } fn info() -> &'static Info { static INFO: Info = Info { regs: Registers{regs: crate::pac::$inst, msgram: crate::pac::$msg_ram_inst, msg_ram_offset: $msg_ram_offset}, interrupt0: crate::_generated::peripheral_interrupts::$inst::IT0::IRQ, _interrupt1: crate::_generated::peripheral_interrupts::$inst::IT1::IRQ, tx_waker: crate::_generated::peripheral_interrupts::$inst::IT0::pend, + internal_operation: peripherals::$inst::internal_operation, }; &INFO } From 5a37dafec1af10263a46689b94c8099c335b332d Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Mon, 10 Mar 2025 09:56:04 +0100 Subject: [PATCH 0811/1217] preserve user attributes --- embassy-executor-macros/src/macros/main.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/embassy-executor-macros/src/macros/main.rs b/embassy-executor-macros/src/macros/main.rs index a774cf622..24f61f30b 100644 --- a/embassy-executor-macros/src/macros/main.rs +++ b/embassy-executor-macros/src/macros/main.rs @@ -155,6 +155,11 @@ pub fn run(args: TokenStream, item: TokenStream, arch: &Arch) -> TokenStream { ), }; + let mut main_attrs = TokenStream::new(); + for attr in f.attrs { + main_attrs.extend(quote!(#attr)); + } + if !errors.is_empty() { main_body = quote! {loop{}}; } @@ -167,6 +172,7 @@ pub fn run(args: TokenStream, item: TokenStream, arch: &Arch) -> TokenStream { } #entry + #main_attrs fn main() -> #main_ret { #main_body } From 869758037b0cad03d47614d99e8e72340e3aa5f8 Mon Sep 17 00:00:00 2001 From: Sebastian Scholz Date: Mon, 10 Mar 2025 19:05:33 +0100 Subject: [PATCH 0812/1217] Add try_from constructors to Duration --- embassy-time/src/duration.rs | 80 +++++++++++++++++++++++++++++++++++- 1 file changed, 78 insertions(+), 2 deletions(-) diff --git a/embassy-time/src/duration.rs b/embassy-time/src/duration.rs index 647d208e3..dcda705d3 100644 --- a/embassy-time/src/duration.rs +++ b/embassy-time/src/duration.rs @@ -64,9 +64,9 @@ impl Duration { /// Creates a duration from the specified number of nanoseconds, rounding up. /// NOTE: Delays this small may be inaccurate. - pub const fn from_nanos(micros: u64) -> Duration { + pub const fn from_nanos(nanoseconds: u64) -> Duration { Duration { - ticks: div_ceil(micros * (TICK_HZ / GCD_1G), 1_000_000_000 / GCD_1G), + ticks: div_ceil(nanoseconds * (TICK_HZ / GCD_1G), 1_000_000_000 / GCD_1G), } } @@ -90,6 +90,82 @@ impl Duration { } } + /// Try to create a duration from the specified number of seconds, rounding up. + /// Fails if the number of seconds is too large. + pub const fn try_from_secs(secs: u64) -> Option { + let Some(ticks) = secs.checked_mul(TICK_HZ) else { + return None; + }; + Some(Duration { ticks }) + } + + /// Try to create a duration from the specified number of milliseconds, rounding up. + /// Fails if the number of milliseconds is too large. + pub const fn try_from_millis(millis: u64) -> Option { + let Some(value) = millis.checked_mul(TICK_HZ / GCD_1K) else { + return None; + }; + Some(Duration { + ticks: div_ceil(value, 1000 / GCD_1K), + }) + } + + /// Try to create a duration from the specified number of microseconds, rounding up. + /// Fails if the number of microseconds is too large. + /// NOTE: Delays this small may be inaccurate. + pub const fn try_from_micros(micros: u64) -> Option { + let Some(value) = micros.checked_mul(TICK_HZ / GCD_1M) else { + return None; + }; + Some(Duration { + ticks: div_ceil(value, 1_000_000 / GCD_1M), + }) + } + + /// Try to create a duration from the specified number of nanoseconds, rounding up. + /// Fails if the number of nanoseconds is too large. + /// NOTE: Delays this small may be inaccurate. + pub const fn try_from_nanos(nanoseconds: u64) -> Option { + let Some(value) = nanoseconds.checked_mul(TICK_HZ / GCD_1G) else { + return None; + }; + Some(Duration { + ticks: div_ceil(value, 1_000_000_000 / GCD_1G), + }) + } + + /// Try to create a duration from the specified number of seconds, rounding down. + /// Fails if the number of seconds is too large. + pub const fn try_from_secs_floor(secs: u64) -> Option { + let Some(ticks) = secs.checked_mul(TICK_HZ) else { + return None; + }; + Some(Duration { ticks }) + } + + /// Try to create a duration from the specified number of milliseconds, rounding down. + /// Fails if the number of milliseconds is too large. + pub const fn try_from_millis_floor(millis: u64) -> Option { + let Some(value) = millis.checked_mul(TICK_HZ / GCD_1K) else { + return None; + }; + Some(Duration { + ticks: value / (1000 / GCD_1K), + }) + } + + /// Try to create a duration from the specified number of microseconds, rounding down. + /// Fails if the number of microseconds is too large. + /// NOTE: Delays this small may be inaccurate. + pub const fn try_from_micros_floor(micros: u64) -> Option { + let Some(value) = micros.checked_mul(TICK_HZ / GCD_1M) else { + return None; + }; + Some(Duration { + ticks: value / (1_000_000 / GCD_1M), + }) + } + /// Creates a duration corresponding to the specified Hz. /// NOTE: Giving this function a hz >= the TICK_HZ of your platform will clamp the Duration to 1 /// tick. Doing so will not deadlock, but will certainly not produce the desired output. From 6cc566645eade9319b02a0ef444bfc4060e128e8 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Wed, 12 Mar 2025 21:07:48 +0100 Subject: [PATCH 0813/1217] Update Rust stable, nightly. --- rust-toolchain-nightly.toml | 2 +- rust-toolchain.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-toolchain-nightly.toml b/rust-toolchain-nightly.toml index 8faa1a073..d803b29a0 100644 --- a/rust-toolchain-nightly.toml +++ b/rust-toolchain-nightly.toml @@ -1,5 +1,5 @@ [toolchain] -channel = "nightly-2025-02-17" +channel = "nightly-2025-03-12" components = [ "rust-src", "rustfmt", "llvm-tools", "miri" ] targets = [ "thumbv7em-none-eabi", diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 73c97872c..ca5816121 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,5 +1,5 @@ [toolchain] -channel = "1.84" +channel = "1.85" components = [ "rust-src", "rustfmt", "llvm-tools" ] targets = [ "thumbv7em-none-eabi", From 59370cde280ea7e86821b430b4adb22a7343315c Mon Sep 17 00:00:00 2001 From: sodo Date: Fri, 21 Feb 2025 22:37:58 +0900 Subject: [PATCH 0814/1217] avr: Change ci-nightly target from `avr-unknown-gnu-atmega328` to `avr-none` Related to: https://github.com/rust-lang/rust/pull/131651 Signed-off-by: sodo --- ci-nightly.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci-nightly.sh b/ci-nightly.sh index e48ad2323..c0a2482e7 100755 --- a/ci-nightly.sh +++ b/ci-nightly.sh @@ -22,4 +22,4 @@ cargo batch \ --- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features nightly,arch-riscv32,executor-thread \ --- build --release --manifest-path examples/nrf52840-rtic/Cargo.toml --target thumbv7em-none-eabi --artifact-dir out/examples/nrf52840-rtic \ -cargo build --release --manifest-path embassy-executor/Cargo.toml --target avr-unknown-gnu-atmega328 -Z build-std=core,alloc --features nightly,arch-avr,avr-device/atmega328p +RUSTFLAGS="$RUSTFLAGS -C target-cpu=atmega328p" cargo build --release --manifest-path embassy-executor/Cargo.toml --target avr-none -Z build-std=core,alloc --features nightly,arch-avr,avr-device/atmega328p From f1db070f78ddbef92c8e14db43b4422b9a14c926 Mon Sep 17 00:00:00 2001 From: elagil Date: Wed, 12 Mar 2025 23:18:34 +0100 Subject: [PATCH 0815/1217] feat: add optional USB SOF output --- embassy-stm32/build.rs | 1 + embassy-stm32/src/usb/usb.rs | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 83a836fb2..b35fd0300 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -876,6 +876,7 @@ fn main() { (("ltdc", "B7"), quote!(crate::ltdc::B7Pin)), (("usb", "DP"), quote!(crate::usb::DpPin)), (("usb", "DM"), quote!(crate::usb::DmPin)), + (("usb", "SOF"), quote!(crate::usb::SofPin)), (("otg", "DP"), quote!(crate::usb::DpPin)), (("otg", "DM"), quote!(crate::usb::DmPin)), (("otg", "ULPI_CK"), quote!(crate::usb::UlpiClkPin)), diff --git a/embassy-stm32/src/usb/usb.rs b/embassy-stm32/src/usb/usb.rs index b9a16bbf1..af639fc9b 100644 --- a/embassy-stm32/src/usb/usb.rs +++ b/embassy-stm32/src/usb/usb.rs @@ -287,6 +287,26 @@ pub struct Driver<'d, T: Instance> { } impl<'d, T: Instance> Driver<'d, T> { + /// Create a new USB driver with start-of-frame (SOF) output. + pub fn new_with_sof( + _usb: impl Peripheral

+ 'd, + _irq: impl interrupt::typelevel::Binding> + 'd, + dp: impl Peripheral

> + 'd, + dm: impl Peripheral

> + 'd, + sof: impl Peripheral

> + 'd, + ) -> Self { + into_ref!(sof); + #[cfg(not(stm32l1))] + { + use crate::gpio::{AfType, OutputType, Speed}; + sof.set_as_af(sof.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh)); + } + #[cfg(stm32l1)] + let _ = sof; // suppress "unused" warning. + + Self::new(_usb, _irq, dp, dm) + } + /// Create a new USB driver. pub fn new( _usb: impl Peripheral

+ 'd, @@ -1208,6 +1228,7 @@ pub trait Instance: SealedInstance + RccPeripheral + 'static { // Internal PHY pins pin_trait!(DpPin, Instance); pin_trait!(DmPin, Instance); +pin_trait!(SofPin, Instance); foreach_interrupt!( ($inst:ident, usb, $block:ident, LP, $irq:ident) => { From e0cdc356ccd7f9e20c2b5355cc52b7eb7610147b Mon Sep 17 00:00:00 2001 From: i509VCB Date: Thu, 13 Mar 2025 22:10:45 -0500 Subject: [PATCH 0816/1217] Embassy for MSPM0 This adds an embassy hal for the Texas Instruments MSPM0 microcontroller series. So far the GPIO and time drivers have been implemented. I have tested these drivers on the following parts: - C1104 - L1306 - L2228 - G3507 - G3519 The PAC is generated at https://github.com/mspm0-rs --- .vscode/settings.json | 5 + embassy-mspm0/Cargo.toml | 125 ++ embassy-mspm0/build.rs | 616 ++++++++++ embassy-mspm0/build_common.rs | 94 ++ embassy-mspm0/src/fmt.rs | 270 +++++ embassy-mspm0/src/gpio.rs | 1070 +++++++++++++++++ embassy-mspm0/src/int_group/c110x.rs | 25 + embassy-mspm0/src/int_group/g350x.rs | 51 + embassy-mspm0/src/int_group/g351x.rs | 52 + embassy-mspm0/src/int_group/l130x.rs | 46 + embassy-mspm0/src/int_group/l222x.rs | 49 + embassy-mspm0/src/lib.rs | 112 ++ embassy-mspm0/src/time_driver.rs | 437 +++++++ embassy-mspm0/src/timer.rs | 48 + examples/mspm0c1104/.cargo/config.toml | 11 + examples/mspm0c1104/Cargo.toml | 32 + examples/mspm0c1104/README.md | 27 + examples/mspm0c1104/build.rs | 35 + examples/mspm0c1104/memory.x | 5 + examples/mspm0c1104/src/bin/blinky.rs | 27 + examples/mspm0c1104/src/bin/button.rs | 35 + examples/mspm0g3507/.cargo/config.toml | 9 + examples/mspm0g3507/Cargo.toml | 21 + examples/mspm0g3507/README.md | 27 + examples/mspm0g3507/build.rs | 35 + examples/mspm0g3507/memory.x | 6 + examples/mspm0g3507/src/bin/blinky.rs | 27 + examples/mspm0g3507/src/bin/button.rs | 35 + examples/mspm0g3519/.cargo/config.toml | 10 + examples/mspm0g3519/Cargo.toml | 21 + examples/mspm0g3519/MSPM0GX51X_Series.yaml | 424 +++++++ examples/mspm0g3519/README.md | 27 + examples/mspm0g3519/build.rs | 35 + examples/mspm0g3519/memory.x | 6 + examples/mspm0g3519/src/bin/blinky.rs | 27 + examples/mspm0g3519/src/bin/button.rs | 35 + examples/mspm0l1306/.cargo/config.toml | 9 + examples/mspm0l1306/Cargo.toml | 21 + examples/mspm0l1306/README.md | 27 + examples/mspm0l1306/build.rs | 35 + examples/mspm0l1306/memory.x | 5 + examples/mspm0l1306/src/bin/blinky.rs | 27 + examples/mspm0l1306/src/bin/button.rs | 35 + examples/mspm0l2228/.cargo/config.toml | 10 + examples/mspm0l2228/Cargo.toml | 21 + .../mspm0l2228/MSPM0L122X_L222X_Series.yaml | 239 ++++ examples/mspm0l2228/README.md | 27 + examples/mspm0l2228/build.rs | 35 + examples/mspm0l2228/memory.x | 6 + examples/mspm0l2228/src/bin/blinky.rs | 27 + examples/mspm0l2228/src/bin/button.rs | 35 + 51 files changed, 4476 insertions(+) create mode 100644 embassy-mspm0/Cargo.toml create mode 100644 embassy-mspm0/build.rs create mode 100644 embassy-mspm0/build_common.rs create mode 100644 embassy-mspm0/src/fmt.rs create mode 100644 embassy-mspm0/src/gpio.rs create mode 100644 embassy-mspm0/src/int_group/c110x.rs create mode 100644 embassy-mspm0/src/int_group/g350x.rs create mode 100644 embassy-mspm0/src/int_group/g351x.rs create mode 100644 embassy-mspm0/src/int_group/l130x.rs create mode 100644 embassy-mspm0/src/int_group/l222x.rs create mode 100644 embassy-mspm0/src/lib.rs create mode 100644 embassy-mspm0/src/time_driver.rs create mode 100644 embassy-mspm0/src/timer.rs create mode 100644 examples/mspm0c1104/.cargo/config.toml create mode 100644 examples/mspm0c1104/Cargo.toml create mode 100644 examples/mspm0c1104/README.md create mode 100644 examples/mspm0c1104/build.rs create mode 100644 examples/mspm0c1104/memory.x create mode 100644 examples/mspm0c1104/src/bin/blinky.rs create mode 100644 examples/mspm0c1104/src/bin/button.rs create mode 100644 examples/mspm0g3507/.cargo/config.toml create mode 100644 examples/mspm0g3507/Cargo.toml create mode 100644 examples/mspm0g3507/README.md create mode 100644 examples/mspm0g3507/build.rs create mode 100644 examples/mspm0g3507/memory.x create mode 100644 examples/mspm0g3507/src/bin/blinky.rs create mode 100644 examples/mspm0g3507/src/bin/button.rs create mode 100644 examples/mspm0g3519/.cargo/config.toml create mode 100644 examples/mspm0g3519/Cargo.toml create mode 100644 examples/mspm0g3519/MSPM0GX51X_Series.yaml create mode 100644 examples/mspm0g3519/README.md create mode 100644 examples/mspm0g3519/build.rs create mode 100644 examples/mspm0g3519/memory.x create mode 100644 examples/mspm0g3519/src/bin/blinky.rs create mode 100644 examples/mspm0g3519/src/bin/button.rs create mode 100644 examples/mspm0l1306/.cargo/config.toml create mode 100644 examples/mspm0l1306/Cargo.toml create mode 100644 examples/mspm0l1306/README.md create mode 100644 examples/mspm0l1306/build.rs create mode 100644 examples/mspm0l1306/memory.x create mode 100644 examples/mspm0l1306/src/bin/blinky.rs create mode 100644 examples/mspm0l1306/src/bin/button.rs create mode 100644 examples/mspm0l2228/.cargo/config.toml create mode 100644 examples/mspm0l2228/Cargo.toml create mode 100644 examples/mspm0l2228/MSPM0L122X_L222X_Series.yaml create mode 100644 examples/mspm0l2228/README.md create mode 100644 examples/mspm0l2228/build.rs create mode 100644 examples/mspm0l2228/memory.x create mode 100644 examples/mspm0l2228/src/bin/blinky.rs create mode 100644 examples/mspm0l2228/src/bin/button.rs diff --git a/.vscode/settings.json b/.vscode/settings.json index 48d0957e6..e4814ff27 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -28,6 +28,11 @@ // To work on the examples, comment the line above and all of the cargo.features lines, // then uncomment ONE line below to select the chip you want to work on. // This makes rust-analyzer work on the example crate and all its dependencies. + // "examples/mspm0c1104/Cargo.toml", + // "examples/mspm0g3507/Cargo.toml", + // "examples/mspm0g3519/Cargo.toml", + // "examples/mspm0l1306/Cargo.toml", + // "examples/mspm0l2228/Cargo.toml", // "examples/nrf52840-rtic/Cargo.toml", // "examples/nrf5340/Cargo.toml", // "examples/nrf-rtos-trace/Cargo.toml", diff --git a/embassy-mspm0/Cargo.toml b/embassy-mspm0/Cargo.toml new file mode 100644 index 000000000..0f4092d8a --- /dev/null +++ b/embassy-mspm0/Cargo.toml @@ -0,0 +1,125 @@ +[package] +name = "embassy-mspm0" +version = "0.1.0" +edition = "2021" +license = "MIT OR Apache-2.0" +description = "Embassy Hardware Abstraction Layer (HAL) for Texas Instruments MSPM0 series microcontrollers" +keywords = ["embedded", "async", "mspm0", "hal", "embedded-hal"] +categories = ["embedded", "hardware-support", "no-std", "asynchronous"] +repository = "https://github.com/embassy-rs/embassy" +documentation = "https://docs.embassy.dev/embassy-mspm0" + +[package.metadata.docs.rs] +features = ["defmt", "unstable-pac", "time-driver-any", "time", "mspm0g3507"] +rustdoc-args = ["--cfg", "docsrs"] + +[dependencies] +embassy-sync = { version = "0.6.2", path = "../embassy-sync" } +embassy-time = { version = "0.4.0", path = "../embassy-time", optional = true } +# TODO: Support other tick rates +embassy-time-driver = { version = "0.2", path = "../embassy-time-driver", optional = true, features = ["tick-hz-32_768"] } +embassy-time-queue-utils = { version = "0.1", path = "../embassy-time-queue-utils", optional = true } +embassy-futures = { version = "0.1.0", path = "../embassy-futures" } +embassy-hal-internal = { version = "0.2.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-2"] } +embassy-embedded-hal = { version = "0.3.0", path = "../embassy-embedded-hal", default-features = false } +embassy-executor = { version = "0.7.0", path = "../embassy-executor", optional = true } + +embedded-hal = { version = "1.0" } +embedded-hal-async = { version = "1.0" } + +defmt = { version = "0.3", optional = true } +log = { version = "0.4.14", optional = true } +cortex-m-rt = ">=0.6.15,<0.8" +cortex-m = "0.7.6" +critical-section = "1.2.0" + +# mspm0-metapac = { version = "" } +mspm0-metapac = { git = "https://github.com/mspm0-rs/mspm0-data-generated/", tag = "mspm0-data-9faa5239a8eab04946086158f2a7fdff5a6a179d" } + +[build-dependencies] +proc-macro2 = "1.0.94" +quote = "1.0.40" + +# mspm0-metapac = { version = "", default-features = false, features = ["metadata"] } +mspm0-metapac = { git = "https://github.com/mspm0-rs/mspm0-data-generated/", tag = "mspm0-data-9faa5239a8eab04946086158f2a7fdff5a6a179d", default-features = false, features = ["metadata"] } + +[features] +default = ["rt"] + +## Enable `mspm0-metapac`'s `rt` feature +rt = ["mspm0-metapac/rt"] + +## Use [`defmt`](https://docs.rs/defmt/latest/defmt/) for logging +defmt = [ + "dep:defmt", + "embassy-sync/defmt", + "embassy-embedded-hal/defmt", + "embassy-hal-internal/defmt", + "embassy-time?/defmt", +] + +## Re-export mspm0-metapac at `mspm0::pac`. +## This is unstable because semver-minor (non-breaking) releases of embassy-mspm0 may major-bump (breaking) the mspm0-metapac version. +## If this is an issue for you, you're encouraged to directly depend on a fixed version of the PAC. +## There are no plans to make this stable. +unstable-pac = [] + +#! ## Time + +# Features starting with `_` are for internal use only. They're not intended +# to be enabled by other crates, and are not covered by semver guarantees. +_time-driver = ["dep:embassy-time-driver", "dep:embassy-time-queue-utils"] + +# Use any time driver +time-driver-any = ["_time-driver"] +## Use TIMG0 as time driver +time-driver-timg0 = ["_time-driver"] +## Use TIMG1 as time driver +time-driver-timg1 = ["_time-driver"] +## Use TIMG2 as time driver +time-driver-timg2 = ["_time-driver"] +## Use TIMG3 as time driver +time-driver-timg3 = ["_time-driver"] +## Use TIMG4 as time driver +time-driver-timg4 = ["_time-driver"] +## Use TIMG5 as time driver +time-driver-timg5 = ["_time-driver"] +## Use TIMG6 as time driver +time-driver-timg6 = ["_time-driver"] +## Use TIMG7 as time driver +time-driver-timg7 = ["_time-driver"] +## Use TIMG8 as time driver +time-driver-timg8 = ["_time-driver"] +## Use TIMG9 as time driver +time-driver-timg9 = ["_time-driver"] +## Use TIMG10 as time driver +time-driver-timg10 = ["_time-driver"] +## Use TIMG11 as time driver +time-driver-timg11 = ["_time-driver"] +# TODO: Support TIMG12 and TIMG13 +## Use TIMG14 as time driver +time-driver-timg14 = ["_time-driver"] +## Use TIMA0 as time driver +time-driver-tima0 = ["_time-driver"] +## Use TIMA1 as time driver +time-driver-tima1 = ["_time-driver"] + +#! ## Chip-selection features +#! Select your chip by specifying the model as a feature, e.g. `mspm0g3507`. +#! Check the `Cargo.toml` for the latest list of supported chips. +#! +#! **Important:** Do not forget to adapt the target chip in your toolchain, +#! e.g. in `.cargo/config.toml`. + +mspm0c110x = [ "mspm0-metapac/mspm0c110x" ] +mspm0g110x = [ "mspm0-metapac/mspm0g110x" ] +mspm0g150x = [ "mspm0-metapac/mspm0g150x" ] +mspm0g151x = [ "mspm0-metapac/mspm0g151x" ] +mspm0g310x = [ "mspm0-metapac/mspm0g310x" ] +mspm0g350x = [ "mspm0-metapac/mspm0g350x" ] +mspm0g351x = [ "mspm0-metapac/mspm0g351x" ] +mspm0l110x = [ "mspm0-metapac/mspm0l110x" ] +mspm0l122x = [ "mspm0-metapac/mspm0l122x" ] +mspm0l130x = [ "mspm0-metapac/mspm0l130x" ] +mspm0l134x = [ "mspm0-metapac/mspm0l134x" ] +mspm0l222x = [ "mspm0-metapac/mspm0l222x" ] diff --git a/embassy-mspm0/build.rs b/embassy-mspm0/build.rs new file mode 100644 index 000000000..ffbe15c56 --- /dev/null +++ b/embassy-mspm0/build.rs @@ -0,0 +1,616 @@ +use std::collections::HashMap; +use std::io::Write; +use std::path::{Path, PathBuf}; +use std::process::Command; +use std::sync::LazyLock; +use std::{env, fs}; + +use common::CfgSet; +use mspm0_metapac::metadata::METADATA; +use proc_macro2::{Ident, Literal, Span, TokenStream}; +use quote::{format_ident, quote}; + +#[path = "./build_common.rs"] +mod common; + +fn main() { + generate_code(); +} + +fn generate_code() { + let mut cfgs = common::CfgSet::new(); + common::set_target_cfgs(&mut cfgs); + + cfgs.declare_all(&["gpio_pb", "gpio_pc", "int_group1"]); + + let mut singletons = Vec::new(); + + // Generate singletons for GPIO pins. To only consider pins available on a family, use the name of + // the pins from the pincm mappings. + for pincm_mapping in METADATA.pincm_mappings.iter() { + singletons.push(pincm_mapping.pin.to_string()); + } + + for peri in METADATA.peripherals { + match peri.kind { + // Specially generated. + "gpio" => match peri.name { + "GPIOB" => cfgs.enable("gpio_pb"), + "GPIOC" => cfgs.enable("gpio_pc"), + _ => (), + }, + + // These peripherals are managed internally by the hal. + "iomux" | "cpuss" => {} + + _ => singletons.push(peri.name.to_string()), + } + } + + time_driver(&singletons, &mut cfgs); + + // ======== + // Write singletons + let mut g = TokenStream::new(); + + let singleton_tokens: Vec<_> = singletons.iter().map(|s| format_ident!("{}", s)).collect(); + + g.extend(quote! { + embassy_hal_internal::peripherals_definition!(#(#singleton_tokens),*); + }); + + g.extend(quote! { + embassy_hal_internal::peripherals_struct!(#(#singleton_tokens),*); + }); + + // ======== + // Generate GPIO pincm lookup tables. + let pincms = METADATA.pincm_mappings.iter().map(|mapping| { + let port_letter = mapping.pin.strip_prefix("P").unwrap(); + let port_base = (port_letter.chars().next().unwrap() as u8 - b'A') * 32; + // This assumes all ports are single letter length. + // This is fine unless TI releases a part with 833+ GPIO pins. + let pin_number = mapping.pin[2..].parse::().unwrap(); + + let num = port_base + pin_number; + + // But subtract 1 since pincm indices start from 0, not 1. + let pincm = Literal::u8_unsuffixed(mapping.pincm - 1); + quote! { + #num => #pincm + } + }); + + g.extend(quote! { + #[doc = "Get the mapping from GPIO pin port to IOMUX PINCM index. This is required since the mapping from IO to PINCM index is not consistent across parts."] + pub(crate) fn gpio_pincm(pin_port: u8) -> u8 { + match pin_port { + #(#pincms),*, + _ => unreachable!(), + } + } + }); + + for pincm_mapping in METADATA.pincm_mappings.iter() { + let name = Ident::new(&pincm_mapping.pin, Span::call_site()); + let port_letter = pincm_mapping.pin.strip_prefix("P").unwrap(); + let port_letter = port_letter.chars().next().unwrap(); + let pin_number = Literal::u8_unsuffixed(pincm_mapping.pin[2..].parse::().unwrap()); + + let port = Ident::new(&format!("Port{}", port_letter), Span::call_site()); + + // TODO: Feature gate pins that can be used as NRST + + g.extend(quote! { + impl_pin!(#name, crate::gpio::Port::#port, #pin_number); + }); + } + + // Generate timers + for peripheral in METADATA + .peripherals + .iter() + .filter(|p| p.name.starts_with("TIM")) + { + let name = Ident::new(&peripheral.name, Span::call_site()); + let timers = &*TIMERS; + + let timer = timers.get(peripheral.name).expect("Timer does not exist"); + assert!(timer.bits == 16 || timer.bits == 32); + let bits = if timer.bits == 16 { + quote! { Bits16 } + } else { + quote! { Bits32 } + }; + + g.extend(quote! { + impl_timer!(#name, #bits); + }); + } + + // Generate interrupt module + let interrupts: Vec = METADATA + .interrupts + .iter() + .map(|interrupt| Ident::new(interrupt.name, Span::call_site())) + .collect(); + + g.extend(quote! { + embassy_hal_internal::interrupt_mod! { + #(#interrupts),* + } + }); + + let group_interrupt_enables = METADATA + .interrupts + .iter() + .filter(|interrupt| interrupt.name.contains("GROUP")) + .map(|interrupt| { + let name = Ident::new(interrupt.name, Span::call_site()); + + quote! { + crate::interrupt::typelevel::#name::enable(); + } + }); + + // Generate interrupt enables for groups + g.extend(quote! { + pub fn enable_group_interrupts(_cs: critical_section::CriticalSection) { + use crate::interrupt::typelevel::Interrupt; + + unsafe { + #(#group_interrupt_enables)* + } + } + }); + + let out_dir = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); + let out_file = out_dir.join("_generated.rs").to_string_lossy().to_string(); + fs::write(&out_file, g.to_string()).unwrap(); + rustfmt(&out_file); +} + +fn time_driver(singletons: &[String], cfgs: &mut CfgSet) { + // Timer features + for (timer, desc) in TIMERS.iter() { + if desc.bits != 16 { + continue; + } + + let name = timer.to_lowercase(); + cfgs.declare(&format!("time_driver_{}", name)); + } + + let time_driver = match env::vars() + .map(|(a, _)| a) + .filter(|x| x.starts_with("CARGO_FEATURE_TIME_DRIVER_")) + .get_one() + { + Ok(x) => Some( + x.strip_prefix("CARGO_FEATURE_TIME_DRIVER_") + .unwrap() + .to_ascii_lowercase(), + ), + Err(GetOneError::None) => None, + Err(GetOneError::Multiple) => panic!("Multiple time-driver-xxx Cargo features enabled"), + }; + + // Verify the selected timer is available + let singleton = match time_driver.as_ref().map(|x| x.as_ref()) { + None => "", + Some("timg0") => "TIMG0", + Some("timg1") => "TIMG1", + Some("timg2") => "TIMG2", + Some("timg3") => "TIMG3", + Some("timg4") => "TIMG4", + Some("timg5") => "TIMG5", + Some("timg6") => "TIMG6", + Some("timg7") => "TIMG7", + Some("timg8") => "TIMG8", + Some("timg9") => "TIMG9", + Some("timg10") => "TIMG10", + Some("timg11") => "TIMG11", + Some("timg14") => "TIMG14", + Some("tima0") => "TIMA0", + Some("tima1") => "TIMA1", + Some("any") => { + // Order of timer candidates: + // 1. 16-bit, 2 channel + // 2. 16-bit, 2 channel with shadow registers + // 3. 16-bit, 4 channel + // 4. 16-bit with QEI + // 5. Advanced timers + // + // TODO: Select RTC first if available + // TODO: 32-bit timers are not considered yet + [ + // 16-bit, 2 channel + "TIMG0", "TIMG1", "TIMG2", "TIMG3", + // 16-bit, 2 channel with shadow registers + "TIMG4", "TIMG5", "TIMG6", "TIMG7", // 16-bit, 4 channel + "TIMG14", // 16-bit with QEI + "TIMG8", "TIMG9", "TIMG10", "TIMG11", // Advanced timers + "TIMA0", "TIMA1", + ] + .iter() + .find(|tim| singletons.contains(&tim.to_string())) + .expect("Could not find any timer") + } + _ => panic!("unknown time_driver {:?}", time_driver), + }; + + if !singleton.is_empty() { + cfgs.enable(format!("time_driver_{}", singleton.to_lowercase())); + } +} + +/// rustfmt a given path. +/// Failures are logged to stderr and ignored. +fn rustfmt(path: impl AsRef) { + let path = path.as_ref(); + match Command::new("rustfmt").args([path]).output() { + Err(e) => { + eprintln!("failed to exec rustfmt {:?}: {:?}", path, e); + } + Ok(out) => { + if !out.status.success() { + eprintln!("rustfmt {:?} failed:", path); + eprintln!("=== STDOUT:"); + std::io::stderr().write_all(&out.stdout).unwrap(); + eprintln!("=== STDERR:"); + std::io::stderr().write_all(&out.stderr).unwrap(); + } + } + } +} + +#[allow(dead_code)] +struct TimerDesc { + bits: u8, + /// Is there an 8-bit prescaler + prescaler: bool, + /// Is there a repeat counter + repeat_counter: bool, + ccp_channels_internal: u8, + ccp_channels_external: u8, + external_pwm_channels: u8, + phase_load: bool, + shadow_load: bool, + shadow_ccs: bool, + deadband: bool, + fault_handler: bool, + qei_hall: bool, +} + +/// Description of all timer instances. +const TIMERS: LazyLock> = LazyLock::new(|| { + let mut map = HashMap::new(); + map.insert( + "TIMG0".into(), + TimerDesc { + bits: 16, + prescaler: true, + repeat_counter: false, + ccp_channels_internal: 2, + ccp_channels_external: 2, + external_pwm_channels: 2, + phase_load: false, + shadow_load: false, + shadow_ccs: false, + deadband: false, + fault_handler: false, + qei_hall: false, + }, + ); + + map.insert( + "TIMG1".into(), + TimerDesc { + bits: 16, + prescaler: true, + repeat_counter: false, + ccp_channels_internal: 2, + ccp_channels_external: 2, + external_pwm_channels: 2, + phase_load: false, + shadow_load: false, + shadow_ccs: false, + deadband: false, + fault_handler: false, + qei_hall: false, + }, + ); + + map.insert( + "TIMG2".into(), + TimerDesc { + bits: 16, + prescaler: true, + repeat_counter: false, + ccp_channels_internal: 2, + ccp_channels_external: 2, + external_pwm_channels: 2, + phase_load: false, + shadow_load: false, + shadow_ccs: false, + deadband: false, + fault_handler: false, + qei_hall: false, + }, + ); + + map.insert( + "TIMG3".into(), + TimerDesc { + bits: 16, + prescaler: true, + repeat_counter: false, + ccp_channels_internal: 2, + ccp_channels_external: 2, + external_pwm_channels: 2, + phase_load: false, + shadow_load: false, + shadow_ccs: false, + deadband: false, + fault_handler: false, + qei_hall: false, + }, + ); + + map.insert( + "TIMG4".into(), + TimerDesc { + bits: 16, + prescaler: true, + repeat_counter: false, + ccp_channels_internal: 2, + ccp_channels_external: 2, + external_pwm_channels: 2, + phase_load: false, + shadow_load: true, + shadow_ccs: true, + deadband: false, + fault_handler: false, + qei_hall: false, + }, + ); + + map.insert( + "TIMG5".into(), + TimerDesc { + bits: 16, + prescaler: true, + repeat_counter: false, + ccp_channels_internal: 2, + ccp_channels_external: 2, + external_pwm_channels: 2, + phase_load: false, + shadow_load: true, + shadow_ccs: true, + deadband: false, + fault_handler: false, + qei_hall: false, + }, + ); + + map.insert( + "TIMG6".into(), + TimerDesc { + bits: 16, + prescaler: true, + repeat_counter: false, + ccp_channels_internal: 2, + ccp_channels_external: 2, + external_pwm_channels: 2, + phase_load: false, + shadow_load: true, + shadow_ccs: true, + deadband: false, + fault_handler: false, + qei_hall: false, + }, + ); + + map.insert( + "TIMG7".into(), + TimerDesc { + bits: 16, + prescaler: true, + repeat_counter: false, + ccp_channels_internal: 2, + ccp_channels_external: 2, + external_pwm_channels: 2, + phase_load: false, + shadow_load: true, + shadow_ccs: true, + deadband: false, + fault_handler: false, + qei_hall: false, + }, + ); + + map.insert( + "TIMG8".into(), + TimerDesc { + bits: 16, + prescaler: true, + repeat_counter: false, + ccp_channels_internal: 2, + ccp_channels_external: 2, + external_pwm_channels: 2, + phase_load: false, + shadow_load: false, + shadow_ccs: false, + deadband: false, + fault_handler: false, + qei_hall: true, + }, + ); + + map.insert( + "TIMG9".into(), + TimerDesc { + bits: 16, + prescaler: true, + repeat_counter: false, + ccp_channels_internal: 2, + ccp_channels_external: 2, + external_pwm_channels: 2, + phase_load: false, + shadow_load: false, + shadow_ccs: false, + deadband: false, + fault_handler: false, + qei_hall: true, + }, + ); + + map.insert( + "TIMG10".into(), + TimerDesc { + bits: 16, + prescaler: true, + repeat_counter: false, + ccp_channels_internal: 2, + ccp_channels_external: 2, + external_pwm_channels: 2, + phase_load: false, + shadow_load: false, + shadow_ccs: false, + deadband: false, + fault_handler: false, + qei_hall: true, + }, + ); + + map.insert( + "TIMG11".into(), + TimerDesc { + bits: 16, + prescaler: true, + repeat_counter: false, + ccp_channels_internal: 2, + ccp_channels_external: 2, + external_pwm_channels: 2, + phase_load: false, + shadow_load: false, + shadow_ccs: false, + deadband: false, + fault_handler: false, + qei_hall: true, + }, + ); + + map.insert( + "TIMG12".into(), + TimerDesc { + bits: 32, + prescaler: false, + repeat_counter: false, + ccp_channels_internal: 2, + ccp_channels_external: 2, + external_pwm_channels: 2, + phase_load: false, + shadow_load: false, + shadow_ccs: true, + deadband: false, + fault_handler: false, + qei_hall: false, + }, + ); + + map.insert( + "TIMG13".into(), + TimerDesc { + bits: 32, + prescaler: false, + repeat_counter: false, + ccp_channels_internal: 2, + ccp_channels_external: 2, + external_pwm_channels: 2, + phase_load: false, + shadow_load: false, + shadow_ccs: true, + deadband: false, + fault_handler: false, + qei_hall: false, + }, + ); + + map.insert( + "TIMG14".into(), + TimerDesc { + bits: 16, + prescaler: true, + repeat_counter: false, + ccp_channels_internal: 4, + ccp_channels_external: 4, + external_pwm_channels: 4, + phase_load: false, + shadow_load: false, + shadow_ccs: false, + deadband: false, + fault_handler: false, + qei_hall: false, + }, + ); + + map.insert( + "TIMA0".into(), + TimerDesc { + bits: 16, + prescaler: true, + repeat_counter: true, + ccp_channels_internal: 4, + ccp_channels_external: 2, + external_pwm_channels: 8, + phase_load: true, + shadow_load: true, + shadow_ccs: true, + deadband: true, + fault_handler: true, + qei_hall: false, + }, + ); + + map.insert( + "TIMA1".into(), + TimerDesc { + bits: 16, + prescaler: true, + repeat_counter: true, + ccp_channels_internal: 2, + ccp_channels_external: 2, + external_pwm_channels: 4, + phase_load: true, + shadow_load: true, + shadow_ccs: true, + deadband: true, + fault_handler: true, + qei_hall: false, + }, + ); + + map +}); + +enum GetOneError { + None, + Multiple, +} + +trait IteratorExt: Iterator { + fn get_one(self) -> Result; +} + +impl IteratorExt for T { + fn get_one(mut self) -> Result { + match self.next() { + None => Err(GetOneError::None), + Some(res) => match self.next() { + Some(_) => Err(GetOneError::Multiple), + None => Ok(res), + }, + } + } +} diff --git a/embassy-mspm0/build_common.rs b/embassy-mspm0/build_common.rs new file mode 100644 index 000000000..4f24e6d37 --- /dev/null +++ b/embassy-mspm0/build_common.rs @@ -0,0 +1,94 @@ +// NOTE: this file is copy-pasted between several Embassy crates, because there is no +// straightforward way to share this code: +// - it cannot be placed into the root of the repo and linked from each build.rs using `#[path = +// "../build_common.rs"]`, because `cargo publish` requires that all files published with a crate +// reside in the crate's directory, +// - it cannot be symlinked from `embassy-xxx/build_common.rs` to `../build_common.rs`, because +// symlinks don't work on Windows. + +use std::collections::HashSet; +use std::env; + +/// Helper for emitting cargo instruction for enabling configs (`cargo:rustc-cfg=X`) and declaring +/// them (`cargo:rust-check-cfg=cfg(X)`). +#[derive(Debug)] +pub struct CfgSet { + enabled: HashSet, + declared: HashSet, +} + +impl CfgSet { + pub fn new() -> Self { + Self { + enabled: HashSet::new(), + declared: HashSet::new(), + } + } + + /// Enable a config, which can then be used in `#[cfg(...)]` for conditional compilation. + /// + /// All configs that can potentially be enabled should be unconditionally declared using + /// [`Self::declare()`]. + pub fn enable(&mut self, cfg: impl AsRef) { + if self.enabled.insert(cfg.as_ref().to_owned()) { + println!("cargo:rustc-cfg={}", cfg.as_ref()); + } + } + + pub fn enable_all(&mut self, cfgs: &[impl AsRef]) { + for cfg in cfgs.iter() { + self.enable(cfg.as_ref()); + } + } + + /// Declare a valid config for conditional compilation, without enabling it. + /// + /// This enables rustc to check that the configs in `#[cfg(...)]` attributes are valid. + pub fn declare(&mut self, cfg: impl AsRef) { + if self.declared.insert(cfg.as_ref().to_owned()) { + println!("cargo:rustc-check-cfg=cfg({})", cfg.as_ref()); + } + } + + pub fn declare_all(&mut self, cfgs: &[impl AsRef]) { + for cfg in cfgs.iter() { + self.declare(cfg.as_ref()); + } + } + + pub fn set(&mut self, cfg: impl Into, enable: bool) { + let cfg = cfg.into(); + if enable { + self.enable(cfg.clone()); + } + self.declare(cfg); + } +} + +/// Sets configs that describe the target platform. +pub fn set_target_cfgs(cfgs: &mut CfgSet) { + let target = env::var("TARGET").unwrap(); + + if target.starts_with("thumbv6m-") { + cfgs.enable_all(&["cortex_m", "armv6m"]); + } else if target.starts_with("thumbv7m-") { + cfgs.enable_all(&["cortex_m", "armv7m"]); + } else if target.starts_with("thumbv7em-") { + cfgs.enable_all(&["cortex_m", "armv7m", "armv7em"]); + } else if target.starts_with("thumbv8m.base") { + cfgs.enable_all(&["cortex_m", "armv8m", "armv8m_base"]); + } else if target.starts_with("thumbv8m.main") { + cfgs.enable_all(&["cortex_m", "armv8m", "armv8m_main"]); + } + cfgs.declare_all(&[ + "cortex_m", + "armv6m", + "armv7m", + "armv7em", + "armv8m", + "armv8m_base", + "armv8m_main", + ]); + + cfgs.set("has_fpu", target.ends_with("-eabihf")); +} diff --git a/embassy-mspm0/src/fmt.rs b/embassy-mspm0/src/fmt.rs new file mode 100644 index 000000000..8ca61bc39 --- /dev/null +++ b/embassy-mspm0/src/fmt.rs @@ -0,0 +1,270 @@ +#![macro_use] +#![allow(unused)] + +use core::fmt::{Debug, Display, LowerHex}; + +#[cfg(all(feature = "defmt", feature = "log"))] +compile_error!("You may not enable both `defmt` and `log` features."); + +#[collapse_debuginfo(yes)] +macro_rules! assert { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::assert!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::assert!($($x)*); + } + }; +} + +#[collapse_debuginfo(yes)] +macro_rules! assert_eq { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::assert_eq!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::assert_eq!($($x)*); + } + }; +} + +#[collapse_debuginfo(yes)] +macro_rules! assert_ne { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::assert_ne!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::assert_ne!($($x)*); + } + }; +} + +#[collapse_debuginfo(yes)] +macro_rules! debug_assert { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::debug_assert!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::debug_assert!($($x)*); + } + }; +} + +#[collapse_debuginfo(yes)] +macro_rules! debug_assert_eq { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::debug_assert_eq!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::debug_assert_eq!($($x)*); + } + }; +} + +#[collapse_debuginfo(yes)] +macro_rules! debug_assert_ne { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::debug_assert_ne!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::debug_assert_ne!($($x)*); + } + }; +} + +#[collapse_debuginfo(yes)] +macro_rules! todo { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::todo!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::todo!($($x)*); + } + }; +} + +#[collapse_debuginfo(yes)] +macro_rules! unreachable { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::unreachable!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::unreachable!($($x)*); + } + }; +} + +#[collapse_debuginfo(yes)] +macro_rules! panic { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::panic!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::panic!($($x)*); + } + }; +} + +#[collapse_debuginfo(yes)] +macro_rules! trace { + ($s:literal $(, $x:expr)* $(,)?) => { + { + #[cfg(feature = "log")] + ::log::trace!($s $(, $x)*); + #[cfg(feature = "defmt")] + ::defmt::trace!($s $(, $x)*); + #[cfg(not(any(feature = "log", feature="defmt")))] + let _ = ($( & $x ),*); + } + }; +} + +#[collapse_debuginfo(yes)] +macro_rules! debug { + ($s:literal $(, $x:expr)* $(,)?) => { + { + #[cfg(feature = "log")] + ::log::debug!($s $(, $x)*); + #[cfg(feature = "defmt")] + ::defmt::debug!($s $(, $x)*); + #[cfg(not(any(feature = "log", feature="defmt")))] + let _ = ($( & $x ),*); + } + }; +} + +#[collapse_debuginfo(yes)] +macro_rules! info { + ($s:literal $(, $x:expr)* $(,)?) => { + { + #[cfg(feature = "log")] + ::log::info!($s $(, $x)*); + #[cfg(feature = "defmt")] + ::defmt::info!($s $(, $x)*); + #[cfg(not(any(feature = "log", feature="defmt")))] + let _ = ($( & $x ),*); + } + }; +} + +#[collapse_debuginfo(yes)] +macro_rules! warn { + ($s:literal $(, $x:expr)* $(,)?) => { + { + #[cfg(feature = "log")] + ::log::warn!($s $(, $x)*); + #[cfg(feature = "defmt")] + ::defmt::warn!($s $(, $x)*); + #[cfg(not(any(feature = "log", feature="defmt")))] + let _ = ($( & $x ),*); + } + }; +} + +#[collapse_debuginfo(yes)] +macro_rules! error { + ($s:literal $(, $x:expr)* $(,)?) => { + { + #[cfg(feature = "log")] + ::log::error!($s $(, $x)*); + #[cfg(feature = "defmt")] + ::defmt::error!($s $(, $x)*); + #[cfg(not(any(feature = "log", feature="defmt")))] + let _ = ($( & $x ),*); + } + }; +} + +#[cfg(feature = "defmt")] +#[collapse_debuginfo(yes)] +macro_rules! unwrap { + ($($x:tt)*) => { + ::defmt::unwrap!($($x)*) + }; +} + +#[cfg(not(feature = "defmt"))] +#[collapse_debuginfo(yes)] +macro_rules! unwrap { + ($arg:expr) => { + match $crate::fmt::Try::into_result($arg) { + ::core::result::Result::Ok(t) => t, + ::core::result::Result::Err(e) => { + ::core::panic!("unwrap of `{}` failed: {:?}", ::core::stringify!($arg), e); + } + } + }; + ($arg:expr, $($msg:expr),+ $(,)? ) => { + match $crate::fmt::Try::into_result($arg) { + ::core::result::Result::Ok(t) => t, + ::core::result::Result::Err(e) => { + ::core::panic!("unwrap of `{}` failed: {}: {:?}", ::core::stringify!($arg), ::core::format_args!($($msg,)*), e); + } + } + } +} + +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub struct NoneError; + +pub trait Try { + type Ok; + type Error; + fn into_result(self) -> Result; +} + +impl Try for Option { + type Ok = T; + type Error = NoneError; + + #[inline] + fn into_result(self) -> Result { + self.ok_or(NoneError) + } +} + +impl Try for Result { + type Ok = T; + type Error = E; + + #[inline] + fn into_result(self) -> Self { + self + } +} + +pub(crate) struct Bytes<'a>(pub &'a [u8]); + +impl<'a> Debug for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +impl<'a> Display for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +impl<'a> LowerHex for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +#[cfg(feature = "defmt")] +impl<'a> defmt::Format for Bytes<'a> { + fn format(&self, fmt: defmt::Formatter) { + defmt::write!(fmt, "{:02x}", self.0) + } +} diff --git a/embassy-mspm0/src/gpio.rs b/embassy-mspm0/src/gpio.rs new file mode 100644 index 000000000..fd4dc55ab --- /dev/null +++ b/embassy-mspm0/src/gpio.rs @@ -0,0 +1,1070 @@ +#![macro_use] + +use core::convert::Infallible; +use core::future::Future; +use core::pin::Pin as FuturePin; +use core::task::{Context, Poll}; + +use embassy_hal_internal::{impl_peripheral, into_ref, Peripheral, PeripheralRef}; +use embassy_sync::waitqueue::AtomicWaker; +#[cfg(all(feature = "rt", feature = "mspm0c110x"))] +use crate::pac::interrupt; + +use crate::pac::{ + self, + gpio::{self, vals::*}, +}; + +/// Represents a digital input or output level. +#[derive(Debug, Eq, PartialEq, Clone, Copy)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum Level { + /// Logical low. + Low, + /// Logical high. + High, +} + +impl From for Level { + fn from(val: bool) -> Self { + match val { + true => Self::High, + false => Self::Low, + } + } +} + +impl From for bool { + fn from(level: Level) -> bool { + match level { + Level::Low => false, + Level::High => true, + } + } +} + +/// Represents a pull setting for an input. +#[derive(Debug, Clone, Copy, Eq, PartialEq)] +pub enum Pull { + /// No pull. + None, + /// Internal pull-up resistor. + Up, + /// Internal pull-down resistor. + Down, +} + +/// A GPIO bank with up to 32 pins. +#[derive(Debug, Clone, Copy, Eq, PartialEq)] +pub enum Port { + /// Port A. + PortA = 0, + + /// Port B. + #[cfg(gpio_pb)] + PortB = 1, + + /// Port C. + #[cfg(gpio_pc)] + PortC = 2, +} + +/// GPIO flexible pin. +/// +/// This pin can either be a disconnected, input, or output pin, or both. The level register bit will remain +/// set while not in output mode, so the pin's level will be 'remembered' when it is not in output +/// mode. +pub struct Flex<'d> { + pin: PeripheralRef<'d, AnyPin>, +} + +impl<'d> Flex<'d> { + /// Wrap the pin in a `Flex`. + /// + /// The pin remains disconnected. The initial output level is unspecified, but can be changed + /// before the pin is put into output mode. + #[inline] + pub fn new(pin: impl Peripheral

+ 'd) -> Self { + into_ref!(pin); + + // Pin will be in disconnected state. + Self { + pin: pin.map_into(), + } + } + + /// Set the pin's pull. + #[inline] + pub fn set_pull(&mut self, pull: Pull) { + let pincm = pac::IOMUX.pincm(self.pin.pin_cm() as usize); + + pincm.modify(|w| { + w.set_pipd(matches!(pull, Pull::Down)); + w.set_pipu(matches!(pull, Pull::Up)); + }); + } + + /// Put the pin into input mode. + /// + /// The pull setting is left unchanged. + #[inline] + pub fn set_as_input(&mut self) { + let pincm = pac::IOMUX.pincm(self.pin.pin_cm() as usize); + + pincm.modify(|w| { + w.set_pf(GPIO_PF); + w.set_hiz1(false); + w.set_pc(true); + w.set_inena(true); + }); + + self.pin.block().doeclr31_0().write(|w| { + w.set_dio(self.pin.bit_index(), true); + }); + } + + /// Put the pin into output mode. + /// + /// The pin level will be whatever was set before (or low by default). If you want it to begin + /// at a specific level, call `set_high`/`set_low` on the pin first. + #[inline] + pub fn set_as_output(&mut self) { + let pincm = pac::IOMUX.pincm(self.pin.pin_cm() as usize); + + pincm.modify(|w| { + w.set_pf(GPIO_PF); + w.set_hiz1(false); + w.set_pc(true); + w.set_inena(false); + }); + + self.pin.block().doeset31_0().write(|w| { + w.set_dio(self.pin.bit_index(), true); + }); + } + + /// Put the pin into input + open-drain output mode. + /// + /// The hardware will drive the line low if you set it to low, and will leave it floating if you set + /// it to high, in which case you can read the input to figure out whether another device + /// is driving the line low. + /// + /// The pin level will be whatever was set before (or low by default). If you want it to begin + /// at a specific level, call `set_high`/`set_low` on the pin first. + /// + /// The internal weak pull-up and pull-down resistors will be disabled. + #[inline] + pub fn set_as_input_output(&mut self) { + let pincm = pac::IOMUX.pincm(self.pin.pin_cm() as usize); + + pincm.modify(|w| { + w.set_pf(GPIO_PF); + w.set_hiz1(true); + w.set_pc(true); + w.set_inena(false); + }); + + self.set_pull(Pull::None); + } + + /// Set the pin as "disconnected", ie doing nothing and consuming the lowest + /// amount of power possible. + /// + /// This is currently the same as [`Self::set_as_analog()`] but is semantically different + /// really. Drivers should `set_as_disconnected()` pins when dropped. + /// + /// Note that this also disables the internal weak pull-up and pull-down resistors. + #[inline] + pub fn set_as_disconnected(&mut self) { + let pincm = pac::IOMUX.pincm(self.pin.pin_cm() as usize); + + pincm.modify(|w| { + w.set_pf(DISCONNECT_PF); + w.set_hiz1(false); + w.set_pc(false); + w.set_inena(false); + }); + + self.set_pull(Pull::None); + self.set_inversion(false); + } + + /// Configure the logic inversion of this pin. + /// + /// Logic inversion applies to both the input and output path of this pin. + #[inline] + pub fn set_inversion(&mut self, invert: bool) { + let pincm = pac::IOMUX.pincm(self.pin.pin_cm() as usize); + + pincm.modify(|w| { + w.set_inv(invert); + }); + } + + // TODO: drive strength, hysteresis, wakeup enable, wakeup compare + + /// Put the pin into the PF mode, unchecked. + /// + /// This puts the pin into the PF mode, with the request number. This is completely unchecked, + /// it can attach the pin to literally any peripheral, so use with care. In addition the pin + /// peripheral is connected in the iomux. + /// + /// The peripheral attached to the pin depends on the part in use. Consult the datasheet + /// or technical reference manual for additional details. + #[inline] + pub fn set_pf_unchecked(&mut self, pf: u8) { + // Per SLAU893, PF is only 5 bits + assert!((pf & 0x3F) != 0, "PF is out of range"); + + let pincm = pac::IOMUX.pincm(self.pin.pin_cm() as usize); + + pincm.modify(|w| { + w.set_pf(pf); + // If the PF is manually set, connect the pin + w.set_pc(true); + }); + } + + /// Get whether the pin input level is high. + #[inline] + pub fn is_high(&self) -> bool { + !self.is_low() + } + + /// Get whether the pin input level is low. + #[inline] + pub fn is_low(&self) -> bool { + self.pin.block().din31_0().read().dio(self.pin.bit_index()) + } + + /// Returns current pin level + #[inline] + pub fn get_level(&self) -> Level { + self.is_high().into() + } + + /// Set the output as high. + #[inline] + pub fn set_high(&mut self) { + self.pin.block().doutset31_0().write(|w| { + w.set_dio(self.pin.bit_index() as usize, true); + }); + } + + /// Set the output as low. + #[inline] + pub fn set_low(&mut self) { + self.pin.block().doutclr31_0().write(|w| { + w.set_dio(self.pin.bit_index(), true); + }); + } + + /// Toggle pin output + #[inline] + pub fn toggle(&mut self) { + self.pin.block().douttgl31_0().write(|w| { + w.set_dio(self.pin.bit_index(), true); + }) + } + + /// Set the output level. + #[inline] + pub fn set_level(&mut self, level: Level) { + match level { + Level::Low => self.set_low(), + Level::High => self.set_high(), + } + } + + /// Get the current pin input level. + #[inline] + pub fn get_output_level(&self) -> Level { + self.is_high().into() + } + + /// Is the output level high? + #[inline] + pub fn is_set_high(&self) -> bool { + !self.is_set_low() + } + + /// Is the output level low? + #[inline] + pub fn is_set_low(&self) -> bool { + (self.pin.block().dout31_0().read().0 & self.pin.bit_index() as u32) == 0 + } + + /// Wait until the pin is high. If it is already high, return immediately. + #[inline] + pub async fn wait_for_high(&mut self) { + if self.is_high() { + return; + } + + self.wait_for_rising_edge().await + } + + /// Wait until the pin is low. If it is already low, return immediately. + #[inline] + pub async fn wait_for_low(&mut self) { + if self.is_low() { + return; + } + + self.wait_for_falling_edge().await + } + + /// Wait for the pin to undergo a transition from low to high. + #[inline] + pub async fn wait_for_rising_edge(&mut self) { + InputFuture::new(self.pin.reborrow(), Polarity::RISE).await + } + + /// Wait for the pin to undergo a transition from high to low. + #[inline] + pub async fn wait_for_falling_edge(&mut self) { + InputFuture::new(self.pin.reborrow(), Polarity::FALL).await + } + + /// Wait for the pin to undergo any transition, i.e low to high OR high to low. + #[inline] + pub async fn wait_for_any_edge(&mut self) { + InputFuture::new(self.pin.reborrow(), Polarity::RISE_FALL).await + } +} + +impl<'d> Drop for Flex<'d> { + #[inline] + fn drop(&mut self) { + self.set_as_disconnected(); + } +} + +/// GPIO input driver. +pub struct Input<'d> { + pin: Flex<'d>, +} + +impl<'d> Input<'d> { + /// Create GPIO input driver for a [Pin] with the provided [Pull] configuration. + #[inline] + pub fn new(pin: impl Peripheral

+ 'd, pull: Pull) -> Self { + let mut pin = Flex::new(pin); + pin.set_as_input(); + pin.set_pull(pull); + Self { pin } + } + + /// Get whether the pin input level is high. + #[inline] + pub fn is_high(&self) -> bool { + self.pin.is_high() + } + + /// Get whether the pin input level is low. + #[inline] + pub fn is_low(&self) -> bool { + self.pin.is_low() + } + + /// Get the current pin input level. + #[inline] + pub fn get_level(&self) -> Level { + self.pin.get_level() + } + + /// Configure the logic inversion of this pin. + /// + /// Logic inversion applies to the input path of this pin. + #[inline] + pub fn set_inversion(&mut self, invert: bool) { + self.pin.set_inversion(invert) + } + + /// Wait until the pin is high. If it is already high, return immediately. + #[inline] + pub async fn wait_for_high(&mut self) { + self.pin.wait_for_high().await + } + + /// Wait until the pin is low. If it is already low, return immediately. + #[inline] + pub async fn wait_for_low(&mut self) { + self.pin.wait_for_low().await + } + + /// Wait for the pin to undergo a transition from low to high. + #[inline] + pub async fn wait_for_rising_edge(&mut self) { + self.pin.wait_for_rising_edge().await + } + + /// Wait for the pin to undergo a transition from high to low. + #[inline] + pub async fn wait_for_falling_edge(&mut self) { + self.pin.wait_for_falling_edge().await + } + + /// Wait for the pin to undergo any transition, i.e low to high OR high to low. + #[inline] + pub async fn wait_for_any_edge(&mut self) { + self.pin.wait_for_any_edge().await + } +} + +/// GPIO output driver. +/// +/// Note that pins will **return to their floating state** when `Output` is dropped. +/// If pins should retain their state indefinitely, either keep ownership of the +/// `Output`, or pass it to [`core::mem::forget`]. +pub struct Output<'d> { + pin: Flex<'d>, +} + +impl<'d> Output<'d> { + /// Create GPIO output driver for a [Pin] with the provided [Level] configuration. + #[inline] + pub fn new(pin: impl Peripheral

+ 'd, initial_output: Level) -> Self { + let mut pin = Flex::new(pin); + pin.set_as_output(); + pin.set_level(initial_output); + Self { pin } + } + + /// Set the output as high. + #[inline] + pub fn set_high(&mut self) { + self.pin.set_high(); + } + + /// Set the output as low. + #[inline] + pub fn set_low(&mut self) { + self.pin.set_low(); + } + + /// Set the output level. + #[inline] + pub fn set_level(&mut self, level: Level) { + self.pin.set_level(level) + } + + /// Is the output pin set as high? + #[inline] + pub fn is_set_high(&self) -> bool { + self.pin.is_set_high() + } + + /// Is the output pin set as low? + #[inline] + pub fn is_set_low(&self) -> bool { + self.pin.is_set_low() + } + + /// What level output is set to + #[inline] + pub fn get_output_level(&self) -> Level { + self.pin.get_output_level() + } + + /// Toggle pin output + #[inline] + pub fn toggle(&mut self) { + self.pin.toggle(); + } + + /// Configure the logic inversion of this pin. + /// + /// Logic inversion applies to the input path of this pin. + #[inline] + pub fn set_inversion(&mut self, invert: bool) { + self.pin.set_inversion(invert) + } +} + +/// GPIO output open-drain driver. +/// +/// Note that pins will **return to their floating state** when `OutputOpenDrain` is dropped. +/// If pins should retain their state indefinitely, either keep ownership of the +/// `OutputOpenDrain`, or pass it to [`core::mem::forget`]. +pub struct OutputOpenDrain<'d> { + pin: Flex<'d>, +} + +impl<'d> OutputOpenDrain<'d> { + /// Create a new GPIO open drain output driver for a [Pin] with the provided [Level]. + #[inline] + pub fn new(pin: impl Peripheral

+ 'd, initial_output: Level) -> Self { + let mut pin = Flex::new(pin); + pin.set_level(initial_output); + pin.set_as_input_output(); + Self { pin } + } + + /// Get whether the pin input level is high. + #[inline] + pub fn is_high(&self) -> bool { + !self.pin.is_low() + } + + /// Get whether the pin input level is low. + #[inline] + pub fn is_low(&self) -> bool { + self.pin.is_low() + } + + /// Get the current pin input level. + #[inline] + pub fn get_level(&self) -> Level { + self.pin.get_level() + } + + /// Set the output as high. + #[inline] + pub fn set_high(&mut self) { + self.pin.set_high(); + } + + /// Set the output as low. + #[inline] + pub fn set_low(&mut self) { + self.pin.set_low(); + } + + /// Set the output level. + #[inline] + pub fn set_level(&mut self, level: Level) { + self.pin.set_level(level); + } + + /// Get whether the output level is set to high. + #[inline] + pub fn is_set_high(&self) -> bool { + self.pin.is_set_high() + } + + /// Get whether the output level is set to low. + #[inline] + pub fn is_set_low(&self) -> bool { + self.pin.is_set_low() + } + + /// Get the current output level. + #[inline] + pub fn get_output_level(&self) -> Level { + self.pin.get_output_level() + } + + /// Toggle pin output + #[inline] + pub fn toggle(&mut self) { + self.pin.toggle() + } + + /// Configure the logic inversion of this pin. + /// + /// Logic inversion applies to the input path of this pin. + #[inline] + pub fn set_inversion(&mut self, invert: bool) { + self.pin.set_inversion(invert) + } + + /// Wait until the pin is high. If it is already high, return immediately. + #[inline] + pub async fn wait_for_high(&mut self) { + self.pin.wait_for_high().await + } + + /// Wait until the pin is low. If it is already low, return immediately. + #[inline] + pub async fn wait_for_low(&mut self) { + self.pin.wait_for_low().await + } + + /// Wait for the pin to undergo a transition from low to high. + #[inline] + pub async fn wait_for_rising_edge(&mut self) { + self.pin.wait_for_rising_edge().await + } + + /// Wait for the pin to undergo a transition from high to low. + #[inline] + pub async fn wait_for_falling_edge(&mut self) { + self.pin.wait_for_falling_edge().await + } + + /// Wait for the pin to undergo any transition, i.e low to high OR high to low. + #[inline] + pub async fn wait_for_any_edge(&mut self) { + self.pin.wait_for_any_edge().await + } +} + +/// Type-erased GPIO pin +pub struct AnyPin { + pin_port: u8, +} + +impl AnyPin { + /// Create an [AnyPin] for a specific pin. + /// + /// # Safety + /// - `pin_port` should not in use by another driver. + #[inline] + pub unsafe fn steal(pin_port: u8) -> Self { + Self { pin_port } + } +} + +impl_peripheral!(AnyPin); + +impl Pin for AnyPin {} +impl SealedPin for AnyPin { + #[inline] + fn pin_port(&self) -> u8 { + self.pin_port + } +} + +/// Interface for a Pin that can be configured by an [Input] or [Output] driver, or converted to an [AnyPin]. +#[allow(private_bounds)] +pub trait Pin: Peripheral

+ Into + SealedPin + Sized + 'static { + fn degrade(self) -> AnyPin { + AnyPin { + pin_port: self.pin_port(), + } + } + + /// The index of this pin in PINCM (pin control management) registers. + #[inline] + fn pin_cm(&self) -> u8 { + self._pin_cm() + } +} + +impl<'d> embedded_hal::digital::ErrorType for Flex<'d> { + type Error = Infallible; +} + +impl<'d> embedded_hal::digital::InputPin for Flex<'d> { + #[inline] + fn is_high(&mut self) -> Result { + Ok((*self).is_high()) + } + + #[inline] + fn is_low(&mut self) -> Result { + Ok((*self).is_low()) + } +} + +impl<'d> embedded_hal::digital::OutputPin for Flex<'d> { + #[inline] + fn set_low(&mut self) -> Result<(), Self::Error> { + Ok(self.set_low()) + } + + #[inline] + fn set_high(&mut self) -> Result<(), Self::Error> { + Ok(self.set_high()) + } +} + +impl<'d> embedded_hal::digital::StatefulOutputPin for Flex<'d> { + #[inline] + fn is_set_high(&mut self) -> Result { + Ok((*self).is_set_high()) + } + + #[inline] + fn is_set_low(&mut self) -> Result { + Ok((*self).is_set_low()) + } +} + +impl<'d> embedded_hal_async::digital::Wait for Flex<'d> { + async fn wait_for_high(&mut self) -> Result<(), Self::Error> { + self.wait_for_high().await; + Ok(()) + } + + async fn wait_for_low(&mut self) -> Result<(), Self::Error> { + self.wait_for_low().await; + Ok(()) + } + + async fn wait_for_rising_edge(&mut self) -> Result<(), Self::Error> { + self.wait_for_rising_edge().await; + Ok(()) + } + + async fn wait_for_falling_edge(&mut self) -> Result<(), Self::Error> { + self.wait_for_falling_edge().await; + Ok(()) + } + + async fn wait_for_any_edge(&mut self) -> Result<(), Self::Error> { + self.wait_for_any_edge().await; + Ok(()) + } +} + +impl<'d> embedded_hal::digital::ErrorType for Input<'d> { + type Error = Infallible; +} + +impl<'d> embedded_hal::digital::InputPin for Input<'d> { + #[inline] + fn is_high(&mut self) -> Result { + Ok((*self).is_high()) + } + + #[inline] + fn is_low(&mut self) -> Result { + Ok((*self).is_low()) + } +} + +impl<'d> embedded_hal_async::digital::Wait for Input<'d> { + async fn wait_for_high(&mut self) -> Result<(), Self::Error> { + self.wait_for_high().await; + Ok(()) + } + + async fn wait_for_low(&mut self) -> Result<(), Self::Error> { + self.wait_for_low().await; + Ok(()) + } + + async fn wait_for_rising_edge(&mut self) -> Result<(), Self::Error> { + self.wait_for_rising_edge().await; + Ok(()) + } + + async fn wait_for_falling_edge(&mut self) -> Result<(), Self::Error> { + self.wait_for_falling_edge().await; + Ok(()) + } + + async fn wait_for_any_edge(&mut self) -> Result<(), Self::Error> { + self.wait_for_any_edge().await; + Ok(()) + } +} + +impl<'d> embedded_hal::digital::ErrorType for Output<'d> { + type Error = Infallible; +} + +impl<'d> embedded_hal::digital::OutputPin for Output<'d> { + #[inline] + fn set_low(&mut self) -> Result<(), Self::Error> { + Ok(self.set_low()) + } + + #[inline] + fn set_high(&mut self) -> Result<(), Self::Error> { + Ok(self.set_high()) + } +} + +impl<'d> embedded_hal::digital::StatefulOutputPin for Output<'d> { + #[inline] + fn is_set_high(&mut self) -> Result { + Ok((*self).is_set_high()) + } + + #[inline] + fn is_set_low(&mut self) -> Result { + Ok((*self).is_set_low()) + } +} + +impl<'d> embedded_hal::digital::ErrorType for OutputOpenDrain<'d> { + type Error = Infallible; +} + +impl<'d> embedded_hal::digital::InputPin for OutputOpenDrain<'d> { + #[inline] + fn is_high(&mut self) -> Result { + Ok((*self).is_high()) + } + + #[inline] + fn is_low(&mut self) -> Result { + Ok((*self).is_low()) + } +} + +impl<'d> embedded_hal::digital::OutputPin for OutputOpenDrain<'d> { + #[inline] + fn set_low(&mut self) -> Result<(), Self::Error> { + Ok(self.set_low()) + } + + #[inline] + fn set_high(&mut self) -> Result<(), Self::Error> { + Ok(self.set_high()) + } +} + +impl<'d> embedded_hal::digital::StatefulOutputPin for OutputOpenDrain<'d> { + #[inline] + fn is_set_high(&mut self) -> Result { + Ok((*self).is_set_high()) + } + + #[inline] + fn is_set_low(&mut self) -> Result { + Ok((*self).is_set_low()) + } +} + +impl<'d> embedded_hal_async::digital::Wait for OutputOpenDrain<'d> { + async fn wait_for_high(&mut self) -> Result<(), Self::Error> { + self.wait_for_high().await; + Ok(()) + } + + async fn wait_for_low(&mut self) -> Result<(), Self::Error> { + self.wait_for_low().await; + Ok(()) + } + + async fn wait_for_rising_edge(&mut self) -> Result<(), Self::Error> { + self.wait_for_rising_edge().await; + Ok(()) + } + + async fn wait_for_falling_edge(&mut self) -> Result<(), Self::Error> { + self.wait_for_falling_edge().await; + Ok(()) + } + + async fn wait_for_any_edge(&mut self) -> Result<(), Self::Error> { + self.wait_for_any_edge().await; + Ok(()) + } +} + +/// The pin function to disconnect peripherals from the pin. +/// +/// This is also the pin function used to connect to analog peripherals, such as an ADC. +const DISCONNECT_PF: u8 = 0; + +/// The pin function for the GPIO peripheral. +/// +/// This is fixed to `1` for every part. +const GPIO_PF: u8 = 1; + +macro_rules! impl_pin { + ($name: ident, $port: expr, $pin_num: expr) => { + impl crate::gpio::Pin for crate::peripherals::$name {} + impl crate::gpio::SealedPin for crate::peripherals::$name { + #[inline] + fn pin_port(&self) -> u8 { + ($port as u8) * 32 + $pin_num + } + } + + impl From for crate::gpio::AnyPin { + fn from(val: crate::peripherals::$name) -> Self { + crate::gpio::Pin::degrade(val) + } + } + }; +} + +// TODO: Possible micro-op for C110X, not every pin is instantiated even on the 20 pin parts. +// This would mean cfg guarding to just cfg guarding every pin instance. +static PORTA_WAKERS: [AtomicWaker; 32] = [const { AtomicWaker::new() }; 32]; +#[cfg(gpio_pb)] +static PORTB_WAKERS: [AtomicWaker; 32] = [const { AtomicWaker::new() }; 32]; +#[cfg(gpio_pc)] +static PORTC_WAKERS: [AtomicWaker; 32] = [const { AtomicWaker::new() }; 32]; + +pub(crate) trait SealedPin { + fn pin_port(&self) -> u8; + + fn port(&self) -> Port { + match self.pin_port() / 32 { + 0 => Port::PortA, + #[cfg(gpio_pb)] + 1 => Port::PortB, + #[cfg(gpio_pc)] + 2 => Port::PortC, + _ => unreachable!(), + } + } + + fn waker(&self) -> &AtomicWaker { + match self.port() { + Port::PortA => &PORTA_WAKERS[self.bit_index()], + #[cfg(gpio_pb)] + Port::PortB => &PORTB_WAKERS[self.bit_index()], + #[cfg(gpio_pc)] + Port::PortC => &PORTC_WAKERS[self.bit_index()], + } + } + + fn _pin_cm(&self) -> u8 { + // Some parts like the MSPM0L222x have pincm mappings all over the place. + crate::gpio_pincm(self.pin_port()) + } + + fn bit_index(&self) -> usize { + (self.pin_port() % 32) as usize + } + + #[inline] + fn block(&self) -> gpio::Gpio { + match self.pin_port() / 32 { + 0 => pac::GPIOA, + #[cfg(gpio_pb)] + 1 => pac::GPIOB, + #[cfg(gpio_pc)] + 2 => pac::GPIOC, + _ => unreachable!(), + } + } +} + +#[must_use = "futures do nothing unless you `.await` or poll them"] +struct InputFuture<'d> { + pin: PeripheralRef<'d, AnyPin>, +} + +impl<'d> InputFuture<'d> { + fn new(pin: PeripheralRef<'d, AnyPin>, polarity: Polarity) -> Self { + let block = pin.block(); + + // First clear the bit for this event. Otherwise previous edge events may be recorded. + block.cpu_int().iclr().write(|w| { + w.set_dio(pin.bit_index(), true); + }); + + // Selecting which polarity events happens is a RMW operation. + // + // Guard with a critical section in case two different threads try to select events at the + // same time. + critical_section::with(|_cs| { + // Tell the hardware which pin event we want to receive. + if pin.bit_index() >= 16 { + block.polarity31_16().modify(|w| { + w.set_dio(pin.bit_index() - 16, polarity); + }); + } else { + block.polarity15_0().modify(|w| { + w.set_dio(pin.bit_index(), polarity); + }); + }; + }); + + Self { pin } + } +} + +impl<'d> Future for InputFuture<'d> { + type Output = (); + + fn poll(self: FuturePin<&mut Self>, cx: &mut Context<'_>) -> Poll { + // We need to register/re-register the waker for each poll because any + // calls to wake will deregister the waker. + let waker = self.pin.waker(); + waker.register(cx.waker()); + + // The interrupt handler will mask the interrupt if the event has occurred. + if self + .pin + .block() + .cpu_int() + .ris() + .read() + .dio(self.pin.bit_index()) + { + return Poll::Ready(()); + } + + // Unmasking the interrupt is a RMW operation. + // + // Guard with a critical section in case two different threads try to unmask at the same time. + critical_section::with(|_cs| { + self.pin.block().cpu_int().imask().modify(|w| { + w.set_dio(self.pin.bit_index(), true); + }); + }); + + Poll::Pending + } +} + +pub(crate) fn init(gpio: gpio::Gpio) { + gpio.gprcm().rstctl().write(|w| { + w.set_resetstkyclr(true); + w.set_resetassert(true); + w.set_key(ResetKey::KEY); + }); + + gpio.gprcm().pwren().write(|w| { + w.set_enable(true); + w.set_key(PwrenKey::KEY); + }); + + gpio.evt_mode().modify(|w| { + // The CPU will clear it's own interrupts + w.set_cpu_cfg(EvtCfg::SOFTWARE); + }); +} + +#[cfg(feature = "rt")] +fn irq_handler(gpio: gpio::Gpio, wakers: &[AtomicWaker; 32]) { + // Only consider pins which have interrupts unmasked. + let bits = gpio.cpu_int().mis().read().0; + + for i in BitIter(bits) { + wakers[i as usize].wake(); + + // Notify the future that an edge event has occurred by masking the interrupt for this pin. + gpio.cpu_int().imask().modify(|w| { + w.set_dio(i as usize, false); + }); + } +} + +struct BitIter(u32); + +impl Iterator for BitIter { + type Item = u32; + + fn next(&mut self) -> Option { + match self.0.trailing_zeros() { + 32 => None, + b => { + self.0 &= !(1 << b); + Some(b) + } + } + } +} + +// C110x has a dedicated interrupt just for GPIOA, as it does not have a GROUP1 interrupt. +#[cfg(all(feature = "rt", feature = "mspm0c110x"))] +#[interrupt] +fn GPIOA() { + gpioa_interrupt(); +} + +#[cfg(feature = "rt")] +pub(crate) fn gpioa_interrupt() { + irq_handler(pac::GPIOA, &PORTA_WAKERS); +} + +#[cfg(all(feature = "rt", gpio_pb))] +pub(crate) fn gpiob_interrupt() { + irq_handler(pac::GPIOB, &PORTB_WAKERS); +} + +#[cfg(all(feature = "rt", gpio_pc))] +pub(crate) fn gpioc_interrupt() { + irq_handler(pac::GPIOC, &PORTC_WAKERS); +} diff --git a/embassy-mspm0/src/int_group/c110x.rs b/embassy-mspm0/src/int_group/c110x.rs new file mode 100644 index 000000000..c503af631 --- /dev/null +++ b/embassy-mspm0/src/int_group/c110x.rs @@ -0,0 +1,25 @@ +use crate::pac; +use crate::pac::interrupt; + +#[cfg(feature = "rt")] +#[interrupt] +fn GROUP0() { + use mspm0_metapac::Group0; + + let group = pac::CPUSS.int_group(1); + + // TODO: Decompose to direct u8 + let iidx = group.iidx().read().stat().to_bits(); + + let Ok(group) = pac::Group0::try_from(iidx as u8) else { + debug!("Invalid IIDX for group 0: {}", iidx); + return; + }; + + match group { + Group0::WWDT0 => todo!("implement WWDT0"), + Group0::DEBUGSS => todo!("implement DEBUGSS"), + Group0::FLASHCTL => todo!("implement FLASHCTL"), + Group0::SYSCTL => todo!("implement SYSCTL"), + } +} diff --git a/embassy-mspm0/src/int_group/g350x.rs b/embassy-mspm0/src/int_group/g350x.rs new file mode 100644 index 000000000..818dd6e1e --- /dev/null +++ b/embassy-mspm0/src/int_group/g350x.rs @@ -0,0 +1,51 @@ +use crate::pac; +use crate::pac::interrupt; + +#[cfg(feature = "rt")] +#[interrupt] +fn GROUP0() { + use mspm0_metapac::Group0; + + let group = pac::CPUSS.int_group(1); + + // Must subtract by 1 since NO_INTR is value 0 + let iidx = group.iidx().read().stat().to_bits() - 1; + + let Ok(group) = pac::Group0::try_from(iidx as u8) else { + debug!("Invalid IIDX for group 0: {}", iidx); + return; + }; + + match group { + Group0::WWDT0 => todo!("implement WWDT0"), + Group0::WWDT1 => todo!("implement WWDT1"), + Group0::DEBUGSS => todo!("implement DEBUGSS"), + Group0::FLASHCTL => todo!("implement FLASHCTL"), + Group0::SYSCTL => todo!("implement SYSCTL"), + } +} + +#[cfg(feature = "rt")] +#[interrupt] +fn GROUP1() { + use mspm0_metapac::Group1; + + let group = pac::CPUSS.int_group(1); + + // Must subtract by 1 since NO_INTR is value 0 + let iidx = group.iidx().read().stat().to_bits() - 1; + + let Ok(group) = pac::Group1::try_from(iidx as u8) else { + debug!("Invalid IIDX for group 1: {}", iidx); + return; + }; + + match group { + Group1::GPIOA => crate::gpio::gpioa_interrupt(), + Group1::GPIOB => crate::gpio::gpiob_interrupt(), + Group1::COMP0 => todo!("implement COMP0"), + Group1::COMP1 => todo!("implement COMP1"), + Group1::COMP2 => todo!("implement COMP2"), + Group1::TRNG => todo!("implement TRNG"), + } +} diff --git a/embassy-mspm0/src/int_group/g351x.rs b/embassy-mspm0/src/int_group/g351x.rs new file mode 100644 index 000000000..b43e0a9db --- /dev/null +++ b/embassy-mspm0/src/int_group/g351x.rs @@ -0,0 +1,52 @@ +use crate::pac; +use crate::pac::interrupt; + +#[cfg(feature = "rt")] +#[interrupt] +fn GROUP0() { + use mspm0_metapac::Group0; + + let group = pac::CPUSS.int_group(1); + + // Must subtract by 1 since NO_INTR is value 0 + let iidx = group.iidx().read().stat().to_bits() - 1; + + let Ok(group) = pac::Group0::try_from(iidx as u8) else { + debug!("Invalid IIDX for group 0: {}", iidx); + return; + }; + + match group { + Group0::WWDT0 => todo!("implement WWDT0"), + Group0::WWDT1 => todo!("implement WWDT1"), + Group0::DEBUGSS => todo!("implement DEBUGSS"), + Group0::FLASHCTL => todo!("implement FLASHCTL"), + Group0::SYSCTL => todo!("implement SYSCTL"), + } +} + +#[cfg(feature = "rt")] +#[interrupt] +fn GROUP1() { + use mspm0_metapac::Group1; + + let group = pac::CPUSS.int_group(1); + + // Must subtract by 1 since NO_INTR is value 0 + let iidx = group.iidx().read().stat().to_bits() - 1; + + let Ok(group) = pac::Group1::try_from(iidx as u8) else { + debug!("Invalid IIDX for group 1: {}", iidx); + return; + }; + + match group { + Group1::GPIOA => crate::gpio::gpioa_interrupt(), + Group1::GPIOB => crate::gpio::gpiob_interrupt(), + Group1::COMP0 => todo!("implement COMP0"), + Group1::COMP1 => todo!("implement COMP1"), + Group1::COMP2 => todo!("implement COMP2"), + Group1::TRNG => todo!("implement TRNG"), + Group1::GPIOC => crate::gpio::gpioc_interrupt(), + } +} diff --git a/embassy-mspm0/src/int_group/l130x.rs b/embassy-mspm0/src/int_group/l130x.rs new file mode 100644 index 000000000..6d033cc56 --- /dev/null +++ b/embassy-mspm0/src/int_group/l130x.rs @@ -0,0 +1,46 @@ +use crate::pac; +use crate::pac::interrupt; + +#[cfg(feature = "rt")] +#[interrupt] +fn GROUP0() { + use mspm0_metapac::Group0; + + let group = pac::CPUSS.int_group(1); + + // Must subtract by 1 since NO_INTR is value 0 + let iidx = group.iidx().read().stat().to_bits() - 1; + + let Ok(group) = pac::Group0::try_from(iidx as u8) else { + debug!("Invalid IIDX for group 0: {}", iidx); + return; + }; + + match group { + Group0::WWDT0 => todo!("implement WWDT0"), + Group0::DEBUGSS => todo!("implement DEBUGSS"), + Group0::FLASHCTL => todo!("implement FLASHCTL"), + Group0::SYSCTL => todo!("implement SYSCTL"), + } +} + +#[cfg(feature = "rt")] +#[interrupt] +fn GROUP1() { + use mspm0_metapac::Group1; + + let group = pac::CPUSS.int_group(1); + + // Must subtract by 1 since NO_INTR is value 0 + let iidx = group.iidx().read().stat().to_bits() - 1; + + let Ok(group) = pac::Group1::try_from(iidx as u8) else { + debug!("Invalid IIDX for group 1: {}", iidx); + return; + }; + + match group { + Group1::GPIOA => crate::gpio::gpioa_interrupt(), + Group1::COMP0 => todo!("implement COMP0"), + } +} diff --git a/embassy-mspm0/src/int_group/l222x.rs b/embassy-mspm0/src/int_group/l222x.rs new file mode 100644 index 000000000..703e16e78 --- /dev/null +++ b/embassy-mspm0/src/int_group/l222x.rs @@ -0,0 +1,49 @@ +use crate::pac; +use crate::pac::interrupt; + +#[cfg(feature = "rt")] +#[interrupt] +fn GROUP0() { + use mspm0_metapac::Group0; + + let group = pac::CPUSS.int_group(1); + + // Must subtract by 1 since NO_INTR is value 0 + let iidx = group.iidx().read().stat().to_bits() - 1; + + let Ok(group) = pac::Group0::try_from(iidx as u8) else { + debug!("Invalid IIDX for group 0: {}", iidx); + return; + }; + + match group { + Group0::WWDT0 => todo!("implement WWDT0"), + Group0::DEBUGSS => todo!("implement DEBUGSS"), + Group0::FLASHCTL => todo!("implement FLASHCTL"), + Group0::SYSCTL => todo!("implement SYSCTL"), + } +} + +#[cfg(feature = "rt")] +#[interrupt] +fn GROUP1() { + use mspm0_metapac::Group1; + + let group = pac::CPUSS.int_group(1); + + // Must subtract by 1 since NO_INTR is value 0 + let iidx = group.iidx().read().stat().to_bits() - 1; + + let Ok(group) = pac::Group1::try_from(iidx as u8) else { + debug!("Invalid IIDX for group 1: {}", iidx); + return; + }; + + match group { + Group1::GPIOA => crate::gpio::gpioa_interrupt(), + Group1::GPIOB => crate::gpio::gpiob_interrupt(), + Group1::COMP0 => todo!("implement COMP0"), + Group1::TRNG => todo!("implement TRNG"), + Group1::GPIOC => crate::gpio::gpioc_interrupt(), + } +} diff --git a/embassy-mspm0/src/lib.rs b/embassy-mspm0/src/lib.rs new file mode 100644 index 000000000..ee629f063 --- /dev/null +++ b/embassy-mspm0/src/lib.rs @@ -0,0 +1,112 @@ +#![no_std] +// Doc feature labels can be tested locally by running RUSTDOCFLAGS="--cfg=docsrs" cargo +nightly doc +#![cfg_attr( + docsrs, + feature(doc_auto_cfg, doc_cfg_hide), + doc(cfg_hide(doc, docsrs)) +)] + +// This mod MUST go first, so that the others see its macros. +pub(crate) mod fmt; + +pub mod gpio; +pub mod timer; + +#[cfg(feature = "_time-driver")] +mod time_driver; + +// Interrupt group handlers. +#[cfg_attr(feature = "mspm0c110x", path = "int_group/c110x.rs")] +#[cfg_attr(feature = "mspm0g110x", path = "int_group/g110x.rs")] +#[cfg_attr(feature = "mspm0g150x", path = "int_group/g150x.rs")] +#[cfg_attr(feature = "mspm0g151x", path = "int_group/g151x.rs")] +#[cfg_attr(feature = "mspm0g310x", path = "int_group/g310x.rs")] +#[cfg_attr(feature = "mspm0g350x", path = "int_group/g350x.rs")] +#[cfg_attr(feature = "mspm0g351x", path = "int_group/g351x.rs")] +#[cfg_attr(feature = "mspm0l110x", path = "int_group/l110x.rs")] +#[cfg_attr(feature = "mspm0l122x", path = "int_group/l122x.rs")] +#[cfg_attr(feature = "mspm0l130x", path = "int_group/l130x.rs")] +#[cfg_attr(feature = "mspm0l134x", path = "int_group/l134x.rs")] +#[cfg_attr(feature = "mspm0l222x", path = "int_group/l222x.rs")] +mod int_group; + +pub(crate) mod _generated { + #![allow(dead_code)] + #![allow(unused_imports)] + #![allow(non_snake_case)] + #![allow(missing_docs)] + + include!(concat!(env!("OUT_DIR"), "/_generated.rs")); +} + +// Reexports +pub use _generated::{peripherals, Peripherals}; +pub use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; +#[cfg(feature = "unstable-pac")] +pub use mspm0_metapac as pac; +#[cfg(not(feature = "unstable-pac"))] +pub(crate) use mspm0_metapac as pac; + +pub use crate::_generated::interrupt; +pub(crate) use _generated::gpio_pincm; + + +/// `embassy-mspm0` global configuration. +#[non_exhaustive] +#[derive(Clone, Copy)] +pub struct Config { + // TODO +} + +impl Default for Config { + fn default() -> Self { + Self { + // TODO + } + } +} + +pub fn init(_config: Config) -> Peripherals { + critical_section::with(|cs| { + let peripherals = Peripherals::take_with_cs(cs); + + // TODO: Further clock configuration + + pac::SYSCTL.mclkcfg().modify(|w| { + // Enable MFCLK + w.set_usemftick(true); + // MDIV must be disabled if MFCLK is enabled. + w.set_mdiv(0); + }); + + // Enable MFCLK for peripheral use + // + // TODO: Optional? + pac::SYSCTL.genclken().modify(|w| { + w.set_mfpclken(true); + }); + + pac::SYSCTL.borthreshold().modify(|w| { + w.set_level(0); + }); + + gpio::init(pac::GPIOA); + #[cfg(gpio_pb)] + gpio::init(pac::GPIOB); + #[cfg(gpio_pc)] + gpio::init(pac::GPIOC); + + _generated::enable_group_interrupts(cs); + + #[cfg(feature = "mspm0c110x")] + unsafe { + use crate::_generated::interrupt::typelevel::Interrupt; + crate::interrupt::typelevel::GPIOA::enable(); + } + + #[cfg(feature = "_time-driver")] + time_driver::init(cs); + + peripherals + }) +} diff --git a/embassy-mspm0/src/time_driver.rs b/embassy-mspm0/src/time_driver.rs new file mode 100644 index 000000000..3af7a5edb --- /dev/null +++ b/embassy-mspm0/src/time_driver.rs @@ -0,0 +1,437 @@ +use core::{ + cell::{Cell, RefCell}, + sync::atomic::{compiler_fence, AtomicU32, Ordering}, + task::Waker, +}; + +use critical_section::{CriticalSection, Mutex}; +use embassy_time_driver::Driver; +use embassy_time_queue_utils::Queue; +use mspm0_metapac::{ + interrupt, + tim::{ + vals::{Cm, Cvae, CxC, EvtCfg, PwrenKey, Ratio, Repeat, ResetKey}, + Counterregs16, Tim, + }, +}; + +use crate::peripherals; +use crate::timer::SealedTimer; + +// Currently TIMG12 and TIMG13 are excluded because those are 32-bit timers. +#[cfg(time_driver_timg0)] +type T = peripherals::TIMG0; +#[cfg(time_driver_timg1)] +type T = peripherals::TIMG1; +#[cfg(time_driver_timg2)] +type T = peripherals::TIMG2; +#[cfg(time_driver_timg3)] +type T = peripherals::TIMG3; +#[cfg(time_driver_timg4)] +type T = peripherals::TIMG4; +#[cfg(time_driver_timg5)] +type T = peripherals::TIMG5; +#[cfg(time_driver_timg6)] +type T = peripherals::TIMG6; +#[cfg(time_driver_timg7)] +type T = peripherals::TIMG7; +#[cfg(time_driver_timg8)] +type T = peripherals::TIMG8; +#[cfg(time_driver_timg9)] +type T = peripherals::TIMG9; +#[cfg(time_driver_timg10)] +type T = peripherals::TIMG10; +#[cfg(time_driver_timg11)] +type T = peripherals::TIMG11; +#[cfg(time_driver_timg14)] +type T = peripherals::TIMG14; +#[cfg(time_driver_tima0)] +type T = peripherals::TIMA0; +#[cfg(time_driver_tima1)] +type T = peripherals::TIMA1; + +// TODO: RTC + +fn regs() -> Tim { + unsafe { Tim::from_ptr(T::regs()) } +} + +fn regs_counter(tim: Tim) -> Counterregs16 { + unsafe { Counterregs16::from_ptr(tim.counterregs(0).as_ptr()) } +} + +/// Clock timekeeping works with something we call "periods", which are time intervals +/// of 2^15 ticks. The Clock counter value is 16 bits, so one "overflow cycle" is 2 periods. +fn calc_now(period: u32, counter: u16) -> u64 { + ((period as u64) << 15) + ((counter as u32 ^ ((period & 1) << 15)) as u64) +} + +/// The TIMx driver uses one of the `TIMG` or `TIMA` timer instances to implement a timer with a 32.768 kHz +/// tick rate. (TODO: Allow setting the tick rate) +/// +/// This driver defines a period to be 2^15 ticks. 16-bit timers of course count to 2^16 ticks. +/// +/// To generate a period every 2^15 ticks, the CC0 value is set to 2^15 and the load value set to 2^16. +/// Incrementing the period on a CCU0 and load results in the a period of 2^15 ticks. +/// +/// For a specific timestamp, load the lower 16 bits into the CC1 value. When the period where the timestamp +/// should be enabled is reached, then the CCU1 (CC1 up) interrupt runs to actually wake the timer. +/// +/// TODO: Compensate for per part variance. This can supposedly be done with the FCC system. +/// TODO: Allow using 32-bit timers (TIMG12 and TIMG13). +struct TimxDriver { + /// Number of 2^15 periods elapsed since boot. + period: AtomicU32, + /// Timestamp at which to fire alarm. u64::MAX if no alarm is scheduled. + alarm: Mutex>, + queue: Mutex>, +} + +impl TimxDriver { + #[inline(never)] + fn init(&'static self, _cs: CriticalSection) { + // Clock config + // TODO: Configurable tick rate up to 4 MHz (32 kHz for now) + let regs = regs(); + + // Reset timer + regs.gprcm(0).rstctl().write(|w| { + w.set_resetassert(true); + w.set_key(ResetKey::KEY); + w.set_resetstkyclr(true); + }); + + // Power up timer + regs.gprcm(0).pwren().write(|w| { + w.set_enable(true); + w.set_key(PwrenKey::KEY); + }); + + // Following the instructions according to SLAU847D 23.2.1: TIMCLK Configuration + + // 1. Select TIMCLK source + regs.clksel().modify(|w| { + // Use LFCLK for a 32.768kHz tick rate + w.set_lfclk_sel(true); + // TODO: Allow MFCLK for configurable tick rate up to 4 MHz + // w.set_mfclk_sel(ClkSel::ENABLE); + }); + + // 2. Divide by TIMCLK, we don't need to divide further for the 32kHz tick rate + regs.clkdiv().modify(|w| { + w.set_ratio(Ratio::DIV_BY_1); + }); + + // 3. To be generic across timer instances, we do not use the prescaler. + // TODO: mspm0-sdk always sets this, regardless of timer width? + regs.commonregs(0).cps().modify(|w| { + w.set_pcnt(0); + }); + + regs.pdbgctl().modify(|w| { + w.set_free(true); + }); + + // 4. Enable the TIMCLK. + regs.commonregs(0).cclkctl().modify(|w| { + w.set_clken(true); + }); + + regs.counterregs(0).ctrctl().modify(|w| { + // allow counting during debug + w.set_repeat(Repeat::REPEAT_3); + w.set_cvae(Cvae::ZEROVAL); + w.set_cm(Cm::UP); + + // Must explicitly set CZC, CAC and CLC to 0 in order for all the timers to count. + // + // The reset value of these registers is 0x07, which is a reserved value. + // + // Looking at a bit representation of the reset value, this appears to be an AND + // of 2-input QEI mode and CCCTL_3 ACOND. Given that TIMG14 and TIMA0 have no QEI + // and 4 capture and compare channels, this works by accident for those timer units. + w.set_czc(CxC::CCTL0); + w.set_cac(CxC::CCTL0); + w.set_clc(CxC::CCTL0); + }); + + // Setup the period + let ctr = regs_counter(regs); + + // Middle + ctr.cc(0).modify(|w| { + w.set_ccval(0x7FFF); + }); + + ctr.load().modify(|w| { + w.set_ld(u16::MAX); + }); + + // Enable the period interrupts + // + // This does not appear to ever be set for CPU_INT in the TI SDK and is not technically needed. + regs.evt_mode().modify(|w| { + w.set_evt_cfg(0, EvtCfg::SOFTWARE); + }); + + regs.int_event(0).imask().modify(|w| { + w.set_l(true); + w.set_ccu0(true); + }); + + unsafe { T::enable_interrupt() }; + + // Allow the counter to start counting. + regs.counterregs(0).ctrctl().modify(|w| { + w.set_en(true); + }); + } + + #[inline(never)] + fn next_period(&self) { + let r = regs(); + + // We only modify the period from the timer interrupt, so we know this can't race. + let period = self.period.load(Ordering::Relaxed) + 1; + self.period.store(period, Ordering::Relaxed); + let t = (period as u64) << 15; + + critical_section::with(move |cs| { + r.int_event(0).imask().modify(move |w| { + let alarm = self.alarm.borrow(cs); + let at = alarm.get(); + + if at < t + 0xC000 { + // just enable it. `set_alarm` has already set the correct CC1 val. + w.set_ccu1(true); + } + }) + }); + } + + #[inline(never)] + fn on_interrupt(&self) { + let r = regs(); + + critical_section::with(|cs| { + let mis = r.int_event(0).mis().read(); + + // Advance to next period if overflowed + if mis.l() { + self.next_period(); + + r.int_event(0).iclr().write(|w| { + w.set_l(true); + }); + } + + if mis.ccu0() { + self.next_period(); + + r.int_event(0).iclr().write(|w| { + w.set_ccu0(true); + }); + } + + if mis.ccu1() { + r.int_event(0).iclr().write(|w| { + w.set_ccu1(true); + }); + + self.trigger_alarm(cs); + } + }); + } + + fn trigger_alarm(&self, cs: CriticalSection) { + let mut next = self + .queue + .borrow(cs) + .borrow_mut() + .next_expiration(self.now()); + + while !self.set_alarm(cs, next) { + next = self + .queue + .borrow(cs) + .borrow_mut() + .next_expiration(self.now()); + } + } + + fn set_alarm(&self, cs: CriticalSection, timestamp: u64) -> bool { + let r = regs(); + let ctr = regs_counter(r); + + self.alarm.borrow(cs).set(timestamp); + + let t = self.now(); + + if timestamp <= t { + // If alarm timestamp has passed the alarm will not fire. + // Disarm the alarm and return `false` to indicate that. + r.int_event(0).imask().modify(|w| w.set_ccu1(false)); + + self.alarm.borrow(cs).set(u64::MAX); + + return false; + } + + // Write the CC1 value regardless of whether we're going to enable it now or not. + // This way, when we enable it later, the right value is already set. + ctr.cc(1).write(|w| { + w.set_ccval(timestamp as u16); + }); + + // Enable it if it'll happen soon. Otherwise, `next_period` will enable it. + let diff = timestamp - t; + r.int_event(0).imask().modify(|w| w.set_ccu1(diff < 0xC000)); + + // Reevaluate if the alarm timestamp is still in the future + let t = self.now(); + if timestamp <= t { + // If alarm timestamp has passed since we set it, we have a race condition and + // the alarm may or may not have fired. + // Disarm the alarm and return `false` to indicate that. + // It is the caller's responsibility to handle this ambiguity. + r.int_event(0).imask().modify(|w| w.set_ccu1(false)); + + self.alarm.borrow(cs).set(u64::MAX); + + return false; + } + + // We're confident the alarm will ring in the future. + true + } +} + +impl Driver for TimxDriver { + fn now(&self) -> u64 { + let regs = regs(); + + let period = self.period.load(Ordering::Relaxed); + // Ensure the compiler does not read the counter before the period. + compiler_fence(Ordering::Acquire); + + let counter = regs_counter(regs).ctr().read().cctr() as u16; + + calc_now(period, counter) + } + + fn schedule_wake(&self, at: u64, waker: &Waker) { + critical_section::with(|cs| { + let mut queue = self.queue.borrow(cs).borrow_mut(); + + if queue.schedule_wake(at, waker) { + let mut next = queue.next_expiration(self.now()); + + while !self.set_alarm(cs, next) { + next = queue.next_expiration(self.now()); + } + } + }); + } +} + +embassy_time_driver::time_driver_impl!(static DRIVER: TimxDriver = TimxDriver { + period: AtomicU32::new(0), + alarm: Mutex::new(Cell::new(u64::MAX)), + queue: Mutex::new(RefCell::new(Queue::new())) +}); + +pub(crate) fn init(cs: CriticalSection) { + DRIVER.init(cs); +} + +#[cfg(time_driver_timg0)] +#[interrupt] +fn TIMG0() { + DRIVER.on_interrupt(); +} + +#[cfg(time_driver_timg1)] +#[interrupt] +fn TIMG1() { + DRIVER.on_interrupt(); +} + +#[cfg(time_driver_timg2)] +#[interrupt] +fn TIMG2() { + DRIVER.on_interrupt(); +} + +#[cfg(time_driver_timg3)] +#[interrupt] +fn TIMG3() { + DRIVER.on_interrupt(); +} + +#[cfg(time_driver_timg4)] +#[interrupt] +fn TIMG4() { + DRIVER.on_interrupt(); +} + +#[cfg(time_driver_timg5)] +#[interrupt] +fn TIMG5() { + DRIVER.on_interrupt(); +} + +#[cfg(time_driver_timg6)] +#[interrupt] +fn TIMG6() { + DRIVER.on_interrupt(); +} + +#[cfg(time_driver_timg7)] +#[interrupt] +fn TIMG7() { + DRIVER.on_interrupt(); +} + +#[cfg(time_driver_timg8)] +#[interrupt] +fn TIMG8() { + DRIVER.on_interrupt(); +} + +#[cfg(time_driver_timg9)] +#[interrupt] +fn TIMG9() { + DRIVER.on_interrupt(); +} + +#[cfg(time_driver_timg10)] +#[interrupt] +fn TIMG10() { + DRIVER.on_interrupt(); +} + +#[cfg(time_driver_timg11)] +#[interrupt] +fn TIMG11() { + DRIVER.on_interrupt(); +} + +// TODO: TIMG12 and TIMG13 + +#[cfg(time_driver_timg14)] +#[interrupt] +fn TIMG14() { + DRIVER.on_interrupt(); +} + +#[cfg(time_driver_tima0)] +#[interrupt] +fn TIMA0() { + DRIVER.on_interrupt(); +} + +#[cfg(time_driver_tima1)] +#[interrupt] +fn TIMA1() { + DRIVER.on_interrupt(); +} diff --git a/embassy-mspm0/src/timer.rs b/embassy-mspm0/src/timer.rs new file mode 100644 index 000000000..4441e5640 --- /dev/null +++ b/embassy-mspm0/src/timer.rs @@ -0,0 +1,48 @@ +#![macro_use] + +/// Amount of bits of a timer. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum TimerBits { + /// 16 bits. + Bits16, + /// 32 bits. + Bits32, +} + +#[allow(private_bounds)] +pub trait Timer: SealedTimer + 'static { + /// Amount of bits this timer has. + const BITS: TimerBits; +} + +pub(crate) trait SealedTimer { + /// Registers for this timer. + /// + /// This is a raw pointer to the register block. The actual register block layout varies depending on the + /// timer type. + fn regs() -> *mut (); + + /// Enable the interrupt corresponding to this timer. + unsafe fn enable_interrupt(); +} + +macro_rules! impl_timer { + ($name: ident, $bits: ident) => { + impl crate::timer::SealedTimer for crate::peripherals::$name { + fn regs() -> *mut () { + crate::pac::$name.as_ptr() + } + + unsafe fn enable_interrupt() { + use embassy_hal_internal::interrupt::InterruptExt; + crate::interrupt::$name.unpend(); + crate::interrupt::$name.enable(); + } + } + + impl crate::timer::Timer for crate::peripherals::$name { + const BITS: crate::timer::TimerBits = crate::timer::TimerBits::$bits; + } + }; +} diff --git a/examples/mspm0c1104/.cargo/config.toml b/examples/mspm0c1104/.cargo/config.toml new file mode 100644 index 000000000..204a56b1c --- /dev/null +++ b/examples/mspm0c1104/.cargo/config.toml @@ -0,0 +1,11 @@ +[target.'cfg(all(target_arch = "arm", target_os = "none"))'] +# replace MSPM0C1104 with your chip as listed in `probe-rs chip list` +runner = "probe-rs run --chip MSPM0C1104 --protocol=swd" + +[build] +target = "thumbv6m-none-eabi" + +[env] +DEFMT_LOG = "debug" +# defmt's buffer needs to be shrunk since the MSPM0C1104 only has 1KB of ram. +DEFMT_RTT_BUFFER_SIZE = "72" diff --git a/examples/mspm0c1104/Cargo.toml b/examples/mspm0c1104/Cargo.toml new file mode 100644 index 000000000..35c9b1358 --- /dev/null +++ b/examples/mspm0c1104/Cargo.toml @@ -0,0 +1,32 @@ +[package] +edition = "2021" +name = "embassy-mspm0-c1104-examples" +version = "0.1.0" +license = "MIT OR Apache-2.0" + +[dependencies] +embassy-mspm0 = { version = "0.1.0", path = "../../embassy-mspm0", features = ["mspm0c110x", "rt", "time-driver-any"] } +embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-128", "arch-cortex-m", "executor-thread", "executor-interrupt"] } +embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } +embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt"] } +panic-halt = "0.2.0" +cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } +cortex-m-rt = { version = "0.7.0"} +defmt = "0.3" +defmt-rtt = "0.4" +panic-probe = { version = "0.3.2", features = ["print-defmt"] } +panic-semihosting = "0.6.0" + +# The chip only has 1KB of ram, so we must optimize binaries regardless +[profile.dev] +debug = 2 +opt-level = "z" +lto = true +codegen-units = 1 +# strip = true + +[profile.release] +debug = 2 +opt-level = "z" +lto = true +codegen-units = 1 diff --git a/examples/mspm0c1104/README.md b/examples/mspm0c1104/README.md new file mode 100644 index 000000000..e5c9f961d --- /dev/null +++ b/examples/mspm0c1104/README.md @@ -0,0 +1,27 @@ +# Examples for MSPM0C110x family + +Run individual examples with +``` +cargo run --bin +``` +for example +``` +cargo run --bin blinky +``` + +## Checklist before running examples +A large number of the examples are written for the [LP-MSPM0C1104](https://www.ti.com/tool/LP-MSPM0C1104) board. + +You might need to adjust `.cargo/config.toml`, `Cargo.toml` and possibly update pin numbers or peripherals to match the specific MCU or board you are using. + +* [ ] Update .cargo/config.toml with the correct probe-rs command to use your specific MCU. For example for C1104 it should be `probe-rs run --chip MSPM0C1104`. (use `probe-rs chip list` to find your chip) +* [ ] Update Cargo.toml to have the correct `embassy-mspm0` feature. For example for C1104 it should be `mspm0c1104`. Look in the `Cargo.toml` file of the `embassy-mspm0` project to find the correct feature flag for your chip. +* [ ] If your board has a special clock or power configuration, make sure that it is set up appropriately. +* [ ] If your board has different pin mapping, update any pin numbers or peripherals in the given example code to match your schematic + +If you are unsure, please drop by the Embassy Matrix chat for support, and let us know: + +* Which example you are trying to run +* Which chip and board you are using + +Embassy Chat: https://matrix.to/#/#embassy-rs:matrix.org diff --git a/examples/mspm0c1104/build.rs b/examples/mspm0c1104/build.rs new file mode 100644 index 000000000..30691aa97 --- /dev/null +++ b/examples/mspm0c1104/build.rs @@ -0,0 +1,35 @@ +//! This build script copies the `memory.x` file from the crate root into +//! a directory where the linker can always find it at build time. +//! For many projects this is optional, as the linker always searches the +//! project root directory -- wherever `Cargo.toml` is. However, if you +//! are using a workspace or have a more complicated build setup, this +//! build script becomes required. Additionally, by requesting that +//! Cargo re-run the build script whenever `memory.x` is changed, +//! updating `memory.x` ensures a rebuild of the application with the +//! new memory settings. + +use std::env; +use std::fs::File; +use std::io::Write; +use std::path::PathBuf; + +fn main() { + // Put `memory.x` in our output directory and ensure it's + // on the linker search path. + let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); + File::create(out.join("memory.x")) + .unwrap() + .write_all(include_bytes!("memory.x")) + .unwrap(); + println!("cargo:rustc-link-search={}", out.display()); + + // By default, Cargo will re-run a build script whenever + // any file in the project changes. By specifying `memory.x` + // here, we ensure the build script is only re-run when + // `memory.x` is changed. + println!("cargo:rerun-if-changed=memory.x"); + + println!("cargo:rustc-link-arg-bins=--nmagic"); + println!("cargo:rustc-link-arg-bins=-Tlink.x"); + println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); +} diff --git a/examples/mspm0c1104/memory.x b/examples/mspm0c1104/memory.x new file mode 100644 index 000000000..a9108835a --- /dev/null +++ b/examples/mspm0c1104/memory.x @@ -0,0 +1,5 @@ +MEMORY +{ + FLASH : ORIGIN = 0x00000000, LENGTH = 16K + RAM : ORIGIN = 0x20000000, LENGTH = 1K +} diff --git a/examples/mspm0c1104/src/bin/blinky.rs b/examples/mspm0c1104/src/bin/blinky.rs new file mode 100644 index 000000000..264ea3eb5 --- /dev/null +++ b/examples/mspm0c1104/src/bin/blinky.rs @@ -0,0 +1,27 @@ +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_mspm0::{ + gpio::{Level, Output}, + Config, +}; +use embassy_time::Timer; +use {defmt_rtt as _, panic_halt as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) -> ! { + info!("Hello world!"); + let p = embassy_mspm0::init(Config::default()); + + let mut led1 = Output::new(p.PA22, Level::Low); + led1.set_inversion(true); + + loop { + Timer::after_millis(400).await; + + info!("Toggle"); + led1.toggle(); + } +} diff --git a/examples/mspm0c1104/src/bin/button.rs b/examples/mspm0c1104/src/bin/button.rs new file mode 100644 index 000000000..988170ef9 --- /dev/null +++ b/examples/mspm0c1104/src/bin/button.rs @@ -0,0 +1,35 @@ +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_mspm0::{ + gpio::{Input, Level, Output, Pull}, + Config, +}; +use {defmt_rtt as _, panic_halt as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) -> ! { + info!("Hello world!"); + + let p = embassy_mspm0::init(Config::default()); + + let led1 = p.PA22; + let s2 = p.PA16; + + let mut led1 = Output::new(led1, Level::Low); + + let mut s2 = Input::new(s2, Pull::Up); + + // led1 is active low + led1.set_high(); + + loop { + s2.wait_for_falling_edge().await; + + info!("Switch 2 was pressed"); + + led1.toggle(); + } +} diff --git a/examples/mspm0g3507/.cargo/config.toml b/examples/mspm0g3507/.cargo/config.toml new file mode 100644 index 000000000..34c720cdd --- /dev/null +++ b/examples/mspm0g3507/.cargo/config.toml @@ -0,0 +1,9 @@ +[target.'cfg(all(target_arch = "arm", target_os = "none"))'] +# replace MSPM0G3507 with your chip as listed in `probe-rs chip list` +runner = "probe-rs run --chip MSPM0G3507 --protocol=swd" + +[build] +target = "thumbv6m-none-eabi" + +[env] +DEFMT_LOG = "debug" diff --git a/examples/mspm0g3507/Cargo.toml b/examples/mspm0g3507/Cargo.toml new file mode 100644 index 000000000..c1f304174 --- /dev/null +++ b/examples/mspm0g3507/Cargo.toml @@ -0,0 +1,21 @@ +[package] +edition = "2021" +name = "embassy-mspm0-g3507-examples" +version = "0.1.0" +license = "MIT OR Apache-2.0" + +[dependencies] +embassy-mspm0 = { version = "0.1.0", path = "../../embassy-mspm0", features = ["mspm0g350x", "rt", "time-driver-any"] } +embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-4096", "arch-cortex-m", "executor-thread", "executor-interrupt"] } +embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } +embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt"] } +panic-halt = "0.2.0" +cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } +cortex-m-rt = { version = "0.7.0"} +defmt = "0.3" +defmt-rtt = "0.4" +panic-probe = { version = "0.3.2", features = ["print-defmt"] } +panic-semihosting = "0.6.0" + +[profile.release] +debug = 2 diff --git a/examples/mspm0g3507/README.md b/examples/mspm0g3507/README.md new file mode 100644 index 000000000..5e8a83212 --- /dev/null +++ b/examples/mspm0g3507/README.md @@ -0,0 +1,27 @@ +# Examples for MSPM0C350x family + +Run individual examples with +``` +cargo run --bin +``` +for example +``` +cargo run --bin blinky +``` + +## Checklist before running examples +A large number of the examples are written for the [LP-MSPM0G3507](https://www.ti.com/tool/LP-MSPM0G3507) board. + +You might need to adjust `.cargo/config.toml`, `Cargo.toml` and possibly update pin numbers or peripherals to match the specific MCU or board you are using. + +* [ ] Update .cargo/config.toml with the correct probe-rs command to use your specific MCU. For example for G3507 it should be `probe-rs run --chip MSPM0G3507`. (use `probe-rs chip list` to find your chip) +* [ ] Update Cargo.toml to have the correct `embassy-mspm0` feature. For example for G3507 it should be `mspm0g3507`. Look in the `Cargo.toml` file of the `embassy-mspm0` project to find the correct feature flag for your chip. +* [ ] If your board has a special clock or power configuration, make sure that it is set up appropriately. +* [ ] If your board has different pin mapping, update any pin numbers or peripherals in the given example code to match your schematic + +If you are unsure, please drop by the Embassy Matrix chat for support, and let us know: + +* Which example you are trying to run +* Which chip and board you are using + +Embassy Chat: https://matrix.to/#/#embassy-rs:matrix.org diff --git a/examples/mspm0g3507/build.rs b/examples/mspm0g3507/build.rs new file mode 100644 index 000000000..30691aa97 --- /dev/null +++ b/examples/mspm0g3507/build.rs @@ -0,0 +1,35 @@ +//! This build script copies the `memory.x` file from the crate root into +//! a directory where the linker can always find it at build time. +//! For many projects this is optional, as the linker always searches the +//! project root directory -- wherever `Cargo.toml` is. However, if you +//! are using a workspace or have a more complicated build setup, this +//! build script becomes required. Additionally, by requesting that +//! Cargo re-run the build script whenever `memory.x` is changed, +//! updating `memory.x` ensures a rebuild of the application with the +//! new memory settings. + +use std::env; +use std::fs::File; +use std::io::Write; +use std::path::PathBuf; + +fn main() { + // Put `memory.x` in our output directory and ensure it's + // on the linker search path. + let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); + File::create(out.join("memory.x")) + .unwrap() + .write_all(include_bytes!("memory.x")) + .unwrap(); + println!("cargo:rustc-link-search={}", out.display()); + + // By default, Cargo will re-run a build script whenever + // any file in the project changes. By specifying `memory.x` + // here, we ensure the build script is only re-run when + // `memory.x` is changed. + println!("cargo:rerun-if-changed=memory.x"); + + println!("cargo:rustc-link-arg-bins=--nmagic"); + println!("cargo:rustc-link-arg-bins=-Tlink.x"); + println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); +} diff --git a/examples/mspm0g3507/memory.x b/examples/mspm0g3507/memory.x new file mode 100644 index 000000000..37e381fbd --- /dev/null +++ b/examples/mspm0g3507/memory.x @@ -0,0 +1,6 @@ +MEMORY +{ + FLASH : ORIGIN = 0x00000000, LENGTH = 128K + /* Select non-parity range of SRAM due to SRAM_ERR_01 errata in SLAZ758 */ + RAM : ORIGIN = 0x20200000, LENGTH = 32K +} diff --git a/examples/mspm0g3507/src/bin/blinky.rs b/examples/mspm0g3507/src/bin/blinky.rs new file mode 100644 index 000000000..11eee2d80 --- /dev/null +++ b/examples/mspm0g3507/src/bin/blinky.rs @@ -0,0 +1,27 @@ +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_mspm0::{ + gpio::{Level, Output}, + Config, +}; +use embassy_time::Timer; +use {defmt_rtt as _, panic_halt as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) -> ! { + info!("Hello world!"); + let p = embassy_mspm0::init(Config::default()); + + let mut led1 = Output::new(p.PA0, Level::Low); + led1.set_inversion(true); + + loop { + Timer::after_millis(400).await; + + info!("Toggle"); + led1.toggle(); + } +} diff --git a/examples/mspm0g3507/src/bin/button.rs b/examples/mspm0g3507/src/bin/button.rs new file mode 100644 index 000000000..1d9a37c5c --- /dev/null +++ b/examples/mspm0g3507/src/bin/button.rs @@ -0,0 +1,35 @@ +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_mspm0::{ + gpio::{Input, Level, Output, Pull}, + Config, +}; +use {defmt_rtt as _, panic_halt as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) -> ! { + info!("Hello world!"); + + let p = embassy_mspm0::init(Config::default()); + + let led1 = p.PA0; + let s2 = p.PB21; + + let mut led1 = Output::new(led1, Level::Low); + + let mut s2 = Input::new(s2, Pull::Up); + + // led1 is active low + led1.set_high(); + + loop { + s2.wait_for_falling_edge().await; + + info!("Switch 2 was pressed"); + + led1.toggle(); + } +} diff --git a/examples/mspm0g3519/.cargo/config.toml b/examples/mspm0g3519/.cargo/config.toml new file mode 100644 index 000000000..1a4768682 --- /dev/null +++ b/examples/mspm0g3519/.cargo/config.toml @@ -0,0 +1,10 @@ +[target.'cfg(all(target_arch = "arm", target_os = "none"))'] +# replace MSPM0G3519 with your chip as listed in `probe-rs chip list` +# TODO: Remove description path after new chiptool release +runner = "probe-rs run --restore-unwritten --verify --chip MSPM0G3519 --protocol=swd --chip-description-path ./MSPM0GX51X_Series.yaml" + +[build] +target = "thumbv6m-none-eabi" + +[env] +DEFMT_LOG = "trace" diff --git a/examples/mspm0g3519/Cargo.toml b/examples/mspm0g3519/Cargo.toml new file mode 100644 index 000000000..fc6f0e31b --- /dev/null +++ b/examples/mspm0g3519/Cargo.toml @@ -0,0 +1,21 @@ +[package] +edition = "2021" +name = "embassy-mspm0-g3519-examples" +version = "0.1.0" +license = "MIT OR Apache-2.0" + +[dependencies] +embassy-mspm0 = { version = "0.1.0", path = "../../embassy-mspm0", features = ["mspm0g351x", "rt", "time-driver-any"] } +embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-16384", "arch-cortex-m", "executor-thread", "executor-interrupt"] } +embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } +embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt"] } +panic-halt = "0.2.0" +cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } +cortex-m-rt = { version = "0.7.0"} +defmt = "0.3" +defmt-rtt = "0.4" +panic-probe = { version = "0.3.2", features = ["print-defmt"] } +panic-semihosting = "0.6.0" + +[profile.release] +debug = 2 diff --git a/examples/mspm0g3519/MSPM0GX51X_Series.yaml b/examples/mspm0g3519/MSPM0GX51X_Series.yaml new file mode 100644 index 000000000..375623b94 --- /dev/null +++ b/examples/mspm0g3519/MSPM0GX51X_Series.yaml @@ -0,0 +1,424 @@ +name: MSPM0GX51X Series +manufacturer: + id: 0x17 + cc: 0x0 +generated_from_pack: true +pack_file_release: 1.0.0 +variants: +- name: MSPM0G1518 + cores: + - name: main + type: armv6m + core_access_options: !Arm + ap: 0 + memory_map: + - !Nvm + name: IROM1 + range: + start: 0x0 + end: 0x40000 + cores: + - main + access: + write: false + boot: true + - !Generic + name: IROM2 + range: + start: 0x400000 + end: 0x440000 + cores: + - main + access: + write: false + - !Generic + name: IRAM1 + range: + start: 0x20000000 + end: 0x20010000 + cores: + - main + - !Generic + name: IRAM_Parity + range: + start: 0x20100000 + end: 0x20110000 + cores: + - main + - !Ram + name: IRAM_No_Parity + range: + start: 0x20200000 + end: 0x20220000 + cores: + - main + - !Generic + name: IRAM_Parity_Code + range: + start: 0x20300000 + end: 0x20310000 + cores: + - main + - !Generic + name: NonMain_ECC + range: + start: 0x41c00000 + end: 0x41c00800 + cores: + - main + access: + write: false + execute: false + - !Generic + name: Factory_ECC + range: + start: 0x41c40000 + end: 0x41c40200 + cores: + - main + access: + write: false + execute: false + - !Generic + name: Data + range: + start: 0x41d00000 + end: 0x41d04000 + cores: + - main + access: + write: false + execute: false + flash_algorithms: + - mspm0gx51x_main_512kb + - mspm0gx51x_nonmain + - mspm0gx51x_data_16kb +- name: MSPM0G1519 + cores: + - name: main + type: armv6m + core_access_options: !Arm + ap: 0 + memory_map: + - !Nvm + name: IROM1 + range: + start: 0x0 + end: 0x80000 + cores: + - main + access: + write: false + boot: true + - !Generic + name: IROM2 + range: + start: 0x400000 + end: 0x480000 + cores: + - main + access: + write: false + - !Generic + name: IRAM1 + range: + start: 0x20000000 + end: 0x20010000 + cores: + - main + - !Generic + name: IRAM_Parity + range: + start: 0x20100000 + end: 0x20110000 + cores: + - main + - !Ram + name: IRAM_No_Parity + range: + start: 0x20200000 + end: 0x20220000 + cores: + - main + - !Generic + name: IRAM_Parity_Code + range: + start: 0x20300000 + end: 0x20310000 + cores: + - main + - !Generic + name: NonMain_ECC + range: + start: 0x41c00000 + end: 0x41c00800 + cores: + - main + access: + write: false + execute: false + - !Generic + name: Factory_ECC + range: + start: 0x41c40000 + end: 0x41c40200 + cores: + - main + access: + write: false + execute: false + - !Generic + name: Data + range: + start: 0x41d00000 + end: 0x41d04000 + cores: + - main + access: + write: false + execute: false + flash_algorithms: + - mspm0gx51x_main_512kb + - mspm0gx51x_nonmain + - mspm0gx51x_data_16kb +- name: MSPM0G3518 + cores: + - name: main + type: armv6m + core_access_options: !Arm + ap: 0 + memory_map: + - !Nvm + name: IROM1 + range: + start: 0x0 + end: 0x40000 + cores: + - main + access: + write: false + boot: true + - !Generic + name: IROM2 + range: + start: 0x400000 + end: 0x440000 + cores: + - main + access: + write: false + - !Generic + name: IRAM1 + range: + start: 0x20000000 + end: 0x20010000 + cores: + - main + - !Generic + name: IRAM_Parity + range: + start: 0x20100000 + end: 0x20110000 + cores: + - main + - !Ram + name: IRAM_No_Parity + range: + start: 0x20200000 + end: 0x20220000 + cores: + - main + - !Generic + name: IRAM_Parity_Code + range: + start: 0x20300000 + end: 0x20310000 + cores: + - main + - !Generic + name: NonMain_ECC + range: + start: 0x41c00000 + end: 0x41c00800 + cores: + - main + access: + write: false + execute: false + - !Generic + name: Factory_ECC + range: + start: 0x41c40000 + end: 0x41c40200 + cores: + - main + access: + write: false + execute: false + - !Generic + name: Data + range: + start: 0x41d00000 + end: 0x41d04000 + cores: + - main + access: + write: false + execute: false + flash_algorithms: + - mspm0gx51x_main_512kb + - mspm0gx51x_nonmain + - mspm0gx51x_data_16kb +- name: MSPM0G3519 + cores: + - name: main + type: armv6m + core_access_options: !Arm + ap: 0 + memory_map: + - !Nvm + name: IROM1 + range: + start: 0x0 + end: 0x80000 + cores: + - main + access: + write: false + boot: true + - !Generic + name: IROM2 + range: + start: 0x400000 + end: 0x480000 + cores: + - main + access: + write: false + - !Generic + name: IRAM1 + range: + start: 0x20000000 + end: 0x20010000 + cores: + - main + - !Generic + name: IRAM_Parity + range: + start: 0x20100000 + end: 0x20110000 + cores: + - main + - !Ram + name: IRAM_No_Parity + range: + start: 0x20200000 + end: 0x20220000 + cores: + - main + - !Generic + name: IRAM_Parity_Code + range: + start: 0x20300000 + end: 0x20310000 + cores: + - main + - !Generic + name: NonMain_ECC + range: + start: 0x41c00000 + end: 0x41c00800 + cores: + - main + access: + write: false + execute: false + - !Generic + name: Factory_ECC + range: + start: 0x41c40000 + end: 0x41c40200 + cores: + - main + access: + write: false + execute: false + - !Generic + name: Data + range: + start: 0x41d00000 + end: 0x41d04000 + cores: + - main + access: + write: false + execute: false + flash_algorithms: + - mspm0gx51x_main_512kb + - mspm0gx51x_nonmain + - mspm0gx51x_data_16kb +flash_algorithms: +- name: mspm0gx51x_main_512kb + description: MSPM0GX51X MAIN 512KB + default: true + instructions: ESEJAgEiQlADSUEYCmgHIBBABCj60HBH0BMAABC1FEgBaAcikUMBYBJMYWggaAMikEMgYBEgAAQIQAEhCgWQQgXQCQSIQgTRAfC2+QHgAfCL+WBoDyGIQ2BgAfCF+QZIAWgEIpFDAWAA8Aj4ACAQvQATQEAAAQtAEO0A4ARIBSFBYAEhAWADSAFoSQf81HBHAOEMQNDjDEAAIHBHcLUEIMZDACQITeAHB9EALgXQKEYA8Oj5BEZ2HPXnASBEQARA//fc/yBGcL0A0AxA+LUERm1GKUYA8Cj4AUYBICp4ACoB0IUCAOBFAgApGtAEIMdDACAMTsEHEdEALw/Q//e+/zBGIUYqRgDwp/xAIjBGIUYA8ND4fxwA8Cn46+cBIUhACED4vQDQDEAQtQxKE2gFJBRgByQcQApLG2gUYIIKCUgQQAlKGkCQQgHSACMLcJBCAdMAIBC9ASAQvcBGABNAQBgAxEH/7z8A/w8AAIGwCkgBaAciCkAAkgCZybIDKQPQAJnJsgEp89EAmMCywR5IQkhBAbBwR8BG0OMMQP61FEYNRgZGAqn/97//ASEAKCjQAC0m0AcgKEAj0QKoAXgBIAApAdCBAgDgQQIBkQ9PACEALRbQwAcU0P/3UP8KSDFGAZoA8Dn8OGhAB/zUBkgxRiJGAPAf+wg2CDQIPf/3tv/l5whG/r3ARgDQDEDQ4wxAELUFTAFRABkAKwPQAspBYFse+eeAaBC9BBEAABC1BUwBUQAZmkIC2ALKQWD654BoEL3ARgQRAAC8tQpMBBkAlACcIYAISUEYACsG0BSIAZEBnSyAkhxbHvbnBElAWICyvL3ARgQRAAAIEQAADBEAALy1CUwEGQCUAJwhgAdJQRiaQgXYFIgBkQGdLICSHPfnA0lAWICyvL0EEQAACBEAAAwRAAAQtQIjE0MRIhIChBhjYCFiASGBUBC9wEaAtQIjE0MDSoNQghjRYf/3kf6AvQQRAAAQtQRGEUgAISFQIBhBYIFgykMCZBEgAAIiGFIjU2ARYgEhIVAgRgDwKfgJSQpoBSMLYAcjE0AHShJoC2CRDgTQACgC0CBGAPAx+BC90BEAAAATQEAYAMRBA0kAIkJQQBhCYIJgcEfARtARAAAAIclDAUqBUHBHwEYQEgAAgbAKSUAYAWgHIgpAAJIAmcmyAykD0ACZybIBKfPRAJjAssEeSEJIQQGwcEfQEwAA/rUYSxloBSIaYAciCkAWSQloGmARIhICApCAGAGQjw4STQEgAp7/sv83+bK5QhXQwQcT0DBGAPD5+AEkYgIwRilGAPBB+0IgAZlIYA1iDGCgAi0YMEb/97v/5OcBIQhA/r3ARgATQEAYAMRBAADQQRC1BEYQSAAhIVAgGEFggWDKQwJkDUhSIiJQIBjBYSBG//fu/QpJCmgFIwtgByMTQAhKEmgLYJEOBNABKALQIEYA8Ar4EL3ARtARAAAEEQAAABNAQBgAxEGAtQdJACJCUEEYSmCKYAVJUiJCUEEYBErKYf/3xf2AvdARAAAEEQAAAADQQfC1h7AERgDwhfgFRjpIAWgFIgJgByIKQDhJCWgCYDhIIBgCkBEgAAIElCYYNUgIQClGAfBf+CpGgAIBkGgIBpAQIAWQACcBJD1GIEYDkgCUlUJJ0sEHR9AGmIVCAdIAIQDgASEoSABoQAUgRgDVCEYpBokOBdH5FTtGJKd5Wh9GBZEAKCBGKtAEnCBGAPBU+AEgAQSyaApDsmAfIQkBBZoKQLNoi0OZGLFgDyFJArJoikNBAlEYsWAAIQKaEWBRYJFgyUMRZFIhcWApRgGaUUMxYjBgIEYAnP/3AP8DmgEhCQZ/GG0cs+cBIQoEs2iTQ7NgCEAHsPC9ABNAQBgAxEHQEQAA/w8AAEggC0AQACAAQACAAAZIAWgFIgJgByIKQARJCWgCYIgEgA9AHHBHwEYAE0BAGADEQREhCQJCGAUjU2ABIkJQAkgBaEkH/NRwR9DjDEAQtQRG//eC/gAoENAJSCAYESEJAmEYACICYEIgSGAGSAhiASAIYCBG//eu/hC9ACAQvcBGEBIAAAAAwEEBSQAiQlBwRxASAAAQtQRG//fs/gMoDNEGSCAYBklhGAAiCmBCIQFgBEnBYSBG//fd/BC9BBEAABASAAAAAMBBELUERv/3FP8AKBDQCUggGBEhCQJhGAAiAmBCIEhgBkgIYgEgCGAgRv/3cP4QvQAgEL3ARhASAAAAAMBBsLURIxsCxBgBJWVgZWIhYhF4IWPFULC9ELUFSwEkxFDDGBxi2WEReNli//eh/BC9BBEAAHC1ESMbAsQYASVlYAMmZmIhYhGIIWPFUHC9wEYQtQZLASTEUMMYAyQcYtlhEYjZYv/3hPwQvcBGBBEAAHC1ESMbAsQYASVlYA8mZmIhYhFoIWPFUHC9wEYQtQZLASTEUMMYDyQcYtlhEWjZYv/3ZvwQvcBGBBEAAHC1ESMbAsQYASVlYP8mZmIhYhFoIWNRaGFjxVBwvcBGELUHSwEkxFDDGP8kHGLZYRFo2WJRaBlj//dE/BC9wEYEEQAAcLURIxsCxBgBJWVg/yYCNmZiIWIReCFjxVBwvRC1BksBJMRQwxj/JAI0HGLZYRF42WL/9yX8EL0EEQAAcLURIxsCxBgBJWVg/yYENmZiIWIRiCFjxVBwvRC1BksBJMRQwxj/JAQ0HGLZYRGI2WL/9wf8EL0EEQAAcLURIxsCxBgBJWVg/yYQNmZiIWIRaCFjxVBwvRC1BksBJMRQwxj/JBA0HGLZYRFo2WL/9+n7EL0EEQAAcLURIxsCxBgBJWVgBE5mYiFiEWghY1FoYWPFUHC9wEb/AQAAELUHSwEkxFDDGAZMHGLZYRFo2WJRaBlj//fG+xC9wEYEEQAA/wEAAPC1ESQkAgUZASZuYP8nAjdvYiliEXgpYxl4AkqBUAZR8L3ARrARAACwtQhMASUFUQQZ/yUCNSVi4WEReOFiGXgDSoFQ//ec+7C9wEYEEQAAsBEAAPC1ESQkAgUZASZuYP8nBDdvYiliEYgpYxl4AkqBUAZR8L3ARrARAACwtQhMASUFUQQZ/yUENSVi4WERiOFiGXgDSoFQ//dy+7C9wEYEEQAAsBEAAPC1ESQkAgUZASZuYP8nEDdvYiliEWgpYxl4AkqBUAZR8L3ARrARAACwtQhMASUFUQQZ/yUQNSVi4WERaOFiGXgDSoFQ//dI+7C9wEYEEQAAsBEAAPC1ESQkAgUZASZuYAVPb2IpYhFoKWNRaGljGXgCSoFQBlHwvf8BAACwEQAAsLUITAElBVEEGQdNJWLhYRFo4WJRaCFjGXgESoFQ//cb+7C9BBEAAP8BAACwEQAA8LWHsB9GBpIFkQRGASEYRgSRCEBBQkFBWh4YRpBBCEARIQkCA5RhGAKRDJkBkQOdAC8f0MEHHdAoRv/30/0oRgWcIUYBmgDwG/gEmQKaUWAKSFBiFGIGnjBoEGNwaFBjEWAINAWUvx4oRv/3jfwINgaW3ecEmQhAB7Dwvf8BAABwtRVGDEYLSUYYIEYA8D75ASGKApVCBNBKApVCCNHACALgPDZgBMAOgUAwaIhDMGBwvcBG1BEAAPi1HEYVRg5GB0YBIdgHAdAIRgDgBCAALADRCEYGmQCRACwQ0MGyASkN0DhGMUYAmv/3yv84RjFGKkb/98X+CDYINaQe7OfAsvi9wEbwtYewBpMEkgORA0YBIQyfOEYCkQhAQUJBQXoeOEaQQQhAGElZGAGRESEJAgWTXBgNmQCRAC8h0MEHH9AFmAOdKUYAmv/3mv8CmmJgDkhgYiViBJ4waCBjcGhgYwaZCHgBmxhgImAINQOVSRwGkb8eBZj/9wf8CDYEltvnApkIQAew8L2wEQAA/wEAAP61ApMVRg5GAZAInwEh+AcB0AhGAOAEIAAvANEIRgmZAJEALxXQwbIBKRLQAZwgRjFGAJr/91z/IEYxRipGApwjRv/3/f4INmQcApQINb8e5+fAsv69/rUfRhRGDUYCRlkeGEaIQREhCQICklYYCJkBkQAvJdDBByPQApgpRgGa//c2/wEgcGABLwvQ/yFxYjViIWgxY2FocWMwYL8eCCECIAfgDyFxYjViIWgxYzBgACcEIW0YgAAkGAKY//ec+9fnASEIQP69+LUfRhRGDUYGRgArAdAEIADgASAGmQCRAC8b0MGyASkY0DBGKUYAmv/3/v4wRilGIkYBLwXQ//d5/b8eCCECIgTg//dT/QAnBCEBIm0YkQBkGOHnwLL4vQNJACJCUEAYQmCCYHBHwEbQEQAAACHJQwJKgVCAGEFggWBwR9ARAAAESQAiQlBAGEJggmACZEJkgmRwR9ARAAAAIclDBEqBUIAYQWCBYAFkQWSBZHBHwEbQEQAAELUERv/3VvwBRgtKEGgFIxNgByMDQAlIAGgTYKQKAikI0wdKEEAA8DX8AUYgRgDwMfwMRiBGEL0AE0BAGADEQf8PAABwtRVGDEYLSUYYIEb/99b/ASGKApVCBNBKApVCCNHACALgPDZgBMAOgUAwaAhDMGBwvcBG1BEAALC1ESMbAsQYAyVlYCFiASFhYhJ4ImPBULC9sLURIxsCxBgDJWVgIWJlYhGIIWMBIcFQsL2wtREjGwLEGAMlZWAhYg8hYWIRaCFjASHBULC9sLURIxsCxBgDJWVgIWL/IWFiEWghY1FoYWMBIcFQsL0QtQZLAyTEUMMYASQcYtlhEXjZYv/3DPkQvcBGBBEAABC1BUsDJMRQwxgcYtlhEYjZYv/3/fgQvQQRAAAQtQZLAyTEUMMYDyQcYtlhEWjZYv/37vgQvcBGBBEAABC1B0sDJMRQwxj/JBxi2WERaNliUWgZY//33PgQvcBGBBEAABC1BksDJMRQwxj/JAI0HGLZYRF42WL/98v4EL0EEQAAELUGSwMkxFDDGP8kBDQcYtlhEYjZYv/3u/gQvQQRAAAQtQZLAyTEUMMY/yQQNBxi2WERaNli//er+BC9BBEAABC1B0sDJMRQwxgGTBxi2WERaNliUWgZY//3mvgQvcBGBBEAAP8BAACwtQhMAyUFUQQZ/yUCNSVi4WEReOFiGXgDSoFQ//eE+LC9wEYEEQAAsBEAALC1CEwDJQVRBBn/JQQ1JWLhYRGI4WIZeANKgVD/9274sL3ARgQRAACwEQAAsLUITAMlBVEEGf8lEDUlYuFhEWjhYhl4A0qBUP/3WPiwvcBGBBEAALARAACwtQhMAyUFUQQZB00lYuFhEWjhYlFoIWMZeARKgVD/90H4sL0EEQAA/wEAALARAACwtREjGwLEGAMlZWAhYv8hAjFhYhF4IWMBIcFQsL2wtREjGwLEGAMlZWAhYv8hBDFhYhGIIWMBIcFQsL2wtREjGwLEGAMlZWAhYv8hEDFhYhFoIWMBIcFQsL3ARrC1ESMbAsQYAyVlYCFiBElhYhFoIWNRaGFjASHBULC9/wEAAHC1ESQkAgUZAyZuYCli/yECMWliEXgpYxl4AkqBUAEhAVFwvbARAABwtREkJAIFGQMmbmApYv8hBDFpYhGIKWMZeAJKgVABIQFRcL2wEQAAcLURJCQCBRkDJm5gKWL/IRAxaWIRaCljGXgCSoFQASEBUXC9sBEAAHC1ESQkAgUZAyZuYCliBklpYhFoKWNRaGljGXgDSoFQASEBUXC9wEb/AQAAsBEAABC1ESISAoMYBiRcYBliASGBUBC9gLUESgYjg1CCGNFh/veU/4C9wEYEEQAAELUTRgRGBEoA8Aj4ESAAAgEhIVAQvcBG//8AALC1B0wRJQVRABkCYsFhGWjBYlloAWOZaEFj2WiBY7C9BBEAABC1E0YERgRK//fo/xEgAAIBISFQEL3ARv//AQCwtR1GE0YERgZK//fZ/yh4BUlgUGAYaXhBYBEgAAIBISFQsL3//wEAsBEAAPC1hbAfRhRGDUYCRhEgAQIAKwHQAy8B2AAgAOABIASSVhgKmQOR/yEQMQKRAZYALzrQwQc40ASYKUYDmv/3WPwBLxDQAy8a2AEgcGACmfAxcWI1YiFoMWNhaHFjMGC/HgghAiIJ4AEicmACmHBiNWIhaDFjMmAAJwQhBJgO4C5GJUYEnCBGMUYqRv/3lf8gRixGNUYBnj8fECEEIm0YkQBkGP/3qfjC5wEhCEAFsPC9/7UBJCICKksZaAOSkUMZYChJDWhtBPzVRX4lQJ5ppkN0GZxhICQEXQMlLEDeaa5DNBncYSBMJWgFJiZgRmo3aB9idmheYgcmLkAmYMRpfyUtAt5prkNkBmQMNBncYQdoRWiCaACSxmgCaQGSQmkCkpppEkwUQDoHEgstA62yqhgyQwCdLQctDRVDAZoVQwKaFUMAfihDCkoCQBAZmGEYaAOaEEMYYAhogAX81f+9wEYIAQtABAILQAATQECNAPD/cv8PALC1/yIEMg5JC2iTQ4J4AyQUQAJ4EgISGRpDCmAJSgpLE2AKTCVobQX81UB4ACgD0AhoECQEQwxgWBwQYLC9wEYUAQtAFAMLQAEAAJEEAgtADEkKaAAoA9ABIIACAkMG4AMggkMKYAEggAIKaIJDCmABIAAFSmgCQ0pgA0gBaIkD/NVwRwABC0AEAgtAASCBAgZKE2iLQxNgAAVRaIFDUWADSAFoiQP81HBHwEYAAQtABAILQAdJiGAHSAJokgL81QEiEgQLaBNDC2ABaMkG/NVwR8BGBAELQAQCC0ABIAAEBEkKaIJDCmADSAFoyQb81HBHwEYEAQtABAILQBC1D0kLaAEik0MLYAMjGwMYQIxonEMgGIhgiGgIIwND9yCDQ4tgCGgQQwhgEAeKaAJDimADSAFoyQX81RC9wEYIAQtABAILQHC1EUsdaAEkpUMdYAMlLQMoQJ5orkMwGJhgmGj/JahDybJAGJhgGGggQxhgmGghBwAqBtAIQ5hgBEgBaMkF/NVwvYhDmGBwvQgBC0AEAgtAsLU/IxsEBEwlaJ1DCEMQQxhAKBggYLC9OAELQAlIAGhABwjUCEhBaMkCBtQAaIAFBdUDIHBHACBwRwIgcEcBIHBHwEYQ7QDgAAELQApJCmwAIAAqANBwRwhKEmhSB/rVCGjABQTUCGiABQPVAyBwRwIgcEcBIHBHAAELQBDtAOAHScprACABKgfRBkoSaFIHA9UIaIACAdUCIHBHASBwRwQBC0AQ7QDgELUISxxrASIiQAjRBkwgQBhgIUBZYNhqBEkBQ9liUEJQQRC9GCALQMD/PwAQAAB2ELUIS5xqASIiQAjRBkwgQBhgIUAZYFhqBEkBQ1liUEJQQRC9ICALQMD/PwBAAAB2ACIDCYtCLNMDCotCEdMAI5xGTuADRgtDPNQAIkMIi0Ix0wMJi0Ic0wMKi0IB05RGP+DDCYtCAdPLAcAaUkGDCYtCAdOLAcAaUkFDCYtCAdNLAcAaUkEDCYtCAdMLAcAaUkHDCItCAdPLAMAaUkGDCItCAdOLAMAaUkFDCItCAdNLAMAaUkFBGgDSAUZSQRBGcEdd4MoPANBJQgMQANNAQlNAnEYAIgMJi0It0wMKi0IS04kB/CISugMKi0IM04kBkhGLQgjTiQGSEYtCBNOJATrQkhEA4IkJwwmLQgHTywHAGlJBgwmLQgHTiwHAGlJBQwmLQgHTSwHAGlJBAwmLQgHTCwHAGlJBwwiLQgHTywDAGlJBgwiLQgHTiwDAGlJB2dJDCItCAdNLAMAaUkFBGgDSAUZSQRBGY0ZbEAHTQEIAKwDVSUJwR2NGWxAA00BCAbUFSQAoAtxJHAhAAOAIRsBGwEYCvQC/////fwAAAAA= + load_address: 0x20200008 + pc_init: 0x1d + pc_uninit: 0x99 + pc_program_page: 0x19d + pc_erase_sector: 0xcd + pc_erase_all: 0x9d + data_section_offset: 0x16e4 + flash_properties: + address_range: + start: 0x0 + end: 0x80000 + page_size: 0x400 + erased_byte_value: 0xff + program_page_timeout: 500 + erase_sector_timeout: 3000 + sectors: + - size: 0x400 + address: 0x0 +- name: mspm0gx51x_nonmain + description: MSPM0GX51X NON-MAIN + instructions: ESEJAgEiQlADSUEYCmgHIBBABCj60HBH0BMAABC1GEgBaAcikUMBYBZIF0kBYBdMYWggaAMikEMgYBEgAAQIQAEhCgWQQgXQCQSIQgTRAfDj+QHgAfC4+WBoDyGIQ2BgAfCy+QpIAWgEIpFDAWAA8BP4CEkCIAhgACDCQ0pgEL0AE0BAAAhEQAEAACYAAQtAEO0A4AARREAESAUhQWABIQFgA0gBaEkH/NRwRwDhDEDQ4wxA/rUBIYhDAig90QCRACACkMBDAZAfTS4jHUwgRgGfOUYqRgDwy/gGRhYjIEY5RhpKAPDE+ARGMEYgQx/QKEYA8DH4uCEVSnpEL0YoRgDwUvhYIRNKekQQSADwTPgALgPQApkDKQbZEOABIAAsB9ACmQQpBNJJHAKRPUbM5wKYACgAmADQ/r0AIP69AJj+vcBGAABEQAAAwEEAAcBBRhYAABgZAAD4tQRGQAoQSYhCGNEEIMZDACAOTQEnwQcT0QAuEdD/94//ugIoRiFGAPCa/EAiKEYhRgDww/h2HADwVvjq5wEg+L14QDhA+L0A4CAAANAMQPi1FEYNRgZGQQoBIBNKkUIi0QAtINAHISlAHdEBIRFPACAALRjQyQcW0P/3Yf8BIIICC0gxRgDwa/w4aEAH/NQHSDFGIkYA8FH7CDYINAg9APAi+AFG4+f4vcBGAOAgAADQDEDQ4wxAcLUEIMZDACQITeAHB9EALgXQKEYA8F75BEZ2HPXnASBEQARA//cw/yBGcL0A0AxAgbAKSAFoByIKQACSAJnJsgMpA9AAmcmyASnz0QCYwLLBHkhCSEEBsHBHwEbQ4wxAELUFTAFRABkAKwPQAspBYFse+eeAaBC9BBEAABC1BUwBUQAZmkIC2ALKQWD654BoEL3ARgQRAAC8tQpMBBkAlACcIYAISUEYACsG0BSIAZEBnSyAkhxbHvbnBElAWICyvL3ARgQRAAAIEQAADBEAALy1CUwEGQCUAJwhgAdJQRiaQgXYFIgBkQGdLICSHPfnA0lAWICyvL0EEQAACBEAAAwRAAAQtQIjE0MRIhIChBhjYCFiASGBUBC9wEaAtQIjE0MDSoNQghjRYf/3Yf6AvQQRAAAQtQRGEUgAISFQIBhBYIFgykMCZBEgAAIiGFIjU2ARYgEhIVAgRgDwKfgJSQpoBSMLYAcjE0AHShJoC2CRDgTQACgC0CBGAPAx+BC90BEAAAATQEAYAMRBA0kAIkJQQBhCYIJgcEfARtARAAAAIclDAUqBUHBHwEYQEgAAgbAKSUAYAWgHIgpAAJIAmcmyAykD0ACZybIBKfPRAJjAssEeSEJIQQGwcEfQEwAA/rUYSxloBSIaYAciCkAWSQloGmARIhICApCAGAGQjw4STQEgAp7/sv83+bK5QhXQwQcT0DBGAPD5+AEkYgIwRilGAPBB+0IgAZlIYA1iDGCgAi0YMEb/97v/5OcBIQhA/r3ARgATQEAYAMRBAADQQRC1BEYQSAAhIVAgGEFggWDKQwJkDUhSIiJQIBjBYSBG//e+/QpJCmgFIwtgByMTQAhKEmgLYJEOBNABKALQIEYA8Ar4EL3ARtARAAAEEQAAABNAQBgAxEGAtQdJACJCUEEYSmCKYAVJUiJCUEEYBErKYf/3lf2AvdARAAAEEQAAAADQQfC1h7AERgDwhfgFRjpIAWgFIgJgByIKQDhJCWgCYDhIIBgCkBEgAAIElCYYNUgIQClGAfBf+CpGgAIBkGgIBpAQIAWQACcBJD1GIEYDkgCUlUJJ0sEHR9AGmIVCAdIAIQDgASEoSABoQAUgRgDVCEYpBokOBdH5FTtGJKd5Wh9GBZEAKCBGKtAEnCBGAPBU+AEgAQSyaApDsmAfIQkBBZoKQLNoi0OZGLFgDyFJArJoikNBAlEYsWAAIQKaEWBRYJFgyUMRZFIhcWApRgGaUUMxYjBgIEYAnP/3AP8DmgEhCQZ/GG0cs+cBIQoEs2iTQ7NgCEAHsPC9ABNAQBgAxEHQEQAA/w8AAEggC0AQACAAQACAAAZIAWgFIgJgByIKQARJCWgCYIgEgA9AHHBHwEYAE0BAGADEQREhCQJCGAUjU2ABIkJQAkgBaEkH/NRwR9DjDEAQtQRG//eC/gAoENAJSCAYESEJAmEYACICYEIgSGAGSAhiASAIYCBG//eu/hC9ACAQvcBGEBIAAAAAwEEBSQAiQlBwRxASAAAQtQRG//fs/gMoDNEGSCAYBklhGAAiCmBCIQFgBEnBYSBG//et/BC9BBEAABASAAAAAMBBELUERv/3FP8AKBDQCUggGBEhCQJhGAAiAmBCIEhgBkgIYgEgCGAgRv/3cP4QvQAgEL3ARhASAAAAAMBBsLURIxsCxBgBJWVgZWIhYhF4IWPFULC9ELUFSwEkxFDDGBxi2WEReNli//dx/BC9BBEAAHC1ESMbAsQYASVlYAMmZmIhYhGIIWPFUHC9wEYQtQZLASTEUMMYAyQcYtlhEYjZYv/3VPwQvcBGBBEAAHC1ESMbAsQYASVlYA8mZmIhYhFoIWPFUHC9wEYQtQZLASTEUMMYDyQcYtlhEWjZYv/3NvwQvcBGBBEAAHC1ESMbAsQYASVlYP8mZmIhYhFoIWNRaGFjxVBwvcBGELUHSwEkxFDDGP8kHGLZYRFo2WJRaBlj//cU/BC9wEYEEQAAcLURIxsCxBgBJWVg/yYCNmZiIWIReCFjxVBwvRC1BksBJMRQwxj/JAI0HGLZYRF42WL/9/X7EL0EEQAAcLURIxsCxBgBJWVg/yYENmZiIWIRiCFjxVBwvRC1BksBJMRQwxj/JAQ0HGLZYRGI2WL/99f7EL0EEQAAcLURIxsCxBgBJWVg/yYQNmZiIWIRaCFjxVBwvRC1BksBJMRQwxj/JBA0HGLZYRFo2WL/97n7EL0EEQAAcLURIxsCxBgBJWVgBE5mYiFiEWghY1FoYWPFUHC9wEb/AQAAELUHSwEkxFDDGAZMHGLZYRFo2WJRaBlj//eW+xC9wEYEEQAA/wEAAPC1ESQkAgUZASZuYP8nAjdvYiliEXgpYxl4AkqBUAZR8L3ARrARAACwtQhMASUFUQQZ/yUCNSVi4WEReOFiGXgDSoFQ//ds+7C9wEYEEQAAsBEAAPC1ESQkAgUZASZuYP8nBDdvYiliEYgpYxl4AkqBUAZR8L3ARrARAACwtQhMASUFUQQZ/yUENSVi4WERiOFiGXgDSoFQ//dC+7C9wEYEEQAAsBEAAPC1ESQkAgUZASZuYP8nEDdvYiliEWgpYxl4AkqBUAZR8L3ARrARAACwtQhMASUFUQQZ/yUQNSVi4WERaOFiGXgDSoFQ//cY+7C9wEYEEQAAsBEAAPC1ESQkAgUZASZuYAVPb2IpYhFoKWNRaGljGXgCSoFQBlHwvf8BAACwEQAAsLUITAElBVEEGQdNJWLhYRFo4WJRaCFjGXgESoFQ//fr+rC9BBEAAP8BAACwEQAA8LWHsB9GBpIFkQRGASEYRgSRCEBBQkFBWh4YRpBBCEARIQkCA5RhGAKRDJkBkQOdAC8f0MEHHdAoRv/30/0oRgWcIUYBmgDwG/gEmQKaUWAKSFBiFGIGnjBoEGNwaFBjEWAINAWUvx4oRv/3jfwINgaW3ecEmQhAB7Dwvf8BAABwtRVGDEYLSUYYIEYA8D75ASGKApVCBNBKApVCCNHACALgPDZgBMAOgUAwaIhDMGBwvcBG1BEAAPi1HEYVRg5GB0YBIdgHAdAIRgDgBCAALADRCEYGmQCRACwQ0MGyASkN0DhGMUYAmv/3yv84RjFGKkb/98X+CDYINaQe7OfAsvi9wEbwtYewBpMEkgORA0YBIQyfOEYCkQhAQUJBQXoeOEaQQQhAGElZGAGRESEJAgWTXBgNmQCRAC8h0MEHH9AFmAOdKUYAmv/3mv8CmmJgDkhgYiViBJ4waCBjcGhgYwaZCHgBmxhgImAINQOVSRwGkb8eBZj/9wf8CDYEltvnApkIQAew8L2wEQAA/wEAAP61ApMVRg5GAZAInwEh+AcB0AhGAOAEIAAvANEIRgmZAJEALxXQwbIBKRLQAZwgRjFGAJr/91z/IEYxRipGApwjRv/3/f4INmQcApQINb8e5+fAsv69/rUfRhRGDUYCRlkeGEaIQREhCQICklYYCJkBkQAvJdDBByPQApgpRgGa//c2/wEgcGABLwvQ/yFxYjViIWgxY2FocWMwYL8eCCECIAfgDyFxYjViIWgxYzBgACcEIW0YgAAkGAKY//ec+9fnASEIQP69+LUfRhRGDUYGRgArAdAEIADgASAGmQCRAC8b0MGyASkY0DBGKUYAmv/3/v4wRilGIkYBLwXQ//d5/b8eCCECIgTg//dT/QAnBCEBIm0YkQBkGOHnwLL4vQNJACJCUEAYQmCCYHBHwEbQEQAAACHJQwJKgVCAGEFggWBwR9ARAAAESQAiQlBAGEJggmACZEJkgmRwR9ARAAAAIclDBEqBUIAYQWCBYAFkQWSBZHBHwEbQEQAAELUERv/3VvwBRgtKEGgFIxNgByMDQAlIAGgTYKQKAikI0wdKEEAA8DX8AUYgRgDwMfwMRiBGEL0AE0BAGADEQf8PAABwtRVGDEYLSUYYIEb/99b/ASGKApVCBNBKApVCCNHACALgPDZgBMAOgUAwaAhDMGBwvcBG1BEAALC1ESMbAsQYAyVlYCFiASFhYhJ4ImPBULC9sLURIxsCxBgDJWVgIWJlYhGIIWMBIcFQsL2wtREjGwLEGAMlZWAhYg8hYWIRaCFjASHBULC9sLURIxsCxBgDJWVgIWL/IWFiEWghY1FoYWMBIcFQsL0QtQZLAyTEUMMYASQcYtlhEXjZYv/33PgQvcBGBBEAABC1BUsDJMRQwxgcYtlhEYjZYv/3zfgQvQQRAAAQtQZLAyTEUMMYDyQcYtlhEWjZYv/3vvgQvcBGBBEAABC1B0sDJMRQwxj/JBxi2WERaNliUWgZY//3rPgQvcBGBBEAABC1BksDJMRQwxj/JAI0HGLZYRF42WL/95v4EL0EEQAAELUGSwMkxFDDGP8kBDQcYtlhEYjZYv/3i/gQvQQRAAAQtQZLAyTEUMMY/yQQNBxi2WERaNli//d7+BC9BBEAABC1B0sDJMRQwxgGTBxi2WERaNliUWgZY//3avgQvcBGBBEAAP8BAACwtQhMAyUFUQQZ/yUCNSVi4WEReOFiGXgDSoFQ//dU+LC9wEYEEQAAsBEAALC1CEwDJQVRBBn/JQQ1JWLhYRGI4WIZeANKgVD/9z74sL3ARgQRAACwEQAAsLUITAMlBVEEGf8lEDUlYuFhEWjhYhl4A0qBUP/3KPiwvcBGBBEAALARAACwtQhMAyUFUQQZB00lYuFhEWjhYlFoIWMZeARKgVD/9xH4sL0EEQAA/wEAALARAACwtREjGwLEGAMlZWAhYv8hAjFhYhF4IWMBIcFQsL2wtREjGwLEGAMlZWAhYv8hBDFhYhGIIWMBIcFQsL2wtREjGwLEGAMlZWAhYv8hEDFhYhFoIWMBIcFQsL3ARrC1ESMbAsQYAyVlYCFiBElhYhFoIWNRaGFjASHBULC9/wEAAHC1ESQkAgUZAyZuYCli/yECMWliEXgpYxl4AkqBUAEhAVFwvbARAABwtREkJAIFGQMmbmApYv8hBDFpYhGIKWMZeAJKgVABIQFRcL2wEQAAcLURJCQCBRkDJm5gKWL/IRAxaWIRaCljGXgCSoFQASEBUXC9sBEAAHC1ESQkAgUZAyZuYCliBklpYhFoKWNRaGljGXgDSoFQASEBUXC9wEb/AQAAsBEAABC1ESISAoMYBiRcYBliASGBUBC9gLUESgYjg1CCGNFh/vdk/4C9wEYEEQAAELUTRgRGBEoA8Aj4ESAAAgEhIVAQvcBG//8AALC1B0wRJQVRABkCYsFhGWjBYlloAWOZaEFj2WiBY7C9BBEAABC1E0YERgRK//fo/xEgAAIBISFQEL3ARv//AQCwtR1GE0YERgZK//fZ/yh4BUlgUGAYaXhBYBEgAAIBISFQsL3//wEAsBEAAPC1hbAfRhRGDUYCRhEgAQIAKwHQAy8B2AAgAOABIASSVhgKmQOR/yEQMQKRAZYALzrQwQc40ASYKUYDmv/3WPwBLxDQAy8a2AEgcGACmfAxcWI1YiFoMWNhaHFjMGC/HgghAiIJ4AEicmACmHBiNWIhaDFjMmAAJwQhBJgO4C5GJUYEnCBGMUYqRv/3lf8gRixGNUYBnj8fECEEIm0YkQBkGP/3qfjC5wEhCEAFsPC9/7UBJCICKksZaAOSkUMZYChJDWhtBPzVRX4lQJ5ppkN0GZxhICQEXQMlLEDeaa5DNBncYSBMJWgFJiZgRmo3aB9idmheYgcmLkAmYMRpfyUtAt5prkNkBmQMNBncYQdoRWiCaACSxmgCaQGSQmkCkpppEkwUQDoHEgstA62yqhgyQwCdLQctDRVDAZoVQwKaFUMAfihDCkoCQBAZmGEYaAOaEEMYYAhogAX81f+9wEYIAQtABAILQAATQECNAPD/cv8PALC1/yIEMg5JC2iTQ4J4AyQUQAJ4EgISGRpDCmAJSgpLE2AKTCVobQX81UB4ACgD0AhoECQEQwxgWBwQYLC9wEYUAQtAFAMLQAEAAJEEAgtADEkKaAAoA9ABIIACAkMG4AMggkMKYAEggAIKaIJDCmABIAAFSmgCQ0pgA0gBaIkD/NVwRwABC0AEAgtAASCBAgZKE2iLQxNgAAVRaIFDUWADSAFoiQP81HBHwEYAAQtABAILQAdJiGAHSAJokgL81QEiEgQLaBNDC2ABaMkG/NVwR8BGBAELQAQCC0ABIAAEBEkKaIJDCmADSAFoyQb81HBHwEYEAQtABAILQBC1D0kLaAEik0MLYAMjGwMYQIxonEMgGIhgiGgIIwND9yCDQ4tgCGgQQwhgEAeKaAJDimADSAFoyQX81RC9wEYIAQtABAILQHC1EUsdaAEkpUMdYAMlLQMoQJ5orkMwGJhgmGj/JahDybJAGJhgGGggQxhgmGghBwAqBtAIQ5hgBEgBaMkF/NVwvYhDmGBwvQgBC0AEAgtAsLU/IxsEBEwlaJ1DCEMQQxhAKBggYLC9OAELQAlIAGhABwjUCEhBaMkCBtQAaIAFBdUDIHBHACBwRwIgcEcBIHBHwEYQ7QDgAAELQApJCmwAIAAqANBwRwhKEmhSB/rVCGjABQTUCGiABQPVAyBwRwIgcEcBIHBHAAELQBDtAOAHScprACABKgfRBkoSaFIHA9UIaIACAdUCIHBHASBwRwQBC0AQ7QDgELUISxxrASIiQAjRBkwgQBhgIUBZYNhqBEkBQ9liUEJQQRC9GCALQMD/PwAQAAB2ELUIS5xqASIiQAjRBkwgQBhgIUAZYFhqBEkBQ1liUEJQQRC9ICALQMD/PwBAAAB2ACIDCYtCLNMDCotCEdMAI5xGTuADRgtDPNQAIkMIi0Ix0wMJi0Ic0wMKi0IB05RGP+DDCYtCAdPLAcAaUkGDCYtCAdOLAcAaUkFDCYtCAdNLAcAaUkEDCYtCAdMLAcAaUkHDCItCAdPLAMAaUkGDCItCAdOLAMAaUkFDCItCAdNLAMAaUkFBGgDSAUZSQRBGcEdd4MoPANBJQgMQANNAQlNAnEYAIgMJi0It0wMKi0IS04kB/CISugMKi0IM04kBkhGLQgjTiQGSEYtCBNOJATrQkhEA4IkJwwmLQgHTywHAGlJBgwmLQgHTiwHAGlJBQwmLQgHTSwHAGlJBAwmLQgHTCwHAGlJBwwiLQgHTywDAGlJBgwiLQgHTiwDAGlJB2dJDCItCAdNLAMAaUkFBGgDSAUZSQRBGY0ZbEAHTQEIAKwDVSUJwR2NGWxAA00BCAbUFSQAoAtxJHAhAAOAIRsBGwEYCvQC/////fwAAAAS7qruqu6q7qv//////////u6q7qruqu6r//7uqu6q7qv///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////9B/+hoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEFgIVAgEDAgOoEv//r5YTdg9yY1+9tEpaCmPDnxKvMPlQpu5clxvhiOicQFH/////////////////////////////////////////////SADJWPEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + load_address: 0x20200008 + pc_init: 0x1d + pc_uninit: 0xb5 + pc_program_page: 0x1a9 + pc_erase_sector: 0x159 + pc_erase_all: 0x211 + data_section_offset: 0x1b84 + flash_properties: + address_range: + start: 0x41c00000 + end: 0x41c00400 + page_size: 0x40 + erased_byte_value: 0xff + program_page_timeout: 500 + erase_sector_timeout: 3000 + sectors: + - size: 0x400 + address: 0x0 +- name: mspm0gx51x_data_16kb + description: MSPM0GX51X DATA 16KB + instructions: ESEJAgEiQlADSUEYCmgHIBBABCj60HBH0BMAABC1FEgBaAcikUMBYBJMYWggaAMikEMgYBEgAAQIQAEhCgWQQgXQCQSIQgTRAfC2+QHgAfCL+WBoDyGIQ2BgAfCF+QZIAWgEIpFDAWAA8Aj4ACAQvQATQEAAAQtAEO0A4ARIBSFBYAEhAWADSAFoSQf81HBHAOEMQNDjDEAAIHBHcLUEIMZDACQITeAHB9EALgXQKEYA8G75BEZ2HPXnASBEQARA//fc/yBGcL0A0AxA+LUERm1GKUYA8Cj4AUYBICp4ACoB0IUCAOBFAgApGtAEIMdDACAMTsEHEdEALw/Q//e+/zBGIUYqRgDwp/xAIjBGIUYA8ND4fxwA8Cn46+cBIUhACED4vQDQDEAQtQxKE2gFJBRgByQcQApLG2gUYIIKCUgQQAlKGkCQQgHSACMLcJBCAdMAIBC9ASAQvcBGABNAQBgAxEH/7z8A/w8AAIGwCkgBaAciCkAAkgCZybIDKQPQAJnJsgEp89EAmMCywR5IQkhBAbBwR8BG0OMMQP61FEYNRgZGAqn/97//ASEAKCjQAC0m0AcgKEAj0QKoAXgBIAApAdCBAgDgQQIBkQ9PACEALRbQwAcU0P/3UP8KSDFGAZoA8Dn8OGhAB/zUBkgxRiJGAPAf+wg2CDQIPf/3tv/l5whG/r3ARgDQDEDQ4wxAELUFTAFRABkAKwPQAspBYFse+eeAaBC9BBEAABC1BUwBUQAZmkIC2ALKQWD654BoEL3ARgQRAAC8tQpMBBkAlACcIYAISUEYACsG0BSIAZEBnSyAkhxbHvbnBElAWICyvL3ARgQRAAAIEQAADBEAALy1CUwEGQCUAJwhgAdJQRiaQgXYFIgBkQGdLICSHPfnA0lAWICyvL0EEQAACBEAAAwRAAAQtQIjE0MRIhIChBhjYCFiASGBUBC9wEaAtQIjE0MDSoNQghjRYf/3kf6AvQQRAAAQtQRGEUgAISFQIBhBYIFgykMCZBEgAAIiGFIjU2ARYgEhIVAgRgDwKfgJSQpoBSMLYAcjE0AHShJoC2CRDgTQACgC0CBGAPAx+BC90BEAAAATQEAYAMRBA0kAIkJQQBhCYIJgcEfARtARAAAAIclDAUqBUHBHwEYQEgAAgbAKSUAYAWgHIgpAAJIAmcmyAykD0ACZybIBKfPRAJjAssEeSEJIQQGwcEfQEwAA/rUYSxloBSIaYAciCkAWSQloGmARIhICApCAGAGQjw4STQEgAp7/sv83+bK5QhXQwQcT0DBGAPD5+AEkYgIwRilGAPBB+0IgAZlIYA1iDGCgAi0YMEb/97v/5OcBIQhA/r3ARgATQEAYAMRBAADQQRC1BEYQSAAhIVAgGEFggWDKQwJkDUhSIiJQIBjBYSBG//fu/QpJCmgFIwtgByMTQAhKEmgLYJEOBNABKALQIEYA8Ar4EL3ARtARAAAEEQAAABNAQBgAxEGAtQdJACJCUEEYSmCKYAVJUiJCUEEYBErKYf/3xf2AvdARAAAEEQAAAADQQfC1h7AERgDwhfgFRjpIAWgFIgJgByIKQDhJCWgCYDhIIBgCkBEgAAIElCYYNUgIQClGAfBf+CpGgAIBkGgIBpAQIAWQACcBJD1GIEYDkgCUlUJJ0sEHR9AGmIVCAdIAIQDgASEoSABoQAUgRgDVCEYpBokOBdH5FTtGJKd5Wh9GBZEAKCBGKtAEnCBGAPBU+AEgAQSyaApDsmAfIQkBBZoKQLNoi0OZGLFgDyFJArJoikNBAlEYsWAAIQKaEWBRYJFgyUMRZFIhcWApRgGaUUMxYjBgIEYAnP/3AP8DmgEhCQZ/GG0cs+cBIQoEs2iTQ7NgCEAHsPC9ABNAQBgAxEHQEQAA/w8AAEggC0AQACAAQACAAAZIAWgFIgJgByIKQARJCWgCYIgEgA9AHHBHwEYAE0BAGADEQREhCQJCGAUjU2ABIkJQAkgBaEkH/NRwR9DjDEAQtQRG//eC/gAoENAJSCAYESEJAmEYACICYEIgSGAGSAhiASAIYCBG//eu/hC9ACAQvcBGEBIAAAAAwEEBSQAiQlBwRxASAAAQtQRG//fs/gMoDNEGSCAYBklhGAAiCmBCIQFgBEnBYSBG//fd/BC9BBEAABASAAAAAMBBELUERv/3FP8AKBDQCUggGBEhCQJhGAAiAmBCIEhgBkgIYgEgCGAgRv/3cP4QvQAgEL3ARhASAAAAAMBBsLURIxsCxBgBJWVgZWIhYhF4IWPFULC9ELUFSwEkxFDDGBxi2WEReNli//eh/BC9BBEAAHC1ESMbAsQYASVlYAMmZmIhYhGIIWPFUHC9wEYQtQZLASTEUMMYAyQcYtlhEYjZYv/3hPwQvcBGBBEAAHC1ESMbAsQYASVlYA8mZmIhYhFoIWPFUHC9wEYQtQZLASTEUMMYDyQcYtlhEWjZYv/3ZvwQvcBGBBEAAHC1ESMbAsQYASVlYP8mZmIhYhFoIWNRaGFjxVBwvcBGELUHSwEkxFDDGP8kHGLZYRFo2WJRaBlj//dE/BC9wEYEEQAAcLURIxsCxBgBJWVg/yYCNmZiIWIReCFjxVBwvRC1BksBJMRQwxj/JAI0HGLZYRF42WL/9yX8EL0EEQAAcLURIxsCxBgBJWVg/yYENmZiIWIRiCFjxVBwvRC1BksBJMRQwxj/JAQ0HGLZYRGI2WL/9wf8EL0EEQAAcLURIxsCxBgBJWVg/yYQNmZiIWIRaCFjxVBwvRC1BksBJMRQwxj/JBA0HGLZYRFo2WL/9+n7EL0EEQAAcLURIxsCxBgBJWVgBE5mYiFiEWghY1FoYWPFUHC9wEb/AQAAELUHSwEkxFDDGAZMHGLZYRFo2WJRaBlj//fG+xC9wEYEEQAA/wEAAPC1ESQkAgUZASZuYP8nAjdvYiliEXgpYxl4AkqBUAZR8L3ARrARAACwtQhMASUFUQQZ/yUCNSVi4WEReOFiGXgDSoFQ//ec+7C9wEYEEQAAsBEAAPC1ESQkAgUZASZuYP8nBDdvYiliEYgpYxl4AkqBUAZR8L3ARrARAACwtQhMASUFUQQZ/yUENSVi4WERiOFiGXgDSoFQ//dy+7C9wEYEEQAAsBEAAPC1ESQkAgUZASZuYP8nEDdvYiliEWgpYxl4AkqBUAZR8L3ARrARAACwtQhMASUFUQQZ/yUQNSVi4WERaOFiGXgDSoFQ//dI+7C9wEYEEQAAsBEAAPC1ESQkAgUZASZuYAVPb2IpYhFoKWNRaGljGXgCSoFQBlHwvf8BAACwEQAAsLUITAElBVEEGQdNJWLhYRFo4WJRaCFjGXgESoFQ//cb+7C9BBEAAP8BAACwEQAA8LWHsB9GBpIFkQRGASEYRgSRCEBBQkFBWh4YRpBBCEARIQkCA5RhGAKRDJkBkQOdAC8f0MEHHdAoRv/30/0oRgWcIUYBmgDwG/gEmQKaUWAKSFBiFGIGnjBoEGNwaFBjEWAINAWUvx4oRv/3jfwINgaW3ecEmQhAB7Dwvf8BAABwtRVGDEYLSUYYIEYA8D75ASGKApVCBNBKApVCCNHACALgPDZgBMAOgUAwaIhDMGBwvcBG1BEAAPi1HEYVRg5GB0YBIdgHAdAIRgDgBCAALADRCEYGmQCRACwQ0MGyASkN0DhGMUYAmv/3yv84RjFGKkb/98X+CDYINaQe7OfAsvi9wEbwtYewBpMEkgORA0YBIQyfOEYCkQhAQUJBQXoeOEaQQQhAGElZGAGRESEJAgWTXBgNmQCRAC8h0MEHH9AFmAOdKUYAmv/3mv8CmmJgDkhgYiViBJ4waCBjcGhgYwaZCHgBmxhgImAINQOVSRwGkb8eBZj/9wf8CDYEltvnApkIQAew8L2wEQAA/wEAAP61ApMVRg5GAZAInwEh+AcB0AhGAOAEIAAvANEIRgmZAJEALxXQwbIBKRLQAZwgRjFGAJr/91z/IEYxRipGApwjRv/3/f4INmQcApQINb8e5+fAsv69/rUfRhRGDUYCRlkeGEaIQREhCQICklYYCJkBkQAvJdDBByPQApgpRgGa//c2/wEgcGABLwvQ/yFxYjViIWgxY2FocWMwYL8eCCECIAfgDyFxYjViIWgxYzBgACcEIW0YgAAkGAKY//ec+9fnASEIQP69+LUfRhRGDUYGRgArAdAEIADgASAGmQCRAC8b0MGyASkY0DBGKUYAmv/3/v4wRilGIkYBLwXQ//d5/b8eCCECIgTg//dT/QAnBCEBIm0YkQBkGOHnwLL4vQNJACJCUEAYQmCCYHBHwEbQEQAAACHJQwJKgVCAGEFggWBwR9ARAAAESQAiQlBAGEJggmACZEJkgmRwR9ARAAAAIclDBEqBUIAYQWCBYAFkQWSBZHBHwEbQEQAAELUERv/3VvwBRgtKEGgFIxNgByMDQAlIAGgTYKQKAikI0wdKEEAA8DX8AUYgRgDwMfwMRiBGEL0AE0BAGADEQf8PAABwtRVGDEYLSUYYIEb/99b/ASGKApVCBNBKApVCCNHACALgPDZgBMAOgUAwaAhDMGBwvcBG1BEAALC1ESMbAsQYAyVlYCFiASFhYhJ4ImPBULC9sLURIxsCxBgDJWVgIWJlYhGIIWMBIcFQsL2wtREjGwLEGAMlZWAhYg8hYWIRaCFjASHBULC9sLURIxsCxBgDJWVgIWL/IWFiEWghY1FoYWMBIcFQsL0QtQZLAyTEUMMYASQcYtlhEXjZYv/3DPkQvcBGBBEAABC1BUsDJMRQwxgcYtlhEYjZYv/3/fgQvQQRAAAQtQZLAyTEUMMYDyQcYtlhEWjZYv/37vgQvcBGBBEAABC1B0sDJMRQwxj/JBxi2WERaNliUWgZY//33PgQvcBGBBEAABC1BksDJMRQwxj/JAI0HGLZYRF42WL/98v4EL0EEQAAELUGSwMkxFDDGP8kBDQcYtlhEYjZYv/3u/gQvQQRAAAQtQZLAyTEUMMY/yQQNBxi2WERaNli//er+BC9BBEAABC1B0sDJMRQwxgGTBxi2WERaNliUWgZY//3mvgQvcBGBBEAAP8BAACwtQhMAyUFUQQZ/yUCNSVi4WEReOFiGXgDSoFQ//eE+LC9wEYEEQAAsBEAALC1CEwDJQVRBBn/JQQ1JWLhYRGI4WIZeANKgVD/9274sL3ARgQRAACwEQAAsLUITAMlBVEEGf8lEDUlYuFhEWjhYhl4A0qBUP/3WPiwvcBGBBEAALARAACwtQhMAyUFUQQZB00lYuFhEWjhYlFoIWMZeARKgVD/90H4sL0EEQAA/wEAALARAACwtREjGwLEGAMlZWAhYv8hAjFhYhF4IWMBIcFQsL2wtREjGwLEGAMlZWAhYv8hBDFhYhGIIWMBIcFQsL2wtREjGwLEGAMlZWAhYv8hEDFhYhFoIWMBIcFQsL3ARrC1ESMbAsQYAyVlYCFiBElhYhFoIWNRaGFjASHBULC9/wEAAHC1ESQkAgUZAyZuYCli/yECMWliEXgpYxl4AkqBUAEhAVFwvbARAABwtREkJAIFGQMmbmApYv8hBDFpYhGIKWMZeAJKgVABIQFRcL2wEQAAcLURJCQCBRkDJm5gKWL/IRAxaWIRaCljGXgCSoFQASEBUXC9sBEAAHC1ESQkAgUZAyZuYCliBklpYhFoKWNRaGljGXgDSoFQASEBUXC9wEb/AQAAsBEAABC1ESISAoMYBiRcYBliASGBUBC9gLUESgYjg1CCGNFh/veU/4C9wEYEEQAAELUTRgRGBEoA8Aj4ESAAAgEhIVAQvcBG//8AALC1B0wRJQVRABkCYsFhGWjBYlloAWOZaEFj2WiBY7C9BBEAABC1E0YERgRK//fo/xEgAAIBISFQEL3ARv//AQCwtR1GE0YERgZK//fZ/yh4BUlgUGAYaXhBYBEgAAIBISFQsL3//wEAsBEAAPC1hbAfRhRGDUYCRhEgAQIAKwHQAy8B2AAgAOABIASSVhgKmQOR/yEQMQKRAZYALzrQwQc40ASYKUYDmv/3WPwBLxDQAy8a2AEgcGACmfAxcWI1YiFoMWNhaHFjMGC/HgghAiIJ4AEicmACmHBiNWIhaDFjMmAAJwQhBJgO4C5GJUYEnCBGMUYqRv/3lf8gRixGNUYBnj8fECEEIm0YkQBkGP/3qfjC5wEhCEAFsPC9/7UBJCICKksZaAOSkUMZYChJDWhtBPzVRX4lQJ5ppkN0GZxhICQEXQMlLEDeaa5DNBncYSBMJWgFJiZgRmo3aB9idmheYgcmLkAmYMRpfyUtAt5prkNkBmQMNBncYQdoRWiCaACSxmgCaQGSQmkCkpppEkwUQDoHEgstA62yqhgyQwCdLQctDRVDAZoVQwKaFUMAfihDCkoCQBAZmGEYaAOaEEMYYAhogAX81f+9wEYIAQtABAILQAATQECNAPD/cv8PALC1/yIEMg5JC2iTQ4J4AyQUQAJ4EgISGRpDCmAJSgpLE2AKTCVobQX81UB4ACgD0AhoECQEQwxgWBwQYLC9wEYUAQtAFAMLQAEAAJEEAgtADEkKaAAoA9ABIIACAkMG4AMggkMKYAEggAIKaIJDCmABIAAFSmgCQ0pgA0gBaIkD/NVwRwABC0AEAgtAASCBAgZKE2iLQxNgAAVRaIFDUWADSAFoiQP81HBHwEYAAQtABAILQAdJiGAHSAJokgL81QEiEgQLaBNDC2ABaMkG/NVwR8BGBAELQAQCC0ABIAAEBEkKaIJDCmADSAFoyQb81HBHwEYEAQtABAILQBC1D0kLaAEik0MLYAMjGwMYQIxonEMgGIhgiGgIIwND9yCDQ4tgCGgQQwhgEAeKaAJDimADSAFoyQX81RC9wEYIAQtABAILQHC1EUsdaAEkpUMdYAMlLQMoQJ5orkMwGJhgmGj/JahDybJAGJhgGGggQxhgmGghBwAqBtAIQ5hgBEgBaMkF/NVwvYhDmGBwvQgBC0AEAgtAsLU/IxsEBEwlaJ1DCEMQQxhAKBggYLC9OAELQAlIAGhABwjUCEhBaMkCBtQAaIAFBdUDIHBHACBwRwIgcEcBIHBHwEYQ7QDgAAELQApJCmwAIAAqANBwRwhKEmhSB/rVCGjABQTUCGiABQPVAyBwRwIgcEcBIHBHAAELQBDtAOAHScprACABKgfRBkoSaFIHA9UIaIACAdUCIHBHASBwRwQBC0AQ7QDgELUISxxrASIiQAjRBkwgQBhgIUBZYNhqBEkBQ9liUEJQQRC9GCALQMD/PwAQAAB2ELUIS5xqASIiQAjRBkwgQBhgIUAZYFhqBEkBQ1liUEJQQRC9ICALQMD/PwBAAAB2ACIDCYtCLNMDCotCEdMAI5xGTuADRgtDPNQAIkMIi0Ix0wMJi0Ic0wMKi0IB05RGP+DDCYtCAdPLAcAaUkGDCYtCAdOLAcAaUkFDCYtCAdNLAcAaUkEDCYtCAdMLAcAaUkHDCItCAdPLAMAaUkGDCItCAdOLAMAaUkFDCItCAdNLAMAaUkFBGgDSAUZSQRBGcEdd4MoPANBJQgMQANNAQlNAnEYAIgMJi0It0wMKi0IS04kB/CISugMKi0IM04kBkhGLQgjTiQGSEYtCBNOJATrQkhEA4IkJwwmLQgHTywHAGlJBgwmLQgHTiwHAGlJBQwmLQgHTSwHAGlJBAwmLQgHTCwHAGlJBwwiLQgHTywDAGlJBgwiLQgHTiwDAGlJB2dJDCItCAdNLAMAaUkFBGgDSAUZSQRBGY0ZbEAHTQEIAKwDVSUJwR2NGWxAA00BCAbUFSQAoAtxJHAhAAOAIRsBGwEYCvQC/////fwAAAAA= + load_address: 0x20200008 + pc_init: 0x1d + pc_uninit: 0x99 + pc_program_page: 0x19d + pc_erase_sector: 0xcd + pc_erase_all: 0x9d + data_section_offset: 0x16e4 + flash_properties: + address_range: + start: 0x0 + end: 0x4000 + page_size: 0x400 + erased_byte_value: 0xff + program_page_timeout: 500 + erase_sector_timeout: 3000 + sectors: + - size: 0x400 + address: 0x0 diff --git a/examples/mspm0g3519/README.md b/examples/mspm0g3519/README.md new file mode 100644 index 000000000..5034b1913 --- /dev/null +++ b/examples/mspm0g3519/README.md @@ -0,0 +1,27 @@ +# Examples for MSPM0G351x family + +Run individual examples with +``` +cargo run --bin +``` +for example +``` +cargo run --bin blinky +``` + +## Checklist before running examples +A large number of the examples are written for the [LP-MSPM0G3519](https://www.ti.com/tool/LP-MSPM0G3519) board. + +You might need to adjust `.cargo/config.toml`, `Cargo.toml` and possibly update pin numbers or peripherals to match the specific MCU or board you are using. + +* [ ] Update .cargo/config.toml with the correct probe-rs command to use your specific MCU. For example for G3519 it should be `probe-rs run --chip MSPM0G3519`. (use `probe-rs chip list` to find your chip) +* [ ] Update Cargo.toml to have the correct `embassy-mspm0` feature. For example for G3519 it should be `mspm0g3519`. Look in the `Cargo.toml` file of the `embassy-mspm0` project to find the correct feature flag for your chip. +* [ ] If your board has a special clock or power configuration, make sure that it is set up appropriately. +* [ ] If your board has different pin mapping, update any pin numbers or peripherals in the given example code to match your schematic + +If you are unsure, please drop by the Embassy Matrix chat for support, and let us know: + +* Which example you are trying to run +* Which chip and board you are using + +Embassy Chat: https://matrix.to/#/#embassy-rs:matrix.org diff --git a/examples/mspm0g3519/build.rs b/examples/mspm0g3519/build.rs new file mode 100644 index 000000000..30691aa97 --- /dev/null +++ b/examples/mspm0g3519/build.rs @@ -0,0 +1,35 @@ +//! This build script copies the `memory.x` file from the crate root into +//! a directory where the linker can always find it at build time. +//! For many projects this is optional, as the linker always searches the +//! project root directory -- wherever `Cargo.toml` is. However, if you +//! are using a workspace or have a more complicated build setup, this +//! build script becomes required. Additionally, by requesting that +//! Cargo re-run the build script whenever `memory.x` is changed, +//! updating `memory.x` ensures a rebuild of the application with the +//! new memory settings. + +use std::env; +use std::fs::File; +use std::io::Write; +use std::path::PathBuf; + +fn main() { + // Put `memory.x` in our output directory and ensure it's + // on the linker search path. + let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); + File::create(out.join("memory.x")) + .unwrap() + .write_all(include_bytes!("memory.x")) + .unwrap(); + println!("cargo:rustc-link-search={}", out.display()); + + // By default, Cargo will re-run a build script whenever + // any file in the project changes. By specifying `memory.x` + // here, we ensure the build script is only re-run when + // `memory.x` is changed. + println!("cargo:rerun-if-changed=memory.x"); + + println!("cargo:rustc-link-arg-bins=--nmagic"); + println!("cargo:rustc-link-arg-bins=-Tlink.x"); + println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); +} diff --git a/examples/mspm0g3519/memory.x b/examples/mspm0g3519/memory.x new file mode 100644 index 000000000..e6e0ec9e9 --- /dev/null +++ b/examples/mspm0g3519/memory.x @@ -0,0 +1,6 @@ +MEMORY +{ + FLASH : ORIGIN = 0x00000000, LENGTH = 512K + /* Select non-parity range of SRAM due to SRAM_ERR_01 errata in SLAZ758 */ + RAM : ORIGIN = 0x20200000, LENGTH = 128K +} diff --git a/examples/mspm0g3519/src/bin/blinky.rs b/examples/mspm0g3519/src/bin/blinky.rs new file mode 100644 index 000000000..11eee2d80 --- /dev/null +++ b/examples/mspm0g3519/src/bin/blinky.rs @@ -0,0 +1,27 @@ +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_mspm0::{ + gpio::{Level, Output}, + Config, +}; +use embassy_time::Timer; +use {defmt_rtt as _, panic_halt as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) -> ! { + info!("Hello world!"); + let p = embassy_mspm0::init(Config::default()); + + let mut led1 = Output::new(p.PA0, Level::Low); + led1.set_inversion(true); + + loop { + Timer::after_millis(400).await; + + info!("Toggle"); + led1.toggle(); + } +} diff --git a/examples/mspm0g3519/src/bin/button.rs b/examples/mspm0g3519/src/bin/button.rs new file mode 100644 index 000000000..2bdb2bcb1 --- /dev/null +++ b/examples/mspm0g3519/src/bin/button.rs @@ -0,0 +1,35 @@ +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_mspm0::{ + gpio::{Input, Level, Output, Pull}, + Config, +}; +use {defmt_rtt as _, panic_halt as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) -> ! { + info!("Hello world!"); + + let p = embassy_mspm0::init(Config::default()); + + let led1 = p.PA0; + let s2 = p.PB3; + + let mut led1 = Output::new(led1, Level::Low); + + let mut s2 = Input::new(s2, Pull::Up); + + // led1 is active low + led1.set_high(); + + loop { + s2.wait_for_falling_edge().await; + + info!("Switch 2 was pressed"); + + led1.toggle(); + } +} diff --git a/examples/mspm0l1306/.cargo/config.toml b/examples/mspm0l1306/.cargo/config.toml new file mode 100644 index 000000000..93f148a71 --- /dev/null +++ b/examples/mspm0l1306/.cargo/config.toml @@ -0,0 +1,9 @@ +[target.'cfg(all(target_arch = "arm", target_os = "none"))'] +# replace MSPM0L1306 with your chip as listed in `probe-rs chip list` +runner = "probe-rs run --chip MSPM0L1306 --protocol=swd" + +[build] +target = "thumbv6m-none-eabi" + +[env] +DEFMT_LOG = "trace" diff --git a/examples/mspm0l1306/Cargo.toml b/examples/mspm0l1306/Cargo.toml new file mode 100644 index 000000000..6b87916b8 --- /dev/null +++ b/examples/mspm0l1306/Cargo.toml @@ -0,0 +1,21 @@ +[package] +edition = "2021" +name = "embassy-mspm0-l1306-examples" +version = "0.1.0" +license = "MIT OR Apache-2.0" + +[dependencies] +embassy-mspm0 = { version = "0.1.0", path = "../../embassy-mspm0", features = ["mspm0l130x", "rt", "time-driver-any"] } +embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-1024", "arch-cortex-m", "executor-thread", "executor-interrupt"] } +embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } +embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt"] } +panic-halt = "0.2.0" +cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } +cortex-m-rt = { version = "0.7.0"} +defmt = "0.3" +defmt-rtt = "0.4" +panic-probe = { version = "0.3.2", features = ["print-defmt"] } +panic-semihosting = "0.6.0" + +[profile.release] +debug = 2 diff --git a/examples/mspm0l1306/README.md b/examples/mspm0l1306/README.md new file mode 100644 index 000000000..5a55d721e --- /dev/null +++ b/examples/mspm0l1306/README.md @@ -0,0 +1,27 @@ +# Examples for MSPM0L130x family + +Run individual examples with +``` +cargo run --bin +``` +for example +``` +cargo run --bin blinky +``` + +## Checklist before running examples +A large number of the examples are written for the [LP-MSPM0L1306](https://www.ti.com/tool/LP-MSPM0L1306) board. + +You might need to adjust `.cargo/config.toml`, `Cargo.toml` and possibly update pin numbers or peripherals to match the specific MCU or board you are using. + +* [ ] Update .cargo/config.toml with the correct probe-rs command to use your specific MCU. For example for L1306 it should be `probe-rs run --chip MSPM0L1306`. (use `probe-rs chip list` to find your chip) +* [ ] Update Cargo.toml to have the correct `embassy-mspm0` feature. For example for L1306 it should be `mspm0l1306`. Look in the `Cargo.toml` file of the `embassy-mspm0` project to find the correct feature flag for your chip. +* [ ] If your board has a special clock or power configuration, make sure that it is set up appropriately. +* [ ] If your board has different pin mapping, update any pin numbers or peripherals in the given example code to match your schematic + +If you are unsure, please drop by the Embassy Matrix chat for support, and let us know: + +* Which example you are trying to run +* Which chip and board you are using + +Embassy Chat: https://matrix.to/#/#embassy-rs:matrix.org diff --git a/examples/mspm0l1306/build.rs b/examples/mspm0l1306/build.rs new file mode 100644 index 000000000..30691aa97 --- /dev/null +++ b/examples/mspm0l1306/build.rs @@ -0,0 +1,35 @@ +//! This build script copies the `memory.x` file from the crate root into +//! a directory where the linker can always find it at build time. +//! For many projects this is optional, as the linker always searches the +//! project root directory -- wherever `Cargo.toml` is. However, if you +//! are using a workspace or have a more complicated build setup, this +//! build script becomes required. Additionally, by requesting that +//! Cargo re-run the build script whenever `memory.x` is changed, +//! updating `memory.x` ensures a rebuild of the application with the +//! new memory settings. + +use std::env; +use std::fs::File; +use std::io::Write; +use std::path::PathBuf; + +fn main() { + // Put `memory.x` in our output directory and ensure it's + // on the linker search path. + let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); + File::create(out.join("memory.x")) + .unwrap() + .write_all(include_bytes!("memory.x")) + .unwrap(); + println!("cargo:rustc-link-search={}", out.display()); + + // By default, Cargo will re-run a build script whenever + // any file in the project changes. By specifying `memory.x` + // here, we ensure the build script is only re-run when + // `memory.x` is changed. + println!("cargo:rerun-if-changed=memory.x"); + + println!("cargo:rustc-link-arg-bins=--nmagic"); + println!("cargo:rustc-link-arg-bins=-Tlink.x"); + println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); +} diff --git a/examples/mspm0l1306/memory.x b/examples/mspm0l1306/memory.x new file mode 100644 index 000000000..d93b61f44 --- /dev/null +++ b/examples/mspm0l1306/memory.x @@ -0,0 +1,5 @@ +MEMORY +{ + FLASH : ORIGIN = 0x00000000, LENGTH = 64K + RAM : ORIGIN = 0x20000000, LENGTH = 4K +} diff --git a/examples/mspm0l1306/src/bin/blinky.rs b/examples/mspm0l1306/src/bin/blinky.rs new file mode 100644 index 000000000..11eee2d80 --- /dev/null +++ b/examples/mspm0l1306/src/bin/blinky.rs @@ -0,0 +1,27 @@ +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_mspm0::{ + gpio::{Level, Output}, + Config, +}; +use embassy_time::Timer; +use {defmt_rtt as _, panic_halt as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) -> ! { + info!("Hello world!"); + let p = embassy_mspm0::init(Config::default()); + + let mut led1 = Output::new(p.PA0, Level::Low); + led1.set_inversion(true); + + loop { + Timer::after_millis(400).await; + + info!("Toggle"); + led1.toggle(); + } +} diff --git a/examples/mspm0l1306/src/bin/button.rs b/examples/mspm0l1306/src/bin/button.rs new file mode 100644 index 000000000..2813518c2 --- /dev/null +++ b/examples/mspm0l1306/src/bin/button.rs @@ -0,0 +1,35 @@ +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_mspm0::{ + gpio::{Input, Level, Output, Pull}, + Config, +}; +use {defmt_rtt as _, panic_halt as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) -> ! { + info!("Hello world!"); + + let p = embassy_mspm0::init(Config::default()); + + let led1 = p.PA0; + let s2 = p.PA14; + + let mut led1 = Output::new(led1, Level::Low); + + let mut s2 = Input::new(s2, Pull::Up); + + // led1 is active low + led1.set_high(); + + loop { + s2.wait_for_falling_edge().await; + + info!("Switch 2 was pressed"); + + led1.toggle(); + } +} diff --git a/examples/mspm0l2228/.cargo/config.toml b/examples/mspm0l2228/.cargo/config.toml new file mode 100644 index 000000000..4284749e9 --- /dev/null +++ b/examples/mspm0l2228/.cargo/config.toml @@ -0,0 +1,10 @@ +[target.'cfg(all(target_arch = "arm", target_os = "none"))'] +# replace MSPM0L2228 with your chip as listed in `probe-rs chip list` +# TODO: Remove description path after new chiptool release +runner = "probe-rs run --restore-unwritten --verify --chip MSPM0L2228 --protocol=swd --chip-description-path ./MSPM0L122X_L222X_Series.yaml" + +[build] +target = "thumbv6m-none-eabi" + +[env] +DEFMT_LOG = "trace" diff --git a/examples/mspm0l2228/Cargo.toml b/examples/mspm0l2228/Cargo.toml new file mode 100644 index 000000000..9474c2ced --- /dev/null +++ b/examples/mspm0l2228/Cargo.toml @@ -0,0 +1,21 @@ +[package] +edition = "2021" +name = "embassy-mspm0-l2228-examples" +version = "0.1.0" +license = "MIT OR Apache-2.0" + +[dependencies] +embassy-mspm0 = { version = "0.1.0", path = "../../embassy-mspm0", features = ["mspm0l222x", "rt", "time-driver-any"] } +embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-1024", "arch-cortex-m", "executor-thread", "executor-interrupt"] } +embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } +embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt"] } +panic-halt = "0.2.0" +cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } +cortex-m-rt = { version = "0.7.0"} +defmt = "0.3" +defmt-rtt = "0.4" +panic-probe = { version = "0.3.2", features = ["print-defmt"] } +panic-semihosting = "0.6.0" + +[profile.release] +debug = 2 diff --git a/examples/mspm0l2228/MSPM0L122X_L222X_Series.yaml b/examples/mspm0l2228/MSPM0L122X_L222X_Series.yaml new file mode 100644 index 000000000..ac52fda2e --- /dev/null +++ b/examples/mspm0l2228/MSPM0L122X_L222X_Series.yaml @@ -0,0 +1,239 @@ +name: MSPM0L122X_L222X Series +manufacturer: + id: 0x17 + cc: 0x0 +generated_from_pack: true +pack_file_release: 1.1.1 +variants: +- name: MSPM0L1227 + cores: + - name: main + type: armv6m + core_access_options: !Arm + ap: 0 + memory_map: + - !Nvm + name: IROM1 + range: + start: 0x0 + end: 0x20000 + cores: + - main + access: + write: false + boot: true + - !Ram + name: IRAM1 + range: + start: 0x20200000 + end: 0x20208000 + cores: + - main + - !Generic + name: NonMain + range: + start: 0x41c00000 + end: 0x41c00200 + cores: + - main + access: + write: false + execute: false + - !Generic + name: Factory + range: + start: 0x41c40000 + end: 0x41c40080 + cores: + - main + access: + write: false + execute: false + flash_algorithms: + - mspm0l122x_l222x_main_256kb + - mspm0l122x_l222x_nonmain +- name: MSPM0L1228 + cores: + - name: main + type: armv6m + core_access_options: !Arm + ap: 0 + memory_map: + - !Nvm + name: IROM1 + range: + start: 0x0 + end: 0x40000 + cores: + - main + access: + write: false + boot: true + - !Ram + name: IRAM1 + range: + start: 0x20200000 + end: 0x20208000 + cores: + - main + - !Generic + name: NonMain + range: + start: 0x41c00000 + end: 0x41c00200 + cores: + - main + access: + write: false + execute: false + - !Generic + name: Factory + range: + start: 0x41c40000 + end: 0x41c40080 + cores: + - main + access: + write: false + execute: false + flash_algorithms: + - mspm0l122x_l222x_main_256kb + - mspm0l122x_l222x_nonmain +- name: MSPM0L2227 + cores: + - name: main + type: armv6m + core_access_options: !Arm + ap: 0 + memory_map: + - !Nvm + name: IROM1 + range: + start: 0x0 + end: 0x20000 + cores: + - main + access: + write: false + boot: true + - !Ram + name: IRAM1 + range: + start: 0x20200000 + end: 0x20208000 + cores: + - main + - !Generic + name: NonMain + range: + start: 0x41c00000 + end: 0x41c00200 + cores: + - main + access: + write: false + execute: false + - !Generic + name: Factory + range: + start: 0x41c40000 + end: 0x41c40080 + cores: + - main + access: + write: false + execute: false + flash_algorithms: + - mspm0l122x_l222x_main_256kb + - mspm0l122x_l222x_nonmain +- name: MSPM0L2228 + cores: + - name: main + type: armv6m + core_access_options: !Arm + ap: 0 + memory_map: + - !Nvm + name: IROM1 + range: + start: 0x0 + end: 0x40000 + cores: + - main + access: + write: false + boot: true + - !Ram + name: IRAM1 + range: + start: 0x20200000 + end: 0x20208000 + cores: + - main + - !Generic + name: NonMain + range: + start: 0x41c00000 + end: 0x41c00200 + cores: + - main + access: + write: false + execute: false + - !Generic + name: Factory + range: + start: 0x41c40000 + end: 0x41c40080 + cores: + - main + access: + write: false + execute: false + flash_algorithms: + - mspm0l122x_l222x_main_256kb + - mspm0l122x_l222x_nonmain +flash_algorithms: +- name: mspm0l122x_l222x_main_256kb + description: MSPM0L122X_222X MAIN 256KB + default: true + instructions: ESEJAgEiQlADSUEYCmgHIBBABCj60HBH0BMAABC1DEgBaAcikUMBYApMIGgDIYhDIGAB8Hn4YGgPIYhDYGAB8HP4BUgBaAQikUMBYAAgEL0AE0BAAAELQBDtAOAAIHBH/rUERgKpAPA1+AAoB9ACqAB4ASEAKAGRBNCKAgPgASUoRv69SgIQSCFGAPCR/AUnACUPTihGfx4pRmlBwAfv0QAp7dBAIghIIUYA8OH4APAz+AAo79AFIQRKUWABmRFgMWhJB/zU5ucA0AxAAOEMQNDjDEAQtQxKE2gFJBRgByQcQApLG2gUYIIKCUgQQAlKGkCQQgHSACMLcJBCAdMAIBC9ASAQvcBGABNAQBgAxEH/7z8A/w8AAARIAWjJB/zQAGgCIQFASAhwR8BG0OMMQIC1A0gA8Fj5ASFIQIC9wEYA0AxA/rUURg1GBkYCqf/3wf8BIQAoMNAALS7QByAoQCvRAqgBeAEgACkB0IECAOBBAgGRFE8AIQAtHtDABxzQD0gxRgGaAPAT/DhoQAf81AtIMUYiRgDw//oINgg0CD3/97r/ACjm0AUhBkpRYAEhEWA5aEkH/NTd5whG/r3ARgDQDEAA4QxA0OMMQBC1BUwBUQAZACsD0ALKQWBbHvnngGgQvQQRAAAQtQVMAVEAGZpCAtgCykFg+ueAaBC9wEYEEQAAvLUKTAQZAJQAnCGACElBGAArBtAUiAGRAZ0sgJIcWx725wRJQFiAsry9wEYEEQAACBEAAAwRAAC8tQlMBBkAlACcIYAHSUEYmkIF2BSIAZEBnSyAkhz35wNJQFiAsry9BBEAAAgRAAAMEQAAELUCIxNDESISAoQYY2AhYgEhgVAQvcBGgLUCIxNDA0qDUIIY0WH/97P+gL0EEQAAELUERhFIACEhUCAYQWCBYMpDAmQRIAACIhhSI1NgEWIBISFQIEYA8Cn4CUkKaAUjC2AHIxNAB0oSaAtgkQ4E0AAoAtAgRgDwJfgQvdARAAAAE0BAGADEQQNJACJCUEAYQmCCYHBHwEbQEQAAACHJQwFKgVBwR8BGEBIAAARJQBgBaMkH/NAAaAIhAUBICHBH0BMAAIC1CUkAIkJQQRhKYIpgESEJAkIYUiNTYARLE2IBIkJQ//fi/4C9wEbQEQAAAADQQRC1BEYQSAAhIVAgGEFggWDKQwJkDUhSIiJQIBjBYSBG//c8/gpJCmgFIwtgByMTQAhKEmgLYJEOBNABKALQIEYA8Ar4EL3ARtARAAAEEQAAABNAQBgAxEGAtQdJACJCUEEYSmCKYAVJUiJCUEEYBErKYf/3E/6AvdARAAAEEQAAAADQQfC1ibAERgDwk/gFRkFKEGgFIQGREWAHIQCRCEA+SQloEGA+SCAYBJARIAACBpQnGDtICEApRgDwp/4qRoACA5BoCAiQECAHkAAkASYlRjBGBZYCkpVCRNLBB0LQCJiFQgHSACEA4AEhLkgAaEAFMEYA1QhGKQaJDgPR4RUqo1laB5EAKDBGJ9ABIAEEumgKQ7pgHyEJAQeaCkAmRrtoi0OZGLlgDyFJArpoikNBAlEYuWAAIQSaEWBRYJFgyUMRZFIheWApRgOaUUM5YjhgBpj/9zD/ApoFngEhCQZkGG0cuOcBJCEEumiKQ7pgCUsZaAGaGmAAmhFAB0oSaBlgkQ4A0MZD8QcC0QaY//cf/yBACbDwvQATQEAYAMRB0BEAAP8PAABIIAtAEAAgAEAAgAAGSAFoBSICYAciCkAESQloAmCIBIAPQBxwR8BGABNAQBgAxEEQtQRG//eu/gAoENAJSCAYESEJAmEYACICYEIgSGAGSAhiASAIYCBG//fa/hC9ACAQvcBGEBIAAAAAwEEBSQAiQlBwRxASAAAQtQRG//fs/gMoDNEGSCAYBklhGAAiCmBCIQFgBEnBYSBG//cr/RC9BBEAABASAAAAAMBBELUERv/3FP8AKBDQCUggGBEhCQJhGAAiAmBCIEhgBkgIYgEgCGAgRv/3nP4QvQAgEL3ARhASAAAAAMBBsLURIxsCxBgBJWVgZWIhYhF4IWPFULC9ELUFSwEkxFDDGBxi2WEReNli//fv/BC9BBEAAHC1ESMbAsQYASVlYAMmZmIhYhGIIWPFUHC9wEYQtQZLASTEUMMYAyQcYtlhEYjZYv/30vwQvcBGBBEAAHC1ESMbAsQYASVlYA8mZmIhYhFoIWPFUHC9wEYQtQZLASTEUMMYDyQcYtlhEWjZYv/3tPwQvcBGBBEAAHC1ESMbAsQYASVlYP8mZmIhYhFoIWNRaGFjxVBwvcBGELUHSwEkxFDDGP8kHGLZYRFo2WJRaBlj//eS/BC9wEYEEQAAcLURIxsCxBgBJWVg/yYCNmZiIWIReCFjxVBwvRC1BksBJMRQwxj/JAI0HGLZYRF42WL/93P8EL0EEQAAcLURIxsCxBgBJWVg/yYENmZiIWIRiCFjxVBwvRC1BksBJMRQwxj/JAQ0HGLZYRGI2WL/91X8EL0EEQAAcLURIxsCxBgBJWVg/yYQNmZiIWIRaCFjxVBwvRC1BksBJMRQwxj/JBA0HGLZYRFo2WL/9zf8EL0EEQAAcLURIxsCxBgBJWVgBE5mYiFiEWghY1FoYWPFUHC9wEb/AQAAELUHSwEkxFDDGAZMHGLZYRFo2WJRaBlj//cU/BC9wEYEEQAA/wEAAPC1ESQkAgUZASZuYP8nAjdvYiliEXgpYxl4AkqBUAZR8L3ARrARAACwtQhMASUFUQQZ/yUCNSVi4WEReOFiGXgDSoFQ//fq+7C9wEYEEQAAsBEAAPC1ESQkAgUZASZuYP8nBDdvYiliEYgpYxl4AkqBUAZR8L3ARrARAACwtQhMASUFUQQZ/yUENSVi4WERiOFiGXgDSoFQ//fA+7C9wEYEEQAAsBEAAPC1ESQkAgUZASZuYP8nEDdvYiliEWgpYxl4AkqBUAZR8L3ARrARAACwtQhMASUFUQQZ/yUQNSVi4WERaOFiGXgDSoFQ//eW+7C9wEYEEQAAsBEAAPC1ESQkAgUZASZuYAVPb2IpYhFoKWNRaGljGXgCSoFQBlHwvf8BAACwEQAAsLUITAElBVEEGQdNJWLhYRFo4WJRaCFjGXgESoFQ//dp+7C9BBEAAP8BAACwEQAA8LWFsBxGA5ICkQNGASEgRgGRCEBBQkFBYh4gRpBBCEARIQkCBJNfGAqZAJEALBvQwQcZ0ASYAp0pRgCaAPAa+AGZeWAKSHhiPWIDnjBoOGNwaHhjOWAINQKVpB4EmP/3v/wINgOW4ecBmQhABbDwvf8BAAD4tRVGDkYHRghGAPBz+QRG//eq/R5JCmgFIwtgByMTQBxKEmgLYBxJfxixCgEmswKdQg7QcwKdQinRGEsbaNsEDNUCKArTEAVADYFCBdkJGgTgHyABQEA3FeBBGB8pEtn/LAfY//eA/T8dASgA0SA84QgI4DAC/zCEQgjS/yDAQyAYwQgIN45AOGiwQzhg+L0AE0BAGADEQdARAABIIAtA+LUcRhVGDkYHRgEh2AcB0AhGAOAEIAAsANEIRgaZAJEALBDQwbIBKQ3QOEYxRgCa//eW/zhGMUYqRv/3l/4INgg1pB7s58Cy+L3ARvC1h7AGkwSSA5EDRgEhDJ84RgKRCEBBQkFBeh44RpBBCEAYSVkYAZERIQkCBZNcGA2ZAJEALyHQwQcf0AWYA50pRgCa//dm/wKaYmAOSGBiJWIEnjBoIGNwaGBjBpkIeAGbGGAiYAg1A5VJHAaRvx4FmP/3BfwINgSW2+cCmQhAB7DwvbARAAD/AQAA/rUCkxVGDkYBkAifASH4BwHQCEYA4AQgAC8A0QhGCZkAkQAvFdDBsgEpEtABnCBGMUYAmv/3KP8gRjFGKkYCnCNG//fP/gg2ZBwClAg1vx7n58Cy/r3+tR9GFEYNRgJGWR4YRohBESEJAgKSVhgImQGRAC8l0MEHI9ACmClGAZr/9wL/ASBwYAEvC9D/IXFiNWIhaDFjYWhxYzBgvx4IIQIgB+APIXFiNWIhaDFjMGAAJwQhbRiAACQYApj/95r71+cBIQhA/r34tR9GFEYNRgZGACsB0AQgAOABIAaZAJEALxvQwbIBKRjQMEYpRgCa//fK/jBGKUYiRgEvBdD/90v9vx4IIQIiBOD/9yX9ACcEIQEibRiRAGQY4efAsvi9A0kAIkJQQBhCYIJgcEfARtARAAAAIclDAkqBUIAYQWCBYHBH0BEAAARJACJCUEAYQmCCYAJkQmSCZHBH0BEAAAAhyUMESoFQgBhBYIFgAWRBZIFkcEfARtARAAAQtQRG//c2/AFGC0oQaAUjE2AHIwNACUgAaBNgpAoCKQjTB0oQQADwUfoBRiBGAPBN+gxGIEYQvQATQEAYAMRB/w8AAPi1FkYNRgdGCEb/99f/AJD/9w78JUkKaAUjC2AHIxNAI0oSaAtgI0l/GKkKASSjAp5CDtBjAp5CEdEfSxto2wQP1QIoDdMQBUANgUII2QkaB+AfIAFAjEA4bCBDOGT4vUEYHykE2IxAOGggQzhg+L2oDAfR//fc+3loASgP0QCYAB8O4A1IhULp2P8gwEMAmQgYwAiEQLhoIEO4YPi9AJjACIRAIUN5YPi9wEYAE0BAGADEQdARAABIIAtA//sHALC1ESMbAsQYAyVlYCFiASFhYhJ4ImPBULC9sLURIxsCxBgDJWVgIWJlYhGIIWMBIcFQsL2wtREjGwLEGAMlZWAhYg8hYWIRaCFjASHBULC9sLURIxsCxBgDJWVgIWL/IWFiEWghY1FoYWMBIcFQsL0QtQZLAyTEUMMYASQcYtlhEXjZYv/36PgQvcBGBBEAABC1BUsDJMRQwxgcYtlhEYjZYv/32fgQvQQRAAAQtQZLAyTEUMMYDyQcYtlhEWjZYv/3yvgQvcBGBBEAABC1B0sDJMRQwxj/JBxi2WERaNliUWgZY//3uPgQvcBGBBEAABC1BksDJMRQwxj/JAI0HGLZYRF42WL/96f4EL0EEQAAELUGSwMkxFDDGP8kBDQcYtlhEYjZYv/3l/gQvQQRAAAQtQZLAyTEUMMY/yQQNBxi2WERaNli//eH+BC9BBEAABC1B0sDJMRQwxgGTBxi2WERaNliUWgZY//3dvgQvcBGBBEAAP8BAACwtQhMAyUFUQQZ/yUCNSVi4WEReOFiGXgDSoFQ//dg+LC9wEYEEQAAsBEAALC1CEwDJQVRBBn/JQQ1JWLhYRGI4WIZeANKgVD/90r4sL3ARgQRAACwEQAAsLUITAMlBVEEGf8lEDUlYuFhEWjhYhl4A0qBUP/3NPiwvcBGBBEAALARAACwtQhMAyUFUQQZB00lYuFhEWjhYlFoIWMZeARKgVD/9x34sL0EEQAA/wEAALARAACwtREjGwLEGAMlZWAhYv8hAjFhYhF4IWMBIcFQsL2wtREjGwLEGAMlZWAhYv8hBDFhYhGIIWMBIcFQsL2wtREjGwLEGAMlZWAhYv8hEDFhYhFoIWMBIcFQsL3ARrC1ESMbAsQYAyVlYCFiBElhYhFoIWNRaGFjASHBULC9/wEAAHC1ESQkAgUZAyZuYCli/yECMWliEXgpYxl4AkqBUAEhAVFwvbARAABwtREkJAIFGQMmbmApYv8hBDFpYhGIKWMZeAJKgVABIQFRcL2wEQAAcLURJCQCBRkDJm5gKWL/IRAxaWIRaCljGXgCSoFQASEBUXC9sBEAAHC1ESQkAgUZAyZuYCliBklpYhFoKWNRaGljGXgDSoFQASEBUXC9wEb/AQAAsBEAABC1ESISAoMYBiRcYBliASGBUBC9gLUESgYjg1CCGNFh/vdw/4C9wEYEEQAAASCBAgZKE2iLQxNgAAVRaIFDUWADSAFoiQP81HBHwEYAAQtABAILQAEgAAQESQpogkMKYANIAWjJBvzUcEfARgQBC0AEAgtAACIDCYtCLNMDCotCEdMAI5xGTuADRgtDPNQAIkMIi0Ix0wMJi0Ic0wMKi0IB05RGP+DDCYtCAdPLAcAaUkGDCYtCAdOLAcAaUkFDCYtCAdNLAcAaUkEDCYtCAdMLAcAaUkHDCItCAdPLAMAaUkGDCItCAdOLAMAaUkFDCItCAdNLAMAaUkFBGgDSAUZSQRBGcEdd4MoPANBJQgMQANNAQlNAnEYAIgMJi0It0wMKi0IS04kB/CISugMKi0IM04kBkhGLQgjTiQGSEYtCBNOJATrQkhEA4IkJwwmLQgHTywHAGlJBgwmLQgHTiwHAGlJBQwmLQgHTSwHAGlJBAwmLQgHTCwHAGlJBwwiLQgHTywDAGlJBgwiLQgHTiwDAGlJB2dJDCItCAdNLAMAaUkFBGgDSAUZSQRBGY0ZbEAHTQEIAKwDVSUJwR2NGWxAA00BCAbUFSQAoAtxJHAhAAOAIRsBGwEYCvQC/////fwAAAAA= + load_address: 0x20200008 + pc_init: 0x1d + pc_uninit: 0x5d + pc_program_page: 0x145 + pc_erase_sector: 0x61 + pc_erase_all: 0x131 + data_section_offset: 0x12dc + flash_properties: + address_range: + start: 0x0 + end: 0x40000 + page_size: 0x400 + erased_byte_value: 0xff + program_page_timeout: 500 + erase_sector_timeout: 3000 + sectors: + - size: 0x400 + address: 0x0 +- name: mspm0l122x_l222x_nonmain + description: MSPM0L122X_222X NON-MAIN + instructions: ESEJAgEiQlADSUEYCmgHIBBABCj60HBH0BMAABC1EEgBaAcikUMBYA5ID0kBYA9MIGgDIYhDIGAB8KL4YGgPIYhDYGAB8Jz4CUgBaAQikUMBYAhJAiAIYAAgwkNKYBC9ABNAQAAIREABAAAmAAELQBDtAOAAEURAACBwR/61ASGIQwIoPdEAkQAgApDAQwGQH00uIx1MIEYBnzlGKkYA8MH4BkYWIyBGOUYaSgDwuvgERjBGIEMf0ChGAPAx+LghFUp6RC9GKEYA8GD4WCETSnpEEEgA8Fr4AC4D0AKZAykG2RDgASAALAfQApkEKQTSSRwCkT1GzOcCmAAoAJgA0P69ACD+vQCY/r3ARgAAREAAAMBBAAHAQW4SAABAFQAA+LUERkAKFUmIQiPRASAAkIICE0ghRgDwZ/wFJgAlEk8oRnYeKUZpQcAHFNEAKRLQQCILSCFGAPC3+ADwV/gAKO/QBSEHSlFgAJkRYDloSQf81ObnASUoRvi9wEYA4CAAANAMQADhDEDQ4wxA+LUGRkAKASQZS5hCLdEAKSvQByAIQCjRFUYAkQEgF08AJACZACkg0MAHHtABJKICEEgxRgDwIvw4aEAH/NQNSDFGKkYA8A77CDYINQCYCDgAkADwFfgAKOLQBSEGSlFgFGA5aEkH/NTa5yBG+L3ARgDgIAAA0AxAAOEMQNDjDEAESAFoyQf80ABoAiEBQEgIcEfARtDjDEAQtQVMAVEAGQArA9ACykFgWx7554BoEL0EEQAAELUFTAFRABmaQgLYAspBYPrngGgQvcBGBBEAALy1CkwEGQCUAJwhgAhJQRgAKwbQFIgBkQGdLICSHFse9ucESUBYgLK8vcBGBBEAAAgRAAAMEQAAvLUJTAQZAJQAnCGAB0lBGJpCBdgUiAGRAZ0sgJIc9+cDSUBYgLK8vQQRAAAIEQAADBEAABC1AiMTQxEiEgKEGGNgIWIBIYFQEL3ARoC1AiMTQwNKg1CCGNFh//eH/oC9BBEAABC1BEYRSAAhIVAgGEFggWDKQwJkESAAAiIYUiNTYBFiASEhUCBGAPAp+AlJCmgFIwtgByMTQAdKEmgLYJEOBNAAKALQIEYA8CX4EL3QEQAAABNAQBgAxEEDSQAiQlBAGEJggmBwR8BG0BEAAAAhyUMBSoFQcEfARhASAAAESUAYAWjJB/zQAGgCIQFASAhwR9ATAACAtQlJACJCUEEYSmCKYBEhCQJCGFIjU2AESxNiASJCUP/34v+AvcBG0BEAAAAA0EEQtQRGEEgAISFQIBhBYIFgykMCZA1IUiIiUCAYwWEgRv/3EP4KSQpoBSMLYAcjE0AIShJoC2CRDgTQASgC0CBGAPAK+BC9wEbQEQAABBEAAAATQEAYAMRBgLUHSQAiQlBBGEpgimAFSVIiQlBBGARKymH/9+f9gL3QEQAABBEAAAAA0EHwtYmwBEYA8JP4BUZBShBoBSEBkRFgByEAkQhAPkkJaBBgPkggGASQESAAAgaUJxg7SAhAKUYA8Kf+KkaAAgOQaAgIkBAgB5AAJAEmJUYwRgWWApKVQkTSwQdC0AiYhUIB0gAhAOABIS5IAGhABTBGANUIRikGiQ4D0eEVKqNZWgeRACgwRifQASABBLpoCkO6YB8hCQEHmgpAJka7aItDmRi5YA8hSQK6aIpDQQJRGLlgACEEmhFgUWCRYMlDEWRSIXlgKUYDmlFDOWI4YAaY//cw/wKaBZ4BIQkGZBhtHLjnASQhBLpoikO6YAlLGWgBmhpgAJoRQAdKEmgZYJEOANDGQ/EHAtEGmP/3H/8gQAmw8L0AE0BAGADEQdARAAD/DwAASCALQBAAIABAAIAABkgBaAUiAmAHIgpABEkJaAJgiASAD0AccEfARgATQEAYAMRBELUERv/3rv4AKBDQCUggGBEhCQJhGAAiAmBCIEhgBkgIYgEgCGAgRv/32v4QvQAgEL3ARhASAAAAAMBBAUkAIkJQcEcQEgAAELUERv/37P4DKAzRBkggGAZJYRgAIgpgQiEBYARJwWEgRv/3//wQvQQRAAAQEgAAAADAQRC1BEb/9xT/ACgQ0AlIIBgRIQkCYRgAIgJgQiBIYAZICGIBIAhgIEb/95z+EL0AIBC9wEYQEgAAAADAQbC1ESMbAsQYASVlYGViIWIReCFjxVCwvRC1BUsBJMRQwxgcYtlhEXjZYv/3w/wQvQQRAABwtREjGwLEGAElZWADJmZiIWIRiCFjxVBwvcBGELUGSwEkxFDDGAMkHGLZYRGI2WL/96b8EL3ARgQRAABwtREjGwLEGAElZWAPJmZiIWIRaCFjxVBwvcBGELUGSwEkxFDDGA8kHGLZYRFo2WL/94j8EL3ARgQRAABwtREjGwLEGAElZWD/JmZiIWIRaCFjUWhhY8VQcL3ARhC1B0sBJMRQwxj/JBxi2WERaNliUWgZY//3ZvwQvcBGBBEAAHC1ESMbAsQYASVlYP8mAjZmYiFiEXghY8VQcL0QtQZLASTEUMMY/yQCNBxi2WEReNli//dH/BC9BBEAAHC1ESMbAsQYASVlYP8mBDZmYiFiEYghY8VQcL0QtQZLASTEUMMY/yQENBxi2WERiNli//cp/BC9BBEAAHC1ESMbAsQYASVlYP8mEDZmYiFiEWghY8VQcL0QtQZLASTEUMMY/yQQNBxi2WERaNli//cL/BC9BBEAAHC1ESMbAsQYASVlYAROZmIhYhFoIWNRaGFjxVBwvcBG/wEAABC1B0sBJMRQwxgGTBxi2WERaNliUWgZY//36PsQvcBGBBEAAP8BAADwtREkJAIFGQEmbmD/JwI3b2IpYhF4KWMZeAJKgVAGUfC9wEawEQAAsLUITAElBVEEGf8lAjUlYuFhEXjhYhl4A0qBUP/3vvuwvcBGBBEAALARAADwtREkJAIFGQEmbmD/JwQ3b2IpYhGIKWMZeAJKgVAGUfC9wEawEQAAsLUITAElBVEEGf8lBDUlYuFhEYjhYhl4A0qBUP/3lPuwvcBGBBEAALARAADwtREkJAIFGQEmbmD/JxA3b2IpYhFoKWMZeAJKgVAGUfC9wEawEQAAsLUITAElBVEEGf8lEDUlYuFhEWjhYhl4A0qBUP/3avuwvcBGBBEAALARAADwtREkJAIFGQEmbmAFT29iKWIRaCljUWhpYxl4AkqBUAZR8L3/AQAAsBEAALC1CEwBJQVRBBkHTSVi4WERaOFiUWghYxl4BEqBUP/3PfuwvQQRAAD/AQAAsBEAAPC1hbAcRgOSApEDRgEhIEYBkQhAQUJBQWIeIEaQQQhAESEJAgSTXxgKmQCRACwb0MEHGdAEmAKdKUYAmgDwGvgBmXlgCkh4Yj1iA54waDhjcGh4YzlgCDUClaQeBJj/97/8CDYDluHnAZkIQAWw8L3/AQAA+LUVRg5GB0YIRgDwc/kERv/3qv0eSQpoBSMLYAcjE0AcShJoC2AcSX8YsQoBJrMCnUIO0HMCnUIp0RhLG2jbBAzVAigK0xAFQA2BQgXZCRoE4B8gAUBANxXgQRgfKRLZ/ywH2P/3gP0/HQEoANEgPOEICOAwAv8whEII0v8gwEMgGMEICDeOQDhosEM4YPi9ABNAQBgAxEHQEQAASCALQPi1HEYVRg5GB0YBIdgHAdAIRgDgBCAALADRCEYGmQCRACwQ0MGyASkN0DhGMUYAmv/3lv84RjFGKkb/95f+CDYINaQe7OfAsvi9wEbwtYewBpMEkgORA0YBIQyfOEYCkQhAQUJBQXoeOEaQQQhAGElZGAGRESEJAgWTXBgNmQCRAC8h0MEHH9AFmAOdKUYAmv/3Zv8CmmJgDkhgYiViBJ4waCBjcGhgYwaZCHgBmxhgImAINQOVSRwGkb8eBZj/9wX8CDYEltvnApkIQAew8L2wEQAA/wEAAP61ApMVRg5GAZAInwEh+AcB0AhGAOAEIAAvANEIRgmZAJEALxXQwbIBKRLQAZwgRjFGAJr/9yj/IEYxRipGApwjRv/3z/4INmQcApQINb8e5+fAsv69/rUfRhRGDUYCRlkeGEaIQREhCQICklYYCJkBkQAvJdDBByPQApgpRgGa//cC/wEgcGABLwvQ/yFxYjViIWgxY2FocWMwYL8eCCECIAfgDyFxYjViIWgxYzBgACcEIW0YgAAkGAKY//ea+9fnASEIQP69+LUfRhRGDUYGRgArAdAEIADgASAGmQCRAC8b0MGyASkY0DBGKUYAmv/3yv4wRilGIkYBLwXQ//dL/b8eCCECIgTg//cl/QAnBCEBIm0YkQBkGOHnwLL4vQNJACJCUEAYQmCCYHBHwEbQEQAAACHJQwJKgVCAGEFggWBwR9ARAAAESQAiQlBAGEJggmACZEJkgmRwR9ARAAAAIclDBEqBUIAYQWCBYAFkQWSBZHBHwEbQEQAAELUERv/3NvwBRgtKEGgFIxNgByMDQAlIAGgTYKQKAikI0wdKEEAA8FH6AUYgRgDwTfoMRiBGEL0AE0BAGADEQf8PAAD4tRZGDUYHRghG//fX/wCQ//cO/CVJCmgFIwtgByMTQCNKEmgLYCNJfxipCgEkowKeQg7QYwKeQhHRH0sbaNsED9UCKA3TEAVADYFCCNkJGgfgHyABQIxAOGwgQzhk+L1BGB8pBNiMQDhoIEM4YPi9qAwH0f/33Pt5aAEoD9EAmAAfDuANSIVC6dj/IMBDAJkIGMAIhEC4aCBDuGD4vQCYwAiEQCFDeWD4vcBGABNAQBgAxEHQEQAASCALQP/7BwCwtREjGwLEGAMlZWAhYgEhYWISeCJjwVCwvbC1ESMbAsQYAyVlYCFiZWIRiCFjASHBULC9sLURIxsCxBgDJWVgIWIPIWFiEWghYwEhwVCwvbC1ESMbAsQYAyVlYCFi/yFhYhFoIWNRaGFjASHBULC9ELUGSwMkxFDDGAEkHGLZYRF42WL/97z4EL3ARgQRAAAQtQVLAyTEUMMYHGLZYRGI2WL/9634EL0EEQAAELUGSwMkxFDDGA8kHGLZYRFo2WL/9574EL3ARgQRAAAQtQdLAyTEUMMY/yQcYtlhEWjZYlFoGWP/94z4EL3ARgQRAAAQtQZLAyTEUMMY/yQCNBxi2WEReNli//d7+BC9BBEAABC1BksDJMRQwxj/JAQ0HGLZYRGI2WL/92v4EL0EEQAAELUGSwMkxFDDGP8kEDQcYtlhEWjZYv/3W/gQvQQRAAAQtQdLAyTEUMMYBkwcYtlhEWjZYlFoGWP/90r4EL3ARgQRAAD/AQAAsLUITAMlBVEEGf8lAjUlYuFhEXjhYhl4A0qBUP/3NPiwvcBGBBEAALARAACwtQhMAyUFUQQZ/yUENSVi4WERiOFiGXgDSoFQ//ce+LC9wEYEEQAAsBEAALC1CEwDJQVRBBn/JRA1JWLhYRFo4WIZeANKgVD/9wj4sL3ARgQRAACwEQAAsLUITAMlBVEEGQdNJWLhYRFo4WJRaCFjGXgESoFQ/vfx/7C9BBEAAP8BAACwEQAAsLURIxsCxBgDJWVgIWL/IQIxYWIReCFjASHBULC9sLURIxsCxBgDJWVgIWL/IQQxYWIRiCFjASHBULC9sLURIxsCxBgDJWVgIWL/IRAxYWIRaCFjASHBULC9wEawtREjGwLEGAMlZWAhYgRJYWIRaCFjUWhhYwEhwVCwvf8BAABwtREkJAIFGQMmbmApYv8hAjFpYhF4KWMZeAJKgVABIQFRcL2wEQAAcLURJCQCBRkDJm5gKWL/IQQxaWIRiCljGXgCSoFQASEBUXC9sBEAAHC1ESQkAgUZAyZuYCli/yEQMWliEWgpYxl4AkqBUAEhAVFwvbARAABwtREkJAIFGQMmbmApYgZJaWIRaCljUWhpYxl4A0qBUAEhAVFwvcBG/wEAALARAAAQtREiEgKDGAYkXGAZYgEhgVAQvYC1BEoGI4NQghjRYf73RP+AvcBGBBEAAAEggQIGShNoi0MTYAAFUWiBQ1FgA0gBaIkD/NRwR8BGAAELQAQCC0ABIAAEBEkKaIJDCmADSAFoyQb81HBHwEYEAQtABAILQAAiAwmLQizTAwqLQhHTACOcRk7gA0YLQzzUACJDCItCMdMDCYtCHNMDCotCAdOURj/gwwmLQgHTywHAGlJBgwmLQgHTiwHAGlJBQwmLQgHTSwHAGlJBAwmLQgHTCwHAGlJBwwiLQgHTywDAGlJBgwiLQgHTiwDAGlJBQwiLQgHTSwDAGlJBQRoA0gFGUkEQRnBHXeDKDwDQSUIDEADTQEJTQJxGACIDCYtCLdMDCotCEtOJAfwiEroDCotCDNOJAZIRi0II04kBkhGLQgTTiQE60JIRAOCJCcMJi0IB08sBwBpSQYMJi0IB04sBwBpSQUMJi0IB00sBwBpSQQMJi0IB0wsBwBpSQcMIi0IB08sAwBpSQYMIi0IB04sAwBpSQdnSQwiLQgHTSwDAGlJBQRoA0gFGUkEQRmNGWxAB00BCACsA1UlCcEdjRlsQANNAQgG1BUkAKALcSRwIQADgCEbARsBGAr0Av////38CAAABu6q7qruqu6r//////////7uqu6q7qruq//+7qruqu6r///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////+yIGk/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAABoCGQIBAwIDshL//6+WE3YPcmNfvbRKWgpjw58SrzD5UKbuXJcb4YjonEBR/////////////////////////////////////////////0gA0UsBbwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= + load_address: 0x20200008 + pc_init: 0x1d + pc_uninit: 0x7d + pc_program_page: 0x18d + pc_erase_sector: 0x121 + pc_erase_all: 0x79 + data_section_offset: 0x1774 + flash_properties: + address_range: + start: 0x41c00000 + end: 0x41c00200 + page_size: 0x40 + erased_byte_value: 0xff + program_page_timeout: 500 + erase_sector_timeout: 3000 + sectors: + - size: 0x200 + address: 0x0 diff --git a/examples/mspm0l2228/README.md b/examples/mspm0l2228/README.md new file mode 100644 index 000000000..c73fa13b6 --- /dev/null +++ b/examples/mspm0l2228/README.md @@ -0,0 +1,27 @@ +# Examples for MSPM0L222x family + +Run individual examples with +``` +cargo run --bin +``` +for example +``` +cargo run --bin blinky +``` + +## Checklist before running examples +A large number of the examples are written for the [LP-MSPM0L2228](https://www.ti.com/tool/LP-MSPM0L2228) board. + +You might need to adjust `.cargo/config.toml`, `Cargo.toml` and possibly update pin numbers or peripherals to match the specific MCU or board you are using. + +* [ ] Update .cargo/config.toml with the correct probe-rs command to use your specific MCU. For example for L2228 it should be `probe-rs run --chip MSPM0L2228`. (use `probe-rs chip list` to find your chip) +* [ ] Update Cargo.toml to have the correct `embassy-mspm0` feature. For example for L2228 it should be `mspm0l2228`. Look in the `Cargo.toml` file of the `embassy-mspm0` project to find the correct feature flag for your chip. +* [ ] If your board has a special clock or power configuration, make sure that it is set up appropriately. +* [ ] If your board has different pin mapping, update any pin numbers or peripherals in the given example code to match your schematic + +If you are unsure, please drop by the Embassy Matrix chat for support, and let us know: + +* Which example you are trying to run +* Which chip and board you are using + +Embassy Chat: https://matrix.to/#/#embassy-rs:matrix.org diff --git a/examples/mspm0l2228/build.rs b/examples/mspm0l2228/build.rs new file mode 100644 index 000000000..30691aa97 --- /dev/null +++ b/examples/mspm0l2228/build.rs @@ -0,0 +1,35 @@ +//! This build script copies the `memory.x` file from the crate root into +//! a directory where the linker can always find it at build time. +//! For many projects this is optional, as the linker always searches the +//! project root directory -- wherever `Cargo.toml` is. However, if you +//! are using a workspace or have a more complicated build setup, this +//! build script becomes required. Additionally, by requesting that +//! Cargo re-run the build script whenever `memory.x` is changed, +//! updating `memory.x` ensures a rebuild of the application with the +//! new memory settings. + +use std::env; +use std::fs::File; +use std::io::Write; +use std::path::PathBuf; + +fn main() { + // Put `memory.x` in our output directory and ensure it's + // on the linker search path. + let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); + File::create(out.join("memory.x")) + .unwrap() + .write_all(include_bytes!("memory.x")) + .unwrap(); + println!("cargo:rustc-link-search={}", out.display()); + + // By default, Cargo will re-run a build script whenever + // any file in the project changes. By specifying `memory.x` + // here, we ensure the build script is only re-run when + // `memory.x` is changed. + println!("cargo:rerun-if-changed=memory.x"); + + println!("cargo:rustc-link-arg-bins=--nmagic"); + println!("cargo:rustc-link-arg-bins=-Tlink.x"); + println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); +} diff --git a/examples/mspm0l2228/memory.x b/examples/mspm0l2228/memory.x new file mode 100644 index 000000000..aba414a88 --- /dev/null +++ b/examples/mspm0l2228/memory.x @@ -0,0 +1,6 @@ +MEMORY +{ + FLASH : ORIGIN = 0x00000000, LENGTH = 256K + /* Select non-parity range of SRAM due to SRAM_ERR_01 errata in SLAZ758 */ + RAM : ORIGIN = 0x20200000, LENGTH = 32K +} diff --git a/examples/mspm0l2228/src/bin/blinky.rs b/examples/mspm0l2228/src/bin/blinky.rs new file mode 100644 index 000000000..11eee2d80 --- /dev/null +++ b/examples/mspm0l2228/src/bin/blinky.rs @@ -0,0 +1,27 @@ +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_mspm0::{ + gpio::{Level, Output}, + Config, +}; +use embassy_time::Timer; +use {defmt_rtt as _, panic_halt as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) -> ! { + info!("Hello world!"); + let p = embassy_mspm0::init(Config::default()); + + let mut led1 = Output::new(p.PA0, Level::Low); + led1.set_inversion(true); + + loop { + Timer::after_millis(400).await; + + info!("Toggle"); + led1.toggle(); + } +} diff --git a/examples/mspm0l2228/src/bin/button.rs b/examples/mspm0l2228/src/bin/button.rs new file mode 100644 index 000000000..f26929dde --- /dev/null +++ b/examples/mspm0l2228/src/bin/button.rs @@ -0,0 +1,35 @@ +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_mspm0::{ + gpio::{Input, Level, Output, Pull}, + Config, +}; +use {defmt_rtt as _, panic_halt as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) -> ! { + info!("Hello world!"); + + let p = embassy_mspm0::init(Config::default()); + + let led1 = p.PA0; + let s2 = p.PB8; + + let mut led1 = Output::new(led1, Level::Low); + + let mut s2 = Input::new(s2, Pull::Up); + + // led1 is active low + led1.set_high(); + + loop { + s2.wait_for_falling_edge().await; + + info!("Switch 2 was pressed"); + + led1.toggle(); + } +} From 9531b7422b0bf231d5782bb60b65eeb823b199ff Mon Sep 17 00:00:00 2001 From: i509VCB Date: Thu, 13 Mar 2025 22:26:06 -0500 Subject: [PATCH 0817/1217] rustfmt... --- embassy-mspm0/build.rs | 9 ++------- embassy-mspm0/src/gpio.rs | 22 ++++++---------------- embassy-mspm0/src/lib.rs | 9 ++------- embassy-mspm0/src/time_driver.rs | 30 ++++++++---------------------- 4 files changed, 18 insertions(+), 52 deletions(-) diff --git a/embassy-mspm0/build.rs b/embassy-mspm0/build.rs index ffbe15c56..8c6dd4a5c 100644 --- a/embassy-mspm0/build.rs +++ b/embassy-mspm0/build.rs @@ -107,11 +107,7 @@ fn generate_code() { } // Generate timers - for peripheral in METADATA - .peripherals - .iter() - .filter(|p| p.name.starts_with("TIM")) - { + for peripheral in METADATA.peripherals.iter().filter(|p| p.name.starts_with("TIM")) { let name = Ident::new(&peripheral.name, Span::call_site()); let timers = &*TIMERS; @@ -225,8 +221,7 @@ fn time_driver(singletons: &[String], cfgs: &mut CfgSet) { // TODO: 32-bit timers are not considered yet [ // 16-bit, 2 channel - "TIMG0", "TIMG1", "TIMG2", "TIMG3", - // 16-bit, 2 channel with shadow registers + "TIMG0", "TIMG1", "TIMG2", "TIMG3", // 16-bit, 2 channel with shadow registers "TIMG4", "TIMG5", "TIMG6", "TIMG7", // 16-bit, 4 channel "TIMG14", // 16-bit with QEI "TIMG8", "TIMG9", "TIMG10", "TIMG11", // Advanced timers diff --git a/embassy-mspm0/src/gpio.rs b/embassy-mspm0/src/gpio.rs index fd4dc55ab..e1eb7eecf 100644 --- a/embassy-mspm0/src/gpio.rs +++ b/embassy-mspm0/src/gpio.rs @@ -7,13 +7,12 @@ use core::task::{Context, Poll}; use embassy_hal_internal::{impl_peripheral, into_ref, Peripheral, PeripheralRef}; use embassy_sync::waitqueue::AtomicWaker; + +use crate::pac::gpio::vals::*; +use crate::pac::gpio::{self}; #[cfg(all(feature = "rt", feature = "mspm0c110x"))] use crate::pac::interrupt; - -use crate::pac::{ - self, - gpio::{self, vals::*}, -}; +use crate::pac::{self}; /// Represents a digital input or output level. #[derive(Debug, Eq, PartialEq, Clone, Copy)] @@ -88,9 +87,7 @@ impl<'d> Flex<'d> { into_ref!(pin); // Pin will be in disconnected state. - Self { - pin: pin.map_into(), - } + Self { pin: pin.map_into() } } /// Set the pin's pull. @@ -974,14 +971,7 @@ impl<'d> Future for InputFuture<'d> { waker.register(cx.waker()); // The interrupt handler will mask the interrupt if the event has occurred. - if self - .pin - .block() - .cpu_int() - .ris() - .read() - .dio(self.pin.bit_index()) - { + if self.pin.block().cpu_int().ris().read().dio(self.pin.bit_index()) { return Poll::Ready(()); } diff --git a/embassy-mspm0/src/lib.rs b/embassy-mspm0/src/lib.rs index ee629f063..1191b1010 100644 --- a/embassy-mspm0/src/lib.rs +++ b/embassy-mspm0/src/lib.rs @@ -1,10 +1,6 @@ #![no_std] // Doc feature labels can be tested locally by running RUSTDOCFLAGS="--cfg=docsrs" cargo +nightly doc -#![cfg_attr( - docsrs, - feature(doc_auto_cfg, doc_cfg_hide), - doc(cfg_hide(doc, docsrs)) -)] +#![cfg_attr(docsrs, feature(doc_auto_cfg, doc_cfg_hide), doc(cfg_hide(doc, docsrs)))] // This mod MUST go first, so that the others see its macros. pub(crate) mod fmt; @@ -40,6 +36,7 @@ pub(crate) mod _generated { } // Reexports +pub(crate) use _generated::gpio_pincm; pub use _generated::{peripherals, Peripherals}; pub use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; #[cfg(feature = "unstable-pac")] @@ -48,8 +45,6 @@ pub use mspm0_metapac as pac; pub(crate) use mspm0_metapac as pac; pub use crate::_generated::interrupt; -pub(crate) use _generated::gpio_pincm; - /// `embassy-mspm0` global configuration. #[non_exhaustive] diff --git a/embassy-mspm0/src/time_driver.rs b/embassy-mspm0/src/time_driver.rs index 3af7a5edb..937ce58d4 100644 --- a/embassy-mspm0/src/time_driver.rs +++ b/embassy-mspm0/src/time_driver.rs @@ -1,19 +1,13 @@ -use core::{ - cell::{Cell, RefCell}, - sync::atomic::{compiler_fence, AtomicU32, Ordering}, - task::Waker, -}; +use core::cell::{Cell, RefCell}; +use core::sync::atomic::{compiler_fence, AtomicU32, Ordering}; +use core::task::Waker; use critical_section::{CriticalSection, Mutex}; use embassy_time_driver::Driver; use embassy_time_queue_utils::Queue; -use mspm0_metapac::{ - interrupt, - tim::{ - vals::{Cm, Cvae, CxC, EvtCfg, PwrenKey, Ratio, Repeat, ResetKey}, - Counterregs16, Tim, - }, -}; +use mspm0_metapac::interrupt; +use mspm0_metapac::tim::vals::{Cm, Cvae, CxC, EvtCfg, PwrenKey, Ratio, Repeat, ResetKey}; +use mspm0_metapac::tim::{Counterregs16, Tim}; use crate::peripherals; use crate::timer::SealedTimer; @@ -244,18 +238,10 @@ impl TimxDriver { } fn trigger_alarm(&self, cs: CriticalSection) { - let mut next = self - .queue - .borrow(cs) - .borrow_mut() - .next_expiration(self.now()); + let mut next = self.queue.borrow(cs).borrow_mut().next_expiration(self.now()); while !self.set_alarm(cs, next) { - next = self - .queue - .borrow(cs) - .borrow_mut() - .next_expiration(self.now()); + next = self.queue.borrow(cs).borrow_mut().next_expiration(self.now()); } } From 0c8dadf0ca2dfa7fac3767d0c33276bd694c5824 Mon Sep 17 00:00:00 2001 From: i509VCB Date: Thu, 13 Mar 2025 22:30:45 -0500 Subject: [PATCH 0818/1217] rustfmt 2: electric boogaloo --- examples/mspm0c1104/src/bin/blinky.rs | 6 ++---- examples/mspm0c1104/src/bin/button.rs | 6 ++---- examples/mspm0g3507/src/bin/blinky.rs | 6 ++---- examples/mspm0g3507/src/bin/button.rs | 6 ++---- examples/mspm0g3519/src/bin/blinky.rs | 6 ++---- examples/mspm0g3519/src/bin/button.rs | 6 ++---- examples/mspm0l1306/src/bin/blinky.rs | 6 ++---- examples/mspm0l1306/src/bin/button.rs | 6 ++---- examples/mspm0l2228/src/bin/blinky.rs | 6 ++---- examples/mspm0l2228/src/bin/button.rs | 6 ++---- 10 files changed, 20 insertions(+), 40 deletions(-) diff --git a/examples/mspm0c1104/src/bin/blinky.rs b/examples/mspm0c1104/src/bin/blinky.rs index 264ea3eb5..0d974cc5e 100644 --- a/examples/mspm0c1104/src/bin/blinky.rs +++ b/examples/mspm0c1104/src/bin/blinky.rs @@ -3,10 +3,8 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_mspm0::{ - gpio::{Level, Output}, - Config, -}; +use embassy_mspm0::gpio::{Level, Output}; +use embassy_mspm0::Config; use embassy_time::Timer; use {defmt_rtt as _, panic_halt as _}; diff --git a/examples/mspm0c1104/src/bin/button.rs b/examples/mspm0c1104/src/bin/button.rs index 988170ef9..7face1618 100644 --- a/examples/mspm0c1104/src/bin/button.rs +++ b/examples/mspm0c1104/src/bin/button.rs @@ -3,10 +3,8 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_mspm0::{ - gpio::{Input, Level, Output, Pull}, - Config, -}; +use embassy_mspm0::gpio::{Input, Level, Output, Pull}; +use embassy_mspm0::Config; use {defmt_rtt as _, panic_halt as _}; #[embassy_executor::main] diff --git a/examples/mspm0g3507/src/bin/blinky.rs b/examples/mspm0g3507/src/bin/blinky.rs index 11eee2d80..055a5cd81 100644 --- a/examples/mspm0g3507/src/bin/blinky.rs +++ b/examples/mspm0g3507/src/bin/blinky.rs @@ -3,10 +3,8 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_mspm0::{ - gpio::{Level, Output}, - Config, -}; +use embassy_mspm0::gpio::{Level, Output}; +use embassy_mspm0::Config; use embassy_time::Timer; use {defmt_rtt as _, panic_halt as _}; diff --git a/examples/mspm0g3507/src/bin/button.rs b/examples/mspm0g3507/src/bin/button.rs index 1d9a37c5c..cde1f2892 100644 --- a/examples/mspm0g3507/src/bin/button.rs +++ b/examples/mspm0g3507/src/bin/button.rs @@ -3,10 +3,8 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_mspm0::{ - gpio::{Input, Level, Output, Pull}, - Config, -}; +use embassy_mspm0::gpio::{Input, Level, Output, Pull}; +use embassy_mspm0::Config; use {defmt_rtt as _, panic_halt as _}; #[embassy_executor::main] diff --git a/examples/mspm0g3519/src/bin/blinky.rs b/examples/mspm0g3519/src/bin/blinky.rs index 11eee2d80..055a5cd81 100644 --- a/examples/mspm0g3519/src/bin/blinky.rs +++ b/examples/mspm0g3519/src/bin/blinky.rs @@ -3,10 +3,8 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_mspm0::{ - gpio::{Level, Output}, - Config, -}; +use embassy_mspm0::gpio::{Level, Output}; +use embassy_mspm0::Config; use embassy_time::Timer; use {defmt_rtt as _, panic_halt as _}; diff --git a/examples/mspm0g3519/src/bin/button.rs b/examples/mspm0g3519/src/bin/button.rs index 2bdb2bcb1..c81cc2918 100644 --- a/examples/mspm0g3519/src/bin/button.rs +++ b/examples/mspm0g3519/src/bin/button.rs @@ -3,10 +3,8 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_mspm0::{ - gpio::{Input, Level, Output, Pull}, - Config, -}; +use embassy_mspm0::gpio::{Input, Level, Output, Pull}; +use embassy_mspm0::Config; use {defmt_rtt as _, panic_halt as _}; #[embassy_executor::main] diff --git a/examples/mspm0l1306/src/bin/blinky.rs b/examples/mspm0l1306/src/bin/blinky.rs index 11eee2d80..055a5cd81 100644 --- a/examples/mspm0l1306/src/bin/blinky.rs +++ b/examples/mspm0l1306/src/bin/blinky.rs @@ -3,10 +3,8 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_mspm0::{ - gpio::{Level, Output}, - Config, -}; +use embassy_mspm0::gpio::{Level, Output}; +use embassy_mspm0::Config; use embassy_time::Timer; use {defmt_rtt as _, panic_halt as _}; diff --git a/examples/mspm0l1306/src/bin/button.rs b/examples/mspm0l1306/src/bin/button.rs index 2813518c2..d8c85947f 100644 --- a/examples/mspm0l1306/src/bin/button.rs +++ b/examples/mspm0l1306/src/bin/button.rs @@ -3,10 +3,8 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_mspm0::{ - gpio::{Input, Level, Output, Pull}, - Config, -}; +use embassy_mspm0::gpio::{Input, Level, Output, Pull}; +use embassy_mspm0::Config; use {defmt_rtt as _, panic_halt as _}; #[embassy_executor::main] diff --git a/examples/mspm0l2228/src/bin/blinky.rs b/examples/mspm0l2228/src/bin/blinky.rs index 11eee2d80..055a5cd81 100644 --- a/examples/mspm0l2228/src/bin/blinky.rs +++ b/examples/mspm0l2228/src/bin/blinky.rs @@ -3,10 +3,8 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_mspm0::{ - gpio::{Level, Output}, - Config, -}; +use embassy_mspm0::gpio::{Level, Output}; +use embassy_mspm0::Config; use embassy_time::Timer; use {defmt_rtt as _, panic_halt as _}; diff --git a/examples/mspm0l2228/src/bin/button.rs b/examples/mspm0l2228/src/bin/button.rs index f26929dde..47bfd274b 100644 --- a/examples/mspm0l2228/src/bin/button.rs +++ b/examples/mspm0l2228/src/bin/button.rs @@ -3,10 +3,8 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_mspm0::{ - gpio::{Input, Level, Output, Pull}, - Config, -}; +use embassy_mspm0::gpio::{Input, Level, Output, Pull}; +use embassy_mspm0::Config; use {defmt_rtt as _, panic_halt as _}; #[embassy_executor::main] From edadc28f02f3f224680ca88f476d58bbbb106356 Mon Sep 17 00:00:00 2001 From: Martin Marmsoler Date: Fri, 14 Mar 2025 19:08:00 +0100 Subject: [PATCH 0819/1217] Add possibility to get the id of a task to be able to use it with rtos-trace Files: spawner.rs --- embassy-executor/src/spawner.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/embassy-executor/src/spawner.rs b/embassy-executor/src/spawner.rs index 7e76a09c6..fdd3ce002 100644 --- a/embassy-executor/src/spawner.rs +++ b/embassy-executor/src/spawner.rs @@ -34,6 +34,15 @@ impl SpawnToken { } } + /// Returns the task if available, otherwise 0 + /// This can be used in combination with rtos-trace to match task names with id's + pub fn id(&self) -> u32 { + match self.raw_task { + None => 0, + Some(t) => t.as_ptr() as u32, + } + } + /// Return a SpawnToken that represents a failed spawn. pub fn new_failed() -> Self { Self { From 0b6b0756ed5e6f259cf2fed8bf6de008eab78cb1 Mon Sep 17 00:00:00 2001 From: elagil Date: Sat, 15 Mar 2025 13:46:02 +0100 Subject: [PATCH 0820/1217] fix: USB ISO IN EP stat --- embassy-stm32/src/usb/usb.rs | 45 ++++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/embassy-stm32/src/usb/usb.rs b/embassy-stm32/src/usb/usb.rs index b9a16bbf1..31ab8f76d 100644 --- a/embassy-stm32/src/usb/usb.rs +++ b/embassy-stm32/src/usb/usb.rs @@ -80,10 +80,10 @@ impl interrupt::typelevel::Handler for InterruptHandl if istr.ctr() { let index = istr.ep_id() as usize; - CTR_TRIGGERED[index].store(true, Ordering::Relaxed); let mut epr = regs.epr(index).read(); if epr.ctr_rx() { + CTR_RX_TRIGGERED[index].store(true, Ordering::Relaxed); if index == 0 && epr.setup() { EP0_SETUP.store(true, Ordering::Relaxed); } @@ -91,6 +91,7 @@ impl interrupt::typelevel::Handler for InterruptHandl EP_OUT_WAKERS[index].wake(); } if epr.ctr_tx() { + CTR_TX_TRIGGERED[index].store(true, Ordering::Relaxed); //trace!("EP {} TX", index); EP_IN_WAKERS[index].wake(); } @@ -122,7 +123,8 @@ const USBRAM_ALIGN: usize = 4; static BUS_WAKER: AtomicWaker = AtomicWaker::new(); static EP0_SETUP: AtomicBool = AtomicBool::new(false); -static CTR_TRIGGERED: [AtomicBool; EP_COUNT] = [const { AtomicBool::new(false) }; EP_COUNT]; +static CTR_TX_TRIGGERED: [AtomicBool; EP_COUNT] = [const { AtomicBool::new(false) }; EP_COUNT]; +static CTR_RX_TRIGGERED: [AtomicBool; EP_COUNT] = [const { AtomicBool::new(false) }; EP_COUNT]; static EP_IN_WAKERS: [AtomicWaker; EP_COUNT] = [const { AtomicWaker::new() }; EP_COUNT]; static EP_OUT_WAKERS: [AtomicWaker; EP_COUNT] = [const { AtomicWaker::new() }; EP_COUNT]; static IRQ_RESET: AtomicBool = AtomicBool::new(false); @@ -209,10 +211,12 @@ mod btable { pub(super) fn write_in_rx(_index: usize, _addr: u16) {} pub(super) fn write_in_len_tx(index: usize, addr: u16, len: u16) { + assert_eq!(addr & 0b11, 0); USBRAM.mem(index * 2).write_value((addr as u32) | ((len as u32) << 16)); } pub(super) fn write_in_len_rx(index: usize, addr: u16, len: u16) { + assert_eq!(addr & 0b11, 0); USBRAM .mem(index * 2 + 1) .write_value((addr as u32) | ((len as u32) << 16)); @@ -640,22 +644,25 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> { fn endpoint_set_enabled(&mut self, ep_addr: EndpointAddress, enabled: bool) { trace!("set_enabled {:?} {}", ep_addr, enabled); // This can race, so do a retry loop. - let reg = T::regs().epr(ep_addr.index() as _); - trace!("EPR before: {:04x}", reg.read().0); + let epr = T::regs().epr(ep_addr.index() as _); + trace!("EPR before: {:04x}", epr.read().0); match ep_addr.direction() { Direction::In => { loop { let want_stat = match enabled { false => Stat::DISABLED, - true => Stat::NAK, + true => match epr.read().ep_type() { + EpType::ISO => Stat::VALID, + _ => Stat::NAK, + }, }; - let r = reg.read(); + let r = epr.read(); if r.stat_tx() == want_stat { break; } let mut w = invariant(r); w.set_stat_tx(Stat::from_bits(r.stat_tx().to_bits() ^ want_stat.to_bits())); - reg.write_value(w); + epr.write_value(w); } EP_IN_WAKERS[ep_addr.index()].wake(); } @@ -665,18 +672,18 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> { false => Stat::DISABLED, true => Stat::VALID, }; - let r = reg.read(); + let r = epr.read(); if r.stat_rx() == want_stat { break; } let mut w = invariant(r); w.set_stat_rx(Stat::from_bits(r.stat_rx().to_bits() ^ want_stat.to_bits())); - reg.write_value(w); + epr.write_value(w); } EP_OUT_WAKERS[ep_addr.index()].wake(); } } - trace!("EPR after: {:04x}", reg.read().0); + trace!("EPR after: {:04x}", epr.read().0); } async fn enable(&mut self) {} @@ -836,7 +843,8 @@ impl<'d, T: Instance> driver::EndpointOut for Endpoint<'d, T, Out> { if self.info.ep_type == EndpointType::Isochronous { // The isochronous endpoint does not change its `STAT_RX` field to `NAK` when receiving a packet. // Therefore, this instead waits until the `CTR` interrupt was triggered. - if matches!(stat, Stat::DISABLED) || CTR_TRIGGERED[index].load(Ordering::Relaxed) { + if matches!(stat, Stat::DISABLED) || CTR_RX_TRIGGERED[index].load(Ordering::Relaxed) { + assert!(matches!(stat, Stat::VALID | Stat::DISABLED)); Poll::Ready(stat) } else { Poll::Pending @@ -851,7 +859,7 @@ impl<'d, T: Instance> driver::EndpointOut for Endpoint<'d, T, Out> { }) .await; - CTR_TRIGGERED[index].store(false, Ordering::Relaxed); + CTR_RX_TRIGGERED[index].store(false, Ordering::Relaxed); if stat == Stat::DISABLED { return Err(EndpointError::Disabled); @@ -895,18 +903,17 @@ impl<'d, T: Instance> driver::EndpointIn for Endpoint<'d, T, In> { if buf.len() > self.info.max_packet_size as usize { return Err(EndpointError::BufferOverflow); } - + trace!("WRITE WAITING, buf.len() = {}", buf.len()); let index = self.info.addr.index(); - - trace!("WRITE WAITING"); let stat = poll_fn(|cx| { EP_IN_WAKERS[index].register(cx.waker()); let regs = T::regs(); let stat = regs.epr(index).read().stat_tx(); if self.info.ep_type == EndpointType::Isochronous { - // The isochronous endpoint does not change its `STAT_RX` field to `NAK` when receiving a packet. + // The isochronous endpoint does not change its `STAT_TX` field to `NAK` after sending a packet. // Therefore, this instead waits until the `CTR` interrupt was triggered. - if matches!(stat, Stat::DISABLED) || CTR_TRIGGERED[index].load(Ordering::Relaxed) { + if matches!(stat, Stat::DISABLED) || CTR_TX_TRIGGERED[index].load(Ordering::Relaxed) { + assert!(matches!(stat, Stat::VALID | Stat::DISABLED)); Poll::Ready(stat) } else { Poll::Pending @@ -921,7 +928,7 @@ impl<'d, T: Instance> driver::EndpointIn for Endpoint<'d, T, In> { }) .await; - CTR_TRIGGERED[index].store(false, Ordering::Relaxed); + CTR_TX_TRIGGERED[index].store(false, Ordering::Relaxed); if stat == Stat::DISABLED { return Err(EndpointError::Disabled); @@ -942,7 +949,6 @@ impl<'d, T: Instance> driver::EndpointIn for Endpoint<'d, T, In> { self.write_data_double_buffered(buf, packet_buffer); - let regs = T::regs(); regs.epr(index).write(|w| { w.set_ep_type(convert_type(self.info.ep_type)); w.set_ea(self.info.addr.index() as _); @@ -955,7 +961,6 @@ impl<'d, T: Instance> driver::EndpointIn for Endpoint<'d, T, In> { w.set_ctr_rx(true); // don't clear w.set_ctr_tx(true); // don't clear }); - trace!("WRITE OK"); Ok(()) From 0f57a18f199f67c805e199361636823d1178d586 Mon Sep 17 00:00:00 2001 From: i509VCB Date: Sat, 15 Mar 2025 13:35:24 -0500 Subject: [PATCH 0821/1217] Remove temporary target yamls These will be in the next probe-rs release --- examples/mspm0g3519/.cargo/config.toml | 3 +- examples/mspm0g3519/MSPM0GX51X_Series.yaml | 424 ------------------ examples/mspm0l2228/.cargo/config.toml | 3 +- .../mspm0l2228/MSPM0L122X_L222X_Series.yaml | 239 ---------- 4 files changed, 2 insertions(+), 667 deletions(-) delete mode 100644 examples/mspm0g3519/MSPM0GX51X_Series.yaml delete mode 100644 examples/mspm0l2228/MSPM0L122X_L222X_Series.yaml diff --git a/examples/mspm0g3519/.cargo/config.toml b/examples/mspm0g3519/.cargo/config.toml index 1a4768682..7bba4646f 100644 --- a/examples/mspm0g3519/.cargo/config.toml +++ b/examples/mspm0g3519/.cargo/config.toml @@ -1,7 +1,6 @@ [target.'cfg(all(target_arch = "arm", target_os = "none"))'] # replace MSPM0G3519 with your chip as listed in `probe-rs chip list` -# TODO: Remove description path after new chiptool release -runner = "probe-rs run --restore-unwritten --verify --chip MSPM0G3519 --protocol=swd --chip-description-path ./MSPM0GX51X_Series.yaml" +runner = "probe-rs run --restore-unwritten --verify --chip MSPM0G3519 --protocol=swd" [build] target = "thumbv6m-none-eabi" diff --git a/examples/mspm0g3519/MSPM0GX51X_Series.yaml b/examples/mspm0g3519/MSPM0GX51X_Series.yaml deleted file mode 100644 index 375623b94..000000000 --- a/examples/mspm0g3519/MSPM0GX51X_Series.yaml +++ /dev/null @@ -1,424 +0,0 @@ -name: MSPM0GX51X Series -manufacturer: - id: 0x17 - cc: 0x0 -generated_from_pack: true -pack_file_release: 1.0.0 -variants: -- name: MSPM0G1518 - cores: - - name: main - type: armv6m - core_access_options: !Arm - ap: 0 - memory_map: - - !Nvm - name: IROM1 - range: - start: 0x0 - end: 0x40000 - cores: - - main - access: - write: false - boot: true - - !Generic - name: IROM2 - range: - start: 0x400000 - end: 0x440000 - cores: - - main - access: - write: false - - !Generic - name: IRAM1 - range: - start: 0x20000000 - end: 0x20010000 - cores: - - main - - !Generic - name: IRAM_Parity - range: - start: 0x20100000 - end: 0x20110000 - cores: - - main - - !Ram - name: IRAM_No_Parity - range: - start: 0x20200000 - end: 0x20220000 - cores: - - main - - !Generic - name: IRAM_Parity_Code - range: - start: 0x20300000 - end: 0x20310000 - cores: - - main - - !Generic - name: NonMain_ECC - range: - start: 0x41c00000 - end: 0x41c00800 - cores: - - main - access: - write: false - execute: false - - !Generic - name: Factory_ECC - range: - start: 0x41c40000 - end: 0x41c40200 - cores: - - main - access: - write: false - execute: false - - !Generic - name: Data - range: - start: 0x41d00000 - end: 0x41d04000 - cores: - - main - access: - write: false - execute: false - flash_algorithms: - - mspm0gx51x_main_512kb - - mspm0gx51x_nonmain - - mspm0gx51x_data_16kb -- name: MSPM0G1519 - cores: - - name: main - type: armv6m - core_access_options: !Arm - ap: 0 - memory_map: - - !Nvm - name: IROM1 - range: - start: 0x0 - end: 0x80000 - cores: - - main - access: - write: false - boot: true - - !Generic - name: IROM2 - range: - start: 0x400000 - end: 0x480000 - cores: - - main - access: - write: false - - !Generic - name: IRAM1 - range: - start: 0x20000000 - end: 0x20010000 - cores: - - main - - !Generic - name: IRAM_Parity - range: - start: 0x20100000 - end: 0x20110000 - cores: - - main - - !Ram - name: IRAM_No_Parity - range: - start: 0x20200000 - end: 0x20220000 - cores: - - main - - !Generic - name: IRAM_Parity_Code - range: - start: 0x20300000 - end: 0x20310000 - cores: - - main - - !Generic - name: NonMain_ECC - range: - start: 0x41c00000 - end: 0x41c00800 - cores: - - main - access: - write: false - execute: false - - !Generic - name: Factory_ECC - range: - start: 0x41c40000 - end: 0x41c40200 - cores: - - main - access: - write: false - execute: false - - !Generic - name: Data - range: - start: 0x41d00000 - end: 0x41d04000 - cores: - - main - access: - write: false - execute: false - flash_algorithms: - - mspm0gx51x_main_512kb - - mspm0gx51x_nonmain - - mspm0gx51x_data_16kb -- name: MSPM0G3518 - cores: - - name: main - type: armv6m - core_access_options: !Arm - ap: 0 - memory_map: - - !Nvm - name: IROM1 - range: - start: 0x0 - end: 0x40000 - cores: - - main - access: - write: false - boot: true - - !Generic - name: IROM2 - range: - start: 0x400000 - end: 0x440000 - cores: - - main - access: - write: false - - !Generic - name: IRAM1 - range: - start: 0x20000000 - end: 0x20010000 - cores: - - main - - !Generic - name: IRAM_Parity - range: - start: 0x20100000 - end: 0x20110000 - cores: - - main - - !Ram - name: IRAM_No_Parity - range: - start: 0x20200000 - end: 0x20220000 - cores: - - main - - !Generic - name: IRAM_Parity_Code - range: - start: 0x20300000 - end: 0x20310000 - cores: - - main - - !Generic - name: NonMain_ECC - range: - start: 0x41c00000 - end: 0x41c00800 - cores: - - main - access: - write: false - execute: false - - !Generic - name: Factory_ECC - range: - start: 0x41c40000 - end: 0x41c40200 - cores: - - main - access: - write: false - execute: false - - !Generic - name: Data - range: - start: 0x41d00000 - end: 0x41d04000 - cores: - - main - access: - write: false - execute: false - flash_algorithms: - - mspm0gx51x_main_512kb - - mspm0gx51x_nonmain - - mspm0gx51x_data_16kb -- name: MSPM0G3519 - cores: - - name: main - type: armv6m - core_access_options: !Arm - ap: 0 - memory_map: - - !Nvm - name: IROM1 - range: - start: 0x0 - end: 0x80000 - cores: - - main - access: - write: false - boot: true - - !Generic - name: IROM2 - range: - start: 0x400000 - end: 0x480000 - cores: - - main - access: - write: false - - !Generic - name: IRAM1 - range: - start: 0x20000000 - end: 0x20010000 - cores: - - main - - !Generic - name: IRAM_Parity - range: - start: 0x20100000 - end: 0x20110000 - cores: - - main - - !Ram - name: IRAM_No_Parity - range: - start: 0x20200000 - end: 0x20220000 - cores: - - main - - !Generic - name: IRAM_Parity_Code - range: - start: 0x20300000 - end: 0x20310000 - cores: - - main - - !Generic - name: NonMain_ECC - range: - start: 0x41c00000 - end: 0x41c00800 - cores: - - main - access: - write: false - execute: false - - !Generic - name: Factory_ECC - range: - start: 0x41c40000 - end: 0x41c40200 - cores: - - main - access: - write: false - execute: false - - !Generic - name: Data - range: - start: 0x41d00000 - end: 0x41d04000 - cores: - - main - access: - write: false - execute: false - flash_algorithms: - - mspm0gx51x_main_512kb - - mspm0gx51x_nonmain - - mspm0gx51x_data_16kb -flash_algorithms: -- name: mspm0gx51x_main_512kb - description: MSPM0GX51X MAIN 512KB - default: true - instructions: ESEJAgEiQlADSUEYCmgHIBBABCj60HBH0BMAABC1FEgBaAcikUMBYBJMYWggaAMikEMgYBEgAAQIQAEhCgWQQgXQCQSIQgTRAfC2+QHgAfCL+WBoDyGIQ2BgAfCF+QZIAWgEIpFDAWAA8Aj4ACAQvQATQEAAAQtAEO0A4ARIBSFBYAEhAWADSAFoSQf81HBHAOEMQNDjDEAAIHBHcLUEIMZDACQITeAHB9EALgXQKEYA8Oj5BEZ2HPXnASBEQARA//fc/yBGcL0A0AxA+LUERm1GKUYA8Cj4AUYBICp4ACoB0IUCAOBFAgApGtAEIMdDACAMTsEHEdEALw/Q//e+/zBGIUYqRgDwp/xAIjBGIUYA8ND4fxwA8Cn46+cBIUhACED4vQDQDEAQtQxKE2gFJBRgByQcQApLG2gUYIIKCUgQQAlKGkCQQgHSACMLcJBCAdMAIBC9ASAQvcBGABNAQBgAxEH/7z8A/w8AAIGwCkgBaAciCkAAkgCZybIDKQPQAJnJsgEp89EAmMCywR5IQkhBAbBwR8BG0OMMQP61FEYNRgZGAqn/97//ASEAKCjQAC0m0AcgKEAj0QKoAXgBIAApAdCBAgDgQQIBkQ9PACEALRbQwAcU0P/3UP8KSDFGAZoA8Dn8OGhAB/zUBkgxRiJGAPAf+wg2CDQIPf/3tv/l5whG/r3ARgDQDEDQ4wxAELUFTAFRABkAKwPQAspBYFse+eeAaBC9BBEAABC1BUwBUQAZmkIC2ALKQWD654BoEL3ARgQRAAC8tQpMBBkAlACcIYAISUEYACsG0BSIAZEBnSyAkhxbHvbnBElAWICyvL3ARgQRAAAIEQAADBEAALy1CUwEGQCUAJwhgAdJQRiaQgXYFIgBkQGdLICSHPfnA0lAWICyvL0EEQAACBEAAAwRAAAQtQIjE0MRIhIChBhjYCFiASGBUBC9wEaAtQIjE0MDSoNQghjRYf/3kf6AvQQRAAAQtQRGEUgAISFQIBhBYIFgykMCZBEgAAIiGFIjU2ARYgEhIVAgRgDwKfgJSQpoBSMLYAcjE0AHShJoC2CRDgTQACgC0CBGAPAx+BC90BEAAAATQEAYAMRBA0kAIkJQQBhCYIJgcEfARtARAAAAIclDAUqBUHBHwEYQEgAAgbAKSUAYAWgHIgpAAJIAmcmyAykD0ACZybIBKfPRAJjAssEeSEJIQQGwcEfQEwAA/rUYSxloBSIaYAciCkAWSQloGmARIhICApCAGAGQjw4STQEgAp7/sv83+bK5QhXQwQcT0DBGAPD5+AEkYgIwRilGAPBB+0IgAZlIYA1iDGCgAi0YMEb/97v/5OcBIQhA/r3ARgATQEAYAMRBAADQQRC1BEYQSAAhIVAgGEFggWDKQwJkDUhSIiJQIBjBYSBG//fu/QpJCmgFIwtgByMTQAhKEmgLYJEOBNABKALQIEYA8Ar4EL3ARtARAAAEEQAAABNAQBgAxEGAtQdJACJCUEEYSmCKYAVJUiJCUEEYBErKYf/3xf2AvdARAAAEEQAAAADQQfC1h7AERgDwhfgFRjpIAWgFIgJgByIKQDhJCWgCYDhIIBgCkBEgAAIElCYYNUgIQClGAfBf+CpGgAIBkGgIBpAQIAWQACcBJD1GIEYDkgCUlUJJ0sEHR9AGmIVCAdIAIQDgASEoSABoQAUgRgDVCEYpBokOBdH5FTtGJKd5Wh9GBZEAKCBGKtAEnCBGAPBU+AEgAQSyaApDsmAfIQkBBZoKQLNoi0OZGLFgDyFJArJoikNBAlEYsWAAIQKaEWBRYJFgyUMRZFIhcWApRgGaUUMxYjBgIEYAnP/3AP8DmgEhCQZ/GG0cs+cBIQoEs2iTQ7NgCEAHsPC9ABNAQBgAxEHQEQAA/w8AAEggC0AQACAAQACAAAZIAWgFIgJgByIKQARJCWgCYIgEgA9AHHBHwEYAE0BAGADEQREhCQJCGAUjU2ABIkJQAkgBaEkH/NRwR9DjDEAQtQRG//eC/gAoENAJSCAYESEJAmEYACICYEIgSGAGSAhiASAIYCBG//eu/hC9ACAQvcBGEBIAAAAAwEEBSQAiQlBwRxASAAAQtQRG//fs/gMoDNEGSCAYBklhGAAiCmBCIQFgBEnBYSBG//fd/BC9BBEAABASAAAAAMBBELUERv/3FP8AKBDQCUggGBEhCQJhGAAiAmBCIEhgBkgIYgEgCGAgRv/3cP4QvQAgEL3ARhASAAAAAMBBsLURIxsCxBgBJWVgZWIhYhF4IWPFULC9ELUFSwEkxFDDGBxi2WEReNli//eh/BC9BBEAAHC1ESMbAsQYASVlYAMmZmIhYhGIIWPFUHC9wEYQtQZLASTEUMMYAyQcYtlhEYjZYv/3hPwQvcBGBBEAAHC1ESMbAsQYASVlYA8mZmIhYhFoIWPFUHC9wEYQtQZLASTEUMMYDyQcYtlhEWjZYv/3ZvwQvcBGBBEAAHC1ESMbAsQYASVlYP8mZmIhYhFoIWNRaGFjxVBwvcBGELUHSwEkxFDDGP8kHGLZYRFo2WJRaBlj//dE/BC9wEYEEQAAcLURIxsCxBgBJWVg/yYCNmZiIWIReCFjxVBwvRC1BksBJMRQwxj/JAI0HGLZYRF42WL/9yX8EL0EEQAAcLURIxsCxBgBJWVg/yYENmZiIWIRiCFjxVBwvRC1BksBJMRQwxj/JAQ0HGLZYRGI2WL/9wf8EL0EEQAAcLURIxsCxBgBJWVg/yYQNmZiIWIRaCFjxVBwvRC1BksBJMRQwxj/JBA0HGLZYRFo2WL/9+n7EL0EEQAAcLURIxsCxBgBJWVgBE5mYiFiEWghY1FoYWPFUHC9wEb/AQAAELUHSwEkxFDDGAZMHGLZYRFo2WJRaBlj//fG+xC9wEYEEQAA/wEAAPC1ESQkAgUZASZuYP8nAjdvYiliEXgpYxl4AkqBUAZR8L3ARrARAACwtQhMASUFUQQZ/yUCNSVi4WEReOFiGXgDSoFQ//ec+7C9wEYEEQAAsBEAAPC1ESQkAgUZASZuYP8nBDdvYiliEYgpYxl4AkqBUAZR8L3ARrARAACwtQhMASUFUQQZ/yUENSVi4WERiOFiGXgDSoFQ//dy+7C9wEYEEQAAsBEAAPC1ESQkAgUZASZuYP8nEDdvYiliEWgpYxl4AkqBUAZR8L3ARrARAACwtQhMASUFUQQZ/yUQNSVi4WERaOFiGXgDSoFQ//dI+7C9wEYEEQAAsBEAAPC1ESQkAgUZASZuYAVPb2IpYhFoKWNRaGljGXgCSoFQBlHwvf8BAACwEQAAsLUITAElBVEEGQdNJWLhYRFo4WJRaCFjGXgESoFQ//cb+7C9BBEAAP8BAACwEQAA8LWHsB9GBpIFkQRGASEYRgSRCEBBQkFBWh4YRpBBCEARIQkCA5RhGAKRDJkBkQOdAC8f0MEHHdAoRv/30/0oRgWcIUYBmgDwG/gEmQKaUWAKSFBiFGIGnjBoEGNwaFBjEWAINAWUvx4oRv/3jfwINgaW3ecEmQhAB7Dwvf8BAABwtRVGDEYLSUYYIEYA8D75ASGKApVCBNBKApVCCNHACALgPDZgBMAOgUAwaIhDMGBwvcBG1BEAAPi1HEYVRg5GB0YBIdgHAdAIRgDgBCAALADRCEYGmQCRACwQ0MGyASkN0DhGMUYAmv/3yv84RjFGKkb/98X+CDYINaQe7OfAsvi9wEbwtYewBpMEkgORA0YBIQyfOEYCkQhAQUJBQXoeOEaQQQhAGElZGAGRESEJAgWTXBgNmQCRAC8h0MEHH9AFmAOdKUYAmv/3mv8CmmJgDkhgYiViBJ4waCBjcGhgYwaZCHgBmxhgImAINQOVSRwGkb8eBZj/9wf8CDYEltvnApkIQAew8L2wEQAA/wEAAP61ApMVRg5GAZAInwEh+AcB0AhGAOAEIAAvANEIRgmZAJEALxXQwbIBKRLQAZwgRjFGAJr/91z/IEYxRipGApwjRv/3/f4INmQcApQINb8e5+fAsv69/rUfRhRGDUYCRlkeGEaIQREhCQICklYYCJkBkQAvJdDBByPQApgpRgGa//c2/wEgcGABLwvQ/yFxYjViIWgxY2FocWMwYL8eCCECIAfgDyFxYjViIWgxYzBgACcEIW0YgAAkGAKY//ec+9fnASEIQP69+LUfRhRGDUYGRgArAdAEIADgASAGmQCRAC8b0MGyASkY0DBGKUYAmv/3/v4wRilGIkYBLwXQ//d5/b8eCCECIgTg//dT/QAnBCEBIm0YkQBkGOHnwLL4vQNJACJCUEAYQmCCYHBHwEbQEQAAACHJQwJKgVCAGEFggWBwR9ARAAAESQAiQlBAGEJggmACZEJkgmRwR9ARAAAAIclDBEqBUIAYQWCBYAFkQWSBZHBHwEbQEQAAELUERv/3VvwBRgtKEGgFIxNgByMDQAlIAGgTYKQKAikI0wdKEEAA8DX8AUYgRgDwMfwMRiBGEL0AE0BAGADEQf8PAABwtRVGDEYLSUYYIEb/99b/ASGKApVCBNBKApVCCNHACALgPDZgBMAOgUAwaAhDMGBwvcBG1BEAALC1ESMbAsQYAyVlYCFiASFhYhJ4ImPBULC9sLURIxsCxBgDJWVgIWJlYhGIIWMBIcFQsL2wtREjGwLEGAMlZWAhYg8hYWIRaCFjASHBULC9sLURIxsCxBgDJWVgIWL/IWFiEWghY1FoYWMBIcFQsL0QtQZLAyTEUMMYASQcYtlhEXjZYv/3DPkQvcBGBBEAABC1BUsDJMRQwxgcYtlhEYjZYv/3/fgQvQQRAAAQtQZLAyTEUMMYDyQcYtlhEWjZYv/37vgQvcBGBBEAABC1B0sDJMRQwxj/JBxi2WERaNliUWgZY//33PgQvcBGBBEAABC1BksDJMRQwxj/JAI0HGLZYRF42WL/98v4EL0EEQAAELUGSwMkxFDDGP8kBDQcYtlhEYjZYv/3u/gQvQQRAAAQtQZLAyTEUMMY/yQQNBxi2WERaNli//er+BC9BBEAABC1B0sDJMRQwxgGTBxi2WERaNliUWgZY//3mvgQvcBGBBEAAP8BAACwtQhMAyUFUQQZ/yUCNSVi4WEReOFiGXgDSoFQ//eE+LC9wEYEEQAAsBEAALC1CEwDJQVRBBn/JQQ1JWLhYRGI4WIZeANKgVD/9274sL3ARgQRAACwEQAAsLUITAMlBVEEGf8lEDUlYuFhEWjhYhl4A0qBUP/3WPiwvcBGBBEAALARAACwtQhMAyUFUQQZB00lYuFhEWjhYlFoIWMZeARKgVD/90H4sL0EEQAA/wEAALARAACwtREjGwLEGAMlZWAhYv8hAjFhYhF4IWMBIcFQsL2wtREjGwLEGAMlZWAhYv8hBDFhYhGIIWMBIcFQsL2wtREjGwLEGAMlZWAhYv8hEDFhYhFoIWMBIcFQsL3ARrC1ESMbAsQYAyVlYCFiBElhYhFoIWNRaGFjASHBULC9/wEAAHC1ESQkAgUZAyZuYCli/yECMWliEXgpYxl4AkqBUAEhAVFwvbARAABwtREkJAIFGQMmbmApYv8hBDFpYhGIKWMZeAJKgVABIQFRcL2wEQAAcLURJCQCBRkDJm5gKWL/IRAxaWIRaCljGXgCSoFQASEBUXC9sBEAAHC1ESQkAgUZAyZuYCliBklpYhFoKWNRaGljGXgDSoFQASEBUXC9wEb/AQAAsBEAABC1ESISAoMYBiRcYBliASGBUBC9gLUESgYjg1CCGNFh/veU/4C9wEYEEQAAELUTRgRGBEoA8Aj4ESAAAgEhIVAQvcBG//8AALC1B0wRJQVRABkCYsFhGWjBYlloAWOZaEFj2WiBY7C9BBEAABC1E0YERgRK//fo/xEgAAIBISFQEL3ARv//AQCwtR1GE0YERgZK//fZ/yh4BUlgUGAYaXhBYBEgAAIBISFQsL3//wEAsBEAAPC1hbAfRhRGDUYCRhEgAQIAKwHQAy8B2AAgAOABIASSVhgKmQOR/yEQMQKRAZYALzrQwQc40ASYKUYDmv/3WPwBLxDQAy8a2AEgcGACmfAxcWI1YiFoMWNhaHFjMGC/HgghAiIJ4AEicmACmHBiNWIhaDFjMmAAJwQhBJgO4C5GJUYEnCBGMUYqRv/3lf8gRixGNUYBnj8fECEEIm0YkQBkGP/3qfjC5wEhCEAFsPC9/7UBJCICKksZaAOSkUMZYChJDWhtBPzVRX4lQJ5ppkN0GZxhICQEXQMlLEDeaa5DNBncYSBMJWgFJiZgRmo3aB9idmheYgcmLkAmYMRpfyUtAt5prkNkBmQMNBncYQdoRWiCaACSxmgCaQGSQmkCkpppEkwUQDoHEgstA62yqhgyQwCdLQctDRVDAZoVQwKaFUMAfihDCkoCQBAZmGEYaAOaEEMYYAhogAX81f+9wEYIAQtABAILQAATQECNAPD/cv8PALC1/yIEMg5JC2iTQ4J4AyQUQAJ4EgISGRpDCmAJSgpLE2AKTCVobQX81UB4ACgD0AhoECQEQwxgWBwQYLC9wEYUAQtAFAMLQAEAAJEEAgtADEkKaAAoA9ABIIACAkMG4AMggkMKYAEggAIKaIJDCmABIAAFSmgCQ0pgA0gBaIkD/NVwRwABC0AEAgtAASCBAgZKE2iLQxNgAAVRaIFDUWADSAFoiQP81HBHwEYAAQtABAILQAdJiGAHSAJokgL81QEiEgQLaBNDC2ABaMkG/NVwR8BGBAELQAQCC0ABIAAEBEkKaIJDCmADSAFoyQb81HBHwEYEAQtABAILQBC1D0kLaAEik0MLYAMjGwMYQIxonEMgGIhgiGgIIwND9yCDQ4tgCGgQQwhgEAeKaAJDimADSAFoyQX81RC9wEYIAQtABAILQHC1EUsdaAEkpUMdYAMlLQMoQJ5orkMwGJhgmGj/JahDybJAGJhgGGggQxhgmGghBwAqBtAIQ5hgBEgBaMkF/NVwvYhDmGBwvQgBC0AEAgtAsLU/IxsEBEwlaJ1DCEMQQxhAKBggYLC9OAELQAlIAGhABwjUCEhBaMkCBtQAaIAFBdUDIHBHACBwRwIgcEcBIHBHwEYQ7QDgAAELQApJCmwAIAAqANBwRwhKEmhSB/rVCGjABQTUCGiABQPVAyBwRwIgcEcBIHBHAAELQBDtAOAHScprACABKgfRBkoSaFIHA9UIaIACAdUCIHBHASBwRwQBC0AQ7QDgELUISxxrASIiQAjRBkwgQBhgIUBZYNhqBEkBQ9liUEJQQRC9GCALQMD/PwAQAAB2ELUIS5xqASIiQAjRBkwgQBhgIUAZYFhqBEkBQ1liUEJQQRC9ICALQMD/PwBAAAB2ACIDCYtCLNMDCotCEdMAI5xGTuADRgtDPNQAIkMIi0Ix0wMJi0Ic0wMKi0IB05RGP+DDCYtCAdPLAcAaUkGDCYtCAdOLAcAaUkFDCYtCAdNLAcAaUkEDCYtCAdMLAcAaUkHDCItCAdPLAMAaUkGDCItCAdOLAMAaUkFDCItCAdNLAMAaUkFBGgDSAUZSQRBGcEdd4MoPANBJQgMQANNAQlNAnEYAIgMJi0It0wMKi0IS04kB/CISugMKi0IM04kBkhGLQgjTiQGSEYtCBNOJATrQkhEA4IkJwwmLQgHTywHAGlJBgwmLQgHTiwHAGlJBQwmLQgHTSwHAGlJBAwmLQgHTCwHAGlJBwwiLQgHTywDAGlJBgwiLQgHTiwDAGlJB2dJDCItCAdNLAMAaUkFBGgDSAUZSQRBGY0ZbEAHTQEIAKwDVSUJwR2NGWxAA00BCAbUFSQAoAtxJHAhAAOAIRsBGwEYCvQC/////fwAAAAA= - load_address: 0x20200008 - pc_init: 0x1d - pc_uninit: 0x99 - pc_program_page: 0x19d - pc_erase_sector: 0xcd - pc_erase_all: 0x9d - data_section_offset: 0x16e4 - flash_properties: - address_range: - start: 0x0 - end: 0x80000 - page_size: 0x400 - erased_byte_value: 0xff - program_page_timeout: 500 - erase_sector_timeout: 3000 - sectors: - - size: 0x400 - address: 0x0 -- name: mspm0gx51x_nonmain - description: MSPM0GX51X NON-MAIN - instructions: ESEJAgEiQlADSUEYCmgHIBBABCj60HBH0BMAABC1GEgBaAcikUMBYBZIF0kBYBdMYWggaAMikEMgYBEgAAQIQAEhCgWQQgXQCQSIQgTRAfDj+QHgAfC4+WBoDyGIQ2BgAfCy+QpIAWgEIpFDAWAA8BP4CEkCIAhgACDCQ0pgEL0AE0BAAAhEQAEAACYAAQtAEO0A4AARREAESAUhQWABIQFgA0gBaEkH/NRwRwDhDEDQ4wxA/rUBIYhDAig90QCRACACkMBDAZAfTS4jHUwgRgGfOUYqRgDwy/gGRhYjIEY5RhpKAPDE+ARGMEYgQx/QKEYA8DH4uCEVSnpEL0YoRgDwUvhYIRNKekQQSADwTPgALgPQApkDKQbZEOABIAAsB9ACmQQpBNJJHAKRPUbM5wKYACgAmADQ/r0AIP69AJj+vcBGAABEQAAAwEEAAcBBRhYAABgZAAD4tQRGQAoQSYhCGNEEIMZDACAOTQEnwQcT0QAuEdD/94//ugIoRiFGAPCa/EAiKEYhRgDww/h2HADwVvjq5wEg+L14QDhA+L0A4CAAANAMQPi1FEYNRgZGQQoBIBNKkUIi0QAtINAHISlAHdEBIRFPACAALRjQyQcW0P/3Yf8BIIICC0gxRgDwa/w4aEAH/NQHSDFGIkYA8FH7CDYINAg9APAi+AFG4+f4vcBGAOAgAADQDEDQ4wxAcLUEIMZDACQITeAHB9EALgXQKEYA8F75BEZ2HPXnASBEQARA//cw/yBGcL0A0AxAgbAKSAFoByIKQACSAJnJsgMpA9AAmcmyASnz0QCYwLLBHkhCSEEBsHBHwEbQ4wxAELUFTAFRABkAKwPQAspBYFse+eeAaBC9BBEAABC1BUwBUQAZmkIC2ALKQWD654BoEL3ARgQRAAC8tQpMBBkAlACcIYAISUEYACsG0BSIAZEBnSyAkhxbHvbnBElAWICyvL3ARgQRAAAIEQAADBEAALy1CUwEGQCUAJwhgAdJQRiaQgXYFIgBkQGdLICSHPfnA0lAWICyvL0EEQAACBEAAAwRAAAQtQIjE0MRIhIChBhjYCFiASGBUBC9wEaAtQIjE0MDSoNQghjRYf/3Yf6AvQQRAAAQtQRGEUgAISFQIBhBYIFgykMCZBEgAAIiGFIjU2ARYgEhIVAgRgDwKfgJSQpoBSMLYAcjE0AHShJoC2CRDgTQACgC0CBGAPAx+BC90BEAAAATQEAYAMRBA0kAIkJQQBhCYIJgcEfARtARAAAAIclDAUqBUHBHwEYQEgAAgbAKSUAYAWgHIgpAAJIAmcmyAykD0ACZybIBKfPRAJjAssEeSEJIQQGwcEfQEwAA/rUYSxloBSIaYAciCkAWSQloGmARIhICApCAGAGQjw4STQEgAp7/sv83+bK5QhXQwQcT0DBGAPD5+AEkYgIwRilGAPBB+0IgAZlIYA1iDGCgAi0YMEb/97v/5OcBIQhA/r3ARgATQEAYAMRBAADQQRC1BEYQSAAhIVAgGEFggWDKQwJkDUhSIiJQIBjBYSBG//e+/QpJCmgFIwtgByMTQAhKEmgLYJEOBNABKALQIEYA8Ar4EL3ARtARAAAEEQAAABNAQBgAxEGAtQdJACJCUEEYSmCKYAVJUiJCUEEYBErKYf/3lf2AvdARAAAEEQAAAADQQfC1h7AERgDwhfgFRjpIAWgFIgJgByIKQDhJCWgCYDhIIBgCkBEgAAIElCYYNUgIQClGAfBf+CpGgAIBkGgIBpAQIAWQACcBJD1GIEYDkgCUlUJJ0sEHR9AGmIVCAdIAIQDgASEoSABoQAUgRgDVCEYpBokOBdH5FTtGJKd5Wh9GBZEAKCBGKtAEnCBGAPBU+AEgAQSyaApDsmAfIQkBBZoKQLNoi0OZGLFgDyFJArJoikNBAlEYsWAAIQKaEWBRYJFgyUMRZFIhcWApRgGaUUMxYjBgIEYAnP/3AP8DmgEhCQZ/GG0cs+cBIQoEs2iTQ7NgCEAHsPC9ABNAQBgAxEHQEQAA/w8AAEggC0AQACAAQACAAAZIAWgFIgJgByIKQARJCWgCYIgEgA9AHHBHwEYAE0BAGADEQREhCQJCGAUjU2ABIkJQAkgBaEkH/NRwR9DjDEAQtQRG//eC/gAoENAJSCAYESEJAmEYACICYEIgSGAGSAhiASAIYCBG//eu/hC9ACAQvcBGEBIAAAAAwEEBSQAiQlBwRxASAAAQtQRG//fs/gMoDNEGSCAYBklhGAAiCmBCIQFgBEnBYSBG//et/BC9BBEAABASAAAAAMBBELUERv/3FP8AKBDQCUggGBEhCQJhGAAiAmBCIEhgBkgIYgEgCGAgRv/3cP4QvQAgEL3ARhASAAAAAMBBsLURIxsCxBgBJWVgZWIhYhF4IWPFULC9ELUFSwEkxFDDGBxi2WEReNli//dx/BC9BBEAAHC1ESMbAsQYASVlYAMmZmIhYhGIIWPFUHC9wEYQtQZLASTEUMMYAyQcYtlhEYjZYv/3VPwQvcBGBBEAAHC1ESMbAsQYASVlYA8mZmIhYhFoIWPFUHC9wEYQtQZLASTEUMMYDyQcYtlhEWjZYv/3NvwQvcBGBBEAAHC1ESMbAsQYASVlYP8mZmIhYhFoIWNRaGFjxVBwvcBGELUHSwEkxFDDGP8kHGLZYRFo2WJRaBlj//cU/BC9wEYEEQAAcLURIxsCxBgBJWVg/yYCNmZiIWIReCFjxVBwvRC1BksBJMRQwxj/JAI0HGLZYRF42WL/9/X7EL0EEQAAcLURIxsCxBgBJWVg/yYENmZiIWIRiCFjxVBwvRC1BksBJMRQwxj/JAQ0HGLZYRGI2WL/99f7EL0EEQAAcLURIxsCxBgBJWVg/yYQNmZiIWIRaCFjxVBwvRC1BksBJMRQwxj/JBA0HGLZYRFo2WL/97n7EL0EEQAAcLURIxsCxBgBJWVgBE5mYiFiEWghY1FoYWPFUHC9wEb/AQAAELUHSwEkxFDDGAZMHGLZYRFo2WJRaBlj//eW+xC9wEYEEQAA/wEAAPC1ESQkAgUZASZuYP8nAjdvYiliEXgpYxl4AkqBUAZR8L3ARrARAACwtQhMASUFUQQZ/yUCNSVi4WEReOFiGXgDSoFQ//ds+7C9wEYEEQAAsBEAAPC1ESQkAgUZASZuYP8nBDdvYiliEYgpYxl4AkqBUAZR8L3ARrARAACwtQhMASUFUQQZ/yUENSVi4WERiOFiGXgDSoFQ//dC+7C9wEYEEQAAsBEAAPC1ESQkAgUZASZuYP8nEDdvYiliEWgpYxl4AkqBUAZR8L3ARrARAACwtQhMASUFUQQZ/yUQNSVi4WERaOFiGXgDSoFQ//cY+7C9wEYEEQAAsBEAAPC1ESQkAgUZASZuYAVPb2IpYhFoKWNRaGljGXgCSoFQBlHwvf8BAACwEQAAsLUITAElBVEEGQdNJWLhYRFo4WJRaCFjGXgESoFQ//fr+rC9BBEAAP8BAACwEQAA8LWHsB9GBpIFkQRGASEYRgSRCEBBQkFBWh4YRpBBCEARIQkCA5RhGAKRDJkBkQOdAC8f0MEHHdAoRv/30/0oRgWcIUYBmgDwG/gEmQKaUWAKSFBiFGIGnjBoEGNwaFBjEWAINAWUvx4oRv/3jfwINgaW3ecEmQhAB7Dwvf8BAABwtRVGDEYLSUYYIEYA8D75ASGKApVCBNBKApVCCNHACALgPDZgBMAOgUAwaIhDMGBwvcBG1BEAAPi1HEYVRg5GB0YBIdgHAdAIRgDgBCAALADRCEYGmQCRACwQ0MGyASkN0DhGMUYAmv/3yv84RjFGKkb/98X+CDYINaQe7OfAsvi9wEbwtYewBpMEkgORA0YBIQyfOEYCkQhAQUJBQXoeOEaQQQhAGElZGAGRESEJAgWTXBgNmQCRAC8h0MEHH9AFmAOdKUYAmv/3mv8CmmJgDkhgYiViBJ4waCBjcGhgYwaZCHgBmxhgImAINQOVSRwGkb8eBZj/9wf8CDYEltvnApkIQAew8L2wEQAA/wEAAP61ApMVRg5GAZAInwEh+AcB0AhGAOAEIAAvANEIRgmZAJEALxXQwbIBKRLQAZwgRjFGAJr/91z/IEYxRipGApwjRv/3/f4INmQcApQINb8e5+fAsv69/rUfRhRGDUYCRlkeGEaIQREhCQICklYYCJkBkQAvJdDBByPQApgpRgGa//c2/wEgcGABLwvQ/yFxYjViIWgxY2FocWMwYL8eCCECIAfgDyFxYjViIWgxYzBgACcEIW0YgAAkGAKY//ec+9fnASEIQP69+LUfRhRGDUYGRgArAdAEIADgASAGmQCRAC8b0MGyASkY0DBGKUYAmv/3/v4wRilGIkYBLwXQ//d5/b8eCCECIgTg//dT/QAnBCEBIm0YkQBkGOHnwLL4vQNJACJCUEAYQmCCYHBHwEbQEQAAACHJQwJKgVCAGEFggWBwR9ARAAAESQAiQlBAGEJggmACZEJkgmRwR9ARAAAAIclDBEqBUIAYQWCBYAFkQWSBZHBHwEbQEQAAELUERv/3VvwBRgtKEGgFIxNgByMDQAlIAGgTYKQKAikI0wdKEEAA8DX8AUYgRgDwMfwMRiBGEL0AE0BAGADEQf8PAABwtRVGDEYLSUYYIEb/99b/ASGKApVCBNBKApVCCNHACALgPDZgBMAOgUAwaAhDMGBwvcBG1BEAALC1ESMbAsQYAyVlYCFiASFhYhJ4ImPBULC9sLURIxsCxBgDJWVgIWJlYhGIIWMBIcFQsL2wtREjGwLEGAMlZWAhYg8hYWIRaCFjASHBULC9sLURIxsCxBgDJWVgIWL/IWFiEWghY1FoYWMBIcFQsL0QtQZLAyTEUMMYASQcYtlhEXjZYv/33PgQvcBGBBEAABC1BUsDJMRQwxgcYtlhEYjZYv/3zfgQvQQRAAAQtQZLAyTEUMMYDyQcYtlhEWjZYv/3vvgQvcBGBBEAABC1B0sDJMRQwxj/JBxi2WERaNliUWgZY//3rPgQvcBGBBEAABC1BksDJMRQwxj/JAI0HGLZYRF42WL/95v4EL0EEQAAELUGSwMkxFDDGP8kBDQcYtlhEYjZYv/3i/gQvQQRAAAQtQZLAyTEUMMY/yQQNBxi2WERaNli//d7+BC9BBEAABC1B0sDJMRQwxgGTBxi2WERaNliUWgZY//3avgQvcBGBBEAAP8BAACwtQhMAyUFUQQZ/yUCNSVi4WEReOFiGXgDSoFQ//dU+LC9wEYEEQAAsBEAALC1CEwDJQVRBBn/JQQ1JWLhYRGI4WIZeANKgVD/9z74sL3ARgQRAACwEQAAsLUITAMlBVEEGf8lEDUlYuFhEWjhYhl4A0qBUP/3KPiwvcBGBBEAALARAACwtQhMAyUFUQQZB00lYuFhEWjhYlFoIWMZeARKgVD/9xH4sL0EEQAA/wEAALARAACwtREjGwLEGAMlZWAhYv8hAjFhYhF4IWMBIcFQsL2wtREjGwLEGAMlZWAhYv8hBDFhYhGIIWMBIcFQsL2wtREjGwLEGAMlZWAhYv8hEDFhYhFoIWMBIcFQsL3ARrC1ESMbAsQYAyVlYCFiBElhYhFoIWNRaGFjASHBULC9/wEAAHC1ESQkAgUZAyZuYCli/yECMWliEXgpYxl4AkqBUAEhAVFwvbARAABwtREkJAIFGQMmbmApYv8hBDFpYhGIKWMZeAJKgVABIQFRcL2wEQAAcLURJCQCBRkDJm5gKWL/IRAxaWIRaCljGXgCSoFQASEBUXC9sBEAAHC1ESQkAgUZAyZuYCliBklpYhFoKWNRaGljGXgDSoFQASEBUXC9wEb/AQAAsBEAABC1ESISAoMYBiRcYBliASGBUBC9gLUESgYjg1CCGNFh/vdk/4C9wEYEEQAAELUTRgRGBEoA8Aj4ESAAAgEhIVAQvcBG//8AALC1B0wRJQVRABkCYsFhGWjBYlloAWOZaEFj2WiBY7C9BBEAABC1E0YERgRK//fo/xEgAAIBISFQEL3ARv//AQCwtR1GE0YERgZK//fZ/yh4BUlgUGAYaXhBYBEgAAIBISFQsL3//wEAsBEAAPC1hbAfRhRGDUYCRhEgAQIAKwHQAy8B2AAgAOABIASSVhgKmQOR/yEQMQKRAZYALzrQwQc40ASYKUYDmv/3WPwBLxDQAy8a2AEgcGACmfAxcWI1YiFoMWNhaHFjMGC/HgghAiIJ4AEicmACmHBiNWIhaDFjMmAAJwQhBJgO4C5GJUYEnCBGMUYqRv/3lf8gRixGNUYBnj8fECEEIm0YkQBkGP/3qfjC5wEhCEAFsPC9/7UBJCICKksZaAOSkUMZYChJDWhtBPzVRX4lQJ5ppkN0GZxhICQEXQMlLEDeaa5DNBncYSBMJWgFJiZgRmo3aB9idmheYgcmLkAmYMRpfyUtAt5prkNkBmQMNBncYQdoRWiCaACSxmgCaQGSQmkCkpppEkwUQDoHEgstA62yqhgyQwCdLQctDRVDAZoVQwKaFUMAfihDCkoCQBAZmGEYaAOaEEMYYAhogAX81f+9wEYIAQtABAILQAATQECNAPD/cv8PALC1/yIEMg5JC2iTQ4J4AyQUQAJ4EgISGRpDCmAJSgpLE2AKTCVobQX81UB4ACgD0AhoECQEQwxgWBwQYLC9wEYUAQtAFAMLQAEAAJEEAgtADEkKaAAoA9ABIIACAkMG4AMggkMKYAEggAIKaIJDCmABIAAFSmgCQ0pgA0gBaIkD/NVwRwABC0AEAgtAASCBAgZKE2iLQxNgAAVRaIFDUWADSAFoiQP81HBHwEYAAQtABAILQAdJiGAHSAJokgL81QEiEgQLaBNDC2ABaMkG/NVwR8BGBAELQAQCC0ABIAAEBEkKaIJDCmADSAFoyQb81HBHwEYEAQtABAILQBC1D0kLaAEik0MLYAMjGwMYQIxonEMgGIhgiGgIIwND9yCDQ4tgCGgQQwhgEAeKaAJDimADSAFoyQX81RC9wEYIAQtABAILQHC1EUsdaAEkpUMdYAMlLQMoQJ5orkMwGJhgmGj/JahDybJAGJhgGGggQxhgmGghBwAqBtAIQ5hgBEgBaMkF/NVwvYhDmGBwvQgBC0AEAgtAsLU/IxsEBEwlaJ1DCEMQQxhAKBggYLC9OAELQAlIAGhABwjUCEhBaMkCBtQAaIAFBdUDIHBHACBwRwIgcEcBIHBHwEYQ7QDgAAELQApJCmwAIAAqANBwRwhKEmhSB/rVCGjABQTUCGiABQPVAyBwRwIgcEcBIHBHAAELQBDtAOAHScprACABKgfRBkoSaFIHA9UIaIACAdUCIHBHASBwRwQBC0AQ7QDgELUISxxrASIiQAjRBkwgQBhgIUBZYNhqBEkBQ9liUEJQQRC9GCALQMD/PwAQAAB2ELUIS5xqASIiQAjRBkwgQBhgIUAZYFhqBEkBQ1liUEJQQRC9ICALQMD/PwBAAAB2ACIDCYtCLNMDCotCEdMAI5xGTuADRgtDPNQAIkMIi0Ix0wMJi0Ic0wMKi0IB05RGP+DDCYtCAdPLAcAaUkGDCYtCAdOLAcAaUkFDCYtCAdNLAcAaUkEDCYtCAdMLAcAaUkHDCItCAdPLAMAaUkGDCItCAdOLAMAaUkFDCItCAdNLAMAaUkFBGgDSAUZSQRBGcEdd4MoPANBJQgMQANNAQlNAnEYAIgMJi0It0wMKi0IS04kB/CISugMKi0IM04kBkhGLQgjTiQGSEYtCBNOJATrQkhEA4IkJwwmLQgHTywHAGlJBgwmLQgHTiwHAGlJBQwmLQgHTSwHAGlJBAwmLQgHTCwHAGlJBwwiLQgHTywDAGlJBgwiLQgHTiwDAGlJB2dJDCItCAdNLAMAaUkFBGgDSAUZSQRBGY0ZbEAHTQEIAKwDVSUJwR2NGWxAA00BCAbUFSQAoAtxJHAhAAOAIRsBGwEYCvQC/////fwAAAAS7qruqu6q7qv//////////u6q7qruqu6r//7uqu6q7qv///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////9B/+hoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEFgIVAgEDAgOoEv//r5YTdg9yY1+9tEpaCmPDnxKvMPlQpu5clxvhiOicQFH/////////////////////////////////////////////SADJWPEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== - load_address: 0x20200008 - pc_init: 0x1d - pc_uninit: 0xb5 - pc_program_page: 0x1a9 - pc_erase_sector: 0x159 - pc_erase_all: 0x211 - data_section_offset: 0x1b84 - flash_properties: - address_range: - start: 0x41c00000 - end: 0x41c00400 - page_size: 0x40 - erased_byte_value: 0xff - program_page_timeout: 500 - erase_sector_timeout: 3000 - sectors: - - size: 0x400 - address: 0x0 -- name: mspm0gx51x_data_16kb - description: MSPM0GX51X DATA 16KB - instructions: ESEJAgEiQlADSUEYCmgHIBBABCj60HBH0BMAABC1FEgBaAcikUMBYBJMYWggaAMikEMgYBEgAAQIQAEhCgWQQgXQCQSIQgTRAfC2+QHgAfCL+WBoDyGIQ2BgAfCF+QZIAWgEIpFDAWAA8Aj4ACAQvQATQEAAAQtAEO0A4ARIBSFBYAEhAWADSAFoSQf81HBHAOEMQNDjDEAAIHBHcLUEIMZDACQITeAHB9EALgXQKEYA8G75BEZ2HPXnASBEQARA//fc/yBGcL0A0AxA+LUERm1GKUYA8Cj4AUYBICp4ACoB0IUCAOBFAgApGtAEIMdDACAMTsEHEdEALw/Q//e+/zBGIUYqRgDwp/xAIjBGIUYA8ND4fxwA8Cn46+cBIUhACED4vQDQDEAQtQxKE2gFJBRgByQcQApLG2gUYIIKCUgQQAlKGkCQQgHSACMLcJBCAdMAIBC9ASAQvcBGABNAQBgAxEH/7z8A/w8AAIGwCkgBaAciCkAAkgCZybIDKQPQAJnJsgEp89EAmMCywR5IQkhBAbBwR8BG0OMMQP61FEYNRgZGAqn/97//ASEAKCjQAC0m0AcgKEAj0QKoAXgBIAApAdCBAgDgQQIBkQ9PACEALRbQwAcU0P/3UP8KSDFGAZoA8Dn8OGhAB/zUBkgxRiJGAPAf+wg2CDQIPf/3tv/l5whG/r3ARgDQDEDQ4wxAELUFTAFRABkAKwPQAspBYFse+eeAaBC9BBEAABC1BUwBUQAZmkIC2ALKQWD654BoEL3ARgQRAAC8tQpMBBkAlACcIYAISUEYACsG0BSIAZEBnSyAkhxbHvbnBElAWICyvL3ARgQRAAAIEQAADBEAALy1CUwEGQCUAJwhgAdJQRiaQgXYFIgBkQGdLICSHPfnA0lAWICyvL0EEQAACBEAAAwRAAAQtQIjE0MRIhIChBhjYCFiASGBUBC9wEaAtQIjE0MDSoNQghjRYf/3kf6AvQQRAAAQtQRGEUgAISFQIBhBYIFgykMCZBEgAAIiGFIjU2ARYgEhIVAgRgDwKfgJSQpoBSMLYAcjE0AHShJoC2CRDgTQACgC0CBGAPAx+BC90BEAAAATQEAYAMRBA0kAIkJQQBhCYIJgcEfARtARAAAAIclDAUqBUHBHwEYQEgAAgbAKSUAYAWgHIgpAAJIAmcmyAykD0ACZybIBKfPRAJjAssEeSEJIQQGwcEfQEwAA/rUYSxloBSIaYAciCkAWSQloGmARIhICApCAGAGQjw4STQEgAp7/sv83+bK5QhXQwQcT0DBGAPD5+AEkYgIwRilGAPBB+0IgAZlIYA1iDGCgAi0YMEb/97v/5OcBIQhA/r3ARgATQEAYAMRBAADQQRC1BEYQSAAhIVAgGEFggWDKQwJkDUhSIiJQIBjBYSBG//fu/QpJCmgFIwtgByMTQAhKEmgLYJEOBNABKALQIEYA8Ar4EL3ARtARAAAEEQAAABNAQBgAxEGAtQdJACJCUEEYSmCKYAVJUiJCUEEYBErKYf/3xf2AvdARAAAEEQAAAADQQfC1h7AERgDwhfgFRjpIAWgFIgJgByIKQDhJCWgCYDhIIBgCkBEgAAIElCYYNUgIQClGAfBf+CpGgAIBkGgIBpAQIAWQACcBJD1GIEYDkgCUlUJJ0sEHR9AGmIVCAdIAIQDgASEoSABoQAUgRgDVCEYpBokOBdH5FTtGJKd5Wh9GBZEAKCBGKtAEnCBGAPBU+AEgAQSyaApDsmAfIQkBBZoKQLNoi0OZGLFgDyFJArJoikNBAlEYsWAAIQKaEWBRYJFgyUMRZFIhcWApRgGaUUMxYjBgIEYAnP/3AP8DmgEhCQZ/GG0cs+cBIQoEs2iTQ7NgCEAHsPC9ABNAQBgAxEHQEQAA/w8AAEggC0AQACAAQACAAAZIAWgFIgJgByIKQARJCWgCYIgEgA9AHHBHwEYAE0BAGADEQREhCQJCGAUjU2ABIkJQAkgBaEkH/NRwR9DjDEAQtQRG//eC/gAoENAJSCAYESEJAmEYACICYEIgSGAGSAhiASAIYCBG//eu/hC9ACAQvcBGEBIAAAAAwEEBSQAiQlBwRxASAAAQtQRG//fs/gMoDNEGSCAYBklhGAAiCmBCIQFgBEnBYSBG//fd/BC9BBEAABASAAAAAMBBELUERv/3FP8AKBDQCUggGBEhCQJhGAAiAmBCIEhgBkgIYgEgCGAgRv/3cP4QvQAgEL3ARhASAAAAAMBBsLURIxsCxBgBJWVgZWIhYhF4IWPFULC9ELUFSwEkxFDDGBxi2WEReNli//eh/BC9BBEAAHC1ESMbAsQYASVlYAMmZmIhYhGIIWPFUHC9wEYQtQZLASTEUMMYAyQcYtlhEYjZYv/3hPwQvcBGBBEAAHC1ESMbAsQYASVlYA8mZmIhYhFoIWPFUHC9wEYQtQZLASTEUMMYDyQcYtlhEWjZYv/3ZvwQvcBGBBEAAHC1ESMbAsQYASVlYP8mZmIhYhFoIWNRaGFjxVBwvcBGELUHSwEkxFDDGP8kHGLZYRFo2WJRaBlj//dE/BC9wEYEEQAAcLURIxsCxBgBJWVg/yYCNmZiIWIReCFjxVBwvRC1BksBJMRQwxj/JAI0HGLZYRF42WL/9yX8EL0EEQAAcLURIxsCxBgBJWVg/yYENmZiIWIRiCFjxVBwvRC1BksBJMRQwxj/JAQ0HGLZYRGI2WL/9wf8EL0EEQAAcLURIxsCxBgBJWVg/yYQNmZiIWIRaCFjxVBwvRC1BksBJMRQwxj/JBA0HGLZYRFo2WL/9+n7EL0EEQAAcLURIxsCxBgBJWVgBE5mYiFiEWghY1FoYWPFUHC9wEb/AQAAELUHSwEkxFDDGAZMHGLZYRFo2WJRaBlj//fG+xC9wEYEEQAA/wEAAPC1ESQkAgUZASZuYP8nAjdvYiliEXgpYxl4AkqBUAZR8L3ARrARAACwtQhMASUFUQQZ/yUCNSVi4WEReOFiGXgDSoFQ//ec+7C9wEYEEQAAsBEAAPC1ESQkAgUZASZuYP8nBDdvYiliEYgpYxl4AkqBUAZR8L3ARrARAACwtQhMASUFUQQZ/yUENSVi4WERiOFiGXgDSoFQ//dy+7C9wEYEEQAAsBEAAPC1ESQkAgUZASZuYP8nEDdvYiliEWgpYxl4AkqBUAZR8L3ARrARAACwtQhMASUFUQQZ/yUQNSVi4WERaOFiGXgDSoFQ//dI+7C9wEYEEQAAsBEAAPC1ESQkAgUZASZuYAVPb2IpYhFoKWNRaGljGXgCSoFQBlHwvf8BAACwEQAAsLUITAElBVEEGQdNJWLhYRFo4WJRaCFjGXgESoFQ//cb+7C9BBEAAP8BAACwEQAA8LWHsB9GBpIFkQRGASEYRgSRCEBBQkFBWh4YRpBBCEARIQkCA5RhGAKRDJkBkQOdAC8f0MEHHdAoRv/30/0oRgWcIUYBmgDwG/gEmQKaUWAKSFBiFGIGnjBoEGNwaFBjEWAINAWUvx4oRv/3jfwINgaW3ecEmQhAB7Dwvf8BAABwtRVGDEYLSUYYIEYA8D75ASGKApVCBNBKApVCCNHACALgPDZgBMAOgUAwaIhDMGBwvcBG1BEAAPi1HEYVRg5GB0YBIdgHAdAIRgDgBCAALADRCEYGmQCRACwQ0MGyASkN0DhGMUYAmv/3yv84RjFGKkb/98X+CDYINaQe7OfAsvi9wEbwtYewBpMEkgORA0YBIQyfOEYCkQhAQUJBQXoeOEaQQQhAGElZGAGRESEJAgWTXBgNmQCRAC8h0MEHH9AFmAOdKUYAmv/3mv8CmmJgDkhgYiViBJ4waCBjcGhgYwaZCHgBmxhgImAINQOVSRwGkb8eBZj/9wf8CDYEltvnApkIQAew8L2wEQAA/wEAAP61ApMVRg5GAZAInwEh+AcB0AhGAOAEIAAvANEIRgmZAJEALxXQwbIBKRLQAZwgRjFGAJr/91z/IEYxRipGApwjRv/3/f4INmQcApQINb8e5+fAsv69/rUfRhRGDUYCRlkeGEaIQREhCQICklYYCJkBkQAvJdDBByPQApgpRgGa//c2/wEgcGABLwvQ/yFxYjViIWgxY2FocWMwYL8eCCECIAfgDyFxYjViIWgxYzBgACcEIW0YgAAkGAKY//ec+9fnASEIQP69+LUfRhRGDUYGRgArAdAEIADgASAGmQCRAC8b0MGyASkY0DBGKUYAmv/3/v4wRilGIkYBLwXQ//d5/b8eCCECIgTg//dT/QAnBCEBIm0YkQBkGOHnwLL4vQNJACJCUEAYQmCCYHBHwEbQEQAAACHJQwJKgVCAGEFggWBwR9ARAAAESQAiQlBAGEJggmACZEJkgmRwR9ARAAAAIclDBEqBUIAYQWCBYAFkQWSBZHBHwEbQEQAAELUERv/3VvwBRgtKEGgFIxNgByMDQAlIAGgTYKQKAikI0wdKEEAA8DX8AUYgRgDwMfwMRiBGEL0AE0BAGADEQf8PAABwtRVGDEYLSUYYIEb/99b/ASGKApVCBNBKApVCCNHACALgPDZgBMAOgUAwaAhDMGBwvcBG1BEAALC1ESMbAsQYAyVlYCFiASFhYhJ4ImPBULC9sLURIxsCxBgDJWVgIWJlYhGIIWMBIcFQsL2wtREjGwLEGAMlZWAhYg8hYWIRaCFjASHBULC9sLURIxsCxBgDJWVgIWL/IWFiEWghY1FoYWMBIcFQsL0QtQZLAyTEUMMYASQcYtlhEXjZYv/3DPkQvcBGBBEAABC1BUsDJMRQwxgcYtlhEYjZYv/3/fgQvQQRAAAQtQZLAyTEUMMYDyQcYtlhEWjZYv/37vgQvcBGBBEAABC1B0sDJMRQwxj/JBxi2WERaNliUWgZY//33PgQvcBGBBEAABC1BksDJMRQwxj/JAI0HGLZYRF42WL/98v4EL0EEQAAELUGSwMkxFDDGP8kBDQcYtlhEYjZYv/3u/gQvQQRAAAQtQZLAyTEUMMY/yQQNBxi2WERaNli//er+BC9BBEAABC1B0sDJMRQwxgGTBxi2WERaNliUWgZY//3mvgQvcBGBBEAAP8BAACwtQhMAyUFUQQZ/yUCNSVi4WEReOFiGXgDSoFQ//eE+LC9wEYEEQAAsBEAALC1CEwDJQVRBBn/JQQ1JWLhYRGI4WIZeANKgVD/9274sL3ARgQRAACwEQAAsLUITAMlBVEEGf8lEDUlYuFhEWjhYhl4A0qBUP/3WPiwvcBGBBEAALARAACwtQhMAyUFUQQZB00lYuFhEWjhYlFoIWMZeARKgVD/90H4sL0EEQAA/wEAALARAACwtREjGwLEGAMlZWAhYv8hAjFhYhF4IWMBIcFQsL2wtREjGwLEGAMlZWAhYv8hBDFhYhGIIWMBIcFQsL2wtREjGwLEGAMlZWAhYv8hEDFhYhFoIWMBIcFQsL3ARrC1ESMbAsQYAyVlYCFiBElhYhFoIWNRaGFjASHBULC9/wEAAHC1ESQkAgUZAyZuYCli/yECMWliEXgpYxl4AkqBUAEhAVFwvbARAABwtREkJAIFGQMmbmApYv8hBDFpYhGIKWMZeAJKgVABIQFRcL2wEQAAcLURJCQCBRkDJm5gKWL/IRAxaWIRaCljGXgCSoFQASEBUXC9sBEAAHC1ESQkAgUZAyZuYCliBklpYhFoKWNRaGljGXgDSoFQASEBUXC9wEb/AQAAsBEAABC1ESISAoMYBiRcYBliASGBUBC9gLUESgYjg1CCGNFh/veU/4C9wEYEEQAAELUTRgRGBEoA8Aj4ESAAAgEhIVAQvcBG//8AALC1B0wRJQVRABkCYsFhGWjBYlloAWOZaEFj2WiBY7C9BBEAABC1E0YERgRK//fo/xEgAAIBISFQEL3ARv//AQCwtR1GE0YERgZK//fZ/yh4BUlgUGAYaXhBYBEgAAIBISFQsL3//wEAsBEAAPC1hbAfRhRGDUYCRhEgAQIAKwHQAy8B2AAgAOABIASSVhgKmQOR/yEQMQKRAZYALzrQwQc40ASYKUYDmv/3WPwBLxDQAy8a2AEgcGACmfAxcWI1YiFoMWNhaHFjMGC/HgghAiIJ4AEicmACmHBiNWIhaDFjMmAAJwQhBJgO4C5GJUYEnCBGMUYqRv/3lf8gRixGNUYBnj8fECEEIm0YkQBkGP/3qfjC5wEhCEAFsPC9/7UBJCICKksZaAOSkUMZYChJDWhtBPzVRX4lQJ5ppkN0GZxhICQEXQMlLEDeaa5DNBncYSBMJWgFJiZgRmo3aB9idmheYgcmLkAmYMRpfyUtAt5prkNkBmQMNBncYQdoRWiCaACSxmgCaQGSQmkCkpppEkwUQDoHEgstA62yqhgyQwCdLQctDRVDAZoVQwKaFUMAfihDCkoCQBAZmGEYaAOaEEMYYAhogAX81f+9wEYIAQtABAILQAATQECNAPD/cv8PALC1/yIEMg5JC2iTQ4J4AyQUQAJ4EgISGRpDCmAJSgpLE2AKTCVobQX81UB4ACgD0AhoECQEQwxgWBwQYLC9wEYUAQtAFAMLQAEAAJEEAgtADEkKaAAoA9ABIIACAkMG4AMggkMKYAEggAIKaIJDCmABIAAFSmgCQ0pgA0gBaIkD/NVwRwABC0AEAgtAASCBAgZKE2iLQxNgAAVRaIFDUWADSAFoiQP81HBHwEYAAQtABAILQAdJiGAHSAJokgL81QEiEgQLaBNDC2ABaMkG/NVwR8BGBAELQAQCC0ABIAAEBEkKaIJDCmADSAFoyQb81HBHwEYEAQtABAILQBC1D0kLaAEik0MLYAMjGwMYQIxonEMgGIhgiGgIIwND9yCDQ4tgCGgQQwhgEAeKaAJDimADSAFoyQX81RC9wEYIAQtABAILQHC1EUsdaAEkpUMdYAMlLQMoQJ5orkMwGJhgmGj/JahDybJAGJhgGGggQxhgmGghBwAqBtAIQ5hgBEgBaMkF/NVwvYhDmGBwvQgBC0AEAgtAsLU/IxsEBEwlaJ1DCEMQQxhAKBggYLC9OAELQAlIAGhABwjUCEhBaMkCBtQAaIAFBdUDIHBHACBwRwIgcEcBIHBHwEYQ7QDgAAELQApJCmwAIAAqANBwRwhKEmhSB/rVCGjABQTUCGiABQPVAyBwRwIgcEcBIHBHAAELQBDtAOAHScprACABKgfRBkoSaFIHA9UIaIACAdUCIHBHASBwRwQBC0AQ7QDgELUISxxrASIiQAjRBkwgQBhgIUBZYNhqBEkBQ9liUEJQQRC9GCALQMD/PwAQAAB2ELUIS5xqASIiQAjRBkwgQBhgIUAZYFhqBEkBQ1liUEJQQRC9ICALQMD/PwBAAAB2ACIDCYtCLNMDCotCEdMAI5xGTuADRgtDPNQAIkMIi0Ix0wMJi0Ic0wMKi0IB05RGP+DDCYtCAdPLAcAaUkGDCYtCAdOLAcAaUkFDCYtCAdNLAcAaUkEDCYtCAdMLAcAaUkHDCItCAdPLAMAaUkGDCItCAdOLAMAaUkFDCItCAdNLAMAaUkFBGgDSAUZSQRBGcEdd4MoPANBJQgMQANNAQlNAnEYAIgMJi0It0wMKi0IS04kB/CISugMKi0IM04kBkhGLQgjTiQGSEYtCBNOJATrQkhEA4IkJwwmLQgHTywHAGlJBgwmLQgHTiwHAGlJBQwmLQgHTSwHAGlJBAwmLQgHTCwHAGlJBwwiLQgHTywDAGlJBgwiLQgHTiwDAGlJB2dJDCItCAdNLAMAaUkFBGgDSAUZSQRBGY0ZbEAHTQEIAKwDVSUJwR2NGWxAA00BCAbUFSQAoAtxJHAhAAOAIRsBGwEYCvQC/////fwAAAAA= - load_address: 0x20200008 - pc_init: 0x1d - pc_uninit: 0x99 - pc_program_page: 0x19d - pc_erase_sector: 0xcd - pc_erase_all: 0x9d - data_section_offset: 0x16e4 - flash_properties: - address_range: - start: 0x0 - end: 0x4000 - page_size: 0x400 - erased_byte_value: 0xff - program_page_timeout: 500 - erase_sector_timeout: 3000 - sectors: - - size: 0x400 - address: 0x0 diff --git a/examples/mspm0l2228/.cargo/config.toml b/examples/mspm0l2228/.cargo/config.toml index 4284749e9..f383afd9e 100644 --- a/examples/mspm0l2228/.cargo/config.toml +++ b/examples/mspm0l2228/.cargo/config.toml @@ -1,7 +1,6 @@ [target.'cfg(all(target_arch = "arm", target_os = "none"))'] # replace MSPM0L2228 with your chip as listed in `probe-rs chip list` -# TODO: Remove description path after new chiptool release -runner = "probe-rs run --restore-unwritten --verify --chip MSPM0L2228 --protocol=swd --chip-description-path ./MSPM0L122X_L222X_Series.yaml" +runner = "probe-rs run --restore-unwritten --verify --chip MSPM0L2228 --protocol=swd" [build] target = "thumbv6m-none-eabi" diff --git a/examples/mspm0l2228/MSPM0L122X_L222X_Series.yaml b/examples/mspm0l2228/MSPM0L122X_L222X_Series.yaml deleted file mode 100644 index ac52fda2e..000000000 --- a/examples/mspm0l2228/MSPM0L122X_L222X_Series.yaml +++ /dev/null @@ -1,239 +0,0 @@ -name: MSPM0L122X_L222X Series -manufacturer: - id: 0x17 - cc: 0x0 -generated_from_pack: true -pack_file_release: 1.1.1 -variants: -- name: MSPM0L1227 - cores: - - name: main - type: armv6m - core_access_options: !Arm - ap: 0 - memory_map: - - !Nvm - name: IROM1 - range: - start: 0x0 - end: 0x20000 - cores: - - main - access: - write: false - boot: true - - !Ram - name: IRAM1 - range: - start: 0x20200000 - end: 0x20208000 - cores: - - main - - !Generic - name: NonMain - range: - start: 0x41c00000 - end: 0x41c00200 - cores: - - main - access: - write: false - execute: false - - !Generic - name: Factory - range: - start: 0x41c40000 - end: 0x41c40080 - cores: - - main - access: - write: false - execute: false - flash_algorithms: - - mspm0l122x_l222x_main_256kb - - mspm0l122x_l222x_nonmain -- name: MSPM0L1228 - cores: - - name: main - type: armv6m - core_access_options: !Arm - ap: 0 - memory_map: - - !Nvm - name: IROM1 - range: - start: 0x0 - end: 0x40000 - cores: - - main - access: - write: false - boot: true - - !Ram - name: IRAM1 - range: - start: 0x20200000 - end: 0x20208000 - cores: - - main - - !Generic - name: NonMain - range: - start: 0x41c00000 - end: 0x41c00200 - cores: - - main - access: - write: false - execute: false - - !Generic - name: Factory - range: - start: 0x41c40000 - end: 0x41c40080 - cores: - - main - access: - write: false - execute: false - flash_algorithms: - - mspm0l122x_l222x_main_256kb - - mspm0l122x_l222x_nonmain -- name: MSPM0L2227 - cores: - - name: main - type: armv6m - core_access_options: !Arm - ap: 0 - memory_map: - - !Nvm - name: IROM1 - range: - start: 0x0 - end: 0x20000 - cores: - - main - access: - write: false - boot: true - - !Ram - name: IRAM1 - range: - start: 0x20200000 - end: 0x20208000 - cores: - - main - - !Generic - name: NonMain - range: - start: 0x41c00000 - end: 0x41c00200 - cores: - - main - access: - write: false - execute: false - - !Generic - name: Factory - range: - start: 0x41c40000 - end: 0x41c40080 - cores: - - main - access: - write: false - execute: false - flash_algorithms: - - mspm0l122x_l222x_main_256kb - - mspm0l122x_l222x_nonmain -- name: MSPM0L2228 - cores: - - name: main - type: armv6m - core_access_options: !Arm - ap: 0 - memory_map: - - !Nvm - name: IROM1 - range: - start: 0x0 - end: 0x40000 - cores: - - main - access: - write: false - boot: true - - !Ram - name: IRAM1 - range: - start: 0x20200000 - end: 0x20208000 - cores: - - main - - !Generic - name: NonMain - range: - start: 0x41c00000 - end: 0x41c00200 - cores: - - main - access: - write: false - execute: false - - !Generic - name: Factory - range: - start: 0x41c40000 - end: 0x41c40080 - cores: - - main - access: - write: false - execute: false - flash_algorithms: - - mspm0l122x_l222x_main_256kb - - mspm0l122x_l222x_nonmain -flash_algorithms: -- name: mspm0l122x_l222x_main_256kb - description: MSPM0L122X_222X MAIN 256KB - default: true - instructions: ESEJAgEiQlADSUEYCmgHIBBABCj60HBH0BMAABC1DEgBaAcikUMBYApMIGgDIYhDIGAB8Hn4YGgPIYhDYGAB8HP4BUgBaAQikUMBYAAgEL0AE0BAAAELQBDtAOAAIHBH/rUERgKpAPA1+AAoB9ACqAB4ASEAKAGRBNCKAgPgASUoRv69SgIQSCFGAPCR/AUnACUPTihGfx4pRmlBwAfv0QAp7dBAIghIIUYA8OH4APAz+AAo79AFIQRKUWABmRFgMWhJB/zU5ucA0AxAAOEMQNDjDEAQtQxKE2gFJBRgByQcQApLG2gUYIIKCUgQQAlKGkCQQgHSACMLcJBCAdMAIBC9ASAQvcBGABNAQBgAxEH/7z8A/w8AAARIAWjJB/zQAGgCIQFASAhwR8BG0OMMQIC1A0gA8Fj5ASFIQIC9wEYA0AxA/rUURg1GBkYCqf/3wf8BIQAoMNAALS7QByAoQCvRAqgBeAEgACkB0IECAOBBAgGRFE8AIQAtHtDABxzQD0gxRgGaAPAT/DhoQAf81AtIMUYiRgDw//oINgg0CD3/97r/ACjm0AUhBkpRYAEhEWA5aEkH/NTd5whG/r3ARgDQDEAA4QxA0OMMQBC1BUwBUQAZACsD0ALKQWBbHvnngGgQvQQRAAAQtQVMAVEAGZpCAtgCykFg+ueAaBC9wEYEEQAAvLUKTAQZAJQAnCGACElBGAArBtAUiAGRAZ0sgJIcWx725wRJQFiAsry9wEYEEQAACBEAAAwRAAC8tQlMBBkAlACcIYAHSUEYmkIF2BSIAZEBnSyAkhz35wNJQFiAsry9BBEAAAgRAAAMEQAAELUCIxNDESISAoQYY2AhYgEhgVAQvcBGgLUCIxNDA0qDUIIY0WH/97P+gL0EEQAAELUERhFIACEhUCAYQWCBYMpDAmQRIAACIhhSI1NgEWIBISFQIEYA8Cn4CUkKaAUjC2AHIxNAB0oSaAtgkQ4E0AAoAtAgRgDwJfgQvdARAAAAE0BAGADEQQNJACJCUEAYQmCCYHBHwEbQEQAAACHJQwFKgVBwR8BGEBIAAARJQBgBaMkH/NAAaAIhAUBICHBH0BMAAIC1CUkAIkJQQRhKYIpgESEJAkIYUiNTYARLE2IBIkJQ//fi/4C9wEbQEQAAAADQQRC1BEYQSAAhIVAgGEFggWDKQwJkDUhSIiJQIBjBYSBG//c8/gpJCmgFIwtgByMTQAhKEmgLYJEOBNABKALQIEYA8Ar4EL3ARtARAAAEEQAAABNAQBgAxEGAtQdJACJCUEEYSmCKYAVJUiJCUEEYBErKYf/3E/6AvdARAAAEEQAAAADQQfC1ibAERgDwk/gFRkFKEGgFIQGREWAHIQCRCEA+SQloEGA+SCAYBJARIAACBpQnGDtICEApRgDwp/4qRoACA5BoCAiQECAHkAAkASYlRjBGBZYCkpVCRNLBB0LQCJiFQgHSACEA4AEhLkgAaEAFMEYA1QhGKQaJDgPR4RUqo1laB5EAKDBGJ9ABIAEEumgKQ7pgHyEJAQeaCkAmRrtoi0OZGLlgDyFJArpoikNBAlEYuWAAIQSaEWBRYJFgyUMRZFIheWApRgOaUUM5YjhgBpj/9zD/ApoFngEhCQZkGG0cuOcBJCEEumiKQ7pgCUsZaAGaGmAAmhFAB0oSaBlgkQ4A0MZD8QcC0QaY//cf/yBACbDwvQATQEAYAMRB0BEAAP8PAABIIAtAEAAgAEAAgAAGSAFoBSICYAciCkAESQloAmCIBIAPQBxwR8BGABNAQBgAxEEQtQRG//eu/gAoENAJSCAYESEJAmEYACICYEIgSGAGSAhiASAIYCBG//fa/hC9ACAQvcBGEBIAAAAAwEEBSQAiQlBwRxASAAAQtQRG//fs/gMoDNEGSCAYBklhGAAiCmBCIQFgBEnBYSBG//cr/RC9BBEAABASAAAAAMBBELUERv/3FP8AKBDQCUggGBEhCQJhGAAiAmBCIEhgBkgIYgEgCGAgRv/3nP4QvQAgEL3ARhASAAAAAMBBsLURIxsCxBgBJWVgZWIhYhF4IWPFULC9ELUFSwEkxFDDGBxi2WEReNli//fv/BC9BBEAAHC1ESMbAsQYASVlYAMmZmIhYhGIIWPFUHC9wEYQtQZLASTEUMMYAyQcYtlhEYjZYv/30vwQvcBGBBEAAHC1ESMbAsQYASVlYA8mZmIhYhFoIWPFUHC9wEYQtQZLASTEUMMYDyQcYtlhEWjZYv/3tPwQvcBGBBEAAHC1ESMbAsQYASVlYP8mZmIhYhFoIWNRaGFjxVBwvcBGELUHSwEkxFDDGP8kHGLZYRFo2WJRaBlj//eS/BC9wEYEEQAAcLURIxsCxBgBJWVg/yYCNmZiIWIReCFjxVBwvRC1BksBJMRQwxj/JAI0HGLZYRF42WL/93P8EL0EEQAAcLURIxsCxBgBJWVg/yYENmZiIWIRiCFjxVBwvRC1BksBJMRQwxj/JAQ0HGLZYRGI2WL/91X8EL0EEQAAcLURIxsCxBgBJWVg/yYQNmZiIWIRaCFjxVBwvRC1BksBJMRQwxj/JBA0HGLZYRFo2WL/9zf8EL0EEQAAcLURIxsCxBgBJWVgBE5mYiFiEWghY1FoYWPFUHC9wEb/AQAAELUHSwEkxFDDGAZMHGLZYRFo2WJRaBlj//cU/BC9wEYEEQAA/wEAAPC1ESQkAgUZASZuYP8nAjdvYiliEXgpYxl4AkqBUAZR8L3ARrARAACwtQhMASUFUQQZ/yUCNSVi4WEReOFiGXgDSoFQ//fq+7C9wEYEEQAAsBEAAPC1ESQkAgUZASZuYP8nBDdvYiliEYgpYxl4AkqBUAZR8L3ARrARAACwtQhMASUFUQQZ/yUENSVi4WERiOFiGXgDSoFQ//fA+7C9wEYEEQAAsBEAAPC1ESQkAgUZASZuYP8nEDdvYiliEWgpYxl4AkqBUAZR8L3ARrARAACwtQhMASUFUQQZ/yUQNSVi4WERaOFiGXgDSoFQ//eW+7C9wEYEEQAAsBEAAPC1ESQkAgUZASZuYAVPb2IpYhFoKWNRaGljGXgCSoFQBlHwvf8BAACwEQAAsLUITAElBVEEGQdNJWLhYRFo4WJRaCFjGXgESoFQ//dp+7C9BBEAAP8BAACwEQAA8LWFsBxGA5ICkQNGASEgRgGRCEBBQkFBYh4gRpBBCEARIQkCBJNfGAqZAJEALBvQwQcZ0ASYAp0pRgCaAPAa+AGZeWAKSHhiPWIDnjBoOGNwaHhjOWAINQKVpB4EmP/3v/wINgOW4ecBmQhABbDwvf8BAAD4tRVGDkYHRghGAPBz+QRG//eq/R5JCmgFIwtgByMTQBxKEmgLYBxJfxixCgEmswKdQg7QcwKdQinRGEsbaNsEDNUCKArTEAVADYFCBdkJGgTgHyABQEA3FeBBGB8pEtn/LAfY//eA/T8dASgA0SA84QgI4DAC/zCEQgjS/yDAQyAYwQgIN45AOGiwQzhg+L0AE0BAGADEQdARAABIIAtA+LUcRhVGDkYHRgEh2AcB0AhGAOAEIAAsANEIRgaZAJEALBDQwbIBKQ3QOEYxRgCa//eW/zhGMUYqRv/3l/4INgg1pB7s58Cy+L3ARvC1h7AGkwSSA5EDRgEhDJ84RgKRCEBBQkFBeh44RpBBCEAYSVkYAZERIQkCBZNcGA2ZAJEALyHQwQcf0AWYA50pRgCa//dm/wKaYmAOSGBiJWIEnjBoIGNwaGBjBpkIeAGbGGAiYAg1A5VJHAaRvx4FmP/3BfwINgSW2+cCmQhAB7DwvbARAAD/AQAA/rUCkxVGDkYBkAifASH4BwHQCEYA4AQgAC8A0QhGCZkAkQAvFdDBsgEpEtABnCBGMUYAmv/3KP8gRjFGKkYCnCNG//fP/gg2ZBwClAg1vx7n58Cy/r3+tR9GFEYNRgJGWR4YRohBESEJAgKSVhgImQGRAC8l0MEHI9ACmClGAZr/9wL/ASBwYAEvC9D/IXFiNWIhaDFjYWhxYzBgvx4IIQIgB+APIXFiNWIhaDFjMGAAJwQhbRiAACQYApj/95r71+cBIQhA/r34tR9GFEYNRgZGACsB0AQgAOABIAaZAJEALxvQwbIBKRjQMEYpRgCa//fK/jBGKUYiRgEvBdD/90v9vx4IIQIiBOD/9yX9ACcEIQEibRiRAGQY4efAsvi9A0kAIkJQQBhCYIJgcEfARtARAAAAIclDAkqBUIAYQWCBYHBH0BEAAARJACJCUEAYQmCCYAJkQmSCZHBH0BEAAAAhyUMESoFQgBhBYIFgAWRBZIFkcEfARtARAAAQtQRG//c2/AFGC0oQaAUjE2AHIwNACUgAaBNgpAoCKQjTB0oQQADwUfoBRiBGAPBN+gxGIEYQvQATQEAYAMRB/w8AAPi1FkYNRgdGCEb/99f/AJD/9w78JUkKaAUjC2AHIxNAI0oSaAtgI0l/GKkKASSjAp5CDtBjAp5CEdEfSxto2wQP1QIoDdMQBUANgUII2QkaB+AfIAFAjEA4bCBDOGT4vUEYHykE2IxAOGggQzhg+L2oDAfR//fc+3loASgP0QCYAB8O4A1IhULp2P8gwEMAmQgYwAiEQLhoIEO4YPi9AJjACIRAIUN5YPi9wEYAE0BAGADEQdARAABIIAtA//sHALC1ESMbAsQYAyVlYCFiASFhYhJ4ImPBULC9sLURIxsCxBgDJWVgIWJlYhGIIWMBIcFQsL2wtREjGwLEGAMlZWAhYg8hYWIRaCFjASHBULC9sLURIxsCxBgDJWVgIWL/IWFiEWghY1FoYWMBIcFQsL0QtQZLAyTEUMMYASQcYtlhEXjZYv/36PgQvcBGBBEAABC1BUsDJMRQwxgcYtlhEYjZYv/32fgQvQQRAAAQtQZLAyTEUMMYDyQcYtlhEWjZYv/3yvgQvcBGBBEAABC1B0sDJMRQwxj/JBxi2WERaNliUWgZY//3uPgQvcBGBBEAABC1BksDJMRQwxj/JAI0HGLZYRF42WL/96f4EL0EEQAAELUGSwMkxFDDGP8kBDQcYtlhEYjZYv/3l/gQvQQRAAAQtQZLAyTEUMMY/yQQNBxi2WERaNli//eH+BC9BBEAABC1B0sDJMRQwxgGTBxi2WERaNliUWgZY//3dvgQvcBGBBEAAP8BAACwtQhMAyUFUQQZ/yUCNSVi4WEReOFiGXgDSoFQ//dg+LC9wEYEEQAAsBEAALC1CEwDJQVRBBn/JQQ1JWLhYRGI4WIZeANKgVD/90r4sL3ARgQRAACwEQAAsLUITAMlBVEEGf8lEDUlYuFhEWjhYhl4A0qBUP/3NPiwvcBGBBEAALARAACwtQhMAyUFUQQZB00lYuFhEWjhYlFoIWMZeARKgVD/9x34sL0EEQAA/wEAALARAACwtREjGwLEGAMlZWAhYv8hAjFhYhF4IWMBIcFQsL2wtREjGwLEGAMlZWAhYv8hBDFhYhGIIWMBIcFQsL2wtREjGwLEGAMlZWAhYv8hEDFhYhFoIWMBIcFQsL3ARrC1ESMbAsQYAyVlYCFiBElhYhFoIWNRaGFjASHBULC9/wEAAHC1ESQkAgUZAyZuYCli/yECMWliEXgpYxl4AkqBUAEhAVFwvbARAABwtREkJAIFGQMmbmApYv8hBDFpYhGIKWMZeAJKgVABIQFRcL2wEQAAcLURJCQCBRkDJm5gKWL/IRAxaWIRaCljGXgCSoFQASEBUXC9sBEAAHC1ESQkAgUZAyZuYCliBklpYhFoKWNRaGljGXgDSoFQASEBUXC9wEb/AQAAsBEAABC1ESISAoMYBiRcYBliASGBUBC9gLUESgYjg1CCGNFh/vdw/4C9wEYEEQAAASCBAgZKE2iLQxNgAAVRaIFDUWADSAFoiQP81HBHwEYAAQtABAILQAEgAAQESQpogkMKYANIAWjJBvzUcEfARgQBC0AEAgtAACIDCYtCLNMDCotCEdMAI5xGTuADRgtDPNQAIkMIi0Ix0wMJi0Ic0wMKi0IB05RGP+DDCYtCAdPLAcAaUkGDCYtCAdOLAcAaUkFDCYtCAdNLAcAaUkEDCYtCAdMLAcAaUkHDCItCAdPLAMAaUkGDCItCAdOLAMAaUkFDCItCAdNLAMAaUkFBGgDSAUZSQRBGcEdd4MoPANBJQgMQANNAQlNAnEYAIgMJi0It0wMKi0IS04kB/CISugMKi0IM04kBkhGLQgjTiQGSEYtCBNOJATrQkhEA4IkJwwmLQgHTywHAGlJBgwmLQgHTiwHAGlJBQwmLQgHTSwHAGlJBAwmLQgHTCwHAGlJBwwiLQgHTywDAGlJBgwiLQgHTiwDAGlJB2dJDCItCAdNLAMAaUkFBGgDSAUZSQRBGY0ZbEAHTQEIAKwDVSUJwR2NGWxAA00BCAbUFSQAoAtxJHAhAAOAIRsBGwEYCvQC/////fwAAAAA= - load_address: 0x20200008 - pc_init: 0x1d - pc_uninit: 0x5d - pc_program_page: 0x145 - pc_erase_sector: 0x61 - pc_erase_all: 0x131 - data_section_offset: 0x12dc - flash_properties: - address_range: - start: 0x0 - end: 0x40000 - page_size: 0x400 - erased_byte_value: 0xff - program_page_timeout: 500 - erase_sector_timeout: 3000 - sectors: - - size: 0x400 - address: 0x0 -- name: mspm0l122x_l222x_nonmain - description: MSPM0L122X_222X NON-MAIN - instructions: ESEJAgEiQlADSUEYCmgHIBBABCj60HBH0BMAABC1EEgBaAcikUMBYA5ID0kBYA9MIGgDIYhDIGAB8KL4YGgPIYhDYGAB8Jz4CUgBaAQikUMBYAhJAiAIYAAgwkNKYBC9ABNAQAAIREABAAAmAAELQBDtAOAAEURAACBwR/61ASGIQwIoPdEAkQAgApDAQwGQH00uIx1MIEYBnzlGKkYA8MH4BkYWIyBGOUYaSgDwuvgERjBGIEMf0ChGAPAx+LghFUp6RC9GKEYA8GD4WCETSnpEEEgA8Fr4AC4D0AKZAykG2RDgASAALAfQApkEKQTSSRwCkT1GzOcCmAAoAJgA0P69ACD+vQCY/r3ARgAAREAAAMBBAAHAQW4SAABAFQAA+LUERkAKFUmIQiPRASAAkIICE0ghRgDwZ/wFJgAlEk8oRnYeKUZpQcAHFNEAKRLQQCILSCFGAPC3+ADwV/gAKO/QBSEHSlFgAJkRYDloSQf81ObnASUoRvi9wEYA4CAAANAMQADhDEDQ4wxA+LUGRkAKASQZS5hCLdEAKSvQByAIQCjRFUYAkQEgF08AJACZACkg0MAHHtABJKICEEgxRgDwIvw4aEAH/NQNSDFGKkYA8A77CDYINQCYCDgAkADwFfgAKOLQBSEGSlFgFGA5aEkH/NTa5yBG+L3ARgDgIAAA0AxAAOEMQNDjDEAESAFoyQf80ABoAiEBQEgIcEfARtDjDEAQtQVMAVEAGQArA9ACykFgWx7554BoEL0EEQAAELUFTAFRABmaQgLYAspBYPrngGgQvcBGBBEAALy1CkwEGQCUAJwhgAhJQRgAKwbQFIgBkQGdLICSHFse9ucESUBYgLK8vcBGBBEAAAgRAAAMEQAAvLUJTAQZAJQAnCGAB0lBGJpCBdgUiAGRAZ0sgJIc9+cDSUBYgLK8vQQRAAAIEQAADBEAABC1AiMTQxEiEgKEGGNgIWIBIYFQEL3ARoC1AiMTQwNKg1CCGNFh//eH/oC9BBEAABC1BEYRSAAhIVAgGEFggWDKQwJkESAAAiIYUiNTYBFiASEhUCBGAPAp+AlJCmgFIwtgByMTQAdKEmgLYJEOBNAAKALQIEYA8CX4EL3QEQAAABNAQBgAxEEDSQAiQlBAGEJggmBwR8BG0BEAAAAhyUMBSoFQcEfARhASAAAESUAYAWjJB/zQAGgCIQFASAhwR9ATAACAtQlJACJCUEEYSmCKYBEhCQJCGFIjU2AESxNiASJCUP/34v+AvcBG0BEAAAAA0EEQtQRGEEgAISFQIBhBYIFgykMCZA1IUiIiUCAYwWEgRv/3EP4KSQpoBSMLYAcjE0AIShJoC2CRDgTQASgC0CBGAPAK+BC9wEbQEQAABBEAAAATQEAYAMRBgLUHSQAiQlBBGEpgimAFSVIiQlBBGARKymH/9+f9gL3QEQAABBEAAAAA0EHwtYmwBEYA8JP4BUZBShBoBSEBkRFgByEAkQhAPkkJaBBgPkggGASQESAAAgaUJxg7SAhAKUYA8Kf+KkaAAgOQaAgIkBAgB5AAJAEmJUYwRgWWApKVQkTSwQdC0AiYhUIB0gAhAOABIS5IAGhABTBGANUIRikGiQ4D0eEVKqNZWgeRACgwRifQASABBLpoCkO6YB8hCQEHmgpAJka7aItDmRi5YA8hSQK6aIpDQQJRGLlgACEEmhFgUWCRYMlDEWRSIXlgKUYDmlFDOWI4YAaY//cw/wKaBZ4BIQkGZBhtHLjnASQhBLpoikO6YAlLGWgBmhpgAJoRQAdKEmgZYJEOANDGQ/EHAtEGmP/3H/8gQAmw8L0AE0BAGADEQdARAAD/DwAASCALQBAAIABAAIAABkgBaAUiAmAHIgpABEkJaAJgiASAD0AccEfARgATQEAYAMRBELUERv/3rv4AKBDQCUggGBEhCQJhGAAiAmBCIEhgBkgIYgEgCGAgRv/32v4QvQAgEL3ARhASAAAAAMBBAUkAIkJQcEcQEgAAELUERv/37P4DKAzRBkggGAZJYRgAIgpgQiEBYARJwWEgRv/3//wQvQQRAAAQEgAAAADAQRC1BEb/9xT/ACgQ0AlIIBgRIQkCYRgAIgJgQiBIYAZICGIBIAhgIEb/95z+EL0AIBC9wEYQEgAAAADAQbC1ESMbAsQYASVlYGViIWIReCFjxVCwvRC1BUsBJMRQwxgcYtlhEXjZYv/3w/wQvQQRAABwtREjGwLEGAElZWADJmZiIWIRiCFjxVBwvcBGELUGSwEkxFDDGAMkHGLZYRGI2WL/96b8EL3ARgQRAABwtREjGwLEGAElZWAPJmZiIWIRaCFjxVBwvcBGELUGSwEkxFDDGA8kHGLZYRFo2WL/94j8EL3ARgQRAABwtREjGwLEGAElZWD/JmZiIWIRaCFjUWhhY8VQcL3ARhC1B0sBJMRQwxj/JBxi2WERaNliUWgZY//3ZvwQvcBGBBEAAHC1ESMbAsQYASVlYP8mAjZmYiFiEXghY8VQcL0QtQZLASTEUMMY/yQCNBxi2WEReNli//dH/BC9BBEAAHC1ESMbAsQYASVlYP8mBDZmYiFiEYghY8VQcL0QtQZLASTEUMMY/yQENBxi2WERiNli//cp/BC9BBEAAHC1ESMbAsQYASVlYP8mEDZmYiFiEWghY8VQcL0QtQZLASTEUMMY/yQQNBxi2WERaNli//cL/BC9BBEAAHC1ESMbAsQYASVlYAROZmIhYhFoIWNRaGFjxVBwvcBG/wEAABC1B0sBJMRQwxgGTBxi2WERaNliUWgZY//36PsQvcBGBBEAAP8BAADwtREkJAIFGQEmbmD/JwI3b2IpYhF4KWMZeAJKgVAGUfC9wEawEQAAsLUITAElBVEEGf8lAjUlYuFhEXjhYhl4A0qBUP/3vvuwvcBGBBEAALARAADwtREkJAIFGQEmbmD/JwQ3b2IpYhGIKWMZeAJKgVAGUfC9wEawEQAAsLUITAElBVEEGf8lBDUlYuFhEYjhYhl4A0qBUP/3lPuwvcBGBBEAALARAADwtREkJAIFGQEmbmD/JxA3b2IpYhFoKWMZeAJKgVAGUfC9wEawEQAAsLUITAElBVEEGf8lEDUlYuFhEWjhYhl4A0qBUP/3avuwvcBGBBEAALARAADwtREkJAIFGQEmbmAFT29iKWIRaCljUWhpYxl4AkqBUAZR8L3/AQAAsBEAALC1CEwBJQVRBBkHTSVi4WERaOFiUWghYxl4BEqBUP/3PfuwvQQRAAD/AQAAsBEAAPC1hbAcRgOSApEDRgEhIEYBkQhAQUJBQWIeIEaQQQhAESEJAgSTXxgKmQCRACwb0MEHGdAEmAKdKUYAmgDwGvgBmXlgCkh4Yj1iA54waDhjcGh4YzlgCDUClaQeBJj/97/8CDYDluHnAZkIQAWw8L3/AQAA+LUVRg5GB0YIRgDwc/kERv/3qv0eSQpoBSMLYAcjE0AcShJoC2AcSX8YsQoBJrMCnUIO0HMCnUIp0RhLG2jbBAzVAigK0xAFQA2BQgXZCRoE4B8gAUBANxXgQRgfKRLZ/ywH2P/3gP0/HQEoANEgPOEICOAwAv8whEII0v8gwEMgGMEICDeOQDhosEM4YPi9ABNAQBgAxEHQEQAASCALQPi1HEYVRg5GB0YBIdgHAdAIRgDgBCAALADRCEYGmQCRACwQ0MGyASkN0DhGMUYAmv/3lv84RjFGKkb/95f+CDYINaQe7OfAsvi9wEbwtYewBpMEkgORA0YBIQyfOEYCkQhAQUJBQXoeOEaQQQhAGElZGAGRESEJAgWTXBgNmQCRAC8h0MEHH9AFmAOdKUYAmv/3Zv8CmmJgDkhgYiViBJ4waCBjcGhgYwaZCHgBmxhgImAINQOVSRwGkb8eBZj/9wX8CDYEltvnApkIQAew8L2wEQAA/wEAAP61ApMVRg5GAZAInwEh+AcB0AhGAOAEIAAvANEIRgmZAJEALxXQwbIBKRLQAZwgRjFGAJr/9yj/IEYxRipGApwjRv/3z/4INmQcApQINb8e5+fAsv69/rUfRhRGDUYCRlkeGEaIQREhCQICklYYCJkBkQAvJdDBByPQApgpRgGa//cC/wEgcGABLwvQ/yFxYjViIWgxY2FocWMwYL8eCCECIAfgDyFxYjViIWgxYzBgACcEIW0YgAAkGAKY//ea+9fnASEIQP69+LUfRhRGDUYGRgArAdAEIADgASAGmQCRAC8b0MGyASkY0DBGKUYAmv/3yv4wRilGIkYBLwXQ//dL/b8eCCECIgTg//cl/QAnBCEBIm0YkQBkGOHnwLL4vQNJACJCUEAYQmCCYHBHwEbQEQAAACHJQwJKgVCAGEFggWBwR9ARAAAESQAiQlBAGEJggmACZEJkgmRwR9ARAAAAIclDBEqBUIAYQWCBYAFkQWSBZHBHwEbQEQAAELUERv/3NvwBRgtKEGgFIxNgByMDQAlIAGgTYKQKAikI0wdKEEAA8FH6AUYgRgDwTfoMRiBGEL0AE0BAGADEQf8PAAD4tRZGDUYHRghG//fX/wCQ//cO/CVJCmgFIwtgByMTQCNKEmgLYCNJfxipCgEkowKeQg7QYwKeQhHRH0sbaNsED9UCKA3TEAVADYFCCNkJGgfgHyABQIxAOGwgQzhk+L1BGB8pBNiMQDhoIEM4YPi9qAwH0f/33Pt5aAEoD9EAmAAfDuANSIVC6dj/IMBDAJkIGMAIhEC4aCBDuGD4vQCYwAiEQCFDeWD4vcBGABNAQBgAxEHQEQAASCALQP/7BwCwtREjGwLEGAMlZWAhYgEhYWISeCJjwVCwvbC1ESMbAsQYAyVlYCFiZWIRiCFjASHBULC9sLURIxsCxBgDJWVgIWIPIWFiEWghYwEhwVCwvbC1ESMbAsQYAyVlYCFi/yFhYhFoIWNRaGFjASHBULC9ELUGSwMkxFDDGAEkHGLZYRF42WL/97z4EL3ARgQRAAAQtQVLAyTEUMMYHGLZYRGI2WL/9634EL0EEQAAELUGSwMkxFDDGA8kHGLZYRFo2WL/9574EL3ARgQRAAAQtQdLAyTEUMMY/yQcYtlhEWjZYlFoGWP/94z4EL3ARgQRAAAQtQZLAyTEUMMY/yQCNBxi2WEReNli//d7+BC9BBEAABC1BksDJMRQwxj/JAQ0HGLZYRGI2WL/92v4EL0EEQAAELUGSwMkxFDDGP8kEDQcYtlhEWjZYv/3W/gQvQQRAAAQtQdLAyTEUMMYBkwcYtlhEWjZYlFoGWP/90r4EL3ARgQRAAD/AQAAsLUITAMlBVEEGf8lAjUlYuFhEXjhYhl4A0qBUP/3NPiwvcBGBBEAALARAACwtQhMAyUFUQQZ/yUENSVi4WERiOFiGXgDSoFQ//ce+LC9wEYEEQAAsBEAALC1CEwDJQVRBBn/JRA1JWLhYRFo4WIZeANKgVD/9wj4sL3ARgQRAACwEQAAsLUITAMlBVEEGQdNJWLhYRFo4WJRaCFjGXgESoFQ/vfx/7C9BBEAAP8BAACwEQAAsLURIxsCxBgDJWVgIWL/IQIxYWIReCFjASHBULC9sLURIxsCxBgDJWVgIWL/IQQxYWIRiCFjASHBULC9sLURIxsCxBgDJWVgIWL/IRAxYWIRaCFjASHBULC9wEawtREjGwLEGAMlZWAhYgRJYWIRaCFjUWhhYwEhwVCwvf8BAABwtREkJAIFGQMmbmApYv8hAjFpYhF4KWMZeAJKgVABIQFRcL2wEQAAcLURJCQCBRkDJm5gKWL/IQQxaWIRiCljGXgCSoFQASEBUXC9sBEAAHC1ESQkAgUZAyZuYCli/yEQMWliEWgpYxl4AkqBUAEhAVFwvbARAABwtREkJAIFGQMmbmApYgZJaWIRaCljUWhpYxl4A0qBUAEhAVFwvcBG/wEAALARAAAQtREiEgKDGAYkXGAZYgEhgVAQvYC1BEoGI4NQghjRYf73RP+AvcBGBBEAAAEggQIGShNoi0MTYAAFUWiBQ1FgA0gBaIkD/NRwR8BGAAELQAQCC0ABIAAEBEkKaIJDCmADSAFoyQb81HBHwEYEAQtABAILQAAiAwmLQizTAwqLQhHTACOcRk7gA0YLQzzUACJDCItCMdMDCYtCHNMDCotCAdOURj/gwwmLQgHTywHAGlJBgwmLQgHTiwHAGlJBQwmLQgHTSwHAGlJBAwmLQgHTCwHAGlJBwwiLQgHTywDAGlJBgwiLQgHTiwDAGlJBQwiLQgHTSwDAGlJBQRoA0gFGUkEQRnBHXeDKDwDQSUIDEADTQEJTQJxGACIDCYtCLdMDCotCEtOJAfwiEroDCotCDNOJAZIRi0II04kBkhGLQgTTiQE60JIRAOCJCcMJi0IB08sBwBpSQYMJi0IB04sBwBpSQUMJi0IB00sBwBpSQQMJi0IB0wsBwBpSQcMIi0IB08sAwBpSQYMIi0IB04sAwBpSQdnSQwiLQgHTSwDAGlJBQRoA0gFGUkEQRmNGWxAB00BCACsA1UlCcEdjRlsQANNAQgG1BUkAKALcSRwIQADgCEbARsBGAr0Av////38CAAABu6q7qruqu6r//////////7uqu6q7qruq//+7qruqu6r///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////+yIGk/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAABoCGQIBAwIDshL//6+WE3YPcmNfvbRKWgpjw58SrzD5UKbuXJcb4YjonEBR/////////////////////////////////////////////0gA0UsBbwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= - load_address: 0x20200008 - pc_init: 0x1d - pc_uninit: 0x7d - pc_program_page: 0x18d - pc_erase_sector: 0x121 - pc_erase_all: 0x79 - data_section_offset: 0x1774 - flash_properties: - address_range: - start: 0x41c00000 - end: 0x41c00200 - page_size: 0x40 - erased_byte_value: 0xff - program_page_timeout: 500 - erase_sector_timeout: 3000 - sectors: - - size: 0x200 - address: 0x0 From 2195156b584cf3675002ee94e274c15fe60808b8 Mon Sep 17 00:00:00 2001 From: i509VCB Date: Sat, 15 Mar 2025 13:44:28 -0500 Subject: [PATCH 0822/1217] Add mspm0 chips to CI which have working int_group implementations Not all of these have been done yet, as I need to go through each datasheet and manually declare all interrupt groups for mspm0-metapac to then generate. --- ci.sh | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/ci.sh b/ci.sh index e32105b16..84312127f 100755 --- a/ci.sh +++ b/ci.sh @@ -170,6 +170,11 @@ cargo batch \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32u073mb,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32u083rc,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-nxp/Cargo.toml --target thumbv8m.main-none-eabihf \ + --- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0c110x,defmt,time-driver-any \ + --- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0g350x,defmt,time-driver-any \ + --- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0g351x,defmt,time-driver-any \ + --- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0l130x,defmt,time-driver-any \ + --- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0l222x,defmt,time-driver-any \ --- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features ''\ --- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'log' \ --- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'defmt' \ @@ -239,6 +244,11 @@ cargo batch \ --- build --release --manifest-path examples/stm32wba/Cargo.toml --target thumbv8m.main-none-eabihf --artifact-dir out/examples/stm32wba \ --- build --release --manifest-path examples/stm32wl/Cargo.toml --target thumbv7em-none-eabi --artifact-dir out/examples/stm32wl \ --- build --release --manifest-path examples/lpc55s69/Cargo.toml --target thumbv8m.main-none-eabihf --artifact-dir out/examples/lpc55s69 \ + --- build --release --manifest-path examples/mspm0c1104/Cargo.toml --target thumbv6m-none-eabi --artifact-dir out/examples/mspm0c1104 \ + --- build --release --manifest-path examples/mspm0g3507/Cargo.toml --target thumbv6m-none-eabi --artifact-dir out/examples/mspm0g3507 \ + --- build --release --manifest-path examples/mspm0g3519/Cargo.toml --target thumbv6m-none-eabi --artifact-dir out/examples/mspm0g3519 \ + --- build --release --manifest-path examples/mspm0l1306/Cargo.toml --target thumbv6m-none-eabi --artifact-dir out/examples/mspm0l1306 \ + --- build --release --manifest-path examples/mspm0l2228/Cargo.toml --target thumbv6m-none-eabi --artifact-dir out/examples/mspm0l2228 \ --- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840,skip-include --artifact-dir out/examples/boot/nrf52840 \ --- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9160-ns,skip-include --artifact-dir out/examples/boot/nrf9160 \ --- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9120-ns,skip-include --artifact-dir out/examples/boot/nrf9120 \ From 7336ca549e17d899471cb96a5106dd6836a40eea Mon Sep 17 00:00:00 2001 From: i509VCB Date: Sat, 15 Mar 2025 13:50:58 -0500 Subject: [PATCH 0823/1217] build C1104 with --release C1104 only has 1KB of ram, so we must build in release --- ci.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci.sh b/ci.sh index 84312127f..62e406f2c 100755 --- a/ci.sh +++ b/ci.sh @@ -244,7 +244,7 @@ cargo batch \ --- build --release --manifest-path examples/stm32wba/Cargo.toml --target thumbv8m.main-none-eabihf --artifact-dir out/examples/stm32wba \ --- build --release --manifest-path examples/stm32wl/Cargo.toml --target thumbv7em-none-eabi --artifact-dir out/examples/stm32wl \ --- build --release --manifest-path examples/lpc55s69/Cargo.toml --target thumbv8m.main-none-eabihf --artifact-dir out/examples/lpc55s69 \ - --- build --release --manifest-path examples/mspm0c1104/Cargo.toml --target thumbv6m-none-eabi --artifact-dir out/examples/mspm0c1104 \ + --- build --release --manifest-path examples/mspm0c1104/Cargo.toml --target thumbv6m-none-eabi --artifact-dir out/examples/mspm0c1104 --release \ --- build --release --manifest-path examples/mspm0g3507/Cargo.toml --target thumbv6m-none-eabi --artifact-dir out/examples/mspm0g3507 \ --- build --release --manifest-path examples/mspm0g3519/Cargo.toml --target thumbv6m-none-eabi --artifact-dir out/examples/mspm0g3519 \ --- build --release --manifest-path examples/mspm0l1306/Cargo.toml --target thumbv6m-none-eabi --artifact-dir out/examples/mspm0l1306 \ From 0642c3a7feb4f221c87f805d8e69f5a75f045248 Mon Sep 17 00:00:00 2001 From: i509VCB Date: Sat, 15 Mar 2025 13:51:43 -0500 Subject: [PATCH 0824/1217] Revert "build C1104 with --release" This reverts commit 7336ca549e17d899471cb96a5106dd6836a40eea. --- ci.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci.sh b/ci.sh index 62e406f2c..84312127f 100755 --- a/ci.sh +++ b/ci.sh @@ -244,7 +244,7 @@ cargo batch \ --- build --release --manifest-path examples/stm32wba/Cargo.toml --target thumbv8m.main-none-eabihf --artifact-dir out/examples/stm32wba \ --- build --release --manifest-path examples/stm32wl/Cargo.toml --target thumbv7em-none-eabi --artifact-dir out/examples/stm32wl \ --- build --release --manifest-path examples/lpc55s69/Cargo.toml --target thumbv8m.main-none-eabihf --artifact-dir out/examples/lpc55s69 \ - --- build --release --manifest-path examples/mspm0c1104/Cargo.toml --target thumbv6m-none-eabi --artifact-dir out/examples/mspm0c1104 --release \ + --- build --release --manifest-path examples/mspm0c1104/Cargo.toml --target thumbv6m-none-eabi --artifact-dir out/examples/mspm0c1104 \ --- build --release --manifest-path examples/mspm0g3507/Cargo.toml --target thumbv6m-none-eabi --artifact-dir out/examples/mspm0g3507 \ --- build --release --manifest-path examples/mspm0g3519/Cargo.toml --target thumbv6m-none-eabi --artifact-dir out/examples/mspm0g3519 \ --- build --release --manifest-path examples/mspm0l1306/Cargo.toml --target thumbv6m-none-eabi --artifact-dir out/examples/mspm0l1306 \ From 1dd129693318e15aa15cb50243c5be6547aa5159 Mon Sep 17 00:00:00 2001 From: i509VCB Date: Sat, 15 Mar 2025 13:56:23 -0500 Subject: [PATCH 0825/1217] more aggressive debug level for CI? --- examples/mspm0c1104/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/mspm0c1104/Cargo.toml b/examples/mspm0c1104/Cargo.toml index 35c9b1358..a56086e2a 100644 --- a/examples/mspm0c1104/Cargo.toml +++ b/examples/mspm0c1104/Cargo.toml @@ -19,14 +19,14 @@ panic-semihosting = "0.6.0" # The chip only has 1KB of ram, so we must optimize binaries regardless [profile.dev] -debug = 2 +debug = 1 opt-level = "z" lto = true codegen-units = 1 # strip = true [profile.release] -debug = 2 +debug = 1 opt-level = "z" lto = true codegen-units = 1 From c5b3cc5f4796f721cac502485dd21875d0e1cc4e Mon Sep 17 00:00:00 2001 From: i509VCB Date: Sat, 15 Mar 2025 13:58:07 -0500 Subject: [PATCH 0826/1217] How about debug=0 for c1104? --- examples/mspm0c1104/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/mspm0c1104/Cargo.toml b/examples/mspm0c1104/Cargo.toml index a56086e2a..3996939a5 100644 --- a/examples/mspm0c1104/Cargo.toml +++ b/examples/mspm0c1104/Cargo.toml @@ -19,14 +19,14 @@ panic-semihosting = "0.6.0" # The chip only has 1KB of ram, so we must optimize binaries regardless [profile.dev] -debug = 1 +debug = 0 opt-level = "z" lto = true codegen-units = 1 # strip = true [profile.release] -debug = 1 +debug = 0 opt-level = "z" lto = true codegen-units = 1 From 0b468ef29cc67e05aae01031604b746b1f21ffcd Mon Sep 17 00:00:00 2001 From: elagil Date: Sat, 15 Mar 2025 20:16:20 +0100 Subject: [PATCH 0827/1217] fix: iso out order --- embassy-stm32/src/usb/usb.rs | 75 ++++++++++++++++++------------------ 1 file changed, 37 insertions(+), 38 deletions(-) diff --git a/embassy-stm32/src/usb/usb.rs b/embassy-stm32/src/usb/usb.rs index 31ab8f76d..cb97169ee 100644 --- a/embassy-stm32/src/usb/usb.rs +++ b/embassy-stm32/src/usb/usb.rs @@ -83,7 +83,7 @@ impl interrupt::typelevel::Handler for InterruptHandl let mut epr = regs.epr(index).read(); if epr.ctr_rx() { - CTR_RX_TRIGGERED[index].store(true, Ordering::Relaxed); + RX_COMPLETE[index].store(true, Ordering::Relaxed); if index == 0 && epr.setup() { EP0_SETUP.store(true, Ordering::Relaxed); } @@ -91,7 +91,7 @@ impl interrupt::typelevel::Handler for InterruptHandl EP_OUT_WAKERS[index].wake(); } if epr.ctr_tx() { - CTR_TX_TRIGGERED[index].store(true, Ordering::Relaxed); + TX_PENDING[index].store(false, Ordering::Relaxed); //trace!("EP {} TX", index); EP_IN_WAKERS[index].wake(); } @@ -123,8 +123,8 @@ const USBRAM_ALIGN: usize = 4; static BUS_WAKER: AtomicWaker = AtomicWaker::new(); static EP0_SETUP: AtomicBool = AtomicBool::new(false); -static CTR_TX_TRIGGERED: [AtomicBool; EP_COUNT] = [const { AtomicBool::new(false) }; EP_COUNT]; -static CTR_RX_TRIGGERED: [AtomicBool; EP_COUNT] = [const { AtomicBool::new(false) }; EP_COUNT]; +static TX_PENDING: [AtomicBool; EP_COUNT] = [const { AtomicBool::new(false) }; EP_COUNT]; +static RX_COMPLETE: [AtomicBool; EP_COUNT] = [const { AtomicBool::new(false) }; EP_COUNT]; static EP_IN_WAKERS: [AtomicWaker; EP_COUNT] = [const { AtomicWaker::new() }; EP_COUNT]; static EP_OUT_WAKERS: [AtomicWaker; EP_COUNT] = [const { AtomicWaker::new() }; EP_COUNT]; static IRQ_RESET: AtomicBool = AtomicBool::new(false); @@ -417,10 +417,10 @@ impl<'d, T: Instance> Driver<'d, T> { let addr = self.alloc_ep_mem(len); // ep_in_len is written when actually TXing packets. - btable::write_in_tx::(index, addr); + btable::write_in_len_tx::(index, addr, 0); if ep_type == EndpointType::Isochronous { - btable::write_in_rx::(index, addr); + btable::write_in_len_rx::(index, addr, 0); } EndpointBuffer { @@ -719,6 +719,7 @@ impl Dir for Out { /// For double-buffered endpoints, both the `Rx` and `Tx` buffer from a channel are used for the same /// direction of transfer. This is opposed to single-buffered endpoints, where one channel can serve /// two directions at the same time. +#[derive(Clone, Copy, Debug)] enum PacketBuffer { /// The RX buffer - must be used for single-buffered OUT endpoints Rx, @@ -843,7 +844,7 @@ impl<'d, T: Instance> driver::EndpointOut for Endpoint<'d, T, Out> { if self.info.ep_type == EndpointType::Isochronous { // The isochronous endpoint does not change its `STAT_RX` field to `NAK` when receiving a packet. // Therefore, this instead waits until the `CTR` interrupt was triggered. - if matches!(stat, Stat::DISABLED) || CTR_RX_TRIGGERED[index].load(Ordering::Relaxed) { + if matches!(stat, Stat::DISABLED) || RX_COMPLETE[index].load(Ordering::Relaxed) { assert!(matches!(stat, Stat::VALID | Stat::DISABLED)); Poll::Ready(stat) } else { @@ -859,7 +860,7 @@ impl<'d, T: Instance> driver::EndpointOut for Endpoint<'d, T, Out> { }) .await; - CTR_RX_TRIGGERED[index].store(false, Ordering::Relaxed); + RX_COMPLETE[index].store(false, Ordering::Relaxed); if stat == Stat::DISABLED { return Err(EndpointError::Disabled); @@ -870,9 +871,9 @@ impl<'d, T: Instance> driver::EndpointOut for Endpoint<'d, T, Out> { let packet_buffer = if self.info.ep_type == EndpointType::Isochronous { // Find the buffer, which is currently in use. Read from the OTHER buffer. if regs.epr(index).read().dtog_rx() { - PacketBuffer::Rx - } else { PacketBuffer::Tx + } else { + PacketBuffer::Rx } } else { PacketBuffer::Rx @@ -904,7 +905,21 @@ impl<'d, T: Instance> driver::EndpointIn for Endpoint<'d, T, In> { return Err(EndpointError::BufferOverflow); } trace!("WRITE WAITING, buf.len() = {}", buf.len()); + + let regs = T::regs(); let index = self.info.addr.index(); + + if self.info.ep_type == EndpointType::Isochronous { + // Find the buffer, which is currently in use. Write to the OTHER buffer. + let packet_buffer = if regs.epr(index).read().dtog_tx() { + PacketBuffer::Rx + } else { + PacketBuffer::Tx + }; + + self.write_data_double_buffered(buf, packet_buffer); + } + let stat = poll_fn(|cx| { EP_IN_WAKERS[index].register(cx.waker()); let regs = T::regs(); @@ -912,7 +927,7 @@ impl<'d, T: Instance> driver::EndpointIn for Endpoint<'d, T, In> { if self.info.ep_type == EndpointType::Isochronous { // The isochronous endpoint does not change its `STAT_TX` field to `NAK` after sending a packet. // Therefore, this instead waits until the `CTR` interrupt was triggered. - if matches!(stat, Stat::DISABLED) || CTR_TX_TRIGGERED[index].load(Ordering::Relaxed) { + if matches!(stat, Stat::DISABLED) || !TX_PENDING[index].load(Ordering::Relaxed) { assert!(matches!(stat, Stat::VALID | Stat::DISABLED)); Poll::Ready(stat) } else { @@ -928,39 +943,23 @@ impl<'d, T: Instance> driver::EndpointIn for Endpoint<'d, T, In> { }) .await; - CTR_TX_TRIGGERED[index].store(false, Ordering::Relaxed); - if stat == Stat::DISABLED { return Err(EndpointError::Disabled); } - let regs = T::regs(); + if self.info.ep_type != EndpointType::Isochronous { + self.write_data(buf); - let packet_buffer = if self.info.ep_type == EndpointType::Isochronous { - // Find the buffer, which is currently in use. Write to the OTHER buffer. - if regs.epr(index).read().dtog_tx() { - PacketBuffer::Tx - } else { - PacketBuffer::Rx - } - } else { - PacketBuffer::Tx - }; - - self.write_data_double_buffered(buf, packet_buffer); - - regs.epr(index).write(|w| { - w.set_ep_type(convert_type(self.info.ep_type)); - w.set_ea(self.info.addr.index() as _); - if self.info.ep_type == EndpointType::Isochronous { - w.set_stat_tx(Stat::from_bits(0)); // STAT_TX remains `VALID`. - } else { + regs.epr(index).write(|w| { + w.set_ep_type(convert_type(self.info.ep_type)); + w.set_ea(self.info.addr.index() as _); w.set_stat_tx(Stat::from_bits(Stat::NAK.to_bits() ^ Stat::VALID.to_bits())); - } - w.set_stat_rx(Stat::from_bits(0)); - w.set_ctr_rx(true); // don't clear - w.set_ctr_tx(true); // don't clear - }); + w.set_stat_rx(Stat::from_bits(0)); + w.set_ctr_rx(true); // don't clear + w.set_ctr_tx(true); // don't clear + }); + } + TX_PENDING[index].store(true, Ordering::Relaxed); trace!("WRITE OK"); Ok(()) From 8fef488738531b419565c35185dd82553ff52a80 Mon Sep 17 00:00:00 2001 From: elagil Date: Sat, 15 Mar 2025 20:24:02 +0100 Subject: [PATCH 0828/1217] refactor: USB read function restructure --- embassy-stm32/src/usb/usb.rs | 33 ++++++++++++++------------------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/embassy-stm32/src/usb/usb.rs b/embassy-stm32/src/usb/usb.rs index cb97169ee..4675b3f1a 100644 --- a/embassy-stm32/src/usb/usb.rs +++ b/embassy-stm32/src/usb/usb.rs @@ -868,31 +868,26 @@ impl<'d, T: Instance> driver::EndpointOut for Endpoint<'d, T, Out> { let regs = T::regs(); - let packet_buffer = if self.info.ep_type == EndpointType::Isochronous { + let rx_len = if self.info.ep_type == EndpointType::Isochronous { // Find the buffer, which is currently in use. Read from the OTHER buffer. - if regs.epr(index).read().dtog_rx() { + let packet_buffer = if regs.epr(index).read().dtog_rx() { PacketBuffer::Tx } else { PacketBuffer::Rx - } + }; + self.read_data_double_buffered(buf, packet_buffer)? } else { - PacketBuffer::Rx - }; - - let rx_len = self.read_data_double_buffered(buf, packet_buffer)?; - - regs.epr(index).write(|w| { - w.set_ep_type(convert_type(self.info.ep_type)); - w.set_ea(self.info.addr.index() as _); - if self.info.ep_type == EndpointType::Isochronous { - w.set_stat_rx(Stat::from_bits(0)); // STAT_RX remains `VALID`. - } else { + regs.epr(index).write(|w| { + w.set_ep_type(convert_type(self.info.ep_type)); + w.set_ea(self.info.addr.index() as _); w.set_stat_rx(Stat::from_bits(Stat::NAK.to_bits() ^ Stat::VALID.to_bits())); - } - w.set_stat_tx(Stat::from_bits(0)); - w.set_ctr_rx(true); // don't clear - w.set_ctr_tx(true); // don't clear - }); + w.set_stat_tx(Stat::from_bits(0)); + w.set_ctr_rx(true); // don't clear + w.set_ctr_tx(true); // don't clear + }); + + self.read_data(buf)? + }; trace!("READ OK, rx_len = {}", rx_len); Ok(rx_len) From 0ff618472397ef6d506afe879900a27014218f81 Mon Sep 17 00:00:00 2001 From: elagil Date: Sat, 15 Mar 2025 20:28:15 +0100 Subject: [PATCH 0829/1217] refactor: fix build warnings --- embassy-stm32/src/usb/usb.rs | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/embassy-stm32/src/usb/usb.rs b/embassy-stm32/src/usb/usb.rs index 4675b3f1a..c00c88215 100644 --- a/embassy-stm32/src/usb/usb.rs +++ b/embassy-stm32/src/usb/usb.rs @@ -206,10 +206,6 @@ mod btable { mod btable { use super::*; - pub(super) fn write_in_tx(_index: usize, _addr: u16) {} - - pub(super) fn write_in_rx(_index: usize, _addr: u16) {} - pub(super) fn write_in_len_tx(index: usize, addr: u16, len: u16) { assert_eq!(addr & 0b11, 0); USBRAM.mem(index * 2).write_value((addr as u32) | ((len as u32) << 16)); @@ -416,11 +412,23 @@ impl<'d, T: Instance> Driver<'d, T> { let len = align_len_up(max_packet_size); let addr = self.alloc_ep_mem(len); - // ep_in_len is written when actually TXing packets. - btable::write_in_len_tx::(index, addr, 0); + #[cfg(not(any(usbram_32_2048, usbram_32_1024)))] + { + // ep_in_len is written when actually transmitting packets. + btable::write_in_tx::(index, addr); - if ep_type == EndpointType::Isochronous { - btable::write_in_len_rx::(index, addr, 0); + if ep_type == EndpointType::Isochronous { + btable::write_in_rx::(index, addr); + } + } + + #[cfg(any(usbram_32_2048, usbram_32_1024))] + { + btable::write_in_len_tx::(index, addr, 0); + + if ep_type == EndpointType::Isochronous { + btable::write_in_len_rx::(index, addr, 0); + } } EndpointBuffer { From cecbe082ff5505b69cd4cc7138a4275d7af4aa8a Mon Sep 17 00:00:00 2001 From: elagil Date: Sun, 16 Mar 2025 16:34:09 +0100 Subject: [PATCH 0830/1217] fix: only ISO EP is always double buffered --- embassy-stm32/src/usb/usb.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/usb/usb.rs b/embassy-stm32/src/usb/usb.rs index c00c88215..8dabfc78f 100644 --- a/embassy-stm32/src/usb/usb.rs +++ b/embassy-stm32/src/usb/usb.rs @@ -363,10 +363,11 @@ impl<'d, T: Instance> Driver<'d, T> { return false; // reserved for control pipe } let used = ep.used_out || ep.used_in; - if used && (ep.ep_type == EndpointType::Isochronous || ep.ep_type == EndpointType::Bulk) { - // Isochronous and bulk endpoints are double-buffered. + if used && (ep.ep_type == EndpointType::Isochronous) { + // Isochronous endpoints are always double-buffered. // Their corresponding endpoint/channel registers are forced to be unidirectional. // Do not reuse this index. + // FIXME: Bulk endpoints can be double buffered, but are not in the current implementation. return false; } From f7f316ad179a1812ffa3f10869165bafc99d515e Mon Sep 17 00:00:00 2001 From: i509VCB Date: Sun, 16 Mar 2025 13:52:12 -0500 Subject: [PATCH 0831/1217] correct group 0 int_group accesses --- embassy-mspm0/src/int_group/c110x.rs | 2 +- embassy-mspm0/src/int_group/g350x.rs | 2 +- embassy-mspm0/src/int_group/g351x.rs | 2 +- embassy-mspm0/src/int_group/l130x.rs | 2 +- embassy-mspm0/src/int_group/l222x.rs | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/embassy-mspm0/src/int_group/c110x.rs b/embassy-mspm0/src/int_group/c110x.rs index c503af631..e6a9ddb99 100644 --- a/embassy-mspm0/src/int_group/c110x.rs +++ b/embassy-mspm0/src/int_group/c110x.rs @@ -6,7 +6,7 @@ use crate::pac::interrupt; fn GROUP0() { use mspm0_metapac::Group0; - let group = pac::CPUSS.int_group(1); + let group = pac::CPUSS.int_group(0); // TODO: Decompose to direct u8 let iidx = group.iidx().read().stat().to_bits(); diff --git a/embassy-mspm0/src/int_group/g350x.rs b/embassy-mspm0/src/int_group/g350x.rs index 818dd6e1e..706ba2078 100644 --- a/embassy-mspm0/src/int_group/g350x.rs +++ b/embassy-mspm0/src/int_group/g350x.rs @@ -6,7 +6,7 @@ use crate::pac::interrupt; fn GROUP0() { use mspm0_metapac::Group0; - let group = pac::CPUSS.int_group(1); + let group = pac::CPUSS.int_group(0); // Must subtract by 1 since NO_INTR is value 0 let iidx = group.iidx().read().stat().to_bits() - 1; diff --git a/embassy-mspm0/src/int_group/g351x.rs b/embassy-mspm0/src/int_group/g351x.rs index b43e0a9db..e785018a7 100644 --- a/embassy-mspm0/src/int_group/g351x.rs +++ b/embassy-mspm0/src/int_group/g351x.rs @@ -6,7 +6,7 @@ use crate::pac::interrupt; fn GROUP0() { use mspm0_metapac::Group0; - let group = pac::CPUSS.int_group(1); + let group = pac::CPUSS.int_group(0); // Must subtract by 1 since NO_INTR is value 0 let iidx = group.iidx().read().stat().to_bits() - 1; diff --git a/embassy-mspm0/src/int_group/l130x.rs b/embassy-mspm0/src/int_group/l130x.rs index 6d033cc56..8be5adcad 100644 --- a/embassy-mspm0/src/int_group/l130x.rs +++ b/embassy-mspm0/src/int_group/l130x.rs @@ -6,7 +6,7 @@ use crate::pac::interrupt; fn GROUP0() { use mspm0_metapac::Group0; - let group = pac::CPUSS.int_group(1); + let group = pac::CPUSS.int_group(0); // Must subtract by 1 since NO_INTR is value 0 let iidx = group.iidx().read().stat().to_bits() - 1; diff --git a/embassy-mspm0/src/int_group/l222x.rs b/embassy-mspm0/src/int_group/l222x.rs index 703e16e78..eeb2ce70d 100644 --- a/embassy-mspm0/src/int_group/l222x.rs +++ b/embassy-mspm0/src/int_group/l222x.rs @@ -6,7 +6,7 @@ use crate::pac::interrupt; fn GROUP0() { use mspm0_metapac::Group0; - let group = pac::CPUSS.int_group(1); + let group = pac::CPUSS.int_group(0); // Must subtract by 1 since NO_INTR is value 0 let iidx = group.iidx().read().stat().to_bits() - 1; From e557ca96065592d5ab6c11c0498a4dee32672635 Mon Sep 17 00:00:00 2001 From: Alix ANNERAUD Date: Sun, 16 Mar 2025 21:45:25 +0100 Subject: [PATCH 0832/1217] Remove blocking read-write lock module and its references and refactor rwlock for a simpler approach --- embassy-sync/src/blocking_rwlock/mod.rs | 221 ------------------------ embassy-sync/src/blocking_rwlock/raw.rs | 209 ---------------------- embassy-sync/src/lib.rs | 1 - embassy-sync/src/rwlock.rs | 157 ++++++----------- 4 files changed, 52 insertions(+), 536 deletions(-) delete mode 100644 embassy-sync/src/blocking_rwlock/mod.rs delete mode 100644 embassy-sync/src/blocking_rwlock/raw.rs diff --git a/embassy-sync/src/blocking_rwlock/mod.rs b/embassy-sync/src/blocking_rwlock/mod.rs deleted file mode 100644 index 88cd2164b..000000000 --- a/embassy-sync/src/blocking_rwlock/mod.rs +++ /dev/null @@ -1,221 +0,0 @@ -//! Blocking read-write lock. -//! -//! This module provides a blocking read-write lock that can be used to synchronize data. -pub mod raw; - -use core::cell::UnsafeCell; - -use self::raw::RawRwLock; - -/// Blocking read-write lock (not async) -/// -/// Provides a blocking read-write lock primitive backed by an implementation of [`raw::RawRwLock`]. -/// -/// Which implementation you select depends on the context in which you're using the read-write lock, and you can choose which kind -/// of interior mutability fits your use case. -/// -/// Use [`CriticalSectionRwLock`] when data can be shared between threads and interrupts. -/// -/// Use [`NoopRwLock`] when data is only shared between tasks running on the same executor. -/// -/// Use [`ThreadModeRwLock`] when data is shared between tasks running on the same executor but you want a global singleton. -/// -/// In all cases, the blocking read-write lock is intended to be short lived and not held across await points. -/// Use the async [`RwLock`](crate::rwlock::RwLock) if you need a lock that is held across await points. -pub struct RwLock { - // NOTE: `raw` must be FIRST, so when using ThreadModeRwLock the "can't drop in non-thread-mode" gets - // to run BEFORE dropping `data`. - raw: R, - data: UnsafeCell, -} - -unsafe impl Send for RwLock {} -unsafe impl Sync for RwLock {} - -impl RwLock { - /// Creates a new read-write lock in an unlocked state ready for use. - #[inline] - pub const fn new(val: T) -> RwLock { - RwLock { - raw: R::INIT, - data: UnsafeCell::new(val), - } - } - - /// Creates a critical section and grants temporary read access to the protected data. - pub fn read_lock(&self, f: impl FnOnce(&T) -> U) -> U { - self.raw.read_lock(|| { - let ptr = self.data.get() as *const T; - let inner = unsafe { &*ptr }; - f(inner) - }) - } - - /// Creates a critical section and grants temporary write access to the protected data. - pub fn write_lock(&self, f: impl FnOnce(&mut T) -> U) -> U { - self.raw.write_lock(|| { - let ptr = self.data.get() as *mut T; - let inner = unsafe { &mut *ptr }; - f(inner) - }) - } -} - -impl RwLock { - /// Creates a new read-write lock based on a pre-existing raw read-write lock. - /// - /// This allows creating a read-write lock in a constant context on stable Rust. - #[inline] - pub const fn const_new(raw_rwlock: R, val: T) -> RwLock { - RwLock { - raw: raw_rwlock, - data: UnsafeCell::new(val), - } - } - - /// Consumes this read-write lock, returning the underlying data. - #[inline] - pub fn into_inner(self) -> T { - self.data.into_inner() - } - - /// Returns a mutable reference to the underlying data. - /// - /// Since this call borrows the `RwLock` mutably, no actual locking needs to - /// take place---the mutable borrow statically guarantees no locks exist. - #[inline] - pub fn get_mut(&mut self) -> &mut T { - unsafe { &mut *self.data.get() } - } -} - -/// A read-write lock that allows borrowing data across executors and interrupts. -/// -/// # Safety -/// -/// This read-write lock is safe to share between different executors and interrupts. -pub type CriticalSectionRwLock = RwLock; - -/// A read-write lock that allows borrowing data in the context of a single executor. -/// -/// # Safety -/// -/// **This Read-Write Lock is only safe within a single executor.** -pub type NoopRwLock = RwLock; - -impl RwLock { - /// Borrows the data for the duration of the critical section - pub fn borrow<'cs>(&'cs self, _cs: critical_section::CriticalSection<'cs>) -> &'cs T { - let ptr = self.data.get() as *const T; - unsafe { &*ptr } - } -} - -impl RwLock { - /// Borrows the data - #[allow(clippy::should_implement_trait)] - pub fn borrow(&self) -> &T { - let ptr = self.data.get() as *const T; - unsafe { &*ptr } - } -} - -// ThreadModeRwLock does NOT use the generic read-write lock from above because it's special: -// it's Send+Sync even if T: !Send. There's no way to do that without specialization (I think?). -// -// There's still a ThreadModeRawRwLock for use with the generic RwLock (handy with Channel, for example), -// but that will require T: Send even though it shouldn't be needed. - -#[cfg(any(cortex_m, feature = "std"))] -pub use thread_mode_rwlock::*; -#[cfg(any(cortex_m, feature = "std"))] -mod thread_mode_rwlock { - use super::*; - - /// A "read-write lock" that only allows borrowing from thread mode. - /// - /// # Safety - /// - /// **This Read-Write Lock is only safe on single-core systems.** - /// - /// On multi-core systems, a `ThreadModeRwLock` **is not sufficient** to ensure exclusive access. - pub struct ThreadModeRwLock { - inner: UnsafeCell, - } - - // NOTE: ThreadModeRwLock only allows borrowing from one execution context ever: thread mode. - // Therefore it cannot be used to send non-sendable stuff between execution contexts, so it can - // be Send+Sync even if T is not Send (unlike CriticalSectionRwLock) - unsafe impl Sync for ThreadModeRwLock {} - unsafe impl Send for ThreadModeRwLock {} - - impl ThreadModeRwLock { - /// Creates a new read-write lock - pub const fn new(value: T) -> Self { - ThreadModeRwLock { - inner: UnsafeCell::new(value), - } - } - } - - impl ThreadModeRwLock { - /// Lock the `ThreadModeRwLock` for reading, granting access to the data. - /// - /// # Panics - /// - /// This will panic if not currently running in thread mode. - pub fn read_lock(&self, f: impl FnOnce(&T) -> R) -> R { - f(self.borrow()) - } - - /// Lock the `ThreadModeRwLock` for writing, granting access to the data. - /// - /// # Panics - /// - /// This will panic if not currently running in thread mode. - pub fn write_lock(&self, f: impl FnOnce(&mut T) -> R) -> R { - f(self.borrow_mut()) - } - - /// Borrows the data - /// - /// # Panics - /// - /// This will panic if not currently running in thread mode. - pub fn borrow(&self) -> &T { - assert!( - raw::in_thread_mode(), - "ThreadModeRwLock can only be borrowed from thread mode." - ); - unsafe { &*self.inner.get() } - } - - /// Mutably borrows the data - /// - /// # Panics - /// - /// This will panic if not currently running in thread mode. - pub fn borrow_mut(&self) -> &mut T { - assert!( - raw::in_thread_mode(), - "ThreadModeRwLock can only be borrowed from thread mode." - ); - unsafe { &mut *self.inner.get() } - } - } - - impl Drop for ThreadModeRwLock { - fn drop(&mut self) { - // Only allow dropping from thread mode. Dropping calls drop on the inner `T`, so - // `drop` needs the same guarantees as `lock`. `ThreadModeRwLock` is Send even if - // T isn't, so without this check a user could create a ThreadModeRwLock in thread mode, - // send it to interrupt context and drop it there, which would "send" a T even if T is not Send. - assert!( - raw::in_thread_mode(), - "ThreadModeRwLock can only be dropped from thread mode." - ); - - // Drop of the inner `T` happens after this. - } - } -} diff --git a/embassy-sync/src/blocking_rwlock/raw.rs b/embassy-sync/src/blocking_rwlock/raw.rs deleted file mode 100644 index 2fb9ce9d1..000000000 --- a/embassy-sync/src/blocking_rwlock/raw.rs +++ /dev/null @@ -1,209 +0,0 @@ -//! Read-Write Lock primitives. -//! -//! This module provides a trait for read-write locks that can be used in different contexts. -use core::cell::RefCell; -use core::marker::PhantomData; - -/// Raw read-write lock trait. -/// -/// This read-write lock is "raw", which means it does not actually contain the protected data, it -/// just implements the read-write lock mechanism. For most uses you should use [`super::RwLock`] instead, -/// which is generic over a RawRwLock and contains the protected data. -/// -/// Note that, unlike other read-write locks, implementations only guarantee no -/// concurrent access from other threads: concurrent access from the current -/// thread is allowed. For example, it's possible to lock the same read-write lock multiple times reentrantly. -/// -/// Therefore, locking a `RawRwLock` is only enough to guarantee safe shared (`&`) access -/// to the data, it is not enough to guarantee exclusive (`&mut`) access. -/// -/// # Safety -/// -/// RawRwLock implementations must ensure that, while locked, no other thread can lock -/// the RawRwLock concurrently. -/// -/// Unsafe code is allowed to rely on this fact, so incorrect implementations will cause undefined behavior. -pub unsafe trait RawRwLock { - /// Create a new `RawRwLock` instance. - /// - /// This is a const instead of a method to allow creating instances in const context. - const INIT: Self; - - /// Lock this `RawRwLock` for reading. - fn read_lock(&self, f: impl FnOnce() -> R) -> R; - - /// Lock this `RawRwLock` for writing. - fn write_lock(&self, f: impl FnOnce() -> R) -> R; -} - -/// A read-write lock that allows borrowing data across executors and interrupts. -/// -/// # Safety -/// -/// This read-write lock is safe to share between different executors and interrupts. -pub struct CriticalSectionRawRwLock { - state: RefCell, -} - -unsafe impl Send for CriticalSectionRawRwLock {} -unsafe impl Sync for CriticalSectionRawRwLock {} - -impl CriticalSectionRawRwLock { - /// Creates a new [`CriticalSectionRawRwLock`]. - pub const fn new() -> Self { - Self { state: RefCell::new(0) } - } - - fn lock_read(&self) { - critical_section::with(|_| { - let mut state = self.state.borrow_mut(); - - while *state & WRITER != 0 { - // Spin until the writer releases the lock - } - *state += 1; - }); - } - - fn unlock_read(&self) { - critical_section::with(|_| { - *self.state.borrow_mut() -= 1; - }); - } - - fn lock_write(&self) { - critical_section::with(|_| { - let mut state = self.state.borrow_mut(); - - while *state != 0 { - // Spin until all readers and writers release the lock - } - *state = WRITER; - }); - } - - fn unlock_write(&self) { - critical_section::with(|_| { - *self.state.borrow_mut() = 0; - }); - } -} - -unsafe impl RawRwLock for CriticalSectionRawRwLock { - const INIT: Self = Self::new(); - - fn read_lock(&self, f: impl FnOnce() -> R) -> R { - self.lock_read(); - let result = f(); - self.unlock_read(); - result - } - - fn write_lock(&self, f: impl FnOnce() -> R) -> R { - self.lock_write(); - let result = f(); - self.unlock_write(); - result - } -} - -const WRITER: isize = -1; - -// ================ - -/// A read-write lock that allows borrowing data in the context of a single executor. -/// -/// # Safety -/// -/// **This Read-Write Lock is only safe within a single executor.** -pub struct NoopRawRwLock { - _phantom: PhantomData<*mut ()>, -} - -unsafe impl Send for NoopRawRwLock {} - -impl NoopRawRwLock { - /// Create a new `NoopRawRwLock`. - pub const fn new() -> Self { - Self { _phantom: PhantomData } - } -} - -unsafe impl RawRwLock for NoopRawRwLock { - const INIT: Self = Self::new(); - fn read_lock(&self, f: impl FnOnce() -> R) -> R { - f() - } - - fn write_lock(&self, f: impl FnOnce() -> R) -> R { - f() - } -} - -// ================ - -#[cfg(any(cortex_m, feature = "std"))] -mod thread_mode { - use super::*; - - /// A "read-write lock" that only allows borrowing from thread mode. - /// - /// # Safety - /// - /// **This Read-Write Lock is only safe on single-core systems.** - /// - /// On multi-core systems, a `ThreadModeRawRwLock` **is not sufficient** to ensure exclusive access. - pub struct ThreadModeRawRwLock { - _phantom: PhantomData<()>, - } - - unsafe impl Send for ThreadModeRawRwLock {} - unsafe impl Sync for ThreadModeRawRwLock {} - - impl ThreadModeRawRwLock { - /// Create a new `ThreadModeRawRwLock`. - pub const fn new() -> Self { - Self { _phantom: PhantomData } - } - } - - unsafe impl RawRwLock for ThreadModeRawRwLock { - const INIT: Self = Self::new(); - fn read_lock(&self, f: impl FnOnce() -> R) -> R { - assert!( - in_thread_mode(), - "ThreadModeRwLock can only be locked from thread mode." - ); - - f() - } - - fn write_lock(&self, f: impl FnOnce() -> R) -> R { - assert!( - in_thread_mode(), - "ThreadModeRwLock can only be locked from thread mode." - ); - - f() - } - } - - impl Drop for ThreadModeRawRwLock { - fn drop(&mut self) { - assert!( - in_thread_mode(), - "ThreadModeRwLock can only be dropped from thread mode." - ); - } - } - - pub(crate) fn in_thread_mode() -> bool { - #[cfg(feature = "std")] - return Some("main") == std::thread::current().name(); - - #[cfg(not(feature = "std"))] - return unsafe { (0xE000ED04 as *const u32).read_volatile() } & 0x1FF == 0; - } -} -#[cfg(any(cortex_m, feature = "std"))] -pub use thread_mode::*; diff --git a/embassy-sync/src/lib.rs b/embassy-sync/src/lib.rs index b9ead5f79..5d91b4d9c 100644 --- a/embassy-sync/src/lib.rs +++ b/embassy-sync/src/lib.rs @@ -11,7 +11,6 @@ pub(crate) mod fmt; mod ring_buffer; pub mod blocking_mutex; -pub mod blocking_rwlock; pub mod channel; pub mod lazy_lock; pub mod mutex; diff --git a/embassy-sync/src/rwlock.rs b/embassy-sync/src/rwlock.rs index 0ad5d5864..0e4088c1e 100644 --- a/embassy-sync/src/rwlock.rs +++ b/embassy-sync/src/rwlock.rs @@ -7,8 +7,8 @@ use core::future::{poll_fn, Future}; use core::ops::{Deref, DerefMut}; use core::task::Poll; -use crate::blocking_rwlock::raw::RawRwLock; -use crate::blocking_rwlock::RwLock as BlockingRwLock; +use crate::blocking_mutex::raw::RawMutex; +use crate::blocking_mutex::Mutex as BlockingMutex; use crate::waitqueue::WakerRegistration; /// Error returned by [`RwLock::try_read_lock`] and [`RwLock::try_write_lock`] @@ -31,53 +31,48 @@ struct State { /// /// Which implementation you select depends on the context in which you're using the read-write lock. /// -/// Use [`CriticalSectionRawRwLock`](crate::blocking_mutex::raw_rwlock::CriticalSectionRawRwLock) when data can be shared between threads and interrupts. +/// Use [`CriticalSectionMutex`] when data can be shared between threads and interrupts. /// -/// Use [`NoopRawRwLock`](crate::blocking_mutex::raw_rwlock::NoopRawRwLock) when data is only shared between tasks running on the same executor. +/// Use [`NoopMutex`] when data is only shared between tasks running on the same executor. /// -/// Use [`ThreadModeRawRwLock`](crate::blocking_mutex::raw_rwlock::ThreadModeRawRwLock) when data is shared between tasks running on the same executor but you want a singleton. +/// Use [`ThreadModeMutex`] when data is shared between tasks running on the same executor but you want a global singleton. /// -pub struct RwLock + +pub struct RwLock where - R: RawRwLock, + M: RawMutex, T: ?Sized, { - state: BlockingRwLock>, + state: BlockingMutex>, inner: UnsafeCell, } -unsafe impl Send for RwLock {} -unsafe impl Sync for RwLock {} +unsafe impl Send for RwLock {} +unsafe impl Sync for RwLock {} /// Async read-write lock. impl RwLock where - R: RawRwLock, + R: RawMutex, { /// Create a new read-write lock with the given value. pub const fn new(value: T) -> Self { Self { inner: UnsafeCell::new(value), - state: BlockingRwLock::new(RefCell::new(State { + state: BlockingMutex::new(RefCell::new(State { readers: 0, writer: false, waker: WakerRegistration::new(), })), } } -} -impl RwLock -where - R: RawRwLock, - T: ?Sized, -{ /// Lock the read-write lock for reading. /// /// This will wait for the lock to be available if it's already locked for writing. - pub fn read_lock(&self) -> impl Future> { + pub fn read(&self) -> impl Future> { poll_fn(|cx| { - let ready = self.state.write_lock(|s| { + let ready = self.state.lock(|s| { let mut s = s.borrow_mut(); if s.writer { s.waker.register(cx.waker()); @@ -99,11 +94,11 @@ where /// Lock the read-write lock for writing. /// /// This will wait for the lock to be available if it's already locked for reading or writing. - pub fn write_lock(&self) -> impl Future> { + pub fn write(&self) -> impl Future> { poll_fn(|cx| { - let ready = self.state.write_lock(|s| { + let ready = self.state.lock(|s| { let mut s = s.borrow_mut(); - if s.readers > 0 || s.writer { + if s.writer || s.readers > 0 { s.waker.register(cx.waker()); false } else { @@ -119,41 +114,13 @@ where } }) } +} - /// Attempt to immediately lock the read-write lock for reading. - /// - /// If the lock is already locked for writing, this will return an error instead of waiting. - pub fn try_read_lock(&self) -> Result, TryLockError> { - self.state.read_lock(|s| { - let mut s = s.borrow_mut(); - if s.writer { - Err(TryLockError) - } else { - s.readers += 1; - Ok(()) - } - })?; - - Ok(RwLockReadGuard { rwlock: self }) - } - - /// Attempt to immediately lock the read-write lock for writing. - /// - /// If the lock is already locked for reading or writing, this will return an error instead of waiting. - pub fn try_write_lock(&self) -> Result, TryLockError> { - self.state.write_lock(|s| { - let mut s = s.borrow_mut(); - if s.readers > 0 || s.writer { - Err(TryLockError) - } else { - s.writer = true; - Ok(()) - } - })?; - - Ok(RwLockWriteGuard { rwlock: self }) - } - +impl RwLock +where + R: RawMutex, + T: ?Sized, +{ /// Consumes this read-write lock, returning the underlying data. pub fn into_inner(self) -> T where @@ -171,7 +138,7 @@ where } } -impl From for RwLock { +impl From for RwLock { fn from(from: T) -> Self { Self::new(from) } @@ -179,7 +146,7 @@ impl From for RwLock { impl Default for RwLock where - R: RawRwLock, + R: RawMutex, T: Default, { fn default() -> Self { @@ -187,26 +154,6 @@ where } } -impl fmt::Debug for RwLock -where - R: RawRwLock, - T: ?Sized + fmt::Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let mut d = f.debug_struct("RwLock"); - match self.try_write_lock() { - Ok(value) => { - d.field("inner", &&*value); - } - Err(TryLockError) => { - d.field("inner", &format_args!("")); - } - } - - d.finish_non_exhaustive() - } -} - /// Async read lock guard. /// /// Owning an instance of this type indicates having @@ -217,19 +164,19 @@ where #[must_use = "if unused the RwLock will immediately unlock"] pub struct RwLockReadGuard<'a, R, T> where - R: RawRwLock, + R: RawMutex, T: ?Sized, { rwlock: &'a RwLock, } -impl<'a, R, T> Drop for RwLockReadGuard<'a, R, T> +impl<'a, M, T> Drop for RwLockReadGuard<'a, M, T> where - R: RawRwLock, + M: RawMutex, T: ?Sized, { fn drop(&mut self) { - self.rwlock.state.write_lock(|s| { + self.rwlock.state.lock(|s| { let mut s = unwrap!(s.try_borrow_mut()); s.readers -= 1; if s.readers == 0 { @@ -239,9 +186,9 @@ where } } -impl<'a, R, T> Deref for RwLockReadGuard<'a, R, T> +impl<'a, M, T> Deref for RwLockReadGuard<'a, M, T> where - R: RawRwLock, + M: RawMutex, T: ?Sized, { type Target = T; @@ -252,9 +199,9 @@ where } } -impl<'a, R, T> fmt::Debug for RwLockReadGuard<'a, R, T> +impl<'a, M, T> fmt::Debug for RwLockReadGuard<'a, M, T> where - R: RawRwLock, + M: RawMutex, T: ?Sized + fmt::Debug, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -262,9 +209,9 @@ where } } -impl<'a, R, T> fmt::Display for RwLockReadGuard<'a, R, T> +impl<'a, M, T> fmt::Display for RwLockReadGuard<'a, M, T> where - R: RawRwLock, + M: RawMutex, T: ?Sized + fmt::Display, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -282,7 +229,7 @@ where #[must_use = "if unused the RwLock will immediately unlock"] pub struct RwLockWriteGuard<'a, R, T> where - R: RawRwLock, + R: RawMutex, T: ?Sized, { rwlock: &'a RwLock, @@ -290,11 +237,11 @@ where impl<'a, R, T> Drop for RwLockWriteGuard<'a, R, T> where - R: RawRwLock, + R: RawMutex, T: ?Sized, { fn drop(&mut self) { - self.rwlock.state.write_lock(|s| { + self.rwlock.state.lock(|s| { let mut s = unwrap!(s.try_borrow_mut()); s.writer = false; s.waker.wake(); @@ -304,7 +251,7 @@ where impl<'a, R, T> Deref for RwLockWriteGuard<'a, R, T> where - R: RawRwLock, + R: RawMutex, T: ?Sized, { type Target = T; @@ -317,7 +264,7 @@ where impl<'a, R, T> DerefMut for RwLockWriteGuard<'a, R, T> where - R: RawRwLock, + R: RawMutex, T: ?Sized, { fn deref_mut(&mut self) -> &mut Self::Target { @@ -329,7 +276,7 @@ where impl<'a, R, T> fmt::Debug for RwLockWriteGuard<'a, R, T> where - R: RawRwLock, + R: RawMutex, T: ?Sized + fmt::Debug, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -339,7 +286,7 @@ where impl<'a, R, T> fmt::Display for RwLockWriteGuard<'a, R, T> where - R: RawRwLock, + R: RawMutex, T: ?Sized + fmt::Display, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -349,41 +296,41 @@ where #[cfg(test)] mod tests { - use crate::blocking_rwlock::raw::NoopRawRwLock; + use crate::blocking_mutex::raw::NoopRawMutex; use crate::rwlock::RwLock; #[futures_test::test] async fn read_guard_releases_lock_when_dropped() { - let rwlock: RwLock = RwLock::new([0, 1]); + let rwlock: RwLock = RwLock::new([0, 1]); { - let guard = rwlock.read_lock().await; + let guard = rwlock.read().await; assert_eq!(*guard, [0, 1]); } { - let guard = rwlock.read_lock().await; + let guard = rwlock.read().await; assert_eq!(*guard, [0, 1]); } - assert_eq!(*rwlock.read_lock().await, [0, 1]); + assert_eq!(*rwlock.read().await, [0, 1]); } #[futures_test::test] async fn write_guard_releases_lock_when_dropped() { - let rwlock: RwLock = RwLock::new([0, 1]); + let rwlock: RwLock = RwLock::new([0, 1]); { - let mut guard = rwlock.write_lock().await; + let mut guard = rwlock.write().await; assert_eq!(*guard, [0, 1]); guard[1] = 2; } { - let guard = rwlock.read_lock().await; + let guard = rwlock.read().await; assert_eq!(*guard, [0, 2]); } - assert_eq!(*rwlock.read_lock().await, [0, 2]); + assert_eq!(*rwlock.read().await, [0, 2]); } } From 63f7a5da09b150de5077c02c5b1394af4d012676 Mon Sep 17 00:00:00 2001 From: elagil Date: Sun, 16 Mar 2025 22:02:43 +0100 Subject: [PATCH 0833/1217] fix: disable `new_with_sof` for STM32L1 --- embassy-stm32/src/usb/usb.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/embassy-stm32/src/usb/usb.rs b/embassy-stm32/src/usb/usb.rs index af639fc9b..64ab3b669 100644 --- a/embassy-stm32/src/usb/usb.rs +++ b/embassy-stm32/src/usb/usb.rs @@ -288,6 +288,7 @@ pub struct Driver<'d, T: Instance> { impl<'d, T: Instance> Driver<'d, T> { /// Create a new USB driver with start-of-frame (SOF) output. + #[cfg(not(stm32l1))] pub fn new_with_sof( _usb: impl Peripheral

+ 'd, _irq: impl interrupt::typelevel::Binding> + 'd, @@ -296,13 +297,10 @@ impl<'d, T: Instance> Driver<'d, T> { sof: impl Peripheral

> + 'd, ) -> Self { into_ref!(sof); - #[cfg(not(stm32l1))] { use crate::gpio::{AfType, OutputType, Speed}; sof.set_as_af(sof.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh)); } - #[cfg(stm32l1)] - let _ = sof; // suppress "unused" warning. Self::new(_usb, _irq, dp, dm) } From e3b0581a876069fde325c82a14efc23f7cd6ad81 Mon Sep 17 00:00:00 2001 From: Murmele Date: Mon, 17 Mar 2025 11:04:04 +0100 Subject: [PATCH 0834/1217] Fix comment --- embassy-executor/src/spawner.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-executor/src/spawner.rs b/embassy-executor/src/spawner.rs index fdd3ce002..9817a2870 100644 --- a/embassy-executor/src/spawner.rs +++ b/embassy-executor/src/spawner.rs @@ -34,7 +34,7 @@ impl SpawnToken { } } - /// Returns the task if available, otherwise 0 + /// Returns the task id if available, otherwise 0 /// This can be used in combination with rtos-trace to match task names with id's pub fn id(&self) -> u32 { match self.raw_task { From 41276de34fdc30ebb1c73d9aa3f1664cd7a26345 Mon Sep 17 00:00:00 2001 From: Alix ANNERAUD Date: Mon, 17 Mar 2025 19:56:17 +0100 Subject: [PATCH 0835/1217] Refactor RwLock implementation to support try_read and try_write methods, enhancing lock acquisition flexibility --- embassy-sync/src/rwlock.rs | 270 ++++++++++++++++++++++++++++++++++--- 1 file changed, 253 insertions(+), 17 deletions(-) diff --git a/embassy-sync/src/rwlock.rs b/embassy-sync/src/rwlock.rs index 0e4088c1e..7f0bbec60 100644 --- a/embassy-sync/src/rwlock.rs +++ b/embassy-sync/src/rwlock.rs @@ -2,10 +2,10 @@ //! //! This module provides a read-write lock that can be used to synchronize data between asynchronous tasks. use core::cell::{RefCell, UnsafeCell}; -use core::fmt; use core::future::{poll_fn, Future}; use core::ops::{Deref, DerefMut}; use core::task::Poll; +use core::{fmt, mem}; use crate::blocking_mutex::raw::RawMutex; use crate::blocking_mutex::Mutex as BlockingMutex; @@ -31,11 +31,11 @@ struct State { /// /// Which implementation you select depends on the context in which you're using the read-write lock. /// -/// Use [`CriticalSectionMutex`] when data can be shared between threads and interrupts. +/// Use [`CriticalSectionRawMutex`](crate::blocking_mutex::raw::CriticalSectionRawMutex) when data can be shared between threads and interrupts. /// -/// Use [`NoopMutex`] when data is only shared between tasks running on the same executor. +/// Use [`NoopRawMutex`](crate::blocking_mutex::raw::NoopRawMutex) when data is only shared between tasks running on the same executor. /// -/// Use [`ThreadModeMutex`] when data is shared between tasks running on the same executor but you want a global singleton. +/// Use [`ThreadModeRawMutex`](crate::blocking_mutex::raw::ThreadModeRawMutex) when data is shared between tasks running on the same executor but you want a singleton. /// pub struct RwLock @@ -51,9 +51,9 @@ unsafe impl Send for RwLock {} unsafe impl Sync for RwLock {} /// Async read-write lock. -impl RwLock +impl RwLock where - R: RawMutex, + M: RawMutex, { /// Create a new read-write lock with the given value. pub const fn new(value: T) -> Self { @@ -66,11 +66,17 @@ where })), } } +} +impl RwLock +where + M: RawMutex, + T: ?Sized, +{ /// Lock the read-write lock for reading. /// /// This will wait for the lock to be available if it's already locked for writing. - pub fn read(&self) -> impl Future> { + pub fn read(&self) -> impl Future> { poll_fn(|cx| { let ready = self.state.lock(|s| { let mut s = s.borrow_mut(); @@ -94,7 +100,7 @@ where /// Lock the read-write lock for writing. /// /// This will wait for the lock to be available if it's already locked for reading or writing. - pub fn write(&self) -> impl Future> { + pub fn write(&self) -> impl Future> { poll_fn(|cx| { let ready = self.state.lock(|s| { let mut s = s.borrow_mut(); @@ -114,13 +120,43 @@ where } }) } -} -impl RwLock -where - R: RawMutex, - T: ?Sized, -{ + /// Attempt to immediately lock the rwlock. + /// + /// If the rwlock is already locked, this will return an error instead of waiting. + pub fn try_read(&self) -> Result, TryLockError> { + self.state + .lock(|s| { + let mut s = s.borrow_mut(); + if s.writer { + return Err(()); + } + s.readers += 1; + Ok(()) + }) + .map_err(|_| TryLockError)?; + + Ok(RwLockReadGuard { rwlock: self }) + } + + /// Attempt to immediately lock the rwlock. + /// + /// If the rwlock is already locked, this will return an error instead of waiting. + pub fn try_write(&self) -> Result, TryLockError> { + self.state + .lock(|s| { + let mut s = s.borrow_mut(); + if s.writer || s.readers > 0 { + return Err(()); + } + s.writer = true; + Ok(()) + }) + .map_err(|_| TryLockError)?; + + Ok(RwLockWriteGuard { rwlock: self }) + } + /// Consumes this read-write lock, returning the underlying data. pub fn into_inner(self) -> T where @@ -138,15 +174,15 @@ where } } -impl From for RwLock { +impl From for RwLock { fn from(from: T) -> Self { Self::new(from) } } -impl Default for RwLock +impl Default for RwLock where - R: RawMutex, + M: RawMutex, T: Default, { fn default() -> Self { @@ -154,6 +190,21 @@ where } } +impl fmt::Debug for RwLock +where + M: RawMutex, + T: ?Sized + fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut d = f.debug_struct("RwLock"); + match self.try_read() { + Ok(guard) => d.field("inner", &&*guard), + Err(TryLockError) => d.field("inner", &"Locked"), + } + .finish_non_exhaustive() + } +} + /// Async read lock guard. /// /// Owning an instance of this type indicates having @@ -170,6 +221,27 @@ where rwlock: &'a RwLock, } +impl<'a, M, T> RwLockReadGuard<'a, M, T> +where + M: RawMutex, + T: ?Sized, +{ + /// Map the contents of the `RwLockReadGuard` to a different type. + /// + /// This is useful for calling methods on the contents of the `RwLockReadGuard` without + /// moving out of the guard. + pub fn map(this: Self, fun: impl FnOnce(&T) -> &U) -> MappedRwLockReadGuard<'a, M, U> { + let rwlock = this.rwlock; + let value = fun(unsafe { &mut *this.rwlock.inner.get() }); + + mem::forget(this); + MappedRwLockReadGuard { + state: &rwlock.state, + value, + } + } +} + impl<'a, M, T> Drop for RwLockReadGuard<'a, M, T> where M: RawMutex, @@ -294,6 +366,170 @@ where } } +/// A handle to a held `Mutex` that has had a function applied to it via [`MutexGuard::map`] or +/// [`MappedMutexGuard::map`]. +/// +/// This can be used to hold a subfield of the protected data. +#[clippy::has_significant_drop] +pub struct MappedRwLockReadGuard<'a, M, T> +where + M: RawMutex, + T: ?Sized, +{ + state: &'a BlockingMutex>, + value: *const T, +} + +impl<'a, M, T> Deref for MappedRwLockReadGuard<'a, M, T> +where + M: RawMutex, + T: ?Sized, +{ + type Target = T; + fn deref(&self) -> &Self::Target { + // Safety: the MappedRwLockReadGuard represents shared access to the contents + // of the read-write lock, so it's OK to get it. + unsafe { &*self.value } + } +} + +impl<'a, M, T> Drop for MappedRwLockReadGuard<'a, M, T> +where + M: RawMutex, + T: ?Sized, +{ + fn drop(&mut self) { + self.state.lock(|s| { + let mut s = unwrap!(s.try_borrow_mut()); + s.readers -= 1; + if s.readers == 0 { + s.waker.wake(); + } + }) + } +} + +unsafe impl<'a, M, T> Send for MappedRwLockReadGuard<'a, M, T> +where + M: RawMutex, + T: ?Sized, +{ +} + +unsafe impl<'a, M, T> Sync for MappedRwLockReadGuard<'a, M, T> +where + M: RawMutex, + T: ?Sized, +{ +} + +impl<'a, M, T> fmt::Debug for MappedRwLockReadGuard<'a, M, T> +where + M: RawMutex, + T: ?Sized + fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&**self, f) + } +} + +impl<'a, M, T> fmt::Display for MappedRwLockReadGuard<'a, M, T> +where + M: RawMutex, + T: ?Sized + fmt::Display, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(&**self, f) + } +} + +/// A handle to a held `Mutex` that has had a function applied to it via [`MutexGuard::map`] or +/// [`MappedMutexGuard::map`]. +/// +/// This can be used to hold a subfield of the protected data. +#[clippy::has_significant_drop] +pub struct MappedRwLockWriteGuard<'a, M, T> +where + M: RawMutex, + T: ?Sized, +{ + state: &'a BlockingMutex>, + value: *mut T, +} + +impl<'a, M, T> Deref for MappedRwLockWriteGuard<'a, M, T> +where + M: RawMutex, + T: ?Sized, +{ + type Target = T; + fn deref(&self) -> &Self::Target { + // Safety: the MappedRwLockWriteGuard represents exclusive access to the contents + // of the read-write lock, so it's OK to get it. + unsafe { &*self.value } + } +} + +impl<'a, M, T> DerefMut for MappedRwLockWriteGuard<'a, M, T> +where + M: RawMutex, + T: ?Sized, +{ + fn deref_mut(&mut self) -> &mut Self::Target { + // Safety: the MappedRwLockWriteGuard represents exclusive access to the contents + // of the read-write lock, so it's OK to get it. + unsafe { &mut *self.value } + } +} + +impl<'a, M, T> Drop for MappedRwLockWriteGuard<'a, M, T> +where + M: RawMutex, + T: ?Sized, +{ + fn drop(&mut self) { + self.state.lock(|s| { + let mut s = unwrap!(s.try_borrow_mut()); + s.writer = false; + s.waker.wake(); + }) + } +} + +unsafe impl<'a, M, T> Send for MappedRwLockWriteGuard<'a, M, T> +where + M: RawMutex, + T: ?Sized, +{ +} + +unsafe impl<'a, M, T> Sync for MappedRwLockWriteGuard<'a, M, T> +where + M: RawMutex, + T: ?Sized, +{ +} + +impl<'a, M, T> fmt::Debug for MappedRwLockWriteGuard<'a, M, T> +where + M: RawMutex, + T: ?Sized + fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&**self, f) + } +} + +impl<'a, M, T> fmt::Display for MappedRwLockWriteGuard<'a, M, T> +where + M: RawMutex, + T: ?Sized + fmt::Display, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(&**self, f) + } +} + #[cfg(test)] mod tests { use crate::blocking_mutex::raw::NoopRawMutex; From bce15cc813f0fec7eaac1cb709706fb0f4c5e3b8 Mon Sep 17 00:00:00 2001 From: Alix ANNERAUD Date: Mon, 17 Mar 2025 20:03:36 +0100 Subject: [PATCH 0836/1217] Enhance RwLock documentation and add map methods for read and write guards to improve data access flexibility --- embassy-sync/src/rwlock.rs | 63 ++++++++++++++++++++++++++++++++++---- 1 file changed, 57 insertions(+), 6 deletions(-) diff --git a/embassy-sync/src/rwlock.rs b/embassy-sync/src/rwlock.rs index 7f0bbec60..25c575925 100644 --- a/embassy-sync/src/rwlock.rs +++ b/embassy-sync/src/rwlock.rs @@ -11,7 +11,7 @@ use crate::blocking_mutex::raw::RawMutex; use crate::blocking_mutex::Mutex as BlockingMutex; use crate::waitqueue::WakerRegistration; -/// Error returned by [`RwLock::try_read_lock`] and [`RwLock::try_write_lock`] +/// Error returned by [`RwLock::try_read`] and [`RwLock::try_write`] when the lock is already held. #[derive(PartialEq, Eq, Clone, Copy, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct TryLockError; @@ -24,7 +24,7 @@ struct State { /// Async read-write lock. /// -/// The read-write lock is generic over a blocking [`RawRwLock`](crate::blocking_mutex::raw_rwlock::RawRwLock). +/// The read-write lock is generic over the raw mutex implementation `M` and the data `T` it protects. /// The raw read-write lock is used to guard access to the internal state. It /// is held for very short periods only, while locking and unlocking. It is *not* held /// for the entire time the async RwLock is locked. @@ -307,6 +307,25 @@ where rwlock: &'a RwLock, } +impl<'a, R, T> RwLockWriteGuard<'a, R, T> +where + R: RawMutex, + T: ?Sized, +{ + /// Returns a locked view over a portion of the locked data. + pub fn map(this: Self, fun: impl FnOnce(&mut T) -> &mut U) -> MappedRwLockWriteGuard<'a, R, U> { + let rwlock = this.rwlock; + let value = fun(unsafe { &mut *this.rwlock.inner.get() }); + // Dont run the `drop` method for RwLockWriteGuard. The ownership of the underlying + // locked state is being moved to the returned MappedRwLockWriteGuard. + mem::forget(this); + MappedRwLockWriteGuard { + state: &rwlock.state, + value, + } + } +} + impl<'a, R, T> Drop for RwLockWriteGuard<'a, R, T> where R: RawMutex, @@ -366,8 +385,8 @@ where } } -/// A handle to a held `Mutex` that has had a function applied to it via [`MutexGuard::map`] or -/// [`MappedMutexGuard::map`]. +/// A handle to a held `RwLock` that has had a function applied to it via [`RwLockReadGuard::map`] or +/// [`MappedRwLockReadGuard::map`]. /// /// This can be used to hold a subfield of the protected data. #[clippy::has_significant_drop] @@ -380,6 +399,22 @@ where value: *const T, } +impl<'a, M, T> MappedRwLockReadGuard<'a, M, T> +where + M: RawMutex, + T: ?Sized, +{ + /// Returns a locked view over a portion of the locked data. + pub fn map(this: Self, fun: impl FnOnce(&T) -> &U) -> MappedRwLockReadGuard<'a, M, U> { + let rwlock = this.state; + let value = fun(unsafe { &*this.value }); + // Dont run the `drop` method for RwLockReadGuard. The ownership of the underlying + // locked state is being moved to the returned MappedRwLockReadGuard. + mem::forget(this); + MappedRwLockReadGuard { state: rwlock, value } + } +} + impl<'a, M, T> Deref for MappedRwLockReadGuard<'a, M, T> where M: RawMutex, @@ -443,8 +478,8 @@ where } } -/// A handle to a held `Mutex` that has had a function applied to it via [`MutexGuard::map`] or -/// [`MappedMutexGuard::map`]. +/// A handle to a held `RwLock` that has had a function applied to it via [`RwLockWriteGuard::map`] or +/// [`MappedRwLockWriteGuard::map`]. /// /// This can be used to hold a subfield of the protected data. #[clippy::has_significant_drop] @@ -457,6 +492,22 @@ where value: *mut T, } +impl<'a, M, T> MappedRwLockWriteGuard<'a, M, T> +where + M: RawMutex, + T: ?Sized, +{ + /// Returns a locked view over a portion of the locked data. + pub fn map(this: Self, fun: impl FnOnce(&mut T) -> &mut U) -> MappedRwLockWriteGuard<'a, M, U> { + let rwlock = this.state; + let value = fun(unsafe { &mut *this.value }); + // Dont run the `drop` method for RwLockWriteGuard. The ownership of the underlying + // locked state is being moved to the returned MappedRwLockWriteGuard. + mem::forget(this); + MappedRwLockWriteGuard { state: rwlock, value } + } +} + impl<'a, M, T> Deref for MappedRwLockWriteGuard<'a, M, T> where M: RawMutex, From e9b842082df4d8138d3100ecc8ad177245391f38 Mon Sep 17 00:00:00 2001 From: dimi Date: Tue, 18 Mar 2025 17:00:40 +0100 Subject: [PATCH 0837/1217] `embassy-stm32::hspi`: gate derive(defmt::Format) behind feature flag --- embassy-stm32/src/hspi/enums.rs | 33 ++++++++++++++++++++++----------- embassy-stm32/src/hspi/mod.rs | 3 ++- 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/embassy-stm32/src/hspi/enums.rs b/embassy-stm32/src/hspi/enums.rs index 351fc9ec6..83a88f4d9 100644 --- a/embassy-stm32/src/hspi/enums.rs +++ b/embassy-stm32/src/hspi/enums.rs @@ -1,7 +1,8 @@ //! Enums used in Hspi configuration. #[allow(dead_code)] -#[derive(Copy, Clone, defmt::Format)] +#[derive(Copy, Clone)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub(crate) enum HspiMode { IndirectWrite, IndirectRead, @@ -22,7 +23,8 @@ impl Into for HspiMode { /// Hspi lane width #[allow(dead_code)] -#[derive(Copy, Clone, defmt::Format)] +#[derive(Copy, Clone)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum HspiWidth { /// None NONE, @@ -53,7 +55,8 @@ impl Into for HspiWidth { /// Flash bank selection #[allow(dead_code)] -#[derive(Copy, Clone, defmt::Format)] +#[derive(Copy, Clone)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum FlashSelection { /// Bank 1 Flash1, @@ -73,7 +76,8 @@ impl Into for FlashSelection { /// Wrap Size #[allow(dead_code)] #[allow(missing_docs)] -#[derive(Copy, Clone, defmt::Format)] +#[derive(Copy, Clone)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum WrapSize { None, _16Bytes, @@ -97,7 +101,8 @@ impl Into for WrapSize { /// Memory Type #[allow(missing_docs)] #[allow(dead_code)] -#[derive(Copy, Clone, defmt::Format)] +#[derive(Copy, Clone)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum MemoryType { Micron, Macronix, @@ -122,7 +127,8 @@ impl Into for MemoryType { /// Hspi memory size. #[allow(missing_docs)] -#[derive(Copy, Clone, defmt::Format)] +#[derive(Copy, Clone)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum MemorySize { _1KiB, _2KiB, @@ -182,7 +188,8 @@ impl Into for MemorySize { } /// Hspi Address size -#[derive(Copy, Clone, defmt::Format)] +#[derive(Copy, Clone)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum AddressSize { /// 8-bit address _8Bit, @@ -207,7 +214,8 @@ impl Into for AddressSize { /// Time the Chip Select line stays high. #[allow(missing_docs)] -#[derive(Copy, Clone, defmt::Format)] +#[derive(Copy, Clone)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum ChipSelectHighTime { _1Cycle, _2Cycle, @@ -236,7 +244,8 @@ impl Into for ChipSelectHighTime { /// FIFO threshold. #[allow(missing_docs)] -#[derive(Copy, Clone, defmt::Format)] +#[derive(Copy, Clone)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum FIFOThresholdLevel { _1Bytes, _2Bytes, @@ -313,7 +322,8 @@ impl Into for FIFOThresholdLevel { /// Dummy cycle count #[allow(missing_docs)] -#[derive(Copy, Clone, defmt::Format)] +#[derive(Copy, Clone)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum DummyCycles { _0, _1, @@ -391,7 +401,8 @@ impl Into for DummyCycles { /// Functional mode #[allow(missing_docs)] #[allow(dead_code)] -#[derive(Copy, Clone, defmt::Format)] +#[derive(Copy, Clone)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum FunctionalMode { IndirectWrite, IndirectRead, diff --git a/embassy-stm32/src/hspi/mod.rs b/embassy-stm32/src/hspi/mod.rs index 97e1993dd..54b442481 100644 --- a/embassy-stm32/src/hspi/mod.rs +++ b/embassy-stm32/src/hspi/mod.rs @@ -24,7 +24,8 @@ use crate::rcc::{self, RccPeripheral}; use crate::{peripherals, Peripheral}; /// HSPI driver config. -#[derive(Clone, Copy, defmt::Format)] +#[derive(Clone, Copy)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct Config { /// Fifo threshold used by the peripheral to generate the interrupt indicating data /// or space is available in the FIFO From 9806f78ea067297a53cb3877a380804c79961bd2 Mon Sep 17 00:00:00 2001 From: decaday Date: Wed, 19 Mar 2025 11:37:35 +0800 Subject: [PATCH 0838/1217] Add information about existing USB IP implementations --- embassy-usb/README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/embassy-usb/README.md b/embassy-usb/README.md index 400fc6695..a053c940b 100644 --- a/embassy-usb/README.md +++ b/embassy-usb/README.md @@ -20,6 +20,11 @@ Async USB device stack for embedded devices in Rust. To add `embassy-usb` support for new hardware (i.e. a new MCU chip), you have to write a driver that implements the [`embassy-usb-driver`](https://crates.io/crates/embassy-usb-driver) traits. +Before writing a new driver, you can first verify whether the chip uses a common USB IP. Several widely used USB IPs already have implementations available, such as: + +- **Synopsys OTG (dwc2)**: Available at [embassy-usb-synopsys-otg](https://crates.io/crates/embassy-usb-synopsys-otg). This IP is used by vendors like STMicroelectronics, Espressif, and others. +- **Musbmhdrc (musb)**: Available at [musb](https://crates.io/crates/musb). This IP is used by vendors like TI, MediaTek, Puya, and others. + Driver crates should depend only on `embassy-usb-driver`, not on the main `embassy-usb` crate. This allows existing drivers to continue working for newer `embassy-usb` major versions, without needing an update, if the driver trait has not had breaking changes. From 0f0030651c4d0fdc8809b341e9b27d7626128cf6 Mon Sep 17 00:00:00 2001 From: decaday Date: Wed, 19 Mar 2025 11:59:05 +0800 Subject: [PATCH 0839/1217] Add py32-hal to documentation --- README.md | 1 + docs/pages/hal.adoc | 4 +++- docs/pages/overview.adoc | 1 + 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index ee5c42245..e9f0d3b24 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,7 @@ Rust's async/await allows - Embassy HAL support for Espressif chips, as well as Async WiFi, Bluetooth and ESP-NOW, is being developed in the [esp-rs/esp-hal](https://github.com/esp-rs/esp-hal) repository. - ch32-hal, for the WCH 32-bit RISC-V(CH32V) series of chips. - mpfs-hal, for the Microchip PolarFire SoC. + - py32-hal, for the Puya Semiconductor PY32 series of microcontrollers. - **Time that Just Works** - No more messing with hardware timers. embassy_time provides Instant, Duration and Timer types that are globally available and never overflow. diff --git a/docs/pages/hal.adoc b/docs/pages/hal.adoc index e1a29751e..3c6839792 100644 --- a/docs/pages/hal.adoc +++ b/docs/pages/hal.adoc @@ -13,4 +13,6 @@ For the ESP32 series, there is an link:https://github.com/esp-rs/esp-hal[esp-hal For the WCH 32-bit RISC-V series, there is an link:https://github.com/ch32-rs/ch32-hal[ch32-hal], which you can use. -For the Microchip PolarFire SoC, there is link:https://github.com/AlexCharlton/mpfs-hal[mpfs-hal]. \ No newline at end of file +For the Microchip PolarFire SoC, there is link:https://github.com/AlexCharlton/mpfs-hal[mpfs-hal]. + +For the Puya Semiconductor PY32 series, there is link:https://github.com/py32-rs/py32-hal[py32-hal]. \ No newline at end of file diff --git a/docs/pages/overview.adoc b/docs/pages/overview.adoc index 9b93ba10c..abc7d25de 100644 --- a/docs/pages/overview.adoc +++ b/docs/pages/overview.adoc @@ -32,6 +32,7 @@ The Embassy project maintains HALs for select hardware, but you can still use HA * link:https://github.com/esp-rs[esp-rs], for the Espressif Systems ESP32 series of chips. * link:https://github.com/ch32-rs/ch32-hal[ch32-hal], for the WCH 32-bit RISC-V(CH32V) series of chips. * link:https://github.com/AlexCharlton/mpfs-hal[mpfs-hal], for the Microchip PolarFire SoC. +* link:https://github.com/py32-rs/py32-hal[py32-hal], for the Puya Semiconductor PY32 series of chips. NOTE: A common question is if one can use the Embassy HALs standalone. Yes, it is possible! There are no dependency on the executor within the HALs. You can even use them without async, as they implement both the link:https://github.com/rust-embedded/embedded-hal[Embedded HAL] blocking and async traits. From f15c587887b39c8027c8c557794b027e09e27d30 Mon Sep 17 00:00:00 2001 From: JuliDi <20155974+JuliDi@users.noreply.github.com> Date: Wed, 19 Mar 2025 10:16:38 +0100 Subject: [PATCH 0840/1217] fix wrong funcsel on rp2350 gpout/gpin --- embassy-rp/src/clocks.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs index 2ac2c925e..9423a7e13 100644 --- a/embassy-rp/src/clocks.rs +++ b/embassy-rp/src/clocks.rs @@ -854,7 +854,14 @@ impl<'d, T: GpinPin> Gpin<'d, T> { pub fn new(gpin: impl Peripheral

+ 'd) -> Self { into_ref!(gpin); + #[cfg(feature = "rp2040")] gpin.gpio().ctrl().write(|w| w.set_funcsel(0x08)); + + // On RP2350 GPIN changed from F8 toF9 + #[cfg(feature = "_rp235x")] + gpin.gpio().ctrl().write(|w| w.set_funcsel(0x09)); + + #[cfg(feature = "_rp235x")] gpin.pad_ctrl().write(|w| { w.set_iso(false); @@ -938,7 +945,14 @@ impl<'d, T: GpoutPin> Gpout<'d, T> { pub fn new(gpout: impl Peripheral

+ 'd) -> Self { into_ref!(gpout); + #[cfg(feature = "rp2040")] gpout.gpio().ctrl().write(|w| w.set_funcsel(0x08)); + + // On RP2350 GPOUT changed from F8 toF9 + #[cfg(feature = "_rp235x")] + gpout.gpio().ctrl().write(|w| w.set_funcsel(0x09)); + + #[cfg(feature = "_rp235x")] gpout.pad_ctrl().write(|w| { w.set_iso(false); From 436f940d5a8398e6aebd328db4da22aec775d1e6 Mon Sep 17 00:00:00 2001 From: JuliDi <20155974+JuliDi@users.noreply.github.com> Date: Wed, 19 Mar 2025 10:42:34 +0100 Subject: [PATCH 0841/1217] make rustfmt happy --- embassy-rp/src/clocks.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs index 9423a7e13..705dde62a 100644 --- a/embassy-rp/src/clocks.rs +++ b/embassy-rp/src/clocks.rs @@ -861,7 +861,6 @@ impl<'d, T: GpinPin> Gpin<'d, T> { #[cfg(feature = "_rp235x")] gpin.gpio().ctrl().write(|w| w.set_funcsel(0x09)); - #[cfg(feature = "_rp235x")] gpin.pad_ctrl().write(|w| { w.set_iso(false); @@ -952,7 +951,6 @@ impl<'d, T: GpoutPin> Gpout<'d, T> { #[cfg(feature = "_rp235x")] gpout.gpio().ctrl().write(|w| w.set_funcsel(0x09)); - #[cfg(feature = "_rp235x")] gpout.pad_ctrl().write(|w| { w.set_iso(false); From 9afb385f6d92149ff15cf03c3bfaa8cb512a6191 Mon Sep 17 00:00:00 2001 From: i509VCB Date: Wed, 19 Mar 2025 13:05:10 -0500 Subject: [PATCH 0842/1217] Add docs related things --- .github/ci/doc.sh | 1 + README.md | 1 + docs/pages/overview.adoc | 1 + embassy-mspm0/Cargo.toml | 8 +++++++- 4 files changed, 10 insertions(+), 1 deletion(-) diff --git a/.github/ci/doc.sh b/.github/ci/doc.sh index c92892406..58ffe5f2e 100755 --- a/.github/ci/doc.sh +++ b/.github/ci/doc.sh @@ -25,6 +25,7 @@ docserver-builder -i ./embassy-executor -o webroot/crates/embassy-executor/git.z docserver-builder -i ./embassy-futures -o webroot/crates/embassy-futures/git.zup docserver-builder -i ./embassy-nrf -o webroot/crates/embassy-nrf/git.zup docserver-builder -i ./embassy-rp -o webroot/crates/embassy-rp/git.zup +docserver-builder -i ./embassy-mspm0 -o webroot/crates/embassy-mspm0/git.zup docserver-builder -i ./embassy-sync -o webroot/crates/embassy-sync/git.zup docserver-builder -i ./cyw43 -o webroot/crates/cyw43/git.zup docserver-builder -i ./cyw43-pio -o webroot/crates/cyw43-pio/git.zup diff --git a/README.md b/README.md index ee5c42245..a682927c8 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,7 @@ Rust's async/await allows - embassy-stm32, for all STM32 microcontroller families. - embassy-nrf, for the Nordic Semiconductor nRF52, nRF53, nRF54 and nRF91 series. - embassy-rp, for the Raspberry Pi RP2040 and RP23xx microcontrollers. + - embassy-mspm0, for the Texas Instruments MSPM0 microcontrollers. - esp-rs, for the Espressif Systems ESP32 series of chips. - Embassy HAL support for Espressif chips, as well as Async WiFi, Bluetooth and ESP-NOW, is being developed in the [esp-rs/esp-hal](https://github.com/esp-rs/esp-hal) repository. - ch32-hal, for the WCH 32-bit RISC-V(CH32V) series of chips. diff --git a/docs/pages/overview.adoc b/docs/pages/overview.adoc index 9b93ba10c..333a5dd9f 100644 --- a/docs/pages/overview.adoc +++ b/docs/pages/overview.adoc @@ -29,6 +29,7 @@ The Embassy project maintains HALs for select hardware, but you can still use HA * link:https://docs.embassy.dev/embassy-stm32/[embassy-stm32], for all STM32 microcontroller families. * link:https://docs.embassy.dev/embassy-nrf/[embassy-nrf], for the Nordic Semiconductor nRF52, nRF53, nRF91 series. * link:https://docs.embassy.dev/embassy-rp/[embassy-rp], for the Raspberry Pi RP2040 microcontroller. +* link:https://docs.embassy.dev/embassy-mspm0/[embassy-mspm0], for the Texas Instruments MSPM0 microcontrollers. * link:https://github.com/esp-rs[esp-rs], for the Espressif Systems ESP32 series of chips. * link:https://github.com/ch32-rs/ch32-hal[ch32-hal], for the WCH 32-bit RISC-V(CH32V) series of chips. * link:https://github.com/AlexCharlton/mpfs-hal[mpfs-hal], for the Microchip PolarFire SoC. diff --git a/embassy-mspm0/Cargo.toml b/embassy-mspm0/Cargo.toml index 0f4092d8a..cfe0c85a9 100644 --- a/embassy-mspm0/Cargo.toml +++ b/embassy-mspm0/Cargo.toml @@ -9,6 +9,12 @@ categories = ["embedded", "hardware-support", "no-std", "asynchronous"] repository = "https://github.com/embassy-rs/embassy" documentation = "https://docs.embassy.dev/embassy-mspm0" +[package.metadata.embassy_docs] +src_base = "https://github.com/embassy-rs/embassy/blob/embassy-mspm0-v$VERSION/embassy-mspm0/src/" +src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-mspm0/src/" + +features = ["defmt", "unstable-pac", "time-driver-any"] + [package.metadata.docs.rs] features = ["defmt", "unstable-pac", "time-driver-any", "time", "mspm0g3507"] rustdoc-args = ["--cfg", "docsrs"] @@ -105,7 +111,7 @@ time-driver-tima0 = ["_time-driver"] time-driver-tima1 = ["_time-driver"] #! ## Chip-selection features -#! Select your chip by specifying the model as a feature, e.g. `mspm0g3507`. +#! Select your chip by specifying the model as a feature, e.g. `mspm0g350x`. #! Check the `Cargo.toml` for the latest list of supported chips. #! #! **Important:** Do not forget to adapt the target chip in your toolchain, From 91684a11c8a15b62a773a1ace40791fcf80fdad2 Mon Sep 17 00:00:00 2001 From: i509VCB Date: Wed, 19 Mar 2025 13:28:03 -0500 Subject: [PATCH 0843/1217] build c1104 seperately for defmt buffer size --- ci.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ci.sh b/ci.sh index 84312127f..5b63c507b 100755 --- a/ci.sh +++ b/ci.sh @@ -244,7 +244,6 @@ cargo batch \ --- build --release --manifest-path examples/stm32wba/Cargo.toml --target thumbv8m.main-none-eabihf --artifact-dir out/examples/stm32wba \ --- build --release --manifest-path examples/stm32wl/Cargo.toml --target thumbv7em-none-eabi --artifact-dir out/examples/stm32wl \ --- build --release --manifest-path examples/lpc55s69/Cargo.toml --target thumbv8m.main-none-eabihf --artifact-dir out/examples/lpc55s69 \ - --- build --release --manifest-path examples/mspm0c1104/Cargo.toml --target thumbv6m-none-eabi --artifact-dir out/examples/mspm0c1104 \ --- build --release --manifest-path examples/mspm0g3507/Cargo.toml --target thumbv6m-none-eabi --artifact-dir out/examples/mspm0g3507 \ --- build --release --manifest-path examples/mspm0g3519/Cargo.toml --target thumbv6m-none-eabi --artifact-dir out/examples/mspm0g3519 \ --- build --release --manifest-path examples/mspm0l1306/Cargo.toml --target thumbv6m-none-eabi --artifact-dir out/examples/mspm0l1306 \ @@ -313,6 +312,11 @@ cargo batch \ $BUILD_EXTRA +# MSPM0C1104 must be built seperately since cargo batch does not consider env vars set in `.cargo/config.toml`. +# Since the target has 1KB of ram, we need to limit defmt's buffer size. +DEFMT_RTT_BUFFER_SIZE="72" cargo batch \ + --- build --release --manifest-path examples/mspm0c1104/Cargo.toml --target thumbv6m-none-eabi --artifact-dir out/examples/mspm0c1104 \ + # temporarily disabled, these boards are dead. rm -rf out/tests/stm32f103c8 rm -rf out/tests/nrf52840-dk From f3b9be7beede167295e8dc431e417bea77bb2455 Mon Sep 17 00:00:00 2001 From: Alexander van Saase Date: Wed, 19 Mar 2025 19:32:05 +0100 Subject: [PATCH 0844/1217] embassy-sync: add lock_mut to blocking_mutex::Mutex --- embassy-sync/src/blocking_mutex/mod.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/embassy-sync/src/blocking_mutex/mod.rs b/embassy-sync/src/blocking_mutex/mod.rs index beafdb43d..5b0e4144a 100644 --- a/embassy-sync/src/blocking_mutex/mod.rs +++ b/embassy-sync/src/blocking_mutex/mod.rs @@ -50,6 +50,20 @@ impl Mutex { f(inner) }) } + + /// Creates a critical section and grants temporary mutable access to the protected data. + /// + /// # Safety + /// This method is unsafe because calling this method when the mutex is already locked, + /// either using this method or `lock`, violates Rust's aliasing rules. + pub unsafe fn lock_mut(&self, f: impl FnOnce(&mut T) -> U) -> U { + self.raw.lock(|| { + let ptr = self.data.get() as *mut T; + // Safety: we have exclusive access to the data, as long as this mutex is not locked re-entrantly + let inner = unsafe { &mut *ptr }; + f(inner) + }) + } } impl Mutex { From 71d94ad5e7e2f20e2f0a55b080677fc97b88ceb9 Mon Sep 17 00:00:00 2001 From: Tobias Naumann Date: Thu, 20 Mar 2025 00:35:11 +0100 Subject: [PATCH 0845/1217] Recover from errors in ringbuffered usart --- embassy-stm32/src/usart/ringbuffered.rs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/embassy-stm32/src/usart/ringbuffered.rs b/embassy-stm32/src/usart/ringbuffered.rs index 3631888e4..ffd4ee544 100644 --- a/embassy-stm32/src/usart/ringbuffered.rs +++ b/embassy-stm32/src/usart/ringbuffered.rs @@ -8,7 +8,9 @@ use embassy_hal_internal::PeripheralRef; use embedded_io_async::ReadReady; use futures_util::future::{select, Either}; -use super::{rdr, reconfigure, set_baudrate, sr, Config, ConfigError, Error, Info, State, UartRx}; +use super::{ + clear_interrupt_flags, rdr, reconfigure, set_baudrate, sr, Config, ConfigError, Error, Info, State, UartRx, +}; use crate::dma::ReadableRingBuffer; use crate::gpio::{AnyPin, SealedPin as _}; use crate::mode::Async; @@ -97,6 +99,8 @@ impl<'d> RingBufferedUartRx<'d> { // enable idle line interrupt w.set_idleie(true); }); + // Clear all potential error interrupt flags + clear_interrupt_flags(r, sr(r).read()); r.cr3().modify(|w| { // enable Error Interrupt: (Frame error, Noise error, Overrun error) w.set_eie(true); @@ -140,14 +144,15 @@ impl<'d> RingBufferedUartRx<'d> { pub async fn read(&mut self, buf: &mut [u8]) -> Result { let r = self.info.regs; - // Start DMA and Uart if it was not already started, - // otherwise check for errors in status register. + // (Re-)start DMA and Uart if it is not running (has not been started yet or has failed), + // and check for errors in status register. Error flags are cleared in `start_uart()` so + // they need to be read first without returning yet. let sr = clear_idle_flag(r); + let res = check_for_errors(sr); if !r.cr3().read().dmar() { self.start_uart(); - } else { - check_for_errors(sr)?; } + res?; loop { match self.ring_buf.read(buf) { From 9407ac67d3b7df7511bce7dbd73814e861851622 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 20 Mar 2025 01:30:12 +0100 Subject: [PATCH 0846/1217] Update stm32-data. --- embassy-stm32/Cargo.toml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 068c5e230..8204a0fea 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -72,8 +72,8 @@ futures-util = { version = "0.3.30", default-features = false } rand_core = "0.6.3" sdio-host = "0.5.0" critical-section = "1.1" -stm32-metapac = { version = "16" } -#stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-db71f6aa03b7db26548b461d3844fc404d40c98c" } +#stm32-metapac = { version = "16" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-4a964af03b298de30ff9f84fcfa890bcab4ce609" } vcell = "0.1.3" nb = "1.0.0" @@ -101,8 +101,8 @@ proptest-state-machine = "0.3.0" proc-macro2 = "1.0.36" quote = "1.0.15" -stm32-metapac = { version = "16", default-features = false, features = ["metadata"]} -#stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-db71f6aa03b7db26548b461d3844fc404d40c98c", default-features = false, features = ["metadata"] } +#stm32-metapac = { version = "16", default-features = false, features = ["metadata"]} +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-4a964af03b298de30ff9f84fcfa890bcab4ce609", default-features = false, features = ["metadata"] } [features] default = ["rt"] From 8c6fa83006a22c77740552161f816e294ec166b3 Mon Sep 17 00:00:00 2001 From: Timofei Korostelev Date: Mon, 17 Feb 2025 21:40:35 -0800 Subject: [PATCH 0847/1217] Added ADC support for STM32C0. --- embassy-stm32/src/adc/c0.rs | 468 ++++++++++++++++++++++++++++++++ embassy-stm32/src/adc/mod.rs | 20 +- embassy-stm32/src/rcc/c0.rs | 3 + examples/stm32c0/src/bin/adc.rs | 57 ++++ 4 files changed, 543 insertions(+), 5 deletions(-) create mode 100644 embassy-stm32/src/adc/c0.rs create mode 100644 examples/stm32c0/src/bin/adc.rs diff --git a/embassy-stm32/src/adc/c0.rs b/embassy-stm32/src/adc/c0.rs new file mode 100644 index 000000000..84763ad4f --- /dev/null +++ b/embassy-stm32/src/adc/c0.rs @@ -0,0 +1,468 @@ +use pac::adc::vals::Scandir; +#[allow(unused)] +use pac::adc::vals::{Adstp, Align, Ckmode, Dmacfg, Exten, Ovrmod, Ovsr}; +use pac::adccommon::vals::Presc; + +use super::{ + blocking_delay_us, Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, SealedAdcChannel, +}; +use crate::dma::Transfer; +use crate::time::Hertz; +use crate::{pac, rcc, Peripheral}; + +/// Default VREF voltage used for sample conversion to millivolts. +pub const VREF_DEFAULT_MV: u32 = 3300; +/// VREF voltage used for factory calibration of VREFINTCAL register. +pub const VREF_CALIB_MV: u32 = 3300; + +const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(25); + +const TIME_ADC_VOLTAGE_REGUALTOR_STARTUP_US: u32 = 20; + +const TEMP_CHANNEL: u8 = 9; +const VREF_CHANNEL: u8 = 10; + +const NUM_HW_CHANNELS: u8 = 22; +const CHSELR_SQ_SIZE: usize = 8; +const CHSELR_SQ_MAX_CHANNEL: u8 = 14; +const CHSELR_SQ_SEQUENCE_END_MARKER: u8 = 0b1111; + +// NOTE: Vrefint/Temperature/Vbat are not available on all ADCs, +// this currently cannot be modeled with stm32-data, +// so these are available from the software on all ADCs. +/// Internal voltage reference channel. +pub struct VrefInt; +impl AdcChannel for VrefInt {} +impl SealedAdcChannel for VrefInt { + fn channel(&self) -> u8 { + VREF_CHANNEL + } +} + +/// Internal temperature channel. +pub struct Temperature; +impl AdcChannel for Temperature {} +impl SealedAdcChannel for Temperature { + fn channel(&self) -> u8 { + TEMP_CHANNEL + } +} + +#[derive(Debug)] +pub enum Prescaler { + NotDivided, + DividedBy2, + DividedBy4, + DividedBy6, + DividedBy8, + DividedBy10, + DividedBy12, + DividedBy16, + DividedBy32, + DividedBy64, + DividedBy128, + DividedBy256, +} + +impl Prescaler { + fn from_ker_ck(frequency: Hertz) -> Self { + let raw_prescaler = frequency.0 / MAX_ADC_CLK_FREQ.0; + match raw_prescaler { + 0 => Self::NotDivided, + 1 => Self::DividedBy2, + 2..=3 => Self::DividedBy4, + 4..=5 => Self::DividedBy6, + 6..=7 => Self::DividedBy8, + 8..=9 => Self::DividedBy10, + 10..=11 => Self::DividedBy12, + _ => unimplemented!(), + } + } + + #[allow(unused)] + fn divisor(&self) -> u32 { + match self { + Prescaler::NotDivided => 1, + Prescaler::DividedBy2 => 2, + Prescaler::DividedBy4 => 4, + Prescaler::DividedBy6 => 6, + Prescaler::DividedBy8 => 8, + Prescaler::DividedBy10 => 10, + Prescaler::DividedBy12 => 12, + Prescaler::DividedBy16 => 16, + Prescaler::DividedBy32 => 32, + Prescaler::DividedBy64 => 64, + Prescaler::DividedBy128 => 128, + Prescaler::DividedBy256 => 256, + } + } + + fn presc(&self) -> Presc { + match self { + Prescaler::NotDivided => Presc::DIV1, + Prescaler::DividedBy2 => Presc::DIV2, + Prescaler::DividedBy4 => Presc::DIV4, + Prescaler::DividedBy6 => Presc::DIV6, + Prescaler::DividedBy8 => Presc::DIV8, + Prescaler::DividedBy10 => Presc::DIV10, + Prescaler::DividedBy12 => Presc::DIV12, + Prescaler::DividedBy16 => Presc::DIV16, + Prescaler::DividedBy32 => Presc::DIV32, + Prescaler::DividedBy64 => Presc::DIV64, + Prescaler::DividedBy128 => Presc::DIV128, + Prescaler::DividedBy256 => Presc::DIV256, + } + } +} + +#[cfg(feature = "defmt")] +impl<'a> defmt::Format for Prescaler { + fn format(&self, fmt: defmt::Formatter) { + match self { + Prescaler::NotDivided => defmt::write!(fmt, "Prescaler::NotDivided"), + Prescaler::DividedBy2 => defmt::write!(fmt, "Prescaler::DividedBy2"), + Prescaler::DividedBy4 => defmt::write!(fmt, "Prescaler::DividedBy4"), + Prescaler::DividedBy6 => defmt::write!(fmt, "Prescaler::DividedBy6"), + Prescaler::DividedBy8 => defmt::write!(fmt, "Prescaler::DividedBy8"), + Prescaler::DividedBy10 => defmt::write!(fmt, "Prescaler::DividedBy10"), + Prescaler::DividedBy12 => defmt::write!(fmt, "Prescaler::DividedBy12"), + Prescaler::DividedBy16 => defmt::write!(fmt, "Prescaler::DividedBy16"), + Prescaler::DividedBy32 => defmt::write!(fmt, "Prescaler::DividedBy32"), + Prescaler::DividedBy64 => defmt::write!(fmt, "Prescaler::DividedBy64"), + Prescaler::DividedBy128 => defmt::write!(fmt, "Prescaler::DividedBy128"), + Prescaler::DividedBy256 => defmt::write!(fmt, "Prescaler::DividedBy256"), + } + } +} + +/// Number of samples used for averaging. +/// TODO: Implement hardware averaging setting. +#[allow(unused)] +pub enum Averaging { + Disabled, + Samples2, + Samples4, + Samples8, + Samples16, + Samples32, + Samples64, + Samples128, + Samples256, + Samples512, + Samples1024, +} + +impl<'d, T: Instance> Adc<'d, T> { + /// Create a new ADC driver. + pub fn new(adc: impl Peripheral

+ 'd, sample_time: SampleTime, resolution: Resolution) -> Self { + embassy_hal_internal::into_ref!(adc); + rcc::enable_and_reset::(); + + T::regs().cfgr2().modify(|w| w.set_ckmode(Ckmode::SYSCLK)); + + let prescaler = Prescaler::from_ker_ck(T::frequency()); + T::common_regs().ccr().modify(|w| w.set_presc(prescaler.presc())); + + let frequency = Hertz(T::frequency().0 / prescaler.divisor()); + debug!("ADC frequency set to {} Hz", frequency.0); + + if frequency > MAX_ADC_CLK_FREQ { + panic!("Maximal allowed frequency for the ADC is {} MHz and it varies with different packages, refer to ST docs for more information.", MAX_ADC_CLK_FREQ.0 / 1_000_000 ); + } + + let mut s = Self { + adc, + sample_time: SampleTime::from_bits(0), + }; + + s.power_up(); + + s.set_resolution(resolution); + + s.calibrate(); + + s.enable(); + + s.configure_default(); + + s.set_sample_time_all_channels(sample_time); + + s + } + + fn power_up(&mut self) { + T::regs().cr().modify(|reg| { + reg.set_advregen(true); + }); + + // "The software must wait for the ADC voltage regulator startup time." + // See datasheet for the value. + blocking_delay_us(TIME_ADC_VOLTAGE_REGUALTOR_STARTUP_US + 1); + } + + fn calibrate(&mut self) { + // We have to make sure AUTOFF is OFF, but keep its value after calibration. + let autoff_value = T::regs().cfgr1().read().autoff(); + T::regs().cfgr1().modify(|w| w.set_autoff(false)); + + T::regs().cr().modify(|w| w.set_adcal(true)); + + // "ADCAL bit stays at 1 during all the calibration sequence." + // "It is then cleared by hardware as soon the calibration completes." + while T::regs().cr().read().adcal() {} + + debug!("ADC calibration value: {}.", T::regs().dr().read().data()); + + T::regs().cfgr1().modify(|w| w.set_autoff(autoff_value)); + } + + fn enable(&mut self) { + T::regs().isr().modify(|w| w.set_adrdy(true)); + T::regs().cr().modify(|w| w.set_aden(true)); + // ADRDY is "ADC ready". Wait until it will be True. + while !T::regs().isr().read().adrdy() {} + } + + fn configure_default(&mut self) { + // single conversion mode, software trigger + T::regs().cfgr1().modify(|w| { + w.set_cont(false); + w.set_exten(Exten::DISABLED); + w.set_align(Align::RIGHT); + }); + } + + /// Enable reading the voltage reference internal channel. + pub fn enable_vrefint(&self) -> VrefInt { + T::common_regs().ccr().modify(|reg| { + reg.set_vrefen(true); + }); + + VrefInt {} + } + + /// Enable reading the temperature internal channel. + pub fn enable_temperature(&self) -> Temperature { + debug!("Ensure that sample time is set to more than temperature sensor T_start from the datasheet!"); + T::common_regs().ccr().modify(|reg| { + reg.set_tsen(true); + }); + + Temperature {} + } + + /// Set the ADC sample time. + /// Shall only be called when ADC is not converting. + pub fn set_sample_time_all_channels(&mut self, sample_time: SampleTime) { + self.sample_time = sample_time; + + // Set all channels to use SMP1 field as source. + T::regs().smpr().modify(|w| { + w.smpsel(0); + w.set_smp1(sample_time); + }); + } + + /// Set the ADC resolution. + pub fn set_resolution(&mut self, resolution: Resolution) { + T::regs().cfgr1().modify(|reg| reg.set_res(resolution)); + } + + /// Perform a single conversion. + fn convert(&mut self) -> u16 { + // Set single conversion mode. + T::regs().cfgr1().modify(|w| w.set_cont(false)); + + // Start conversion + T::regs().cr().modify(|reg| { + reg.set_adstart(true); + }); + + // Waiting for End Of Conversion (EOC). + while !T::regs().isr().read().eoc() {} + + T::regs().dr().read().data() as u16 + } + + pub fn blocking_read(&mut self, channel: &mut impl AdcChannel) -> u16 { + Self::configure_channel(channel); + T::regs().cfgr1().write(|reg| { + reg.set_chselrmod(false); + reg.set_align(Align::RIGHT); + }); + self.convert() + } + + fn setup_channel_sequencer<'a>(channel_sequence: impl ExactSizeIterator>) { + assert!( + channel_sequence.len() <= CHSELR_SQ_SIZE, + "Seqenced read set cannot be more than {} in size.", + CHSELR_SQ_SIZE + ); + let mut last_sq_set: usize = 0; + T::regs().chselr_sq().write(|w| { + for (i, channel) in channel_sequence.enumerate() { + assert!( + channel.channel() <= CHSELR_SQ_MAX_CHANNEL, + "Sequencer only support HW channels smaller than {}.", + CHSELR_SQ_MAX_CHANNEL + ); + w.set_sq(i, channel.channel()); + last_sq_set = i; + } + + for i in (last_sq_set + 1)..CHSELR_SQ_SIZE { + w.set_sq(i, CHSELR_SQ_SEQUENCE_END_MARKER); + } + }); + + Self::apply_channel_conf() + } + + async fn dma_convert(&mut self, rx_dma: &mut impl RxDma, readings: &mut [u16]) { + // Enable overrun control, so no new DMA requests will be generated until + // previous DR values is read. + T::regs().isr().modify(|reg| { + reg.set_ovr(true); + }); + + // Set continuous mode with oneshot dma. + T::regs().cfgr1().modify(|reg| { + reg.set_discen(false); + reg.set_cont(true); + reg.set_dmacfg(Dmacfg::DMA_ONE_SHOT); + reg.set_dmaen(true); + reg.set_ovrmod(Ovrmod::PRESERVE); + }); + + let request = rx_dma.request(); + let transfer = unsafe { + Transfer::new_read( + rx_dma, + request, + T::regs().dr().as_ptr() as *mut u16, + readings, + Default::default(), + ) + }; + + // Start conversion. + T::regs().cr().modify(|reg| { + reg.set_adstart(true); + }); + + // Wait for conversion sequence to finish. + transfer.await; + + // Ensure conversions are finished. + Self::cancel_conversions(); + + // Reset configuration. + T::regs().cfgr1().modify(|reg| { + reg.set_cont(false); + reg.set_dmacfg(Dmacfg::from_bits(0)); + reg.set_dmaen(false); + }); + } + + /// Read one or multiple ADC channels using DMA in hardware order. + /// Readings will be ordered based on **hardware** ADC channel number and `scandir` setting. + /// Readings won't be in the same order as in the `set`! + /// + /// In STM32C0, channels bigger than 14 cannot be read using sequencer, so you have to use + /// either blocking reads or use the mechanism to read in HW order (CHSELRMOD=0). + /// TODO(chudsaviet): externalize generic code and merge with read(). + pub async fn read_in_hw_order( + &mut self, + rx_dma: &mut impl RxDma, + hw_channel_selection: u32, + scandir: Scandir, + readings: &mut [u16], + ) { + assert!( + hw_channel_selection != 0, + "Some bits in `hw_channel_selection` shall be set." + ); + assert!( + (hw_channel_selection >> NUM_HW_CHANNELS) == 0, + "STM32C0 only have {} ADC channels. `hw_channel_selection` cannot have bits higher than this number set.", + NUM_HW_CHANNELS + ); + // To check for correct readings slice size, we shall solve Hamming weight problem, + // which is either slow or memory consuming. + // Since we have limited resources, we don't do it here. + // Not doing this have a great potential for a bug through. + + // Ensure no conversions are ongoing. + Self::cancel_conversions(); + + T::regs().cfgr1().modify(|reg| { + reg.set_chselrmod(false); + reg.set_scandir(scandir); + reg.set_align(Align::RIGHT); + }); + + // Set required channels for multi-convert. + unsafe { (T::regs().chselr().as_ptr() as *mut u32).write_volatile(hw_channel_selection) } + + Self::apply_channel_conf(); + + self.dma_convert(rx_dma, readings).await + } + + // Read ADC channels in specified order using DMA (CHSELRMOD = 1). + // In STM32C0, only lower 14 ADC channels can be read this way. + // For other channels, use `read_in_hw_order()` or blocking read. + pub async fn read( + &mut self, + rx_dma: &mut impl RxDma, + channel_sequence: impl ExactSizeIterator>, + readings: &mut [u16], + ) { + assert!( + channel_sequence.len() != 0, + "Asynchronous read channel sequence cannot be empty." + ); + assert!( + channel_sequence.len() == readings.len(), + "Channel sequence length must be equal to readings length." + ); + + // Ensure no conversions are ongoing. + Self::cancel_conversions(); + + T::regs().cfgr1().modify(|reg| { + reg.set_chselrmod(true); + reg.set_align(Align::RIGHT); + }); + + Self::setup_channel_sequencer(channel_sequence); + + self.dma_convert(rx_dma, readings).await + } + + fn configure_channel(channel: &mut impl AdcChannel) { + channel.setup(); + // write() because we want all other bits to be set to 0. + T::regs() + .chselr() + .write(|w| w.set_chsel(channel.channel().into(), true)); + + Self::apply_channel_conf(); + } + + fn apply_channel_conf() { + // Trigger and wait for the channel selection procedure to complete. + T::regs().isr().modify(|w| w.set_ccrdy(false)); + while !T::regs().isr().read().ccrdy() {} + } + + fn cancel_conversions() { + if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() { + T::regs().cr().modify(|reg| { + reg.set_adstp(Adstp::STOP); + }); + while T::regs().cr().read().adstart() {} + } + } +} diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index 36898b8f9..31a08b6eb 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs @@ -14,6 +14,7 @@ #[cfg_attr(any(adc_v3, adc_g0, adc_h5, adc_u0), path = "v3.rs")] #[cfg_attr(any(adc_v4, adc_u5), path = "v4.rs")] #[cfg_attr(adc_g4, path = "g4.rs")] +#[cfg_attr(adc_c0, path = "c0.rs")] mod _version; use core::marker::PhantomData; @@ -71,7 +72,7 @@ trait SealedInstance { } pub(crate) trait SealedAdcChannel { - #[cfg(any(adc_v1, adc_l0, adc_v2, adc_g4, adc_v4, adc_u5))] + #[cfg(any(adc_v1, adc_c0, adc_l0, adc_v2, adc_g4, adc_v4, adc_u5))] fn setup(&mut self) {} #[allow(unused)] @@ -106,7 +107,8 @@ pub(crate) fn blocking_delay_us(us: u32) { adc_g0, adc_u0, adc_h5, - adc_u5 + adc_u5, + adc_c0 )))] #[allow(private_bounds)] pub trait Instance: SealedInstance + crate::Peripheral

{ @@ -126,7 +128,8 @@ pub trait Instance: SealedInstance + crate::Peripheral

{ adc_g0, adc_u0, adc_h5, - adc_u5 + adc_u5, + adc_c0 ))] #[allow(private_bounds)] pub trait Instance: SealedInstance + crate::Peripheral

+ crate::rcc::RccPeripheral { @@ -164,6 +167,13 @@ impl SealedAdcChannel for AnyAdcChannel { } } +impl AnyAdcChannel { + #[allow(unused)] + pub fn get_hw_channel(&self) -> u8 { + self.channel + } +} + #[cfg(adc_u5)] foreach_adc!( (ADC4, $common_inst:ident, $clock:ident) => { @@ -225,7 +235,7 @@ macro_rules! impl_adc_pin { ($inst:ident, $pin:ident, $ch:expr) => { impl crate::adc::AdcChannel for crate::peripherals::$pin {} impl crate::adc::SealedAdcChannel for crate::peripherals::$pin { - #[cfg(any(adc_v1, adc_l0, adc_v2, adc_g4, adc_v4, adc_u5))] + #[cfg(any(adc_v1, adc_c0, adc_l0, adc_v2, adc_g4, adc_v4, adc_u5))] fn setup(&mut self) { ::set_as_analog(self); } @@ -254,7 +264,7 @@ pub const fn resolution_to_max_count(res: Resolution) -> u32 { Resolution::BITS12 => (1 << 12) - 1, Resolution::BITS10 => (1 << 10) - 1, Resolution::BITS8 => (1 << 8) - 1, - #[cfg(any(adc_v1, adc_v2, adc_v3, adc_l0, adc_g0, adc_f3, adc_f3_v1_1, adc_h5))] + #[cfg(any(adc_v1, adc_v2, adc_v3, adc_l0, adc_c0, adc_g0, adc_f3, adc_f3_v1_1, adc_h5))] Resolution::BITS6 => (1 << 6) - 1, #[allow(unreachable_patterns)] _ => core::unreachable!(), diff --git a/embassy-stm32/src/rcc/c0.rs b/embassy-stm32/src/rcc/c0.rs index 977b2e7a2..04cbe83ed 100644 --- a/embassy-stm32/src/rcc/c0.rs +++ b/embassy-stm32/src/rcc/c0.rs @@ -180,6 +180,9 @@ pub(crate) unsafe fn init(config: Config) { lsi: None, lse: None, ); + + RCC.ccipr() + .modify(|w| w.set_adc1sel(stm32_metapac::rcc::vals::Adcsel::SYS)); } mod max { diff --git a/examples/stm32c0/src/bin/adc.rs b/examples/stm32c0/src/bin/adc.rs new file mode 100644 index 000000000..10481f4d2 --- /dev/null +++ b/examples/stm32c0/src/bin/adc.rs @@ -0,0 +1,57 @@ +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::adc::vals::Scandir; +use embassy_stm32::adc::{Adc, AdcChannel, AnyAdcChannel, Resolution, SampleTime}; +use embassy_stm32::peripherals::ADC1; +use embassy_time::Timer; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let config = Default::default(); + let p = embassy_stm32::init(config); + + info!("ADC STM32C0 example."); + + // We need to set certain sample time to be able to read temp sensor. + let mut adc = Adc::new(p.ADC1, SampleTime::CYCLES12_5, Resolution::BITS12); + let mut temp = adc.enable_temperature().degrade_adc(); + let mut vref = adc.enable_vrefint().degrade_adc(); + let mut pin0 = p.PA0.degrade_adc(); + + let mut dma = p.DMA1_CH1; + let mut read_buffer: [u16; 3] = [0; 3]; + + loop { + info!("============================"); + let blocking_temp = adc.blocking_read(&mut temp); + let blocking_vref = adc.blocking_read(&mut vref); + let blocing_pin0 = adc.blocking_read(&mut pin0); + info!( + "Blocking ADC read: vref = {}, temp = {}, pin0 = {}.", + blocking_vref, blocking_temp, blocing_pin0 + ); + + let channels_seqence: [&mut AnyAdcChannel; 3] = [&mut vref, &mut temp, &mut pin0]; + adc.read(&mut dma, channels_seqence.into_iter(), &mut read_buffer).await; + // Values are ordered according to hardware ADC channel number! + info!( + "DMA ADC read in set: vref = {}, temp = {}, pin0 = {}.", + read_buffer[0], read_buffer[1], read_buffer[2] + ); + + let hw_channel_selection: u32 = + (1 << temp.get_hw_channel()) + (1 << vref.get_hw_channel()) + (1 << pin0.get_hw_channel()); + adc.read_in_hw_order(&mut dma, hw_channel_selection, Scandir::UP, &mut read_buffer) + .await; + info!( + "DMA ADC read in hardware order: vref = {}, temp = {}, pin0 = {}.", + read_buffer[2], read_buffer[1], read_buffer[0] + ); + + Timer::after_millis(2000).await; + } +} From 97ed7f085a5f0fdec2e0311848b236883512ef70 Mon Sep 17 00:00:00 2001 From: Rasmus Melchior Jacobsen Date: Thu, 13 Feb 2025 14:33:55 +0100 Subject: [PATCH 0848/1217] feat(stm32): Add OTP flash region (again) --- embassy-stm32/build.rs | 2 ++ embassy-stm32/src/flash/f4.rs | 5 ++++- embassy-stm32/src/flash/h5.rs | 1 + embassy-stm32/src/flash/h50.rs | 2 ++ embassy-stm32/src/flash/mod.rs | 2 ++ embassy-stm32/src/flash/u5.rs | 2 ++ 6 files changed, 13 insertions(+), 1 deletion(-) diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index b35fd0300..eb0437bc2 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -296,6 +296,8 @@ fn main() { "Bank1" } else if region.name.starts_with("BANK_2") { "Bank2" + } else if region.name == "OTP" { + "Otp" } else { continue; } diff --git a/embassy-stm32/src/flash/f4.rs b/embassy-stm32/src/flash/f4.rs index d818c77d0..86afdce8a 100644 --- a/embassy-stm32/src/flash/f4.rs +++ b/embassy-stm32/src/flash/f4.rs @@ -15,7 +15,7 @@ mod alt_regions { use embassy_hal_internal::PeripheralRef; - use crate::_generated::flash_regions::{BANK1_REGION1, BANK1_REGION2, BANK1_REGION3}; + use crate::_generated::flash_regions::{OTPRegion, BANK1_REGION1, BANK1_REGION2, BANK1_REGION3, OTP_REGION}; use crate::_generated::FLASH_SIZE; use crate::flash::{asynch, Async, Bank1Region1, Bank1Region2, Blocking, Error, Flash, FlashBank, FlashRegion}; use crate::peripherals::FLASH; @@ -62,6 +62,7 @@ mod alt_regions { pub bank2_region1: AltBank2Region1<'d, MODE>, pub bank2_region2: AltBank2Region2<'d, MODE>, pub bank2_region3: AltBank2Region3<'d, MODE>, + pub otp_region: OTPRegion<'d, MODE>, } impl<'d> Flash<'d> { @@ -78,6 +79,7 @@ mod alt_regions { bank2_region1: AltBank2Region1(&ALT_BANK2_REGION1, unsafe { p.clone_unchecked() }, PhantomData), bank2_region2: AltBank2Region2(&ALT_BANK2_REGION2, unsafe { p.clone_unchecked() }, PhantomData), bank2_region3: AltBank2Region3(&ALT_BANK2_REGION3, unsafe { p.clone_unchecked() }, PhantomData), + otp_region: OTPRegion(&OTP_REGION, unsafe { p.clone_unchecked() }, PhantomData), } } @@ -94,6 +96,7 @@ mod alt_regions { bank2_region1: AltBank2Region1(&ALT_BANK2_REGION1, unsafe { p.clone_unchecked() }, PhantomData), bank2_region2: AltBank2Region2(&ALT_BANK2_REGION2, unsafe { p.clone_unchecked() }, PhantomData), bank2_region3: AltBank2Region3(&ALT_BANK2_REGION3, unsafe { p.clone_unchecked() }, PhantomData), + otp_region: OTPRegion(&OTP_REGION, unsafe { p.clone_unchecked() }, PhantomData), } } } diff --git a/embassy-stm32/src/flash/h5.rs b/embassy-stm32/src/flash/h5.rs index 9e131ca2b..d95de2e38 100644 --- a/embassy-stm32/src/flash/h5.rs +++ b/embassy-stm32/src/flash/h5.rs @@ -114,6 +114,7 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E r.set_bksel(match sector.bank { crate::flash::FlashBank::Bank1 => stm32_metapac::flash::vals::NscrBksel::B_0X0, crate::flash::FlashBank::Bank2 => stm32_metapac::flash::vals::NscrBksel::B_0X1, + _ => unreachable!(), }); r.set_snb(sector.index_in_bank); r.set_ser(true); diff --git a/embassy-stm32/src/flash/h50.rs b/embassy-stm32/src/flash/h50.rs index 82e77d130..74cd6cc03 100644 --- a/embassy-stm32/src/flash/h50.rs +++ b/embassy-stm32/src/flash/h50.rs @@ -55,6 +55,7 @@ pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) } pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> { + assert!(sector.bank != FlashBank::Otp); assert!(sector.index_in_bank < 8); while busy() {} @@ -67,6 +68,7 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E (FlashBank::Bank2, true) => Bksel::BANK1, (FlashBank::Bank2, false) => Bksel::BANK2, (FlashBank::Bank1, true) => Bksel::BANK2, + _ => unreachable!(), }); w.set_snb(sector.index_in_bank); w.set_ser(true); diff --git a/embassy-stm32/src/flash/mod.rs b/embassy-stm32/src/flash/mod.rs index b564de093..c7488c8ef 100644 --- a/embassy-stm32/src/flash/mod.rs +++ b/embassy-stm32/src/flash/mod.rs @@ -88,6 +88,8 @@ pub enum FlashBank { Bank1 = 0, /// Bank 2 Bank2 = 1, + /// OTP region, + Otp, } #[cfg_attr(any(flash_l0, flash_l1, flash_l4, flash_l5, flash_wl, flash_wb), path = "l.rs")] diff --git a/embassy-stm32/src/flash/u5.rs b/embassy-stm32/src/flash/u5.rs index e5af4f1f7..dad698316 100644 --- a/embassy-stm32/src/flash/u5.rs +++ b/embassy-stm32/src/flash/u5.rs @@ -75,6 +75,7 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E w.set_bker(match sector.bank { FlashBank::Bank1 => pac::flash::vals::SeccrBker::B_0X0, FlashBank::Bank2 => pac::flash::vals::SeccrBker::B_0X1, + _ => unreachable!(), }); }); #[cfg(not(feature = "trustzone-secure"))] @@ -85,6 +86,7 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E w.set_bker(match sector.bank { FlashBank::Bank1 => pac::flash::vals::NscrBker::B_0X0, FlashBank::Bank2 => pac::flash::vals::NscrBker::B_0X1, + _ => unreachable!(), }); }); From 5e762e8cf41c82c33632d2b01e0644341483b57c Mon Sep 17 00:00:00 2001 From: Rasmus Melchior Jacobsen Date: Tue, 18 Feb 2025 08:43:48 +0100 Subject: [PATCH 0849/1217] Fix compile error in ospi --- embassy-stm32/src/ospi/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/ospi/mod.rs b/embassy-stm32/src/ospi/mod.rs index e35d51c91..5dff3c4c3 100644 --- a/embassy-stm32/src/ospi/mod.rs +++ b/embassy-stm32/src/ospi/mod.rs @@ -372,7 +372,7 @@ impl<'d, T: Instance, M: PeriMode> Ospi<'d, T, M> { }); T::REGS.cr().modify(|w| { - w.set_fthres(vals::Threshold(config.fifo_threshold.into())); + w.set_fthres(vals::Threshold::from_bits(config.fifo_threshold.into())); }); // Wait for busy flag to clear @@ -643,7 +643,7 @@ impl<'d, T: Instance, M: PeriMode> Ospi<'d, T, M> { }); T::REGS.cr().modify(|w| { - w.set_fthres(vals::Threshold(config.fifo_threshold.into())); + w.set_fthres(vals::Threshold::from_bits(config.fifo_threshold.into())); }); // Wait for busy flag to clear From c7e997a8d8b966771dc561bf02abeaf8532fc5d9 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Thu, 20 Mar 2025 11:25:06 +0800 Subject: [PATCH 0850/1217] embassy-net: Add std and alloc features These are passed through to smoltcp, which otherwise won't handle some match cases when managed/std feature is enabled externally. --> .../index.crates.io-1949cf8c6b5b557f/smoltcp-0.12.0/src/iface/socket_set.rs:82:15 | 82 | match &mut self.sockets { | ^^^^^^^^^^^^^^^^^ pattern `&mut ManagedSlice::Owned(_)` not covered --- embassy-net/Cargo.toml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/embassy-net/Cargo.toml b/embassy-net/Cargo.toml index 1e513a9ea..c3bf1acbc 100644 --- a/embassy-net/Cargo.toml +++ b/embassy-net/Cargo.toml @@ -61,6 +61,10 @@ medium-ip = ["smoltcp/medium-ip"] medium-ieee802154 = ["smoltcp/medium-ieee802154"] ## Enable multicast support (for both ipv4 and/or ipv6 if enabled) multicast = ["smoltcp/multicast"] +## Enable smoltcp std feature (necessary if using "managed" crate std feature) +std = ["smoltcp/std"] +## Enable smoltcp alloc feature (necessary if using "managed" crate alloc feature) +alloc = ["smoltcp/alloc"] [dependencies] From a0b948f270bf31373a6b119acad5e9a0752a0609 Mon Sep 17 00:00:00 2001 From: Steven Friedman Date: Wed, 19 Mar 2025 11:45:21 -0400 Subject: [PATCH 0851/1217] define stm32h7rs ethernet pin traits --- embassy-stm32/build.rs | 18 +++++ examples/stm32h7rs/Cargo.toml | 2 +- examples/stm32h7rs/src/bin/eth.rs | 116 ++++++++++++++++++++++++++++++ 3 files changed, 135 insertions(+), 1 deletion(-) create mode 100644 examples/stm32h7rs/src/bin/eth.rs diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index eb0437bc2..8965b312c 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -911,6 +911,24 @@ fn main() { (("eth", "TXD2"), quote!(crate::eth::TXD2Pin)), (("eth", "TXD3"), quote!(crate::eth::TXD3Pin)), (("eth", "TX_EN"), quote!(crate::eth::TXEnPin)), + (("eth", "MII_REF_CLK"), quote!(crate::eth::RefClkPin)), + (("eth", "MII_RX_CLK"), quote!(crate::eth::RXClkPin)), + (("eth", "MII_TX_CLK"), quote!(crate::eth::TXClkPin)), + (("eth", "MII_MDIO"), quote!(crate::eth::MDIOPin)), + (("eth", "MII_MDC"), quote!(crate::eth::MDCPin)), + (("eth", "MII_CRS_DV"), quote!(crate::eth::CRSPin)), + (("eth", "MII_RX_DV"), quote!(crate::eth::RXDVPin)), + (("eth", "MII_RXD0"), quote!(crate::eth::RXD0Pin)), + (("eth", "MII_RXD1"), quote!(crate::eth::RXD1Pin)), + (("eth", "MII_RXD2"), quote!(crate::eth::RXD2Pin)), + (("eth", "MII_RXD3"), quote!(crate::eth::RXD3Pin)), + (("eth", "MII_TXD0"), quote!(crate::eth::TXD0Pin)), + (("eth", "MII_TXD1"), quote!(crate::eth::TXD1Pin)), + (("eth", "MII_TXD2"), quote!(crate::eth::TXD2Pin)), + (("eth", "MII_TXD3"), quote!(crate::eth::TXD3Pin)), + (("eth", "MII_TX_EN"), quote!(crate::eth::TXEnPin)), + (("eth", "RMII_REF_CLK"), quote!(crate::eth::RefClkPin)), + (("eth", "RMII_CRS_DV"), quote!(crate::eth::CRSPin)), (("fmc", "A0"), quote!(crate::fmc::A0Pin)), (("fmc", "A1"), quote!(crate::fmc::A1Pin)), (("fmc", "A2"), quote!(crate::fmc::A2Pin)), diff --git a/examples/stm32h7rs/Cargo.toml b/examples/stm32h7rs/Cargo.toml index 6564fffbf..a47dbe21e 100644 --- a/examples/stm32h7rs/Cargo.toml +++ b/examples/stm32h7rs/Cargo.toml @@ -10,7 +10,7 @@ embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [" embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } -embassy-net = { version = "0.7.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } +embassy-net = { version = "0.7.0", path = "../../embassy-net", features = ["defmt", "udp", "medium-ethernet", "medium-ip", "proto-ipv4"] } embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32h7rs/src/bin/eth.rs b/examples/stm32h7rs/src/bin/eth.rs new file mode 100644 index 000000000..1bb748faa --- /dev/null +++ b/examples/stm32h7rs/src/bin/eth.rs @@ -0,0 +1,116 @@ +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_net::udp::{PacketMetadata, UdpSocket}; +use embassy_net::{Ipv4Cidr, Ipv4Address, StackResources}; +use embassy_stm32::eth::{Ethernet, GenericPhy, PacketQueue}; +use embassy_stm32::peripherals::ETH; +use embassy_stm32::rng::Rng; +use embassy_stm32::{bind_interrupts, eth, peripherals, rng, Config}; +use embassy_time::Timer; +use heapless::Vec; +use rand_core::RngCore; +use static_cell::StaticCell; +use {defmt_rtt as _, panic_probe as _}; + +bind_interrupts!(struct Irqs { + ETH => eth::InterruptHandler; + RNG => rng::InterruptHandler; +}); + +type Device = Ethernet<'static, ETH, GenericPhy>; + +#[embassy_executor::task] +async fn net_task(mut runner: embassy_net::Runner<'static, Device>) -> ! { + runner.run().await +} + +#[embassy_executor::main] +async fn main(spawner: Spawner) -> ! { + let mut config = Config::default(); + { + use embassy_stm32::rcc::*; + config.rcc.hsi = Some(HSIPrescaler::DIV1); + config.rcc.csi = true; + config.rcc.hsi48 = Some(Default::default()); // needed for RNG + config.rcc.pll1 = Some(Pll { + source: PllSource::HSI, + prediv: PllPreDiv::DIV4, + mul: PllMul::MUL50, + divp: Some(PllDiv::DIV2), + divq: None, + divr: None, + }); + config.rcc.sys = Sysclk::PLL1_P; // 400 Mhz + config.rcc.ahb_pre = AHBPrescaler::DIV2; // 200 Mhz + config.rcc.apb1_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.apb2_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.apb5_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.voltage_scale = VoltageScale::HIGH; + } + let p = embassy_stm32::init(config); + info!("Hello World!"); + + // Generate random seed. + let mut rng = Rng::new(p.RNG, Irqs); + let mut seed = [0; 8]; + rng.fill_bytes(&mut seed); + let seed = u64::from_le_bytes(seed); + + let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF]; + + static PACKETS: StaticCell> = StaticCell::new(); + let device = Ethernet::new( + PACKETS.init(PacketQueue::<4, 4>::new()), + p.ETH, + Irqs, + p.PB6, + p.PA2, + p.PG6, + p.PA7, + p.PG4, + p.PG5, + p.PG13, + p.PG12, + p.PG11, + GenericPhy::new(0), + mac_addr, + ); + + // Have to use UDP w/ static config to fit in internal flash + // let config = embassy_net::Config::dhcpv4(Default::default()); + let config = embassy_net::Config::ipv4_static(embassy_net::StaticConfigV4 { + address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24), + dns_servers: Vec::new(), + gateway: Some(Ipv4Address::new(10, 42, 0, 1)), + }); + + // Init network stack + static RESOURCES: StaticCell> = StaticCell::new(); + let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed); + + // Launch network task + unwrap!(spawner.spawn(net_task(runner))); + + // Ensure DHCP configuration is up before trying connect + stack.wait_config_up().await; + + info!("Network task initialized"); + + // Then we can use it! + let mut rx_meta = [PacketMetadata::EMPTY; 16]; + let mut rx_buffer = [0; 1024]; + let mut tx_meta = [PacketMetadata::EMPTY; 16]; + let mut tx_buffer = [0; 1024]; + + let remote_endpoint = (Ipv4Address::new(10, 42, 0, 1), 8000); + let socket = UdpSocket::new(stack, &mut rx_meta, &mut rx_buffer, &mut tx_meta, &mut tx_buffer); + loop { + // You need to start a server on the host machine, for example: `nc -lu 8000` + socket.send_to(b"Hello, world", remote_endpoint).await.expect("Buffer sent"); + Timer::after_secs(1).await; + } +} From 9fd464dc500e628cc6a162fab731f44674ecdf1b Mon Sep 17 00:00:00 2001 From: Steven Friedman Date: Wed, 19 Mar 2025 11:47:57 -0400 Subject: [PATCH 0852/1217] reformat --- examples/stm32h7rs/src/bin/eth.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/examples/stm32h7rs/src/bin/eth.rs b/examples/stm32h7rs/src/bin/eth.rs index 1bb748faa..2f0ef2492 100644 --- a/examples/stm32h7rs/src/bin/eth.rs +++ b/examples/stm32h7rs/src/bin/eth.rs @@ -4,7 +4,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_net::udp::{PacketMetadata, UdpSocket}; -use embassy_net::{Ipv4Cidr, Ipv4Address, StackResources}; +use embassy_net::{Ipv4Address, Ipv4Cidr, StackResources}; use embassy_stm32::eth::{Ethernet, GenericPhy, PacketQueue}; use embassy_stm32::peripherals::ETH; use embassy_stm32::rng::Rng; @@ -76,7 +76,7 @@ async fn main(spawner: Spawner) -> ! { p.PG13, p.PG12, p.PG11, - GenericPhy::new(0), + GenericPhy::new(0), mac_addr, ); @@ -110,7 +110,10 @@ async fn main(spawner: Spawner) -> ! { let socket = UdpSocket::new(stack, &mut rx_meta, &mut rx_buffer, &mut tx_meta, &mut tx_buffer); loop { // You need to start a server on the host machine, for example: `nc -lu 8000` - socket.send_to(b"Hello, world", remote_endpoint).await.expect("Buffer sent"); + socket + .send_to(b"Hello, world", remote_endpoint) + .await + .expect("Buffer sent"); Timer::after_secs(1).await; } } From 1e027d3b61dac659fa7bf28cd3ff604d49bd1e5c Mon Sep 17 00:00:00 2001 From: Steven Friedman Date: Wed, 19 Mar 2025 18:17:43 -0400 Subject: [PATCH 0853/1217] revert changes to build.rs --- embassy-stm32/build.rs | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 8965b312c..eb0437bc2 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -911,24 +911,6 @@ fn main() { (("eth", "TXD2"), quote!(crate::eth::TXD2Pin)), (("eth", "TXD3"), quote!(crate::eth::TXD3Pin)), (("eth", "TX_EN"), quote!(crate::eth::TXEnPin)), - (("eth", "MII_REF_CLK"), quote!(crate::eth::RefClkPin)), - (("eth", "MII_RX_CLK"), quote!(crate::eth::RXClkPin)), - (("eth", "MII_TX_CLK"), quote!(crate::eth::TXClkPin)), - (("eth", "MII_MDIO"), quote!(crate::eth::MDIOPin)), - (("eth", "MII_MDC"), quote!(crate::eth::MDCPin)), - (("eth", "MII_CRS_DV"), quote!(crate::eth::CRSPin)), - (("eth", "MII_RX_DV"), quote!(crate::eth::RXDVPin)), - (("eth", "MII_RXD0"), quote!(crate::eth::RXD0Pin)), - (("eth", "MII_RXD1"), quote!(crate::eth::RXD1Pin)), - (("eth", "MII_RXD2"), quote!(crate::eth::RXD2Pin)), - (("eth", "MII_RXD3"), quote!(crate::eth::RXD3Pin)), - (("eth", "MII_TXD0"), quote!(crate::eth::TXD0Pin)), - (("eth", "MII_TXD1"), quote!(crate::eth::TXD1Pin)), - (("eth", "MII_TXD2"), quote!(crate::eth::TXD2Pin)), - (("eth", "MII_TXD3"), quote!(crate::eth::TXD3Pin)), - (("eth", "MII_TX_EN"), quote!(crate::eth::TXEnPin)), - (("eth", "RMII_REF_CLK"), quote!(crate::eth::RefClkPin)), - (("eth", "RMII_CRS_DV"), quote!(crate::eth::CRSPin)), (("fmc", "A0"), quote!(crate::fmc::A0Pin)), (("fmc", "A1"), quote!(crate::fmc::A1Pin)), (("fmc", "A2"), quote!(crate::fmc::A2Pin)), From 83b70d5847e919421696b40ac6ed7021eb7a4678 Mon Sep 17 00:00:00 2001 From: Steven Friedman Date: Thu, 20 Mar 2025 08:43:35 -0400 Subject: [PATCH 0854/1217] w/ static config, don't need to wait for DHCP --- examples/stm32h7rs/src/bin/eth.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/stm32h7rs/src/bin/eth.rs b/examples/stm32h7rs/src/bin/eth.rs index 2f0ef2492..f2bd9575e 100644 --- a/examples/stm32h7rs/src/bin/eth.rs +++ b/examples/stm32h7rs/src/bin/eth.rs @@ -96,7 +96,7 @@ async fn main(spawner: Spawner) -> ! { unwrap!(spawner.spawn(net_task(runner))); // Ensure DHCP configuration is up before trying connect - stack.wait_config_up().await; + //stack.wait_config_up().await; info!("Network task initialized"); From 1e6192ffa53a4b5ded7abe6ccd052c50383a79d7 Mon Sep 17 00:00:00 2001 From: Tobias Naumann Date: Fri, 21 Mar 2025 11:18:16 +0100 Subject: [PATCH 0855/1217] Add embedded_hal_nb::serial::Read impl for RingBufferedUartRx --- embassy-stm32/src/usart/ringbuffered.rs | 49 +++++++++++++++++++------ 1 file changed, 38 insertions(+), 11 deletions(-) diff --git a/embassy-stm32/src/usart/ringbuffered.rs b/embassy-stm32/src/usart/ringbuffered.rs index ffd4ee544..f1161aa79 100644 --- a/embassy-stm32/src/usart/ringbuffered.rs +++ b/embassy-stm32/src/usart/ringbuffered.rs @@ -133,6 +133,20 @@ impl<'d> RingBufferedUartRx<'d> { compiler_fence(Ordering::SeqCst); } + /// (Re-)start DMA and Uart if it is not running (has not been started yet or has failed), and + /// check for errors in status register. Error flags are cleared in `start_uart()` so they need + /// to be read first without returning yet. + fn start_dma_or_check_errors(&mut self) -> Result<(), Error> { + let r = self.info.regs; + + let sr = clear_idle_flag(r); + let res = check_for_errors(sr); + if !r.cr3().read().dmar() { + self.start_uart(); + } + res + } + /// Read bytes that are readily available in the ring buffer. /// If no bytes are currently available in the buffer the call waits until the some /// bytes are available (at least one byte and at most half the buffer size) @@ -142,17 +156,7 @@ impl<'d> RingBufferedUartRx<'d> { /// Receive in the background is terminated if an error is returned. /// It must then manually be started again by calling `start()` or by re-calling `read()`. pub async fn read(&mut self, buf: &mut [u8]) -> Result { - let r = self.info.regs; - - // (Re-)start DMA and Uart if it is not running (has not been started yet or has failed), - // and check for errors in status register. Error flags are cleared in `start_uart()` so - // they need to be read first without returning yet. - let sr = clear_idle_flag(r); - let res = check_for_errors(sr); - if !r.cr3().read().dmar() { - self.start_uart(); - } - res?; + self.start_dma_or_check_errors()?; loop { match self.ring_buf.read(buf) { @@ -281,6 +285,29 @@ impl embedded_io_async::Read for RingBufferedUartRx<'_> { } } +impl embedded_hal_nb::serial::Read for RingBufferedUartRx<'_> { + fn read(&mut self) -> nb::Result { + self.start_dma_or_check_errors()?; + + let mut buf = [0u8; 1]; + match self.ring_buf.read(&mut buf) { + Ok((0, _)) => Err(nb::Error::WouldBlock), + Ok((len, _)) => { + assert!(len == 1); + Ok(buf[0]) + } + Err(_) => { + self.stop_uart(); + Err(nb::Error::Other(Error::Overrun)) + } + } + } +} + +impl embedded_hal_nb::serial::ErrorType for RingBufferedUartRx<'_> { + type Error = Error; +} + impl ReadReady for RingBufferedUartRx<'_> { fn read_ready(&mut self) -> Result { let len = self.ring_buf.len().map_err(|e| match e { From ac7c44c1d1465bd125ef9a2c6da7e3b42a52569c Mon Sep 17 00:00:00 2001 From: Tobias Naumann Date: Fri, 21 Mar 2025 13:27:29 +0100 Subject: [PATCH 0856/1217] Use write closure to clear idle flag, only read rdr on usart versions which need it --- embassy-stm32/src/usart/ringbuffered.rs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/embassy-stm32/src/usart/ringbuffered.rs b/embassy-stm32/src/usart/ringbuffered.rs index f1161aa79..d76a52d1e 100644 --- a/embassy-stm32/src/usart/ringbuffered.rs +++ b/embassy-stm32/src/usart/ringbuffered.rs @@ -261,14 +261,13 @@ fn clear_idle_flag(r: Regs) -> Sr { let sr = sr(r).read(); - // This read also clears the error and idle interrupt flags on v1. - unsafe { rdr(r).read_volatile() }; #[cfg(any(usart_v3, usart_v4))] - { - let mut clear_idle = regs::Icr(0); - clear_idle.set_idle(true); - r.icr().write_value(clear_idle); - } + r.icr().write(|w| w.set_idle(true)); + #[cfg(not(any(usart_v3, usart_v4)))] + unsafe { + // This read also clears the error and idle interrupt flags on v1. + rdr(r).read_volatile() + }; r.cr1().modify(|w| w.set_idleie(true)); From 402b78138b76ae125bb9be0a336e5d0bc17e7833 Mon Sep 17 00:00:00 2001 From: Tobias Naumann Date: Fri, 21 Mar 2025 14:04:33 +0100 Subject: [PATCH 0857/1217] Check and clear idle and error flags together --- embassy-stm32/src/usart/ringbuffered.rs | 79 ++++++++++++------------- 1 file changed, 39 insertions(+), 40 deletions(-) diff --git a/embassy-stm32/src/usart/ringbuffered.rs b/embassy-stm32/src/usart/ringbuffered.rs index d76a52d1e..3ab9f95e0 100644 --- a/embassy-stm32/src/usart/ringbuffered.rs +++ b/embassy-stm32/src/usart/ringbuffered.rs @@ -99,8 +99,6 @@ impl<'d> RingBufferedUartRx<'d> { // enable idle line interrupt w.set_idleie(true); }); - // Clear all potential error interrupt flags - clear_interrupt_flags(r, sr(r).read()); r.cr3().modify(|w| { // enable Error Interrupt: (Frame error, Noise error, Overrun error) w.set_eie(true); @@ -134,17 +132,15 @@ impl<'d> RingBufferedUartRx<'d> { } /// (Re-)start DMA and Uart if it is not running (has not been started yet or has failed), and - /// check for errors in status register. Error flags are cleared in `start_uart()` so they need - /// to be read first without returning yet. + /// check for errors in status register. Error flags are checked/cleared first. fn start_dma_or_check_errors(&mut self) -> Result<(), Error> { let r = self.info.regs; - let sr = clear_idle_flag(r); - let res = check_for_errors(sr); + check_idle_and_errors(r)?; if !r.cr3().read().dmar() { self.start_uart(); } - res + Ok(()) } /// Read bytes that are readily available in the ring buffer. @@ -191,13 +187,7 @@ impl<'d> RingBufferedUartRx<'d> { compiler_fence(Ordering::SeqCst); - // Critical section is needed so that IDLE isn't set after - // our read but before we clear it. - let sr = critical_section::with(|_| clear_idle_flag(self.info.regs)); - - check_for_errors(sr)?; - - if sr.idle() { + if check_idle_and_errors(self.info.regs)? { // Idle line is detected Poll::Ready(Ok(())) } else { @@ -240,40 +230,49 @@ impl Drop for RingBufferedUartRx<'_> { } } -/// Return an error result if the Sr register has errors -fn check_for_errors(s: Sr) -> Result<(), Error> { - if s.pe() { +/// Check and clear idle and error interrupts, return true if idle, Err(e) on error +/// +/// All flags are read and cleared in a single step, respectively. When more than one flag is set +/// at the same time, all flags will be cleared but only one flag will be reported. So the other +/// flag(s) will gone missing unnoticed. The error flags are checked first, the idle flag last. +/// +/// For usart_v1 and usart_v2, all status flags must be handled together anyway because all flags +/// are cleared by a single read to the RDR register. +fn check_idle_and_errors(r: Regs) -> Result { + // Critical section is required so that the flags aren't set after read and before clear + let sr = critical_section::with(|_| { + // SAFETY: read only and we only use Rx related flags + let sr = sr(r).read(); + + #[cfg(any(usart_v3, usart_v4))] + r.icr().write(|w| { + w.set_idle(true); + w.set_pe(true); + w.set_fe(true); + w.set_ne(true); + w.set_ore(true); + }); + #[cfg(not(any(usart_v3, usart_v4)))] + unsafe { + // This read also clears the error and idle interrupt flags on v1 (TODO and v2?) + rdr(r).read_volatile() + }; + sr + }); + if sr.pe() { Err(Error::Parity) - } else if s.fe() { + } else if sr.fe() { Err(Error::Framing) - } else if s.ne() { + } else if sr.ne() { Err(Error::Noise) - } else if s.ore() { + } else if sr.ore() { Err(Error::Overrun) } else { - Ok(()) + r.cr1().modify(|w| w.set_idleie(true)); + Ok(sr.idle()) } } -/// Clear IDLE and return the Sr register -fn clear_idle_flag(r: Regs) -> Sr { - // SAFETY: read only and we only use Rx related flags - - let sr = sr(r).read(); - - #[cfg(any(usart_v3, usart_v4))] - r.icr().write(|w| w.set_idle(true)); - #[cfg(not(any(usart_v3, usart_v4)))] - unsafe { - // This read also clears the error and idle interrupt flags on v1. - rdr(r).read_volatile() - }; - - r.cr1().modify(|w| w.set_idleie(true)); - - sr -} - impl embedded_io_async::ErrorType for RingBufferedUartRx<'_> { type Error = Error; } From d43acbb22b71e11b1731cbd2f6b4c6f56088d2f4 Mon Sep 17 00:00:00 2001 From: i509VCB Date: Fri, 21 Mar 2025 15:16:27 -0500 Subject: [PATCH 0858/1217] Add missing flavors to docs for mspm0 --- embassy-mspm0/Cargo.toml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/embassy-mspm0/Cargo.toml b/embassy-mspm0/Cargo.toml index cfe0c85a9..b747d270e 100644 --- a/embassy-mspm0/Cargo.toml +++ b/embassy-mspm0/Cargo.toml @@ -14,6 +14,11 @@ src_base = "https://github.com/embassy-rs/embassy/blob/embassy-mspm0-v$VERSION/e src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-mspm0/src/" features = ["defmt", "unstable-pac", "time-driver-any"] +flavors = [ + { regex_feature = "mspm0c.*", target = "thumbv6m-none-eabi" }, + { regex_feature = "mspm0l.*", target = "thumbv6m-none-eabi" }, + { regex_feature = "mspm0g.*", target = "thumbv6m-none-eabi" }, +] [package.metadata.docs.rs] features = ["defmt", "unstable-pac", "time-driver-any", "time", "mspm0g3507"] From 7a031eed66ef27e83b8582e7c1e7ca00d16ccf64 Mon Sep 17 00:00:00 2001 From: Alexander van Saase Date: Fri, 21 Mar 2025 23:02:04 +0100 Subject: [PATCH 0859/1217] Add note about RefCell alternative --- embassy-sync/src/blocking_mutex/mod.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/embassy-sync/src/blocking_mutex/mod.rs b/embassy-sync/src/blocking_mutex/mod.rs index 5b0e4144a..a41bc3569 100644 --- a/embassy-sync/src/blocking_mutex/mod.rs +++ b/embassy-sync/src/blocking_mutex/mod.rs @@ -54,8 +54,11 @@ impl Mutex { /// Creates a critical section and grants temporary mutable access to the protected data. /// /// # Safety - /// This method is unsafe because calling this method when the mutex is already locked, - /// either using this method or `lock`, violates Rust's aliasing rules. + /// + /// This method is marked unsafe because calling this method re-entrantly, i.e. within + /// another `lock_mut` or `lock` closure, violates Rust's aliasing rules. Calling this + /// method at the same time from different tasks is safe. For a safe alternative with + /// mutable access that never causes UB, use a `RefCell` in a `Mutex`. pub unsafe fn lock_mut(&self, f: impl FnOnce(&mut T) -> U) -> U { self.raw.lock(|| { let ptr = self.data.get() as *mut T; From 46a96ff68c7070c11e201f07ff4a21563b976542 Mon Sep 17 00:00:00 2001 From: i509VCB Date: Fri, 21 Mar 2025 19:20:09 -0500 Subject: [PATCH 0860/1217] mspm0: Remove features for which int_group is not implemented in metapac yet These will be readded again when I eliminate int_group manual impls in the near future --- embassy-mspm0/Cargo.toml | 7 ------- embassy-mspm0/src/lib.rs | 7 ------- 2 files changed, 14 deletions(-) diff --git a/embassy-mspm0/Cargo.toml b/embassy-mspm0/Cargo.toml index b747d270e..e63a86103 100644 --- a/embassy-mspm0/Cargo.toml +++ b/embassy-mspm0/Cargo.toml @@ -123,14 +123,7 @@ time-driver-tima1 = ["_time-driver"] #! e.g. in `.cargo/config.toml`. mspm0c110x = [ "mspm0-metapac/mspm0c110x" ] -mspm0g110x = [ "mspm0-metapac/mspm0g110x" ] -mspm0g150x = [ "mspm0-metapac/mspm0g150x" ] -mspm0g151x = [ "mspm0-metapac/mspm0g151x" ] -mspm0g310x = [ "mspm0-metapac/mspm0g310x" ] mspm0g350x = [ "mspm0-metapac/mspm0g350x" ] mspm0g351x = [ "mspm0-metapac/mspm0g351x" ] -mspm0l110x = [ "mspm0-metapac/mspm0l110x" ] -mspm0l122x = [ "mspm0-metapac/mspm0l122x" ] mspm0l130x = [ "mspm0-metapac/mspm0l130x" ] -mspm0l134x = [ "mspm0-metapac/mspm0l134x" ] mspm0l222x = [ "mspm0-metapac/mspm0l222x" ] diff --git a/embassy-mspm0/src/lib.rs b/embassy-mspm0/src/lib.rs index 1191b1010..3128bb3c7 100644 --- a/embassy-mspm0/src/lib.rs +++ b/embassy-mspm0/src/lib.rs @@ -13,16 +13,9 @@ mod time_driver; // Interrupt group handlers. #[cfg_attr(feature = "mspm0c110x", path = "int_group/c110x.rs")] -#[cfg_attr(feature = "mspm0g110x", path = "int_group/g110x.rs")] -#[cfg_attr(feature = "mspm0g150x", path = "int_group/g150x.rs")] -#[cfg_attr(feature = "mspm0g151x", path = "int_group/g151x.rs")] -#[cfg_attr(feature = "mspm0g310x", path = "int_group/g310x.rs")] #[cfg_attr(feature = "mspm0g350x", path = "int_group/g350x.rs")] #[cfg_attr(feature = "mspm0g351x", path = "int_group/g351x.rs")] -#[cfg_attr(feature = "mspm0l110x", path = "int_group/l110x.rs")] -#[cfg_attr(feature = "mspm0l122x", path = "int_group/l122x.rs")] #[cfg_attr(feature = "mspm0l130x", path = "int_group/l130x.rs")] -#[cfg_attr(feature = "mspm0l134x", path = "int_group/l134x.rs")] #[cfg_attr(feature = "mspm0l222x", path = "int_group/l222x.rs")] mod int_group; From 07387ea405b3228b9526d994da94e7d4a73339f7 Mon Sep 17 00:00:00 2001 From: elagil Date: Sat, 22 Mar 2025 11:46:28 +0100 Subject: [PATCH 0861/1217] fix: apply STM32H5 USB errata (OUT transfer delay) --- embassy-stm32/src/usb/usb.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/embassy-stm32/src/usb/usb.rs b/embassy-stm32/src/usb/usb.rs index 24983cf3c..d5cfa1bb8 100644 --- a/embassy-stm32/src/usb/usb.rs +++ b/embassy-stm32/src/usb/usb.rs @@ -7,6 +7,7 @@ use core::task::Poll; use embassy_hal_internal::into_ref; use embassy_sync::waitqueue::AtomicWaker; +use embassy_time::Timer; use embassy_usb_driver as driver; use embassy_usb_driver::{ Direction, EndpointAddress, EndpointAllocError, EndpointError, EndpointInfo, EndpointType, Event, Unsupported, @@ -887,6 +888,16 @@ impl<'d, T: Instance> driver::EndpointOut for Endpoint<'d, T, Out> { }) .await; + // Errata for STM32H5, 2.20.1: + // During OUT transfers, the correct transfer interrupt (CTR) is triggered a little before the last USB SRAM accesses + // have completed. If the software responds quickly to the interrupt, the full buffer contents may not be correct. + // + // Workaround: + // Software should ensure that a small delay is included before accessing the SRAM contents. This delay should be + // 800 ns in Full Speed mode and 6.4 μs in Low Speed mode. + #[cfg(stm32h5)] + Timer::after_nanos(800).await; + RX_COMPLETE[index].store(false, Ordering::Relaxed); if stat == Stat::DISABLED { From 5264d770079633786f6b34d6d656599bfc7efe7d Mon Sep 17 00:00:00 2001 From: elagil Date: Sat, 22 Mar 2025 11:46:38 +0100 Subject: [PATCH 0862/1217] fix: mute by default (UAC1) --- embassy-usb/src/class/uac1/speaker.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-usb/src/class/uac1/speaker.rs b/embassy-usb/src/class/uac1/speaker.rs index 25de25d9c..1ff29088c 100644 --- a/embassy-usb/src/class/uac1/speaker.rs +++ b/embassy-usb/src/class/uac1/speaker.rs @@ -348,7 +348,7 @@ pub struct AudioSettings { impl Default for AudioSettings { fn default() -> Self { AudioSettings { - muted: [true; MAX_AUDIO_CHANNEL_COUNT], + muted: [false; MAX_AUDIO_CHANNEL_COUNT], volume_8q8_db: [MAX_VOLUME_DB * VOLUME_STEPS_PER_DB; MAX_AUDIO_CHANNEL_COUNT], } } From e34b4d69ee101f15f773381ca575a236f6dd452e Mon Sep 17 00:00:00 2001 From: elagil Date: Sat, 22 Mar 2025 11:58:50 +0100 Subject: [PATCH 0863/1217] fix: build --- embassy-stm32/src/usb/usb.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/embassy-stm32/src/usb/usb.rs b/embassy-stm32/src/usb/usb.rs index d5cfa1bb8..f050c00ce 100644 --- a/embassy-stm32/src/usb/usb.rs +++ b/embassy-stm32/src/usb/usb.rs @@ -7,7 +7,6 @@ use core::task::Poll; use embassy_hal_internal::into_ref; use embassy_sync::waitqueue::AtomicWaker; -use embassy_time::Timer; use embassy_usb_driver as driver; use embassy_usb_driver::{ Direction, EndpointAddress, EndpointAllocError, EndpointError, EndpointInfo, EndpointType, Event, Unsupported, @@ -896,7 +895,7 @@ impl<'d, T: Instance> driver::EndpointOut for Endpoint<'d, T, Out> { // Software should ensure that a small delay is included before accessing the SRAM contents. This delay should be // 800 ns in Full Speed mode and 6.4 μs in Low Speed mode. #[cfg(stm32h5)] - Timer::after_nanos(800).await; + embassy_time::Timer::after_nanos(800).await; RX_COMPLETE[index].store(false, Ordering::Relaxed); From 816aa9a06ced95e801f7245f4402ef7a8120045f Mon Sep 17 00:00:00 2001 From: drindr Date: Sun, 23 Mar 2025 00:01:01 +0800 Subject: [PATCH 0864/1217] clean the SAADC's register while dropping --- embassy-nrf/src/saadc.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/embassy-nrf/src/saadc.rs b/embassy-nrf/src/saadc.rs index 70bda9f70..00e2b7402 100644 --- a/embassy-nrf/src/saadc.rs +++ b/embassy-nrf/src/saadc.rs @@ -465,6 +465,10 @@ impl<'d, const N: usize> Drop for Saadc<'d, N> { fn drop(&mut self) { let r = Self::regs(); r.enable().write(|w| w.set_enable(false)); + for i in 0..N { + r.ch(i).pselp().write(|w| w.set_pselp(InputChannel::NC)); + r.ch(i).pseln().write(|w| w.set_pseln(InputChannel::NC)); + } } } From 07da54ec18ce5c8dbd07b3d894665e54b75dbe52 Mon Sep 17 00:00:00 2001 From: i509VCB Date: Fri, 21 Mar 2025 19:18:19 -0500 Subject: [PATCH 0865/1217] mspm0: generate all singletons --- embassy-mspm0/Cargo.toml | 9 +- embassy-mspm0/build.rs | 415 +++++++++++++++++++++++-------- embassy-mspm0/src/lib.rs | 19 ++ embassy-mspm0/src/time_driver.rs | 3 + 4 files changed, 335 insertions(+), 111 deletions(-) diff --git a/embassy-mspm0/Cargo.toml b/embassy-mspm0/Cargo.toml index b747d270e..6aeafe932 100644 --- a/embassy-mspm0/Cargo.toml +++ b/embassy-mspm0/Cargo.toml @@ -45,14 +45,14 @@ cortex-m = "0.7.6" critical-section = "1.2.0" # mspm0-metapac = { version = "" } -mspm0-metapac = { git = "https://github.com/mspm0-rs/mspm0-data-generated/", tag = "mspm0-data-9faa5239a8eab04946086158f2a7fdff5a6a179d" } +mspm0-metapac = { git = "https://github.com/mspm0-rs/mspm0-data-generated/", tag = "mspm0-data-119240dd23ef5748d2a7bef219ca298d37ba604a" } [build-dependencies] proc-macro2 = "1.0.94" quote = "1.0.40" # mspm0-metapac = { version = "", default-features = false, features = ["metadata"] } -mspm0-metapac = { git = "https://github.com/mspm0-rs/mspm0-data-generated/", tag = "mspm0-data-9faa5239a8eab04946086158f2a7fdff5a6a179d", default-features = false, features = ["metadata"] } +mspm0-metapac = { git = "https://github.com/mspm0-rs/mspm0-data-generated/", tag = "mspm0-data-119240dd23ef5748d2a7bef219ca298d37ba604a", default-features = false, features = ["metadata"] } [features] default = ["rt"] @@ -107,7 +107,10 @@ time-driver-timg9 = ["_time-driver"] time-driver-timg10 = ["_time-driver"] ## Use TIMG11 as time driver time-driver-timg11 = ["_time-driver"] -# TODO: Support TIMG12 and TIMG13 +## Use TIMG12 as time driver +time-driver-timg12 = ["_time-driver"] +## Use TIMG13 as time driver +time-driver-timg13 = ["_time-driver"] ## Use TIMG14 as time driver time-driver-timg14 = ["_time-driver"] ## Use TIMA0 as time driver diff --git a/embassy-mspm0/build.rs b/embassy-mspm0/build.rs index 8c6dd4a5c..9025c337a 100644 --- a/embassy-mspm0/build.rs +++ b/embassy-mspm0/build.rs @@ -1,4 +1,5 @@ -use std::collections::HashMap; +use std::cmp::Ordering; +use std::collections::{BTreeSet, HashMap}; use std::io::Write; use std::path::{Path, PathBuf}; use std::process::Command; @@ -23,48 +24,131 @@ fn generate_code() { cfgs.declare_all(&["gpio_pb", "gpio_pc", "int_group1"]); - let mut singletons = Vec::new(); + let mut singletons = get_singletons(&mut cfgs); - // Generate singletons for GPIO pins. To only consider pins available on a family, use the name of - // the pins from the pincm mappings. - for pincm_mapping in METADATA.pincm_mappings.iter() { - singletons.push(pincm_mapping.pin.to_string()); - } + time_driver(&mut singletons, &mut cfgs); - for peri in METADATA.peripherals { - match peri.kind { - // Specially generated. - "gpio" => match peri.name { - "GPIOB" => cfgs.enable("gpio_pb"), - "GPIOC" => cfgs.enable("gpio_pc"), - _ => (), - }, - - // These peripherals are managed internally by the hal. - "iomux" | "cpuss" => {} - - _ => singletons.push(peri.name.to_string()), - } - } - - time_driver(&singletons, &mut cfgs); - - // ======== - // Write singletons let mut g = TokenStream::new(); - let singleton_tokens: Vec<_> = singletons.iter().map(|s| format_ident!("{}", s)).collect(); + g.extend(generate_singletons(&singletons)); + g.extend(generate_pincm_mapping()); + g.extend(generate_pin()); + g.extend(generate_timers()); + g.extend(generate_interrupts()); + g.extend(generate_peripheral_instances()); + g.extend(generate_pin_trait_impls()); - g.extend(quote! { - embassy_hal_internal::peripherals_definition!(#(#singleton_tokens),*); - }); + let out_dir = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); + let out_file = out_dir.join("_generated.rs").to_string_lossy().to_string(); + fs::write(&out_file, g.to_string()).unwrap(); + rustfmt(&out_file); +} - g.extend(quote! { - embassy_hal_internal::peripherals_struct!(#(#singleton_tokens),*); - }); +#[derive(Debug, Clone)] +struct Singleton { + name: String, - // ======== - // Generate GPIO pincm lookup tables. + cfg: Option, +} + +impl PartialEq for Singleton { + fn eq(&self, other: &Self) -> bool { + self.name == other.name + } +} + +impl Eq for Singleton {} + +impl PartialOrd for Singleton { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for Singleton { + fn cmp(&self, other: &Self) -> Ordering { + self.name.cmp(&other.name) + } +} + +fn get_singletons(cfgs: &mut common::CfgSet) -> Vec { + let mut singletons = Vec::::new(); + + for peripheral in METADATA.peripherals { + // Some peripherals do not generate a singleton, but generate a singleton for each pin. + let skip_peripheral_singleton = match peripheral.kind { + "gpio" => { + // Also enable ports that are present. + match peripheral.name { + "GPIOB" => cfgs.enable("gpio_pb"), + "GPIOC" => cfgs.enable("gpio_pc"), + _ => (), + } + + true + } + + // Each channel gets a singleton, handled separately. + "dma" => true, + + // These peripherals do not exist as singletons, and have no signals but are managed + // by the HAL. + "iomux" | "cpuss" => true, + + _ => false, + }; + + if !skip_peripheral_singleton { + singletons.push(Singleton { + name: peripheral.name.to_string(), + cfg: None, + }); + } + + let mut signals = BTreeSet::new(); + + // Pick out each unique signal. There may be multiple instances of each signal due to + // iomux mappings. + for pin in peripheral.pins { + let signal = if peripheral.name.starts_with("GPIO") + || peripheral.name.starts_with("VREF") + || peripheral.name.starts_with("RTC") + { + pin.signal.to_string() + } else { + format!("{}_{}", peripheral.name, pin.signal) + }; + + // We need to rename some signals to become valid Rust identifiers. + let signal = make_valid_identifier(&signal); + signals.insert(signal); + } + + singletons.extend(signals); + } + + // DMA channels get their own singletons + for dma_channel in METADATA.dma_channels.iter() { + singletons.push(Singleton { + name: format!("DMA_CH{}", dma_channel.number), + cfg: None, + }); + } + + // TODO: Remove `/` signals from metapac (PA1/NRST on C110x for example) + singletons.retain(|s| !s.name.contains('/')); + + singletons.sort_by(|a, b| a.name.cmp(&b.name)); + singletons +} + +fn make_valid_identifier(s: &str) -> Singleton { + let name = s.replace('+', "_P").replace("-", "_N"); + + Singleton { name, cfg: None } +} + +fn generate_pincm_mapping() -> TokenStream { let pincms = METADATA.pincm_mappings.iter().map(|mapping| { let port_letter = mapping.pin.strip_prefix("P").unwrap(); let port_base = (port_letter.chars().next().unwrap() as u8 - b'A') * 32; @@ -81,7 +165,7 @@ fn generate_code() { } }); - g.extend(quote! { + quote! { #[doc = "Get the mapping from GPIO pin port to IOMUX PINCM index. This is required since the mapping from IO to PINCM index is not consistent across parts."] pub(crate) fn gpio_pincm(pin_port: u8) -> u8 { match pin_port { @@ -89,9 +173,11 @@ fn generate_code() { _ => unreachable!(), } } - }); + } +} - for pincm_mapping in METADATA.pincm_mappings.iter() { +fn generate_pin() -> TokenStream { + let pin_impls = METADATA.pincm_mappings.iter().map(|pincm_mapping| { let name = Ident::new(&pincm_mapping.pin, Span::call_site()); let port_letter = pincm_mapping.pin.strip_prefix("P").unwrap(); let port_letter = port_letter.chars().next().unwrap(); @@ -101,78 +187,19 @@ fn generate_code() { // TODO: Feature gate pins that can be used as NRST - g.extend(quote! { + quote! { impl_pin!(#name, crate::gpio::Port::#port, #pin_number); - }); - } - - // Generate timers - for peripheral in METADATA.peripherals.iter().filter(|p| p.name.starts_with("TIM")) { - let name = Ident::new(&peripheral.name, Span::call_site()); - let timers = &*TIMERS; - - let timer = timers.get(peripheral.name).expect("Timer does not exist"); - assert!(timer.bits == 16 || timer.bits == 32); - let bits = if timer.bits == 16 { - quote! { Bits16 } - } else { - quote! { Bits32 } - }; - - g.extend(quote! { - impl_timer!(#name, #bits); - }); - } - - // Generate interrupt module - let interrupts: Vec = METADATA - .interrupts - .iter() - .map(|interrupt| Ident::new(interrupt.name, Span::call_site())) - .collect(); - - g.extend(quote! { - embassy_hal_internal::interrupt_mod! { - #(#interrupts),* } }); - let group_interrupt_enables = METADATA - .interrupts - .iter() - .filter(|interrupt| interrupt.name.contains("GROUP")) - .map(|interrupt| { - let name = Ident::new(interrupt.name, Span::call_site()); - - quote! { - crate::interrupt::typelevel::#name::enable(); - } - }); - - // Generate interrupt enables for groups - g.extend(quote! { - pub fn enable_group_interrupts(_cs: critical_section::CriticalSection) { - use crate::interrupt::typelevel::Interrupt; - - unsafe { - #(#group_interrupt_enables)* - } - } - }); - - let out_dir = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); - let out_file = out_dir.join("_generated.rs").to_string_lossy().to_string(); - fs::write(&out_file, g.to_string()).unwrap(); - rustfmt(&out_file); + quote! { + #(#pin_impls)* + } } -fn time_driver(singletons: &[String], cfgs: &mut CfgSet) { +fn time_driver(singletons: &mut Vec, cfgs: &mut CfgSet) { // Timer features - for (timer, desc) in TIMERS.iter() { - if desc.bits != 16 { - continue; - } - + for (timer, _) in TIMERS.iter() { let name = timer.to_lowercase(); cfgs.declare(&format!("time_driver_{}", name)); } @@ -192,7 +219,7 @@ fn time_driver(singletons: &[String], cfgs: &mut CfgSet) { }; // Verify the selected timer is available - let singleton = match time_driver.as_ref().map(|x| x.as_ref()) { + let selected_timer = match time_driver.as_ref().map(|x| x.as_ref()) { None => "", Some("timg0") => "TIMG0", Some("timg1") => "TIMG1", @@ -228,14 +255,186 @@ fn time_driver(singletons: &[String], cfgs: &mut CfgSet) { "TIMA0", "TIMA1", ] .iter() - .find(|tim| singletons.contains(&tim.to_string())) + .find(|tim| singletons.iter().any(|s| s.name == **tim)) .expect("Could not find any timer") } _ => panic!("unknown time_driver {:?}", time_driver), }; - if !singleton.is_empty() { - cfgs.enable(format!("time_driver_{}", singleton.to_lowercase())); + if !selected_timer.is_empty() { + cfgs.enable(format!("time_driver_{}", selected_timer.to_lowercase())); + } + + // Apply cfgs to each timer and it's pins + for singleton in singletons.iter_mut() { + if singleton.name.starts_with("TIM") { + // Remove suffixes for pin singletons. + let name = if singleton.name.contains("_CCP") { + singleton.name.split_once("_CCP").unwrap().0 + } else if singleton.name.contains("_FAULT") { + singleton.name.split_once("_FAULT").unwrap().0 + } else if singleton.name.contains("_IDX") { + singleton.name.split_once("_IDX").unwrap().0 + } else { + &singleton.name + }; + + let feature = format!("time-driver-{}", name.to_lowercase()); + + if singleton.name.contains(selected_timer) { + singleton.cfg = Some(quote! { #[cfg(not(all(feature = "time-driver-any", feature = #feature)))] }); + } else { + singleton.cfg = Some(quote! { #[cfg(not(feature = #feature))] }); + } + } + } +} + +fn generate_singletons(singletons: &[Singleton]) -> TokenStream { + let singletons = singletons + .iter() + .map(|s| { + let cfg = s.cfg.clone().unwrap_or_default(); + + let ident = format_ident!("{}", s.name); + + quote! { + #cfg + #ident + } + }) + .collect::>(); + + quote! { + embassy_hal_internal::peripherals_definition!(#(#singletons),*); + embassy_hal_internal::peripherals_struct!(#(#singletons),*); + } +} + +fn generate_timers() -> TokenStream { + // Generate timers + let timer_impls = METADATA + .peripherals + .iter() + .filter(|p| p.name.starts_with("TIM")) + .map(|peripheral| { + let name = Ident::new(&peripheral.name, Span::call_site()); + let timers = &*TIMERS; + + let timer = timers.get(peripheral.name).expect("Timer does not exist"); + assert!(timer.bits == 16 || timer.bits == 32); + let bits = if timer.bits == 16 { + quote! { Bits16 } + } else { + quote! { Bits32 } + }; + + quote! { + impl_timer!(#name, #bits); + } + }); + + quote! { + #(#timer_impls)* + } +} + +fn generate_interrupts() -> TokenStream { + // Generate interrupt module + let interrupts: Vec = METADATA + .interrupts + .iter() + .map(|interrupt| Ident::new(interrupt.name, Span::call_site())) + .collect(); + + let group_interrupt_enables = METADATA + .interrupts + .iter() + .filter(|interrupt| interrupt.name.contains("GROUP")) + .map(|interrupt| { + let name = Ident::new(interrupt.name, Span::call_site()); + + quote! { + crate::interrupt::typelevel::#name::enable(); + } + }); + + // Generate interrupt enables for groups + quote! { + embassy_hal_internal::interrupt_mod! { + #(#interrupts),* + } + + pub fn enable_group_interrupts(_cs: critical_section::CriticalSection) { + use crate::interrupt::typelevel::Interrupt; + + unsafe { + #(#group_interrupt_enables)* + } + } + } +} + +fn generate_peripheral_instances() -> TokenStream { + let mut impls = Vec::::new(); + + for peripheral in METADATA.peripherals { + let peri = format_ident!("{}", peripheral.name); + + // Will be filled in when uart implementation is finished + let _ = peri; + let tokens = match peripheral.kind { + // "uart" => Some(quote! { impl_uart_instance!(#peri); }), + _ => None, + }; + + if let Some(tokens) = tokens { + impls.push(tokens); + } + } + + quote! { + #(#impls)* + } +} + +fn generate_pin_trait_impls() -> TokenStream { + let mut impls = Vec::::new(); + + for peripheral in METADATA.peripherals { + for pin in peripheral.pins { + // TODO: Remove `/` signals from metapac (PA1/NRST on C110x for example) + if pin.pin.contains('/') { + continue; + } + + let key = (peripheral.kind, pin.signal); + + let pin_name = format_ident!("{}", pin.pin); + let peri = format_ident!("{}", peripheral.name); + let pf = pin.pf; + + // Will be filled in when uart implementation is finished + let _ = pin_name; + let _ = peri; + let _ = pf; + + let tokens = match key { + // ("uart", "TX") => Some(quote! { impl_uart_tx_pin!(#peri, #pin_name, #pf); }), + // ("uart", "RX") => Some(quote! { impl_uart_rx_pin!(#peri, #pin_name, #pf); }), + // ("uart", "CTS") => Some(quote! { impl_uart_cts_pin!(#peri, #pin_name, #pf); }), + // ("uart", "RTS") => Some(quote! { impl_uart_rts_pin!(#peri, #pin_name, #pf); }), + _ => None, + }; + + if let Some(tokens) = tokens { + impls.push(tokens); + } + } + } + + quote! { + #(#impls)* } } diff --git a/embassy-mspm0/src/lib.rs b/embassy-mspm0/src/lib.rs index 1191b1010..f13245453 100644 --- a/embassy-mspm0/src/lib.rs +++ b/embassy-mspm0/src/lib.rs @@ -8,6 +8,25 @@ pub(crate) mod fmt; pub mod gpio; pub mod timer; +/// Operating modes for peripherals. +pub mod mode { + trait SealedMode {} + + /// Operating mode for a peripheral. + #[allow(private_bounds)] + pub trait Mode: SealedMode {} + + /// Blocking mode. + pub struct Blocking; + impl SealedMode for Blocking {} + impl Mode for Blocking {} + + /// Async mode. + pub struct Async; + impl SealedMode for Async {} + impl Mode for Async {} +} + #[cfg(feature = "_time-driver")] mod time_driver; diff --git a/embassy-mspm0/src/time_driver.rs b/embassy-mspm0/src/time_driver.rs index 937ce58d4..e80e89e55 100644 --- a/embassy-mspm0/src/time_driver.rs +++ b/embassy-mspm0/src/time_driver.rs @@ -12,6 +12,9 @@ use mspm0_metapac::tim::{Counterregs16, Tim}; use crate::peripherals; use crate::timer::SealedTimer; +#[cfg(any(time_driver_timg12, time_driver_timg13))] +compile_error!("TIMG12 and TIMG13 are not supported by the time driver yet"); + // Currently TIMG12 and TIMG13 are excluded because those are 32-bit timers. #[cfg(time_driver_timg0)] type T = peripherals::TIMG0; From 73c0bad8ad398c072215c8ff4382dffbe1a6a057 Mon Sep 17 00:00:00 2001 From: i509VCB Date: Sat, 22 Mar 2025 19:27:52 -0500 Subject: [PATCH 0866/1217] mspm0: remove todo comment about pin names with slash these are now gone from metapac --- embassy-mspm0/build.rs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/embassy-mspm0/build.rs b/embassy-mspm0/build.rs index 9025c337a..39d8b2f8a 100644 --- a/embassy-mspm0/build.rs +++ b/embassy-mspm0/build.rs @@ -135,9 +135,6 @@ fn get_singletons(cfgs: &mut common::CfgSet) -> Vec { }); } - // TODO: Remove `/` signals from metapac (PA1/NRST on C110x for example) - singletons.retain(|s| !s.name.contains('/')); - singletons.sort_by(|a, b| a.name.cmp(&b.name)); singletons } @@ -403,11 +400,6 @@ fn generate_pin_trait_impls() -> TokenStream { for peripheral in METADATA.peripherals { for pin in peripheral.pins { - // TODO: Remove `/` signals from metapac (PA1/NRST on C110x for example) - if pin.pin.contains('/') { - continue; - } - let key = (peripheral.kind, pin.signal); let pin_name = format_ident!("{}", pin.pin); From 15394ae5fa9b8e3490fa7a600382ef549bff8f02 Mon Sep 17 00:00:00 2001 From: elagil Date: Mon, 24 Mar 2025 19:49:44 +0100 Subject: [PATCH 0867/1217] fix(usb): blocking wait --- embassy-stm32/src/usb/usb.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/src/usb/usb.rs b/embassy-stm32/src/usb/usb.rs index f050c00ce..6682374d3 100644 --- a/embassy-stm32/src/usb/usb.rs +++ b/embassy-stm32/src/usb/usb.rs @@ -895,7 +895,7 @@ impl<'d, T: Instance> driver::EndpointOut for Endpoint<'d, T, Out> { // Software should ensure that a small delay is included before accessing the SRAM contents. This delay should be // 800 ns in Full Speed mode and 6.4 μs in Low Speed mode. #[cfg(stm32h5)] - embassy_time::Timer::after_nanos(800).await; + embassy_time::block_for(embassy_time::Duration::from_nanos(800)); RX_COMPLETE[index].store(false, Ordering::Relaxed); From eff9168846df1b0b4fa2be75e061c63c2bb8c942 Mon Sep 17 00:00:00 2001 From: Bailey Quarters Date: Mon, 24 Mar 2025 19:53:36 +0100 Subject: [PATCH 0868/1217] Make CDC ACM state constructor `const` --- embassy-usb/src/class/cdc_acm.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/embassy-usb/src/class/cdc_acm.rs b/embassy-usb/src/class/cdc_acm.rs index c5b1a56fe..ea9d9fb7b 100644 --- a/embassy-usb/src/class/cdc_acm.rs +++ b/embassy-usb/src/class/cdc_acm.rs @@ -47,10 +47,10 @@ impl<'a> Default for State<'a> { impl<'a> State<'a> { /// Create a new `State`. - pub fn new() -> Self { + pub const fn new() -> Self { Self { control: MaybeUninit::uninit(), - shared: ControlShared::default(), + shared: ControlShared::new(), } } } @@ -92,6 +92,12 @@ struct ControlShared { impl Default for ControlShared { fn default() -> Self { + Self::new() + } +} + +impl ControlShared { + const fn new() -> Self { ControlShared { dtr: AtomicBool::new(false), rts: AtomicBool::new(false), @@ -105,9 +111,7 @@ impl Default for ControlShared { changed: AtomicBool::new(false), } } -} -impl ControlShared { fn changed(&self) -> impl Future + '_ { poll_fn(|cx| { if self.changed.load(Ordering::Relaxed) { From 3e63a2e5df6e720c1582e32492d3d9302e34bc29 Mon Sep 17 00:00:00 2001 From: John Kjellberg Date: Tue, 25 Mar 2025 11:10:51 +0100 Subject: [PATCH 0869/1217] Clarified ADC API documentation for some STM32s. --- embassy-stm32/src/adc/v3.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs index fc20974dd..7a608a44e 100644 --- a/embassy-stm32/src/adc/v3.rs +++ b/embassy-stm32/src/adc/v3.rs @@ -262,6 +262,9 @@ impl<'d, T: Instance> Adc<'d, T> { /// /// `sequence` iterator and `readings` must have the same length. /// + /// Note: The order of values in `readings` is defined by the pin ADC + /// channel number and not the pin order in `sequence`. + /// /// Example /// ```rust,ignore /// use embassy_stm32::adc::{Adc, AdcChannel} From f007b53db3b850e1186f9cde26160951b14ba2e7 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 25 Mar 2025 20:33:47 +0100 Subject: [PATCH 0870/1217] stm32/dac: dedup pin and DMA traits, demacrofify. --- embassy-stm32/build.rs | 17 +-- embassy-stm32/src/dac/mod.rs | 220 ++++++++++++++++++----------------- 2 files changed, 115 insertions(+), 122 deletions(-) diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index eb0437bc2..8ca79eadf 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -1151,6 +1151,8 @@ fn main() { (("tsc", "G8_IO2"), quote!(crate::tsc::G8IO2Pin)), (("tsc", "G8_IO3"), quote!(crate::tsc::G8IO3Pin)), (("tsc", "G8_IO4"), quote!(crate::tsc::G8IO4Pin)), + (("dac", "OUT1"), quote!(crate::dac::DacPin)), + (("dac", "OUT2"), quote!(crate::dac::DacPin)), ].into(); for p in METADATA.peripherals { @@ -1250,17 +1252,6 @@ fn main() { } } - // DAC is special - if regs.kind == "dac" { - let peri = format_ident!("{}", p.name); - let pin_name = format_ident!("{}", pin.pin); - let ch: u8 = pin.signal.strip_prefix("OUT").unwrap().parse().unwrap(); - - g.extend(quote! { - impl_dac_pin!( #peri, #pin_name, #ch); - }) - } - if regs.kind == "spdifrx" { let peri = format_ident!("{}", p.name); let pin_name = format_ident!("{}", pin.pin); @@ -1304,8 +1295,8 @@ fn main() { (("quadspi", "QUADSPI"), quote!(crate::qspi::QuadDma)), (("octospi", "OCTOSPI1"), quote!(crate::ospi::OctoDma)), (("hspi", "HSPI1"), quote!(crate::hspi::HspiDma)), - (("dac", "CH1"), quote!(crate::dac::DacDma1)), - (("dac", "CH2"), quote!(crate::dac::DacDma2)), + (("dac", "CH1"), quote!(crate::dac::Dma)), + (("dac", "CH2"), quote!(crate::dac::Dma)), (("timer", "UP"), quote!(crate::timer::UpDma)), (("hash", "IN"), quote!(crate::hash::Dma)), (("cryp", "IN"), quote!(crate::cryp::DmaIn)), diff --git a/embassy-stm32/src/dac/mod.rs b/embassy-stm32/src/dac/mod.rs index 8bba5ded0..4406f2960 100644 --- a/embassy-stm32/src/dac/mod.rs +++ b/embassy-stm32/src/dac/mod.rs @@ -100,20 +100,18 @@ pub enum ValueArray<'a> { /// /// If you want to use both channels, either together or independently, /// create a [`Dac`] first and use it to access each channel. -pub struct DacChannel<'d, T: Instance, const N: u8, DMA = NoDma> { - phantom: PhantomData<&'d mut T>, +pub struct DacChannel<'d, T: Instance, C: Channel, DMA = NoDma> { + phantom: PhantomData<&'d mut (T, C)>, #[allow(unused)] dma: PeripheralRef<'d, DMA>, } /// DAC channel 1 type alias. -pub type DacCh1<'d, T, DMA = NoDma> = DacChannel<'d, T, 1, DMA>; +pub type DacCh1<'d, T, DMA = NoDma> = DacChannel<'d, T, Ch1, DMA>; /// DAC channel 2 type alias. -pub type DacCh2<'d, T, DMA = NoDma> = DacChannel<'d, T, 2, DMA>; - -impl<'d, T: Instance, const N: u8, DMA> DacChannel<'d, T, N, DMA> { - const IDX: usize = (N - 1) as usize; +pub type DacCh2<'d, T, DMA = NoDma> = DacChannel<'d, T, Ch2, DMA>; +impl<'d, T: Instance, C: Channel, DMA> DacChannel<'d, T, C, DMA> { /// Create a new `DacChannel` instance, consuming the underlying DAC peripheral. /// /// If you're not using DMA, pass [`dma::NoDma`] for the `dma` argument. @@ -127,7 +125,7 @@ impl<'d, T: Instance, const N: u8, DMA> DacChannel<'d, T, N, DMA> { pub fn new( _peri: impl Peripheral

+ 'd, dma: impl Peripheral

+ 'd, - pin: impl Peripheral

+ crate::gpio::Pin> + 'd, + pin: impl Peripheral

+ crate::gpio::Pin> + 'd, ) -> Self { into_ref!(dma, pin); pin.set_as_analog(); @@ -173,7 +171,7 @@ impl<'d, T: Instance, const N: u8, DMA> DacChannel<'d, T, N, DMA> { pub fn set_enable(&mut self, on: bool) { critical_section::with(|_| { T::regs().cr().modify(|reg| { - reg.set_en(Self::IDX, on); + reg.set_en(C::IDX, on); }); }); } @@ -194,8 +192,8 @@ impl<'d, T: Instance, const N: u8, DMA> DacChannel<'d, T, N, DMA> { pub fn set_trigger(&mut self, source: TriggerSel) { critical_section::with(|_| { T::regs().cr().modify(|reg| { - reg.set_en(Self::IDX, false); - reg.set_tsel(Self::IDX, source as u8); + reg.set_en(C::IDX, false); + reg.set_tsel(C::IDX, source as u8); }); }); } @@ -204,7 +202,7 @@ impl<'d, T: Instance, const N: u8, DMA> DacChannel<'d, T, N, DMA> { pub fn set_triggering(&mut self, on: bool) { critical_section::with(|_| { T::regs().cr().modify(|reg| { - reg.set_ten(Self::IDX, on); + reg.set_ten(C::IDX, on); }); }); } @@ -212,7 +210,7 @@ impl<'d, T: Instance, const N: u8, DMA> DacChannel<'d, T, N, DMA> { /// Software trigger this channel. pub fn trigger(&mut self) { T::regs().swtrigr().write(|reg| { - reg.set_swtrig(Self::IDX, true); + reg.set_swtrig(C::IDX, true); }); } @@ -223,10 +221,10 @@ impl<'d, T: Instance, const N: u8, DMA> DacChannel<'d, T, N, DMA> { pub fn set_mode(&mut self, mode: Mode) { critical_section::with(|_| { T::regs().cr().modify(|reg| { - reg.set_en(Self::IDX, false); + reg.set_en(C::IDX, false); }); T::regs().mcr().modify(|reg| { - reg.set_mode(Self::IDX, mode.mode()); + reg.set_mode(C::IDX, mode.mode()); }); }); } @@ -237,15 +235,15 @@ impl<'d, T: Instance, const N: u8, DMA> DacChannel<'d, T, N, DMA> { /// it will be output after the next trigger. pub fn set(&mut self, value: Value) { match value { - Value::Bit8(v) => T::regs().dhr8r(Self::IDX).write(|reg| reg.set_dhr(v)), - Value::Bit12Left(v) => T::regs().dhr12l(Self::IDX).write(|reg| reg.set_dhr(v)), - Value::Bit12Right(v) => T::regs().dhr12r(Self::IDX).write(|reg| reg.set_dhr(v)), + Value::Bit8(v) => T::regs().dhr8r(C::IDX).write(|reg| reg.set_dhr(v)), + Value::Bit12Left(v) => T::regs().dhr12l(C::IDX).write(|reg| reg.set_dhr(v)), + Value::Bit12Right(v) => T::regs().dhr12r(C::IDX).write(|reg| reg.set_dhr(v)), } } /// Read the current output value of the DAC. pub fn read(&self) -> u16 { - T::regs().dor(Self::IDX).read().dor() + T::regs().dor(C::IDX).read().dor() } /// Set HFSEL as appropriate for the current peripheral clock frequency. @@ -277,84 +275,75 @@ impl<'d, T: Instance, const N: u8, DMA> DacChannel<'d, T, N, DMA> { }); } } + + /// Write `data` to this channel via DMA. + /// + /// To prevent delays or glitches when outputing a periodic waveform, the `circular` + /// flag can be set. This configures a circular DMA transfer that continually outputs + /// `data`. Note that for performance reasons in circular mode the transfer-complete + /// interrupt is disabled. + #[cfg(not(gpdma))] + pub async fn write(&mut self, data: ValueArray<'_>, circular: bool) + where + DMA: Dma, + { + // Enable DAC and DMA + T::regs().cr().modify(|w| { + w.set_en(C::IDX, true); + w.set_dmaen(C::IDX, true); + }); + + let tx_request = self.dma.request(); + let dma_channel = &mut self.dma; + + let tx_options = crate::dma::TransferOptions { + circular, + half_transfer_ir: false, + complete_transfer_ir: !circular, + ..Default::default() + }; + + // Initiate the correct type of DMA transfer depending on what data is passed + let tx_f = match data { + ValueArray::Bit8(buf) => unsafe { + crate::dma::Transfer::new_write( + dma_channel, + tx_request, + buf, + T::regs().dhr8r(C::IDX).as_ptr() as *mut u8, + tx_options, + ) + }, + ValueArray::Bit12Left(buf) => unsafe { + crate::dma::Transfer::new_write( + dma_channel, + tx_request, + buf, + T::regs().dhr12l(C::IDX).as_ptr() as *mut u16, + tx_options, + ) + }, + ValueArray::Bit12Right(buf) => unsafe { + crate::dma::Transfer::new_write( + dma_channel, + tx_request, + buf, + T::regs().dhr12r(C::IDX).as_ptr() as *mut u16, + tx_options, + ) + }, + }; + + tx_f.await; + + T::regs().cr().modify(|w| { + w.set_en(C::IDX, false); + w.set_dmaen(C::IDX, false); + }); + } } -macro_rules! impl_dma_methods { - ($n:literal, $trait:ident) => { - impl<'d, T: Instance, DMA> DacChannel<'d, T, $n, DMA> - where - DMA: $trait, - { - /// Write `data` to this channel via DMA. - /// - /// To prevent delays or glitches when outputing a periodic waveform, the `circular` - /// flag can be set. This configures a circular DMA transfer that continually outputs - /// `data`. Note that for performance reasons in circular mode the transfer-complete - /// interrupt is disabled. - #[cfg(not(gpdma))] - pub async fn write(&mut self, data: ValueArray<'_>, circular: bool) { - // Enable DAC and DMA - T::regs().cr().modify(|w| { - w.set_en(Self::IDX, true); - w.set_dmaen(Self::IDX, true); - }); - - let tx_request = self.dma.request(); - let dma_channel = &mut self.dma; - - let tx_options = crate::dma::TransferOptions { - circular, - half_transfer_ir: false, - complete_transfer_ir: !circular, - ..Default::default() - }; - - // Initiate the correct type of DMA transfer depending on what data is passed - let tx_f = match data { - ValueArray::Bit8(buf) => unsafe { - crate::dma::Transfer::new_write( - dma_channel, - tx_request, - buf, - T::regs().dhr8r(Self::IDX).as_ptr() as *mut u8, - tx_options, - ) - }, - ValueArray::Bit12Left(buf) => unsafe { - crate::dma::Transfer::new_write( - dma_channel, - tx_request, - buf, - T::regs().dhr12l(Self::IDX).as_ptr() as *mut u16, - tx_options, - ) - }, - ValueArray::Bit12Right(buf) => unsafe { - crate::dma::Transfer::new_write( - dma_channel, - tx_request, - buf, - T::regs().dhr12r(Self::IDX).as_ptr() as *mut u16, - tx_options, - ) - }, - }; - - tx_f.await; - - T::regs().cr().modify(|w| { - w.set_en(Self::IDX, false); - w.set_dmaen(Self::IDX, false); - }); - } - } - }; -} - -impl_dma_methods!(1, DacDma1); -impl_dma_methods!(2, DacDma2); - -impl<'d, T: Instance, const N: u8, DMA> Drop for DacChannel<'d, T, N, DMA> { +impl<'d, T: Instance, C: Channel, DMA> Drop for DacChannel<'d, T, C, DMA> { fn drop(&mut self) { rcc::disable::(); } @@ -371,8 +360,8 @@ impl<'d, T: Instance, const N: u8, DMA> Drop for DacChannel<'d, T, N, DMA> { /// let (dac_ch1, dac_ch2) = embassy_stm32::dac::Dac::new(p.DAC1, NoDma, NoDma, p.PA4, p.PA5).split(); /// ``` pub struct Dac<'d, T: Instance, DMACh1 = NoDma, DMACh2 = NoDma> { - ch1: DacChannel<'d, T, 1, DMACh1>, - ch2: DacChannel<'d, T, 2, DMACh2>, + ch1: DacChannel<'d, T, Ch1, DMACh1>, + ch2: DacChannel<'d, T, Ch2, DMACh2>, } impl<'d, T: Instance, DMACh1, DMACh2> Dac<'d, T, DMACh1, DMACh2> { @@ -392,8 +381,8 @@ impl<'d, T: Instance, DMACh1, DMACh2> Dac<'d, T, DMACh1, DMACh2> { _peri: impl Peripheral

+ 'd, dma_ch1: impl Peripheral

+ 'd, dma_ch2: impl Peripheral

+ 'd, - pin_ch1: impl Peripheral

+ crate::gpio::Pin> + 'd, - pin_ch2: impl Peripheral

+ crate::gpio::Pin> + 'd, + pin_ch1: impl Peripheral

+ crate::gpio::Pin> + 'd, + pin_ch2: impl Peripheral

+ crate::gpio::Pin> + 'd, ) -> Self { into_ref!(dma_ch1, dma_ch2, pin_ch1, pin_ch2); pin_ch1.set_as_analog(); @@ -514,11 +503,30 @@ trait SealedInstance { /// DAC instance. #[allow(private_bounds)] pub trait Instance: SealedInstance + RccPeripheral + 'static {} -dma_trait!(DacDma1, Instance); -dma_trait!(DacDma2, Instance); -/// Marks a pin that can be used with the DAC -pub trait DacPin: crate::gpio::Pin + 'static {} +/// Channel 1 marker type. +pub enum Ch1 {} +/// Channel 2 marker type. +pub enum Ch2 {} + +trait SealedChannel { + const IDX: usize; +} +/// DAC channel trait. +#[allow(private_bounds)] +pub trait Channel: SealedChannel {} + +impl SealedChannel for Ch1 { + const IDX: usize = 0; +} +impl SealedChannel for Ch2 { + const IDX: usize = 1; +} +impl Channel for Ch1 {} +impl Channel for Ch2 {} + +dma_trait!(Dma, Instance, Channel); +pin_trait!(DacPin, Instance, Channel); foreach_peripheral!( (dac, $inst:ident) => { @@ -531,9 +539,3 @@ foreach_peripheral!( impl crate::dac::Instance for peripherals::$inst {} }; ); - -macro_rules! impl_dac_pin { - ($inst:ident, $pin:ident, $ch:expr) => { - impl crate::dac::DacPin for crate::peripherals::$pin {} - }; -} From 73ec3a7506f48bc76bc462a83213992436b55eb7 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 25 Mar 2025 21:31:28 +0100 Subject: [PATCH 0871/1217] stm32/dac: remove DMA generic params. --- embassy-stm32/src/dac/mod.rs | 332 +++++++++++++++++----------- examples/stm32f4/src/bin/dac.rs | 3 +- examples/stm32h7/src/bin/dac.rs | 3 +- examples/stm32h7/src/bin/dac_dma.rs | 7 +- examples/stm32l4/src/bin/dac.rs | 3 +- examples/stm32l4/src/bin/dac_dma.rs | 7 +- examples/stm32u0/src/bin/dac.rs | 3 +- tests/stm32/src/bin/dac.rs | 3 +- tests/stm32/src/bin/dac_l1.rs | 3 +- 9 files changed, 215 insertions(+), 149 deletions(-) diff --git a/embassy-stm32/src/dac/mod.rs b/embassy-stm32/src/dac/mod.rs index 4406f2960..7a63dc5fc 100644 --- a/embassy-stm32/src/dac/mod.rs +++ b/embassy-stm32/src/dac/mod.rs @@ -3,9 +3,10 @@ use core::marker::PhantomData; -use embassy_hal_internal::{into_ref, PeripheralRef}; +use embassy_hal_internal::into_ref; -use crate::dma::NoDma; +use crate::dma::ChannelAndRequest; +use crate::mode::{Async, Blocking, Mode as PeriMode}; #[cfg(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7))] use crate::pac::dac; use crate::rcc::{self, RccPeripheral}; @@ -100,22 +101,20 @@ pub enum ValueArray<'a> { /// /// If you want to use both channels, either together or independently, /// create a [`Dac`] first and use it to access each channel. -pub struct DacChannel<'d, T: Instance, C: Channel, DMA = NoDma> { - phantom: PhantomData<&'d mut (T, C)>, +pub struct DacChannel<'d, T: Instance, C: Channel, M: PeriMode> { + phantom: PhantomData<&'d mut (T, C, M)>, #[allow(unused)] - dma: PeripheralRef<'d, DMA>, + dma: Option>, } /// DAC channel 1 type alias. -pub type DacCh1<'d, T, DMA = NoDma> = DacChannel<'d, T, Ch1, DMA>; +pub type DacCh1<'d, T, M> = DacChannel<'d, T, Ch1, M>; /// DAC channel 2 type alias. -pub type DacCh2<'d, T, DMA = NoDma> = DacChannel<'d, T, Ch2, DMA>; +pub type DacCh2<'d, T, M> = DacChannel<'d, T, Ch2, M>; -impl<'d, T: Instance, C: Channel, DMA> DacChannel<'d, T, C, DMA> { +impl<'d, T: Instance, C: Channel> DacChannel<'d, T, C, Async> { /// Create a new `DacChannel` instance, consuming the underlying DAC peripheral. /// - /// If you're not using DMA, pass [`dma::NoDma`] for the `dma` argument. - /// /// The channel is enabled on creation and begin to drive the output pin. /// Note that some methods, such as `set_trigger()` and `set_mode()`, will /// disable the channel; you must re-enable it with `enable()`. @@ -123,21 +122,18 @@ impl<'d, T: Instance, C: Channel, DMA> DacChannel<'d, T, C, DMA> { /// By default, triggering is disabled, but it can be enabled using /// [`DacChannel::set_trigger()`]. pub fn new( - _peri: impl Peripheral

+ 'd, - dma: impl Peripheral

+ 'd, - pin: impl Peripheral

+ crate::gpio::Pin> + 'd, + peri: impl Peripheral

+ 'd, + dma: impl Peripheral

> + 'd, + pin: impl Peripheral

> + 'd, ) -> Self { into_ref!(dma, pin); pin.set_as_analog(); - rcc::enable_and_reset::(); - let mut dac = Self { - phantom: PhantomData, - dma, - }; - #[cfg(any(dac_v5, dac_v6, dac_v7))] - dac.set_hfsel(); - dac.enable(); - dac + Self::new_inner( + peri, + new_dma!(dma), + #[cfg(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7))] + Mode::NormalExternalBuffered, + ) } /// Create a new `DacChannel` instance where the external output pin is not used, @@ -148,13 +144,99 @@ impl<'d, T: Instance, C: Channel, DMA> DacChannel<'d, T, C, DMA> { /// Note that some methods, such as `set_trigger()` and `set_mode()`, will disable the /// channel; you must re-enable it with `enable()`. /// - /// If you're not using DMA, pass [`dma::NoDma`] for the `dma` argument. + /// By default, triggering is disabled, but it can be enabled using + /// [`DacChannel::set_trigger()`]. + #[cfg(all(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7), not(any(stm32h56x, stm32h57x))))] + pub fn new_internal(peri: impl Peripheral

+ 'd, dma: impl Peripheral

> + 'd) -> Self { + into_ref!(dma); + Self::new_inner(peri, new_dma!(dma), Mode::NormalInternalUnbuffered) + } + + /// Write `data` to this channel via DMA. + /// + /// To prevent delays or glitches when outputing a periodic waveform, the `circular` + /// flag can be set. This configures a circular DMA transfer that continually outputs + /// `data`. Note that for performance reasons in circular mode the transfer-complete + /// interrupt is disabled. + #[cfg(not(gpdma))] + pub async fn write(&mut self, data: ValueArray<'_>, circular: bool) { + // Enable DAC and DMA + T::regs().cr().modify(|w| { + w.set_en(C::IDX, true); + w.set_dmaen(C::IDX, true); + }); + + let dma = self.dma.as_mut().unwrap(); + + let tx_options = crate::dma::TransferOptions { + circular, + half_transfer_ir: false, + complete_transfer_ir: !circular, + ..Default::default() + }; + + // Initiate the correct type of DMA transfer depending on what data is passed + let tx_f = match data { + ValueArray::Bit8(buf) => unsafe { dma.write(buf, T::regs().dhr8r(C::IDX).as_ptr() as *mut u8, tx_options) }, + ValueArray::Bit12Left(buf) => unsafe { + dma.write(buf, T::regs().dhr12l(C::IDX).as_ptr() as *mut u16, tx_options) + }, + ValueArray::Bit12Right(buf) => unsafe { + dma.write(buf, T::regs().dhr12r(C::IDX).as_ptr() as *mut u16, tx_options) + }, + }; + + tx_f.await; + + T::regs().cr().modify(|w| { + w.set_en(C::IDX, false); + w.set_dmaen(C::IDX, false); + }); + } +} + +impl<'d, T: Instance, C: Channel> DacChannel<'d, T, C, Blocking> { + /// Create a new `DacChannel` instance, consuming the underlying DAC peripheral. + /// + /// The channel is enabled on creation and begin to drive the output pin. + /// Note that some methods, such as `set_trigger()` and `set_mode()`, will + /// disable the channel; you must re-enable it with `enable()`. + /// + /// By default, triggering is disabled, but it can be enabled using + /// [`DacChannel::set_trigger()`]. + pub fn new_blocking(peri: impl Peripheral

+ 'd, pin: impl Peripheral

> + 'd) -> Self { + into_ref!(pin); + pin.set_as_analog(); + Self::new_inner( + peri, + None, + #[cfg(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7))] + Mode::NormalExternalBuffered, + ) + } + + /// Create a new `DacChannel` instance where the external output pin is not used, + /// so the DAC can only be used to generate internal signals. + /// The GPIO pin is therefore available to be used for other functions. + /// + /// The channel is set to [`Mode::NormalInternalUnbuffered`] and enabled on creation. + /// Note that some methods, such as `set_trigger()` and `set_mode()`, will disable the + /// channel; you must re-enable it with `enable()`. /// /// By default, triggering is disabled, but it can be enabled using /// [`DacChannel::set_trigger()`]. #[cfg(all(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7), not(any(stm32h56x, stm32h57x))))] - pub fn new_internal(_peri: impl Peripheral

+ 'd, dma: impl Peripheral

+ 'd) -> Self { - into_ref!(dma); + pub fn new_internal_blocking(peri: impl Peripheral

+ 'd) -> Self { + Self::new_inner(peri, None, Mode::NormalInternalUnbuffered) + } +} + +impl<'d, T: Instance, C: Channel, M: PeriMode> DacChannel<'d, T, C, M> { + fn new_inner( + _peri: impl Peripheral

+ 'd, + dma: Option>, + #[cfg(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7))] mode: Mode, + ) -> Self { rcc::enable_and_reset::(); let mut dac = Self { phantom: PhantomData, @@ -162,7 +244,8 @@ impl<'d, T: Instance, C: Channel, DMA> DacChannel<'d, T, C, DMA> { }; #[cfg(any(dac_v5, dac_v6, dac_v7))] dac.set_hfsel(); - dac.set_mode(Mode::NormalInternalUnbuffered); + #[cfg(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7))] + dac.set_mode(mode); dac.enable(); dac } @@ -275,75 +358,9 @@ impl<'d, T: Instance, C: Channel, DMA> DacChannel<'d, T, C, DMA> { }); } } - - /// Write `data` to this channel via DMA. - /// - /// To prevent delays or glitches when outputing a periodic waveform, the `circular` - /// flag can be set. This configures a circular DMA transfer that continually outputs - /// `data`. Note that for performance reasons in circular mode the transfer-complete - /// interrupt is disabled. - #[cfg(not(gpdma))] - pub async fn write(&mut self, data: ValueArray<'_>, circular: bool) - where - DMA: Dma, - { - // Enable DAC and DMA - T::regs().cr().modify(|w| { - w.set_en(C::IDX, true); - w.set_dmaen(C::IDX, true); - }); - - let tx_request = self.dma.request(); - let dma_channel = &mut self.dma; - - let tx_options = crate::dma::TransferOptions { - circular, - half_transfer_ir: false, - complete_transfer_ir: !circular, - ..Default::default() - }; - - // Initiate the correct type of DMA transfer depending on what data is passed - let tx_f = match data { - ValueArray::Bit8(buf) => unsafe { - crate::dma::Transfer::new_write( - dma_channel, - tx_request, - buf, - T::regs().dhr8r(C::IDX).as_ptr() as *mut u8, - tx_options, - ) - }, - ValueArray::Bit12Left(buf) => unsafe { - crate::dma::Transfer::new_write( - dma_channel, - tx_request, - buf, - T::regs().dhr12l(C::IDX).as_ptr() as *mut u16, - tx_options, - ) - }, - ValueArray::Bit12Right(buf) => unsafe { - crate::dma::Transfer::new_write( - dma_channel, - tx_request, - buf, - T::regs().dhr12r(C::IDX).as_ptr() as *mut u16, - tx_options, - ) - }, - }; - - tx_f.await; - - T::regs().cr().modify(|w| { - w.set_en(C::IDX, false); - w.set_dmaen(C::IDX, false); - }); - } } -impl<'d, T: Instance, C: Channel, DMA> Drop for DacChannel<'d, T, C, DMA> { +impl<'d, T: Instance, C: Channel, M: PeriMode> Drop for DacChannel<'d, T, C, M> { fn drop(&mut self) { rcc::disable::(); } @@ -357,14 +374,14 @@ impl<'d, T: Instance, C: Channel, DMA> Drop for DacChannel<'d, T, C, DMA> { /// /// ```ignore /// // Pins may need to be changed for your specific device. -/// let (dac_ch1, dac_ch2) = embassy_stm32::dac::Dac::new(p.DAC1, NoDma, NoDma, p.PA4, p.PA5).split(); +/// let (dac_ch1, dac_ch2) = embassy_stm32::dac::Dac::new_blocking(p.DAC1, p.PA4, p.PA5).split(); /// ``` -pub struct Dac<'d, T: Instance, DMACh1 = NoDma, DMACh2 = NoDma> { - ch1: DacChannel<'d, T, Ch1, DMACh1>, - ch2: DacChannel<'d, T, Ch2, DMACh2>, +pub struct Dac<'d, T: Instance, M: PeriMode> { + ch1: DacChannel<'d, T, Ch1, M>, + ch2: DacChannel<'d, T, Ch2, M>, } -impl<'d, T: Instance, DMACh1, DMACh2> Dac<'d, T, DMACh1, DMACh2> { +impl<'d, T: Instance> Dac<'d, T, Async> { /// Create a new `Dac` instance, consuming the underlying DAC peripheral. /// /// This struct allows you to access both channels of the DAC, where available. You can either @@ -378,37 +395,22 @@ impl<'d, T: Instance, DMACh1, DMACh2> Dac<'d, T, DMACh1, DMACh2> { /// By default, triggering is disabled, but it can be enabled using the `set_trigger()` /// method on the underlying channels. pub fn new( - _peri: impl Peripheral

+ 'd, - dma_ch1: impl Peripheral

+ 'd, - dma_ch2: impl Peripheral

+ 'd, + peri: impl Peripheral

+ 'd, + dma_ch1: impl Peripheral

> + 'd, + dma_ch2: impl Peripheral

> + 'd, pin_ch1: impl Peripheral

+ crate::gpio::Pin> + 'd, pin_ch2: impl Peripheral

+ crate::gpio::Pin> + 'd, ) -> Self { into_ref!(dma_ch1, dma_ch2, pin_ch1, pin_ch2); pin_ch1.set_as_analog(); pin_ch2.set_as_analog(); - - // Enable twice to increment the DAC refcount for each channel. - rcc::enable_and_reset::(); - rcc::enable_and_reset::(); - - let mut ch1 = DacCh1 { - phantom: PhantomData, - dma: dma_ch1, - }; - #[cfg(any(dac_v5, dac_v6, dac_v7))] - ch1.set_hfsel(); - ch1.enable(); - - let mut ch2 = DacCh2 { - phantom: PhantomData, - dma: dma_ch2, - }; - #[cfg(any(dac_v5, dac_v6, dac_v7))] - ch2.set_hfsel(); - ch2.enable(); - - Self { ch1, ch2 } + Self::new_inner( + peri, + new_dma!(dma_ch1), + new_dma!(dma_ch2), + #[cfg(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7))] + Mode::NormalExternalBuffered, + ) } /// Create a new `Dac` instance where the external output pins are not used, @@ -427,11 +429,77 @@ impl<'d, T: Instance, DMACh1, DMACh2> Dac<'d, T, DMACh1, DMACh2> { /// method on the underlying channels. #[cfg(all(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7), not(any(stm32h56x, stm32h57x))))] pub fn new_internal( - _peri: impl Peripheral

+ 'd, - dma_ch1: impl Peripheral

+ 'd, - dma_ch2: impl Peripheral

+ 'd, + peri: impl Peripheral

+ 'd, + dma_ch1: impl Peripheral

> + 'd, + dma_ch2: impl Peripheral

> + 'd, ) -> Self { into_ref!(dma_ch1, dma_ch2); + Self::new_inner( + peri, + new_dma!(dma_ch1), + new_dma!(dma_ch2), + Mode::NormalInternalUnbuffered, + ) + } +} + +impl<'d, T: Instance> Dac<'d, T, Blocking> { + /// Create a new `Dac` instance, consuming the underlying DAC peripheral. + /// + /// This struct allows you to access both channels of the DAC, where available. You can either + /// call `split()` to obtain separate `DacChannel`s, or use methods on `Dac` to use + /// the two channels together. + /// + /// The channels are enabled on creation and begin to drive their output pins. + /// Note that some methods, such as `set_trigger()` and `set_mode()`, will + /// disable the channel; you must re-enable them with `enable()`. + /// + /// By default, triggering is disabled, but it can be enabled using the `set_trigger()` + /// method on the underlying channels. + pub fn new_blocking( + peri: impl Peripheral

+ 'd, + pin_ch1: impl Peripheral

+ crate::gpio::Pin> + 'd, + pin_ch2: impl Peripheral

+ crate::gpio::Pin> + 'd, + ) -> Self { + into_ref!(pin_ch1, pin_ch2); + pin_ch1.set_as_analog(); + pin_ch2.set_as_analog(); + Self::new_inner( + peri, + None, + None, + #[cfg(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7))] + Mode::NormalExternalBuffered, + ) + } + + /// Create a new `Dac` instance where the external output pins are not used, + /// so the DAC can only be used to generate internal signals but the GPIO + /// pins remain available for other functions. + /// + /// This struct allows you to access both channels of the DAC, where available. You can either + /// call `split()` to obtain separate `DacChannel`s, or use methods on `Dac` to use the two + /// channels together. + /// + /// The channels are set to [`Mode::NormalInternalUnbuffered`] and enabled on creation. + /// Note that some methods, such as `set_trigger()` and `set_mode()`, will disable the + /// channel; you must re-enable them with `enable()`. + /// + /// By default, triggering is disabled, but it can be enabled using the `set_trigger()` + /// method on the underlying channels. + #[cfg(all(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7), not(any(stm32h56x, stm32h57x))))] + pub fn new_internal(peri: impl Peripheral

+ 'd) -> Self { + Self::new_inner(peri, None, None, Mode::NormalInternalUnbuffered) + } +} + +impl<'d, T: Instance, M: PeriMode> Dac<'d, T, M> { + fn new_inner( + _peri: impl Peripheral

+ 'd, + dma_ch1: Option>, + dma_ch2: Option>, + #[cfg(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7))] mode: Mode, + ) -> Self { // Enable twice to increment the DAC refcount for each channel. rcc::enable_and_reset::(); rcc::enable_and_reset::(); @@ -442,7 +510,8 @@ impl<'d, T: Instance, DMACh1, DMACh2> Dac<'d, T, DMACh1, DMACh2> { }; #[cfg(any(dac_v5, dac_v6, dac_v7))] ch1.set_hfsel(); - ch1.set_mode(Mode::NormalInternalUnbuffered); + #[cfg(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7))] + ch1.set_mode(mode); ch1.enable(); let mut ch2 = DacCh2 { @@ -451,7 +520,8 @@ impl<'d, T: Instance, DMACh1, DMACh2> Dac<'d, T, DMACh1, DMACh2> { }; #[cfg(any(dac_v5, dac_v6, dac_v7))] ch2.set_hfsel(); - ch2.set_mode(Mode::NormalInternalUnbuffered); + #[cfg(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7))] + ch2.set_mode(mode); ch2.enable(); Self { ch1, ch2 } @@ -460,17 +530,17 @@ impl<'d, T: Instance, DMACh1, DMACh2> Dac<'d, T, DMACh1, DMACh2> { /// Split this `Dac` into separate channels. /// /// You can access and move the channels around separately after splitting. - pub fn split(self) -> (DacCh1<'d, T, DMACh1>, DacCh2<'d, T, DMACh2>) { + pub fn split(self) -> (DacCh1<'d, T, M>, DacCh2<'d, T, M>) { (self.ch1, self.ch2) } /// Temporarily access channel 1. - pub fn ch1(&mut self) -> &mut DacCh1<'d, T, DMACh1> { + pub fn ch1(&mut self) -> &mut DacCh1<'d, T, M> { &mut self.ch1 } /// Temporarily access channel 2. - pub fn ch2(&mut self) -> &mut DacCh2<'d, T, DMACh2> { + pub fn ch2(&mut self) -> &mut DacCh2<'d, T, M> { &mut self.ch2 } diff --git a/examples/stm32f4/src/bin/dac.rs b/examples/stm32f4/src/bin/dac.rs index dd2a45718..68fe6cabd 100644 --- a/examples/stm32f4/src/bin/dac.rs +++ b/examples/stm32f4/src/bin/dac.rs @@ -4,7 +4,6 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::dac::{DacCh1, Value}; -use embassy_stm32::dma::NoDma; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] @@ -12,7 +11,7 @@ async fn main(_spawner: Spawner) -> ! { let p = embassy_stm32::init(Default::default()); info!("Hello World, dude!"); - let mut dac = DacCh1::new(p.DAC1, NoDma, p.PA4); + let mut dac = DacCh1::new_blocking(p.DAC1, p.PA4); loop { for v in 0..=255 { diff --git a/examples/stm32h7/src/bin/dac.rs b/examples/stm32h7/src/bin/dac.rs index a6f969aba..27df80336 100644 --- a/examples/stm32h7/src/bin/dac.rs +++ b/examples/stm32h7/src/bin/dac.rs @@ -4,7 +4,6 @@ use cortex_m_rt::entry; use defmt::*; use embassy_stm32::dac::{DacCh1, Value}; -use embassy_stm32::dma::NoDma; use embassy_stm32::Config; use {defmt_rtt as _, panic_probe as _}; @@ -44,7 +43,7 @@ fn main() -> ! { } let p = embassy_stm32::init(config); - let mut dac = DacCh1::new(p.DAC1, NoDma, p.PA4); + let mut dac = DacCh1::new_blocking(p.DAC1, p.PA4); loop { for v in 0..=255 { diff --git a/examples/stm32h7/src/bin/dac_dma.rs b/examples/stm32h7/src/bin/dac_dma.rs index 3a9887e3c..98c9f1e90 100644 --- a/examples/stm32h7/src/bin/dac_dma.rs +++ b/examples/stm32h7/src/bin/dac_dma.rs @@ -4,8 +4,9 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::dac::{DacCh1, DacCh2, ValueArray}; +use embassy_stm32::mode::Async; use embassy_stm32::pac::timer::vals::Mms; -use embassy_stm32::peripherals::{DAC1, DMA1_CH3, DMA1_CH4, TIM6, TIM7}; +use embassy_stm32::peripherals::{DAC1, TIM6, TIM7}; use embassy_stm32::rcc::frequency; use embassy_stm32::time::Hertz; use embassy_stm32::timer::low_level::Timer; @@ -56,7 +57,7 @@ async fn main(spawner: Spawner) { } #[embassy_executor::task] -async fn dac_task1(tim: TIM6, mut dac: DacCh1<'static, DAC1, DMA1_CH3>) { +async fn dac_task1(tim: TIM6, mut dac: DacCh1<'static, DAC1, Async>) { let data: &[u8; 256] = &calculate_array::<256>(); info!("TIM6 frequency is {}", frequency::()); @@ -99,7 +100,7 @@ async fn dac_task1(tim: TIM6, mut dac: DacCh1<'static, DAC1, DMA1_CH3>) { } #[embassy_executor::task] -async fn dac_task2(tim: TIM7, mut dac: DacCh2<'static, DAC1, DMA1_CH4>) { +async fn dac_task2(tim: TIM7, mut dac: DacCh2<'static, DAC1, Async>) { let data: &[u8; 256] = &calculate_array::<256>(); info!("TIM7 frequency is {}", frequency::()); diff --git a/examples/stm32l4/src/bin/dac.rs b/examples/stm32l4/src/bin/dac.rs index fdbf1d374..50db0e082 100644 --- a/examples/stm32l4/src/bin/dac.rs +++ b/examples/stm32l4/src/bin/dac.rs @@ -3,7 +3,6 @@ use defmt::*; use embassy_stm32::dac::{DacCh1, Value}; -use embassy_stm32::dma::NoDma; use {defmt_rtt as _, panic_probe as _}; #[cortex_m_rt::entry] @@ -11,7 +10,7 @@ fn main() -> ! { let p = embassy_stm32::init(Default::default()); info!("Hello World!"); - let mut dac = DacCh1::new(p.DAC1, NoDma, p.PA4); + let mut dac = DacCh1::new_blocking(p.DAC1, p.PA4); loop { for v in 0..=255 { diff --git a/examples/stm32l4/src/bin/dac_dma.rs b/examples/stm32l4/src/bin/dac_dma.rs index d01b016c0..6c9219080 100644 --- a/examples/stm32l4/src/bin/dac_dma.rs +++ b/examples/stm32l4/src/bin/dac_dma.rs @@ -4,8 +4,9 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::dac::{DacCh1, DacCh2, ValueArray}; +use embassy_stm32::mode::Async; use embassy_stm32::pac::timer::vals::Mms; -use embassy_stm32::peripherals::{DAC1, DMA1_CH3, DMA1_CH4, TIM6, TIM7}; +use embassy_stm32::peripherals::{DAC1, TIM6, TIM7}; use embassy_stm32::rcc::frequency; use embassy_stm32::time::Hertz; use embassy_stm32::timer::low_level::Timer; @@ -27,7 +28,7 @@ async fn main(spawner: Spawner) { } #[embassy_executor::task] -async fn dac_task1(tim: TIM6, mut dac: DacCh1<'static, DAC1, DMA1_CH3>) { +async fn dac_task1(tim: TIM6, mut dac: DacCh1<'static, DAC1, Async>) { let data: &[u8; 256] = &calculate_array::<256>(); info!("TIM6 frequency is {}", frequency::()); @@ -70,7 +71,7 @@ async fn dac_task1(tim: TIM6, mut dac: DacCh1<'static, DAC1, DMA1_CH3>) { } #[embassy_executor::task] -async fn dac_task2(tim: TIM7, mut dac: DacCh2<'static, DAC1, DMA1_CH4>) { +async fn dac_task2(tim: TIM7, mut dac: DacCh2<'static, DAC1, Async>) { let data: &[u8; 256] = &calculate_array::<256>(); info!("TIM7 frequency is {}", frequency::()); diff --git a/examples/stm32u0/src/bin/dac.rs b/examples/stm32u0/src/bin/dac.rs index fdbf1d374..50db0e082 100644 --- a/examples/stm32u0/src/bin/dac.rs +++ b/examples/stm32u0/src/bin/dac.rs @@ -3,7 +3,6 @@ use defmt::*; use embassy_stm32::dac::{DacCh1, Value}; -use embassy_stm32::dma::NoDma; use {defmt_rtt as _, panic_probe as _}; #[cortex_m_rt::entry] @@ -11,7 +10,7 @@ fn main() -> ! { let p = embassy_stm32::init(Default::default()); info!("Hello World!"); - let mut dac = DacCh1::new(p.DAC1, NoDma, p.PA4); + let mut dac = DacCh1::new_blocking(p.DAC1, p.PA4); loop { for v in 0..=255 { diff --git a/tests/stm32/src/bin/dac.rs b/tests/stm32/src/bin/dac.rs index 88e661525..d34bbb255 100644 --- a/tests/stm32/src/bin/dac.rs +++ b/tests/stm32/src/bin/dac.rs @@ -12,7 +12,6 @@ use defmt::assert; use embassy_executor::Spawner; use embassy_stm32::adc::Adc; use embassy_stm32::dac::{DacCh1, Value}; -use embassy_stm32::dma::NoDma; use embassy_time::Timer; use micromath::F32Ext; use {defmt_rtt as _, panic_probe as _}; @@ -27,7 +26,7 @@ async fn main(_spawner: Spawner) { let dac_pin = peri!(p, DAC_PIN); let mut adc_pin = unsafe { core::ptr::read(&dac_pin) }; - let mut dac = DacCh1::new(dac, NoDma, dac_pin); + let mut dac = DacCh1::new_blocking(dac, dac_pin); let mut adc = Adc::new(adc); #[cfg(feature = "stm32h755zi")] diff --git a/tests/stm32/src/bin/dac_l1.rs b/tests/stm32/src/bin/dac_l1.rs index 925db617d..e6400f28e 100644 --- a/tests/stm32/src/bin/dac_l1.rs +++ b/tests/stm32/src/bin/dac_l1.rs @@ -12,7 +12,6 @@ use defmt::assert; use embassy_executor::Spawner; use embassy_stm32::adc::Adc; use embassy_stm32::dac::{DacCh1, Value}; -use embassy_stm32::dma::NoDma; use embassy_stm32::{bind_interrupts, peripherals}; use embassy_time::Timer; use micromath::F32Ext; @@ -32,7 +31,7 @@ async fn main(_spawner: Spawner) { let dac_pin = peri!(p, DAC_PIN); let mut adc_pin = unsafe { core::ptr::read(&dac_pin) }; - let mut dac = DacCh1::new(dac, NoDma, dac_pin); + let mut dac = DacCh1::new_blocking(dac, dac_pin); let mut adc = Adc::new(adc, Irqs); #[cfg(feature = "stm32h755zi")] From 9a0afa7bf4821d89b56265b67b7c76be382046ac Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 25 Mar 2025 21:43:47 +0100 Subject: [PATCH 0872/1217] stm32/sdmmc: remove DMA generic param. --- embassy-stm32/src/macros.rs | 12 ++++ embassy-stm32/src/sdmmc/mod.rs | 104 +++++++++++++++++---------------- 2 files changed, 66 insertions(+), 50 deletions(-) diff --git a/embassy-stm32/src/macros.rs b/embassy-stm32/src/macros.rs index ae53deb08..000773e2d 100644 --- a/embassy-stm32/src/macros.rs +++ b/embassy-stm32/src/macros.rs @@ -85,6 +85,18 @@ macro_rules! dma_trait_impl { }; } +#[allow(unused)] +macro_rules! new_dma_nonopt { + ($name:ident) => {{ + let dma = $name.into_ref(); + let request = dma.request(); + crate::dma::ChannelAndRequest { + channel: dma.map_into(), + request, + } + }}; +} + macro_rules! new_dma { ($name:ident) => {{ let dma = $name.into_ref(); diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs index 8af2f8381..d8671caf7 100644 --- a/embassy-stm32/src/sdmmc/mod.rs +++ b/embassy-stm32/src/sdmmc/mod.rs @@ -12,7 +12,8 @@ use embassy_hal_internal::{into_ref, PeripheralRef}; use embassy_sync::waitqueue::AtomicWaker; use sdio_host::{BusWidth, CardCapacity, CardStatus, CurrentState, SDStatus, CID, CSD, OCR, SCR}; -use crate::dma::NoDma; +#[cfg(sdmmc_v1)] +use crate::dma::ChannelAndRequest; #[cfg(gpio_v2)] use crate::gpio::Pull; use crate::gpio::{AfType, AnyPin, OutputType, SealedPin, Speed}; @@ -301,10 +302,10 @@ impl Default for Config { } /// Sdmmc device -pub struct Sdmmc<'d, T: Instance, Dma: SdmmcDma = NoDma> { +pub struct Sdmmc<'d, T: Instance> { _peri: PeripheralRef<'d, T>, - #[allow(unused)] - dma: PeripheralRef<'d, Dma>, + #[cfg(sdmmc_v1)] + dma: ChannelAndRequest<'d>, clk: PeripheralRef<'d, AnyPin>, cmd: PeripheralRef<'d, AnyPin>, @@ -334,18 +335,18 @@ const CMD_AF: AfType = AfType::output_pull(OutputType::PushPull, Speed::VeryHigh const DATA_AF: AfType = CMD_AF; #[cfg(sdmmc_v1)] -impl<'d, T: Instance, Dma: SdmmcDma> Sdmmc<'d, T, Dma> { +impl<'d, T: Instance> Sdmmc<'d, T> { /// Create a new SDMMC driver, with 1 data lane. pub fn new_1bit( sdmmc: impl Peripheral

+ 'd, _irq: impl interrupt::typelevel::Binding> + 'd, - dma: impl Peripheral

+ 'd, + dma: impl Peripheral

> + 'd, clk: impl Peripheral

> + 'd, cmd: impl Peripheral

> + 'd, d0: impl Peripheral

> + 'd, config: Config, ) -> Self { - into_ref!(clk, cmd, d0); + into_ref!(dma, clk, cmd, d0); critical_section::with(|_| { clk.set_as_af(clk.af_num(), CLK_AF); @@ -355,7 +356,7 @@ impl<'d, T: Instance, Dma: SdmmcDma> Sdmmc<'d, T, Dma> { Self::new_inner( sdmmc, - dma, + new_dma_nonopt!(dma), clk.map_into(), cmd.map_into(), d0.map_into(), @@ -370,7 +371,7 @@ impl<'d, T: Instance, Dma: SdmmcDma> Sdmmc<'d, T, Dma> { pub fn new_4bit( sdmmc: impl Peripheral

+ 'd, _irq: impl interrupt::typelevel::Binding> + 'd, - dma: impl Peripheral

+ 'd, + dma: impl Peripheral

> + 'd, clk: impl Peripheral

> + 'd, cmd: impl Peripheral

> + 'd, d0: impl Peripheral

> + 'd, @@ -392,7 +393,7 @@ impl<'d, T: Instance, Dma: SdmmcDma> Sdmmc<'d, T, Dma> { Self::new_inner( sdmmc, - dma, + new_dma_nonopt!(dma), clk.map_into(), cmd.map_into(), d0.map_into(), @@ -405,7 +406,7 @@ impl<'d, T: Instance, Dma: SdmmcDma> Sdmmc<'d, T, Dma> { } #[cfg(sdmmc_v2)] -impl<'d, T: Instance> Sdmmc<'d, T, NoDma> { +impl<'d, T: Instance> Sdmmc<'d, T> { /// Create a new SDMMC driver, with 1 data lane. pub fn new_1bit( sdmmc: impl Peripheral

+ 'd, @@ -425,7 +426,6 @@ impl<'d, T: Instance> Sdmmc<'d, T, NoDma> { Self::new_inner( sdmmc, - NoDma.into_ref(), clk.map_into(), cmd.map_into(), d0.map_into(), @@ -461,7 +461,6 @@ impl<'d, T: Instance> Sdmmc<'d, T, NoDma> { Self::new_inner( sdmmc, - NoDma.into_ref(), clk.map_into(), cmd.map_into(), d0.map_into(), @@ -473,10 +472,10 @@ impl<'d, T: Instance> Sdmmc<'d, T, NoDma> { } } -impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { +impl<'d, T: Instance> Sdmmc<'d, T> { fn new_inner( sdmmc: impl Peripheral

+ 'd, - dma: impl Peripheral

+ 'd, + #[cfg(sdmmc_v1)] dma: ChannelAndRequest<'d>, clk: PeripheralRef<'d, AnyPin>, cmd: PeripheralRef<'d, AnyPin>, d0: PeripheralRef<'d, AnyPin>, @@ -485,7 +484,7 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { d3: Option>, config: Config, ) -> Self { - into_ref!(sdmmc, dma); + into_ref!(sdmmc); rcc::enable_and_reset::(); @@ -514,6 +513,7 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { Self { _peri: sdmmc, + #[cfg(sdmmc_v1)] dma, clk, @@ -567,7 +567,7 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { #[allow(unused_variables)] fn prepare_datapath_read<'a>( config: &Config, - dma: &'a mut PeripheralRef<'d, Dma>, + #[cfg(sdmmc_v1)] dma: &'a mut ChannelAndRequest<'d>, buffer: &'a mut [u32], length_bytes: u32, block_size: u8, @@ -583,16 +583,7 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { regs.dlenr().write(|w| w.set_datalength(length_bytes)); #[cfg(sdmmc_v1)] - let transfer = unsafe { - let request = dma.request(); - Transfer::new_read( - dma, - request, - regs.fifor().as_ptr() as *mut u32, - buffer, - DMA_TRANSFER_OPTIONS, - ) - }; + let transfer = unsafe { dma.read(regs.fifor().as_ptr() as *mut u32, buffer, DMA_TRANSFER_OPTIONS) }; #[cfg(sdmmc_v2)] let transfer = { regs.idmabase0r().write(|w| w.set_idmabase0(buffer.as_mut_ptr() as u32)); @@ -632,14 +623,8 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { #[cfg(sdmmc_v1)] let transfer = unsafe { - let request = self.dma.request(); - Transfer::new_write( - &mut self.dma, - request, - buffer, - regs.fifor().as_ptr() as *mut u32, - DMA_TRANSFER_OPTIONS, - ) + self.dma + .write(buffer, regs.fifor().as_ptr() as *mut u32, DMA_TRANSFER_OPTIONS) }; #[cfg(sdmmc_v2)] let transfer = { @@ -735,7 +720,14 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { let regs = T::regs(); let on_drop = OnDrop::new(|| Self::on_drop()); - let transfer = Self::prepare_datapath_read(&self.config, &mut self.dma, status.as_mut(), 64, 6); + let transfer = Self::prepare_datapath_read( + &self.config, + #[cfg(sdmmc_v1)] + &mut self.dma, + status.as_mut(), + 64, + 6, + ); InterruptHandler::::data_interrupts(true); Self::cmd(Cmd::cmd6(set_function), true)?; // CMD6 @@ -821,7 +813,14 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { let regs = T::regs(); let on_drop = OnDrop::new(|| Self::on_drop()); - let transfer = Self::prepare_datapath_read(&self.config, &mut self.dma, status.as_mut(), 64, 6); + let transfer = Self::prepare_datapath_read( + &self.config, + #[cfg(sdmmc_v1)] + &mut self.dma, + status.as_mut(), + 64, + 6, + ); InterruptHandler::::data_interrupts(true); Self::cmd(Cmd::card_status(0), true)?; @@ -924,7 +923,14 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { let regs = T::regs(); let on_drop = OnDrop::new(|| Self::on_drop()); - let transfer = Self::prepare_datapath_read(&self.config, &mut self.dma, scr, 8, 3); + let transfer = Self::prepare_datapath_read( + &self.config, + #[cfg(sdmmc_v1)] + &mut self.dma, + scr, + 8, + 3, + ); InterruptHandler::::data_interrupts(true); Self::cmd(Cmd::cmd51(), true)?; @@ -1214,7 +1220,14 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { let regs = T::regs(); let on_drop = OnDrop::new(|| Self::on_drop()); - let transfer = Self::prepare_datapath_read(&self.config, &mut self.dma, buffer, 512, 9); + let transfer = Self::prepare_datapath_read( + &self.config, + #[cfg(sdmmc_v1)] + &mut self.dma, + buffer, + 512, + 9, + ); InterruptHandler::::data_interrupts(true); Self::cmd(Cmd::read_single_block(address), true)?; @@ -1347,7 +1360,7 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { } } -impl<'d, T: Instance, Dma: SdmmcDma + 'd> Drop for Sdmmc<'d, T, Dma> { +impl<'d, T: Instance> Drop for Sdmmc<'d, T> { fn drop(&mut self) { T::Interrupt::disable(); Self::on_drop(); @@ -1484,15 +1497,6 @@ pin_trait!(D7Pin, Instance); #[cfg(sdmmc_v1)] dma_trait!(SdmmcDma, Instance); -/// DMA instance trait. -/// -/// This is only implemented for `NoDma`, since SDMMCv2 has DMA built-in, instead of -/// using ST's system-wide DMA peripheral. -#[cfg(sdmmc_v2)] -pub trait SdmmcDma {} -#[cfg(sdmmc_v2)] -impl SdmmcDma for NoDma {} - foreach_peripheral!( (sdmmc, $inst:ident) => { impl SealedInstance for peripherals::$inst { @@ -1512,7 +1516,7 @@ foreach_peripheral!( }; ); -impl<'d, T: Instance, Dma: SdmmcDma + 'd> block_device_driver::BlockDevice<512> for Sdmmc<'d, T, Dma> { +impl<'d, T: Instance> block_device_driver::BlockDevice<512> for Sdmmc<'d, T> { type Error = Error; type Align = aligned::A4; From db86aba841851d1a25f9bec7a1686db34c94c885 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 25 Mar 2025 21:57:37 +0100 Subject: [PATCH 0873/1217] stm32/hash: remove DMA generic param. --- embassy-stm32/src/dma/util.rs | 6 +- embassy-stm32/src/hash/mod.rs | 286 ++++++++++++++++++---------------- embassy-stm32/src/spi/mod.rs | 2 +- tests/stm32/src/bin/hash.rs | 3 +- 4 files changed, 153 insertions(+), 144 deletions(-) diff --git a/embassy-stm32/src/dma/util.rs b/embassy-stm32/src/dma/util.rs index 5aaca57c9..5e1158182 100644 --- a/embassy-stm32/src/dma/util.rs +++ b/embassy-stm32/src/dma/util.rs @@ -39,10 +39,10 @@ impl<'d> ChannelAndRequest<'d> { Transfer::new_write(&mut self.channel, self.request, buf, peri_addr, options) } - pub unsafe fn write_raw<'a, W: Word>( + pub unsafe fn write_raw<'a, MW: Word, PW: Word>( &'a mut self, - buf: *const [W], - peri_addr: *mut W, + buf: *const [MW], + peri_addr: *mut PW, options: TransferOptions, ) -> Transfer<'a> { Transfer::new_write_raw(&mut self.channel, self.request, buf, peri_addr, options) diff --git a/embassy-stm32/src/hash/mod.rs b/embassy-stm32/src/hash/mod.rs index 3c2125498..3951e9d63 100644 --- a/embassy-stm32/src/hash/mod.rs +++ b/embassy-stm32/src/hash/mod.rs @@ -12,10 +12,12 @@ use embassy_hal_internal::{into_ref, PeripheralRef}; use embassy_sync::waitqueue::AtomicWaker; use stm32_metapac::hash::regs::*; -use crate::dma::NoDma; #[cfg(hash_v2)] -use crate::dma::Transfer; +use crate::dma::ChannelAndRequest; use crate::interrupt::typelevel::Interrupt; +#[cfg(hash_v2)] +use crate::mode::Async; +use crate::mode::{Blocking, Mode}; use crate::peripherals::HASH; use crate::{interrupt, pac, peripherals, rcc, Peripheral}; @@ -116,24 +118,26 @@ pub struct Context<'c> { type HmacKey<'k> = Option<&'k [u8]>; /// HASH driver. -pub struct Hash<'d, T: Instance, D = NoDma> { +pub struct Hash<'d, T: Instance, M: Mode> { _peripheral: PeripheralRef<'d, T>, - #[allow(dead_code)] - dma: PeripheralRef<'d, D>, + _phantom: PhantomData, + #[cfg(hash_v2)] + dma: Option>, } -impl<'d, T: Instance, D> Hash<'d, T, D> { +impl<'d, T: Instance> Hash<'d, T, Blocking> { /// Instantiates, resets, and enables the HASH peripheral. - pub fn new( + pub fn new_blocking( peripheral: impl Peripheral

+ 'd, - dma: impl Peripheral

+ 'd, _irq: impl interrupt::typelevel::Binding> + 'd, ) -> Self { rcc::enable_and_reset::(); - into_ref!(peripheral, dma); + into_ref!(peripheral); let instance = Self { _peripheral: peripheral, - dma: dma, + _phantom: PhantomData, + #[cfg(hash_v2)] + dma: None, }; T::Interrupt::unpend(); @@ -141,7 +145,9 @@ impl<'d, T: Instance, D> Hash<'d, T, D> { instance } +} +impl<'d, T: Instance, M: Mode> Hash<'d, T, M> { /// Starts computation of a new hash and returns the saved peripheral state. pub fn start<'c>(&mut self, algorithm: Algorithm, format: DataType, key: HmacKey<'c>) -> Context<'c> { // Define a context for this new computation. @@ -282,14 +288,136 @@ impl<'d, T: Instance, D> Hash<'d, T, D> { self.store_context(ctx); } + /// Computes a digest for the given context. + /// The digest buffer must be large enough to accomodate a digest for the selected algorithm. + /// The largest returned digest size is 128 bytes for SHA-512. + /// Panics if the supplied digest buffer is too short. + pub fn finish_blocking<'c>(&mut self, mut ctx: Context<'c>, digest: &mut [u8]) -> usize { + // Restore the peripheral state. + self.load_context(&ctx); + + // Hash the leftover bytes, if any. + self.accumulate_blocking(&ctx.buffer[0..ctx.buflen]); + ctx.buflen = 0; + + //Start the digest calculation. + T::regs().str().write(|w| w.set_dcal(true)); + + // Load the HMAC key if provided. + if let Some(key) = ctx.key { + while !T::regs().sr().read().dinis() {} + self.accumulate_blocking(key); + T::regs().str().write(|w| w.set_dcal(true)); + } + + // Block until digest computation is complete. + while !T::regs().sr().read().dcis() {} + + // Return the digest. + let digest_words = match ctx.algo { + Algorithm::SHA1 => 5, + #[cfg(any(hash_v1, hash_v2, hash_v4))] + Algorithm::MD5 => 4, + Algorithm::SHA224 => 7, + Algorithm::SHA256 => 8, + #[cfg(hash_v3)] + Algorithm::SHA384 => 12, + #[cfg(hash_v3)] + Algorithm::SHA512_224 => 7, + #[cfg(hash_v3)] + Algorithm::SHA512_256 => 8, + #[cfg(hash_v3)] + Algorithm::SHA512 => 16, + }; + + let digest_len_bytes = digest_words * 4; + // Panics if the supplied digest buffer is too short. + if digest.len() < digest_len_bytes { + panic!("Digest buffer must be at least {} bytes long.", digest_words * 4); + } + + let mut i = 0; + while i < digest_words { + let word = T::regs().hr(i).read(); + digest[(i * 4)..((i * 4) + 4)].copy_from_slice(word.to_be_bytes().as_slice()); + i += 1; + } + digest_len_bytes + } + + /// Push data into the hash core. + fn accumulate_blocking(&mut self, input: &[u8]) { + // Set the number of valid bits. + let num_valid_bits: u8 = (8 * (input.len() % 4)) as u8; + T::regs().str().modify(|w| w.set_nblw(num_valid_bits)); + + let mut i = 0; + while i < input.len() { + let mut word: [u8; 4] = [0; 4]; + let copy_idx = min(i + 4, input.len()); + word[0..copy_idx - i].copy_from_slice(&input[i..copy_idx]); + T::regs().din().write_value(u32::from_ne_bytes(word)); + i += 4; + } + } + + /// Save the peripheral state to a context. + fn store_context<'c>(&mut self, ctx: &mut Context<'c>) { + // Block waiting for data in ready. + while !T::regs().sr().read().dinis() {} + + // Store peripheral context. + ctx.imr = T::regs().imr().read().0; + ctx.str = T::regs().str().read().0; + ctx.cr = T::regs().cr().read().0; + let mut i = 0; + while i < NUM_CONTEXT_REGS { + ctx.csr[i] = T::regs().csr(i).read(); + i += 1; + } + } + + /// Restore the peripheral state from a context. + fn load_context(&mut self, ctx: &Context) { + // Restore the peripheral state from the context. + T::regs().imr().write_value(Imr { 0: ctx.imr }); + T::regs().str().write_value(Str { 0: ctx.str }); + T::regs().cr().write_value(Cr { 0: ctx.cr }); + T::regs().cr().modify(|w| w.set_init(true)); + let mut i = 0; + while i < NUM_CONTEXT_REGS { + T::regs().csr(i).write_value(ctx.csr[i]); + i += 1; + } + } +} + +#[cfg(hash_v2)] +impl<'d, T: Instance> Hash<'d, T, Async> { + /// Instantiates, resets, and enables the HASH peripheral. + pub fn new( + peripheral: impl Peripheral

+ 'd, + dma: impl Peripheral

> + 'd, + _irq: impl interrupt::typelevel::Binding> + 'd, + ) -> Self { + rcc::enable_and_reset::(); + into_ref!(peripheral, dma); + let instance = Self { + _peripheral: peripheral, + _phantom: PhantomData, + dma: new_dma!(dma), + }; + + T::Interrupt::unpend(); + unsafe { T::Interrupt::enable() }; + + instance + } + /// Restores the peripheral state using the given context, /// then updates the state with the provided data. /// Peripheral state is saved upon return. - #[cfg(hash_v2)] - pub async fn update<'c>(&mut self, ctx: &mut Context<'c>, input: &[u8]) - where - D: crate::hash::Dma, - { + pub async fn update(&mut self, ctx: &mut Context<'_>, input: &[u8]) { // Restore the peripheral state. self.load_context(&ctx); @@ -353,68 +481,7 @@ impl<'d, T: Instance, D> Hash<'d, T, D> { /// The digest buffer must be large enough to accomodate a digest for the selected algorithm. /// The largest returned digest size is 128 bytes for SHA-512. /// Panics if the supplied digest buffer is too short. - pub fn finish_blocking<'c>(&mut self, mut ctx: Context<'c>, digest: &mut [u8]) -> usize { - // Restore the peripheral state. - self.load_context(&ctx); - - // Hash the leftover bytes, if any. - self.accumulate_blocking(&ctx.buffer[0..ctx.buflen]); - ctx.buflen = 0; - - //Start the digest calculation. - T::regs().str().write(|w| w.set_dcal(true)); - - // Load the HMAC key if provided. - if let Some(key) = ctx.key { - while !T::regs().sr().read().dinis() {} - self.accumulate_blocking(key); - T::regs().str().write(|w| w.set_dcal(true)); - } - - // Block until digest computation is complete. - while !T::regs().sr().read().dcis() {} - - // Return the digest. - let digest_words = match ctx.algo { - Algorithm::SHA1 => 5, - #[cfg(any(hash_v1, hash_v2, hash_v4))] - Algorithm::MD5 => 4, - Algorithm::SHA224 => 7, - Algorithm::SHA256 => 8, - #[cfg(hash_v3)] - Algorithm::SHA384 => 12, - #[cfg(hash_v3)] - Algorithm::SHA512_224 => 7, - #[cfg(hash_v3)] - Algorithm::SHA512_256 => 8, - #[cfg(hash_v3)] - Algorithm::SHA512 => 16, - }; - - let digest_len_bytes = digest_words * 4; - // Panics if the supplied digest buffer is too short. - if digest.len() < digest_len_bytes { - panic!("Digest buffer must be at least {} bytes long.", digest_words * 4); - } - - let mut i = 0; - while i < digest_words { - let word = T::regs().hr(i).read(); - digest[(i * 4)..((i * 4) + 4)].copy_from_slice(word.to_be_bytes().as_slice()); - i += 1; - } - digest_len_bytes - } - - /// Computes a digest for the given context. - /// The digest buffer must be large enough to accomodate a digest for the selected algorithm. - /// The largest returned digest size is 128 bytes for SHA-512. - /// Panics if the supplied digest buffer is too short. - #[cfg(hash_v2)] - pub async fn finish<'c>(&mut self, mut ctx: Context<'c>, digest: &mut [u8]) -> usize - where - D: crate::hash::Dma, - { + pub async fn finish<'c>(&mut self, mut ctx: Context<'c>, digest: &mut [u8]) -> usize { // Restore the peripheral state. self.load_context(&ctx); @@ -483,27 +550,7 @@ impl<'d, T: Instance, D> Hash<'d, T, D> { } /// Push data into the hash core. - fn accumulate_blocking(&mut self, input: &[u8]) { - // Set the number of valid bits. - let num_valid_bits: u8 = (8 * (input.len() % 4)) as u8; - T::regs().str().modify(|w| w.set_nblw(num_valid_bits)); - - let mut i = 0; - while i < input.len() { - let mut word: [u8; 4] = [0; 4]; - let copy_idx = min(i + 4, input.len()); - word[0..copy_idx - i].copy_from_slice(&input[i..copy_idx]); - T::regs().din().write_value(u32::from_ne_bytes(word)); - i += 4; - } - } - - /// Push data into the hash core. - #[cfg(hash_v2)] - async fn accumulate(&mut self, input: &[u8]) - where - D: crate::hash::Dma, - { + async fn accumulate(&mut self, input: &[u8]) { // Ignore an input length of 0. if input.len() == 0 { return; @@ -514,57 +561,20 @@ impl<'d, T: Instance, D> Hash<'d, T, D> { T::regs().str().modify(|w| w.set_nblw(num_valid_bits)); // Configure DMA to transfer input to hash core. - let dma_request = self.dma.request(); let dst_ptr: *mut u32 = T::regs().din().as_ptr(); let mut num_words = input.len() / 4; if input.len() % 4 > 0 { num_words += 1; } let src_ptr: *const [u8] = ptr::slice_from_raw_parts(input.as_ptr().cast(), num_words); - let dma_transfer = unsafe { - Transfer::new_write_raw( - &mut self.dma, - dma_request, - src_ptr, - dst_ptr as *mut u32, - Default::default(), - ) - }; + + let dma = self.dma.as_mut().unwrap(); + let dma_transfer = unsafe { dma.write_raw(src_ptr, dst_ptr as *mut u32, Default::default()) }; T::regs().cr().modify(|w| w.set_dmae(true)); // Wait for the transfer to complete. dma_transfer.await; } - - /// Save the peripheral state to a context. - fn store_context<'c>(&mut self, ctx: &mut Context<'c>) { - // Block waiting for data in ready. - while !T::regs().sr().read().dinis() {} - - // Store peripheral context. - ctx.imr = T::regs().imr().read().0; - ctx.str = T::regs().str().read().0; - ctx.cr = T::regs().cr().read().0; - let mut i = 0; - while i < NUM_CONTEXT_REGS { - ctx.csr[i] = T::regs().csr(i).read(); - i += 1; - } - } - - /// Restore the peripheral state from a context. - fn load_context(&mut self, ctx: &Context) { - // Restore the peripheral state from the context. - T::regs().imr().write_value(Imr { 0: ctx.imr }); - T::regs().str().write_value(Str { 0: ctx.str }); - T::regs().cr().write_value(Cr { 0: ctx.cr }); - T::regs().cr().modify(|w| w.set_init(true)); - let mut i = 0; - while i < NUM_CONTEXT_REGS { - T::regs().csr(i).write_value(ctx.csr[i]); - i += 1; - } - } } trait SealedInstance { diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs index 44dda6a9e..a43da1b5a 100644 --- a/embassy-stm32/src/spi/mod.rs +++ b/embassy-stm32/src/spi/mod.rs @@ -839,7 +839,7 @@ impl<'d> Spi<'d, Async> { let rx_src = self.info.regs.rx_ptr(); let rx_f = unsafe { self.rx_dma.as_mut().unwrap().read_raw(rx_src, read, Default::default()) }; - let tx_dst = self.info.regs.tx_ptr(); + let tx_dst: *mut W = self.info.regs.tx_ptr(); let tx_f = unsafe { self.tx_dma .as_mut() diff --git a/tests/stm32/src/bin/hash.rs b/tests/stm32/src/bin/hash.rs index bdb3c9a69..52b84a499 100644 --- a/tests/stm32/src/bin/hash.rs +++ b/tests/stm32/src/bin/hash.rs @@ -6,7 +6,6 @@ mod common; use common::*; use embassy_executor::Spawner; -use embassy_stm32::dma::NoDma; use embassy_stm32::hash::*; use embassy_stm32::{bind_interrupts, hash, peripherals}; use hmac::{Hmac, Mac}; @@ -36,7 +35,7 @@ bind_interrupts!(struct Irqs { #[embassy_executor::main] async fn main(_spawner: Spawner) { let p: embassy_stm32::Peripherals = init(); - let mut hw_hasher = Hash::new(p.HASH, NoDma, Irqs); + let mut hw_hasher = Hash::new_blocking(p.HASH, Irqs); let test_1: &[u8] = b"as;dfhaslfhas;oifvnasd;nifvnhasd;nifvhndlkfghsd;nvfnahssdfgsdafgsasdfasdfasdfasdfasdfghjklmnbvcalskdjghalskdjgfbaslkdjfgbalskdjgbalskdjbdfhsdfhsfghsfghfgh"; let test_2: &[u8] = b"fdhalksdjfhlasdjkfhalskdjfhgal;skdjfgalskdhfjgalskdjfglafgadfgdfgdafgaadsfgfgdfgadrgsyfthxfgjfhklhjkfgukhulkvhlvhukgfhfsrghzdhxyfufynufyuszeradrtydyytserr"; From a592acb8068011787453944963b384fd43a52e65 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 25 Mar 2025 22:18:21 +0100 Subject: [PATCH 0874/1217] stm32/cryp: remove DMA generic param. --- embassy-stm32/src/cryp/mod.rs | 897 +++++++++++++++++----------------- embassy-stm32/src/dma/mod.rs | 11 - 2 files changed, 445 insertions(+), 463 deletions(-) diff --git a/embassy-stm32/src/cryp/mod.rs b/embassy-stm32/src/cryp/mod.rs index 6afe68a39..54d2c30e5 100644 --- a/embassy-stm32/src/cryp/mod.rs +++ b/embassy-stm32/src/cryp/mod.rs @@ -7,8 +7,9 @@ use core::ptr; use embassy_hal_internal::{into_ref, PeripheralRef}; use embassy_sync::waitqueue::AtomicWaker; -use crate::dma::{NoDma, Transfer, TransferOptions}; +use crate::dma::{ChannelAndRequest, TransferOptions}; use crate::interrupt::typelevel::Interrupt; +use crate::mode::{Async, Blocking, Mode}; use crate::{interrupt, pac, peripherals, rcc, Peripheral}; const DES_BLOCK_SIZE: usize = 8; // 64 bits @@ -57,15 +58,10 @@ pub trait Cipher<'c> { fn prepare_key(&self, _p: pac::cryp::Cryp) {} /// Performs any cipher-specific initialization. - fn init_phase_blocking(&self, _p: pac::cryp::Cryp, _cryp: &Cryp) {} + fn init_phase_blocking(&self, _p: pac::cryp::Cryp, _cryp: &Cryp) {} /// Performs any cipher-specific initialization. - async fn init_phase(&self, _p: pac::cryp::Cryp, _cryp: &mut Cryp<'_, T, DmaIn, DmaOut>) - where - DmaIn: crate::cryp::DmaIn, - DmaOut: crate::cryp::DmaOut, - { - } + async fn init_phase(&self, _p: pac::cryp::Cryp, _cryp: &mut Cryp<'_, T, Async>) {} /// Called prior to processing the last data block for cipher-specific operations. fn pre_final(&self, _p: pac::cryp::Cryp, _dir: Direction, _padding_len: usize) -> [u32; 4] { @@ -73,10 +69,10 @@ pub trait Cipher<'c> { } /// Called after processing the last data block for cipher-specific operations. - fn post_final_blocking( + fn post_final_blocking( &self, _p: pac::cryp::Cryp, - _cryp: &Cryp, + _cryp: &Cryp, _dir: Direction, _int_data: &mut [u8; AES_BLOCK_SIZE], _temp1: [u32; 4], @@ -85,18 +81,15 @@ pub trait Cipher<'c> { } /// Called after processing the last data block for cipher-specific operations. - async fn post_final( + async fn post_final( &self, _p: pac::cryp::Cryp, - _cryp: &mut Cryp<'_, T, DmaIn, DmaOut>, + _cryp: &mut Cryp<'_, T, Async>, _dir: Direction, _int_data: &mut [u8; AES_BLOCK_SIZE], _temp1: [u32; 4], _padding_mask: [u8; 16], - ) where - DmaIn: crate::cryp::DmaIn, - DmaOut: crate::cryp::DmaOut, - { + ) { } /// Returns the AAD header block as required by the cipher. @@ -474,13 +467,13 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGcm<'c, KEY_SIZE> { p.cr().modify(|w| w.set_algomode3(true)); } - fn init_phase_blocking(&self, p: pac::cryp::Cryp, _cryp: &Cryp) { + fn init_phase_blocking(&self, p: pac::cryp::Cryp, _cryp: &Cryp) { p.cr().modify(|w| w.set_gcm_ccmph(0)); p.cr().modify(|w| w.set_crypen(true)); while p.cr().read().crypen() {} } - async fn init_phase(&self, p: pac::cryp::Cryp, _cryp: &mut Cryp<'_, T, DmaIn, DmaOut>) { + async fn init_phase(&self, p: pac::cryp::Cryp, _cryp: &mut Cryp<'_, T, Async>) { p.cr().modify(|w| w.set_gcm_ccmph(0)); p.cr().modify(|w| w.set_crypen(true)); while p.cr().read().crypen() {} @@ -508,10 +501,10 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGcm<'c, KEY_SIZE> { } #[cfg(cryp_v2)] - fn post_final_blocking( + fn post_final_blocking( &self, p: pac::cryp::Cryp, - cryp: &Cryp, + cryp: &Cryp, dir: Direction, int_data: &mut [u8; AES_BLOCK_SIZE], _temp1: [u32; 4], @@ -534,18 +527,15 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGcm<'c, KEY_SIZE> { } #[cfg(cryp_v2)] - async fn post_final( + async fn post_final( &self, p: pac::cryp::Cryp, - cryp: &mut Cryp<'_, T, DmaIn, DmaOut>, + cryp: &mut Cryp<'_, T, Async>, dir: Direction, int_data: &mut [u8; AES_BLOCK_SIZE], _temp1: [u32; 4], padding_mask: [u8; AES_BLOCK_SIZE], - ) where - DmaIn: crate::cryp::DmaIn, - DmaOut: crate::cryp::DmaOut, - { + ) { if dir == Direction::Encrypt { // Handle special GCM partial block process. p.cr().modify(|w| w.set_crypen(false)); @@ -559,8 +549,8 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGcm<'c, KEY_SIZE> { let mut out_data: [u8; AES_BLOCK_SIZE] = [0; AES_BLOCK_SIZE]; - let read = Cryp::::read_bytes(&mut cryp.outdma, Self::BLOCK_SIZE, &mut out_data); - let write = Cryp::::write_bytes(&mut cryp.indma, Self::BLOCK_SIZE, int_data); + let read = Cryp::::read_bytes(cryp.outdma.as_mut().unwrap(), Self::BLOCK_SIZE, &mut out_data); + let write = Cryp::::write_bytes(cryp.indma.as_mut().unwrap(), Self::BLOCK_SIZE, int_data); embassy_futures::join::join(read, write).await; @@ -615,13 +605,13 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGmac<'c, KEY_SIZE> { p.cr().modify(|w| w.set_algomode3(true)); } - fn init_phase_blocking(&self, p: pac::cryp::Cryp, _cryp: &Cryp) { + fn init_phase_blocking(&self, p: pac::cryp::Cryp, _cryp: &Cryp) { p.cr().modify(|w| w.set_gcm_ccmph(0)); p.cr().modify(|w| w.set_crypen(true)); while p.cr().read().crypen() {} } - async fn init_phase(&self, p: pac::cryp::Cryp, _cryp: &mut Cryp<'_, T, DmaIn, DmaOut>) { + async fn init_phase(&self, p: pac::cryp::Cryp, _cryp: &mut Cryp<'_, T, Async>) { p.cr().modify(|w| w.set_gcm_ccmph(0)); p.cr().modify(|w| w.set_crypen(true)); while p.cr().read().crypen() {} @@ -649,10 +639,10 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGmac<'c, KEY_SIZE> { } #[cfg(cryp_v2)] - fn post_final_blocking( + fn post_final_blocking( &self, p: pac::cryp::Cryp, - cryp: &Cryp, + cryp: &Cryp, dir: Direction, int_data: &mut [u8; AES_BLOCK_SIZE], _temp1: [u32; 4], @@ -675,18 +665,15 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGmac<'c, KEY_SIZE> { } #[cfg(cryp_v2)] - async fn post_final( + async fn post_final( &self, p: pac::cryp::Cryp, - cryp: &mut Cryp<'_, T, DmaIn, DmaOut>, + cryp: &mut Cryp<'_, T, Async>, dir: Direction, int_data: &mut [u8; AES_BLOCK_SIZE], _temp1: [u32; 4], padding_mask: [u8; AES_BLOCK_SIZE], - ) where - DmaIn: crate::cryp::DmaIn, - DmaOut: crate::cryp::DmaOut, - { + ) { if dir == Direction::Encrypt { // Handle special GCM partial block process. p.cr().modify(|w| w.set_crypen(false)); @@ -700,8 +687,8 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGmac<'c, KEY_SIZE> { let mut out_data: [u8; AES_BLOCK_SIZE] = [0; AES_BLOCK_SIZE]; - let read = Cryp::::read_bytes(&mut cryp.outdma, Self::BLOCK_SIZE, &mut out_data); - let write = Cryp::::write_bytes(&mut cryp.indma, Self::BLOCK_SIZE, int_data); + let read = Cryp::::read_bytes(cryp.outdma.as_mut().unwrap(), Self::BLOCK_SIZE, &mut out_data); + let write = Cryp::::write_bytes(cryp.indma.as_mut().unwrap(), Self::BLOCK_SIZE, int_data); embassy_futures::join::join(read, write).await; } @@ -812,7 +799,7 @@ impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> Cip p.cr().modify(|w| w.set_algomode3(true)); } - fn init_phase_blocking(&self, p: pac::cryp::Cryp, cryp: &Cryp) { + fn init_phase_blocking(&self, p: pac::cryp::Cryp, cryp: &Cryp) { p.cr().modify(|w| w.set_gcm_ccmph(0)); cryp.write_bytes_blocking(Self::BLOCK_SIZE, &self.block0); @@ -821,14 +808,10 @@ impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> Cip while p.cr().read().crypen() {} } - async fn init_phase(&self, p: pac::cryp::Cryp, cryp: &mut Cryp<'_, T, DmaIn, DmaOut>) - where - DmaIn: crate::cryp::DmaIn, - DmaOut: crate::cryp::DmaOut, - { + async fn init_phase(&self, p: pac::cryp::Cryp, cryp: &mut Cryp<'_, T, Async>) { p.cr().modify(|w| w.set_gcm_ccmph(0)); - Cryp::::write_bytes(&mut cryp.indma, Self::BLOCK_SIZE, &self.block0).await; + Cryp::::write_bytes(cryp.indma.as_mut().unwrap(), Self::BLOCK_SIZE, &self.block0).await; p.cr().modify(|w| w.set_crypen(true)); while p.cr().read().crypen() {} @@ -865,10 +848,10 @@ impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> Cip } #[cfg(cryp_v2)] - fn post_final_blocking( + fn post_final_blocking( &self, p: pac::cryp::Cryp, - cryp: &Cryp, + cryp: &Cryp, dir: Direction, int_data: &mut [u8; AES_BLOCK_SIZE], temp1: [u32; 4], @@ -902,18 +885,15 @@ impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> Cip } #[cfg(cryp_v2)] - async fn post_final( + async fn post_final( &self, p: pac::cryp::Cryp, - cryp: &mut Cryp<'_, T, DmaIn, DmaOut>, + cryp: &mut Cryp<'_, T, Async>, dir: Direction, int_data: &mut [u8; AES_BLOCK_SIZE], temp1: [u32; 4], padding_mask: [u8; 16], - ) where - DmaIn: crate::cryp::DmaIn, - DmaOut: crate::cryp::DmaOut, - { + ) { if dir == Direction::Decrypt { //Handle special CCM partial block process. let mut temp2 = [0; 4]; @@ -937,7 +917,7 @@ impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> Cip in_data[i] = int_word; in_data[i] = in_data[i] ^ temp1[i] ^ temp2[i]; } - Cryp::::write_words(&mut cryp.indma, Self::BLOCK_SIZE, &in_data).await; + Cryp::::write_words(cryp.indma.as_mut().unwrap(), Self::BLOCK_SIZE, &in_data).await; } } } @@ -1007,26 +987,26 @@ pub enum Direction { } /// Crypto Accelerator Driver -pub struct Cryp<'d, T: Instance, DmaIn = NoDma, DmaOut = NoDma> { +pub struct Cryp<'d, T: Instance, M: Mode> { _peripheral: PeripheralRef<'d, T>, - indma: PeripheralRef<'d, DmaIn>, - outdma: PeripheralRef<'d, DmaOut>, + _phantom: PhantomData, + indma: Option>, + outdma: Option>, } -impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> { - /// Create a new CRYP driver. - pub fn new( +impl<'d, T: Instance> Cryp<'d, T, Blocking> { + /// Create a new CRYP driver in blocking mode. + pub fn new_blocking( peri: impl Peripheral

+ 'd, - indma: impl Peripheral

+ 'd, - outdma: impl Peripheral

+ 'd, _irq: impl interrupt::typelevel::Binding> + 'd, ) -> Self { rcc::enable_and_reset::(); - into_ref!(peri, indma, outdma); + into_ref!(peri); let instance = Self { _peripheral: peri, - indma: indma, - outdma: outdma, + _phantom: PhantomData, + indma: None, + outdma: None, }; T::Interrupt::unpend(); @@ -1034,7 +1014,9 @@ impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> { instance } +} +impl<'d, T: Instance, M: Mode> Cryp<'d, T, M> { /// Start a new encrypt or decrypt operation for the given cipher. pub fn start_blocking<'c, C: Cipher<'c> + CipherSized + IVSized>( &self, @@ -1114,89 +1096,6 @@ impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> { ctx } - /// Start a new encrypt or decrypt operation for the given cipher. - pub async fn start<'c, C: Cipher<'c> + CipherSized + IVSized>( - &mut self, - cipher: &'c C, - dir: Direction, - ) -> Context<'c, C> - where - DmaIn: crate::cryp::DmaIn, - DmaOut: crate::cryp::DmaOut, - { - let mut ctx: Context<'c, C> = Context { - dir, - last_block_processed: false, - cr: 0, - iv: [0; 4], - csgcmccm: [0; 8], - csgcm: [0; 8], - aad_complete: false, - header_len: 0, - payload_len: 0, - cipher: cipher, - phantom_data: PhantomData, - header_processed: false, - aad_buffer: [0; 16], - aad_buffer_len: 0, - }; - - T::regs().cr().modify(|w| w.set_crypen(false)); - - let key = ctx.cipher.key(); - - if key.len() == (128 / 8) { - T::regs().cr().modify(|w| w.set_keysize(0)); - } else if key.len() == (192 / 8) { - T::regs().cr().modify(|w| w.set_keysize(1)); - } else if key.len() == (256 / 8) { - T::regs().cr().modify(|w| w.set_keysize(2)); - } - - self.load_key(key); - - // Set data type to 8-bit. This will match software implementations. - T::regs().cr().modify(|w| w.set_datatype(2)); - - ctx.cipher.prepare_key(T::regs()); - - ctx.cipher.set_algomode(T::regs()); - - // Set encrypt/decrypt - if dir == Direction::Encrypt { - T::regs().cr().modify(|w| w.set_algodir(false)); - } else { - T::regs().cr().modify(|w| w.set_algodir(true)); - } - - // Load the IV into the registers. - let iv = ctx.cipher.iv(); - let mut full_iv: [u8; 16] = [0; 16]; - full_iv[0..iv.len()].copy_from_slice(iv); - let mut iv_idx = 0; - let mut iv_word: [u8; 4] = [0; 4]; - iv_word.copy_from_slice(&full_iv[iv_idx..iv_idx + 4]); - iv_idx += 4; - T::regs().init(0).ivlr().write_value(u32::from_be_bytes(iv_word)); - iv_word.copy_from_slice(&full_iv[iv_idx..iv_idx + 4]); - iv_idx += 4; - T::regs().init(0).ivrr().write_value(u32::from_be_bytes(iv_word)); - iv_word.copy_from_slice(&full_iv[iv_idx..iv_idx + 4]); - iv_idx += 4; - T::regs().init(1).ivlr().write_value(u32::from_be_bytes(iv_word)); - iv_word.copy_from_slice(&full_iv[iv_idx..iv_idx + 4]); - T::regs().init(1).ivrr().write_value(u32::from_be_bytes(iv_word)); - - // Flush in/out FIFOs - T::regs().cr().modify(|w| w.fflush()); - - ctx.cipher.init_phase(T::regs(), self).await; - - self.store_context(&mut ctx); - - ctx - } - #[cfg(any(cryp_v2, cryp_v3, cryp_v4))] /// Controls the header phase of cipher processing. /// This function is only valid for authenticated ciphers including GCM, CCM, and GMAC. @@ -1294,101 +1193,6 @@ impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> { self.store_context(ctx); } - #[cfg(any(cryp_v2, cryp_v3, cryp_v4))] - /// Controls the header phase of cipher processing. - /// This function is only valid for authenticated ciphers including GCM, CCM, and GMAC. - /// All additional associated data (AAD) must be supplied to this function prior to starting the payload phase with `payload`. - /// The AAD must be supplied in multiples of the block size (128-bits for AES, 64-bits for DES), except when supplying the last block. - /// When supplying the last block of AAD, `last_aad_block` must be `true`. - pub async fn aad<'c, const TAG_SIZE: usize, C: Cipher<'c> + CipherSized + IVSized + CipherAuthenticated>( - &mut self, - ctx: &mut Context<'c, C>, - aad: &[u8], - last_aad_block: bool, - ) where - DmaIn: crate::cryp::DmaIn, - DmaOut: crate::cryp::DmaOut, - { - self.load_context(ctx); - - // Perform checks for correctness. - if ctx.aad_complete { - panic!("Cannot update AAD after starting payload!") - } - - ctx.header_len += aad.len() as u64; - - // Header phase - T::regs().cr().modify(|w| w.set_crypen(false)); - T::regs().cr().modify(|w| w.set_gcm_ccmph(1)); - T::regs().cr().modify(|w| w.set_crypen(true)); - - // First write the header B1 block if not yet written. - if !ctx.header_processed { - ctx.header_processed = true; - let header = ctx.cipher.get_header_block(); - ctx.aad_buffer[0..header.len()].copy_from_slice(header); - ctx.aad_buffer_len += header.len(); - } - - // Fill the header block to make a full block. - let len_to_copy = min(aad.len(), C::BLOCK_SIZE - ctx.aad_buffer_len); - ctx.aad_buffer[ctx.aad_buffer_len..ctx.aad_buffer_len + len_to_copy].copy_from_slice(&aad[..len_to_copy]); - ctx.aad_buffer_len += len_to_copy; - ctx.aad_buffer[ctx.aad_buffer_len..].fill(0); - let mut aad_len_remaining = aad.len() - len_to_copy; - - if ctx.aad_buffer_len < C::BLOCK_SIZE { - // The buffer isn't full and this is the last buffer, so process it as is (already padded). - if last_aad_block { - Self::write_bytes(&mut self.indma, C::BLOCK_SIZE, &ctx.aad_buffer).await; - assert_eq!(T::regs().sr().read().ifem(), true); - - // Switch to payload phase. - ctx.aad_complete = true; - T::regs().cr().modify(|w| w.set_crypen(false)); - T::regs().cr().modify(|w| w.set_gcm_ccmph(2)); - T::regs().cr().modify(|w| w.fflush()); - } else { - // Just return because we don't yet have a full block to process. - return; - } - } else { - // Load the full block from the buffer. - Self::write_bytes(&mut self.indma, C::BLOCK_SIZE, &ctx.aad_buffer).await; - assert_eq!(T::regs().sr().read().ifem(), true); - } - - // Handle a partial block that is passed in. - ctx.aad_buffer_len = 0; - let leftovers = aad_len_remaining % C::BLOCK_SIZE; - ctx.aad_buffer[..leftovers].copy_from_slice(&aad[aad.len() - leftovers..aad.len()]); - ctx.aad_buffer_len += leftovers; - ctx.aad_buffer[ctx.aad_buffer_len..].fill(0); - aad_len_remaining -= leftovers; - assert_eq!(aad_len_remaining % C::BLOCK_SIZE, 0); - - // Load full data blocks into core. - let num_full_blocks = aad_len_remaining / C::BLOCK_SIZE; - let start_index = len_to_copy; - let end_index = start_index + (C::BLOCK_SIZE * num_full_blocks); - Self::write_bytes(&mut self.indma, C::BLOCK_SIZE, &aad[start_index..end_index]).await; - - if last_aad_block { - if leftovers > 0 { - Self::write_bytes(&mut self.indma, C::BLOCK_SIZE, &ctx.aad_buffer).await; - assert_eq!(T::regs().sr().read().ifem(), true); - } - // Switch to payload phase. - ctx.aad_complete = true; - T::regs().cr().modify(|w| w.set_crypen(false)); - T::regs().cr().modify(|w| w.set_gcm_ccmph(2)); - T::regs().cr().modify(|w| w.fflush()); - } - - self.store_context(ctx); - } - /// Performs encryption/decryption on the provided context. /// The context determines algorithm, mode, and state of the crypto accelerator. /// When the last piece of data is supplied, `last_block` should be `true`. @@ -1478,105 +1282,6 @@ impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> { self.store_context(ctx); } - /// Performs encryption/decryption on the provided context. - /// The context determines algorithm, mode, and state of the crypto accelerator. - /// When the last piece of data is supplied, `last_block` should be `true`. - /// This function panics under various mismatches of parameters. - /// Output buffer must be at least as long as the input buffer. - /// Data must be a multiple of block size (128-bits for AES, 64-bits for DES) for CBC and ECB modes. - /// Padding or ciphertext stealing must be managed by the application for these modes. - /// Data must also be a multiple of block size unless `last_block` is `true`. - pub async fn payload<'c, C: Cipher<'c> + CipherSized + IVSized>( - &mut self, - ctx: &mut Context<'c, C>, - input: &[u8], - output: &mut [u8], - last_block: bool, - ) where - DmaIn: crate::cryp::DmaIn, - DmaOut: crate::cryp::DmaOut, - { - self.load_context(ctx); - - let last_block_remainder = input.len() % C::BLOCK_SIZE; - - // Perform checks for correctness. - if !ctx.aad_complete && ctx.header_len > 0 { - panic!("Additional associated data must be processed first!"); - } else if !ctx.aad_complete { - #[cfg(any(cryp_v2, cryp_v3, cryp_v4))] - { - ctx.aad_complete = true; - T::regs().cr().modify(|w| w.set_crypen(false)); - T::regs().cr().modify(|w| w.set_gcm_ccmph(2)); - T::regs().cr().modify(|w| w.fflush()); - T::regs().cr().modify(|w| w.set_crypen(true)); - } - } - if ctx.last_block_processed { - panic!("The last block has already been processed!"); - } - if input.len() > output.len() { - panic!("Output buffer length must match input length."); - } - if !last_block { - if last_block_remainder != 0 { - panic!("Input length must be a multiple of {} bytes.", C::BLOCK_SIZE); - } - } - if C::REQUIRES_PADDING { - if last_block_remainder != 0 { - panic!("Input must be a multiple of {} bytes in ECB and CBC modes. Consider padding or ciphertext stealing.", C::BLOCK_SIZE); - } - } - if last_block { - ctx.last_block_processed = true; - } - - // Load data into core, block by block. - let num_full_blocks = input.len() / C::BLOCK_SIZE; - for block in 0..num_full_blocks { - let index = block * C::BLOCK_SIZE; - // Read block out - let read = Self::read_bytes( - &mut self.outdma, - C::BLOCK_SIZE, - &mut output[index..index + C::BLOCK_SIZE], - ); - // Write block in - let write = Self::write_bytes(&mut self.indma, C::BLOCK_SIZE, &input[index..index + C::BLOCK_SIZE]); - embassy_futures::join::join(read, write).await; - } - - // Handle the final block, which is incomplete. - if last_block_remainder > 0 { - let padding_len = C::BLOCK_SIZE - last_block_remainder; - let temp1 = ctx.cipher.pre_final(T::regs(), ctx.dir, padding_len); - - let mut intermediate_data: [u8; AES_BLOCK_SIZE] = [0; AES_BLOCK_SIZE]; - let mut last_block: [u8; AES_BLOCK_SIZE] = [0; AES_BLOCK_SIZE]; - last_block[..last_block_remainder].copy_from_slice(&input[input.len() - last_block_remainder..input.len()]); - let read = Self::read_bytes(&mut self.outdma, C::BLOCK_SIZE, &mut intermediate_data); - let write = Self::write_bytes(&mut self.indma, C::BLOCK_SIZE, &last_block); - embassy_futures::join::join(read, write).await; - - // Handle the last block depending on mode. - let output_len = output.len(); - output[output_len - last_block_remainder..output_len] - .copy_from_slice(&intermediate_data[0..last_block_remainder]); - - let mut mask: [u8; 16] = [0; 16]; - mask[..last_block_remainder].fill(0xFF); - ctx.cipher - .post_final(T::regs(), self, ctx.dir, &mut intermediate_data, temp1, mask) - .await; - } - - ctx.payload_len += input.len() as u64; - - self.store_context(ctx); - } - #[cfg(any(cryp_v2, cryp_v3, cryp_v4))] /// Generates an authentication tag for authenticated ciphers including GCM, CCM, and GMAC. /// Called after the all data has been encrypted/decrypted by `payload`. @@ -1623,57 +1328,6 @@ impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> { tag } - #[cfg(any(cryp_v2, cryp_v3, cryp_v4))] - // Generates an authentication tag for authenticated ciphers including GCM, CCM, and GMAC. - /// Called after the all data has been encrypted/decrypted by `payload`. - pub async fn finish< - 'c, - const TAG_SIZE: usize, - C: Cipher<'c> + CipherSized + IVSized + CipherAuthenticated, - >( - &mut self, - mut ctx: Context<'c, C>, - ) -> [u8; TAG_SIZE] - where - DmaIn: crate::cryp::DmaIn, - DmaOut: crate::cryp::DmaOut, - { - self.load_context(&mut ctx); - - T::regs().cr().modify(|w| w.set_crypen(false)); - T::regs().cr().modify(|w| w.set_gcm_ccmph(3)); - T::regs().cr().modify(|w| w.set_crypen(true)); - - let headerlen1: u32 = ((ctx.header_len * 8) >> 32) as u32; - let headerlen2: u32 = (ctx.header_len * 8) as u32; - let payloadlen1: u32 = ((ctx.payload_len * 8) >> 32) as u32; - let payloadlen2: u32 = (ctx.payload_len * 8) as u32; - - #[cfg(cryp_v2)] - let footer: [u32; 4] = [ - headerlen1.swap_bytes(), - headerlen2.swap_bytes(), - payloadlen1.swap_bytes(), - payloadlen2.swap_bytes(), - ]; - #[cfg(any(cryp_v3, cryp_v4))] - let footer: [u32; 4] = [headerlen1, headerlen2, payloadlen1, payloadlen2]; - - let write = Self::write_words(&mut self.indma, C::BLOCK_SIZE, &footer); - - let mut full_tag: [u8; 16] = [0; 16]; - let read = Self::read_bytes(&mut self.outdma, C::BLOCK_SIZE, &mut full_tag); - - embassy_futures::join::join(read, write).await; - - let mut tag: [u8; TAG_SIZE] = [0; TAG_SIZE]; - tag.copy_from_slice(&full_tag[0..TAG_SIZE]); - - T::regs().cr().modify(|w| w.set_crypen(false)); - - tag - } - fn load_key(&self, key: &[u8]) { // Load the key into the registers. let mut keyidx = 0; @@ -1774,31 +1428,6 @@ impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> { } } - async fn write_bytes(dma: &mut PeripheralRef<'_, DmaIn>, block_size: usize, blocks: &[u8]) - where - DmaIn: crate::cryp::DmaIn, - { - if blocks.len() == 0 { - return; - } - // Ensure input is a multiple of block size. - assert_eq!(blocks.len() % block_size, 0); - // Configure DMA to transfer input to crypto core. - let dma_request = dma.request(); - let dst_ptr: *mut u32 = T::regs().din().as_ptr(); - let num_words = blocks.len() / 4; - let src_ptr: *const [u8] = ptr::slice_from_raw_parts(blocks.as_ptr().cast(), num_words); - let options = TransferOptions { - #[cfg(not(gpdma))] - priority: crate::dma::Priority::High, - ..Default::default() - }; - let dma_transfer = unsafe { Transfer::new_write_raw(dma, dma_request, src_ptr, dst_ptr, options) }; - T::regs().dmacr().modify(|w| w.set_dien(true)); - // Wait for the transfer to complete. - dma_transfer.await; - } - #[cfg(any(cryp_v2, cryp_v3, cryp_v4))] fn write_words_blocking(&self, block_size: usize, blocks: &[u32]) { assert_eq!((blocks.len() * 4) % block_size, 0); @@ -1813,32 +1442,6 @@ impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> { } } - #[cfg(any(cryp_v2, cryp_v3, cryp_v4))] - async fn write_words(dma: &mut PeripheralRef<'_, DmaIn>, block_size: usize, blocks: &[u32]) - where - DmaIn: crate::cryp::DmaIn, - { - if blocks.len() == 0 { - return; - } - // Ensure input is a multiple of block size. - assert_eq!((blocks.len() * 4) % block_size, 0); - // Configure DMA to transfer input to crypto core. - let dma_request = dma.request(); - let dst_ptr: *mut u32 = T::regs().din().as_ptr(); - let num_words = blocks.len(); - let src_ptr: *const [u32] = ptr::slice_from_raw_parts(blocks.as_ptr().cast(), num_words); - let options = TransferOptions { - #[cfg(not(gpdma))] - priority: crate::dma::Priority::High, - ..Default::default() - }; - let dma_transfer = unsafe { Transfer::new_write_raw(dma, dma_request, src_ptr, dst_ptr, options) }; - T::regs().dmacr().modify(|w| w.set_dien(true)); - // Wait for the transfer to complete. - dma_transfer.await; - } - fn read_bytes_blocking(&self, block_size: usize, blocks: &mut [u8]) { // Block until there is output to read. while !T::regs().sr().read().ofne() {} @@ -1853,18 +1456,408 @@ impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> { index += 4; } } +} - async fn read_bytes(dma: &mut PeripheralRef<'_, DmaOut>, block_size: usize, blocks: &mut [u8]) - where - DmaOut: crate::cryp::DmaOut, - { +impl<'d, T: Instance> Cryp<'d, T, Async> { + /// Create a new CRYP driver. + pub fn new( + peri: impl Peripheral

+ 'd, + indma: impl Peripheral

> + 'd, + outdma: impl Peripheral

> + 'd, + _irq: impl interrupt::typelevel::Binding> + 'd, + ) -> Self { + rcc::enable_and_reset::(); + into_ref!(peri, indma, outdma); + let instance = Self { + _peripheral: peri, + _phantom: PhantomData, + indma: new_dma!(indma), + outdma: new_dma!(outdma), + }; + + T::Interrupt::unpend(); + unsafe { T::Interrupt::enable() }; + + instance + } + + /// Start a new encrypt or decrypt operation for the given cipher. + pub async fn start<'c, C: Cipher<'c> + CipherSized + IVSized>( + &mut self, + cipher: &'c C, + dir: Direction, + ) -> Context<'c, C> { + let mut ctx: Context<'c, C> = Context { + dir, + last_block_processed: false, + cr: 0, + iv: [0; 4], + csgcmccm: [0; 8], + csgcm: [0; 8], + aad_complete: false, + header_len: 0, + payload_len: 0, + cipher: cipher, + phantom_data: PhantomData, + header_processed: false, + aad_buffer: [0; 16], + aad_buffer_len: 0, + }; + + T::regs().cr().modify(|w| w.set_crypen(false)); + + let key = ctx.cipher.key(); + + if key.len() == (128 / 8) { + T::regs().cr().modify(|w| w.set_keysize(0)); + } else if key.len() == (192 / 8) { + T::regs().cr().modify(|w| w.set_keysize(1)); + } else if key.len() == (256 / 8) { + T::regs().cr().modify(|w| w.set_keysize(2)); + } + + self.load_key(key); + + // Set data type to 8-bit. This will match software implementations. + T::regs().cr().modify(|w| w.set_datatype(2)); + + ctx.cipher.prepare_key(T::regs()); + + ctx.cipher.set_algomode(T::regs()); + + // Set encrypt/decrypt + if dir == Direction::Encrypt { + T::regs().cr().modify(|w| w.set_algodir(false)); + } else { + T::regs().cr().modify(|w| w.set_algodir(true)); + } + + // Load the IV into the registers. + let iv = ctx.cipher.iv(); + let mut full_iv: [u8; 16] = [0; 16]; + full_iv[0..iv.len()].copy_from_slice(iv); + let mut iv_idx = 0; + let mut iv_word: [u8; 4] = [0; 4]; + iv_word.copy_from_slice(&full_iv[iv_idx..iv_idx + 4]); + iv_idx += 4; + T::regs().init(0).ivlr().write_value(u32::from_be_bytes(iv_word)); + iv_word.copy_from_slice(&full_iv[iv_idx..iv_idx + 4]); + iv_idx += 4; + T::regs().init(0).ivrr().write_value(u32::from_be_bytes(iv_word)); + iv_word.copy_from_slice(&full_iv[iv_idx..iv_idx + 4]); + iv_idx += 4; + T::regs().init(1).ivlr().write_value(u32::from_be_bytes(iv_word)); + iv_word.copy_from_slice(&full_iv[iv_idx..iv_idx + 4]); + T::regs().init(1).ivrr().write_value(u32::from_be_bytes(iv_word)); + + // Flush in/out FIFOs + T::regs().cr().modify(|w| w.fflush()); + + ctx.cipher.init_phase(T::regs(), self).await; + + self.store_context(&mut ctx); + + ctx + } + + #[cfg(any(cryp_v2, cryp_v3, cryp_v4))] + /// Controls the header phase of cipher processing. + /// This function is only valid for authenticated ciphers including GCM, CCM, and GMAC. + /// All additional associated data (AAD) must be supplied to this function prior to starting the payload phase with `payload`. + /// The AAD must be supplied in multiples of the block size (128-bits for AES, 64-bits for DES), except when supplying the last block. + /// When supplying the last block of AAD, `last_aad_block` must be `true`. + pub async fn aad< + 'c, + const TAG_SIZE: usize, + C: Cipher<'c> + CipherSized + IVSized + CipherAuthenticated, + >( + &mut self, + ctx: &mut Context<'c, C>, + aad: &[u8], + last_aad_block: bool, + ) { + self.load_context(ctx); + + // Perform checks for correctness. + if ctx.aad_complete { + panic!("Cannot update AAD after starting payload!") + } + + ctx.header_len += aad.len() as u64; + + // Header phase + T::regs().cr().modify(|w| w.set_crypen(false)); + T::regs().cr().modify(|w| w.set_gcm_ccmph(1)); + T::regs().cr().modify(|w| w.set_crypen(true)); + + // First write the header B1 block if not yet written. + if !ctx.header_processed { + ctx.header_processed = true; + let header = ctx.cipher.get_header_block(); + ctx.aad_buffer[0..header.len()].copy_from_slice(header); + ctx.aad_buffer_len += header.len(); + } + + // Fill the header block to make a full block. + let len_to_copy = min(aad.len(), C::BLOCK_SIZE - ctx.aad_buffer_len); + ctx.aad_buffer[ctx.aad_buffer_len..ctx.aad_buffer_len + len_to_copy].copy_from_slice(&aad[..len_to_copy]); + ctx.aad_buffer_len += len_to_copy; + ctx.aad_buffer[ctx.aad_buffer_len..].fill(0); + let mut aad_len_remaining = aad.len() - len_to_copy; + + if ctx.aad_buffer_len < C::BLOCK_SIZE { + // The buffer isn't full and this is the last buffer, so process it as is (already padded). + if last_aad_block { + Self::write_bytes(self.indma.as_mut().unwrap(), C::BLOCK_SIZE, &ctx.aad_buffer).await; + assert_eq!(T::regs().sr().read().ifem(), true); + + // Switch to payload phase. + ctx.aad_complete = true; + T::regs().cr().modify(|w| w.set_crypen(false)); + T::regs().cr().modify(|w| w.set_gcm_ccmph(2)); + T::regs().cr().modify(|w| w.fflush()); + } else { + // Just return because we don't yet have a full block to process. + return; + } + } else { + // Load the full block from the buffer. + Self::write_bytes(self.indma.as_mut().unwrap(), C::BLOCK_SIZE, &ctx.aad_buffer).await; + assert_eq!(T::regs().sr().read().ifem(), true); + } + + // Handle a partial block that is passed in. + ctx.aad_buffer_len = 0; + let leftovers = aad_len_remaining % C::BLOCK_SIZE; + ctx.aad_buffer[..leftovers].copy_from_slice(&aad[aad.len() - leftovers..aad.len()]); + ctx.aad_buffer_len += leftovers; + ctx.aad_buffer[ctx.aad_buffer_len..].fill(0); + aad_len_remaining -= leftovers; + assert_eq!(aad_len_remaining % C::BLOCK_SIZE, 0); + + // Load full data blocks into core. + let num_full_blocks = aad_len_remaining / C::BLOCK_SIZE; + let start_index = len_to_copy; + let end_index = start_index + (C::BLOCK_SIZE * num_full_blocks); + Self::write_bytes( + self.indma.as_mut().unwrap(), + C::BLOCK_SIZE, + &aad[start_index..end_index], + ) + .await; + + if last_aad_block { + if leftovers > 0 { + Self::write_bytes(self.indma.as_mut().unwrap(), C::BLOCK_SIZE, &ctx.aad_buffer).await; + assert_eq!(T::regs().sr().read().ifem(), true); + } + // Switch to payload phase. + ctx.aad_complete = true; + T::regs().cr().modify(|w| w.set_crypen(false)); + T::regs().cr().modify(|w| w.set_gcm_ccmph(2)); + T::regs().cr().modify(|w| w.fflush()); + } + + self.store_context(ctx); + } + + /// Performs encryption/decryption on the provided context. + /// The context determines algorithm, mode, and state of the crypto accelerator. + /// When the last piece of data is supplied, `last_block` should be `true`. + /// This function panics under various mismatches of parameters. + /// Output buffer must be at least as long as the input buffer. + /// Data must be a multiple of block size (128-bits for AES, 64-bits for DES) for CBC and ECB modes. + /// Padding or ciphertext stealing must be managed by the application for these modes. + /// Data must also be a multiple of block size unless `last_block` is `true`. + pub async fn payload<'c, C: Cipher<'c> + CipherSized + IVSized>( + &mut self, + ctx: &mut Context<'c, C>, + input: &[u8], + output: &mut [u8], + last_block: bool, + ) { + self.load_context(ctx); + + let last_block_remainder = input.len() % C::BLOCK_SIZE; + + // Perform checks for correctness. + if !ctx.aad_complete && ctx.header_len > 0 { + panic!("Additional associated data must be processed first!"); + } else if !ctx.aad_complete { + #[cfg(any(cryp_v2, cryp_v3, cryp_v4))] + { + ctx.aad_complete = true; + T::regs().cr().modify(|w| w.set_crypen(false)); + T::regs().cr().modify(|w| w.set_gcm_ccmph(2)); + T::regs().cr().modify(|w| w.fflush()); + T::regs().cr().modify(|w| w.set_crypen(true)); + } + } + if ctx.last_block_processed { + panic!("The last block has already been processed!"); + } + if input.len() > output.len() { + panic!("Output buffer length must match input length."); + } + if !last_block { + if last_block_remainder != 0 { + panic!("Input length must be a multiple of {} bytes.", C::BLOCK_SIZE); + } + } + if C::REQUIRES_PADDING { + if last_block_remainder != 0 { + panic!("Input must be a multiple of {} bytes in ECB and CBC modes. Consider padding or ciphertext stealing.", C::BLOCK_SIZE); + } + } + if last_block { + ctx.last_block_processed = true; + } + + // Load data into core, block by block. + let num_full_blocks = input.len() / C::BLOCK_SIZE; + for block in 0..num_full_blocks { + let index = block * C::BLOCK_SIZE; + // Read block out + let read = Self::read_bytes( + self.outdma.as_mut().unwrap(), + C::BLOCK_SIZE, + &mut output[index..index + C::BLOCK_SIZE], + ); + // Write block in + let write = Self::write_bytes( + self.indma.as_mut().unwrap(), + C::BLOCK_SIZE, + &input[index..index + C::BLOCK_SIZE], + ); + embassy_futures::join::join(read, write).await; + } + + // Handle the final block, which is incomplete. + if last_block_remainder > 0 { + let padding_len = C::BLOCK_SIZE - last_block_remainder; + let temp1 = ctx.cipher.pre_final(T::regs(), ctx.dir, padding_len); + + let mut intermediate_data: [u8; AES_BLOCK_SIZE] = [0; AES_BLOCK_SIZE]; + let mut last_block: [u8; AES_BLOCK_SIZE] = [0; AES_BLOCK_SIZE]; + last_block[..last_block_remainder].copy_from_slice(&input[input.len() - last_block_remainder..input.len()]); + let read = Self::read_bytes(self.outdma.as_mut().unwrap(), C::BLOCK_SIZE, &mut intermediate_data); + let write = Self::write_bytes(self.indma.as_mut().unwrap(), C::BLOCK_SIZE, &last_block); + embassy_futures::join::join(read, write).await; + + // Handle the last block depending on mode. + let output_len = output.len(); + output[output_len - last_block_remainder..output_len] + .copy_from_slice(&intermediate_data[0..last_block_remainder]); + + let mut mask: [u8; 16] = [0; 16]; + mask[..last_block_remainder].fill(0xFF); + ctx.cipher + .post_final(T::regs(), self, ctx.dir, &mut intermediate_data, temp1, mask) + .await; + } + + ctx.payload_len += input.len() as u64; + + self.store_context(ctx); + } + + #[cfg(any(cryp_v2, cryp_v3, cryp_v4))] + // Generates an authentication tag for authenticated ciphers including GCM, CCM, and GMAC. + /// Called after the all data has been encrypted/decrypted by `payload`. + pub async fn finish< + 'c, + const TAG_SIZE: usize, + C: Cipher<'c> + CipherSized + IVSized + CipherAuthenticated, + >( + &mut self, + mut ctx: Context<'c, C>, + ) -> [u8; TAG_SIZE] { + self.load_context(&mut ctx); + + T::regs().cr().modify(|w| w.set_crypen(false)); + T::regs().cr().modify(|w| w.set_gcm_ccmph(3)); + T::regs().cr().modify(|w| w.set_crypen(true)); + + let headerlen1: u32 = ((ctx.header_len * 8) >> 32) as u32; + let headerlen2: u32 = (ctx.header_len * 8) as u32; + let payloadlen1: u32 = ((ctx.payload_len * 8) >> 32) as u32; + let payloadlen2: u32 = (ctx.payload_len * 8) as u32; + + #[cfg(cryp_v2)] + let footer: [u32; 4] = [ + headerlen1.swap_bytes(), + headerlen2.swap_bytes(), + payloadlen1.swap_bytes(), + payloadlen2.swap_bytes(), + ]; + #[cfg(any(cryp_v3, cryp_v4))] + let footer: [u32; 4] = [headerlen1, headerlen2, payloadlen1, payloadlen2]; + + let write = Self::write_words(self.indma.as_mut().unwrap(), C::BLOCK_SIZE, &footer); + + let mut full_tag: [u8; 16] = [0; 16]; + let read = Self::read_bytes(self.outdma.as_mut().unwrap(), C::BLOCK_SIZE, &mut full_tag); + + embassy_futures::join::join(read, write).await; + + let mut tag: [u8; TAG_SIZE] = [0; TAG_SIZE]; + tag.copy_from_slice(&full_tag[0..TAG_SIZE]); + + T::regs().cr().modify(|w| w.set_crypen(false)); + + tag + } + + async fn write_bytes(dma: &mut ChannelAndRequest<'d>, block_size: usize, blocks: &[u8]) { + if blocks.len() == 0 { + return; + } + // Ensure input is a multiple of block size. + assert_eq!(blocks.len() % block_size, 0); + // Configure DMA to transfer input to crypto core. + let dst_ptr: *mut u32 = T::regs().din().as_ptr(); + let num_words = blocks.len() / 4; + let src_ptr: *const [u8] = ptr::slice_from_raw_parts(blocks.as_ptr().cast(), num_words); + let options = TransferOptions { + #[cfg(not(gpdma))] + priority: crate::dma::Priority::High, + ..Default::default() + }; + let dma_transfer = unsafe { dma.write_raw(src_ptr, dst_ptr, options) }; + T::regs().dmacr().modify(|w| w.set_dien(true)); + // Wait for the transfer to complete. + dma_transfer.await; + } + + #[cfg(any(cryp_v2, cryp_v3, cryp_v4))] + async fn write_words(dma: &mut ChannelAndRequest<'d>, block_size: usize, blocks: &[u32]) { + if blocks.len() == 0 { + return; + } + // Ensure input is a multiple of block size. + assert_eq!((blocks.len() * 4) % block_size, 0); + // Configure DMA to transfer input to crypto core. + let dst_ptr: *mut u32 = T::regs().din().as_ptr(); + let num_words = blocks.len(); + let src_ptr: *const [u32] = ptr::slice_from_raw_parts(blocks.as_ptr().cast(), num_words); + let options = TransferOptions { + #[cfg(not(gpdma))] + priority: crate::dma::Priority::High, + ..Default::default() + }; + let dma_transfer = unsafe { dma.write_raw(src_ptr, dst_ptr, options) }; + T::regs().dmacr().modify(|w| w.set_dien(true)); + // Wait for the transfer to complete. + dma_transfer.await; + } + + async fn read_bytes(dma: &mut ChannelAndRequest<'d>, block_size: usize, blocks: &mut [u8]) { if blocks.len() == 0 { return; } // Ensure input is a multiple of block size. assert_eq!(blocks.len() % block_size, 0); // Configure DMA to get output from crypto core. - let dma_request = dma.request(); let src_ptr = T::regs().dout().as_ptr(); let num_words = blocks.len() / 4; let dst_ptr = ptr::slice_from_raw_parts_mut(blocks.as_mut_ptr().cast(), num_words); @@ -1873,7 +1866,7 @@ impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> { priority: crate::dma::Priority::VeryHigh, ..Default::default() }; - let dma_transfer = unsafe { Transfer::new_read_raw(dma, dma_request, src_ptr, dst_ptr, options) }; + let dma_transfer = unsafe { dma.read_raw(src_ptr, dst_ptr, options) }; T::regs().dmacr().modify(|w| w.set_doen(true)); // Wait for the transfer to complete. dma_transfer.await; diff --git a/embassy-stm32/src/dma/mod.rs b/embassy-stm32/src/dma/mod.rs index 66c4aa53c..ac4a0f98e 100644 --- a/embassy-stm32/src/dma/mod.rs +++ b/embassy-stm32/src/dma/mod.rs @@ -108,17 +108,6 @@ impl Channel for AnyChannel {} const CHANNEL_COUNT: usize = crate::_generated::DMA_CHANNELS.len(); static STATE: [ChannelState; CHANNEL_COUNT] = [ChannelState::NEW; CHANNEL_COUNT]; -/// "No DMA" placeholder. -/// -/// You may pass this in place of a real DMA channel when creating a driver -/// to indicate it should not use DMA. -/// -/// This often causes async functionality to not be available on the instance, -/// leaving only blocking functionality. -pub struct NoDma; - -impl_peripheral!(NoDma); - // safety: must be called only once at startup pub(crate) unsafe fn init( cs: critical_section::CriticalSection, From db7759ea7db24b00e6f585f560c73bad9fdc1def Mon Sep 17 00:00:00 2001 From: i509VCB Date: Tue, 25 Mar 2025 23:47:28 -0500 Subject: [PATCH 0875/1217] mspm0: disable events before clearing gpio ris --- embassy-mspm0/src/gpio.rs | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/embassy-mspm0/src/gpio.rs b/embassy-mspm0/src/gpio.rs index e1eb7eecf..1048d980e 100644 --- a/embassy-mspm0/src/gpio.rs +++ b/embassy-mspm0/src/gpio.rs @@ -935,15 +935,32 @@ impl<'d> InputFuture<'d> { fn new(pin: PeripheralRef<'d, AnyPin>, polarity: Polarity) -> Self { let block = pin.block(); + // Before clearing any previous edge events, we must disable events. + // + // If we don't do this, it is possible that after we clear the interrupt, the current event + // the hardware is listening for may not be the same event we will configure. This may result + // in RIS being set. Then when interrupts are unmasked and RIS is set, we may get the wrong event + // causing an interrupt. + // + // Selecting which polarity events happen is a RMW operation. + critical_section::with(|_cs| { + if pin.bit_index() >= 16 { + block.polarity31_16().modify(|w| { + w.set_dio(pin.bit_index() - 16, Polarity::DISABLE); + }); + } else { + block.polarity15_0().modify(|w| { + w.set_dio(pin.bit_index(), Polarity::DISABLE); + }); + }; + }); + // First clear the bit for this event. Otherwise previous edge events may be recorded. block.cpu_int().iclr().write(|w| { w.set_dio(pin.bit_index(), true); }); - // Selecting which polarity events happens is a RMW operation. - // - // Guard with a critical section in case two different threads try to select events at the - // same time. + // Selecting which polarity events happen is a RMW operation. critical_section::with(|_cs| { // Tell the hardware which pin event we want to receive. if pin.bit_index() >= 16 { From 1b6e563260ec2b00cb518e0e801222ebd1ba9902 Mon Sep 17 00:00:00 2001 From: Adrian Wowk Date: Wed, 26 Mar 2025 17:11:27 -0500 Subject: [PATCH 0876/1217] rp/adc: fix potential race condition This commit rearranges the Adc::wait_for_ready function to make sure that wakers are registered before the interrupt is enabled, and keeps enabling the interrupt until the ADC is ready --- embassy-rp/src/adc.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/embassy-rp/src/adc.rs b/embassy-rp/src/adc.rs index 8defb5231..1265a22a0 100644 --- a/embassy-rp/src/adc.rs +++ b/embassy-rp/src/adc.rs @@ -205,11 +205,13 @@ impl<'d> Adc<'d, Async> { fn wait_for_ready() -> impl Future { let r = Self::regs(); - r.inte().write(|w| w.set_fifo(true)); - compiler_fence(Ordering::SeqCst); poll_fn(move |cx| { WAKER.register(cx.waker()); + + r.inte().write(|w| w.set_fifo(true)); + compiler_fence(Ordering::SeqCst); + if r.cs().read().ready() { return Poll::Ready(()); } From 5777284304ec4b718204ed67d004f1e20856e3f9 Mon Sep 17 00:00:00 2001 From: Adrian Wowk Date: Wed, 26 Mar 2025 19:05:27 -0500 Subject: [PATCH 0877/1217] rp: rename BOOTROM_BASE to BOOTRAM_BASE Previously the constant pointing at the base of the bootram was incorrectly called BOOTROM_BASE. According to the datasheet, the bootrom is a 32K region starting at 0x00000000 while the bootram is a 1K region of SRAM starting at 0x400e0000. --- embassy-rp/src/flash.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/embassy-rp/src/flash.rs b/embassy-rp/src/flash.rs index fbc8b35ec..a69b44961 100644 --- a/embassy-rp/src/flash.rs +++ b/embassy-rp/src/flash.rs @@ -19,7 +19,7 @@ pub const FLASH_BASE: *const u32 = 0x10000000 as _; /// Address for xip setup function set up by the 235x bootrom. #[cfg(feature = "_rp235x")] -pub const BOOTROM_BASE: *const u32 = 0x400e0000 as _; +pub const BOOTRAM_BASE: *const u32 = 0x400e0000 as _; /// If running from RAM, we might have no boot2. Use bootrom `flash_enter_cmd_xip` instead. // TODO: when run-from-ram is set, completely skip the "pause cores and jumpp to RAM" dance. @@ -527,7 +527,7 @@ mod ram_helpers { #[cfg(feature = "rp2040")] rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256); #[cfg(feature = "_rp235x")] - core::ptr::copy_nonoverlapping(BOOTROM_BASE as *const u8, boot2.as_mut_ptr() as *mut u8, 256); + core::ptr::copy_nonoverlapping(BOOTRAM_BASE as *const u8, boot2.as_mut_ptr() as *mut u8, 256); flash_function_pointers_with_boot2(true, false, &boot2) } else { flash_function_pointers(true, false) @@ -560,7 +560,7 @@ mod ram_helpers { #[cfg(feature = "rp2040")] rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256); #[cfg(feature = "_rp235x")] - core::ptr::copy_nonoverlapping(BOOTROM_BASE as *const u8, (boot2).as_mut_ptr() as *mut u8, 256); + core::ptr::copy_nonoverlapping(BOOTRAM_BASE as *const u8, (boot2).as_mut_ptr() as *mut u8, 256); flash_function_pointers_with_boot2(true, true, &boot2) } else { flash_function_pointers(true, true) @@ -598,7 +598,7 @@ mod ram_helpers { #[cfg(feature = "rp2040")] rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256); #[cfg(feature = "_rp235x")] - core::ptr::copy_nonoverlapping(BOOTROM_BASE as *const u8, boot2.as_mut_ptr() as *mut u8, 256); + core::ptr::copy_nonoverlapping(BOOTRAM_BASE as *const u8, boot2.as_mut_ptr() as *mut u8, 256); flash_function_pointers_with_boot2(false, true, &boot2) } else { flash_function_pointers(false, true) From 9e31a45134ec8ab114108825989c4e623c7ccfe8 Mon Sep 17 00:00:00 2001 From: Tobias Naumann Date: Wed, 26 Mar 2025 18:04:59 +0100 Subject: [PATCH 0878/1217] Fix unused imports --- embassy-stm32/src/usart/mod.rs | 5 ----- embassy-stm32/src/usart/ringbuffered.rs | 8 ++------ 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index 568067360..e52647795 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -18,11 +18,6 @@ use crate::gpio::{self, AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed} use crate::interrupt::typelevel::Interrupt as _; use crate::interrupt::{self, Interrupt, InterruptExt}; use crate::mode::{Async, Blocking, Mode}; -#[allow(unused_imports)] -#[cfg(not(any(usart_v1, usart_v2)))] -use crate::pac::usart::regs::Isr as Sr; -#[cfg(any(usart_v1, usart_v2))] -use crate::pac::usart::regs::Sr; #[cfg(not(any(usart_v1, usart_v2)))] use crate::pac::usart::Lpuart as Regs; #[cfg(any(usart_v1, usart_v2))] diff --git a/embassy-stm32/src/usart/ringbuffered.rs b/embassy-stm32/src/usart/ringbuffered.rs index 3ab9f95e0..69423c940 100644 --- a/embassy-stm32/src/usart/ringbuffered.rs +++ b/embassy-stm32/src/usart/ringbuffered.rs @@ -8,16 +8,12 @@ use embassy_hal_internal::PeripheralRef; use embedded_io_async::ReadReady; use futures_util::future::{select, Either}; -use super::{ - clear_interrupt_flags, rdr, reconfigure, set_baudrate, sr, Config, ConfigError, Error, Info, State, UartRx, -}; +use super::{rdr, reconfigure, set_baudrate, sr, Config, ConfigError, Error, Info, State, UartRx}; use crate::dma::ReadableRingBuffer; use crate::gpio::{AnyPin, SealedPin as _}; use crate::mode::Async; -#[cfg(any(usart_v3, usart_v4))] -use crate::pac::usart::regs; use crate::time::Hertz; -use crate::usart::{Regs, Sr}; +use crate::usart::Regs; /// Rx-only Ring-buffered UART Driver /// From 14d079ae84ac28ce860015ad6ca8d040edf3f065 Mon Sep 17 00:00:00 2001 From: Tobias Naumann Date: Thu, 27 Mar 2025 12:03:52 +0100 Subject: [PATCH 0879/1217] Cleanup stm32_metapac register usage in usart module --- embassy-stm32/src/usart/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index e52647795..803a5d579 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -398,7 +398,7 @@ pub struct UartRx<'d, M: Mode> { rx_dma: Option>, detect_previous_overrun: bool, #[cfg(any(usart_v1, usart_v2))] - buffered_sr: stm32_metapac::usart::regs::Sr, + buffered_sr: regs::Sr, _phantom: PhantomData, } @@ -945,7 +945,7 @@ impl<'d, M: Mode> UartRx<'d, M> { rx_dma, detect_previous_overrun: config.detect_previous_overrun, #[cfg(any(usart_v1, usart_v2))] - buffered_sr: stm32_metapac::usart::regs::Sr(0), + buffered_sr: regs::Sr(0), }; this.enable_and_configure(&config)?; Ok(this) @@ -1444,7 +1444,7 @@ impl<'d, M: Mode> Uart<'d, M> { rx_dma, detect_previous_overrun: config.detect_previous_overrun, #[cfg(any(usart_v1, usart_v2))] - buffered_sr: stm32_metapac::usart::regs::Sr(0), + buffered_sr: regs::Sr(0), }, }; this.enable_and_configure(&config)?; From d41eeeae79388f219bf6a84e2f7bde9f6b532516 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Wed, 26 Mar 2025 16:01:37 +0100 Subject: [PATCH 0880/1217] Remove Peripheral trait, rename PeripheralRef->Peri. --- README.md | 6 +- cyw43-pio/src/lib.rs | 22 +- embassy-boot-nrf/src/lib.rs | 4 +- embassy-boot-rp/src/lib.rs | 3 +- embassy-hal-internal/src/lib.rs | 2 +- embassy-hal-internal/src/macros.rs | 40 ++- embassy-hal-internal/src/peripheral.rs | 151 ++-------- embassy-mspm0/src/gpio.rs | 38 ++- embassy-mspm0/src/lib.rs | 2 +- embassy-nrf/src/buffered_uarte.rs | 186 ++++++------ embassy-nrf/src/egu.rs | 11 +- embassy-nrf/src/gpio.rs | 39 ++- embassy-nrf/src/gpiote.rs | 49 ++-- embassy-nrf/src/i2s.rs | 68 +++-- embassy-nrf/src/lib.rs | 2 +- embassy-nrf/src/nfct.rs | 9 +- embassy-nrf/src/nvmc.rs | 8 +- embassy-nrf/src/pdm.rs | 26 +- embassy-nrf/src/ppi/dppi.rs | 16 +- embassy-nrf/src/ppi/mod.rs | 76 ++--- embassy-nrf/src/ppi/ppi.rs | 16 +- embassy-nrf/src/pwm.rs | 159 ++++------- embassy-nrf/src/qdec.rs | 36 ++- embassy-nrf/src/qspi.rs | 24 +- embassy-nrf/src/radio/ble.rs | 8 +- embassy-nrf/src/radio/ieee802154.rs | 9 +- embassy-nrf/src/radio/mod.rs | 5 +- embassy-nrf/src/rng.rs | 12 +- embassy-nrf/src/saadc.rs | 73 ++--- embassy-nrf/src/spim.rs | 60 ++-- embassy-nrf/src/spis.rs | 84 +++--- embassy-nrf/src/temp.rs | 9 +- embassy-nrf/src/timer.rs | 18 +- embassy-nrf/src/twim.rs | 16 +- embassy-nrf/src/twis.rs | 16 +- embassy-nrf/src/uarte.rs | 124 ++++---- embassy-nrf/src/usb/mod.rs | 16 +- embassy-nrf/src/wdt.rs | 30 +- embassy-nxp/src/gpio.rs | 35 +-- embassy-nxp/src/lib.rs | 2 +- embassy-nxp/src/pint.rs | 18 +- embassy-rp/src/adc.rs | 30 +- embassy-rp/src/bootsel.rs | 21 +- embassy-rp/src/clocks.rs | 25 +- embassy-rp/src/dma.rs | 33 +-- embassy-rp/src/flash.rs | 15 +- embassy-rp/src/gpio.rs | 41 ++- embassy-rp/src/i2c.rs | 34 +-- embassy-rp/src/i2c_slave.rs | 11 +- embassy-rp/src/lib.rs | 2 +- embassy-rp/src/multicore.rs | 4 +- embassy-rp/src/pio/mod.rs | 18 +- embassy-rp/src/pio_programs/hd44780.rs | 24 +- embassy-rp/src/pio_programs/i2s.rs | 39 ++- embassy-rp/src/pio_programs/onewire.rs | 3 +- embassy-rp/src/pio_programs/pwm.rs | 4 +- embassy-rp/src/pio_programs/rotary_encoder.rs | 5 +- embassy-rp/src/pio_programs/stepper.rs | 9 +- embassy-rp/src/pio_programs/uart.rs | 45 +-- embassy-rp/src/pio_programs/ws2812.rs | 15 +- embassy-rp/src/pwm.rs | 80 ++---- embassy-rp/src/rtc/mod.rs | 10 +- embassy-rp/src/spi.rs | 136 +++++---- embassy-rp/src/trng.rs | 10 +- embassy-rp/src/uart/buffered.rs | 66 ++--- embassy-rp/src/uart/mod.rs | 168 +++++------ embassy-rp/src/usb.rs | 7 +- embassy-rp/src/watchdog.rs | 4 +- embassy-stm32-wpan/src/lib.rs | 8 +- embassy-stm32/build.rs | 4 +- embassy-stm32/src/adc/c0.rs | 11 +- embassy-stm32/src/adc/f1.rs | 7 +- embassy-stm32/src/adc/f3.rs | 8 +- embassy-stm32/src/adc/f3_v1_1.rs | 7 +- embassy-stm32/src/adc/g4.rs | 11 +- embassy-stm32/src/adc/mod.rs | 15 +- embassy-stm32/src/adc/ringbuffered_v2.rs | 10 +- embassy-stm32/src/adc/u5_adc4.rs | 19 +- embassy-stm32/src/adc/v1.rs | 6 +- embassy-stm32/src/adc/v2.rs | 7 +- embassy-stm32/src/adc/v3.rs | 8 +- embassy-stm32/src/adc/v4.rs | 11 +- embassy-stm32/src/can/bxcan/mod.rs | 13 +- embassy-stm32/src/can/fdcan.rs | 16 +- embassy-stm32/src/cordic/mod.rs | 30 +- embassy-stm32/src/crc/v1.rs | 11 +- embassy-stm32/src/crc/v2v3.rs | 9 +- embassy-stm32/src/cryp/mod.rs | 18 +- embassy-stm32/src/dac/mod.rs | 53 ++-- embassy-stm32/src/dcmi.rs | 267 +++++++++--------- embassy-stm32/src/dma/dma_bdma.rs | 44 ++- embassy-stm32/src/dma/gpdma.rs | 28 +- embassy-stm32/src/dma/mod.rs | 20 +- embassy-stm32/src/dma/util.rs | 22 +- embassy-stm32/src/dsihost.rs | 14 +- embassy-stm32/src/dts/mod.rs | 9 +- embassy-stm32/src/eth/mod.rs | 3 +- embassy-stm32/src/eth/v1/mod.rs | 48 ++-- embassy-stm32/src/eth/v2/mod.rs | 112 ++++---- embassy-stm32/src/exti.rs | 35 +-- embassy-stm32/src/flash/asynch.rs | 7 +- embassy-stm32/src/flash/common.rs | 9 +- embassy-stm32/src/flash/f4.rs | 11 +- embassy-stm32/src/fmc.rs | 23 +- embassy-stm32/src/gpio.rs | 43 ++- embassy-stm32/src/hash/mod.rs | 16 +- embassy-stm32/src/hrtim/mod.rs | 26 +- embassy-stm32/src/hrtim/traits.rs | 4 +- embassy-stm32/src/hsem/mod.rs | 16 +- embassy-stm32/src/hspi/mod.rs | 164 ++++++----- embassy-stm32/src/i2c/mod.rs | 28 +- embassy-stm32/src/i2s.rs | 87 +++--- embassy-stm32/src/lib.rs | 2 +- embassy-stm32/src/lptim/mod.rs | 3 +- embassy-stm32/src/lptim/pwm.rs | 24 +- embassy-stm32/src/lptim/timer/mod.rs | 8 +- embassy-stm32/src/ltdc.rs | 68 +++-- embassy-stm32/src/macros.rs | 14 +- embassy-stm32/src/opamp.rs | 27 +- embassy-stm32/src/ospi/mod.rs | 224 ++++++++------- embassy-stm32/src/qspi/mod.rs | 96 +++---- embassy-stm32/src/rcc/mco.rs | 15 +- embassy-stm32/src/rng.rs | 11 +- embassy-stm32/src/rtc/mod.rs | 4 +- embassy-stm32/src/sai/mod.rs | 71 +++-- embassy-stm32/src/sdmmc/mod.rs | 133 ++++----- embassy-stm32/src/spdifrx/mod.rs | 19 +- embassy-stm32/src/spi/mod.rs | 85 +++--- embassy-stm32/src/timer/complementary_pwm.rs | 14 +- embassy-stm32/src/timer/input_capture.rs | 15 +- embassy-stm32/src/timer/low_level.rs | 8 +- embassy-stm32/src/timer/mod.rs | 4 +- embassy-stm32/src/timer/pwm_input.rs | 24 +- embassy-stm32/src/timer/qei.rs | 14 +- embassy-stm32/src/timer/simple_pwm.rs | 42 +-- embassy-stm32/src/tsc/mod.rs | 5 +- embassy-stm32/src/tsc/pin_groups.rs | 14 +- embassy-stm32/src/tsc/tsc.rs | 22 +- embassy-stm32/src/ucpd.rs | 22 +- embassy-stm32/src/usart/buffered.rs | 82 +++--- embassy-stm32/src/usart/mod.rs | 172 +++++------ embassy-stm32/src/usart/ringbuffered.rs | 6 +- embassy-stm32/src/usb/otg.rs | 76 +++-- embassy-stm32/src/usb/usb.rs | 23 +- embassy-stm32/src/wdg/mod.rs | 9 +- examples/nrf52840-rtic/src/bin/blinky.rs | 4 +- .../src/bin/channel_sender_receiver.rs | 7 +- examples/nrf52840/src/bin/pdm_continuous.rs | 4 +- examples/nrf52840/src/bin/qspi_lowpower.rs | 14 +- examples/nrf52840/src/bin/saadc.rs | 2 +- examples/nrf52840/src/bin/saadc_continuous.rs | 12 +- examples/nrf52840/src/bin/twim_lowpower.rs | 8 +- examples/nrf9160/src/bin/modem_tcp_client.rs | 8 +- examples/rp/Cargo.toml | 2 +- examples/rp/src/bin/adc_dma.rs | 4 +- examples/rp/src/bin/assign_resources.rs | 7 +- examples/rp/src/bin/blinky_two_channels.rs | 4 +- examples/rp/src/bin/blinky_two_tasks.rs | 4 +- examples/rp/src/bin/orchestrate_tasks.rs | 2 +- examples/rp/src/bin/pio_async.rs | 8 +- examples/rp/src/bin/pio_dma.rs | 6 +- examples/rp/src/bin/pio_i2s.rs | 7 +- examples/rp/src/bin/pwm.rs | 5 +- examples/rp/src/bin/shared_bus.rs | 6 +- examples/rp/src/bin/zerocopy.rs | 9 +- examples/rp235x/Cargo.toml | 2 +- examples/rp235x/src/bin/adc_dma.rs | 4 +- examples/rp235x/src/bin/assign_resources.rs | 7 +- .../rp235x/src/bin/blinky_two_channels.rs | 4 +- examples/rp235x/src/bin/blinky_two_tasks.rs | 4 +- examples/rp235x/src/bin/pio_async.rs | 4 +- examples/rp235x/src/bin/pio_dma.rs | 6 +- .../rp235x/src/bin/pio_rotary_encoder_rxf.rs | 6 +- examples/rp235x/src/bin/pwm.rs | 5 +- .../src/bin/pwm_tb6612fng_motor_driver.rs | 2 +- examples/rp235x/src/bin/shared_bus.rs | 6 +- examples/rp235x/src/bin/zerocopy.rs | 9 +- examples/stm32c0/src/bin/adc.rs | 5 +- .../src/bin/button_controlled_blink.rs | 7 +- examples/stm32f1/src/bin/input_capture.rs | 4 +- examples/stm32f1/src/bin/pwm_input.rs | 4 +- examples/stm32f1/src/bin/usb_serial.rs | 2 +- examples/stm32f334/src/bin/opamp.rs | 2 +- examples/stm32f4/src/bin/can.rs | 2 +- examples/stm32f4/src/bin/flash_async.rs | 8 +- examples/stm32f4/src/bin/input_capture.rs | 4 +- examples/stm32f4/src/bin/pwm_input.rs | 4 +- examples/stm32f4/src/bin/ws2812_pwm.rs | 2 +- examples/stm32f7/src/bin/can.rs | 2 +- examples/stm32g0/src/bin/adc_dma.rs | 2 +- examples/stm32g0/src/bin/input_capture.rs | 4 +- examples/stm32g0/src/bin/pwm_input.rs | 4 +- examples/stm32g4/src/bin/adc_dma.rs | 2 +- examples/stm32h5/src/bin/cordic.rs | 6 +- examples/stm32h5/src/bin/stop.rs | 4 +- examples/stm32h7/src/bin/adc_dma.rs | 2 +- examples/stm32h7/src/bin/dac_dma.rs | 5 +- .../stm32h7/src/bin/low_level_timer_api.rs | 14 +- examples/stm32h723/src/bin/spdifrx.rs | 34 ++- examples/stm32l4/src/bin/dac_dma.rs | 5 +- examples/stm32l5/src/bin/stop.rs | 4 +- examples/stm32u5/src/bin/adc.rs | 4 +- tests/nrf/src/bin/buffered_uart.rs | 14 +- tests/nrf/src/bin/buffered_uart_halves.rs | 16 +- tests/nrf/src/bin/buffered_uart_spam.rs | 6 +- tests/nrf/src/bin/spim.rs | 8 +- tests/nrf/src/bin/uart_halves.rs | 14 +- tests/nrf/src/bin/uart_split.rs | 6 +- tests/rp/src/bin/adc.rs | 61 ++-- tests/rp/src/bin/bootsel.rs | 5 +- tests/rp/src/bin/gpio.rs | 40 +-- tests/rp/src/bin/gpio_async.rs | 24 +- tests/rp/src/bin/gpio_multicore.rs | 5 +- tests/rp/src/bin/pwm.rs | 50 ++-- tests/rp/src/bin/uart.rs | 14 +- tests/rp/src/bin/uart_buffered.rs | 38 ++- tests/rp/src/bin/uart_dma.rs | 38 +-- tests/stm32/src/bin/can.rs | 2 +- tests/stm32/src/bin/cordic.rs | 4 +- tests/stm32/src/bin/gpio.rs | 44 +-- tests/stm32/src/bin/sdmmc.rs | 26 +- tests/stm32/src/bin/spi.rs | 16 +- tests/stm32/src/bin/spi_dma.rs | 34 ++- tests/stm32/src/bin/ucpd.rs | 10 +- tests/stm32/src/bin/usart.rs | 6 +- 225 files changed, 2645 insertions(+), 3215 deletions(-) diff --git a/README.md b/README.md index c64a07be8..383fb6671 100644 --- a/README.md +++ b/README.md @@ -55,11 +55,11 @@ use defmt::info; use embassy_executor::Spawner; use embassy_time::{Duration, Timer}; use embassy_nrf::gpio::{AnyPin, Input, Level, Output, OutputDrive, Pin, Pull}; -use embassy_nrf::Peripherals; +use embassy_nrf::{Peri, Peripherals}; // Declare async tasks #[embassy_executor::task] -async fn blink(pin: AnyPin) { +async fn blink(pin: Peri<'static, AnyPin>) { let mut led = Output::new(pin, Level::Low, OutputDrive::Standard); loop { @@ -77,7 +77,7 @@ async fn main(spawner: Spawner) { let p = embassy_nrf::init(Default::default()); // Spawned tasks run in the background, concurrently. - spawner.spawn(blink(p.P0_13.degrade())).unwrap(); + spawner.spawn(blink(p.P0_13.into())).unwrap(); let mut button = Input::new(p.P0_11, Pull::Up); loop { diff --git a/cyw43-pio/src/lib.rs b/cyw43-pio/src/lib.rs index c1b301547..b0be19358 100644 --- a/cyw43-pio/src/lib.rs +++ b/cyw43-pio/src/lib.rs @@ -10,16 +10,16 @@ use embassy_rp::dma::Channel; use embassy_rp::gpio::{Drive, Level, Output, Pull, SlewRate}; use embassy_rp::pio::program::pio_asm; use embassy_rp::pio::{Common, Config, Direction, Instance, Irq, PioPin, ShiftDirection, StateMachine}; -use embassy_rp::{Peripheral, PeripheralRef}; +use embassy_rp::Peri; use fixed::types::extra::U8; use fixed::FixedU32; /// SPI comms driven by PIO. -pub struct PioSpi<'d, PIO: Instance, const SM: usize, DMA> { +pub struct PioSpi<'d, PIO: Instance, const SM: usize, DMA: Channel> { cs: Output<'d>, sm: StateMachine<'d, PIO, SM>, irq: Irq<'d, PIO, 0>, - dma: PeripheralRef<'d, DMA>, + dma: Peri<'d, DMA>, wrap_target: u8, } @@ -48,20 +48,16 @@ where PIO: Instance, { /// Create a new instance of PioSpi. - pub fn new( + pub fn new( common: &mut Common<'d, PIO>, mut sm: StateMachine<'d, PIO, SM>, clock_divider: FixedU32, irq: Irq<'d, PIO, 0>, cs: Output<'d>, - dio: DIO, - clk: CLK, - dma: impl Peripheral

+ 'd, - ) -> Self - where - DIO: PioPin, - CLK: PioPin, - { + dio: Peri<'d, impl PioPin>, + clk: Peri<'d, impl PioPin>, + dma: Peri<'d, DMA>, + ) -> Self { let loaded_program = if clock_divider < DEFAULT_CLOCK_DIVIDER { let overclock_program = pio_asm!( ".side_set 1" @@ -146,7 +142,7 @@ where cs, sm, irq, - dma: dma.into_ref(), + dma: dma, wrap_target: loaded_program.wrap.target, } } diff --git a/embassy-boot-nrf/src/lib.rs b/embassy-boot-nrf/src/lib.rs index e5bc870b5..46c1994e2 100644 --- a/embassy-boot-nrf/src/lib.rs +++ b/embassy-boot-nrf/src/lib.rs @@ -9,7 +9,7 @@ pub use embassy_boot::{ }; use embassy_nrf::nvmc::PAGE_SIZE; use embassy_nrf::peripherals::WDT; -use embassy_nrf::wdt; +use embassy_nrf::{wdt, Peri}; use embedded_storage::nor_flash::{ErrorType, NorFlash, ReadNorFlash}; /// A bootloader for nRF devices. @@ -113,7 +113,7 @@ pub struct WatchdogFlash { impl WatchdogFlash { /// Start a new watchdog with a given flash and WDT peripheral and a timeout - pub fn start(flash: FLASH, wdt: WDT, config: wdt::Config) -> Self { + pub fn start(flash: FLASH, wdt: Peri<'static, WDT>, config: wdt::Config) -> Self { let (_wdt, [wdt]) = match wdt::Watchdog::try_new(wdt, config) { Ok(x) => x, Err(_) => { diff --git a/embassy-boot-rp/src/lib.rs b/embassy-boot-rp/src/lib.rs index 6ec33a580..f704380ef 100644 --- a/embassy-boot-rp/src/lib.rs +++ b/embassy-boot-rp/src/lib.rs @@ -10,6 +10,7 @@ pub use embassy_boot::{ use embassy_rp::flash::{Blocking, Flash, ERASE_SIZE}; use embassy_rp::peripherals::{FLASH, WATCHDOG}; use embassy_rp::watchdog::Watchdog; +use embassy_rp::Peri; use embassy_time::Duration; use embedded_storage::nor_flash::{ErrorType, NorFlash, ReadNorFlash}; @@ -68,7 +69,7 @@ pub struct WatchdogFlash<'d, const SIZE: usize> { impl<'d, const SIZE: usize> WatchdogFlash<'d, SIZE> { /// Start a new watchdog with a given flash and watchdog peripheral and a timeout - pub fn start(flash: FLASH, watchdog: WATCHDOG, timeout: Duration) -> Self { + pub fn start(flash: Peri<'static, FLASH>, watchdog: Peri<'static, WATCHDOG>, timeout: Duration) -> Self { let flash = Flash::<_, Blocking, SIZE>::new_blocking(flash); let mut watchdog = Watchdog::new(watchdog); watchdog.start(timeout); diff --git a/embassy-hal-internal/src/lib.rs b/embassy-hal-internal/src/lib.rs index 89f20e993..7addb71e2 100644 --- a/embassy-hal-internal/src/lib.rs +++ b/embassy-hal-internal/src/lib.rs @@ -11,7 +11,7 @@ pub mod drop; mod macros; mod peripheral; pub mod ratio; -pub use peripheral::{Peripheral, PeripheralRef}; +pub use peripheral::{Peri, PeripheralType}; #[cfg(feature = "cortex-m")] pub mod interrupt; diff --git a/embassy-hal-internal/src/macros.rs b/embassy-hal-internal/src/macros.rs index 07cd89487..cd2bc3cab 100644 --- a/embassy-hal-internal/src/macros.rs +++ b/embassy-hal-internal/src/macros.rs @@ -18,8 +18,8 @@ macro_rules! peripherals_definition { /// /// You must ensure that you're only using one instance of this type at a time. #[inline] - pub unsafe fn steal() -> Self { - Self{ _private: ()} + pub unsafe fn steal() -> $crate::Peri<'static, Self> { + $crate::Peri::new_unchecked(Self{ _private: ()}) } } @@ -42,7 +42,7 @@ macro_rules! peripherals_struct { $( #[doc = concat!(stringify!($name), " peripheral")] $(#[$cfg])? - pub $name: peripherals::$name, + pub $name: $crate::Peri<'static, peripherals::$name>, )* } @@ -108,28 +108,26 @@ macro_rules! peripherals { }; } -/// Convenience converting into reference. -#[macro_export] -macro_rules! into_ref { - ($($name:ident),*) => { - $( - let mut $name = $name.into_ref(); - )* - } -} - /// Implement the peripheral trait. #[macro_export] macro_rules! impl_peripheral { - ($type:ident) => { - impl $crate::Peripheral for $type { - type P = $type; - - #[inline] - unsafe fn clone_unchecked(&self) -> Self::P { - #[allow(clippy::needless_update)] - $type { ..*self } + ($type:ident<$($T:ident $(: $bound:tt $(+ $others:tt )*)?),*>) => { + impl<$($T: $($bound $(+$others)*)?),*> Copy for $type <$($T),*> {} + impl<$($T: $($bound $(+$others)*)?),*> Clone for $type <$($T),*> { + fn clone(&self) -> Self { + *self } } + impl<$($T: $($bound $(+$others)*)?),*> PeripheralType for $type <$($T),*> {} + }; + + ($type:ident) => { + impl Copy for $type {} + impl Clone for $type { + fn clone(&self) -> Self { + *self + } + } + impl $crate::PeripheralType for $type {} }; } diff --git a/embassy-hal-internal/src/peripheral.rs b/embassy-hal-internal/src/peripheral.rs index 0b0f13338..803259bb8 100644 --- a/embassy-hal-internal/src/peripheral.rs +++ b/embassy-hal-internal/src/peripheral.rs @@ -1,5 +1,5 @@ use core::marker::PhantomData; -use core::ops::{Deref, DerefMut}; +use core::ops::Deref; /// An exclusive reference to a peripheral. /// @@ -9,20 +9,26 @@ use core::ops::{Deref, DerefMut}; /// - Memory efficiency: Peripheral singletons are typically either zero-sized (for concrete /// peripherals like `PA9` or `SPI4`) or very small (for example `AnyPin`, which is 1 byte). /// However `&mut T` is always 4 bytes for 32-bit targets, even if T is zero-sized. -/// PeripheralRef stores a copy of `T` instead, so it's the same size. +/// Peripheral stores a copy of `T` instead, so it's the same size. /// - Code size efficiency. If the user uses the same driver with both `SPI4` and `&mut SPI4`, -/// the driver code would be monomorphized two times. With PeripheralRef, the driver is generic -/// over a lifetime only. `SPI4` becomes `PeripheralRef<'static, SPI4>`, and `&mut SPI4` becomes -/// `PeripheralRef<'a, SPI4>`. Lifetimes don't cause monomorphization. -pub struct PeripheralRef<'a, T> { +/// the driver code would be monomorphized two times. With Peri, the driver is generic +/// over a lifetime only. `SPI4` becomes `Peri<'static, SPI4>`, and `&mut SPI4` becomes +/// `Peri<'a, SPI4>`. Lifetimes don't cause monomorphization. +pub struct Peri<'a, T: PeripheralType> { inner: T, _lifetime: PhantomData<&'a mut T>, } -impl<'a, T> PeripheralRef<'a, T> { - /// Create a new reference to a peripheral. +impl<'a, T: PeripheralType> Peri<'a, T> { + /// Create a new owned a peripheral. + /// + /// For use by HALs only. + /// + /// If you're an end user you shouldn't use this, you should use `steal()` + /// on the actual peripheral types instead. #[inline] - pub fn new(inner: T) -> Self { + #[doc(hidden)] + pub unsafe fn new_unchecked(inner: T) -> Self { Self { inner, _lifetime: PhantomData, @@ -38,46 +44,38 @@ impl<'a, T> PeripheralRef<'a, T> { /// create two SPI drivers on `SPI1`, because they will "fight" each other. /// /// You should strongly prefer using `reborrow()` instead. It returns a - /// `PeripheralRef` that borrows `self`, which allows the borrow checker + /// `Peri` that borrows `self`, which allows the borrow checker /// to enforce this at compile time. - pub unsafe fn clone_unchecked(&self) -> PeripheralRef<'a, T> - where - T: Peripheral

, - { - PeripheralRef::new(self.inner.clone_unchecked()) + pub unsafe fn clone_unchecked(&self) -> Peri<'a, T> { + Peri::new_unchecked(self.inner) } - /// Reborrow into a "child" PeripheralRef. + /// Reborrow into a "child" Peri. /// - /// `self` will stay borrowed until the child PeripheralRef is dropped. - pub fn reborrow(&mut self) -> PeripheralRef<'_, T> - where - T: Peripheral

, - { - // safety: we're returning the clone inside a new PeripheralRef that borrows + /// `self` will stay borrowed until the child Peripheral is dropped. + pub fn reborrow(&mut self) -> Peri<'_, T> { + // safety: we're returning the clone inside a new Peripheral that borrows // self, so user code can't use both at the same time. - PeripheralRef::new(unsafe { self.inner.clone_unchecked() }) + unsafe { self.clone_unchecked() } } /// Map the inner peripheral using `Into`. /// - /// This converts from `PeripheralRef<'a, T>` to `PeripheralRef<'a, U>`, using an + /// This converts from `Peri<'a, T>` to `Peri<'a, U>`, using an /// `Into` impl to convert from `T` to `U`. /// - /// For example, this can be useful to degrade GPIO pins: converting from PeripheralRef<'a, PB11>` to `PeripheralRef<'a, AnyPin>`. + /// For example, this can be useful to.into() GPIO pins: converting from Peri<'a, PB11>` to `Peri<'a, AnyPin>`. #[inline] - pub fn map_into(self) -> PeripheralRef<'a, U> + pub fn into(self) -> Peri<'a, U> where T: Into, + U: PeripheralType, { - PeripheralRef { - inner: self.inner.into(), - _lifetime: PhantomData, - } + unsafe { Peri::new_unchecked(self.inner.into()) } } } -impl<'a, T> Deref for PeripheralRef<'a, T> { +impl<'a, T: PeripheralType> Deref for Peri<'a, T> { type Target = T; #[inline] @@ -86,92 +84,5 @@ impl<'a, T> Deref for PeripheralRef<'a, T> { } } -/// Trait for any type that can be used as a peripheral of type `P`. -/// -/// This is used in driver constructors, to allow passing either owned peripherals (e.g. `TWISPI0`), -/// or borrowed peripherals (e.g. `&mut TWISPI0`). -/// -/// For example, if you have a driver with a constructor like this: -/// -/// ```ignore -/// impl<'d, T: Instance> Twim<'d, T> { -/// pub fn new( -/// twim: impl Peripheral

+ 'd, -/// irq: impl Peripheral

+ 'd, -/// sda: impl Peripheral

+ 'd, -/// scl: impl Peripheral

+ 'd, -/// config: Config, -/// ) -> Self { .. } -/// } -/// ``` -/// -/// You may call it with owned peripherals, which yields an instance that can live forever (`'static`): -/// -/// ```ignore -/// let mut twi: Twim<'static, ...> = Twim::new(p.TWISPI0, irq, p.P0_03, p.P0_04, config); -/// ``` -/// -/// Or you may call it with borrowed peripherals, which yields an instance that can only live for as long -/// as the borrows last: -/// -/// ```ignore -/// let mut twi: Twim<'_, ...> = Twim::new(&mut p.TWISPI0, &mut irq, &mut p.P0_03, &mut p.P0_04, config); -/// ``` -/// -/// # Implementation details, for HAL authors -/// -/// When writing a HAL, the intended way to use this trait is to take `impl Peripheral

` in -/// the HAL's public API (such as driver constructors), calling `.into_ref()` to obtain a `PeripheralRef`, -/// and storing that in the driver struct. -/// -/// `.into_ref()` on an owned `T` yields a `PeripheralRef<'static, T>`. -/// `.into_ref()` on an `&'a mut T` yields a `PeripheralRef<'a, T>`. -pub trait Peripheral: Sized { - /// Peripheral singleton type - type P; - - /// Unsafely clone (duplicate) a peripheral singleton. - /// - /// # Safety - /// - /// This returns an owned clone of the peripheral. You must manually ensure - /// only one copy of the peripheral is in use at a time. For example, don't - /// create two SPI drivers on `SPI1`, because they will "fight" each other. - /// - /// You should strongly prefer using `into_ref()` instead. It returns a - /// `PeripheralRef`, which allows the borrow checker to enforce this at compile time. - unsafe fn clone_unchecked(&self) -> Self::P; - - /// Convert a value into a `PeripheralRef`. - /// - /// When called on an owned `T`, yields a `PeripheralRef<'static, T>`. - /// When called on an `&'a mut T`, yields a `PeripheralRef<'a, T>`. - #[inline] - fn into_ref<'a>(self) -> PeripheralRef<'a, Self::P> - where - Self: 'a, - { - PeripheralRef::new(unsafe { self.clone_unchecked() }) - } -} - -impl<'b, T: DerefMut> Peripheral for T -where - T::Target: Peripheral, -{ - type P = ::P; - - #[inline] - unsafe fn clone_unchecked(&self) -> Self::P { - T::Target::clone_unchecked(self) - } -} - -impl<'b, T: Peripheral> Peripheral for PeripheralRef<'_, T> { - type P = T::P; - - #[inline] - unsafe fn clone_unchecked(&self) -> Self::P { - T::clone_unchecked(self) - } -} +/// Marker trait for peripheral types. +pub trait PeripheralType: Copy + Sized {} diff --git a/embassy-mspm0/src/gpio.rs b/embassy-mspm0/src/gpio.rs index 1048d980e..2edadbc5a 100644 --- a/embassy-mspm0/src/gpio.rs +++ b/embassy-mspm0/src/gpio.rs @@ -5,7 +5,7 @@ use core::future::Future; use core::pin::Pin as FuturePin; use core::task::{Context, Poll}; -use embassy_hal_internal::{impl_peripheral, into_ref, Peripheral, PeripheralRef}; +use embassy_hal_internal::{impl_peripheral, Peri, PeripheralType}; use embassy_sync::waitqueue::AtomicWaker; use crate::pac::gpio::vals::*; @@ -74,7 +74,7 @@ pub enum Port { /// set while not in output mode, so the pin's level will be 'remembered' when it is not in output /// mode. pub struct Flex<'d> { - pin: PeripheralRef<'d, AnyPin>, + pin: Peri<'d, AnyPin>, } impl<'d> Flex<'d> { @@ -83,11 +83,9 @@ impl<'d> Flex<'d> { /// The pin remains disconnected. The initial output level is unspecified, but can be changed /// before the pin is put into output mode. #[inline] - pub fn new(pin: impl Peripheral

+ 'd) -> Self { - into_ref!(pin); - + pub fn new(pin: Peri<'d, impl Pin>) -> Self { // Pin will be in disconnected state. - Self { pin: pin.map_into() } + Self { pin: pin.into() } } /// Set the pin's pull. @@ -345,7 +343,7 @@ pub struct Input<'d> { impl<'d> Input<'d> { /// Create GPIO input driver for a [Pin] with the provided [Pull] configuration. #[inline] - pub fn new(pin: impl Peripheral

+ 'd, pull: Pull) -> Self { + pub fn new(pin: Peri<'d, impl Pin>, pull: Pull) -> Self { let mut pin = Flex::new(pin); pin.set_as_input(); pin.set_pull(pull); @@ -421,7 +419,7 @@ pub struct Output<'d> { impl<'d> Output<'d> { /// Create GPIO output driver for a [Pin] with the provided [Level] configuration. #[inline] - pub fn new(pin: impl Peripheral

+ 'd, initial_output: Level) -> Self { + pub fn new(pin: Peri<'d, impl Pin>, initial_output: Level) -> Self { let mut pin = Flex::new(pin); pin.set_as_output(); pin.set_level(initial_output); @@ -491,7 +489,7 @@ pub struct OutputOpenDrain<'d> { impl<'d> OutputOpenDrain<'d> { /// Create a new GPIO open drain output driver for a [Pin] with the provided [Level]. #[inline] - pub fn new(pin: impl Peripheral

+ 'd, initial_output: Level) -> Self { + pub fn new(pin: Peri<'d, impl Pin>, initial_output: Level) -> Self { let mut pin = Flex::new(pin); pin.set_level(initial_output); pin.set_as_input_output(); @@ -599,7 +597,7 @@ impl<'d> OutputOpenDrain<'d> { /// Type-erased GPIO pin pub struct AnyPin { - pin_port: u8, + pub(crate) pin_port: u8, } impl AnyPin { @@ -608,8 +606,8 @@ impl AnyPin { /// # Safety /// - `pin_port` should not in use by another driver. #[inline] - pub unsafe fn steal(pin_port: u8) -> Self { - Self { pin_port } + pub unsafe fn steal(pin_port: u8) -> Peri<'static, Self> { + Peri::new_unchecked(Self { pin_port }) } } @@ -625,13 +623,7 @@ impl SealedPin for AnyPin { /// Interface for a Pin that can be configured by an [Input] or [Output] driver, or converted to an [AnyPin]. #[allow(private_bounds)] -pub trait Pin: Peripheral

+ Into + SealedPin + Sized + 'static { - fn degrade(self) -> AnyPin { - AnyPin { - pin_port: self.pin_port(), - } - } - +pub trait Pin: PeripheralType + Into + SealedPin + Sized + 'static { /// The index of this pin in PINCM (pin control management) registers. #[inline] fn pin_cm(&self) -> u8 { @@ -866,7 +858,9 @@ macro_rules! impl_pin { impl From for crate::gpio::AnyPin { fn from(val: crate::peripherals::$name) -> Self { - crate::gpio::Pin::degrade(val) + Self { + pin_port: crate::gpio::SealedPin::pin_port(&val), + } } } }; @@ -928,11 +922,11 @@ pub(crate) trait SealedPin { #[must_use = "futures do nothing unless you `.await` or poll them"] struct InputFuture<'d> { - pin: PeripheralRef<'d, AnyPin>, + pin: Peri<'d, AnyPin>, } impl<'d> InputFuture<'d> { - fn new(pin: PeripheralRef<'d, AnyPin>, polarity: Polarity) -> Self { + fn new(pin: Peri<'d, AnyPin>, polarity: Polarity) -> Self { let block = pin.block(); // Before clearing any previous edge events, we must disable events. diff --git a/embassy-mspm0/src/lib.rs b/embassy-mspm0/src/lib.rs index 1df85a520..99b7ed4a1 100644 --- a/embassy-mspm0/src/lib.rs +++ b/embassy-mspm0/src/lib.rs @@ -50,7 +50,7 @@ pub(crate) mod _generated { // Reexports pub(crate) use _generated::gpio_pincm; pub use _generated::{peripherals, Peripherals}; -pub use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; +pub use embassy_hal_internal::Peri; #[cfg(feature = "unstable-pac")] pub use mspm0_metapac as pac; #[cfg(not(feature = "unstable-pac"))] diff --git a/embassy-nrf/src/buffered_uarte.rs b/embassy-nrf/src/buffered_uarte.rs index c3fcfd06e..f939be004 100644 --- a/embassy-nrf/src/buffered_uarte.rs +++ b/embassy-nrf/src/buffered_uarte.rs @@ -16,7 +16,7 @@ use core::sync::atomic::{compiler_fence, AtomicBool, AtomicU8, AtomicUsize, Orde use core::task::Poll; use embassy_hal_internal::atomic_ring_buffer::RingBuffer; -use embassy_hal_internal::{into_ref, PeripheralRef}; +use embassy_hal_internal::Peri; use pac::uarte::vals; // Re-export SVD variants to allow user to directly set values pub use pac::uarte::vals::{Baudrate, ConfigParity as Parity}; @@ -28,7 +28,7 @@ use crate::ppi::{ }; use crate::timer::{Instance as TimerInstance, Timer}; use crate::uarte::{configure, configure_rx_pins, configure_tx_pins, drop_tx_rx, Config, Instance as UarteInstance}; -use crate::{interrupt, pac, Peripheral, EASY_DMA_SIZE}; +use crate::{interrupt, pac, EASY_DMA_SIZE}; pub(crate) struct State { tx_buf: RingBuffer, @@ -222,27 +222,26 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> { /// Panics if `rx_buffer.len()` is odd. #[allow(clippy::too_many_arguments)] pub fn new( - uarte: impl Peripheral

+ 'd, - timer: impl Peripheral

+ 'd, - ppi_ch1: impl Peripheral

+ 'd, - ppi_ch2: impl Peripheral

+ 'd, - ppi_group: impl Peripheral

+ 'd, + uarte: Peri<'d, U>, + timer: Peri<'d, T>, + ppi_ch1: Peri<'d, impl ConfigurableChannel>, + ppi_ch2: Peri<'d, impl ConfigurableChannel>, + ppi_group: Peri<'d, impl Group>, _irq: impl interrupt::typelevel::Binding> + 'd, - rxd: impl Peripheral

+ 'd, - txd: impl Peripheral

+ 'd, + rxd: Peri<'d, impl GpioPin>, + txd: Peri<'d, impl GpioPin>, config: Config, rx_buffer: &'d mut [u8], tx_buffer: &'d mut [u8], ) -> Self { - into_ref!(uarte, timer, rxd, txd, ppi_ch1, ppi_ch2, ppi_group); Self::new_inner( uarte, timer, - ppi_ch1.map_into(), - ppi_ch2.map_into(), - ppi_group.map_into(), - rxd.map_into(), - txd.map_into(), + ppi_ch1.into(), + ppi_ch2.into(), + ppi_group.into(), + rxd.into(), + txd.into(), None, None, config, @@ -258,31 +257,30 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> { /// Panics if `rx_buffer.len()` is odd. #[allow(clippy::too_many_arguments)] pub fn new_with_rtscts( - uarte: impl Peripheral

+ 'd, - timer: impl Peripheral

+ 'd, - ppi_ch1: impl Peripheral

+ 'd, - ppi_ch2: impl Peripheral

+ 'd, - ppi_group: impl Peripheral

+ 'd, + uarte: Peri<'d, U>, + timer: Peri<'d, T>, + ppi_ch1: Peri<'d, impl ConfigurableChannel>, + ppi_ch2: Peri<'d, impl ConfigurableChannel>, + ppi_group: Peri<'d, impl Group>, _irq: impl interrupt::typelevel::Binding> + 'd, - rxd: impl Peripheral

+ 'd, - txd: impl Peripheral

+ 'd, - cts: impl Peripheral

+ 'd, - rts: impl Peripheral

+ 'd, + rxd: Peri<'d, impl GpioPin>, + txd: Peri<'d, impl GpioPin>, + cts: Peri<'d, impl GpioPin>, + rts: Peri<'d, impl GpioPin>, config: Config, rx_buffer: &'d mut [u8], tx_buffer: &'d mut [u8], ) -> Self { - into_ref!(uarte, timer, rxd, txd, cts, rts, ppi_ch1, ppi_ch2, ppi_group); Self::new_inner( uarte, timer, - ppi_ch1.map_into(), - ppi_ch2.map_into(), - ppi_group.map_into(), - rxd.map_into(), - txd.map_into(), - Some(cts.map_into()), - Some(rts.map_into()), + ppi_ch1.into(), + ppi_ch2.into(), + ppi_group.into(), + rxd.into(), + txd.into(), + Some(cts.into()), + Some(rts.into()), config, rx_buffer, tx_buffer, @@ -291,15 +289,15 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> { #[allow(clippy::too_many_arguments)] fn new_inner( - peri: PeripheralRef<'d, U>, - timer: PeripheralRef<'d, T>, - ppi_ch1: PeripheralRef<'d, AnyConfigurableChannel>, - ppi_ch2: PeripheralRef<'d, AnyConfigurableChannel>, - ppi_group: PeripheralRef<'d, AnyGroup>, - rxd: PeripheralRef<'d, AnyPin>, - txd: PeripheralRef<'d, AnyPin>, - cts: Option>, - rts: Option>, + peri: Peri<'d, U>, + timer: Peri<'d, T>, + ppi_ch1: Peri<'d, AnyConfigurableChannel>, + ppi_ch2: Peri<'d, AnyConfigurableChannel>, + ppi_group: Peri<'d, AnyGroup>, + rxd: Peri<'d, AnyPin>, + txd: Peri<'d, AnyPin>, + cts: Option>, + rts: Option>, config: Config, rx_buffer: &'d mut [u8], tx_buffer: &'d mut [u8], @@ -372,20 +370,19 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> { /// Reader part of the buffered UARTE driver. pub struct BufferedUarteTx<'d, U: UarteInstance> { - _peri: PeripheralRef<'d, U>, + _peri: Peri<'d, U>, } impl<'d, U: UarteInstance> BufferedUarteTx<'d, U> { /// Create a new BufferedUarteTx without hardware flow control. pub fn new( - uarte: impl Peripheral

+ 'd, + uarte: Peri<'d, U>, _irq: impl interrupt::typelevel::Binding> + 'd, - txd: impl Peripheral

+ 'd, + txd: Peri<'d, impl GpioPin>, config: Config, tx_buffer: &'d mut [u8], ) -> Self { - into_ref!(uarte, txd); - Self::new_inner(uarte, txd.map_into(), None, config, tx_buffer) + Self::new_inner(uarte, txd.into(), None, config, tx_buffer) } /// Create a new BufferedUarte with hardware flow control (RTS/CTS) @@ -394,21 +391,20 @@ impl<'d, U: UarteInstance> BufferedUarteTx<'d, U> { /// /// Panics if `rx_buffer.len()` is odd. pub fn new_with_cts( - uarte: impl Peripheral

+ 'd, + uarte: Peri<'d, U>, _irq: impl interrupt::typelevel::Binding> + 'd, - txd: impl Peripheral

+ 'd, - cts: impl Peripheral

+ 'd, + txd: Peri<'d, impl GpioPin>, + cts: Peri<'d, impl GpioPin>, config: Config, tx_buffer: &'d mut [u8], ) -> Self { - into_ref!(uarte, txd, cts); - Self::new_inner(uarte, txd.map_into(), Some(cts.map_into()), config, tx_buffer) + Self::new_inner(uarte, txd.into(), Some(cts.into()), config, tx_buffer) } fn new_inner( - peri: PeripheralRef<'d, U>, - txd: PeripheralRef<'d, AnyPin>, - cts: Option>, + peri: Peri<'d, U>, + txd: Peri<'d, AnyPin>, + cts: Option>, config: Config, tx_buffer: &'d mut [u8], ) -> Self { @@ -426,9 +422,9 @@ impl<'d, U: UarteInstance> BufferedUarteTx<'d, U> { } fn new_innerer( - peri: PeripheralRef<'d, U>, - txd: PeripheralRef<'d, AnyPin>, - cts: Option>, + peri: Peri<'d, U>, + txd: Peri<'d, AnyPin>, + cts: Option>, tx_buffer: &'d mut [u8], ) -> Self { let r = U::regs(); @@ -542,7 +538,7 @@ impl<'a, U: UarteInstance> Drop for BufferedUarteTx<'a, U> { /// Reader part of the buffered UARTE driver. pub struct BufferedUarteRx<'d, U: UarteInstance, T: TimerInstance> { - _peri: PeripheralRef<'d, U>, + _peri: Peri<'d, U>, timer: Timer<'d, T>, _ppi_ch1: Ppi<'d, AnyConfigurableChannel, 1, 1>, _ppi_ch2: Ppi<'d, AnyConfigurableChannel, 1, 2>, @@ -557,24 +553,23 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarteRx<'d, U, T> { /// Panics if `rx_buffer.len()` is odd. #[allow(clippy::too_many_arguments)] pub fn new( - uarte: impl Peripheral

+ 'd, - timer: impl Peripheral

+ 'd, - ppi_ch1: impl Peripheral

+ 'd, - ppi_ch2: impl Peripheral

+ 'd, - ppi_group: impl Peripheral

+ 'd, + uarte: Peri<'d, U>, + timer: Peri<'d, T>, + ppi_ch1: Peri<'d, impl ConfigurableChannel>, + ppi_ch2: Peri<'d, impl ConfigurableChannel>, + ppi_group: Peri<'d, impl Group>, _irq: impl interrupt::typelevel::Binding> + 'd, - rxd: impl Peripheral

+ 'd, + rxd: Peri<'d, impl GpioPin>, config: Config, rx_buffer: &'d mut [u8], ) -> Self { - into_ref!(uarte, timer, rxd, ppi_ch1, ppi_ch2, ppi_group); Self::new_inner( uarte, timer, - ppi_ch1.map_into(), - ppi_ch2.map_into(), - ppi_group.map_into(), - rxd.map_into(), + ppi_ch1.into(), + ppi_ch2.into(), + ppi_group.into(), + rxd.into(), None, config, rx_buffer, @@ -588,26 +583,25 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarteRx<'d, U, T> { /// Panics if `rx_buffer.len()` is odd. #[allow(clippy::too_many_arguments)] pub fn new_with_rts( - uarte: impl Peripheral

+ 'd, - timer: impl Peripheral

+ 'd, - ppi_ch1: impl Peripheral

+ 'd, - ppi_ch2: impl Peripheral

+ 'd, - ppi_group: impl Peripheral

+ 'd, + uarte: Peri<'d, U>, + timer: Peri<'d, T>, + ppi_ch1: Peri<'d, impl ConfigurableChannel>, + ppi_ch2: Peri<'d, impl ConfigurableChannel>, + ppi_group: Peri<'d, impl Group>, _irq: impl interrupt::typelevel::Binding> + 'd, - rxd: impl Peripheral

+ 'd, - rts: impl Peripheral

+ 'd, + rxd: Peri<'d, impl GpioPin>, + rts: Peri<'d, impl GpioPin>, config: Config, rx_buffer: &'d mut [u8], ) -> Self { - into_ref!(uarte, timer, rxd, rts, ppi_ch1, ppi_ch2, ppi_group); Self::new_inner( uarte, timer, - ppi_ch1.map_into(), - ppi_ch2.map_into(), - ppi_group.map_into(), - rxd.map_into(), - Some(rts.map_into()), + ppi_ch1.into(), + ppi_ch2.into(), + ppi_group.into(), + rxd.into(), + Some(rts.into()), config, rx_buffer, ) @@ -615,13 +609,13 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarteRx<'d, U, T> { #[allow(clippy::too_many_arguments)] fn new_inner( - peri: PeripheralRef<'d, U>, - timer: PeripheralRef<'d, T>, - ppi_ch1: PeripheralRef<'d, AnyConfigurableChannel>, - ppi_ch2: PeripheralRef<'d, AnyConfigurableChannel>, - ppi_group: PeripheralRef<'d, AnyGroup>, - rxd: PeripheralRef<'d, AnyPin>, - rts: Option>, + peri: Peri<'d, U>, + timer: Peri<'d, T>, + ppi_ch1: Peri<'d, AnyConfigurableChannel>, + ppi_ch2: Peri<'d, AnyConfigurableChannel>, + ppi_group: Peri<'d, AnyGroup>, + rxd: Peri<'d, AnyPin>, + rts: Option>, config: Config, rx_buffer: &'d mut [u8], ) -> Self { @@ -640,13 +634,13 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarteRx<'d, U, T> { #[allow(clippy::too_many_arguments)] fn new_innerer( - peri: PeripheralRef<'d, U>, - timer: PeripheralRef<'d, T>, - ppi_ch1: PeripheralRef<'d, AnyConfigurableChannel>, - ppi_ch2: PeripheralRef<'d, AnyConfigurableChannel>, - ppi_group: PeripheralRef<'d, AnyGroup>, - rxd: PeripheralRef<'d, AnyPin>, - rts: Option>, + peri: Peri<'d, U>, + timer: Peri<'d, T>, + ppi_ch1: Peri<'d, AnyConfigurableChannel>, + ppi_ch2: Peri<'d, AnyConfigurableChannel>, + ppi_group: Peri<'d, AnyGroup>, + rxd: Peri<'d, AnyPin>, + rts: Option>, rx_buffer: &'d mut [u8], ) -> Self { assert!(rx_buffer.len() % 2 == 0); diff --git a/embassy-nrf/src/egu.rs b/embassy-nrf/src/egu.rs index 7f9abdac4..028396c7c 100644 --- a/embassy-nrf/src/egu.rs +++ b/embassy-nrf/src/egu.rs @@ -7,20 +7,19 @@ use core::marker::PhantomData; -use embassy_hal_internal::into_ref; +use embassy_hal_internal::PeripheralType; use crate::ppi::{Event, Task}; -use crate::{interrupt, pac, Peripheral, PeripheralRef}; +use crate::{interrupt, pac, Peri}; /// An instance of the EGU. pub struct Egu<'d, T: Instance> { - _p: PeripheralRef<'d, T>, + _p: Peri<'d, T>, } impl<'d, T: Instance> Egu<'d, T> { /// Create a new EGU instance. - pub fn new(_p: impl Peripheral

+ 'd) -> Self { - into_ref!(_p); + pub fn new(_p: Peri<'d, T>) -> Self { Self { _p } } @@ -39,7 +38,7 @@ pub(crate) trait SealedInstance { /// Basic Egu instance. #[allow(private_bounds)] -pub trait Instance: Peripheral

+ SealedInstance + 'static + Send { +pub trait Instance: SealedInstance + PeripheralType + 'static + Send { /// Interrupt for this peripheral. type Interrupt: interrupt::typelevel::Interrupt; } diff --git a/embassy-nrf/src/gpio.rs b/embassy-nrf/src/gpio.rs index c78fa4df5..d02da9ac5 100644 --- a/embassy-nrf/src/gpio.rs +++ b/embassy-nrf/src/gpio.rs @@ -5,14 +5,14 @@ use core::convert::Infallible; use core::hint::unreachable_unchecked; use cfg_if::cfg_if; -use embassy_hal_internal::{impl_peripheral, into_ref, PeripheralRef}; +use embassy_hal_internal::{impl_peripheral, Peri, PeripheralType}; +use crate::pac; use crate::pac::common::{Reg, RW}; use crate::pac::gpio; use crate::pac::gpio::vals; #[cfg(not(feature = "_nrf51"))] use crate::pac::shared::{regs::Psel, vals::Connect}; -use crate::{pac, Peripheral}; /// A GPIO port with up to 32 pins. #[derive(Debug, Eq, PartialEq)] @@ -49,7 +49,7 @@ pub struct Input<'d> { impl<'d> Input<'d> { /// Create GPIO input driver for a [Pin] with the provided [Pull] configuration. #[inline] - pub fn new(pin: impl Peripheral

+ 'd, pull: Pull) -> Self { + pub fn new(pin: Peri<'d, impl Pin>, pull: Pull) -> Self { let mut pin = Flex::new(pin); pin.set_as_input(pull); @@ -210,7 +210,7 @@ pub struct Output<'d> { impl<'d> Output<'d> { /// Create GPIO output driver for a [Pin] with the provided [Level] and [OutputDriver] configuration. #[inline] - pub fn new(pin: impl Peripheral

+ 'd, initial_output: Level, drive: OutputDrive) -> Self { + pub fn new(pin: Peri<'d, impl Pin>, initial_output: Level, drive: OutputDrive) -> Self { let mut pin = Flex::new(pin); match initial_output { Level::High => pin.set_high(), @@ -310,7 +310,7 @@ fn convert_pull(pull: Pull) -> vals::Pull { /// set while not in output mode, so the pin's level will be 'remembered' when it is not in output /// mode. pub struct Flex<'d> { - pub(crate) pin: PeripheralRef<'d, AnyPin>, + pub(crate) pin: Peri<'d, AnyPin>, } impl<'d> Flex<'d> { @@ -319,10 +319,9 @@ impl<'d> Flex<'d> { /// The pin remains disconnected. The initial output level is unspecified, but can be changed /// before the pin is put into output mode. #[inline] - pub fn new(pin: impl Peripheral

+ 'd) -> Self { - into_ref!(pin); + pub fn new(pin: Peri<'d, impl Pin>) -> Self { // Pin will be in disconnected state. - Self { pin: pin.map_into() } + Self { pin: pin.into() } } /// Put the pin into input mode. @@ -503,7 +502,7 @@ pub(crate) trait SealedPin { /// Interface for a Pin that can be configured by an [Input] or [Output] driver, or converted to an [AnyPin]. #[allow(private_bounds)] -pub trait Pin: Peripheral

+ Into + SealedPin + Sized + 'static { +pub trait Pin: PeripheralType + Into + SealedPin + Sized + 'static { /// Number of the pin within the port (0..31) #[inline] fn pin(&self) -> u8 { @@ -529,19 +528,11 @@ pub trait Pin: Peripheral

+ Into + SealedPin + Sized + 'static fn psel_bits(&self) -> pac::shared::regs::Psel { pac::shared::regs::Psel(self.pin_port() as u32) } - - /// Convert from concrete pin type PX_XX to type erased `AnyPin`. - #[inline] - fn degrade(self) -> AnyPin { - AnyPin { - pin_port: self.pin_port(), - } - } } /// Type-erased GPIO pin pub struct AnyPin { - pin_port: u8, + pub(crate) pin_port: u8, } impl AnyPin { @@ -550,8 +541,8 @@ impl AnyPin { /// # Safety /// - `pin_port` should not in use by another driver. #[inline] - pub unsafe fn steal(pin_port: u8) -> Self { - Self { pin_port } + pub unsafe fn steal(pin_port: u8) -> Peri<'static, Self> { + Peri::new_unchecked(Self { pin_port }) } } @@ -573,7 +564,7 @@ pub(crate) trait PselBits { } #[cfg(not(feature = "_nrf51"))] -impl<'a, P: Pin> PselBits for Option> { +impl<'a, P: Pin> PselBits for Option> { #[inline] fn psel_bits(&self) -> pac::shared::regs::Psel { match self { @@ -611,8 +602,10 @@ macro_rules! impl_pin { } impl From for crate::gpio::AnyPin { - fn from(val: peripherals::$type) -> Self { - crate::gpio::Pin::degrade(val) + fn from(_val: peripherals::$type) -> Self { + Self { + pin_port: $port_num * 32 + $pin_num, + } } } }; diff --git a/embassy-nrf/src/gpiote.rs b/embassy-nrf/src/gpiote.rs index 8771f9f08..d169b49f9 100644 --- a/embassy-nrf/src/gpiote.rs +++ b/embassy-nrf/src/gpiote.rs @@ -4,7 +4,7 @@ use core::convert::Infallible; use core::future::{poll_fn, Future}; use core::task::{Context, Poll}; -use embassy_hal_internal::{impl_peripheral, into_ref, Peripheral, PeripheralRef}; +use embassy_hal_internal::{impl_peripheral, Peri, PeripheralType}; use embassy_sync::waitqueue::AtomicWaker; use crate::gpio::{AnyPin, Flex, Input, Output, Pin as GpioPin, SealedPin as _}; @@ -189,7 +189,7 @@ impl Iterator for BitIter { /// GPIOTE channel driver in input mode pub struct InputChannel<'d> { - ch: PeripheralRef<'d, AnyChannel>, + ch: Peri<'d, AnyChannel>, pin: Input<'d>, } @@ -204,9 +204,7 @@ impl<'d> Drop for InputChannel<'d> { impl<'d> InputChannel<'d> { /// Create a new GPIOTE input channel driver. - pub fn new(ch: impl Peripheral

+ 'd, pin: Input<'d>, polarity: InputChannelPolarity) -> Self { - into_ref!(ch); - + pub fn new(ch: Peri<'d, impl Channel>, pin: Input<'d>, polarity: InputChannelPolarity) -> Self { let g = regs(); let num = ch.number(); @@ -228,7 +226,7 @@ impl<'d> InputChannel<'d> { g.events_in(num).write_value(0); - InputChannel { ch: ch.map_into(), pin } + InputChannel { ch: ch.into(), pin } } /// Asynchronously wait for an event in this channel. @@ -261,7 +259,7 @@ impl<'d> InputChannel<'d> { /// GPIOTE channel driver in output mode pub struct OutputChannel<'d> { - ch: PeripheralRef<'d, AnyChannel>, + ch: Peri<'d, AnyChannel>, _pin: Output<'d>, } @@ -276,8 +274,7 @@ impl<'d> Drop for OutputChannel<'d> { impl<'d> OutputChannel<'d> { /// Create a new GPIOTE output channel driver. - pub fn new(ch: impl Peripheral

+ 'd, pin: Output<'d>, polarity: OutputChannelPolarity) -> Self { - into_ref!(ch); + pub fn new(ch: Peri<'d, impl Channel>, pin: Output<'d>, polarity: OutputChannelPolarity) -> Self { let g = regs(); let num = ch.number(); @@ -301,7 +298,7 @@ impl<'d> OutputChannel<'d> { }); OutputChannel { - ch: ch.map_into(), + ch: ch.into(), _pin: pin, } } @@ -351,14 +348,12 @@ impl<'d> OutputChannel<'d> { #[must_use = "futures do nothing unless you `.await` or poll them"] pub(crate) struct PortInputFuture<'a> { - pin: PeripheralRef<'a, AnyPin>, + pin: Peri<'a, AnyPin>, } impl<'a> PortInputFuture<'a> { - fn new(pin: impl Peripheral

+ 'a) -> Self { - Self { - pin: pin.into_ref().map_into(), - } + fn new(pin: Peri<'a, impl GpioPin>) -> Self { + Self { pin: pin.into() } } } @@ -415,13 +410,13 @@ impl<'d> Flex<'d> { /// Wait until the pin is high. If it is already high, return immediately. pub async fn wait_for_high(&mut self) { self.pin.conf().modify(|w| w.set_sense(Sense::HIGH)); - PortInputFuture::new(&mut self.pin).await + PortInputFuture::new(self.pin.reborrow()).await } /// Wait until the pin is low. If it is already low, return immediately. pub async fn wait_for_low(&mut self) { self.pin.conf().modify(|w| w.set_sense(Sense::LOW)); - PortInputFuture::new(&mut self.pin).await + PortInputFuture::new(self.pin.reborrow()).await } /// Wait for the pin to undergo a transition from low to high. @@ -443,7 +438,7 @@ impl<'d> Flex<'d> { } else { self.pin.conf().modify(|w| w.set_sense(Sense::HIGH)); } - PortInputFuture::new(&mut self.pin).await + PortInputFuture::new(self.pin.reborrow()).await } } @@ -455,24 +450,14 @@ trait SealedChannel {} /// /// Implemented by all GPIOTE channels. #[allow(private_bounds)] -pub trait Channel: SealedChannel + Into + Sized + 'static { +pub trait Channel: PeripheralType + SealedChannel + Into + Sized + 'static { /// Get the channel number. fn number(&self) -> usize; - - /// Convert this channel to a type-erased `AnyChannel`. - /// - /// This allows using several channels in situations that might require - /// them to be the same type, like putting them in an array. - fn degrade(self) -> AnyChannel { - AnyChannel { - number: self.number() as u8, - } - } } /// Type-erased channel. /// -/// Obtained by calling `Channel::degrade`. +/// Obtained by calling `Channel::into()`. /// /// This allows using several channels in situations that might require /// them to be the same type, like putting them in an array. @@ -498,7 +483,9 @@ macro_rules! impl_channel { impl From for AnyChannel { fn from(val: peripherals::$type) -> Self { - Channel::degrade(val) + Self { + number: val.number() as u8, + } } } }; diff --git a/embassy-nrf/src/i2s.rs b/embassy-nrf/src/i2s.rs index 384a1637b..a7dde8cd7 100644 --- a/embassy-nrf/src/i2s.rs +++ b/embassy-nrf/src/i2s.rs @@ -10,14 +10,14 @@ use core::sync::atomic::{compiler_fence, AtomicBool, Ordering}; use core::task::Poll; use embassy_hal_internal::drop::OnDrop; -use embassy_hal_internal::{into_ref, PeripheralRef}; +use embassy_hal_internal::{Peri, PeripheralType}; use embassy_sync::waitqueue::AtomicWaker; use crate::gpio::{AnyPin, Pin as GpioPin, PselBits}; use crate::interrupt::typelevel::Interrupt; use crate::pac::i2s::vals; use crate::util::slice_in_ram_or; -use crate::{interrupt, pac, Peripheral, EASY_DMA_SIZE}; +use crate::{interrupt, pac, EASY_DMA_SIZE}; /// Type alias for `MultiBuffering` with 2 buffers. pub type DoubleBuffering = MultiBuffering; @@ -406,12 +406,12 @@ impl interrupt::typelevel::Handler for InterruptHandl /// I2S driver. pub struct I2S<'d, T: Instance> { - i2s: PeripheralRef<'d, T>, - mck: Option>, - sck: PeripheralRef<'d, AnyPin>, - lrck: PeripheralRef<'d, AnyPin>, - sdin: Option>, - sdout: Option>, + i2s: Peri<'d, T>, + mck: Option>, + sck: Peri<'d, AnyPin>, + lrck: Peri<'d, AnyPin>, + sdin: Option>, + sdout: Option>, master_clock: Option, config: Config, } @@ -419,20 +419,19 @@ pub struct I2S<'d, T: Instance> { impl<'d, T: Instance> I2S<'d, T> { /// Create a new I2S in master mode pub fn new_master( - i2s: impl Peripheral

+ 'd, + i2s: Peri<'d, T>, _irq: impl interrupt::typelevel::Binding> + 'd, - mck: impl Peripheral

+ 'd, - sck: impl Peripheral

+ 'd, - lrck: impl Peripheral

+ 'd, + mck: Peri<'d, impl GpioPin>, + sck: Peri<'d, impl GpioPin>, + lrck: Peri<'d, impl GpioPin>, master_clock: MasterClock, config: Config, ) -> Self { - into_ref!(i2s, mck, sck, lrck); Self { i2s, - mck: Some(mck.map_into()), - sck: sck.map_into(), - lrck: lrck.map_into(), + mck: Some(mck.into()), + sck: sck.into(), + lrck: lrck.into(), sdin: None, sdout: None, master_clock: Some(master_clock), @@ -442,18 +441,17 @@ impl<'d, T: Instance> I2S<'d, T> { /// Create a new I2S in slave mode pub fn new_slave( - i2s: impl Peripheral

+ 'd, + i2s: Peri<'d, T>, _irq: impl interrupt::typelevel::Binding> + 'd, - sck: impl Peripheral

+ 'd, - lrck: impl Peripheral

+ 'd, + sck: Peri<'d, impl GpioPin>, + lrck: Peri<'d, impl GpioPin>, config: Config, ) -> Self { - into_ref!(i2s, sck, lrck); Self { i2s, mck: None, - sck: sck.map_into(), - lrck: lrck.map_into(), + sck: sck.into(), + lrck: lrck.into(), sdin: None, sdout: None, master_clock: None, @@ -464,10 +462,10 @@ impl<'d, T: Instance> I2S<'d, T> { /// I2S output only pub fn output( mut self, - sdout: impl Peripheral

+ 'd, + sdout: Peri<'d, impl GpioPin>, buffers: MultiBuffering, ) -> OutputStream<'d, T, S, NB, NS> { - self.sdout = Some(sdout.into_ref().map_into()); + self.sdout = Some(sdout.into()); OutputStream { _p: self.build(), buffers, @@ -477,10 +475,10 @@ impl<'d, T: Instance> I2S<'d, T> { /// I2S input only pub fn input( mut self, - sdin: impl Peripheral

+ 'd, + sdin: Peri<'d, impl GpioPin>, buffers: MultiBuffering, ) -> InputStream<'d, T, S, NB, NS> { - self.sdin = Some(sdin.into_ref().map_into()); + self.sdin = Some(sdin.into()); InputStream { _p: self.build(), buffers, @@ -490,13 +488,13 @@ impl<'d, T: Instance> I2S<'d, T> { /// I2S full duplex (input and output) pub fn full_duplex( mut self, - sdin: impl Peripheral

+ 'd, - sdout: impl Peripheral

+ 'd, + sdin: Peri<'d, impl GpioPin>, + sdout: Peri<'d, impl GpioPin>, buffers_out: MultiBuffering, buffers_in: MultiBuffering, ) -> FullDuplexStream<'d, T, S, NB, NS> { - self.sdout = Some(sdout.into_ref().map_into()); - self.sdin = Some(sdin.into_ref().map_into()); + self.sdout = Some(sdout.into()); + self.sdin = Some(sdin.into()); FullDuplexStream { _p: self.build(), @@ -505,7 +503,7 @@ impl<'d, T: Instance> I2S<'d, T> { } } - fn build(self) -> PeripheralRef<'d, T> { + fn build(self) -> Peri<'d, T> { self.apply_config(); self.select_pins(); self.setup_interrupt(); @@ -702,7 +700,7 @@ impl<'d, T: Instance> I2S<'d, T> { /// I2S output pub struct OutputStream<'d, T: Instance, S: Sample, const NB: usize, const NS: usize> { - _p: PeripheralRef<'d, T>, + _p: Peri<'d, T>, buffers: MultiBuffering, } @@ -756,7 +754,7 @@ impl<'d, T: Instance, S: Sample, const NB: usize, const NS: usize> OutputStream< /// I2S input pub struct InputStream<'d, T: Instance, S: Sample, const NB: usize, const NS: usize> { - _p: PeripheralRef<'d, T>, + _p: Peri<'d, T>, buffers: MultiBuffering, } @@ -811,7 +809,7 @@ impl<'d, T: Instance, S: Sample, const NB: usize, const NS: usize> InputStream<' /// I2S full duplex stream (input & output) pub struct FullDuplexStream<'d, T: Instance, S: Sample, const NB: usize, const NS: usize> { - _p: PeripheralRef<'d, T>, + _p: Peri<'d, T>, buffers_out: MultiBuffering, buffers_in: MultiBuffering, } @@ -1148,7 +1146,7 @@ pub(crate) trait SealedInstance { /// I2S peripheral instance. #[allow(private_bounds)] -pub trait Instance: Peripheral

+ SealedInstance + 'static + Send { +pub trait Instance: SealedInstance + PeripheralType + 'static + Send { /// Interrupt for this peripheral. type Interrupt: interrupt::typelevel::Interrupt; } diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index 5cd0efa58..d2ff054f4 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs @@ -263,7 +263,7 @@ pub use chip::pac; #[cfg(not(feature = "unstable-pac"))] pub(crate) use chip::pac; pub use chip::{peripherals, Peripherals, EASY_DMA_SIZE}; -pub use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; +pub use embassy_hal_internal::{Peri, PeripheralType}; pub use crate::chip::interrupt; #[cfg(feature = "rt")] diff --git a/embassy-nrf/src/nfct.rs b/embassy-nrf/src/nfct.rs index 8b4b6dfe0..8d70ec954 100644 --- a/embassy-nrf/src/nfct.rs +++ b/embassy-nrf/src/nfct.rs @@ -13,7 +13,6 @@ use core::future::poll_fn; use core::sync::atomic::{compiler_fence, Ordering}; use core::task::Poll; -use embassy_hal_internal::{into_ref, PeripheralRef}; use embassy_sync::waitqueue::AtomicWaker; pub use vals::{Bitframesdd as SddPat, Discardmode as DiscardMode}; @@ -22,7 +21,7 @@ use crate::pac::nfct::vals; use crate::pac::NFCT; use crate::peripherals::NFCT; use crate::util::slice_in_ram; -use crate::{interrupt, pac, Peripheral}; +use crate::{interrupt, pac, Peri}; /// NFCID1 (aka UID) of different sizes. #[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] @@ -96,7 +95,7 @@ pub enum Error { /// NFC tag emulator driver. pub struct NfcT<'d> { - _p: PeripheralRef<'d, NFCT>, + _p: Peri<'d, NFCT>, rx_buf: [u8; 256], tx_buf: [u8; 256], } @@ -104,12 +103,10 @@ pub struct NfcT<'d> { impl<'d> NfcT<'d> { /// Create an Nfc Tag driver pub fn new( - _p: impl Peripheral

+ 'd, + _p: Peri<'d, NFCT>, _irq: impl interrupt::typelevel::Binding + 'd, config: &Config, ) -> Self { - into_ref!(_p); - let r = pac::NFCT; unsafe { diff --git a/embassy-nrf/src/nvmc.rs b/embassy-nrf/src/nvmc.rs index 6973b4847..c46af0b34 100644 --- a/embassy-nrf/src/nvmc.rs +++ b/embassy-nrf/src/nvmc.rs @@ -2,14 +2,13 @@ use core::{ptr, slice}; -use embassy_hal_internal::{into_ref, PeripheralRef}; use embedded_storage::nor_flash::{ ErrorType, MultiwriteNorFlash, NorFlash, NorFlashError, NorFlashErrorKind, ReadNorFlash, }; use crate::pac::nvmc::vals; use crate::peripherals::NVMC; -use crate::{pac, Peripheral}; +use crate::{pac, Peri}; #[cfg(not(feature = "_nrf5340-net"))] /// Erase size of NVMC flash in bytes. @@ -42,13 +41,12 @@ impl NorFlashError for Error { /// Non-Volatile Memory Controller (NVMC) that implements the `embedded-storage` traits. pub struct Nvmc<'d> { - _p: PeripheralRef<'d, NVMC>, + _p: Peri<'d, NVMC>, } impl<'d> Nvmc<'d> { /// Create Nvmc driver. - pub fn new(_p: impl Peripheral

+ 'd) -> Self { - into_ref!(_p); + pub fn new(_p: Peri<'d, NVMC>) -> Self { Self { _p } } diff --git a/embassy-nrf/src/pdm.rs b/embassy-nrf/src/pdm.rs index 483d1a644..c2a4ba65f 100644 --- a/embassy-nrf/src/pdm.rs +++ b/embassy-nrf/src/pdm.rs @@ -8,7 +8,7 @@ use core::sync::atomic::{compiler_fence, Ordering}; use core::task::Poll; use embassy_hal_internal::drop::OnDrop; -use embassy_hal_internal::{into_ref, PeripheralRef}; +use embassy_hal_internal::{Peri, PeripheralType}; use embassy_sync::waitqueue::AtomicWaker; use fixed::types::I7F1; @@ -25,7 +25,7 @@ pub use crate::pac::pdm::vals::Freq as Frequency; feature = "_nrf91", ))] pub use crate::pac::pdm::vals::Ratio; -use crate::{interrupt, pac, Peripheral}; +use crate::{interrupt, pac}; /// Interrupt handler pub struct InterruptHandler { @@ -54,7 +54,7 @@ impl interrupt::typelevel::Handler for InterruptHandl /// PDM microphone interface pub struct Pdm<'d, T: Instance> { - _peri: PeripheralRef<'d, T>, + _peri: Peri<'d, T>, } /// PDM error @@ -89,24 +89,16 @@ pub enum SamplerState { impl<'d, T: Instance> Pdm<'d, T> { /// Create PDM driver pub fn new( - pdm: impl Peripheral

+ 'd, + pdm: Peri<'d, T>, _irq: impl interrupt::typelevel::Binding> + 'd, - clk: impl Peripheral

+ 'd, - din: impl Peripheral

+ 'd, + clk: Peri<'d, impl GpioPin>, + din: Peri<'d, impl GpioPin>, config: Config, ) -> Self { - into_ref!(pdm, clk, din); - Self::new_inner(pdm, clk.map_into(), din.map_into(), config) + Self::new_inner(pdm, clk.into(), din.into(), config) } - fn new_inner( - pdm: PeripheralRef<'d, T>, - clk: PeripheralRef<'d, AnyPin>, - din: PeripheralRef<'d, AnyPin>, - config: Config, - ) -> Self { - into_ref!(pdm); - + fn new_inner(pdm: Peri<'d, T>, clk: Peri<'d, AnyPin>, din: Peri<'d, AnyPin>, config: Config) -> Self { let r = T::regs(); // setup gpio pins @@ -452,7 +444,7 @@ pub(crate) trait SealedInstance { /// PDM peripheral instance #[allow(private_bounds)] -pub trait Instance: Peripheral

+ SealedInstance + 'static + Send { +pub trait Instance: SealedInstance + PeripheralType + 'static + Send { /// Interrupt for this peripheral type Interrupt: interrupt::typelevel::Interrupt; } diff --git a/embassy-nrf/src/ppi/dppi.rs b/embassy-nrf/src/ppi/dppi.rs index 3c7b96df7..686f66987 100644 --- a/embassy-nrf/src/ppi/dppi.rs +++ b/embassy-nrf/src/ppi/dppi.rs @@ -1,7 +1,5 @@ -use embassy_hal_internal::into_ref; - use super::{Channel, ConfigurableChannel, Event, Ppi, Task}; -use crate::{pac, Peripheral}; +use crate::{pac, Peri}; const DPPI_ENABLE_BIT: u32 = 0x8000_0000; const DPPI_CHANNEL_MASK: u32 = 0x0000_00FF; @@ -12,14 +10,14 @@ pub(crate) fn regs() -> pac::dppic::Dppic { impl<'d, C: ConfigurableChannel> Ppi<'d, C, 1, 1> { /// Configure PPI channel to trigger `task` on `event`. - pub fn new_one_to_one(ch: impl Peripheral

+ 'd, event: Event<'d>, task: Task<'d>) -> Self { + pub fn new_one_to_one(ch: Peri<'d, C>, event: Event<'d>, task: Task<'d>) -> Self { Ppi::new_many_to_many(ch, [event], [task]) } } impl<'d, C: ConfigurableChannel> Ppi<'d, C, 1, 2> { /// Configure PPI channel to trigger both `task1` and `task2` on `event`. - pub fn new_one_to_two(ch: impl Peripheral

+ 'd, event: Event<'d>, task1: Task<'d>, task2: Task<'d>) -> Self { + pub fn new_one_to_two(ch: Peri<'d, C>, event: Event<'d>, task1: Task<'d>, task2: Task<'d>) -> Self { Ppi::new_many_to_many(ch, [event], [task1, task2]) } } @@ -28,13 +26,7 @@ impl<'d, C: ConfigurableChannel, const EVENT_COUNT: usize, const TASK_COUNT: usi Ppi<'d, C, EVENT_COUNT, TASK_COUNT> { /// Configure a DPPI channel to trigger all `tasks` when any of the `events` fires. - pub fn new_many_to_many( - ch: impl Peripheral

+ 'd, - events: [Event<'d>; EVENT_COUNT], - tasks: [Task<'d>; TASK_COUNT], - ) -> Self { - into_ref!(ch); - + pub fn new_many_to_many(ch: Peri<'d, C>, events: [Event<'d>; EVENT_COUNT], tasks: [Task<'d>; TASK_COUNT]) -> Self { let val = DPPI_ENABLE_BIT | (ch.number() as u32 & DPPI_CHANNEL_MASK); for task in tasks { if unsafe { task.subscribe_reg().read_volatile() } != 0 { diff --git a/embassy-nrf/src/ppi/mod.rs b/embassy-nrf/src/ppi/mod.rs index 325e4ce00..531777205 100644 --- a/embassy-nrf/src/ppi/mod.rs +++ b/embassy-nrf/src/ppi/mod.rs @@ -18,10 +18,10 @@ use core::marker::PhantomData; use core::ptr::NonNull; -use embassy_hal_internal::{impl_peripheral, into_ref, PeripheralRef}; +use embassy_hal_internal::{impl_peripheral, Peri, PeripheralType}; use crate::pac::common::{Reg, RW, W}; -use crate::{peripherals, Peripheral}; +use crate::peripherals; #[cfg_attr(feature = "_dppi", path = "dppi.rs")] #[cfg_attr(feature = "_ppi", path = "ppi.rs")] @@ -30,7 +30,7 @@ pub(crate) use _version::*; /// PPI channel driver. pub struct Ppi<'d, C: Channel, const EVENT_COUNT: usize, const TASK_COUNT: usize> { - ch: PeripheralRef<'d, C>, + ch: Peri<'d, C>, #[cfg(feature = "_dppi")] events: [Event<'d>; EVENT_COUNT], #[cfg(feature = "_dppi")] @@ -39,16 +39,14 @@ pub struct Ppi<'d, C: Channel, const EVENT_COUNT: usize, const TASK_COUNT: usize /// PPI channel group driver. pub struct PpiGroup<'d, G: Group> { - g: PeripheralRef<'d, G>, + g: Peri<'d, G>, } impl<'d, G: Group> PpiGroup<'d, G> { /// Create a new PPI group driver. /// /// The group is initialized as containing no channels. - pub fn new(g: impl Peripheral

+ 'd) -> Self { - into_ref!(g); - + pub fn new(g: Peri<'d, G>) -> Self { let r = regs(); let n = g.number(); r.chg(n).write(|_| ()); @@ -210,34 +208,22 @@ pub(crate) trait SealedGroup {} /// Interface for PPI channels. #[allow(private_bounds)] -pub trait Channel: SealedChannel + Peripheral

+ Sized + 'static { +pub trait Channel: SealedChannel + PeripheralType + Sized + 'static { /// Returns the number of the channel fn number(&self) -> usize; } /// Interface for PPI channels that can be configured. -pub trait ConfigurableChannel: Channel + Into { - /// Convert into a type erased configurable channel. - fn degrade(self) -> AnyConfigurableChannel; -} +pub trait ConfigurableChannel: Channel + Into {} /// Interface for PPI channels that cannot be configured. -pub trait StaticChannel: Channel + Into { - /// Convert into a type erased static channel. - fn degrade(self) -> AnyStaticChannel; -} +pub trait StaticChannel: Channel + Into {} /// Interface for a group of PPI channels. #[allow(private_bounds)] -pub trait Group: SealedGroup + Peripheral

+ Into + Sized + 'static { +pub trait Group: SealedGroup + PeripheralType + Into + Sized + 'static { /// Returns the number of the group. fn number(&self) -> usize; - /// Convert into a type erased group. - fn degrade(self) -> AnyGroup { - AnyGroup { - number: self.number() as u8, - } - } } // ====================== @@ -255,11 +241,7 @@ impl Channel for AnyStaticChannel { self.number as usize } } -impl StaticChannel for AnyStaticChannel { - fn degrade(self) -> AnyStaticChannel { - self - } -} +impl StaticChannel for AnyStaticChannel {} /// The any configurable channel can represent any configurable channel at runtime. /// This can be used to have fewer generic parameters in some places. @@ -273,11 +255,7 @@ impl Channel for AnyConfigurableChannel { self.number as usize } } -impl ConfigurableChannel for AnyConfigurableChannel { - fn degrade(self) -> AnyConfigurableChannel { - self - } -} +impl ConfigurableChannel for AnyConfigurableChannel {} #[cfg(not(feature = "_nrf51"))] macro_rules! impl_ppi_channel { @@ -291,35 +269,23 @@ macro_rules! impl_ppi_channel { }; ($type:ident, $number:expr => static) => { impl_ppi_channel!($type, $number); - impl crate::ppi::StaticChannel for peripherals::$type { - fn degrade(self) -> crate::ppi::AnyStaticChannel { - use crate::ppi::Channel; - crate::ppi::AnyStaticChannel { - number: self.number() as u8, - } - } - } - + impl crate::ppi::StaticChannel for peripherals::$type {} impl From for crate::ppi::AnyStaticChannel { fn from(val: peripherals::$type) -> Self { - crate::ppi::StaticChannel::degrade(val) + Self { + number: crate::ppi::Channel::number(&val) as u8, + } } } }; ($type:ident, $number:expr => configurable) => { impl_ppi_channel!($type, $number); - impl crate::ppi::ConfigurableChannel for peripherals::$type { - fn degrade(self) -> crate::ppi::AnyConfigurableChannel { - use crate::ppi::Channel; - crate::ppi::AnyConfigurableChannel { - number: self.number() as u8, - } - } - } - + impl crate::ppi::ConfigurableChannel for peripherals::$type {} impl From for crate::ppi::AnyConfigurableChannel { fn from(val: peripherals::$type) -> Self { - crate::ppi::ConfigurableChannel::degrade(val) + Self { + number: crate::ppi::Channel::number(&val) as u8, + } } } }; @@ -351,7 +317,9 @@ macro_rules! impl_group { impl From for crate::ppi::AnyGroup { fn from(val: peripherals::$type) -> Self { - crate::ppi::Group::degrade(val) + Self { + number: crate::ppi::Group::number(&val) as u8, + } } } }; diff --git a/embassy-nrf/src/ppi/ppi.rs b/embassy-nrf/src/ppi/ppi.rs index a1beb9dcd..e04dacbc0 100644 --- a/embassy-nrf/src/ppi/ppi.rs +++ b/embassy-nrf/src/ppi/ppi.rs @@ -1,7 +1,5 @@ -use embassy_hal_internal::into_ref; - use super::{Channel, ConfigurableChannel, Event, Ppi, Task}; -use crate::{pac, Peripheral}; +use crate::{pac, Peri}; impl<'d> Task<'d> { fn reg_val(&self) -> u32 { @@ -21,9 +19,7 @@ pub(crate) fn regs() -> pac::ppi::Ppi { #[cfg(not(feature = "_nrf51"))] // Not for nrf51 because of the fork task impl<'d, C: super::StaticChannel> Ppi<'d, C, 0, 1> { /// Configure PPI channel to trigger `task`. - pub fn new_zero_to_one(ch: impl Peripheral

+ 'd, task: Task) -> Self { - into_ref!(ch); - + pub fn new_zero_to_one(ch: Peri<'d, C>, task: Task) -> Self { let r = regs(); let n = ch.number(); r.fork(n).tep().write_value(task.reg_val()); @@ -34,9 +30,7 @@ impl<'d, C: super::StaticChannel> Ppi<'d, C, 0, 1> { impl<'d, C: ConfigurableChannel> Ppi<'d, C, 1, 1> { /// Configure PPI channel to trigger `task` on `event`. - pub fn new_one_to_one(ch: impl Peripheral

+ 'd, event: Event<'d>, task: Task<'d>) -> Self { - into_ref!(ch); - + pub fn new_one_to_one(ch: Peri<'d, C>, event: Event<'d>, task: Task<'d>) -> Self { let r = regs(); let n = ch.number(); r.ch(n).eep().write_value(event.reg_val()); @@ -49,9 +43,7 @@ impl<'d, C: ConfigurableChannel> Ppi<'d, C, 1, 1> { #[cfg(not(feature = "_nrf51"))] // Not for nrf51 because of the fork task impl<'d, C: ConfigurableChannel> Ppi<'d, C, 1, 2> { /// Configure PPI channel to trigger both `task1` and `task2` on `event`. - pub fn new_one_to_two(ch: impl Peripheral

+ 'd, event: Event<'d>, task1: Task<'d>, task2: Task<'d>) -> Self { - into_ref!(ch); - + pub fn new_one_to_two(ch: Peri<'d, C>, event: Event<'d>, task1: Task<'d>, task2: Task<'d>) -> Self { let r = regs(); let n = ch.number(); r.ch(n).eep().write_value(event.reg_val()); diff --git a/embassy-nrf/src/pwm.rs b/embassy-nrf/src/pwm.rs index 6247ff6a5..a2e153e26 100644 --- a/embassy-nrf/src/pwm.rs +++ b/embassy-nrf/src/pwm.rs @@ -4,34 +4,34 @@ use core::sync::atomic::{compiler_fence, Ordering}; -use embassy_hal_internal::{into_ref, PeripheralRef}; +use embassy_hal_internal::{Peri, PeripheralType}; use crate::gpio::{convert_drive, AnyPin, OutputDrive, Pin as GpioPin, PselBits, SealedPin as _, DISCONNECTED}; use crate::pac::gpio::vals as gpiovals; use crate::pac::pwm::vals; use crate::ppi::{Event, Task}; use crate::util::slice_in_ram_or; -use crate::{interrupt, pac, Peripheral}; +use crate::{interrupt, pac}; /// SimplePwm is the traditional pwm interface you're probably used to, allowing /// to simply set a duty cycle across up to four channels. pub struct SimplePwm<'d, T: Instance> { - _peri: PeripheralRef<'d, T>, + _peri: Peri<'d, T>, duty: [u16; 4], - ch0: Option>, - ch1: Option>, - ch2: Option>, - ch3: Option>, + ch0: Option>, + ch1: Option>, + ch2: Option>, + ch3: Option>, } /// SequencePwm allows you to offload the updating of a sequence of duty cycles /// to up to four channels, as well as repeat that sequence n times. pub struct SequencePwm<'d, T: Instance> { - _peri: PeripheralRef<'d, T>, - ch0: Option>, - ch1: Option>, - ch2: Option>, - ch3: Option>, + _peri: Peri<'d, T>, + ch0: Option>, + ch1: Option>, + ch2: Option>, + ch3: Option>, } /// PWM error @@ -54,78 +54,61 @@ pub const PWM_CLK_HZ: u32 = 16_000_000; impl<'d, T: Instance> SequencePwm<'d, T> { /// Create a new 1-channel PWM #[allow(unused_unsafe)] - pub fn new_1ch( - pwm: impl Peripheral

+ 'd, - ch0: impl Peripheral

+ 'd, - config: Config, - ) -> Result { - into_ref!(ch0); - Self::new_inner(pwm, Some(ch0.map_into()), None, None, None, config) + pub fn new_1ch(pwm: Peri<'d, T>, ch0: Peri<'d, impl GpioPin>, config: Config) -> Result { + Self::new_inner(pwm, Some(ch0.into()), None, None, None, config) } /// Create a new 2-channel PWM #[allow(unused_unsafe)] pub fn new_2ch( - pwm: impl Peripheral

+ 'd, - ch0: impl Peripheral

+ 'd, - ch1: impl Peripheral

+ 'd, + pwm: Peri<'d, T>, + ch0: Peri<'d, impl GpioPin>, + ch1: Peri<'d, impl GpioPin>, config: Config, ) -> Result { - into_ref!(ch0, ch1); - Self::new_inner(pwm, Some(ch0.map_into()), Some(ch1.map_into()), None, None, config) + Self::new_inner(pwm, Some(ch0.into()), Some(ch1.into()), None, None, config) } /// Create a new 3-channel PWM #[allow(unused_unsafe)] pub fn new_3ch( - pwm: impl Peripheral

+ 'd, - ch0: impl Peripheral

+ 'd, - ch1: impl Peripheral

+ 'd, - ch2: impl Peripheral

+ 'd, + pwm: Peri<'d, T>, + ch0: Peri<'d, impl GpioPin>, + ch1: Peri<'d, impl GpioPin>, + ch2: Peri<'d, impl GpioPin>, config: Config, ) -> Result { - into_ref!(ch0, ch1, ch2); - Self::new_inner( - pwm, - Some(ch0.map_into()), - Some(ch1.map_into()), - Some(ch2.map_into()), - None, - config, - ) + Self::new_inner(pwm, Some(ch0.into()), Some(ch1.into()), Some(ch2.into()), None, config) } /// Create a new 4-channel PWM #[allow(unused_unsafe)] pub fn new_4ch( - pwm: impl Peripheral

+ 'd, - ch0: impl Peripheral

+ 'd, - ch1: impl Peripheral

+ 'd, - ch2: impl Peripheral

+ 'd, - ch3: impl Peripheral

+ 'd, + pwm: Peri<'d, T>, + ch0: Peri<'d, impl GpioPin>, + ch1: Peri<'d, impl GpioPin>, + ch2: Peri<'d, impl GpioPin>, + ch3: Peri<'d, impl GpioPin>, config: Config, ) -> Result { - into_ref!(ch0, ch1, ch2, ch3); Self::new_inner( pwm, - Some(ch0.map_into()), - Some(ch1.map_into()), - Some(ch2.map_into()), - Some(ch3.map_into()), + Some(ch0.into()), + Some(ch1.into()), + Some(ch2.into()), + Some(ch3.into()), config, ) } fn new_inner( - _pwm: impl Peripheral

+ 'd, - ch0: Option>, - ch1: Option>, - ch2: Option>, - ch3: Option>, + _pwm: Peri<'d, T>, + ch0: Option>, + ch1: Option>, + ch2: Option>, + ch3: Option>, config: Config, ) -> Result { - into_ref!(_pwm); - let r = T::regs(); if let Some(pin) = &ch0 { @@ -610,74 +593,54 @@ pub enum CounterMode { impl<'d, T: Instance> SimplePwm<'d, T> { /// Create a new 1-channel PWM #[allow(unused_unsafe)] - pub fn new_1ch(pwm: impl Peripheral

+ 'd, ch0: impl Peripheral

+ 'd) -> Self { - unsafe { - into_ref!(ch0); - Self::new_inner(pwm, Some(ch0.map_into()), None, None, None) - } + pub fn new_1ch(pwm: Peri<'d, T>, ch0: Peri<'d, impl GpioPin>) -> Self { + unsafe { Self::new_inner(pwm, Some(ch0.into()), None, None, None) } } /// Create a new 2-channel PWM #[allow(unused_unsafe)] - pub fn new_2ch( - pwm: impl Peripheral

+ 'd, - ch0: impl Peripheral

+ 'd, - ch1: impl Peripheral

+ 'd, - ) -> Self { - into_ref!(ch0, ch1); - Self::new_inner(pwm, Some(ch0.map_into()), Some(ch1.map_into()), None, None) + pub fn new_2ch(pwm: Peri<'d, T>, ch0: Peri<'d, impl GpioPin>, ch1: Peri<'d, impl GpioPin>) -> Self { + Self::new_inner(pwm, Some(ch0.into()), Some(ch1.into()), None, None) } /// Create a new 3-channel PWM #[allow(unused_unsafe)] pub fn new_3ch( - pwm: impl Peripheral

+ 'd, - ch0: impl Peripheral

+ 'd, - ch1: impl Peripheral

+ 'd, - ch2: impl Peripheral

+ 'd, + pwm: Peri<'d, T>, + ch0: Peri<'d, impl GpioPin>, + ch1: Peri<'d, impl GpioPin>, + ch2: Peri<'d, impl GpioPin>, ) -> Self { - unsafe { - into_ref!(ch0, ch1, ch2); - Self::new_inner( - pwm, - Some(ch0.map_into()), - Some(ch1.map_into()), - Some(ch2.map_into()), - None, - ) - } + unsafe { Self::new_inner(pwm, Some(ch0.into()), Some(ch1.into()), Some(ch2.into()), None) } } /// Create a new 4-channel PWM #[allow(unused_unsafe)] pub fn new_4ch( - pwm: impl Peripheral

+ 'd, - ch0: impl Peripheral

+ 'd, - ch1: impl Peripheral

+ 'd, - ch2: impl Peripheral

+ 'd, - ch3: impl Peripheral

+ 'd, + pwm: Peri<'d, T>, + ch0: Peri<'d, impl GpioPin>, + ch1: Peri<'d, impl GpioPin>, + ch2: Peri<'d, impl GpioPin>, + ch3: Peri<'d, impl GpioPin>, ) -> Self { unsafe { - into_ref!(ch0, ch1, ch2, ch3); Self::new_inner( pwm, - Some(ch0.map_into()), - Some(ch1.map_into()), - Some(ch2.map_into()), - Some(ch3.map_into()), + Some(ch0.into()), + Some(ch1.into()), + Some(ch2.into()), + Some(ch3.into()), ) } } fn new_inner( - _pwm: impl Peripheral

+ 'd, - ch0: Option>, - ch1: Option>, - ch2: Option>, - ch3: Option>, + _pwm: Peri<'d, T>, + ch0: Option>, + ch1: Option>, + ch2: Option>, + ch3: Option>, ) -> Self { - into_ref!(_pwm); - let r = T::regs(); for (i, ch) in [&ch0, &ch1, &ch2, &ch3].into_iter().enumerate() { @@ -896,7 +859,7 @@ pub(crate) trait SealedInstance { /// PWM peripheral instance. #[allow(private_bounds)] -pub trait Instance: Peripheral

+ SealedInstance + 'static { +pub trait Instance: SealedInstance + PeripheralType + 'static { /// Interrupt for this peripheral. type Interrupt: interrupt::typelevel::Interrupt; } diff --git a/embassy-nrf/src/qdec.rs b/embassy-nrf/src/qdec.rs index efd2a134c..69bfab0bb 100644 --- a/embassy-nrf/src/qdec.rs +++ b/embassy-nrf/src/qdec.rs @@ -6,18 +6,18 @@ use core::future::poll_fn; use core::marker::PhantomData; use core::task::Poll; -use embassy_hal_internal::{into_ref, PeripheralRef}; +use embassy_hal_internal::{Peri, PeripheralType}; use embassy_sync::waitqueue::AtomicWaker; use crate::gpio::{AnyPin, Pin as GpioPin, SealedPin as _}; use crate::interrupt::typelevel::Interrupt; use crate::pac::gpio::vals as gpiovals; use crate::pac::qdec::vals; -use crate::{interrupt, pac, Peripheral}; +use crate::{interrupt, pac}; /// Quadrature decoder driver. pub struct Qdec<'d, T: Instance> { - _p: PeripheralRef<'d, T>, + _p: Peri<'d, T>, } /// QDEC config @@ -62,34 +62,32 @@ impl interrupt::typelevel::Handler for InterruptHandl impl<'d, T: Instance> Qdec<'d, T> { /// Create a new QDEC. pub fn new( - qdec: impl Peripheral

+ 'd, + qdec: Peri<'d, T>, _irq: impl interrupt::typelevel::Binding> + 'd, - a: impl Peripheral

+ 'd, - b: impl Peripheral

+ 'd, + a: Peri<'d, impl GpioPin>, + b: Peri<'d, impl GpioPin>, config: Config, ) -> Self { - into_ref!(qdec, a, b); - Self::new_inner(qdec, a.map_into(), b.map_into(), None, config) + Self::new_inner(qdec, a.into(), b.into(), None, config) } /// Create a new QDEC, with a pin for LED output. pub fn new_with_led( - qdec: impl Peripheral

+ 'd, + qdec: Peri<'d, T>, _irq: impl interrupt::typelevel::Binding> + 'd, - a: impl Peripheral

+ 'd, - b: impl Peripheral

+ 'd, - led: impl Peripheral

+ 'd, + a: Peri<'d, impl GpioPin>, + b: Peri<'d, impl GpioPin>, + led: Peri<'d, impl GpioPin>, config: Config, ) -> Self { - into_ref!(qdec, a, b, led); - Self::new_inner(qdec, a.map_into(), b.map_into(), Some(led.map_into()), config) + Self::new_inner(qdec, a.into(), b.into(), Some(led.into()), config) } fn new_inner( - p: PeripheralRef<'d, T>, - a: PeripheralRef<'d, AnyPin>, - b: PeripheralRef<'d, AnyPin>, - led: Option>, + p: Peri<'d, T>, + a: Peri<'d, AnyPin>, + b: Peri<'d, AnyPin>, + led: Option>, config: Config, ) -> Self { let r = T::regs(); @@ -272,7 +270,7 @@ pub(crate) trait SealedInstance { /// qdec peripheral instance. #[allow(private_bounds)] -pub trait Instance: Peripheral

+ SealedInstance + 'static + Send { +pub trait Instance: SealedInstance + PeripheralType + 'static + Send { /// Interrupt for this peripheral. type Interrupt: interrupt::typelevel::Interrupt; } diff --git a/embassy-nrf/src/qspi.rs b/embassy-nrf/src/qspi.rs index 17e127700..e6e829f6e 100755 --- a/embassy-nrf/src/qspi.rs +++ b/embassy-nrf/src/qspi.rs @@ -8,7 +8,7 @@ use core::ptr; use core::task::Poll; use embassy_hal_internal::drop::OnDrop; -use embassy_hal_internal::{into_ref, PeripheralRef}; +use embassy_hal_internal::{Peri, PeripheralType}; use embassy_sync::waitqueue::AtomicWaker; use embedded_storage::nor_flash::{ErrorType, NorFlash, NorFlashError, NorFlashErrorKind, ReadNorFlash}; @@ -19,7 +19,7 @@ use crate::pac::qspi::vals; pub use crate::pac::qspi::vals::{ Addrmode as AddressMode, Ppsize as WritePageSize, Readoc as ReadOpcode, Spimode as SpiMode, Writeoc as WriteOpcode, }; -use crate::{interrupt, pac, Peripheral}; +use crate::{interrupt, pac}; /// Deep power-down config. pub struct DeepPowerDownConfig { @@ -139,7 +139,7 @@ impl interrupt::typelevel::Handler for InterruptHandl /// QSPI flash driver. pub struct Qspi<'d, T: Instance> { - _peri: PeripheralRef<'d, T>, + _peri: Peri<'d, T>, dpm_enabled: bool, capacity: u32, } @@ -147,18 +147,16 @@ pub struct Qspi<'d, T: Instance> { impl<'d, T: Instance> Qspi<'d, T> { /// Create a new QSPI driver. pub fn new( - qspi: impl Peripheral

+ 'd, + qspi: Peri<'d, T>, _irq: impl interrupt::typelevel::Binding> + 'd, - sck: impl Peripheral

+ 'd, - csn: impl Peripheral

+ 'd, - io0: impl Peripheral

+ 'd, - io1: impl Peripheral

+ 'd, - io2: impl Peripheral

+ 'd, - io3: impl Peripheral

+ 'd, + sck: Peri<'d, impl GpioPin>, + csn: Peri<'d, impl GpioPin>, + io0: Peri<'d, impl GpioPin>, + io1: Peri<'d, impl GpioPin>, + io2: Peri<'d, impl GpioPin>, + io3: Peri<'d, impl GpioPin>, config: Config, ) -> Self { - into_ref!(qspi, sck, csn, io0, io1, io2, io3); - let r = T::regs(); macro_rules! config_pin { @@ -664,7 +662,7 @@ pub(crate) trait SealedInstance { /// QSPI peripheral instance. #[allow(private_bounds)] -pub trait Instance: Peripheral

+ SealedInstance + 'static + Send { +pub trait Instance: SealedInstance + PeripheralType + 'static + Send { /// Interrupt for this peripheral. type Interrupt: interrupt::typelevel::Interrupt; } diff --git a/embassy-nrf/src/radio/ble.rs b/embassy-nrf/src/radio/ble.rs index 682ca1c79..d42bbe5f6 100644 --- a/embassy-nrf/src/radio/ble.rs +++ b/embassy-nrf/src/radio/ble.rs @@ -5,7 +5,6 @@ use core::sync::atomic::{compiler_fence, Ordering}; use core::task::Poll; use embassy_hal_internal::drop::OnDrop; -use embassy_hal_internal::{into_ref, PeripheralRef}; pub use pac::radio::vals::Mode; #[cfg(not(feature = "_nrf51"))] use pac::radio::vals::Plen as PreambleLength; @@ -15,20 +14,19 @@ use crate::pac::radio::vals; use crate::radio::*; pub use crate::radio::{Error, TxPower}; use crate::util::slice_in_ram_or; +use crate::Peri; /// Radio driver. pub struct Radio<'d, T: Instance> { - _p: PeripheralRef<'d, T>, + _p: Peri<'d, T>, } impl<'d, T: Instance> Radio<'d, T> { /// Create a new radio driver. pub fn new( - radio: impl Peripheral

+ 'd, + radio: Peri<'d, T>, _irq: impl interrupt::typelevel::Binding> + 'd, ) -> Self { - into_ref!(radio); - let r = T::regs(); r.pcnf1().write(|w| { diff --git a/embassy-nrf/src/radio/ieee802154.rs b/embassy-nrf/src/radio/ieee802154.rs index 083842f4a..2f0bcbe04 100644 --- a/embassy-nrf/src/radio/ieee802154.rs +++ b/embassy-nrf/src/radio/ieee802154.rs @@ -4,13 +4,12 @@ use core::sync::atomic::{compiler_fence, Ordering}; use core::task::Poll; use embassy_hal_internal::drop::OnDrop; -use embassy_hal_internal::{into_ref, PeripheralRef}; use super::{state, Error, Instance, InterruptHandler, RadioState, TxPower}; use crate::interrupt::typelevel::Interrupt; use crate::interrupt::{self}; use crate::pac::radio::vals; -use crate::Peripheral; +use crate::Peri; /// Default (IEEE compliant) Start of Frame Delimiter pub const DEFAULT_SFD: u8 = 0xA7; @@ -33,18 +32,16 @@ pub enum Cca { /// IEEE 802.15.4 radio driver. pub struct Radio<'d, T: Instance> { - _p: PeripheralRef<'d, T>, + _p: Peri<'d, T>, needs_enable: bool, } impl<'d, T: Instance> Radio<'d, T> { /// Create a new IEEE 802.15.4 radio driver. pub fn new( - radio: impl Peripheral

+ 'd, + radio: Peri<'d, T>, _irq: impl interrupt::typelevel::Binding> + 'd, ) -> Self { - into_ref!(radio); - let r = T::regs(); // Disable and enable to reset peripheral diff --git a/embassy-nrf/src/radio/mod.rs b/embassy-nrf/src/radio/mod.rs index 251f37d3d..982436266 100644 --- a/embassy-nrf/src/radio/mod.rs +++ b/embassy-nrf/src/radio/mod.rs @@ -19,11 +19,12 @@ pub mod ieee802154; use core::marker::PhantomData; +use embassy_hal_internal::PeripheralType; use embassy_sync::waitqueue::AtomicWaker; use pac::radio::vals::State as RadioState; pub use pac::radio::vals::Txpower as TxPower; -use crate::{interrupt, pac, Peripheral}; +use crate::{interrupt, pac}; /// RADIO error. #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -94,7 +95,7 @@ macro_rules! impl_radio { /// Radio peripheral instance. #[allow(private_bounds)] -pub trait Instance: Peripheral

+ SealedInstance + 'static + Send { +pub trait Instance: SealedInstance + PeripheralType + 'static + Send { /// Interrupt for this peripheral. type Interrupt: interrupt::typelevel::Interrupt; } diff --git a/embassy-nrf/src/rng.rs b/embassy-nrf/src/rng.rs index 7a98ab2fb..e75ffda00 100644 --- a/embassy-nrf/src/rng.rs +++ b/embassy-nrf/src/rng.rs @@ -10,11 +10,11 @@ use core::task::Poll; use critical_section::{CriticalSection, Mutex}; use embassy_hal_internal::drop::OnDrop; -use embassy_hal_internal::{into_ref, PeripheralRef}; +use embassy_hal_internal::{Peri, PeripheralType}; use embassy_sync::waitqueue::WakerRegistration; use crate::interrupt::typelevel::Interrupt; -use crate::{interrupt, pac, Peripheral}; +use crate::{interrupt, pac}; /// Interrupt handler. pub struct InterruptHandler { @@ -56,7 +56,7 @@ impl interrupt::typelevel::Handler for InterruptHandl /// /// It has a non-blocking API, and a blocking api through `rand`. pub struct Rng<'d, T: Instance> { - _peri: PeripheralRef<'d, T>, + _peri: Peri<'d, T>, } impl<'d, T: Instance> Rng<'d, T> { @@ -67,11 +67,9 @@ impl<'d, T: Instance> Rng<'d, T> { /// /// The synchronous API is safe. pub fn new( - rng: impl Peripheral

+ 'd, + rng: Peri<'d, T>, _irq: impl interrupt::typelevel::Binding> + 'd, ) -> Self { - into_ref!(rng); - let this = Self { _peri: rng }; this.stop(); @@ -250,7 +248,7 @@ pub(crate) trait SealedInstance { /// RNG peripheral instance. #[allow(private_bounds)] -pub trait Instance: Peripheral

+ SealedInstance + 'static + Send { +pub trait Instance: SealedInstance + PeripheralType + 'static + Send { /// Interrupt for this peripheral. type Interrupt: interrupt::typelevel::Interrupt; } diff --git a/embassy-nrf/src/saadc.rs b/embassy-nrf/src/saadc.rs index 00e2b7402..92b6fb01f 100644 --- a/embassy-nrf/src/saadc.rs +++ b/embassy-nrf/src/saadc.rs @@ -3,11 +3,12 @@ #![macro_use] use core::future::poll_fn; +use core::marker::PhantomData; use core::sync::atomic::{compiler_fence, Ordering}; use core::task::Poll; use embassy_hal_internal::drop::OnDrop; -use embassy_hal_internal::{impl_peripheral, into_ref, PeripheralRef}; +use embassy_hal_internal::{impl_peripheral, Peri}; use embassy_sync::waitqueue::AtomicWaker; pub(crate) use vals::Psel as InputChannel; @@ -15,7 +16,7 @@ use crate::interrupt::InterruptExt; use crate::pac::saadc::vals; use crate::ppi::{ConfigurableChannel, Event, Ppi, Task}; use crate::timer::{Frequency, Instance as TimerInstance, Timer}; -use crate::{interrupt, pac, peripherals, Peripheral}; +use crate::{interrupt, pac, peripherals}; /// SAADC error #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -87,37 +88,32 @@ pub struct ChannelConfig<'d> { /// Acquisition time in microseconds. pub time: Time, /// Positive channel to sample - p_channel: PeripheralRef<'d, AnyInput>, + p_channel: AnyInput<'d>, /// An optional negative channel to sample - n_channel: Option>, + n_channel: Option>, } impl<'d> ChannelConfig<'d> { /// Default configuration for single ended channel sampling. - pub fn single_ended(input: impl Peripheral

+ 'd) -> Self { - into_ref!(input); + pub fn single_ended(input: impl Input + 'd) -> Self { Self { reference: Reference::INTERNAL, gain: Gain::GAIN1_6, resistor: Resistor::BYPASS, time: Time::_10US, - p_channel: input.map_into(), + p_channel: input.degrade_saadc(), n_channel: None, } } /// Default configuration for differential channel sampling. - pub fn differential( - p_input: impl Peripheral

+ 'd, - n_input: impl Peripheral

+ 'd, - ) -> Self { - into_ref!(p_input, n_input); + pub fn differential(p_input: impl Input + 'd, n_input: impl Input + 'd) -> Self { Self { reference: Reference::INTERNAL, gain: Gain::GAIN1_6, resistor: Resistor::BYPASS, time: Time::_10US, - p_channel: p_input.map_into(), - n_channel: Some(n_input.map_into()), + p_channel: p_input.degrade_saadc(), + n_channel: Some(n_input.degrade_saadc()), } } } @@ -133,19 +129,17 @@ pub enum CallbackResult { /// One-shot and continuous SAADC. pub struct Saadc<'d, const N: usize> { - _p: PeripheralRef<'d, peripherals::SAADC>, + _p: Peri<'d, peripherals::SAADC>, } impl<'d, const N: usize> Saadc<'d, N> { /// Create a new SAADC driver. pub fn new( - saadc: impl Peripheral

+ 'd, + saadc: Peri<'d, peripherals::SAADC>, _irq: impl interrupt::typelevel::Binding + 'd, config: Config, channel_configs: [ChannelConfig; N], ) -> Self { - into_ref!(saadc); - let r = pac::SAADC; let Config { resolution, oversample } = config; @@ -284,9 +278,9 @@ impl<'d, const N: usize> Saadc<'d, N> { pub async fn run_task_sampler( &mut self, - timer: &mut T, - ppi_ch1: &mut impl ConfigurableChannel, - ppi_ch2: &mut impl ConfigurableChannel, + timer: Peri<'_, T>, + ppi_ch1: Peri<'_, impl ConfigurableChannel>, + ppi_ch2: Peri<'_, impl ConfigurableChannel>, frequency: Frequency, sample_counter: u32, bufs: &mut [[[i16; N]; N0]; 2], @@ -655,14 +649,18 @@ pub(crate) trait SealedInput { /// An input that can be used as either or negative end of a ADC differential in the SAADC periperhal. #[allow(private_bounds)] -pub trait Input: SealedInput + Into + Peripheral

+ Sized + 'static { +pub trait Input: SealedInput + Sized { /// Convert this SAADC input to a type-erased `AnyInput`. /// /// This allows using several inputs in situations that might require /// them to be the same type, like putting them in an array. - fn degrade_saadc(self) -> AnyInput { + fn degrade_saadc<'a>(self) -> AnyInput<'a> + where + Self: 'a, + { AnyInput { channel: self.channel(), + _phantom: core::marker::PhantomData, } } } @@ -671,23 +669,36 @@ pub trait Input: SealedInput + Into + Peripheral

+ Sized + ' /// /// This allows using several inputs in situations that might require /// them to be the same type, like putting them in an array. -pub struct AnyInput { +pub struct AnyInput<'a> { channel: InputChannel, + _phantom: PhantomData<&'a ()>, } -impl_peripheral!(AnyInput); +impl<'a> AnyInput<'a> { + /// Reborrow into a "child" AnyInput. + /// + /// `self` will stay borrowed until the child AnyInput is dropped. + pub fn reborrow(&mut self) -> AnyInput<'_> { + // safety: we're returning the clone inside a new Peripheral that borrows + // self, so user code can't use both at the same time. + Self { + channel: self.channel, + _phantom: PhantomData, + } + } +} -impl SealedInput for AnyInput { +impl SealedInput for AnyInput<'_> { fn channel(&self) -> InputChannel { self.channel } } -impl Input for AnyInput {} +impl Input for AnyInput<'_> {} macro_rules! impl_saadc_input { ($pin:ident, $ch:ident) => { - impl_saadc_input!(@local, crate::peripherals::$pin, $ch); + impl_saadc_input!(@local, crate::Peri<'_, crate::peripherals::$pin>, $ch); }; (@local, $pin:ty, $ch:ident) => { impl crate::saadc::SealedInput for $pin { @@ -696,12 +707,6 @@ macro_rules! impl_saadc_input { } } impl crate::saadc::Input for $pin {} - - impl From<$pin> for crate::saadc::AnyInput { - fn from(val: $pin) -> Self { - crate::saadc::Input::degrade_saadc(val) - } - } }; } diff --git a/embassy-nrf/src/spim.rs b/embassy-nrf/src/spim.rs index bd193cfe8..59f5b6d58 100644 --- a/embassy-nrf/src/spim.rs +++ b/embassy-nrf/src/spim.rs @@ -10,7 +10,7 @@ use core::sync::atomic::{compiler_fence, Ordering}; use core::task::Poll; use embassy_embedded_hal::SetConfig; -use embassy_hal_internal::{into_ref, PeripheralRef}; +use embassy_hal_internal::{Peri, PeripheralType}; use embassy_sync::waitqueue::AtomicWaker; pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; pub use pac::spim::vals::{Frequency, Order as BitOrder}; @@ -21,7 +21,7 @@ use crate::interrupt::typelevel::Interrupt; use crate::pac::gpio::vals as gpiovals; use crate::pac::spim::vals; use crate::util::slice_in_ram_or; -use crate::{interrupt, pac, Peripheral}; +use crate::{interrupt, pac}; /// SPIM error #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -100,73 +100,61 @@ impl interrupt::typelevel::Handler for InterruptHandl /// SPIM driver. pub struct Spim<'d, T: Instance> { - _p: PeripheralRef<'d, T>, + _p: Peri<'d, T>, } impl<'d, T: Instance> Spim<'d, T> { /// Create a new SPIM driver. pub fn new( - spim: impl Peripheral

+ 'd, + spim: Peri<'d, T>, _irq: impl interrupt::typelevel::Binding> + 'd, - sck: impl Peripheral

+ 'd, - miso: impl Peripheral

+ 'd, - mosi: impl Peripheral

+ 'd, + sck: Peri<'d, impl GpioPin>, + miso: Peri<'d, impl GpioPin>, + mosi: Peri<'d, impl GpioPin>, config: Config, ) -> Self { - into_ref!(sck, miso, mosi); - Self::new_inner( - spim, - Some(sck.map_into()), - Some(miso.map_into()), - Some(mosi.map_into()), - config, - ) + Self::new_inner(spim, Some(sck.into()), Some(miso.into()), Some(mosi.into()), config) } /// Create a new SPIM driver, capable of TX only (MOSI only). pub fn new_txonly( - spim: impl Peripheral

+ 'd, + spim: Peri<'d, T>, _irq: impl interrupt::typelevel::Binding> + 'd, - sck: impl Peripheral

+ 'd, - mosi: impl Peripheral

+ 'd, + sck: Peri<'d, impl GpioPin>, + mosi: Peri<'d, impl GpioPin>, config: Config, ) -> Self { - into_ref!(sck, mosi); - Self::new_inner(spim, Some(sck.map_into()), None, Some(mosi.map_into()), config) + Self::new_inner(spim, Some(sck.into()), None, Some(mosi.into()), config) } /// Create a new SPIM driver, capable of RX only (MISO only). pub fn new_rxonly( - spim: impl Peripheral

+ 'd, + spim: Peri<'d, T>, _irq: impl interrupt::typelevel::Binding> + 'd, - sck: impl Peripheral

+ 'd, - miso: impl Peripheral

+ 'd, + sck: Peri<'d, impl GpioPin>, + miso: Peri<'d, impl GpioPin>, config: Config, ) -> Self { - into_ref!(sck, miso); - Self::new_inner(spim, Some(sck.map_into()), Some(miso.map_into()), None, config) + Self::new_inner(spim, Some(sck.into()), Some(miso.into()), None, config) } /// Create a new SPIM driver, capable of TX only (MOSI only), without SCK pin. pub fn new_txonly_nosck( - spim: impl Peripheral

+ 'd, + spim: Peri<'d, T>, _irq: impl interrupt::typelevel::Binding> + 'd, - mosi: impl Peripheral

+ 'd, + mosi: Peri<'d, impl GpioPin>, config: Config, ) -> Self { - into_ref!(mosi); - Self::new_inner(spim, None, None, Some(mosi.map_into()), config) + Self::new_inner(spim, None, None, Some(mosi.into()), config) } fn new_inner( - spim: impl Peripheral

+ 'd, - sck: Option>, - miso: Option>, - mosi: Option>, + spim: Peri<'d, T>, + sck: Option>, + miso: Option>, + mosi: Option>, config: Config, ) -> Self { - into_ref!(spim); - let r = T::regs(); // Configure pins @@ -511,7 +499,7 @@ pub(crate) trait SealedInstance { /// SPIM peripheral instance #[allow(private_bounds)] -pub trait Instance: Peripheral

+ SealedInstance + 'static { +pub trait Instance: SealedInstance + PeripheralType + 'static { /// Interrupt for this peripheral. type Interrupt: interrupt::typelevel::Interrupt; } diff --git a/embassy-nrf/src/spis.rs b/embassy-nrf/src/spis.rs index 88230fa26..2a3928d25 100644 --- a/embassy-nrf/src/spis.rs +++ b/embassy-nrf/src/spis.rs @@ -7,7 +7,7 @@ use core::sync::atomic::{compiler_fence, Ordering}; use core::task::Poll; use embassy_embedded_hal::SetConfig; -use embassy_hal_internal::{into_ref, PeripheralRef}; +use embassy_hal_internal::{Peri, PeripheralType}; use embassy_sync::waitqueue::AtomicWaker; pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; pub use pac::spis::vals::Order as BitOrder; @@ -18,7 +18,7 @@ use crate::interrupt::typelevel::Interrupt; use crate::pac::gpio::vals as gpiovals; use crate::pac::spis::vals; use crate::util::slice_in_ram_or; -use crate::{interrupt, pac, Peripheral}; +use crate::{interrupt, pac}; /// SPIS error #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -98,95 +98,75 @@ impl interrupt::typelevel::Handler for InterruptHandl /// SPIS driver. pub struct Spis<'d, T: Instance> { - _p: PeripheralRef<'d, T>, + _p: Peri<'d, T>, } impl<'d, T: Instance> Spis<'d, T> { /// Create a new SPIS driver. pub fn new( - spis: impl Peripheral

+ 'd, + spis: Peri<'d, T>, _irq: impl interrupt::typelevel::Binding> + 'd, - cs: impl Peripheral

+ 'd, - sck: impl Peripheral

+ 'd, - miso: impl Peripheral

+ 'd, - mosi: impl Peripheral

+ 'd, + cs: Peri<'d, impl GpioPin>, + sck: Peri<'d, impl GpioPin>, + miso: Peri<'d, impl GpioPin>, + mosi: Peri<'d, impl GpioPin>, config: Config, ) -> Self { - into_ref!(cs, sck, miso, mosi); Self::new_inner( spis, - cs.map_into(), - Some(sck.map_into()), - Some(miso.map_into()), - Some(mosi.map_into()), + cs.into(), + Some(sck.into()), + Some(miso.into()), + Some(mosi.into()), config, ) } /// Create a new SPIS driver, capable of TX only (MISO only). pub fn new_txonly( - spis: impl Peripheral

+ 'd, + spis: Peri<'d, T>, _irq: impl interrupt::typelevel::Binding> + 'd, - cs: impl Peripheral

+ 'd, - sck: impl Peripheral

+ 'd, - miso: impl Peripheral

+ 'd, + cs: Peri<'d, impl GpioPin>, + sck: Peri<'d, impl GpioPin>, + miso: Peri<'d, impl GpioPin>, config: Config, ) -> Self { - into_ref!(cs, sck, miso); - Self::new_inner( - spis, - cs.map_into(), - Some(sck.map_into()), - Some(miso.map_into()), - None, - config, - ) + Self::new_inner(spis, cs.into(), Some(sck.into()), Some(miso.into()), None, config) } /// Create a new SPIS driver, capable of RX only (MOSI only). pub fn new_rxonly( - spis: impl Peripheral

+ 'd, + spis: Peri<'d, T>, _irq: impl interrupt::typelevel::Binding> + 'd, - cs: impl Peripheral

+ 'd, - sck: impl Peripheral

+ 'd, - mosi: impl Peripheral

+ 'd, + cs: Peri<'d, impl GpioPin>, + sck: Peri<'d, impl GpioPin>, + mosi: Peri<'d, impl GpioPin>, config: Config, ) -> Self { - into_ref!(cs, sck, mosi); - Self::new_inner( - spis, - cs.map_into(), - Some(sck.map_into()), - None, - Some(mosi.map_into()), - config, - ) + Self::new_inner(spis, cs.into(), Some(sck.into()), None, Some(mosi.into()), config) } /// Create a new SPIS driver, capable of TX only (MISO only) without SCK pin. pub fn new_txonly_nosck( - spis: impl Peripheral

+ 'd, + spis: Peri<'d, T>, _irq: impl interrupt::typelevel::Binding> + 'd, - cs: impl Peripheral

+ 'd, - miso: impl Peripheral

+ 'd, + cs: Peri<'d, impl GpioPin>, + miso: Peri<'d, impl GpioPin>, config: Config, ) -> Self { - into_ref!(cs, miso); - Self::new_inner(spis, cs.map_into(), None, Some(miso.map_into()), None, config) + Self::new_inner(spis, cs.into(), None, Some(miso.into()), None, config) } fn new_inner( - spis: impl Peripheral

+ 'd, - cs: PeripheralRef<'d, AnyPin>, - sck: Option>, - miso: Option>, - mosi: Option>, + spis: Peri<'d, T>, + cs: Peri<'d, AnyPin>, + sck: Option>, + miso: Option>, + mosi: Option>, config: Config, ) -> Self { compiler_fence(Ordering::SeqCst); - into_ref!(spis, cs); - let r = T::regs(); // Configure pins. @@ -485,7 +465,7 @@ pub(crate) trait SealedInstance { /// SPIS peripheral instance #[allow(private_bounds)] -pub trait Instance: Peripheral

+ SealedInstance + 'static { +pub trait Instance: SealedInstance + PeripheralType + 'static { /// Interrupt for this peripheral. type Interrupt: interrupt::typelevel::Interrupt; } diff --git a/embassy-nrf/src/temp.rs b/embassy-nrf/src/temp.rs index 1488c5c24..44be0f6d1 100644 --- a/embassy-nrf/src/temp.rs +++ b/embassy-nrf/src/temp.rs @@ -4,13 +4,12 @@ use core::future::poll_fn; use core::task::Poll; use embassy_hal_internal::drop::OnDrop; -use embassy_hal_internal::{into_ref, PeripheralRef}; use embassy_sync::waitqueue::AtomicWaker; use fixed::types::I30F2; use crate::interrupt::InterruptExt; use crate::peripherals::TEMP; -use crate::{interrupt, pac, Peripheral}; +use crate::{interrupt, pac, Peri}; /// Interrupt handler. pub struct InterruptHandler { @@ -27,7 +26,7 @@ impl interrupt::typelevel::Handler for InterruptHand /// Builtin temperature sensor driver. pub struct Temp<'d> { - _peri: PeripheralRef<'d, TEMP>, + _peri: Peri<'d, TEMP>, } static WAKER: AtomicWaker = AtomicWaker::new(); @@ -35,11 +34,9 @@ static WAKER: AtomicWaker = AtomicWaker::new(); impl<'d> Temp<'d> { /// Create a new temperature sensor driver. pub fn new( - _peri: impl Peripheral

+ 'd, + _peri: Peri<'d, TEMP>, _irq: impl interrupt::typelevel::Binding + 'd, ) -> Self { - into_ref!(_peri); - // Enable interrupt that signals temperature values interrupt::TEMP.unpend(); unsafe { interrupt::TEMP.enable() }; diff --git a/embassy-nrf/src/timer.rs b/embassy-nrf/src/timer.rs index a9aeb40fa..5b58b0a50 100644 --- a/embassy-nrf/src/timer.rs +++ b/embassy-nrf/src/timer.rs @@ -6,11 +6,11 @@ #![macro_use] -use embassy_hal_internal::{into_ref, PeripheralRef}; +use embassy_hal_internal::{Peri, PeripheralType}; +use crate::pac; use crate::pac::timer::vals; use crate::ppi::{Event, Task}; -use crate::{pac, Peripheral}; pub(crate) trait SealedInstance { /// The number of CC registers this instance has. @@ -20,7 +20,7 @@ pub(crate) trait SealedInstance { /// Basic Timer instance. #[allow(private_bounds)] -pub trait Instance: Peripheral

+ SealedInstance + 'static + Send { +pub trait Instance: SealedInstance + PeripheralType + 'static + Send { /// Interrupt for this peripheral. type Interrupt: crate::interrupt::typelevel::Interrupt; } @@ -84,7 +84,7 @@ pub enum Frequency { /// Timer driver. pub struct Timer<'d, T: Instance> { - _p: PeripheralRef<'d, T>, + _p: Peri<'d, T>, } impl<'d, T: Instance> Timer<'d, T> { @@ -92,7 +92,7 @@ impl<'d, T: Instance> Timer<'d, T> { /// /// This can be useful for triggering tasks via PPI /// `Uarte` uses this internally. - pub fn new(timer: impl Peripheral

+ 'd) -> Self { + pub fn new(timer: Peri<'d, T>) -> Self { Self::new_inner(timer, false) } @@ -100,13 +100,11 @@ impl<'d, T: Instance> Timer<'d, T> { /// /// This can be useful for triggering tasks via PPI /// `Uarte` uses this internally. - pub fn new_counter(timer: impl Peripheral

+ 'd) -> Self { + pub fn new_counter(timer: Peri<'d, T>) -> Self { Self::new_inner(timer, true) } - fn new_inner(timer: impl Peripheral

+ 'd, _is_counter: bool) -> Self { - into_ref!(timer); - + fn new_inner(timer: Peri<'d, T>, _is_counter: bool) -> Self { let regs = T::regs(); let this = Self { _p: timer }; @@ -229,7 +227,7 @@ impl<'d, T: Instance> Timer<'d, T> { /// When the register's CAPTURE task is triggered, the timer will store the current value of its counter in the register pub struct Cc<'d, T: Instance> { n: usize, - _p: PeripheralRef<'d, T>, + _p: Peri<'d, T>, } impl<'d, T: Instance> Cc<'d, T> { diff --git a/embassy-nrf/src/twim.rs b/embassy-nrf/src/twim.rs index bfce00f1b..083b54b99 100644 --- a/embassy-nrf/src/twim.rs +++ b/embassy-nrf/src/twim.rs @@ -10,7 +10,7 @@ use core::sync::atomic::Ordering::SeqCst; use core::task::Poll; use embassy_embedded_hal::SetConfig; -use embassy_hal_internal::{into_ref, PeripheralRef}; +use embassy_hal_internal::{Peri, PeripheralType}; use embassy_sync::waitqueue::AtomicWaker; #[cfg(feature = "time")] use embassy_time::{Duration, Instant}; @@ -23,7 +23,7 @@ use crate::interrupt::typelevel::Interrupt; use crate::pac::gpio::vals as gpiovals; use crate::pac::twim::vals; use crate::util::slice_in_ram; -use crate::{gpio, interrupt, pac, Peripheral}; +use crate::{gpio, interrupt, pac}; /// TWIM config. #[non_exhaustive] @@ -114,20 +114,18 @@ impl interrupt::typelevel::Handler for InterruptHandl /// TWI driver. pub struct Twim<'d, T: Instance> { - _p: PeripheralRef<'d, T>, + _p: Peri<'d, T>, } impl<'d, T: Instance> Twim<'d, T> { /// Create a new TWI driver. pub fn new( - twim: impl Peripheral

+ 'd, + twim: Peri<'d, T>, _irq: impl interrupt::typelevel::Binding> + 'd, - sda: impl Peripheral

+ 'd, - scl: impl Peripheral

+ 'd, + sda: Peri<'d, impl GpioPin>, + scl: Peri<'d, impl GpioPin>, config: Config, ) -> Self { - into_ref!(twim, sda, scl); - let r = T::regs(); // Configure pins @@ -847,7 +845,7 @@ pub(crate) trait SealedInstance { /// TWIM peripheral instance. #[allow(private_bounds)] -pub trait Instance: Peripheral

+ SealedInstance + 'static { +pub trait Instance: SealedInstance + PeripheralType + 'static { /// Interrupt for this peripheral. type Interrupt: interrupt::typelevel::Interrupt; } diff --git a/embassy-nrf/src/twis.rs b/embassy-nrf/src/twis.rs index 60de2ed9d..3e4d537ae 100644 --- a/embassy-nrf/src/twis.rs +++ b/embassy-nrf/src/twis.rs @@ -8,7 +8,7 @@ use core::sync::atomic::compiler_fence; use core::sync::atomic::Ordering::SeqCst; use core::task::Poll; -use embassy_hal_internal::{into_ref, PeripheralRef}; +use embassy_hal_internal::{Peri, PeripheralType}; use embassy_sync::waitqueue::AtomicWaker; #[cfg(feature = "time")] use embassy_time::{Duration, Instant}; @@ -19,7 +19,7 @@ use crate::interrupt::typelevel::Interrupt; use crate::pac::gpio::vals as gpiovals; use crate::pac::twis::vals; use crate::util::slice_in_ram_or; -use crate::{gpio, interrupt, pac, Peripheral}; +use crate::{gpio, interrupt, pac}; /// TWIS config. #[non_exhaustive] @@ -141,20 +141,18 @@ impl interrupt::typelevel::Handler for InterruptHandl /// TWIS driver. pub struct Twis<'d, T: Instance> { - _p: PeripheralRef<'d, T>, + _p: Peri<'d, T>, } impl<'d, T: Instance> Twis<'d, T> { /// Create a new TWIS driver. pub fn new( - twis: impl Peripheral

+ 'd, + twis: Peri<'d, T>, _irq: impl interrupt::typelevel::Binding> + 'd, - sda: impl Peripheral

+ 'd, - scl: impl Peripheral

+ 'd, + sda: Peri<'d, impl GpioPin>, + scl: Peri<'d, impl GpioPin>, config: Config, ) -> Self { - into_ref!(twis, sda, scl); - let r = T::regs(); // Configure pins @@ -791,7 +789,7 @@ pub(crate) trait SealedInstance { /// TWIS peripheral instance. #[allow(private_bounds)] -pub trait Instance: Peripheral

+ SealedInstance + 'static { +pub trait Instance: SealedInstance + PeripheralType + 'static { /// Interrupt for this peripheral. type Interrupt: interrupt::typelevel::Interrupt; } diff --git a/embassy-nrf/src/uarte.rs b/embassy-nrf/src/uarte.rs index ebb4dd941..b44edfe84 100644 --- a/embassy-nrf/src/uarte.rs +++ b/embassy-nrf/src/uarte.rs @@ -19,7 +19,7 @@ use core::sync::atomic::{compiler_fence, AtomicU8, Ordering}; use core::task::Poll; use embassy_hal_internal::drop::OnDrop; -use embassy_hal_internal::{into_ref, PeripheralRef}; +use embassy_hal_internal::{Peri, PeripheralType}; use embassy_sync::waitqueue::AtomicWaker; // Re-export SVD variants to allow user to directly set values. pub use pac::uarte::vals::{Baudrate, ConfigParity as Parity}; @@ -32,7 +32,7 @@ use crate::pac::uarte::vals; use crate::ppi::{AnyConfigurableChannel, ConfigurableChannel, Event, Ppi, Task}; use crate::timer::{Frequency, Instance as TimerInstance, Timer}; use crate::util::slice_in_ram_or; -use crate::{interrupt, pac, Peripheral}; +use crate::{interrupt, pac}; /// UARTE config. #[derive(Clone)] @@ -141,56 +141,54 @@ pub struct Uarte<'d, T: Instance> { /// /// This can be obtained via [`Uarte::split`], or created directly. pub struct UarteTx<'d, T: Instance> { - _p: PeripheralRef<'d, T>, + _p: Peri<'d, T>, } /// Receiver part of the UARTE driver. /// /// This can be obtained via [`Uarte::split`], or created directly. pub struct UarteRx<'d, T: Instance> { - _p: PeripheralRef<'d, T>, + _p: Peri<'d, T>, } impl<'d, T: Instance> Uarte<'d, T> { /// Create a new UARTE without hardware flow control pub fn new( - uarte: impl Peripheral

+ 'd, + uarte: Peri<'d, T>, _irq: impl interrupt::typelevel::Binding> + 'd, - rxd: impl Peripheral

+ 'd, - txd: impl Peripheral

+ 'd, + rxd: Peri<'d, impl GpioPin>, + txd: Peri<'d, impl GpioPin>, config: Config, ) -> Self { - into_ref!(uarte, rxd, txd); - Self::new_inner(uarte, rxd.map_into(), txd.map_into(), None, None, config) + Self::new_inner(uarte, rxd.into(), txd.into(), None, None, config) } /// Create a new UARTE with hardware flow control (RTS/CTS) pub fn new_with_rtscts( - uarte: impl Peripheral

+ 'd, + uarte: Peri<'d, T>, _irq: impl interrupt::typelevel::Binding> + 'd, - rxd: impl Peripheral

+ 'd, - txd: impl Peripheral

+ 'd, - cts: impl Peripheral

+ 'd, - rts: impl Peripheral

+ 'd, + rxd: Peri<'d, impl GpioPin>, + txd: Peri<'d, impl GpioPin>, + cts: Peri<'d, impl GpioPin>, + rts: Peri<'d, impl GpioPin>, config: Config, ) -> Self { - into_ref!(uarte, rxd, txd, cts, rts); Self::new_inner( uarte, - rxd.map_into(), - txd.map_into(), - Some(cts.map_into()), - Some(rts.map_into()), + rxd.into(), + txd.into(), + Some(cts.into()), + Some(rts.into()), config, ) } fn new_inner( - uarte: PeripheralRef<'d, T>, - rxd: PeripheralRef<'d, AnyPin>, - txd: PeripheralRef<'d, AnyPin>, - cts: Option>, - rts: Option>, + uarte: Peri<'d, T>, + rxd: Peri<'d, AnyPin>, + txd: Peri<'d, AnyPin>, + cts: Option>, + rts: Option>, config: Config, ) -> Self { let r = T::regs(); @@ -239,9 +237,9 @@ impl<'d, T: Instance> Uarte<'d, T> { /// This is useful to concurrently transmit and receive from independent tasks. pub fn split_with_idle( self, - timer: impl Peripheral

+ 'd, - ppi_ch1: impl Peripheral

+ 'd, - ppi_ch2: impl Peripheral

+ 'd, + timer: Peri<'d, U>, + ppi_ch1: Peri<'d, impl ConfigurableChannel + 'd>, + ppi_ch2: Peri<'d, impl ConfigurableChannel + 'd>, ) -> (UarteTx<'d, T>, UarteRxWithIdle<'d, T, U>) { (self.tx, self.rx.with_idle(timer, ppi_ch1, ppi_ch2)) } @@ -283,11 +281,7 @@ impl<'d, T: Instance> Uarte<'d, T> { } } -pub(crate) fn configure_tx_pins( - r: pac::uarte::Uarte, - txd: PeripheralRef<'_, AnyPin>, - cts: Option>, -) { +pub(crate) fn configure_tx_pins(r: pac::uarte::Uarte, txd: Peri<'_, AnyPin>, cts: Option>) { txd.set_high(); txd.conf().write(|w| { w.set_dir(gpiovals::Dir::OUTPUT); @@ -306,11 +300,7 @@ pub(crate) fn configure_tx_pins( r.psel().cts().write_value(cts.psel_bits()); } -pub(crate) fn configure_rx_pins( - r: pac::uarte::Uarte, - rxd: PeripheralRef<'_, AnyPin>, - rts: Option>, -) { +pub(crate) fn configure_rx_pins(r: pac::uarte::Uarte, rxd: Peri<'_, AnyPin>, rts: Option>) { rxd.conf().write(|w| { w.set_dir(gpiovals::Dir::INPUT); w.set_input(gpiovals::Input::CONNECT); @@ -356,33 +346,26 @@ pub(crate) fn configure(r: pac::uarte::Uarte, config: Config, hardware_flow_cont impl<'d, T: Instance> UarteTx<'d, T> { /// Create a new tx-only UARTE without hardware flow control pub fn new( - uarte: impl Peripheral

+ 'd, + uarte: Peri<'d, T>, _irq: impl interrupt::typelevel::Binding> + 'd, - txd: impl Peripheral

+ 'd, + txd: Peri<'d, impl GpioPin>, config: Config, ) -> Self { - into_ref!(uarte, txd); - Self::new_inner(uarte, txd.map_into(), None, config) + Self::new_inner(uarte, txd.into(), None, config) } /// Create a new tx-only UARTE with hardware flow control (RTS/CTS) pub fn new_with_rtscts( - uarte: impl Peripheral

+ 'd, + uarte: Peri<'d, T>, _irq: impl interrupt::typelevel::Binding> + 'd, - txd: impl Peripheral

+ 'd, - cts: impl Peripheral

+ 'd, + txd: Peri<'d, impl GpioPin>, + cts: Peri<'d, impl GpioPin>, config: Config, ) -> Self { - into_ref!(uarte, txd, cts); - Self::new_inner(uarte, txd.map_into(), Some(cts.map_into()), config) + Self::new_inner(uarte, txd.into(), Some(cts.into()), config) } - fn new_inner( - uarte: PeripheralRef<'d, T>, - txd: PeripheralRef<'d, AnyPin>, - cts: Option>, - config: Config, - ) -> Self { + fn new_inner(uarte: Peri<'d, T>, txd: Peri<'d, AnyPin>, cts: Option>, config: Config) -> Self { let r = T::regs(); configure(r, config, cts.is_some()); @@ -539,25 +522,23 @@ impl<'a, T: Instance> Drop for UarteTx<'a, T> { impl<'d, T: Instance> UarteRx<'d, T> { /// Create a new rx-only UARTE without hardware flow control pub fn new( - uarte: impl Peripheral

+ 'd, + uarte: Peri<'d, T>, _irq: impl interrupt::typelevel::Binding> + 'd, - rxd: impl Peripheral

+ 'd, + rxd: Peri<'d, impl GpioPin>, config: Config, ) -> Self { - into_ref!(uarte, rxd); - Self::new_inner(uarte, rxd.map_into(), None, config) + Self::new_inner(uarte, rxd.into(), None, config) } /// Create a new rx-only UARTE with hardware flow control (RTS/CTS) pub fn new_with_rtscts( - uarte: impl Peripheral

+ 'd, + uarte: Peri<'d, T>, _irq: impl interrupt::typelevel::Binding> + 'd, - rxd: impl Peripheral

+ 'd, - rts: impl Peripheral

+ 'd, + rxd: Peri<'d, impl GpioPin>, + rts: Peri<'d, impl GpioPin>, config: Config, ) -> Self { - into_ref!(uarte, rxd, rts); - Self::new_inner(uarte, rxd.map_into(), Some(rts.map_into()), config) + Self::new_inner(uarte, rxd.into(), Some(rts.into()), config) } /// Check for errors and clear the error register if an error occured. @@ -568,12 +549,7 @@ impl<'d, T: Instance> UarteRx<'d, T> { ErrorSource::from_bits_truncate(err_bits.0).check() } - fn new_inner( - uarte: PeripheralRef<'d, T>, - rxd: PeripheralRef<'d, AnyPin>, - rts: Option>, - config: Config, - ) -> Self { + fn new_inner(uarte: Peri<'d, T>, rxd: Peri<'d, AnyPin>, rts: Option>, config: Config) -> Self { let r = T::regs(); configure(r, config, rts.is_some()); @@ -592,14 +568,12 @@ impl<'d, T: Instance> UarteRx<'d, T> { /// Upgrade to an instance that supports idle line detection. pub fn with_idle( self, - timer: impl Peripheral

+ 'd, - ppi_ch1: impl Peripheral

+ 'd, - ppi_ch2: impl Peripheral

+ 'd, + timer: Peri<'d, U>, + ppi_ch1: Peri<'d, impl ConfigurableChannel + 'd>, + ppi_ch2: Peri<'d, impl ConfigurableChannel + 'd>, ) -> UarteRxWithIdle<'d, T, U> { let timer = Timer::new(timer); - into_ref!(ppi_ch1, ppi_ch2); - let r = T::regs(); // BAUDRATE register values are `baudrate * 2^32 / 16000000` @@ -617,7 +591,7 @@ impl<'d, T: Instance> UarteRx<'d, T> { timer.cc(0).short_compare_stop(); let mut ppi_ch1 = Ppi::new_one_to_two( - ppi_ch1.map_into(), + ppi_ch1.into(), Event::from_reg(r.events_rxdrdy()), timer.task_clear(), timer.task_start(), @@ -625,7 +599,7 @@ impl<'d, T: Instance> UarteRx<'d, T> { ppi_ch1.enable(); let mut ppi_ch2 = Ppi::new_one_to_one( - ppi_ch2.map_into(), + ppi_ch2.into(), timer.cc(0).event_compare(), Task::from_reg(r.tasks_stoprx()), ); @@ -992,7 +966,7 @@ pub(crate) trait SealedInstance { /// UARTE peripheral instance. #[allow(private_bounds)] -pub trait Instance: Peripheral

+ SealedInstance + 'static + Send { +pub trait Instance: SealedInstance + PeripheralType + 'static + Send { /// Interrupt for this peripheral. type Interrupt: interrupt::typelevel::Interrupt; } diff --git a/embassy-nrf/src/usb/mod.rs b/embassy-nrf/src/usb/mod.rs index 06dae694b..6cc1b0111 100644 --- a/embassy-nrf/src/usb/mod.rs +++ b/embassy-nrf/src/usb/mod.rs @@ -11,7 +11,7 @@ use core::sync::atomic::{compiler_fence, AtomicU32, Ordering}; use core::task::Poll; use cortex_m::peripheral::NVIC; -use embassy_hal_internal::{into_ref, PeripheralRef}; +use embassy_hal_internal::{Peri, PeripheralType}; use embassy_sync::waitqueue::AtomicWaker; use embassy_usb_driver as driver; use embassy_usb_driver::{Direction, EndpointAddress, EndpointError, EndpointInfo, EndpointType, Event, Unsupported}; @@ -20,7 +20,7 @@ use self::vbus_detect::VbusDetect; use crate::interrupt::typelevel::Interrupt; use crate::pac::usbd::vals; use crate::util::slice_in_ram; -use crate::{interrupt, pac, Peripheral}; +use crate::{interrupt, pac}; static BUS_WAKER: AtomicWaker = AtomicWaker::new(); static EP0_WAKER: AtomicWaker = AtomicWaker::new(); @@ -87,7 +87,7 @@ impl interrupt::typelevel::Handler for InterruptHandl /// USB driver. pub struct Driver<'d, T: Instance, V: VbusDetect> { - _p: PeripheralRef<'d, T>, + _p: Peri<'d, T>, alloc_in: Allocator, alloc_out: Allocator, vbus_detect: V, @@ -96,12 +96,10 @@ pub struct Driver<'d, T: Instance, V: VbusDetect> { impl<'d, T: Instance, V: VbusDetect> Driver<'d, T, V> { /// Create a new USB driver. pub fn new( - usb: impl Peripheral

+ 'd, + usb: Peri<'d, T>, _irq: impl interrupt::typelevel::Binding> + 'd, vbus_detect: V, ) -> Self { - into_ref!(usb); - T::Interrupt::unpend(); unsafe { T::Interrupt::enable() }; @@ -169,7 +167,7 @@ impl<'d, T: Instance, V: VbusDetect + 'd> driver::Driver<'d> for Driver<'d, T, V /// USB bus. pub struct Bus<'d, T: Instance, V: VbusDetect> { - _p: PeripheralRef<'d, T>, + _p: Peri<'d, T>, power_available: bool, vbus_detect: V, } @@ -592,7 +590,7 @@ impl<'d, T: Instance> driver::EndpointIn for Endpoint<'d, T, In> { /// USB control pipe. pub struct ControlPipe<'d, T: Instance> { - _p: PeripheralRef<'d, T>, + _p: Peri<'d, T>, max_packet_size: u16, } @@ -779,7 +777,7 @@ pub(crate) trait SealedInstance { /// USB peripheral instance. #[allow(private_bounds)] -pub trait Instance: Peripheral

+ SealedInstance + 'static + Send { +pub trait Instance: SealedInstance + PeripheralType + 'static + Send { /// Interrupt for this peripheral. type Interrupt: interrupt::typelevel::Interrupt; } diff --git a/embassy-nrf/src/wdt.rs b/embassy-nrf/src/wdt.rs index f7812258c..11cfa398e 100644 --- a/embassy-nrf/src/wdt.rs +++ b/embassy-nrf/src/wdt.rs @@ -3,9 +3,11 @@ //! This HAL implements a basic watchdog timer with 1..=8 handles. //! Once the watchdog has been started, it cannot be stopped. +use core::marker::PhantomData; + use crate::pac::wdt::vals; pub use crate::pac::wdt::vals::{Halt as HaltConfig, Sleep as SleepConfig}; -use crate::peripherals; +use crate::{peripherals, Peri}; const MIN_TICKS: u32 = 15; @@ -61,7 +63,7 @@ impl Default for Config { /// Watchdog driver. pub struct Watchdog { - _private: (), + _wdt: Peri<'static, peripherals::WDT>, } impl Watchdog { @@ -74,9 +76,9 @@ impl Watchdog { /// `N` must be between 1 and 8, inclusive. #[inline] pub fn try_new( - wdt: peripherals::WDT, + wdt: Peri<'static, peripherals::WDT>, config: Config, - ) -> Result<(Self, [WatchdogHandle; N]), peripherals::WDT> { + ) -> Result<(Self, [WatchdogHandle; N]), Peri<'static, peripherals::WDT>> { assert!(N >= 1 && N <= 8); let r = crate::pac::WDT; @@ -110,11 +112,19 @@ impl Watchdog { r.tasks_start().write_value(1); } - let this = Self { _private: () }; + let this = Self { _wdt: wdt }; - let mut handles = [const { WatchdogHandle { index: 0 } }; N]; + let mut handles = [const { + WatchdogHandle { + _wdt: PhantomData, + index: 0, + } + }; N]; for i in 0..N { - handles[i] = WatchdogHandle { index: i as u8 }; + handles[i] = WatchdogHandle { + _wdt: PhantomData, + index: i as u8, + }; handles[i].pet(); } @@ -155,6 +165,7 @@ impl Watchdog { /// Watchdog handle. pub struct WatchdogHandle { + _wdt: PhantomData>, index: u8, } @@ -183,6 +194,9 @@ impl WatchdogHandle { /// Watchdog must be initialized and `index` must be between `0` and `N-1` /// where `N` is the handle count when initializing. pub unsafe fn steal(index: u8) -> Self { - Self { index } + Self { + _wdt: PhantomData, + index, + } } } diff --git a/embassy-nxp/src/gpio.rs b/embassy-nxp/src/gpio.rs index d5d04ee69..c7c78ce61 100644 --- a/embassy-nxp/src/gpio.rs +++ b/embassy-nxp/src/gpio.rs @@ -1,7 +1,7 @@ -use embassy_hal_internal::impl_peripheral; +use embassy_hal_internal::{impl_peripheral, PeripheralType}; use crate::pac_utils::*; -use crate::{peripherals, Peripheral, PeripheralRef}; +use crate::{peripherals, Peri}; pub(crate) fn init() { // Enable clocks for GPIO, PINT, and IOCON @@ -45,7 +45,7 @@ pub struct Output<'d> { impl<'d> Output<'d> { /// Create GPIO output driver for a [Pin] with the provided [initial output](Level). #[inline] - pub fn new(pin: impl Peripheral

+ 'd, initial_output: Level) -> Self { + pub fn new(pin: Peri<'d, impl Pin>, initial_output: Level) -> Self { let mut pin = Flex::new(pin); pin.set_as_output(); let mut result = Self { pin }; @@ -90,7 +90,7 @@ pub struct Input<'d> { impl<'d> Input<'d> { /// Create GPIO output driver for a [Pin] with the provided [Pull]. #[inline] - pub fn new(pin: impl Peripheral

+ 'd, pull: Pull) -> Self { + pub fn new(pin: Peri<'d, impl Pin>, pull: Pull) -> Self { let mut pin = Flex::new(pin); pin.set_as_input(); let mut result = Self { pin }; @@ -124,7 +124,7 @@ impl<'d> Input<'d> { /// A flexible GPIO (digital mode) pin whose mode is not yet determined. Under the hood, this is a /// reference to a type-erased pin called ["AnyPin"](AnyPin). pub struct Flex<'d> { - pub(crate) pin: PeripheralRef<'d, AnyPin>, + pub(crate) pin: Peri<'d, AnyPin>, } impl<'d> Flex<'d> { @@ -132,10 +132,8 @@ impl<'d> Flex<'d> { /// /// Note: you cannot assume that the pin will be in Digital mode after this call. #[inline] - pub fn new(pin: impl Peripheral

+ 'd) -> Self { - Self { - pin: pin.into_ref().map_into(), - } + pub fn new(pin: Peri<'d, impl Pin>) -> Self { + Self { pin: pin.into() } } /// Get the bank of this pin. See also [Bank]. @@ -218,15 +216,7 @@ pub(crate) trait SealedPin: Sized { /// [AnyPin]. By default, this trait is sealed and cannot be implemented outside of the /// `embassy-nxp` crate due to the [SealedPin] trait. #[allow(private_bounds)] -pub trait Pin: Peripheral

+ Into + SealedPin + Sized + 'static { - /// Degrade to a generic pin struct - fn degrade(self) -> AnyPin { - AnyPin { - pin_bank: self.pin_bank(), - pin_number: self.pin_number(), - } - } - +pub trait Pin: PeripheralType + Into + SealedPin + Sized + 'static { /// Returns the pin number within a bank #[inline] fn pin(&self) -> u8 { @@ -252,8 +242,8 @@ impl AnyPin { /// # Safety /// /// You must ensure that you’re only using one instance of this type at a time. - pub unsafe fn steal(pin_bank: Bank, pin_number: u8) -> Self { - Self { pin_bank, pin_number } + pub unsafe fn steal(pin_bank: Bank, pin_number: u8) -> Peri<'static, Self> { + Peri::new_unchecked(Self { pin_bank, pin_number }) } } @@ -289,7 +279,10 @@ macro_rules! impl_pin { impl From for crate::gpio::AnyPin { fn from(val: peripherals::$name) -> Self { - crate::gpio::Pin::degrade(val) + Self { + pin_bank: val.pin_bank(), + pin_number: val.pin_number(), + } } } }; diff --git a/embassy-nxp/src/lib.rs b/embassy-nxp/src/lib.rs index 80fdecb2e..ad2056c06 100644 --- a/embassy-nxp/src/lib.rs +++ b/embassy-nxp/src/lib.rs @@ -4,7 +4,7 @@ pub mod gpio; mod pac_utils; pub mod pint; -pub use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; +pub use embassy_hal_internal::Peri; pub use lpc55_pac as pac; /// Initialize the `embassy-nxp` HAL with the provided configuration. diff --git a/embassy-nxp/src/pint.rs b/embassy-nxp/src/pint.rs index 809be4bff..8d6dc1277 100644 --- a/embassy-nxp/src/pint.rs +++ b/embassy-nxp/src/pint.rs @@ -5,12 +5,12 @@ use core::pin::Pin as FuturePin; use core::task::{Context, Poll}; use critical_section::Mutex; -use embassy_hal_internal::{Peripheral, PeripheralRef}; use embassy_sync::waitqueue::AtomicWaker; use crate::gpio::{self, AnyPin, Level, SealedPin}; use crate::pac::interrupt; use crate::pac_utils::*; +use crate::Peri; struct PinInterrupt { assigned: bool, @@ -107,14 +107,14 @@ pub(crate) fn init() { #[must_use = "futures do nothing unless you `.await` or poll them"] struct InputFuture<'d> { #[allow(dead_code)] - pin: PeripheralRef<'d, AnyPin>, + pin: Peri<'d, AnyPin>, interrupt_number: usize, } impl<'d> InputFuture<'d> { /// Create a new input future. Returns None if all interrupts are in use. - fn new(pin: impl Peripheral

+ 'd, interrupt_on: InterruptOn) -> Option { - let pin = pin.into_ref().map_into(); + fn new(pin: Peri<'d, impl gpio::Pin>, interrupt_on: InterruptOn) -> Option { + let pin = pin.into(); let interrupt_number = next_available_interrupt()?; // Clear interrupt, just in case @@ -344,35 +344,35 @@ impl gpio::Flex<'_> { /// Wait for a falling or rising edge on the pin. You can have at most 8 pins waiting. If you /// try to wait for more than 8 pins, this function will return `None`. pub async fn wait_for_any_edge(&mut self) -> Option<()> { - InputFuture::new(&mut self.pin, InterruptOn::Edge(Edge::Both))?.await; + InputFuture::new(self.pin.reborrow(), InterruptOn::Edge(Edge::Both))?.await; Some(()) } /// Wait for a falling edge on the pin. You can have at most 8 pins waiting. If you try to wait /// for more than 8 pins, this function will return `None`. pub async fn wait_for_falling_edge(&mut self) -> Option<()> { - InputFuture::new(&mut self.pin, InterruptOn::Edge(Edge::Falling))?.await; + InputFuture::new(self.pin.reborrow(), InterruptOn::Edge(Edge::Falling))?.await; Some(()) } /// Wait for a rising edge on the pin. You can have at most 8 pins waiting. If you try to wait /// for more than 8 pins, this function will return `None`. pub async fn wait_for_rising_edge(&mut self) -> Option<()> { - InputFuture::new(&mut self.pin, InterruptOn::Edge(Edge::Rising))?.await; + InputFuture::new(self.pin.reborrow(), InterruptOn::Edge(Edge::Rising))?.await; Some(()) } /// Wait for a low level on the pin. You can have at most 8 pins waiting. If you try to wait for /// more than 8 pins, this function will return `None`. pub async fn wait_for_low(&mut self) -> Option<()> { - InputFuture::new(&mut self.pin, InterruptOn::Level(Level::Low))?.await; + InputFuture::new(self.pin.reborrow(), InterruptOn::Level(Level::Low))?.await; Some(()) } /// Wait for a high level on the pin. You can have at most 8 pins waiting. If you try to wait for /// more than 8 pins, this function will return `None`. pub async fn wait_for_high(&mut self) -> Option<()> { - InputFuture::new(&mut self.pin, InterruptOn::Level(Level::High))?.await; + InputFuture::new(self.pin.reborrow(), InterruptOn::Level(Level::High))?.await; Some(()) } } diff --git a/embassy-rp/src/adc.rs b/embassy-rp/src/adc.rs index 8defb5231..ba9ec732d 100644 --- a/embassy-rp/src/adc.rs +++ b/embassy-rp/src/adc.rs @@ -5,7 +5,6 @@ use core::mem; use core::sync::atomic::{compiler_fence, Ordering}; use core::task::Poll; -use embassy_hal_internal::{into_ref, PeripheralRef}; use embassy_sync::waitqueue::AtomicWaker; use crate::gpio::{self, AnyPin, Pull, SealedPin as GpioPin}; @@ -13,7 +12,7 @@ use crate::interrupt::typelevel::Binding; use crate::interrupt::InterruptExt; use crate::pac::dma::vals::TreqSel; use crate::peripherals::{ADC, ADC_TEMP_SENSOR}; -use crate::{dma, interrupt, pac, peripherals, Peripheral, RegExt}; +use crate::{dma, interrupt, pac, peripherals, Peri, RegExt}; static WAKER: AtomicWaker = AtomicWaker::new(); @@ -23,8 +22,8 @@ static WAKER: AtomicWaker = AtomicWaker::new(); pub struct Config {} enum Source<'p> { - Pin(PeripheralRef<'p, AnyPin>), - TempSensor(PeripheralRef<'p, ADC_TEMP_SENSOR>), + Pin(Peri<'p, AnyPin>), + TempSensor(Peri<'p, ADC_TEMP_SENSOR>), } /// ADC channel. @@ -32,8 +31,7 @@ pub struct Channel<'p>(Source<'p>); impl<'p> Channel<'p> { /// Create a new ADC channel from pin with the provided [Pull] configuration. - pub fn new_pin(pin: impl Peripheral

+ 'p, pull: Pull) -> Self { - into_ref!(pin); + pub fn new_pin(pin: Peri<'p, impl AdcPin + 'p>, pull: Pull) -> Self { pin.pad_ctrl().modify(|w| { #[cfg(feature = "_rp235x")] w.set_iso(false); @@ -47,14 +45,14 @@ impl<'p> Channel<'p> { w.set_pue(pull == Pull::Up); w.set_pde(pull == Pull::Down); }); - Self(Source::Pin(pin.map_into())) + Self(Source::Pin(pin.into())) } /// Create a new ADC channel for the internal temperature sensor. - pub fn new_temp_sensor(s: impl Peripheral

+ 'p) -> Self { + pub fn new_temp_sensor(s: Peri<'p, ADC_TEMP_SENSOR>) -> Self { let r = pac::ADC; r.cs().write_set(|w| w.set_ts_en(true)); - Self(Source::TempSensor(s.into_ref())) + Self(Source::TempSensor(s)) } fn channel(&self) -> u8 { @@ -190,7 +188,7 @@ impl<'d, M: Mode> Adc<'d, M> { impl<'d> Adc<'d, Async> { /// Create ADC driver in async mode. pub fn new( - _inner: impl Peripheral

+ 'd, + _inner: Peri<'d, ADC>, _irq: impl Binding, _config: Config, ) -> Self { @@ -240,7 +238,7 @@ impl<'d> Adc<'d, Async> { buf: &mut [W], fcs_err: bool, div: u16, - dma: impl Peripheral

, + dma: Peri<'_, impl dma::Channel>, ) -> Result<(), Error> { #[cfg(feature = "rp2040")] let mut rrobin = 0_u8; @@ -321,7 +319,7 @@ impl<'d> Adc<'d, Async> { ch: &mut [Channel<'_>], buf: &mut [S], div: u16, - dma: impl Peripheral

, + dma: Peri<'_, impl dma::Channel>, ) -> Result<(), Error> { self.read_many_inner(ch.iter().map(|c| c.channel()), buf, false, div, dma) .await @@ -337,7 +335,7 @@ impl<'d> Adc<'d, Async> { ch: &mut [Channel<'_>], buf: &mut [Sample], div: u16, - dma: impl Peripheral

, + dma: Peri<'_, impl dma::Channel>, ) { // errors are reported in individual samples let _ = self @@ -360,7 +358,7 @@ impl<'d> Adc<'d, Async> { ch: &mut Channel<'_>, buf: &mut [S], div: u16, - dma: impl Peripheral

, + dma: Peri<'_, impl dma::Channel>, ) -> Result<(), Error> { self.read_many_inner([ch.channel()].into_iter(), buf, false, div, dma) .await @@ -375,7 +373,7 @@ impl<'d> Adc<'d, Async> { ch: &mut Channel<'_>, buf: &mut [Sample], div: u16, - dma: impl Peripheral

, + dma: Peri<'_, impl dma::Channel>, ) { // errors are reported in individual samples let _ = self @@ -392,7 +390,7 @@ impl<'d> Adc<'d, Async> { impl<'d> Adc<'d, Blocking> { /// Create ADC driver in blocking mode. - pub fn new_blocking(_inner: impl Peripheral

+ 'd, _config: Config) -> Self { + pub fn new_blocking(_inner: Peri<'d, ADC>, _config: Config) -> Self { Self::setup(); Self { phantom: PhantomData } diff --git a/embassy-rp/src/bootsel.rs b/embassy-rp/src/bootsel.rs index d24ce7bd8..14f9e46aa 100644 --- a/embassy-rp/src/bootsel.rs +++ b/embassy-rp/src/bootsel.rs @@ -8,20 +8,19 @@ //! This module provides functionality to poll BOOTSEL from an embassy application. use crate::flash::in_ram; +use crate::Peri; -impl crate::peripherals::BOOTSEL { - /// Polls the BOOTSEL button. Returns true if the button is pressed. - /// - /// Polling isn't cheap, as this function waits for core 1 to finish it's current - /// task and for any DMAs from flash to complete - pub fn is_pressed(&mut self) -> bool { - let mut cs_status = Default::default(); +/// Reads the BOOTSEL button. Returns true if the button is pressed. +/// +/// Reading isn't cheap, as this function waits for core 1 to finish it's current +/// task and for any DMAs from flash to complete +pub fn is_bootsel_pressed(_p: Peri<'_, crate::peripherals::BOOTSEL>) -> bool { + let mut cs_status = Default::default(); - unsafe { in_ram(|| cs_status = ram_helpers::read_cs_status()) }.expect("Must be called from Core 0"); + unsafe { in_ram(|| cs_status = ram_helpers::read_cs_status()) }.expect("Must be called from Core 0"); - // bootsel is active low, so invert - !cs_status.infrompad() - } + // bootsel is active low, so invert + !cs_status.infrompad() } mod ram_helpers { diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs index 705dde62a..67aa5e540 100644 --- a/embassy-rp/src/clocks.rs +++ b/embassy-rp/src/clocks.rs @@ -7,13 +7,12 @@ use core::marker::PhantomData; use core::sync::atomic::AtomicU16; use core::sync::atomic::{AtomicU32, Ordering}; -use embassy_hal_internal::{into_ref, PeripheralRef}; use pac::clocks::vals::*; use crate::gpio::{AnyPin, SealedPin}; #[cfg(feature = "rp2040")] use crate::pac::common::{Reg, RW}; -use crate::{pac, reset, Peripheral}; +use crate::{pac, reset, Peri}; // NOTE: all gpin handling is commented out for future reference. // gpin is not usually safe to use during the boot init() call, so it won't @@ -200,8 +199,8 @@ impl ClockConfig { // pub fn bind_gpin(&mut self, gpin: Gpin<'static, P>, hz: u32) { // match P::NR { - // 0 => self.gpin0 = Some((hz, gpin.map_into())), - // 1 => self.gpin1 = Some((hz, gpin.map_into())), + // 0 => self.gpin0 = Some((hz, gpin.into())), + // 1 => self.gpin1 = Some((hz, gpin.into())), // _ => unreachable!(), // } // // pin is now provisionally bound. if the config is applied it must be forgotten, @@ -845,15 +844,13 @@ impl_gpinpin!(PIN_22, 22, 1); /// General purpose clock input driver. pub struct Gpin<'d, T: GpinPin> { - gpin: PeripheralRef<'d, AnyPin>, + gpin: Peri<'d, AnyPin>, _phantom: PhantomData, } impl<'d, T: GpinPin> Gpin<'d, T> { /// Create new gpin driver. - pub fn new(gpin: impl Peripheral

+ 'd) -> Self { - into_ref!(gpin); - + pub fn new(gpin: Peri<'d, T>) -> Self { #[cfg(feature = "rp2040")] gpin.gpio().ctrl().write(|w| w.set_funcsel(0x08)); @@ -867,14 +864,10 @@ impl<'d, T: GpinPin> Gpin<'d, T> { }); Gpin { - gpin: gpin.map_into(), + gpin: gpin.into(), _phantom: PhantomData, } } - - // fn map_into(self) -> Gpin<'d, AnyPin> { - // unsafe { core::mem::transmute(self) } - // } } impl<'d, T: GpinPin> Drop for Gpin<'d, T> { @@ -936,14 +929,12 @@ pub enum GpoutSrc { /// General purpose clock output driver. pub struct Gpout<'d, T: GpoutPin> { - gpout: PeripheralRef<'d, T>, + gpout: Peri<'d, T>, } impl<'d, T: GpoutPin> Gpout<'d, T> { /// Create new general purpose clock output. - pub fn new(gpout: impl Peripheral

+ 'd) -> Self { - into_ref!(gpout); - + pub fn new(gpout: Peri<'d, T>) -> Self { #[cfg(feature = "rp2040")] gpout.gpio().ctrl().write(|w| w.set_funcsel(0x08)); diff --git a/embassy-rp/src/dma.rs b/embassy-rp/src/dma.rs index 2edcfdf5b..d31d1e159 100644 --- a/embassy-rp/src/dma.rs +++ b/embassy-rp/src/dma.rs @@ -4,7 +4,7 @@ use core::pin::Pin; use core::sync::atomic::{compiler_fence, Ordering}; use core::task::{Context, Poll}; -use embassy_hal_internal::{impl_peripheral, into_ref, Peripheral, PeripheralRef}; +use embassy_hal_internal::{impl_peripheral, Peri, PeripheralType}; use embassy_sync::waitqueue::AtomicWaker; use pac::dma::vals::DataSize; @@ -42,7 +42,7 @@ pub(crate) unsafe fn init() { /// /// SAFETY: Slice must point to a valid location reachable by DMA. pub unsafe fn read<'a, C: Channel, W: Word>( - ch: impl Peripheral

+ 'a, + ch: Peri<'a, C>, from: *const W, to: *mut [W], dreq: vals::TreqSel, @@ -63,7 +63,7 @@ pub unsafe fn read<'a, C: Channel, W: Word>( /// /// SAFETY: Slice must point to a valid location reachable by DMA. pub unsafe fn write<'a, C: Channel, W: Word>( - ch: impl Peripheral

+ 'a, + ch: Peri<'a, C>, from: *const [W], to: *mut W, dreq: vals::TreqSel, @@ -87,7 +87,7 @@ static mut DUMMY: u32 = 0; /// /// SAFETY: Slice must point to a valid location reachable by DMA. pub unsafe fn write_repeated<'a, C: Channel, W: Word>( - ch: impl Peripheral

+ 'a, + ch: Peri<'a, C>, to: *mut W, len: usize, dreq: vals::TreqSel, @@ -107,11 +107,7 @@ pub unsafe fn write_repeated<'a, C: Channel, W: Word>( /// DMA copy between slices. /// /// SAFETY: Slices must point to locations reachable by DMA. -pub unsafe fn copy<'a, C: Channel, W: Word>( - ch: impl Peripheral

+ 'a, - from: &[W], - to: &mut [W], -) -> Transfer<'a, C> { +pub unsafe fn copy<'a, C: Channel, W: Word>(ch: Peri<'a, C>, from: &[W], to: &mut [W]) -> Transfer<'a, C> { let from_len = from.len(); let to_len = to.len(); assert_eq!(from_len, to_len); @@ -128,7 +124,7 @@ pub unsafe fn copy<'a, C: Channel, W: Word>( } fn copy_inner<'a, C: Channel>( - ch: impl Peripheral

+ 'a, + ch: Peri<'a, C>, from: *const u32, to: *mut u32, len: usize, @@ -137,8 +133,6 @@ fn copy_inner<'a, C: Channel>( incr_write: bool, dreq: vals::TreqSel, ) -> Transfer<'a, C> { - into_ref!(ch); - let p = ch.regs(); p.read_addr().write_value(from as u32); @@ -171,13 +165,11 @@ fn copy_inner<'a, C: Channel>( /// DMA transfer driver. #[must_use = "futures do nothing unless you `.await` or poll them"] pub struct Transfer<'a, C: Channel> { - channel: PeripheralRef<'a, C>, + channel: Peri<'a, C>, } impl<'a, C: Channel> Transfer<'a, C> { - pub(crate) fn new(channel: impl Peripheral

+ 'a) -> Self { - into_ref!(channel); - + pub(crate) fn new(channel: Peri<'a, C>) -> Self { Self { channel } } } @@ -219,7 +211,7 @@ trait SealedWord {} /// DMA channel interface. #[allow(private_bounds)] -pub trait Channel: Peripheral

+ SealedChannel + Into + Sized + 'static { +pub trait Channel: PeripheralType + SealedChannel + Into + Sized + 'static { /// Channel number. fn number(&self) -> u8; @@ -227,11 +219,6 @@ pub trait Channel: Peripheral

+ SealedChannel + Into + Siz fn regs(&self) -> pac::dma::Channel { pac::DMA.ch(self.number() as _) } - - /// Convert into type-erased [AnyChannel]. - fn degrade(self) -> AnyChannel { - AnyChannel { number: self.number() } - } } /// DMA word. @@ -287,7 +274,7 @@ macro_rules! channel { impl From for crate::dma::AnyChannel { fn from(val: peripherals::$name) -> Self { - crate::dma::Channel::degrade(val) + Self { number: val.number() } } } }; diff --git a/embassy-rp/src/flash.rs b/embassy-rp/src/flash.rs index fbc8b35ec..b30cbdd36 100644 --- a/embassy-rp/src/flash.rs +++ b/embassy-rp/src/flash.rs @@ -4,7 +4,7 @@ use core::marker::PhantomData; use core::pin::Pin; use core::task::{Context, Poll}; -use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; +use embassy_hal_internal::{Peri, PeripheralType}; use embedded_storage::nor_flash::{ check_erase, check_read, check_write, ErrorType, MultiwriteNorFlash, NorFlash, NorFlashError, NorFlashErrorKind, ReadNorFlash, @@ -114,7 +114,7 @@ impl<'a, 'd, T: Instance, const FLASH_SIZE: usize> Drop for BackgroundRead<'a, ' /// Flash driver. pub struct Flash<'d, T: Instance, M: Mode, const FLASH_SIZE: usize> { - dma: Option>, + dma: Option>, phantom: PhantomData<(&'d mut T, M)>, } @@ -253,7 +253,7 @@ impl<'d, T: Instance, M: Mode, const FLASH_SIZE: usize> Flash<'d, T, M, FLASH_SI impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, Blocking, FLASH_SIZE> { /// Create a new flash driver in blocking mode. - pub fn new_blocking(_flash: impl Peripheral

+ 'd) -> Self { + pub fn new_blocking(_flash: Peri<'d, T>) -> Self { Self { dma: None, phantom: PhantomData, @@ -263,10 +263,9 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, Blocking, FLASH_SIZE impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, Async, FLASH_SIZE> { /// Create a new flash driver in async mode. - pub fn new(_flash: impl Peripheral

+ 'd, dma: impl Peripheral

+ 'd) -> Self { - into_ref!(dma); + pub fn new(_flash: Peri<'d, T>, dma: Peri<'d, impl Channel>) -> Self { Self { - dma: Some(dma.map_into()), + dma: Some(dma.into()), phantom: PhantomData, } } @@ -316,7 +315,7 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, Async, FLASH_SIZE> { const XIP_AUX_BASE: *const u32 = 0x50500000 as *const _; let transfer = unsafe { crate::dma::read( - self.dma.as_mut().unwrap(), + self.dma.as_mut().unwrap().reborrow(), XIP_AUX_BASE, data, pac::dma::vals::TreqSel::XIP_STREAM, @@ -965,7 +964,7 @@ trait SealedMode {} /// Flash instance. #[allow(private_bounds)] -pub trait Instance: SealedInstance {} +pub trait Instance: SealedInstance + PeripheralType {} /// Flash mode. #[allow(private_bounds)] pub trait Mode: SealedMode {} diff --git a/embassy-rp/src/gpio.rs b/embassy-rp/src/gpio.rs index 111e03356..af0837f6a 100644 --- a/embassy-rp/src/gpio.rs +++ b/embassy-rp/src/gpio.rs @@ -5,13 +5,13 @@ use core::future::Future; use core::pin::Pin as FuturePin; use core::task::{Context, Poll}; -use embassy_hal_internal::{impl_peripheral, into_ref, PeripheralRef}; +use embassy_hal_internal::{impl_peripheral, Peri, PeripheralType}; use embassy_sync::waitqueue::AtomicWaker; use crate::interrupt::InterruptExt; use crate::pac::common::{Reg, RW}; use crate::pac::SIO; -use crate::{interrupt, pac, peripherals, Peripheral, RegExt}; +use crate::{interrupt, pac, peripherals, RegExt}; #[cfg(any(feature = "rp2040", feature = "rp235xa"))] pub(crate) const BANK0_PIN_COUNT: usize = 30; @@ -115,7 +115,7 @@ pub struct Input<'d> { impl<'d> Input<'d> { /// Create GPIO input driver for a [Pin] with the provided [Pull] configuration. #[inline] - pub fn new(pin: impl Peripheral

+ 'd, pull: Pull) -> Self { + pub fn new(pin: Peri<'d, impl Pin>, pull: Pull) -> Self { let mut pin = Flex::new(pin); pin.set_as_input(); pin.set_pull(pull); @@ -266,11 +266,11 @@ fn IO_IRQ_QSPI() { #[must_use = "futures do nothing unless you `.await` or poll them"] struct InputFuture<'d> { - pin: PeripheralRef<'d, AnyPin>, + pin: Peri<'d, AnyPin>, } impl<'d> InputFuture<'d> { - fn new(pin: PeripheralRef<'d, AnyPin>, level: InterruptTrigger) -> Self { + fn new(pin: Peri<'d, AnyPin>, level: InterruptTrigger) -> Self { let pin_group = (pin.pin() % 8) as usize; // first, clear the INTR register bits. without this INTR will still // contain reports of previous edges, causing the IRQ to fire early @@ -359,7 +359,7 @@ pub struct Output<'d> { impl<'d> Output<'d> { /// Create GPIO output driver for a [Pin] with the provided [Level]. #[inline] - pub fn new(pin: impl Peripheral

+ 'd, initial_output: Level) -> Self { + pub fn new(pin: Peri<'d, impl Pin>, initial_output: Level) -> Self { let mut pin = Flex::new(pin); match initial_output { Level::High => pin.set_high(), @@ -440,7 +440,7 @@ pub struct OutputOpenDrain<'d> { impl<'d> OutputOpenDrain<'d> { /// Create GPIO output driver for a [Pin] in open drain mode with the provided [Level]. #[inline] - pub fn new(pin: impl Peripheral

+ 'd, initial_output: Level) -> Self { + pub fn new(pin: Peri<'d, impl Pin>, initial_output: Level) -> Self { let mut pin = Flex::new(pin); pin.set_low(); match initial_output { @@ -581,7 +581,7 @@ impl<'d> OutputOpenDrain<'d> { /// set while not in output mode, so the pin's level will be 'remembered' when it is not in output /// mode. pub struct Flex<'d> { - pin: PeripheralRef<'d, AnyPin>, + pin: Peri<'d, AnyPin>, } impl<'d> Flex<'d> { @@ -590,9 +590,7 @@ impl<'d> Flex<'d> { /// The pin remains disconnected. The initial output level is unspecified, but can be changed /// before the pin is put into output mode. #[inline] - pub fn new(pin: impl Peripheral

+ 'd) -> Self { - into_ref!(pin); - + pub fn new(pin: Peri<'d, impl Pin>) -> Self { pin.pad_ctrl().write(|w| { #[cfg(feature = "_rp235x")] w.set_iso(false); @@ -606,7 +604,7 @@ impl<'d> Flex<'d> { w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::SIOB_PROC_0 as _); }); - Self { pin: pin.map_into() } + Self { pin: pin.into() } } #[inline] @@ -829,7 +827,7 @@ impl<'d> Drop for Flex<'d> { /// Dormant wake driver. pub struct DormantWake<'w> { - pin: PeripheralRef<'w, AnyPin>, + pin: Peri<'w, AnyPin>, cfg: DormantWakeConfig, } @@ -919,14 +917,7 @@ pub(crate) trait SealedPin: Sized { /// Interface for a Pin that can be configured by an [Input] or [Output] driver, or converted to an [AnyPin]. #[allow(private_bounds)] -pub trait Pin: Peripheral

+ Into + SealedPin + Sized + 'static { - /// Degrade to a generic pin struct - fn degrade(self) -> AnyPin { - AnyPin { - pin_bank: self.pin_bank(), - } - } - +pub trait Pin: PeripheralType + Into + SealedPin + Sized + 'static { /// Returns the pin number within a bank #[inline] fn pin(&self) -> u8 { @@ -951,8 +942,8 @@ impl AnyPin { /// # Safety /// /// You must ensure that you’re only using one instance of this type at a time. - pub unsafe fn steal(pin_bank: u8) -> Self { - Self { pin_bank } + pub unsafe fn steal(pin_bank: u8) -> Peri<'static, Self> { + Peri::new_unchecked(Self { pin_bank }) } } @@ -979,7 +970,9 @@ macro_rules! impl_pin { impl From for crate::gpio::AnyPin { fn from(val: peripherals::$name) -> Self { - crate::gpio::Pin::degrade(val) + Self { + pin_bank: val.pin_bank(), + } } } }; diff --git a/embassy-rp/src/i2c.rs b/embassy-rp/src/i2c.rs index 3a2ee666c..adc38b73d 100644 --- a/embassy-rp/src/i2c.rs +++ b/embassy-rp/src/i2c.rs @@ -5,13 +5,13 @@ use core::future; use core::marker::PhantomData; use core::task::Poll; -use embassy_hal_internal::{into_ref, PeripheralRef}; +use embassy_hal_internal::{Peri, PeripheralType}; use embassy_sync::waitqueue::AtomicWaker; use pac::i2c; use crate::gpio::AnyPin; use crate::interrupt::typelevel::{Binding, Interrupt}; -use crate::{interrupt, pac, peripherals, Peripheral}; +use crate::{interrupt, pac, peripherals}; /// I2C error abort reason #[derive(Debug, PartialEq, Eq, Clone, Copy)] @@ -83,28 +83,25 @@ pub struct I2c<'d, T: Instance, M: Mode> { impl<'d, T: Instance> I2c<'d, T, Blocking> { /// Create a new driver instance in blocking mode. pub fn new_blocking( - peri: impl Peripheral

+ 'd, - scl: impl Peripheral

> + 'd, - sda: impl Peripheral

> + 'd, + peri: Peri<'d, T>, + scl: Peri<'d, impl SclPin>, + sda: Peri<'d, impl SdaPin>, config: Config, ) -> Self { - into_ref!(scl, sda); - Self::new_inner(peri, scl.map_into(), sda.map_into(), config) + Self::new_inner(peri, scl.into(), sda.into(), config) } } impl<'d, T: Instance> I2c<'d, T, Async> { /// Create a new driver instance in async mode. pub fn new_async( - peri: impl Peripheral

+ 'd, - scl: impl Peripheral

> + 'd, - sda: impl Peripheral

> + 'd, + peri: Peri<'d, T>, + scl: Peri<'d, impl SclPin>, + sda: Peri<'d, impl SdaPin>, _irq: impl Binding>, config: Config, ) -> Self { - into_ref!(scl, sda); - - let i2c = Self::new_inner(peri, scl.map_into(), sda.map_into(), config); + let i2c = Self::new_inner(peri, scl.into(), sda.into(), config); let r = T::regs(); @@ -378,14 +375,7 @@ where } impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> { - fn new_inner( - _peri: impl Peripheral

+ 'd, - scl: PeripheralRef<'d, AnyPin>, - sda: PeripheralRef<'d, AnyPin>, - config: Config, - ) -> Self { - into_ref!(_peri); - + fn new_inner(_peri: Peri<'d, T>, scl: Peri<'d, AnyPin>, sda: Peri<'d, AnyPin>, config: Config) -> Self { let reset = T::reset(); crate::reset::reset(reset); crate::reset::unreset_wait(reset); @@ -804,7 +794,7 @@ impl_mode!(Async); /// I2C instance. #[allow(private_bounds)] -pub trait Instance: SealedInstance { +pub trait Instance: SealedInstance + PeripheralType { /// Interrupt for this peripheral. type Interrupt: interrupt::typelevel::Interrupt; } diff --git a/embassy-rp/src/i2c_slave.rs b/embassy-rp/src/i2c_slave.rs index d17b11d14..d420030d8 100644 --- a/embassy-rp/src/i2c_slave.rs +++ b/embassy-rp/src/i2c_slave.rs @@ -3,12 +3,11 @@ use core::future; use core::marker::PhantomData; use core::task::Poll; -use embassy_hal_internal::into_ref; use pac::i2c; use crate::i2c::{set_up_i2c_pin, AbortReason, Instance, InterruptHandler, SclPin, SdaPin, FIFO_SIZE}; use crate::interrupt::typelevel::{Binding, Interrupt}; -use crate::{pac, Peripheral}; +use crate::{pac, Peri}; /// I2C error #[derive(Debug, PartialEq, Eq, Clone, Copy)] @@ -87,14 +86,12 @@ pub struct I2cSlave<'d, T: Instance> { impl<'d, T: Instance> I2cSlave<'d, T> { /// Create a new instance. pub fn new( - _peri: impl Peripheral

+ 'd, - scl: impl Peripheral

> + 'd, - sda: impl Peripheral

> + 'd, + _peri: Peri<'d, T>, + scl: Peri<'d, impl SclPin>, + sda: Peri<'d, impl SdaPin>, _irq: impl Binding>, config: Config, ) -> Self { - into_ref!(_peri, scl, sda); - assert!(config.addr != 0); // Configure SCL & SDA pins diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs index de60af890..35099d07b 100644 --- a/embassy-rp/src/lib.rs +++ b/embassy-rp/src/lib.rs @@ -54,7 +54,7 @@ pub mod pio; pub(crate) mod relocate; // Reexports -pub use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; +pub use embassy_hal_internal::{Peri, PeripheralType}; #[cfg(feature = "unstable-pac")] pub use rp_pac as pac; #[cfg(not(feature = "unstable-pac"))] diff --git a/embassy-rp/src/multicore.rs b/embassy-rp/src/multicore.rs index 1450505b9..d10b6837c 100644 --- a/embassy-rp/src/multicore.rs +++ b/embassy-rp/src/multicore.rs @@ -51,7 +51,7 @@ use core::sync::atomic::{compiler_fence, AtomicBool, Ordering}; use crate::interrupt::InterruptExt; use crate::peripherals::CORE1; -use crate::{gpio, install_stack_guard, interrupt, pac}; +use crate::{gpio, install_stack_guard, interrupt, pac, Peri}; const PAUSE_TOKEN: u32 = 0xDEADBEEF; const RESUME_TOKEN: u32 = !0xDEADBEEF; @@ -139,7 +139,7 @@ unsafe fn SIO_IRQ_FIFO() { } /// Spawn a function on this core -pub fn spawn_core1(_core1: CORE1, stack: &'static mut Stack, entry: F) +pub fn spawn_core1(_core1: Peri<'static, CORE1>, stack: &'static mut Stack, entry: F) where F: FnOnce() -> bad::Never + Send + 'static, { diff --git a/embassy-rp/src/pio/mod.rs b/embassy-rp/src/pio/mod.rs index fd09d4bba..ec698d99c 100644 --- a/embassy-rp/src/pio/mod.rs +++ b/embassy-rp/src/pio/mod.rs @@ -6,7 +6,7 @@ use core::sync::atomic::{compiler_fence, Ordering}; use core::task::{Context, Poll}; use atomic_polyfill::{AtomicU64, AtomicU8}; -use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; +use embassy_hal_internal::{Peri, PeripheralType}; use embassy_sync::waitqueue::AtomicWaker; use fixed::types::extra::U8; use fixed::FixedU32; @@ -235,7 +235,7 @@ impl<'a, 'd, PIO: Instance> Drop for IrqFuture<'a, 'd, PIO> { /// Type representing a PIO pin. pub struct Pin<'l, PIO: Instance> { - pin: PeripheralRef<'l, AnyPin>, + pin: Peri<'l, AnyPin>, pio: PhantomData, } @@ -360,7 +360,7 @@ impl<'d, PIO: Instance, const SM: usize> StateMachineRx<'d, PIO, SM> { /// Prepare DMA transfer from RX FIFO. pub fn dma_pull<'a, C: Channel, W: Word>( &'a mut self, - ch: PeripheralRef<'a, C>, + ch: Peri<'a, C>, data: &'a mut [W], bswap: bool, ) -> Transfer<'a, C> { @@ -451,7 +451,7 @@ impl<'d, PIO: Instance, const SM: usize> StateMachineTx<'d, PIO, SM> { /// Prepare a DMA transfer to TX FIFO. pub fn dma_push<'a, C: Channel, W: Word>( &'a mut self, - ch: PeripheralRef<'a, C>, + ch: Peri<'a, C>, data: &'a [W], bswap: bool, ) -> Transfer<'a, C> { @@ -1147,9 +1147,7 @@ impl<'d, PIO: Instance> Common<'d, PIO> { /// (i.e., have their `FUNCSEL` reset to `NULL`) when the [`Common`] *and* /// all [`StateMachine`]s for this block have been dropped. **Other members /// of [`Pio`] do not keep pin registrations alive.** - pub fn make_pio_pin(&mut self, pin: impl Peripheral

+ 'd) -> Pin<'d, PIO> { - into_ref!(pin); - + pub fn make_pio_pin(&mut self, pin: Peri<'d, impl PioPin + 'd>) -> Pin<'d, PIO> { // enable the outputs pin.pad_ctrl().write(|w| w.set_od(false)); // especially important on the 235x, where IE defaults to 0 @@ -1171,7 +1169,7 @@ impl<'d, PIO: Instance> Common<'d, PIO> { // we can be relaxed about this because we're &mut here and nothing is cached PIO::state().used_pins.fetch_or(1 << pin.pin_bank(), Ordering::Relaxed); Pin { - pin: pin.into_ref().map_into(), + pin: pin.into(), pio: PhantomData::default(), } } @@ -1304,7 +1302,7 @@ pub struct Pio<'d, PIO: Instance> { impl<'d, PIO: Instance> Pio<'d, PIO> { /// Create a new instance of a PIO peripheral. - pub fn new(_pio: impl Peripheral

+ 'd, _irq: impl Binding>) -> Self { + pub fn new(_pio: Peri<'d, PIO>, _irq: impl Binding>) -> Self { PIO::state().users.store(5, Ordering::Release); PIO::state().used_pins.store(0, Ordering::Release); PIO::Interrupt::unpend(); @@ -1389,7 +1387,7 @@ trait SealedInstance { /// PIO instance. #[allow(private_bounds)] -pub trait Instance: SealedInstance + Sized + Unpin { +pub trait Instance: SealedInstance + PeripheralType + Sized + Unpin { /// Interrupt for this peripheral. type Interrupt: crate::interrupt::typelevel::Interrupt; } diff --git a/embassy-rp/src/pio_programs/hd44780.rs b/embassy-rp/src/pio_programs/hd44780.rs index 6997b91f3..5846a8027 100644 --- a/embassy-rp/src/pio_programs/hd44780.rs +++ b/embassy-rp/src/pio_programs/hd44780.rs @@ -5,7 +5,7 @@ use crate::pio::{ Common, Config, Direction, FifoJoin, Instance, Irq, LoadedProgram, PioPin, ShiftConfig, ShiftDirection, StateMachine, }; -use crate::{into_ref, Peripheral, PeripheralRef}; +use crate::Peri; /// This struct represents a HD44780 program that takes command words ( <0:4>) pub struct PioHD44780CommandWordProgram<'a, PIO: Instance> { @@ -99,7 +99,7 @@ impl<'a, PIO: Instance> PioHD44780CommandSequenceProgram<'a, PIO> { /// Pio backed HD44780 driver pub struct PioHD44780<'l, P: Instance, const S: usize> { - dma: PeripheralRef<'l, AnyChannel>, + dma: Peri<'l, AnyChannel>, sm: StateMachine<'l, P, S>, buf: [u8; 40], @@ -111,19 +111,17 @@ impl<'l, P: Instance, const S: usize> PioHD44780<'l, P, S> { common: &mut Common<'l, P>, mut sm: StateMachine<'l, P, S>, mut irq: Irq<'l, P, S>, - dma: impl Peripheral

+ 'l, - rs: impl PioPin, - rw: impl PioPin, - e: impl PioPin, - db4: impl PioPin, - db5: impl PioPin, - db6: impl PioPin, - db7: impl PioPin, + mut dma: Peri<'l, impl Channel>, + rs: Peri<'l, impl PioPin>, + rw: Peri<'l, impl PioPin>, + e: Peri<'l, impl PioPin>, + db4: Peri<'l, impl PioPin>, + db5: Peri<'l, impl PioPin>, + db6: Peri<'l, impl PioPin>, + db7: Peri<'l, impl PioPin>, word_prg: &PioHD44780CommandWordProgram<'l, P>, seq_prg: &PioHD44780CommandSequenceProgram<'l, P>, ) -> PioHD44780<'l, P, S> { - into_ref!(dma); - let rs = common.make_pio_pin(rs); let rw = common.make_pio_pin(rw); let e = common.make_pio_pin(e); @@ -176,7 +174,7 @@ impl<'l, P: Instance, const S: usize> PioHD44780<'l, P, S> { sm.tx().dma_push(dma.reborrow(), &[0x81u8, 0x0f, 1], false).await; Self { - dma: dma.map_into(), + dma: dma.into(), sm, buf: [0x20; 40], } diff --git a/embassy-rp/src/pio_programs/i2s.rs b/embassy-rp/src/pio_programs/i2s.rs index 17e321405..b967f0160 100644 --- a/embassy-rp/src/pio_programs/i2s.rs +++ b/embassy-rp/src/pio_programs/i2s.rs @@ -6,16 +6,16 @@ use crate::dma::{AnyChannel, Channel, Transfer}; use crate::pio::{ Common, Config, Direction, FifoJoin, Instance, LoadedProgram, PioPin, ShiftConfig, ShiftDirection, StateMachine, }; -use crate::{into_ref, Peripheral, PeripheralRef}; +use crate::Peri; /// This struct represents an i2s output driver program -pub struct PioI2sOutProgram<'a, PIO: Instance> { - prg: LoadedProgram<'a, PIO>, +pub struct PioI2sOutProgram<'d, PIO: Instance> { + prg: LoadedProgram<'d, PIO>, } -impl<'a, PIO: Instance> PioI2sOutProgram<'a, PIO> { +impl<'d, PIO: Instance> PioI2sOutProgram<'d, PIO> { /// Load the program into the given pio - pub fn new(common: &mut Common<'a, PIO>) -> Self { + pub fn new(common: &mut Common<'d, PIO>) -> Self { let prg = pio::pio_asm!( ".side_set 2", " set x, 14 side 0b01", // side 0bWB - W = Word Clock, B = Bit Clock @@ -37,27 +37,25 @@ impl<'a, PIO: Instance> PioI2sOutProgram<'a, PIO> { } /// Pio backed I2s output driver -pub struct PioI2sOut<'a, P: Instance, const S: usize> { - dma: PeripheralRef<'a, AnyChannel>, - sm: StateMachine<'a, P, S>, +pub struct PioI2sOut<'d, P: Instance, const S: usize> { + dma: Peri<'d, AnyChannel>, + sm: StateMachine<'d, P, S>, } -impl<'a, P: Instance, const S: usize> PioI2sOut<'a, P, S> { +impl<'d, P: Instance, const S: usize> PioI2sOut<'d, P, S> { /// Configure a state machine to output I2s pub fn new( - common: &mut Common<'a, P>, - mut sm: StateMachine<'a, P, S>, - dma: impl Peripheral

+ 'a, - data_pin: impl PioPin, - bit_clock_pin: impl PioPin, - lr_clock_pin: impl PioPin, + common: &mut Common<'d, P>, + mut sm: StateMachine<'d, P, S>, + dma: Peri<'d, impl Channel>, + data_pin: Peri<'d, impl PioPin>, + bit_clock_pin: Peri<'d, impl PioPin>, + lr_clock_pin: Peri<'d, impl PioPin>, sample_rate: u32, bit_depth: u32, channels: u32, - program: &PioI2sOutProgram<'a, P>, + program: &PioI2sOutProgram<'d, P>, ) -> Self { - into_ref!(dma); - let data_pin = common.make_pio_pin(data_pin); let bit_clock_pin = common.make_pio_pin(bit_clock_pin); let left_right_clock_pin = common.make_pio_pin(lr_clock_pin); @@ -82,10 +80,7 @@ impl<'a, P: Instance, const S: usize> PioI2sOut<'a, P, S> { sm.set_enable(true); - Self { - dma: dma.map_into(), - sm, - } + Self { dma: dma.into(), sm } } /// Return an in-prograss dma transfer future. Awaiting it will guarentee a complete transfer. diff --git a/embassy-rp/src/pio_programs/onewire.rs b/embassy-rp/src/pio_programs/onewire.rs index 040333e76..00783aab0 100644 --- a/embassy-rp/src/pio_programs/onewire.rs +++ b/embassy-rp/src/pio_programs/onewire.rs @@ -1,6 +1,7 @@ //! OneWire pio driver use crate::pio::{Common, Config, Instance, LoadedProgram, PioPin, ShiftConfig, ShiftDirection, StateMachine}; +use crate::Peri; /// This struct represents an onewire driver program pub struct PioOneWireProgram<'a, PIO: Instance> { @@ -69,7 +70,7 @@ impl<'d, PIO: Instance, const SM: usize> PioOneWire<'d, PIO, SM> { pub fn new( common: &mut Common<'d, PIO>, mut sm: StateMachine<'d, PIO, SM>, - pin: impl PioPin, + pin: Peri<'d, impl PioPin>, program: &PioOneWireProgram<'d, PIO>, ) -> Self { let pin = common.make_pio_pin(pin); diff --git a/embassy-rp/src/pio_programs/pwm.rs b/embassy-rp/src/pio_programs/pwm.rs index 01ffe012a..f0f837bc5 100644 --- a/embassy-rp/src/pio_programs/pwm.rs +++ b/embassy-rp/src/pio_programs/pwm.rs @@ -4,9 +4,9 @@ use core::time::Duration; use pio::InstructionOperands; -use crate::clocks; use crate::gpio::Level; use crate::pio::{Common, Config, Direction, Instance, LoadedProgram, Pin, PioPin, StateMachine}; +use crate::{clocks, Peri}; /// This converts the duration provided into the number of cycles the PIO needs to run to make it take the same time fn to_pio_cycles(duration: Duration) -> u32 { @@ -52,7 +52,7 @@ impl<'d, T: Instance, const SM: usize> PioPwm<'d, T, SM> { pub fn new( pio: &mut Common<'d, T>, mut sm: StateMachine<'d, T, SM>, - pin: impl PioPin, + pin: Peri<'d, impl PioPin>, program: &PioPwmProgram<'d, T>, ) -> Self { let pin = pio.make_pio_pin(pin); diff --git a/embassy-rp/src/pio_programs/rotary_encoder.rs b/embassy-rp/src/pio_programs/rotary_encoder.rs index f2fb02aca..e520da8a3 100644 --- a/embassy-rp/src/pio_programs/rotary_encoder.rs +++ b/embassy-rp/src/pio_programs/rotary_encoder.rs @@ -6,6 +6,7 @@ use crate::gpio::Pull; use crate::pio::{ Common, Config, Direction as PioDirection, FifoJoin, Instance, LoadedProgram, PioPin, ShiftDirection, StateMachine, }; +use crate::Peri; /// This struct represents an Encoder program loaded into pio instruction memory. pub struct PioEncoderProgram<'a, PIO: Instance> { @@ -33,8 +34,8 @@ impl<'d, T: Instance, const SM: usize> PioEncoder<'d, T, SM> { pub fn new( pio: &mut Common<'d, T>, mut sm: StateMachine<'d, T, SM>, - pin_a: impl PioPin, - pin_b: impl PioPin, + pin_a: Peri<'d, impl PioPin>, + pin_b: Peri<'d, impl PioPin>, program: &PioEncoderProgram<'d, T>, ) -> Self { let mut pin_a = pio.make_pio_pin(pin_a); diff --git a/embassy-rp/src/pio_programs/stepper.rs b/embassy-rp/src/pio_programs/stepper.rs index c8f74167d..495191659 100644 --- a/embassy-rp/src/pio_programs/stepper.rs +++ b/embassy-rp/src/pio_programs/stepper.rs @@ -7,6 +7,7 @@ use fixed::types::extra::U8; use fixed::FixedU32; use crate::pio::{Common, Config, Direction, Instance, Irq, LoadedProgram, PioPin, StateMachine}; +use crate::Peri; /// This struct represents a Stepper driver program loaded into pio instruction memory. pub struct PioStepperProgram<'a, PIO: Instance> { @@ -50,10 +51,10 @@ impl<'d, T: Instance, const SM: usize> PioStepper<'d, T, SM> { pio: &mut Common<'d, T>, mut sm: StateMachine<'d, T, SM>, irq: Irq<'d, T, SM>, - pin0: impl PioPin, - pin1: impl PioPin, - pin2: impl PioPin, - pin3: impl PioPin, + pin0: Peri<'d, impl PioPin>, + pin1: Peri<'d, impl PioPin>, + pin2: Peri<'d, impl PioPin>, + pin3: Peri<'d, impl PioPin>, program: &PioStepperProgram<'d, T>, ) -> Self { let pin0 = pio.make_pio_pin(pin0); diff --git a/embassy-rp/src/pio_programs/uart.rs b/embassy-rp/src/pio_programs/uart.rs index 641daca61..04e39a571 100644 --- a/embassy-rp/src/pio_programs/uart.rs +++ b/embassy-rp/src/pio_programs/uart.rs @@ -10,15 +10,16 @@ use crate::gpio::Level; use crate::pio::{ Common, Config, Direction as PioDirection, FifoJoin, Instance, LoadedProgram, PioPin, ShiftDirection, StateMachine, }; +use crate::Peri; /// This struct represents a uart tx program loaded into pio instruction memory. -pub struct PioUartTxProgram<'a, PIO: Instance> { - prg: LoadedProgram<'a, PIO>, +pub struct PioUartTxProgram<'d, PIO: Instance> { + prg: LoadedProgram<'d, PIO>, } -impl<'a, PIO: Instance> PioUartTxProgram<'a, PIO> { +impl<'d, PIO: Instance> PioUartTxProgram<'d, PIO> { /// Load the uart tx program into the given pio - pub fn new(common: &mut Common<'a, PIO>) -> Self { + pub fn new(common: &mut Common<'d, PIO>) -> Self { let prg = pio::pio_asm!( r#" .side_set 1 opt @@ -41,18 +42,18 @@ impl<'a, PIO: Instance> PioUartTxProgram<'a, PIO> { } /// PIO backed Uart transmitter -pub struct PioUartTx<'a, PIO: Instance, const SM: usize> { - sm_tx: StateMachine<'a, PIO, SM>, +pub struct PioUartTx<'d, PIO: Instance, const SM: usize> { + sm_tx: StateMachine<'d, PIO, SM>, } -impl<'a, PIO: Instance, const SM: usize> PioUartTx<'a, PIO, SM> { +impl<'d, PIO: Instance, const SM: usize> PioUartTx<'d, PIO, SM> { /// Configure a pio state machine to use the loaded tx program. pub fn new( baud: u32, - common: &mut Common<'a, PIO>, - mut sm_tx: StateMachine<'a, PIO, SM>, - tx_pin: impl PioPin, - program: &PioUartTxProgram<'a, PIO>, + common: &mut Common<'d, PIO>, + mut sm_tx: StateMachine<'d, PIO, SM>, + tx_pin: Peri<'d, impl PioPin>, + program: &PioUartTxProgram<'d, PIO>, ) -> Self { let tx_pin = common.make_pio_pin(tx_pin); sm_tx.set_pins(Level::High, &[&tx_pin]); @@ -92,13 +93,13 @@ impl Write for PioUartTx<'_, PIO, SM> { } /// This struct represents a Uart Rx program loaded into pio instruction memory. -pub struct PioUartRxProgram<'a, PIO: Instance> { - prg: LoadedProgram<'a, PIO>, +pub struct PioUartRxProgram<'d, PIO: Instance> { + prg: LoadedProgram<'d, PIO>, } -impl<'a, PIO: Instance> PioUartRxProgram<'a, PIO> { +impl<'d, PIO: Instance> PioUartRxProgram<'d, PIO> { /// Load the uart rx program into the given pio - pub fn new(common: &mut Common<'a, PIO>) -> Self { + pub fn new(common: &mut Common<'d, PIO>) -> Self { let prg = pio::pio_asm!( r#" ; Slightly more fleshed-out 8n1 UART receiver which handles framing errors and @@ -130,18 +131,18 @@ impl<'a, PIO: Instance> PioUartRxProgram<'a, PIO> { } /// PIO backed Uart reciever -pub struct PioUartRx<'a, PIO: Instance, const SM: usize> { - sm_rx: StateMachine<'a, PIO, SM>, +pub struct PioUartRx<'d, PIO: Instance, const SM: usize> { + sm_rx: StateMachine<'d, PIO, SM>, } -impl<'a, PIO: Instance, const SM: usize> PioUartRx<'a, PIO, SM> { +impl<'d, PIO: Instance, const SM: usize> PioUartRx<'d, PIO, SM> { /// Configure a pio state machine to use the loaded rx program. pub fn new( baud: u32, - common: &mut Common<'a, PIO>, - mut sm_rx: StateMachine<'a, PIO, SM>, - rx_pin: impl PioPin, - program: &PioUartRxProgram<'a, PIO>, + common: &mut Common<'d, PIO>, + mut sm_rx: StateMachine<'d, PIO, SM>, + rx_pin: Peri<'d, impl PioPin>, + program: &PioUartRxProgram<'d, PIO>, ) -> Self { let mut cfg = Config::default(); cfg.use_program(&program.prg, &[]); diff --git a/embassy-rp/src/pio_programs/ws2812.rs b/embassy-rp/src/pio_programs/ws2812.rs index 2462a64e6..578937e11 100644 --- a/embassy-rp/src/pio_programs/ws2812.rs +++ b/embassy-rp/src/pio_programs/ws2812.rs @@ -9,7 +9,7 @@ use crate::dma::{AnyChannel, Channel}; use crate::pio::{ Common, Config, FifoJoin, Instance, LoadedProgram, PioPin, ShiftConfig, ShiftDirection, StateMachine, }; -use crate::{into_ref, Peripheral, PeripheralRef}; +use crate::Peri; const T1: u8 = 2; // start bit const T2: u8 = 5; // data bit @@ -53,7 +53,7 @@ impl<'a, PIO: Instance> PioWs2812Program<'a, PIO> { /// Pio backed ws2812 driver /// Const N is the number of ws2812 leds attached to this pin pub struct PioWs2812<'d, P: Instance, const S: usize, const N: usize> { - dma: PeripheralRef<'d, AnyChannel>, + dma: Peri<'d, AnyChannel>, sm: StateMachine<'d, P, S>, } @@ -62,12 +62,10 @@ impl<'d, P: Instance, const S: usize, const N: usize> PioWs2812<'d, P, S, N> { pub fn new( pio: &mut Common<'d, P>, mut sm: StateMachine<'d, P, S>, - dma: impl Peripheral

+ 'd, - pin: impl PioPin, + dma: Peri<'d, impl Channel>, + pin: Peri<'d, impl PioPin>, program: &PioWs2812Program<'d, P>, ) -> Self { - into_ref!(dma); - // Setup sm0 let mut cfg = Config::default(); @@ -95,10 +93,7 @@ impl<'d, P: Instance, const S: usize, const N: usize> PioWs2812<'d, P, S, N> { sm.set_config(&cfg); sm.set_enable(true); - Self { - dma: dma.map_into(), - sm, - } + Self { dma: dma.into(), sm } } /// Write a buffer of [smart_leds::RGB8] to the ws2812 string diff --git a/embassy-rp/src/pwm.rs b/embassy-rp/src/pwm.rs index 4fb8ade12..f631402a2 100644 --- a/embassy-rp/src/pwm.rs +++ b/embassy-rp/src/pwm.rs @@ -1,6 +1,6 @@ //! Pulse Width Modulation (PWM) -use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; +use embassy_hal_internal::{Peri, PeripheralType}; pub use embedded_hal_1::pwm::SetDutyCycle; use embedded_hal_1::pwm::{Error, ErrorKind, ErrorType}; use fixed::traits::ToFixed; @@ -99,8 +99,8 @@ impl Error for PwmError { /// PWM driver. pub struct Pwm<'d> { - pin_a: Option>, - pin_b: Option>, + pin_a: Option>, + pin_b: Option>, slice: usize, } @@ -131,8 +131,8 @@ impl<'d> SetDutyCycle for Pwm<'d> { impl<'d> Pwm<'d> { fn new_inner( slice: usize, - a: Option>, - b: Option>, + a: Option>, + b: Option>, b_pull: Pull, config: Config, divmode: Divmode, @@ -171,60 +171,34 @@ impl<'d> Pwm<'d> { /// Create PWM driver without any configured pins. #[inline] - pub fn new_free(slice: impl Peripheral

+ 'd, config: Config) -> Self { - into_ref!(slice); + pub fn new_free(slice: Peri<'d, T>, config: Config) -> Self { Self::new_inner(slice.number(), None, None, Pull::None, config, Divmode::DIV) } /// Create PWM driver with a single 'a' pin as output. #[inline] - pub fn new_output_a( - slice: impl Peripheral

+ 'd, - a: impl Peripheral

> + 'd, - config: Config, - ) -> Self { - into_ref!(slice, a); - Self::new_inner( - slice.number(), - Some(a.map_into()), - None, - Pull::None, - config, - Divmode::DIV, - ) + pub fn new_output_a(slice: Peri<'d, T>, a: Peri<'d, impl ChannelAPin>, config: Config) -> Self { + Self::new_inner(slice.number(), Some(a.into()), None, Pull::None, config, Divmode::DIV) } /// Create PWM driver with a single 'b' pin as output. #[inline] - pub fn new_output_b( - slice: impl Peripheral

+ 'd, - b: impl Peripheral

> + 'd, - config: Config, - ) -> Self { - into_ref!(slice, b); - Self::new_inner( - slice.number(), - None, - Some(b.map_into()), - Pull::None, - config, - Divmode::DIV, - ) + pub fn new_output_b(slice: Peri<'d, T>, b: Peri<'d, impl ChannelBPin>, config: Config) -> Self { + Self::new_inner(slice.number(), None, Some(b.into()), Pull::None, config, Divmode::DIV) } /// Create PWM driver with a 'a' and 'b' pins as output. #[inline] pub fn new_output_ab( - slice: impl Peripheral

+ 'd, - a: impl Peripheral

> + 'd, - b: impl Peripheral

> + 'd, + slice: Peri<'d, T>, + a: Peri<'d, impl ChannelAPin>, + b: Peri<'d, impl ChannelBPin>, config: Config, ) -> Self { - into_ref!(slice, a, b); Self::new_inner( slice.number(), - Some(a.map_into()), - Some(b.map_into()), + Some(a.into()), + Some(b.into()), Pull::None, config, Divmode::DIV, @@ -234,31 +208,29 @@ impl<'d> Pwm<'d> { /// Create PWM driver with a single 'b' as input pin. #[inline] pub fn new_input( - slice: impl Peripheral

+ 'd, - b: impl Peripheral

> + 'd, + slice: Peri<'d, T>, + b: Peri<'d, impl ChannelBPin>, b_pull: Pull, mode: InputMode, config: Config, ) -> Self { - into_ref!(slice, b); - Self::new_inner(slice.number(), None, Some(b.map_into()), b_pull, config, mode.into()) + Self::new_inner(slice.number(), None, Some(b.into()), b_pull, config, mode.into()) } /// Create PWM driver with a 'a' and 'b' pins in the desired input mode. #[inline] pub fn new_output_input( - slice: impl Peripheral

+ 'd, - a: impl Peripheral

> + 'd, - b: impl Peripheral

> + 'd, + slice: Peri<'d, T>, + a: Peri<'d, impl ChannelAPin>, + b: Peri<'d, impl ChannelBPin>, b_pull: Pull, mode: InputMode, config: Config, ) -> Self { - into_ref!(slice, a, b); Self::new_inner( slice.number(), - Some(a.map_into()), - Some(b.map_into()), + Some(a.into()), + Some(b.into()), b_pull, config, mode.into(), @@ -373,8 +345,8 @@ impl<'d> Pwm<'d> { } enum PwmChannelPin<'d> { - A(PeripheralRef<'d, AnyPin>), - B(PeripheralRef<'d, AnyPin>), + A(Peri<'d, AnyPin>), + B(Peri<'d, AnyPin>), } /// Single channel of Pwm driver. @@ -498,7 +470,7 @@ trait SealedSlice {} /// PWM Slice. #[allow(private_bounds)] -pub trait Slice: Peripheral

+ SealedSlice + Sized + 'static { +pub trait Slice: PeripheralType + SealedSlice + Sized + 'static { /// Slice number. fn number(&self) -> usize; } diff --git a/embassy-rp/src/rtc/mod.rs b/embassy-rp/src/rtc/mod.rs index 2ce7ac645..63cf91d28 100644 --- a/embassy-rp/src/rtc/mod.rs +++ b/embassy-rp/src/rtc/mod.rs @@ -1,7 +1,7 @@ //! RTC driver. mod filter; -use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; +use embassy_hal_internal::{Peri, PeripheralType}; pub use self::filter::DateTimeFilter; @@ -14,7 +14,7 @@ use crate::clocks::clk_rtc_freq; /// A reference to the real time clock of the system pub struct Rtc<'d, T: Instance> { - inner: PeripheralRef<'d, T>, + inner: Peri<'d, T>, } impl<'d, T: Instance> Rtc<'d, T> { @@ -23,9 +23,7 @@ impl<'d, T: Instance> Rtc<'d, T> { /// # Errors /// /// Will return `RtcError::InvalidDateTime` if the datetime is not a valid range. - pub fn new(inner: impl Peripheral

+ 'd) -> Self { - into_ref!(inner); - + pub fn new(inner: Peri<'d, T>) -> Self { // Set the RTC divider inner.regs().clkdiv_m1().write(|w| w.set_clkdiv_m1(clk_rtc_freq() - 1)); @@ -194,7 +192,7 @@ trait SealedInstance { /// RTC peripheral instance. #[allow(private_bounds)] -pub trait Instance: SealedInstance {} +pub trait Instance: SealedInstance + PeripheralType {} impl SealedInstance for crate::peripherals::RTC { fn regs(&self) -> crate::pac::rtc::Rtc { diff --git a/embassy-rp/src/spi.rs b/embassy-rp/src/spi.rs index c48b5c54f..559b3b909 100644 --- a/embassy-rp/src/spi.rs +++ b/embassy-rp/src/spi.rs @@ -3,12 +3,12 @@ use core::marker::PhantomData; use embassy_embedded_hal::SetConfig; use embassy_futures::join::join; -use embassy_hal_internal::{into_ref, PeripheralRef}; +use embassy_hal_internal::{Peri, PeripheralType}; pub use embedded_hal_02::spi::{Phase, Polarity}; use crate::dma::{AnyChannel, Channel}; use crate::gpio::{AnyPin, Pin as GpioPin, SealedPin as _}; -use crate::{pac, peripherals, Peripheral}; +use crate::{pac, peripherals}; /// SPI errors. #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -42,9 +42,9 @@ impl Default for Config { /// SPI driver. pub struct Spi<'d, T: Instance, M: Mode> { - inner: PeripheralRef<'d, T>, - tx_dma: Option>, - rx_dma: Option>, + inner: Peri<'d, T>, + tx_dma: Option>, + rx_dma: Option>, phantom: PhantomData<(&'d mut T, M)>, } @@ -73,17 +73,15 @@ fn calc_prescs(freq: u32) -> (u8, u8) { impl<'d, T: Instance, M: Mode> Spi<'d, T, M> { fn new_inner( - inner: impl Peripheral

+ 'd, - clk: Option>, - mosi: Option>, - miso: Option>, - cs: Option>, - tx_dma: Option>, - rx_dma: Option>, + inner: Peri<'d, T>, + clk: Option>, + mosi: Option>, + miso: Option>, + cs: Option>, + tx_dma: Option>, + rx_dma: Option>, config: Config, ) -> Self { - into_ref!(inner); - Self::apply_config(&inner, &config); let p = inner.regs(); @@ -161,7 +159,7 @@ impl<'d, T: Instance, M: Mode> Spi<'d, T, M> { /// /// Driver should be disabled before making changes and reenabled after the modifications /// are applied. - fn apply_config(inner: &PeripheralRef<'d, T>, config: &Config) { + fn apply_config(inner: &Peri<'d, T>, config: &Config) { let p = inner.regs(); let (presc, postdiv) = calc_prescs(config.frequency); @@ -273,18 +271,17 @@ impl<'d, T: Instance, M: Mode> Spi<'d, T, M> { impl<'d, T: Instance> Spi<'d, T, Blocking> { /// Create an SPI driver in blocking mode. pub fn new_blocking( - inner: impl Peripheral

+ 'd, - clk: impl Peripheral

+ 'd> + 'd, - mosi: impl Peripheral

+ 'd> + 'd, - miso: impl Peripheral

+ 'd> + 'd, + inner: Peri<'d, T>, + clk: Peri<'d, impl ClkPin + 'd>, + mosi: Peri<'d, impl MosiPin + 'd>, + miso: Peri<'d, impl MisoPin + 'd>, config: Config, ) -> Self { - into_ref!(clk, mosi, miso); Self::new_inner( inner, - Some(clk.map_into()), - Some(mosi.map_into()), - Some(miso.map_into()), + Some(clk.into()), + Some(mosi.into()), + Some(miso.into()), None, None, None, @@ -294,16 +291,15 @@ impl<'d, T: Instance> Spi<'d, T, Blocking> { /// Create an SPI driver in blocking mode supporting writes only. pub fn new_blocking_txonly( - inner: impl Peripheral

+ 'd, - clk: impl Peripheral

+ 'd> + 'd, - mosi: impl Peripheral

+ 'd> + 'd, + inner: Peri<'d, T>, + clk: Peri<'d, impl ClkPin + 'd>, + mosi: Peri<'d, impl MosiPin + 'd>, config: Config, ) -> Self { - into_ref!(clk, mosi); Self::new_inner( inner, - Some(clk.map_into()), - Some(mosi.map_into()), + Some(clk.into()), + Some(mosi.into()), None, None, None, @@ -314,17 +310,16 @@ impl<'d, T: Instance> Spi<'d, T, Blocking> { /// Create an SPI driver in blocking mode supporting reads only. pub fn new_blocking_rxonly( - inner: impl Peripheral

+ 'd, - clk: impl Peripheral

+ 'd> + 'd, - miso: impl Peripheral

+ 'd> + 'd, + inner: Peri<'d, T>, + clk: Peri<'d, impl ClkPin + 'd>, + miso: Peri<'d, impl MisoPin + 'd>, config: Config, ) -> Self { - into_ref!(clk, miso); Self::new_inner( inner, - Some(clk.map_into()), + Some(clk.into()), None, - Some(miso.map_into()), + Some(miso.into()), None, None, None, @@ -336,43 +331,41 @@ impl<'d, T: Instance> Spi<'d, T, Blocking> { impl<'d, T: Instance> Spi<'d, T, Async> { /// Create an SPI driver in async mode supporting DMA operations. pub fn new( - inner: impl Peripheral

+ 'd, - clk: impl Peripheral

+ 'd> + 'd, - mosi: impl Peripheral

+ 'd> + 'd, - miso: impl Peripheral

+ 'd> + 'd, - tx_dma: impl Peripheral

+ 'd, - rx_dma: impl Peripheral

+ 'd, + inner: Peri<'d, T>, + clk: Peri<'d, impl ClkPin + 'd>, + mosi: Peri<'d, impl MosiPin + 'd>, + miso: Peri<'d, impl MisoPin + 'd>, + tx_dma: Peri<'d, impl Channel>, + rx_dma: Peri<'d, impl Channel>, config: Config, ) -> Self { - into_ref!(tx_dma, rx_dma, clk, mosi, miso); Self::new_inner( inner, - Some(clk.map_into()), - Some(mosi.map_into()), - Some(miso.map_into()), + Some(clk.into()), + Some(mosi.into()), + Some(miso.into()), None, - Some(tx_dma.map_into()), - Some(rx_dma.map_into()), + Some(tx_dma.into()), + Some(rx_dma.into()), config, ) } /// Create an SPI driver in async mode supporting DMA write operations only. pub fn new_txonly( - inner: impl Peripheral

+ 'd, - clk: impl Peripheral

+ 'd> + 'd, - mosi: impl Peripheral

+ 'd> + 'd, - tx_dma: impl Peripheral

+ 'd, + inner: Peri<'d, T>, + clk: Peri<'d, impl ClkPin + 'd>, + mosi: Peri<'d, impl MosiPin + 'd>, + tx_dma: Peri<'d, impl Channel>, config: Config, ) -> Self { - into_ref!(tx_dma, clk, mosi); Self::new_inner( inner, - Some(clk.map_into()), - Some(mosi.map_into()), + Some(clk.into()), + Some(mosi.into()), None, None, - Some(tx_dma.map_into()), + Some(tx_dma.into()), None, config, ) @@ -380,29 +373,28 @@ impl<'d, T: Instance> Spi<'d, T, Async> { /// Create an SPI driver in async mode supporting DMA read operations only. pub fn new_rxonly( - inner: impl Peripheral

+ 'd, - clk: impl Peripheral

+ 'd> + 'd, - miso: impl Peripheral

+ 'd> + 'd, - tx_dma: impl Peripheral

+ 'd, - rx_dma: impl Peripheral

+ 'd, + inner: Peri<'d, T>, + clk: Peri<'d, impl ClkPin + 'd>, + miso: Peri<'d, impl MisoPin + 'd>, + tx_dma: Peri<'d, impl Channel>, + rx_dma: Peri<'d, impl Channel>, config: Config, ) -> Self { - into_ref!(tx_dma, rx_dma, clk, miso); Self::new_inner( inner, - Some(clk.map_into()), + Some(clk.into()), None, - Some(miso.map_into()), + Some(miso.into()), None, - Some(tx_dma.map_into()), - Some(rx_dma.map_into()), + Some(tx_dma.into()), + Some(rx_dma.into()), config, ) } /// Write data to SPI using DMA. pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> { - let tx_ch = self.tx_dma.as_mut().unwrap(); + let tx_ch = self.tx_dma.as_mut().unwrap().reborrow(); let tx_transfer = unsafe { // If we don't assign future to a variable, the data register pointer // is held across an await and makes the future non-Send. @@ -427,14 +419,14 @@ impl<'d, T: Instance> Spi<'d, T, Async> { pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { // Start RX first. Transfer starts when TX starts, if RX // is not started yet we might lose bytes. - let rx_ch = self.rx_dma.as_mut().unwrap(); + let rx_ch = self.rx_dma.as_mut().unwrap().reborrow(); let rx_transfer = unsafe { // If we don't assign future to a variable, the data register pointer // is held across an await and makes the future non-Send. crate::dma::read(rx_ch, self.inner.regs().dr().as_ptr() as *const _, buffer, T::RX_DREQ) }; - let tx_ch = self.tx_dma.as_mut().unwrap(); + let tx_ch = self.tx_dma.as_mut().unwrap().reborrow(); let tx_transfer = unsafe { // If we don't assign future to a variable, the data register pointer // is held across an await and makes the future non-Send. @@ -462,20 +454,20 @@ impl<'d, T: Instance> Spi<'d, T, Async> { async fn transfer_inner(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(), Error> { // Start RX first. Transfer starts when TX starts, if RX // is not started yet we might lose bytes. - let rx_ch = self.rx_dma.as_mut().unwrap(); + let rx_ch = self.rx_dma.as_mut().unwrap().reborrow(); let rx_transfer = unsafe { // If we don't assign future to a variable, the data register pointer // is held across an await and makes the future non-Send. crate::dma::read(rx_ch, self.inner.regs().dr().as_ptr() as *const _, rx, T::RX_DREQ) }; - let mut tx_ch = self.tx_dma.as_mut().unwrap(); + let mut tx_ch = self.tx_dma.as_mut().unwrap().reborrow(); // If we don't assign future to a variable, the data register pointer // is held across an await and makes the future non-Send. let tx_transfer = async { let p = self.inner.regs(); unsafe { - crate::dma::write(&mut tx_ch, tx, p.dr().as_ptr() as *mut _, T::TX_DREQ).await; + crate::dma::write(tx_ch.reborrow(), tx, p.dr().as_ptr() as *mut _, T::TX_DREQ).await; if rx.len() > tx.len() { let write_bytes_len = rx.len() - tx.len(); @@ -519,7 +511,7 @@ pub trait Mode: SealedMode {} /// SPI instance trait. #[allow(private_bounds)] -pub trait Instance: SealedInstance {} +pub trait Instance: SealedInstance + PeripheralType {} macro_rules! impl_instance { ($type:ident, $irq:ident, $tx_dreq:expr, $rx_dreq:expr) => { diff --git a/embassy-rp/src/trng.rs b/embassy-rp/src/trng.rs index 9f2f33c4b..44b1bb996 100644 --- a/embassy-rp/src/trng.rs +++ b/embassy-rp/src/trng.rs @@ -5,7 +5,7 @@ use core::marker::PhantomData; use core::ops::Not; use core::task::Poll; -use embassy_hal_internal::Peripheral; +use embassy_hal_internal::{Peri, PeripheralType}; use embassy_sync::waitqueue::AtomicWaker; use rand_core::Error; @@ -20,7 +20,7 @@ trait SealedInstance { /// TRNG peripheral instance. #[allow(private_bounds)] -pub trait Instance: SealedInstance { +pub trait Instance: SealedInstance + PeripheralType { /// Interrupt for this peripheral. type Interrupt: Interrupt; } @@ -158,11 +158,7 @@ const TRNG_BLOCK_SIZE_BYTES: usize = TRNG_BLOCK_SIZE_BITS / 8; impl<'d, T: Instance> Trng<'d, T> { /// Create a new TRNG driver. - pub fn new( - _trng: impl Peripheral

+ 'd, - _irq: impl Binding> + 'd, - config: Config, - ) -> Self { + pub fn new(_trng: Peri<'d, T>, _irq: impl Binding> + 'd, config: Config) -> Self { let regs = T::regs(); regs.rng_imr().write(|w| w.set_ehr_valid_int_mask(false)); diff --git a/embassy-rp/src/uart/buffered.rs b/embassy-rp/src/uart/buffered.rs index 152a432c9..5b5159d22 100644 --- a/embassy-rp/src/uart/buffered.rs +++ b/embassy-rp/src/uart/buffered.rs @@ -90,17 +90,15 @@ pub(crate) fn init_buffers<'d, T: Instance + 'd>( impl<'d, T: Instance> BufferedUart<'d, T> { /// Create a buffered UART instance. pub fn new( - _uart: impl Peripheral

+ 'd, + _uart: Peri<'d, T>, irq: impl Binding>, - tx: impl Peripheral

> + 'd, - rx: impl Peripheral

> + 'd, + tx: Peri<'d, impl TxPin>, + rx: Peri<'d, impl RxPin>, tx_buffer: &'d mut [u8], rx_buffer: &'d mut [u8], config: Config, ) -> Self { - into_ref!(tx, rx); - - super::Uart::<'d, T, Async>::init(Some(tx.map_into()), Some(rx.map_into()), None, None, config); + super::Uart::<'d, T, Async>::init(Some(tx.into()), Some(rx.into()), None, None, config); init_buffers::(irq, Some(tx_buffer), Some(rx_buffer)); Self { @@ -111,23 +109,21 @@ impl<'d, T: Instance> BufferedUart<'d, T> { /// Create a buffered UART instance with flow control. pub fn new_with_rtscts( - _uart: impl Peripheral

+ 'd, + _uart: Peri<'d, T>, irq: impl Binding>, - tx: impl Peripheral

> + 'd, - rx: impl Peripheral

> + 'd, - rts: impl Peripheral

> + 'd, - cts: impl Peripheral

> + 'd, + tx: Peri<'d, impl TxPin>, + rx: Peri<'d, impl RxPin>, + rts: Peri<'d, impl RtsPin>, + cts: Peri<'d, impl CtsPin>, tx_buffer: &'d mut [u8], rx_buffer: &'d mut [u8], config: Config, ) -> Self { - into_ref!(tx, rx, cts, rts); - super::Uart::<'d, T, Async>::init( - Some(tx.map_into()), - Some(rx.map_into()), - Some(rts.map_into()), - Some(cts.map_into()), + Some(tx.into()), + Some(rx.into()), + Some(rts.into()), + Some(cts.into()), config, ); init_buffers::(irq, Some(tx_buffer), Some(rx_buffer)); @@ -184,15 +180,13 @@ impl<'d, T: Instance> BufferedUart<'d, T> { impl<'d, T: Instance> BufferedUartRx<'d, T> { /// Create a new buffered UART RX. pub fn new( - _uart: impl Peripheral

+ 'd, + _uart: Peri<'d, T>, irq: impl Binding>, - rx: impl Peripheral

> + 'd, + rx: Peri<'d, impl RxPin>, rx_buffer: &'d mut [u8], config: Config, ) -> Self { - into_ref!(rx); - - super::Uart::<'d, T, Async>::init(None, Some(rx.map_into()), None, None, config); + super::Uart::<'d, T, Async>::init(None, Some(rx.into()), None, None, config); init_buffers::(irq, None, Some(rx_buffer)); Self { phantom: PhantomData } @@ -200,16 +194,14 @@ impl<'d, T: Instance> BufferedUartRx<'d, T> { /// Create a new buffered UART RX with flow control. pub fn new_with_rts( - _uart: impl Peripheral

+ 'd, + _uart: Peri<'d, T>, irq: impl Binding>, - rx: impl Peripheral

> + 'd, - rts: impl Peripheral

> + 'd, + rx: Peri<'d, impl RxPin>, + rts: Peri<'d, impl RtsPin>, rx_buffer: &'d mut [u8], config: Config, ) -> Self { - into_ref!(rx, rts); - - super::Uart::<'d, T, Async>::init(None, Some(rx.map_into()), Some(rts.map_into()), None, config); + super::Uart::<'d, T, Async>::init(None, Some(rx.into()), Some(rts.into()), None, config); init_buffers::(irq, None, Some(rx_buffer)); Self { phantom: PhantomData } @@ -338,15 +330,13 @@ impl<'d, T: Instance> BufferedUartRx<'d, T> { impl<'d, T: Instance> BufferedUartTx<'d, T> { /// Create a new buffered UART TX. pub fn new( - _uart: impl Peripheral

+ 'd, + _uart: Peri<'d, T>, irq: impl Binding>, - tx: impl Peripheral

> + 'd, + tx: Peri<'d, impl TxPin>, tx_buffer: &'d mut [u8], config: Config, ) -> Self { - into_ref!(tx); - - super::Uart::<'d, T, Async>::init(Some(tx.map_into()), None, None, None, config); + super::Uart::<'d, T, Async>::init(Some(tx.into()), None, None, None, config); init_buffers::(irq, Some(tx_buffer), None); Self { phantom: PhantomData } @@ -354,16 +344,14 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> { /// Create a new buffered UART TX with flow control. pub fn new_with_cts( - _uart: impl Peripheral

+ 'd, + _uart: Peri<'d, T>, irq: impl Binding>, - tx: impl Peripheral

> + 'd, - cts: impl Peripheral

> + 'd, + tx: Peri<'d, impl TxPin>, + cts: Peri<'d, impl CtsPin>, tx_buffer: &'d mut [u8], config: Config, ) -> Self { - into_ref!(tx, cts); - - super::Uart::<'d, T, Async>::init(Some(tx.map_into()), None, None, Some(cts.map_into()), config); + super::Uart::<'d, T, Async>::init(Some(tx.into()), None, None, Some(cts.into()), config); init_buffers::(irq, Some(tx_buffer), None); Self { phantom: PhantomData } diff --git a/embassy-rp/src/uart/mod.rs b/embassy-rp/src/uart/mod.rs index 8d12aeef6..90c7655be 100644 --- a/embassy-rp/src/uart/mod.rs +++ b/embassy-rp/src/uart/mod.rs @@ -5,7 +5,7 @@ use core::task::Poll; use atomic_polyfill::{AtomicU16, Ordering}; use embassy_futures::select::{select, Either}; -use embassy_hal_internal::{into_ref, PeripheralRef}; +use embassy_hal_internal::{Peri, PeripheralType}; use embassy_sync::waitqueue::AtomicWaker; use embassy_time::{Delay, Timer}; use pac::uart::regs::Uartris; @@ -15,7 +15,7 @@ use crate::dma::{AnyChannel, Channel}; use crate::gpio::{AnyPin, SealedPin}; use crate::interrupt::typelevel::{Binding, Interrupt}; use crate::pac::io::vals::{Inover, Outover}; -use crate::{interrupt, pac, peripherals, Peripheral, RegExt}; +use crate::{interrupt, pac, peripherals, RegExt}; mod buffered; pub use buffered::{BufferedInterruptHandler, BufferedUart, BufferedUartRx, BufferedUartTx}; @@ -142,30 +142,29 @@ pub struct Uart<'d, T: Instance, M: Mode> { /// UART TX driver. pub struct UartTx<'d, T: Instance, M: Mode> { - tx_dma: Option>, + tx_dma: Option>, phantom: PhantomData<(&'d mut T, M)>, } /// UART RX driver. pub struct UartRx<'d, T: Instance, M: Mode> { - rx_dma: Option>, + rx_dma: Option>, phantom: PhantomData<(&'d mut T, M)>, } impl<'d, T: Instance, M: Mode> UartTx<'d, T, M> { /// Create a new DMA-enabled UART which can only send data pub fn new( - _uart: impl Peripheral

+ 'd, - tx: impl Peripheral

> + 'd, - tx_dma: impl Peripheral

+ 'd, + _uart: Peri<'d, T>, + tx: Peri<'d, impl TxPin>, + tx_dma: Peri<'d, impl Channel>, config: Config, ) -> Self { - into_ref!(tx, tx_dma); - Uart::::init(Some(tx.map_into()), None, None, None, config); - Self::new_inner(Some(tx_dma.map_into())) + Uart::::init(Some(tx.into()), None, None, None, config); + Self::new_inner(Some(tx_dma.into())) } - fn new_inner(tx_dma: Option>) -> Self { + fn new_inner(tx_dma: Option>) -> Self { Self { tx_dma, phantom: PhantomData, @@ -225,13 +224,8 @@ impl<'d, T: Instance, M: Mode> UartTx<'d, T, M> { impl<'d, T: Instance> UartTx<'d, T, Blocking> { /// Create a new UART TX instance for blocking mode operations. - pub fn new_blocking( - _uart: impl Peripheral

+ 'd, - tx: impl Peripheral

> + 'd, - config: Config, - ) -> Self { - into_ref!(tx); - Uart::::init(Some(tx.map_into()), None, None, None, config); + pub fn new_blocking(_uart: Peri<'d, T>, tx: Peri<'d, impl TxPin>, config: Config) -> Self { + Uart::::init(Some(tx.into()), None, None, None, config); Self::new_inner(None) } @@ -251,7 +245,7 @@ impl<'d, T: Instance> UartTx<'d, T, Blocking> { impl<'d, T: Instance> UartTx<'d, T, Async> { /// Write to UART TX from the provided buffer using DMA. pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> { - let ch = self.tx_dma.as_mut().unwrap(); + let ch = self.tx_dma.as_mut().unwrap().reborrow(); let transfer = unsafe { T::regs().uartdmacr().write_set(|reg| { reg.set_txdmae(true); @@ -268,18 +262,17 @@ impl<'d, T: Instance> UartTx<'d, T, Async> { impl<'d, T: Instance, M: Mode> UartRx<'d, T, M> { /// Create a new DMA-enabled UART which can only receive data pub fn new( - _uart: impl Peripheral

+ 'd, - rx: impl Peripheral

> + 'd, + _uart: Peri<'d, T>, + rx: Peri<'d, impl RxPin>, _irq: impl Binding>, - rx_dma: impl Peripheral

+ 'd, + rx_dma: Peri<'d, impl Channel>, config: Config, ) -> Self { - into_ref!(rx, rx_dma); - Uart::::init(None, Some(rx.map_into()), None, None, config); - Self::new_inner(true, Some(rx_dma.map_into())) + Uart::::init(None, Some(rx.into()), None, None, config); + Self::new_inner(true, Some(rx_dma.into())) } - fn new_inner(has_irq: bool, rx_dma: Option>) -> Self { + fn new_inner(has_irq: bool, rx_dma: Option>) -> Self { debug_assert_eq!(has_irq, rx_dma.is_some()); if has_irq { // disable all error interrupts initially @@ -346,13 +339,8 @@ impl<'d, T: Instance, M: Mode> Drop for UartRx<'d, T, M> { impl<'d, T: Instance> UartRx<'d, T, Blocking> { /// Create a new UART RX instance for blocking mode operations. - pub fn new_blocking( - _uart: impl Peripheral

+ 'd, - rx: impl Peripheral

> + 'd, - config: Config, - ) -> Self { - into_ref!(rx); - Uart::::init(None, Some(rx.map_into()), None, None, config); + pub fn new_blocking(_uart: Peri<'d, T>, rx: Peri<'d, impl RxPin>, config: Config) -> Self { + Uart::::init(None, Some(rx.into()), None, None, config); Self::new_inner(false, None) } @@ -419,7 +407,7 @@ impl<'d, T: Instance> UartRx<'d, T, Async> { // start a dma transfer. if errors have happened in the interim some error // interrupt flags will have been raised, and those will be picked up immediately // by the interrupt handler. - let ch = self.rx_dma.as_mut().unwrap(); + let ch = self.rx_dma.as_mut().unwrap().reborrow(); T::regs().uartimsc().write_set(|w| { w.set_oeim(true); w.set_beim(true); @@ -566,7 +554,7 @@ impl<'d, T: Instance> UartRx<'d, T, Async> { // start a dma transfer. if errors have happened in the interim some error // interrupt flags will have been raised, and those will be picked up immediately // by the interrupt handler. - let mut ch = self.rx_dma.as_mut().unwrap(); + let ch = self.rx_dma.as_mut().unwrap(); T::regs().uartimsc().write_set(|w| { w.set_oeim(true); w.set_beim(true); @@ -583,7 +571,7 @@ impl<'d, T: Instance> UartRx<'d, T, Async> { // If we don't assign future to a variable, the data register pointer // is held across an await and makes the future non-Send. crate::dma::read( - &mut ch, + ch.reborrow(), T::regs().uartdr().as_ptr() as *const _, sbuffer, T::RX_DREQ.into(), @@ -700,41 +688,29 @@ impl<'d, T: Instance> UartRx<'d, T, Async> { impl<'d, T: Instance> Uart<'d, T, Blocking> { /// Create a new UART without hardware flow control pub fn new_blocking( - uart: impl Peripheral

+ 'd, - tx: impl Peripheral

> + 'd, - rx: impl Peripheral

> + 'd, + uart: Peri<'d, T>, + tx: Peri<'d, impl TxPin>, + rx: Peri<'d, impl RxPin>, config: Config, ) -> Self { - into_ref!(tx, rx); - Self::new_inner( - uart, - tx.map_into(), - rx.map_into(), - None, - None, - false, - None, - None, - config, - ) + Self::new_inner(uart, tx.into(), rx.into(), None, None, false, None, None, config) } /// Create a new UART with hardware flow control (RTS/CTS) pub fn new_with_rtscts_blocking( - uart: impl Peripheral

+ 'd, - tx: impl Peripheral

> + 'd, - rx: impl Peripheral

> + 'd, - rts: impl Peripheral

> + 'd, - cts: impl Peripheral

> + 'd, + uart: Peri<'d, T>, + tx: Peri<'d, impl TxPin>, + rx: Peri<'d, impl RxPin>, + rts: Peri<'d, impl RtsPin>, + cts: Peri<'d, impl CtsPin>, config: Config, ) -> Self { - into_ref!(tx, rx, cts, rts); Self::new_inner( uart, - tx.map_into(), - rx.map_into(), - Some(rts.map_into()), - Some(cts.map_into()), + tx.into(), + rx.into(), + Some(rts.into()), + Some(cts.into()), false, None, None, @@ -762,50 +738,48 @@ impl<'d, T: Instance> Uart<'d, T, Blocking> { impl<'d, T: Instance> Uart<'d, T, Async> { /// Create a new DMA enabled UART without hardware flow control pub fn new( - uart: impl Peripheral

+ 'd, - tx: impl Peripheral

> + 'd, - rx: impl Peripheral

> + 'd, + uart: Peri<'d, T>, + tx: Peri<'d, impl TxPin>, + rx: Peri<'d, impl RxPin>, _irq: impl Binding>, - tx_dma: impl Peripheral

+ 'd, - rx_dma: impl Peripheral

+ 'd, + tx_dma: Peri<'d, impl Channel>, + rx_dma: Peri<'d, impl Channel>, config: Config, ) -> Self { - into_ref!(tx, rx, tx_dma, rx_dma); Self::new_inner( uart, - tx.map_into(), - rx.map_into(), + tx.into(), + rx.into(), None, None, true, - Some(tx_dma.map_into()), - Some(rx_dma.map_into()), + Some(tx_dma.into()), + Some(rx_dma.into()), config, ) } /// Create a new DMA enabled UART with hardware flow control (RTS/CTS) pub fn new_with_rtscts( - uart: impl Peripheral

+ 'd, - tx: impl Peripheral

> + 'd, - rx: impl Peripheral

> + 'd, - rts: impl Peripheral

> + 'd, - cts: impl Peripheral

> + 'd, + uart: Peri<'d, T>, + tx: Peri<'d, impl TxPin>, + rx: Peri<'d, impl RxPin>, + rts: Peri<'d, impl RtsPin>, + cts: Peri<'d, impl CtsPin>, _irq: impl Binding>, - tx_dma: impl Peripheral

+ 'd, - rx_dma: impl Peripheral

+ 'd, + tx_dma: Peri<'d, impl Channel>, + rx_dma: Peri<'d, impl Channel>, config: Config, ) -> Self { - into_ref!(tx, rx, cts, rts, tx_dma, rx_dma); Self::new_inner( uart, - tx.map_into(), - rx.map_into(), - Some(rts.map_into()), - Some(cts.map_into()), + tx.into(), + rx.into(), + Some(rts.into()), + Some(cts.into()), true, - Some(tx_dma.map_into()), - Some(rx_dma.map_into()), + Some(tx_dma.into()), + Some(rx_dma.into()), config, ) } @@ -813,14 +787,14 @@ impl<'d, T: Instance> Uart<'d, T, Async> { impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> { fn new_inner( - _uart: impl Peripheral

+ 'd, - mut tx: PeripheralRef<'d, AnyPin>, - mut rx: PeripheralRef<'d, AnyPin>, - mut rts: Option>, - mut cts: Option>, + _uart: Peri<'d, T>, + mut tx: Peri<'d, AnyPin>, + mut rx: Peri<'d, AnyPin>, + mut rts: Option>, + mut cts: Option>, has_irq: bool, - tx_dma: Option>, - rx_dma: Option>, + tx_dma: Option>, + rx_dma: Option>, config: Config, ) -> Self { Self::init( @@ -838,10 +812,10 @@ impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> { } fn init( - tx: Option>, - rx: Option>, - rts: Option>, - cts: Option>, + tx: Option>, + rx: Option>, + rts: Option>, + cts: Option>, config: Config, ) { let r = T::regs(); @@ -1326,7 +1300,7 @@ impl_mode!(Async); /// UART instance. #[allow(private_bounds)] -pub trait Instance: SealedInstance { +pub trait Instance: SealedInstance + PeripheralType { /// Interrupt for this instance. type Interrupt: interrupt::typelevel::Interrupt; } diff --git a/embassy-rp/src/usb.rs b/embassy-rp/src/usb.rs index 26cb90d89..96541ade6 100644 --- a/embassy-rp/src/usb.rs +++ b/embassy-rp/src/usb.rs @@ -5,6 +5,7 @@ use core::slice; use core::sync::atomic::{compiler_fence, Ordering}; use core::task::Poll; +use embassy_hal_internal::PeripheralType; use embassy_sync::waitqueue::AtomicWaker; use embassy_usb_driver as driver; use embassy_usb_driver::{ @@ -12,7 +13,7 @@ use embassy_usb_driver::{ }; use crate::interrupt::typelevel::{Binding, Interrupt}; -use crate::{interrupt, pac, peripherals, Peripheral, RegExt}; +use crate::{interrupt, pac, peripherals, Peri, RegExt}; trait SealedInstance { fn regs() -> crate::pac::usb::Usb; @@ -21,7 +22,7 @@ trait SealedInstance { /// USB peripheral instance. #[allow(private_bounds)] -pub trait Instance: SealedInstance + 'static { +pub trait Instance: SealedInstance + PeripheralType + 'static { /// Interrupt for this peripheral. type Interrupt: interrupt::typelevel::Interrupt; } @@ -107,7 +108,7 @@ pub struct Driver<'d, T: Instance> { impl<'d, T: Instance> Driver<'d, T> { /// Create a new USB driver. - pub fn new(_usb: impl Peripheral

+ 'd, _irq: impl Binding>) -> Self { + pub fn new(_usb: Peri<'d, T>, _irq: impl Binding>) -> Self { T::Interrupt::unpend(); unsafe { T::Interrupt::enable() }; diff --git a/embassy-rp/src/watchdog.rs b/embassy-rp/src/watchdog.rs index 553936602..760d6aac2 100644 --- a/embassy-rp/src/watchdog.rs +++ b/embassy-rp/src/watchdog.rs @@ -10,8 +10,8 @@ use core::marker::PhantomData; use embassy_time::Duration; -use crate::pac; use crate::peripherals::WATCHDOG; +use crate::{pac, Peri}; /// The reason for a system reset from the watchdog. #[derive(Debug, Copy, Clone, PartialEq, Eq)] @@ -30,7 +30,7 @@ pub struct Watchdog { impl Watchdog { /// Create a new `Watchdog` - pub fn new(_watchdog: WATCHDOG) -> Self { + pub fn new(_watchdog: Peri<'static, WATCHDOG>) -> Self { Self { phantom: PhantomData, load_value: 0, diff --git a/embassy-stm32-wpan/src/lib.rs b/embassy-stm32-wpan/src/lib.rs index 25e6d965a..40ff14795 100644 --- a/embassy-stm32-wpan/src/lib.rs +++ b/embassy-stm32-wpan/src/lib.rs @@ -23,7 +23,7 @@ mod fmt; use core::mem::MaybeUninit; use core::sync::atomic::{compiler_fence, Ordering}; -use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; +use embassy_hal_internal::Peri; use embassy_stm32::interrupt; use embassy_stm32::ipcc::{Config, Ipcc, ReceiveInterruptHandler, TransmitInterruptHandler}; use embassy_stm32::peripherals::IPCC; @@ -52,7 +52,7 @@ type PacketHeader = LinkedListNode; /// Transport Layer for the Mailbox interface pub struct TlMbox<'d> { - _ipcc: PeripheralRef<'d, IPCC>, + _ipcc: Peri<'d, IPCC>, pub sys_subsystem: Sys, pub mm_subsystem: MemoryManager, @@ -92,13 +92,11 @@ impl<'d> TlMbox<'d> { /// Figure 66. // TODO: document what the user should do after calling init to use the mac_802_15_4 subsystem pub fn init( - ipcc: impl Peripheral

+ 'd, + ipcc: Peri<'d, IPCC>, _irqs: impl interrupt::typelevel::Binding + interrupt::typelevel::Binding, config: Config, ) -> Self { - into_ref!(ipcc); - // this is an inlined version of TL_Init from the STM32WB firmware as requested by AN5289. // HW_IPCC_Init is not called, and its purpose is (presumably?) covered by this // implementation diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 8ca79eadf..798133162 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -324,7 +324,7 @@ fn main() { let region_type = format_ident!("{}", get_flash_region_type_name(region.name)); flash_regions.extend(quote! { #[cfg(flash)] - pub struct #region_type<'d, MODE = crate::flash::Async>(pub &'static crate::flash::FlashRegion, pub(crate) embassy_hal_internal::PeripheralRef<'d, crate::peripherals::FLASH>, pub(crate) core::marker::PhantomData); + pub struct #region_type<'d, MODE = crate::flash::Async>(pub &'static crate::flash::FlashRegion, pub(crate) embassy_hal_internal::Peri<'d, crate::peripherals::FLASH>, pub(crate) core::marker::PhantomData); }); } @@ -356,7 +356,7 @@ fn main() { #[cfg(flash)] impl<'d, MODE> FlashLayout<'d, MODE> { - pub(crate) fn new(p: embassy_hal_internal::PeripheralRef<'d, crate::peripherals::FLASH>) -> Self { + pub(crate) fn new(p: embassy_hal_internal::Peri<'d, crate::peripherals::FLASH>) -> Self { Self { #(#inits),*, _mode: core::marker::PhantomData, diff --git a/embassy-stm32/src/adc/c0.rs b/embassy-stm32/src/adc/c0.rs index 84763ad4f..a9c1d8faf 100644 --- a/embassy-stm32/src/adc/c0.rs +++ b/embassy-stm32/src/adc/c0.rs @@ -8,7 +8,7 @@ use super::{ }; use crate::dma::Transfer; use crate::time::Hertz; -use crate::{pac, rcc, Peripheral}; +use crate::{pac, rcc, Peri}; /// Default VREF voltage used for sample conversion to millivolts. pub const VREF_DEFAULT_MV: u32 = 3300; @@ -154,8 +154,7 @@ pub enum Averaging { impl<'d, T: Instance> Adc<'d, T> { /// Create a new ADC driver. - pub fn new(adc: impl Peripheral

+ 'd, sample_time: SampleTime, resolution: Resolution) -> Self { - embassy_hal_internal::into_ref!(adc); + pub fn new(adc: Peri<'d, T>, sample_time: SampleTime, resolution: Resolution) -> Self { rcc::enable_and_reset::(); T::regs().cfgr2().modify(|w| w.set_ckmode(Ckmode::SYSCLK)); @@ -319,7 +318,7 @@ impl<'d, T: Instance> Adc<'d, T> { Self::apply_channel_conf() } - async fn dma_convert(&mut self, rx_dma: &mut impl RxDma, readings: &mut [u16]) { + async fn dma_convert(&mut self, rx_dma: Peri<'_, impl RxDma>, readings: &mut [u16]) { // Enable overrun control, so no new DMA requests will be generated until // previous DR values is read. T::regs().isr().modify(|reg| { @@ -374,7 +373,7 @@ impl<'d, T: Instance> Adc<'d, T> { /// TODO(chudsaviet): externalize generic code and merge with read(). pub async fn read_in_hw_order( &mut self, - rx_dma: &mut impl RxDma, + rx_dma: Peri<'_, impl RxDma>, hw_channel_selection: u32, scandir: Scandir, readings: &mut [u16], @@ -415,7 +414,7 @@ impl<'d, T: Instance> Adc<'d, T> { // For other channels, use `read_in_hw_order()` or blocking read. pub async fn read( &mut self, - rx_dma: &mut impl RxDma, + rx_dma: Peri<'_, impl RxDma>, channel_sequence: impl ExactSizeIterator>, readings: &mut [u16], ) { diff --git a/embassy-stm32/src/adc/f1.rs b/embassy-stm32/src/adc/f1.rs index b37ec260f..fa6255c23 100644 --- a/embassy-stm32/src/adc/f1.rs +++ b/embassy-stm32/src/adc/f1.rs @@ -2,12 +2,10 @@ use core::future::poll_fn; use core::marker::PhantomData; use core::task::Poll; -use embassy_hal_internal::into_ref; - use super::blocking_delay_us; use crate::adc::{Adc, AdcChannel, Instance, SampleTime}; use crate::time::Hertz; -use crate::{interrupt, rcc, Peripheral}; +use crate::{interrupt, rcc, Peri}; pub const VDDA_CALIB_MV: u32 = 3300; pub const ADC_MAX: u32 = (1 << 12) - 1; @@ -48,8 +46,7 @@ impl super::SealedAdcChannel for Temperature { } impl<'d, T: Instance> Adc<'d, T> { - pub fn new(adc: impl Peripheral

+ 'd) -> Self { - into_ref!(adc); + pub fn new(adc: Peri<'d, T>) -> Self { rcc::enable_and_reset::(); T::regs().cr2().modify(|reg| reg.set_adon(true)); diff --git a/embassy-stm32/src/adc/f3.rs b/embassy-stm32/src/adc/f3.rs index 0ebeb8a9e..3aeb6f2c7 100644 --- a/embassy-stm32/src/adc/f3.rs +++ b/embassy-stm32/src/adc/f3.rs @@ -2,13 +2,11 @@ use core::future::poll_fn; use core::marker::PhantomData; use core::task::Poll; -use embassy_hal_internal::into_ref; - use super::blocking_delay_us; use crate::adc::{Adc, AdcChannel, Instance, SampleTime}; use crate::interrupt::typelevel::Interrupt; use crate::time::Hertz; -use crate::{interrupt, rcc, Peripheral}; +use crate::{interrupt, rcc, Peri}; pub const VDDA_CALIB_MV: u32 = 3300; pub const ADC_MAX: u32 = (1 << 12) - 1; @@ -56,13 +54,11 @@ impl super::SealedAdcChannel for Temperature { impl<'d, T: Instance> Adc<'d, T> { pub fn new( - adc: impl Peripheral

+ 'd, + adc: Peri<'d, T>, _irq: impl interrupt::typelevel::Binding> + 'd, ) -> Self { use crate::pac::adc::vals; - into_ref!(adc); - rcc::enable_and_reset::(); // Enable the adc regulator diff --git a/embassy-stm32/src/adc/f3_v1_1.rs b/embassy-stm32/src/adc/f3_v1_1.rs index 291a3861e..944e971bb 100644 --- a/embassy-stm32/src/adc/f3_v1_1.rs +++ b/embassy-stm32/src/adc/f3_v1_1.rs @@ -3,14 +3,13 @@ use core::marker::PhantomData; use core::task::Poll; use embassy_futures::yield_now; -use embassy_hal_internal::into_ref; use embassy_time::Instant; use super::Resolution; use crate::adc::{Adc, AdcChannel, Instance, SampleTime}; use crate::interrupt::typelevel::Interrupt; use crate::time::Hertz; -use crate::{interrupt, rcc, Peripheral}; +use crate::{interrupt, rcc, Peri}; const ADC_FREQ: Hertz = crate::rcc::HSI_FREQ; @@ -138,11 +137,9 @@ impl Drop for Temperature { impl<'d, T: Instance> Adc<'d, T> { pub fn new( - adc: impl Peripheral

+ 'd, + adc: Peri<'d, T>, _irq: impl interrupt::typelevel::Binding> + 'd, ) -> Self { - into_ref!(adc); - rcc::enable_and_reset::(); //let r = T::regs(); diff --git a/embassy-stm32/src/adc/g4.rs b/embassy-stm32/src/adc/g4.rs index 0291ef4de..6a00e788e 100644 --- a/embassy-stm32/src/adc/g4.rs +++ b/embassy-stm32/src/adc/g4.rs @@ -11,7 +11,7 @@ use super::{blocking_delay_us, Adc, AdcChannel, AnyAdcChannel, Instance, Resolut use crate::adc::SealedAdcChannel; use crate::dma::Transfer; use crate::time::Hertz; -use crate::{pac, rcc, Peripheral}; +use crate::{pac, rcc, Peri}; /// Default VREF voltage used for sample conversion to millivolts. pub const VREF_DEFAULT_MV: u32 = 3300; @@ -135,8 +135,7 @@ impl Prescaler { impl<'d, T: Instance> Adc<'d, T> { /// Create a new ADC driver. - pub fn new(adc: impl Peripheral

+ 'd) -> Self { - embassy_hal_internal::into_ref!(adc); + pub fn new(adc: Peri<'d, T>) -> Self { rcc::enable_and_reset::(); let prescaler = Prescaler::from_ker_ck(T::frequency()); @@ -364,8 +363,8 @@ impl<'d, T: Instance> Adc<'d, T> { /// use embassy_stm32::adc::{Adc, AdcChannel} /// /// let mut adc = Adc::new(p.ADC1); - /// let mut adc_pin0 = p.PA0.degrade_adc(); - /// let mut adc_pin1 = p.PA1.degrade_adc(); + /// let mut adc_pin0 = p.PA0.into(); + /// let mut adc_pin1 = p.PA1.into(); /// let mut measurements = [0u16; 2]; /// /// adc.read_async( @@ -382,7 +381,7 @@ impl<'d, T: Instance> Adc<'d, T> { /// ``` pub async fn read( &mut self, - rx_dma: &mut impl RxDma, + rx_dma: Peri<'_, impl RxDma>, sequence: impl ExactSizeIterator, SampleTime)>, readings: &mut [u16], ) { diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index 31a08b6eb..321db7431 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs @@ -22,6 +22,7 @@ use core::marker::PhantomData; #[allow(unused)] #[cfg(not(any(adc_f3_v2)))] pub use _version::*; +use embassy_hal_internal::{impl_peripheral, PeripheralType}; #[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))] use embassy_sync::waitqueue::AtomicWaker; @@ -42,7 +43,7 @@ dma_trait!(RxDma4, adc4::Instance); /// Analog to Digital driver. pub struct Adc<'d, T: Instance> { #[allow(unused)] - adc: crate::PeripheralRef<'d, T>, + adc: crate::Peri<'d, T>, #[cfg(not(any(adc_f3_v2, adc_f3_v1_1)))] sample_time: SampleTime, } @@ -111,7 +112,7 @@ pub(crate) fn blocking_delay_us(us: u32) { adc_c0 )))] #[allow(private_bounds)] -pub trait Instance: SealedInstance + crate::Peripheral

{ +pub trait Instance: SealedInstance + crate::PeripheralType { type Interrupt: crate::interrupt::typelevel::Interrupt; } /// ADC instance. @@ -132,7 +133,7 @@ pub trait Instance: SealedInstance + crate::Peripheral

{ adc_c0 ))] #[allow(private_bounds)] -pub trait Instance: SealedInstance + crate::Peripheral

+ crate::rcc::RccPeripheral { +pub trait Instance: SealedInstance + crate::PeripheralType + crate::rcc::RccPeripheral { type Interrupt: crate::interrupt::typelevel::Interrupt; } @@ -159,7 +160,7 @@ pub struct AnyAdcChannel { channel: u8, _phantom: PhantomData, } - +impl_peripheral!(AnyAdcChannel); impl AdcChannel for AnyAdcChannel {} impl SealedAdcChannel for AnyAdcChannel { fn channel(&self) -> u8 { @@ -233,11 +234,11 @@ foreach_adc!( macro_rules! impl_adc_pin { ($inst:ident, $pin:ident, $ch:expr) => { - impl crate::adc::AdcChannel for crate::peripherals::$pin {} - impl crate::adc::SealedAdcChannel for crate::peripherals::$pin { + impl crate::adc::AdcChannel for crate::Peri<'_, crate::peripherals::$pin> {} + impl crate::adc::SealedAdcChannel for crate::Peri<'_, crate::peripherals::$pin> { #[cfg(any(adc_v1, adc_c0, adc_l0, adc_v2, adc_g4, adc_v4, adc_u5))] fn setup(&mut self) { - ::set_as_analog(self); + ::set_as_analog(self); } fn channel(&self) -> u8 { diff --git a/embassy-stm32/src/adc/ringbuffered_v2.rs b/embassy-stm32/src/adc/ringbuffered_v2.rs index f3d1ca0ab..fabf0284b 100644 --- a/embassy-stm32/src/adc/ringbuffered_v2.rs +++ b/embassy-stm32/src/adc/ringbuffered_v2.rs @@ -2,13 +2,12 @@ use core::marker::PhantomData; use core::mem; use core::sync::atomic::{compiler_fence, Ordering}; -use embassy_hal_internal::{into_ref, Peripheral}; use stm32_metapac::adc::vals::SampleTime; use crate::adc::{Adc, AdcChannel, Instance, RxDma}; use crate::dma::{Priority, ReadableRingBuffer, TransferOptions}; use crate::pac::adc::vals; -use crate::rcc; +use crate::{rcc, Peri}; #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct OverrunError; @@ -103,13 +102,8 @@ impl<'d, T: Instance> Adc<'d, T> { /// It is critical to call `read` frequently to prevent DMA buffer overrun. /// /// [`read`]: #method.read - pub fn into_ring_buffered( - self, - dma: impl Peripheral

> + 'd, - dma_buf: &'d mut [u16], - ) -> RingBufferedAdc<'d, T> { + pub fn into_ring_buffered(self, dma: Peri<'d, impl RxDma>, dma_buf: &'d mut [u16]) -> RingBufferedAdc<'d, T> { assert!(!dma_buf.is_empty() && dma_buf.len() <= 0xFFFF); - into_ref!(dma); let opts: crate::dma::TransferOptions = TransferOptions { half_transfer_ir: true, diff --git a/embassy-stm32/src/adc/u5_adc4.rs b/embassy-stm32/src/adc/u5_adc4.rs index cec88d482..a5cfbfdcf 100644 --- a/embassy-stm32/src/adc/u5_adc4.rs +++ b/embassy-stm32/src/adc/u5_adc4.rs @@ -6,7 +6,7 @@ use crate::dma::Transfer; pub use crate::pac::adc::regs::Adc4Chselrmod0; pub use crate::pac::adc::vals::{Adc4Presc as Presc, Adc4Res as Resolution, Adc4SampleTime as SampleTime}; use crate::time::Hertz; -use crate::{pac, rcc, Peripheral}; +use crate::{pac, rcc, Peri}; const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(55); @@ -169,13 +169,13 @@ pub trait SealedInstance { fn regs() -> crate::pac::adc::Adc4; } -pub trait Instance: SealedInstance + crate::Peripheral

+ crate::rcc::RccPeripheral { +pub trait Instance: SealedInstance + crate::PeripheralType + crate::rcc::RccPeripheral { type Interrupt: crate::interrupt::typelevel::Interrupt; } pub struct Adc4<'d, T: Instance> { #[allow(unused)] - adc: crate::PeripheralRef<'d, T>, + adc: crate::Peri<'d, T>, } #[derive(Debug)] @@ -186,8 +186,7 @@ pub enum Adc4Error { impl<'d, T: Instance> Adc4<'d, T> { /// Create a new ADC driver. - pub fn new(adc: impl Peripheral

+ 'd) -> Self { - embassy_hal_internal::into_ref!(adc); + pub fn new(adc: Peri<'d, T>) -> Self { rcc::enable_and_reset::(); let prescaler = Prescaler::from_ker_ck(T::frequency()); @@ -379,15 +378,15 @@ impl<'d, T: Instance> Adc4<'d, T> { /// let mut adc4 = adc4::Adc4::new(p.ADC4); /// let mut adc4_pin1 = p.PC1; /// let mut adc4_pin2 = p.PC0; - /// let mut degraded41 = adc4_pin1.degrade_adc(); - /// let mut degraded42 = adc4_pin2.degrade_adc(); + /// let mut.into()d41 = adc4_pin1.into(); + /// let mut.into()d42 = adc4_pin2.into(); /// let mut measurements = [0u16; 2]; /// // not that the channels must be in ascending order /// adc4.read( /// &mut p.GPDMA1_CH1, /// [ - /// &mut degraded42, - /// &mut degraded41, + /// &mut.into()d42, + /// &mut.into()d41, /// ] /// .into_iter(), /// &mut measurements, @@ -395,7 +394,7 @@ impl<'d, T: Instance> Adc4<'d, T> { /// ``` pub async fn read( &mut self, - rx_dma: &mut impl RxDma4, + rx_dma: Peri<'_, impl RxDma4>, sequence: impl ExactSizeIterator>, readings: &mut [u16], ) -> Result<(), Adc4Error> { diff --git a/embassy-stm32/src/adc/v1.rs b/embassy-stm32/src/adc/v1.rs index d5cd14661..fb6f5b7d0 100644 --- a/embassy-stm32/src/adc/v1.rs +++ b/embassy-stm32/src/adc/v1.rs @@ -2,7 +2,6 @@ use core::future::poll_fn; use core::marker::PhantomData; use core::task::Poll; -use embassy_hal_internal::into_ref; #[cfg(adc_l0)] use stm32_metapac::adc::vals::Ckmode; @@ -10,7 +9,7 @@ use super::blocking_delay_us; use crate::adc::{Adc, AdcChannel, Instance, Resolution, SampleTime}; use crate::interrupt::typelevel::Interrupt; use crate::peripherals::ADC1; -use crate::{interrupt, rcc, Peripheral}; +use crate::{interrupt, rcc, Peri}; pub const VDDA_CALIB_MV: u32 = 3300; pub const VREF_INT: u32 = 1230; @@ -63,10 +62,9 @@ impl super::SealedAdcChannel for Temperature { impl<'d, T: Instance> Adc<'d, T> { pub fn new( - adc: impl Peripheral

+ 'd, + adc: Peri<'d, T>, _irq: impl interrupt::typelevel::Binding> + 'd, ) -> Self { - into_ref!(adc); rcc::enable_and_reset::(); // Delay 1μs when using HSI14 as the ADC clock. diff --git a/embassy-stm32/src/adc/v2.rs b/embassy-stm32/src/adc/v2.rs index 842a5ee6d..e94a25b24 100644 --- a/embassy-stm32/src/adc/v2.rs +++ b/embassy-stm32/src/adc/v2.rs @@ -1,10 +1,8 @@ -use embassy_hal_internal::into_ref; - use super::blocking_delay_us; use crate::adc::{Adc, AdcChannel, Instance, Resolution, SampleTime}; use crate::peripherals::ADC1; use crate::time::Hertz; -use crate::{rcc, Peripheral}; +use crate::{rcc, Peri}; mod ringbuffered_v2; pub use ringbuffered_v2::{RingBufferedAdc, Sequence}; @@ -97,8 +95,7 @@ impl<'d, T> Adc<'d, T> where T: Instance, { - pub fn new(adc: impl Peripheral

+ 'd) -> Self { - into_ref!(adc); + pub fn new(adc: Peri<'d, T>) -> Self { rcc::enable_and_reset::(); let presc = Prescaler::from_pclk2(T::frequency()); diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs index 7a608a44e..2de12d1d6 100644 --- a/embassy-stm32/src/adc/v3.rs +++ b/embassy-stm32/src/adc/v3.rs @@ -1,12 +1,11 @@ use cfg_if::cfg_if; -use embassy_hal_internal::into_ref; use pac::adc::vals::Dmacfg; use super::{ blocking_delay_us, Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, SealedAdcChannel, }; use crate::dma::Transfer; -use crate::{pac, rcc, Peripheral}; +use crate::{pac, rcc, Peri}; /// Default VREF voltage used for sample conversion to millivolts. pub const VREF_DEFAULT_MV: u32 = 3300; @@ -95,8 +94,7 @@ cfg_if! { } impl<'d, T: Instance> Adc<'d, T> { - pub fn new(adc: impl Peripheral

+ 'd) -> Self { - into_ref!(adc); + pub fn new(adc: Peri<'d, T>) -> Self { rcc::enable_and_reset::(); T::regs().cr().modify(|reg| { #[cfg(not(any(adc_g0, adc_u0)))] @@ -288,7 +286,7 @@ impl<'d, T: Instance> Adc<'d, T> { /// ``` pub async fn read( &mut self, - rx_dma: &mut impl RxDma, + rx_dma: Peri<'_, impl RxDma>, sequence: impl ExactSizeIterator, SampleTime)>, readings: &mut [u16], ) { diff --git a/embassy-stm32/src/adc/v4.rs b/embassy-stm32/src/adc/v4.rs index 9860efa8a..5910eef30 100644 --- a/embassy-stm32/src/adc/v4.rs +++ b/embassy-stm32/src/adc/v4.rs @@ -9,7 +9,7 @@ use super::{ }; use crate::dma::Transfer; use crate::time::Hertz; -use crate::{pac, rcc, Peripheral}; +use crate::{pac, rcc, Peri}; /// Default VREF voltage used for sample conversion to millivolts. pub const VREF_DEFAULT_MV: u32 = 3300; @@ -158,8 +158,7 @@ pub enum Averaging { impl<'d, T: Instance> Adc<'d, T> { /// Create a new ADC driver. - pub fn new(adc: impl Peripheral

+ 'd) -> Self { - embassy_hal_internal::into_ref!(adc); + pub fn new(adc: Peri<'d, T>) -> Self { rcc::enable_and_reset::(); let prescaler = Prescaler::from_ker_ck(T::frequency()); @@ -344,8 +343,8 @@ impl<'d, T: Instance> Adc<'d, T> { /// use embassy_stm32::adc::{Adc, AdcChannel} /// /// let mut adc = Adc::new(p.ADC1); - /// let mut adc_pin0 = p.PA0.degrade_adc(); - /// let mut adc_pin2 = p.PA2.degrade_adc(); + /// let mut adc_pin0 = p.PA0.into(); + /// let mut adc_pin2 = p.PA2.into(); /// let mut measurements = [0u16; 2]; /// /// adc.read_async( @@ -362,7 +361,7 @@ impl<'d, T: Instance> Adc<'d, T> { /// ``` pub async fn read( &mut self, - rx_dma: &mut impl RxDma, + rx_dma: Peri<'_, impl RxDma>, sequence: impl ExactSizeIterator, SampleTime)>, readings: &mut [u16], ) { diff --git a/embassy-stm32/src/can/bxcan/mod.rs b/embassy-stm32/src/can/bxcan/mod.rs index c0b3c730b..305666d5b 100644 --- a/embassy-stm32/src/can/bxcan/mod.rs +++ b/embassy-stm32/src/can/bxcan/mod.rs @@ -6,7 +6,7 @@ use core::marker::PhantomData; use core::task::Poll; use embassy_hal_internal::interrupt::InterruptExt; -use embassy_hal_internal::into_ref; +use embassy_hal_internal::PeripheralType; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::channel::Channel; use embassy_sync::waitqueue::AtomicWaker; @@ -21,7 +21,7 @@ use crate::can::enums::{BusError, InternalOperation, TryReadError}; use crate::gpio::{AfType, OutputType, Pull, Speed}; use crate::interrupt::typelevel::Interrupt; use crate::rcc::{self, RccPeripheral}; -use crate::{interrupt, peripherals, Peripheral}; +use crate::{interrupt, peripherals, Peri}; /// Interrupt handler. pub struct TxInterruptHandler { @@ -173,16 +173,15 @@ impl<'d> Can<'d> { /// Creates a new Bxcan instance, keeping the peripheral in sleep mode. /// You must call [Can::enable_non_blocking] to use the peripheral. pub fn new( - _peri: impl Peripheral

+ 'd, - rx: impl Peripheral

> + 'd, - tx: impl Peripheral

> + 'd, + _peri: Peri<'d, T>, + rx: Peri<'d, impl RxPin>, + tx: Peri<'d, impl TxPin>, _irqs: impl interrupt::typelevel::Binding> + interrupt::typelevel::Binding> + interrupt::typelevel::Binding> + interrupt::typelevel::Binding> + 'd, ) -> Self { - into_ref!(_peri, rx, tx); let info = T::info(); let regs = &T::info().regs; @@ -1083,7 +1082,7 @@ trait SealedInstance { /// CAN instance trait. #[allow(private_bounds)] -pub trait Instance: Peripheral

+ SealedInstance + RccPeripheral + 'static { +pub trait Instance: SealedInstance + PeripheralType + RccPeripheral + 'static { /// TX interrupt for this instance. type TXInterrupt: crate::interrupt::typelevel::Interrupt; /// RX0 interrupt for this instance. diff --git a/embassy-stm32/src/can/fdcan.rs b/embassy-stm32/src/can/fdcan.rs index f950b6f99..5467a40f1 100644 --- a/embassy-stm32/src/can/fdcan.rs +++ b/embassy-stm32/src/can/fdcan.rs @@ -4,7 +4,7 @@ use core::marker::PhantomData; use core::task::Poll; use embassy_hal_internal::interrupt::InterruptExt; -use embassy_hal_internal::{into_ref, PeripheralRef}; +use embassy_hal_internal::PeripheralType; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::channel::Channel; use embassy_sync::waitqueue::AtomicWaker; @@ -13,7 +13,7 @@ use crate::can::fd::peripheral::Registers; use crate::gpio::{AfType, OutputType, Pull, Speed}; use crate::interrupt::typelevel::Interrupt; use crate::rcc::{self, RccPeripheral}; -use crate::{interrupt, peripherals, Peripheral}; +use crate::{interrupt, peripherals, Peri}; pub(crate) mod fd; @@ -175,15 +175,13 @@ impl<'d> CanConfigurator<'d> { /// Creates a new Fdcan instance, keeping the peripheral in sleep mode. /// You must call [Fdcan::enable_non_blocking] to use the peripheral. pub fn new( - _peri: impl Peripheral

+ 'd, - rx: impl Peripheral

> + 'd, - tx: impl Peripheral

> + 'd, + _peri: Peri<'d, T>, + rx: Peri<'d, impl RxPin>, + tx: Peri<'d, impl TxPin>, _irqs: impl interrupt::typelevel::Binding> + interrupt::typelevel::Binding> + 'd, ) -> CanConfigurator<'d> { - into_ref!(_peri, rx, tx); - rx.set_as_af(rx.af_num(), AfType::input(Pull::None)); tx.set_as_af(tx.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh)); @@ -957,7 +955,7 @@ trait SealedInstance { /// Instance trait #[allow(private_bounds)] -pub trait Instance: SealedInstance + RccPeripheral + 'static { +pub trait Instance: SealedInstance + PeripheralType + RccPeripheral + 'static { /// Interrupt 0 type IT0Interrupt: crate::interrupt::typelevel::Interrupt; /// Interrupt 1 @@ -965,7 +963,7 @@ pub trait Instance: SealedInstance + RccPeripheral + 'static { } /// Fdcan Instance struct -pub struct FdcanInstance<'a, T>(PeripheralRef<'a, T>); +pub struct FdcanInstance<'a, T: Instance>(Peri<'a, T>); macro_rules! impl_fdcan { ($inst:ident, diff --git a/embassy-stm32/src/cordic/mod.rs b/embassy-stm32/src/cordic/mod.rs index fb342d2e7..320774857 100644 --- a/embassy-stm32/src/cordic/mod.rs +++ b/embassy-stm32/src/cordic/mod.rs @@ -1,7 +1,7 @@ //! coordinate rotation digital computer (CORDIC) use embassy_hal_internal::drop::OnDrop; -use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; +use embassy_hal_internal::{Peri, PeripheralType}; use crate::pac::cordic::vals; use crate::{dma, peripherals, rcc}; @@ -16,7 +16,7 @@ pub mod utils; /// CORDIC driver pub struct Cordic<'d, T: Instance> { - peri: PeripheralRef<'d, T>, + peri: Peri<'d, T>, config: Config, } @@ -137,7 +137,7 @@ trait SealedInstance { /// CORDIC instance trait #[allow(private_bounds)] -pub trait Instance: SealedInstance + Peripheral

+ crate::rcc::RccPeripheral {} +pub trait Instance: SealedInstance + PeripheralType + crate::rcc::RccPeripheral {} /// CORDIC configuration #[derive(Debug)] @@ -198,11 +198,9 @@ impl<'d, T: Instance> Cordic<'d, T> { /// Note: /// If you need a peripheral -> CORDIC -> peripheral mode, /// you may want to set Cordic into [Mode::ZeroOverhead] mode, and add extra arguments with [Self::extra_config] - pub fn new(peri: impl Peripheral

+ 'd, config: Config) -> Self { + pub fn new(peri: Peri<'d, T>, config: Config) -> Self { rcc::enable_and_reset::(); - into_ref!(peri); - let mut instance = Self { peri, config }; instance.reconfigure(); @@ -378,8 +376,8 @@ impl<'d, T: Instance> Cordic<'d, T> { /// If you want to make sure ARG2 is set to +1, consider run [.reconfigure()](Self::reconfigure). pub async fn async_calc_32bit( &mut self, - write_dma: impl Peripheral

>, - read_dma: impl Peripheral

>, + mut write_dma: Peri<'_, impl WriteDma>, + mut read_dma: Peri<'_, impl ReadDma>, arg: &[u32], res: &mut [u32], arg1_only: bool, @@ -393,8 +391,6 @@ impl<'d, T: Instance> Cordic<'d, T> { let active_res_buf = &mut res[..res_cnt]; - into_ref!(write_dma, read_dma); - self.peri .set_argument_count(if arg1_only { AccessCount::One } else { AccessCount::Two }); @@ -416,7 +412,7 @@ impl<'d, T: Instance> Cordic<'d, T> { unsafe { let write_transfer = dma::Transfer::new_write( - &mut write_dma, + write_dma.reborrow(), write_req, arg, T::regs().wdata().as_ptr() as *mut _, @@ -424,7 +420,7 @@ impl<'d, T: Instance> Cordic<'d, T> { ); let read_transfer = dma::Transfer::new_read( - &mut read_dma, + read_dma.reborrow(), read_req, T::regs().rdata().as_ptr() as *mut _, active_res_buf, @@ -519,8 +515,8 @@ impl<'d, T: Instance> Cordic<'d, T> { /// User will take respond to merge two u16 arguments into one u32 data, and/or split one u32 data into two u16 results. pub async fn async_calc_16bit( &mut self, - write_dma: impl Peripheral

>, - read_dma: impl Peripheral

>, + mut write_dma: Peri<'_, impl WriteDma>, + mut read_dma: Peri<'_, impl ReadDma>, arg: &[u32], res: &mut [u32], ) -> Result { @@ -536,8 +532,6 @@ impl<'d, T: Instance> Cordic<'d, T> { let active_res_buf = &mut res[..res_cnt]; - into_ref!(write_dma, read_dma); - // In q1.15 mode, 1 write/read to access 2 arguments/results self.peri.set_argument_count(AccessCount::One); self.peri.set_result_count(AccessCount::One); @@ -557,7 +551,7 @@ impl<'d, T: Instance> Cordic<'d, T> { unsafe { let write_transfer = dma::Transfer::new_write( - &mut write_dma, + write_dma.reborrow(), write_req, arg, T::regs().wdata().as_ptr() as *mut _, @@ -565,7 +559,7 @@ impl<'d, T: Instance> Cordic<'d, T> { ); let read_transfer = dma::Transfer::new_read( - &mut read_dma, + read_dma.reborrow(), read_req, T::regs().rdata().as_ptr() as *mut _, active_res_buf, diff --git a/embassy-stm32/src/crc/v1.rs b/embassy-stm32/src/crc/v1.rs index f3d13de7c..a78b3c2b7 100644 --- a/embassy-stm32/src/crc/v1.rs +++ b/embassy-stm32/src/crc/v1.rs @@ -1,23 +1,18 @@ -use embassy_hal_internal::{into_ref, PeripheralRef}; - use crate::pac::CRC as PAC_CRC; use crate::peripherals::CRC; -use crate::{rcc, Peripheral}; +use crate::{rcc, Peri}; /// CRC driver. pub struct Crc<'d> { - _peri: PeripheralRef<'d, CRC>, + _peri: Peri<'d, CRC>, } impl<'d> Crc<'d> { /// Instantiates the CRC32 peripheral and initializes it to default values. - pub fn new(peripheral: impl Peripheral

+ 'd) -> Self { - into_ref!(peripheral); - + pub fn new(peripheral: Peri<'d, CRC>) -> Self { // Note: enable and reset come from RccPeripheral. // enable CRC clock in RCC. rcc::enable_and_reset::(); - // Peripheral the peripheral let mut instance = Self { _peri: peripheral }; instance.reset(); instance diff --git a/embassy-stm32/src/crc/v2v3.rs b/embassy-stm32/src/crc/v2v3.rs index ecb507ff4..c94c9f380 100644 --- a/embassy-stm32/src/crc/v2v3.rs +++ b/embassy-stm32/src/crc/v2v3.rs @@ -1,13 +1,11 @@ -use embassy_hal_internal::{into_ref, PeripheralRef}; - use crate::pac::crc::vals; use crate::pac::CRC as PAC_CRC; use crate::peripherals::CRC; -use crate::{rcc, Peripheral}; +use crate::{rcc, Peri}; /// CRC driver. pub struct Crc<'d> { - _peripheral: PeripheralRef<'d, CRC>, + _peripheral: Peri<'d, CRC>, _config: Config, } @@ -80,11 +78,10 @@ pub enum PolySize { impl<'d> Crc<'d> { /// Instantiates the CRC32 peripheral and initializes it to default values. - pub fn new(peripheral: impl Peripheral

+ 'd, config: Config) -> Self { + pub fn new(peripheral: Peri<'d, CRC>, config: Config) -> Self { // Note: enable and reset come from RccPeripheral. // reset to default values and enable CRC clock in RCC. rcc::enable_and_reset::(); - into_ref!(peripheral); let mut instance = Self { _peripheral: peripheral, _config: config, diff --git a/embassy-stm32/src/cryp/mod.rs b/embassy-stm32/src/cryp/mod.rs index 54d2c30e5..fba3c0fd7 100644 --- a/embassy-stm32/src/cryp/mod.rs +++ b/embassy-stm32/src/cryp/mod.rs @@ -4,13 +4,13 @@ use core::cmp::min; use core::marker::PhantomData; use core::ptr; -use embassy_hal_internal::{into_ref, PeripheralRef}; +use embassy_hal_internal::{Peri, PeripheralType}; use embassy_sync::waitqueue::AtomicWaker; use crate::dma::{ChannelAndRequest, TransferOptions}; use crate::interrupt::typelevel::Interrupt; use crate::mode::{Async, Blocking, Mode}; -use crate::{interrupt, pac, peripherals, rcc, Peripheral}; +use crate::{interrupt, pac, peripherals, rcc}; const DES_BLOCK_SIZE: usize = 8; // 64 bits const AES_BLOCK_SIZE: usize = 16; // 128 bits @@ -988,7 +988,7 @@ pub enum Direction { /// Crypto Accelerator Driver pub struct Cryp<'d, T: Instance, M: Mode> { - _peripheral: PeripheralRef<'d, T>, + _peripheral: Peri<'d, T>, _phantom: PhantomData, indma: Option>, outdma: Option>, @@ -997,11 +997,10 @@ pub struct Cryp<'d, T: Instance, M: Mode> { impl<'d, T: Instance> Cryp<'d, T, Blocking> { /// Create a new CRYP driver in blocking mode. pub fn new_blocking( - peri: impl Peripheral

+ 'd, + peri: Peri<'d, T>, _irq: impl interrupt::typelevel::Binding> + 'd, ) -> Self { rcc::enable_and_reset::(); - into_ref!(peri); let instance = Self { _peripheral: peri, _phantom: PhantomData, @@ -1461,13 +1460,12 @@ impl<'d, T: Instance, M: Mode> Cryp<'d, T, M> { impl<'d, T: Instance> Cryp<'d, T, Async> { /// Create a new CRYP driver. pub fn new( - peri: impl Peripheral

+ 'd, - indma: impl Peripheral

> + 'd, - outdma: impl Peripheral

> + 'd, + peri: Peri<'d, T>, + indma: Peri<'d, impl DmaIn>, + outdma: Peri<'d, impl DmaOut>, _irq: impl interrupt::typelevel::Binding> + 'd, ) -> Self { rcc::enable_and_reset::(); - into_ref!(peri, indma, outdma); let instance = Self { _peripheral: peri, _phantom: PhantomData, @@ -1879,7 +1877,7 @@ trait SealedInstance { /// CRYP instance trait. #[allow(private_bounds)] -pub trait Instance: SealedInstance + Peripheral

+ crate::rcc::RccPeripheral + 'static + Send { +pub trait Instance: SealedInstance + PeripheralType + crate::rcc::RccPeripheral + 'static + Send { /// Interrupt for this CRYP instance. type Interrupt: interrupt::typelevel::Interrupt; } diff --git a/embassy-stm32/src/dac/mod.rs b/embassy-stm32/src/dac/mod.rs index 7a63dc5fc..30046849b 100644 --- a/embassy-stm32/src/dac/mod.rs +++ b/embassy-stm32/src/dac/mod.rs @@ -3,16 +3,15 @@ use core::marker::PhantomData; -use embassy_hal_internal::into_ref; - use crate::dma::ChannelAndRequest; use crate::mode::{Async, Blocking, Mode as PeriMode}; #[cfg(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7))] use crate::pac::dac; use crate::rcc::{self, RccPeripheral}; -use crate::{peripherals, Peripheral}; +use crate::{peripherals, Peri}; mod tsel; +use embassy_hal_internal::PeripheralType; pub use tsel::TriggerSel; /// Operating mode for DAC channel @@ -121,12 +120,7 @@ impl<'d, T: Instance, C: Channel> DacChannel<'d, T, C, Async> { /// /// By default, triggering is disabled, but it can be enabled using /// [`DacChannel::set_trigger()`]. - pub fn new( - peri: impl Peripheral

+ 'd, - dma: impl Peripheral

> + 'd, - pin: impl Peripheral

> + 'd, - ) -> Self { - into_ref!(dma, pin); + pub fn new(peri: Peri<'d, T>, dma: Peri<'d, impl Dma>, pin: Peri<'d, impl DacPin>) -> Self { pin.set_as_analog(); Self::new_inner( peri, @@ -147,8 +141,7 @@ impl<'d, T: Instance, C: Channel> DacChannel<'d, T, C, Async> { /// By default, triggering is disabled, but it can be enabled using /// [`DacChannel::set_trigger()`]. #[cfg(all(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7), not(any(stm32h56x, stm32h57x))))] - pub fn new_internal(peri: impl Peripheral

+ 'd, dma: impl Peripheral

> + 'd) -> Self { - into_ref!(dma); + pub fn new_internal(peri: Peri<'d, T>, dma: Peri<'d, impl Dma>) -> Self { Self::new_inner(peri, new_dma!(dma), Mode::NormalInternalUnbuffered) } @@ -204,8 +197,7 @@ impl<'d, T: Instance, C: Channel> DacChannel<'d, T, C, Blocking> { /// /// By default, triggering is disabled, but it can be enabled using /// [`DacChannel::set_trigger()`]. - pub fn new_blocking(peri: impl Peripheral

+ 'd, pin: impl Peripheral

> + 'd) -> Self { - into_ref!(pin); + pub fn new_blocking(peri: Peri<'d, T>, pin: Peri<'d, impl DacPin>) -> Self { pin.set_as_analog(); Self::new_inner( peri, @@ -226,14 +218,14 @@ impl<'d, T: Instance, C: Channel> DacChannel<'d, T, C, Blocking> { /// By default, triggering is disabled, but it can be enabled using /// [`DacChannel::set_trigger()`]. #[cfg(all(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7), not(any(stm32h56x, stm32h57x))))] - pub fn new_internal_blocking(peri: impl Peripheral

+ 'd) -> Self { + pub fn new_internal_blocking(peri: Peri<'d, T>) -> Self { Self::new_inner(peri, None, Mode::NormalInternalUnbuffered) } } impl<'d, T: Instance, C: Channel, M: PeriMode> DacChannel<'d, T, C, M> { fn new_inner( - _peri: impl Peripheral

+ 'd, + _peri: Peri<'d, T>, dma: Option>, #[cfg(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7))] mode: Mode, ) -> Self { @@ -395,13 +387,12 @@ impl<'d, T: Instance> Dac<'d, T, Async> { /// By default, triggering is disabled, but it can be enabled using the `set_trigger()` /// method on the underlying channels. pub fn new( - peri: impl Peripheral

+ 'd, - dma_ch1: impl Peripheral

> + 'd, - dma_ch2: impl Peripheral

> + 'd, - pin_ch1: impl Peripheral

+ crate::gpio::Pin> + 'd, - pin_ch2: impl Peripheral

+ crate::gpio::Pin> + 'd, + peri: Peri<'d, T>, + dma_ch1: Peri<'d, impl Dma>, + dma_ch2: Peri<'d, impl Dma>, + pin_ch1: Peri<'d, impl DacPin + crate::gpio::Pin>, + pin_ch2: Peri<'d, impl DacPin + crate::gpio::Pin>, ) -> Self { - into_ref!(dma_ch1, dma_ch2, pin_ch1, pin_ch2); pin_ch1.set_as_analog(); pin_ch2.set_as_analog(); Self::new_inner( @@ -429,11 +420,10 @@ impl<'d, T: Instance> Dac<'d, T, Async> { /// method on the underlying channels. #[cfg(all(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7), not(any(stm32h56x, stm32h57x))))] pub fn new_internal( - peri: impl Peripheral

+ 'd, - dma_ch1: impl Peripheral

> + 'd, - dma_ch2: impl Peripheral

> + 'd, + peri: Peri<'d, T>, + dma_ch1: Peri<'d, impl Dma>, + dma_ch2: Peri<'d, impl Dma>, ) -> Self { - into_ref!(dma_ch1, dma_ch2); Self::new_inner( peri, new_dma!(dma_ch1), @@ -457,11 +447,10 @@ impl<'d, T: Instance> Dac<'d, T, Blocking> { /// By default, triggering is disabled, but it can be enabled using the `set_trigger()` /// method on the underlying channels. pub fn new_blocking( - peri: impl Peripheral

+ 'd, - pin_ch1: impl Peripheral

+ crate::gpio::Pin> + 'd, - pin_ch2: impl Peripheral

+ crate::gpio::Pin> + 'd, + peri: Peri<'d, T>, + pin_ch1: Peri<'d, impl DacPin + crate::gpio::Pin>, + pin_ch2: Peri<'d, impl DacPin + crate::gpio::Pin>, ) -> Self { - into_ref!(pin_ch1, pin_ch2); pin_ch1.set_as_analog(); pin_ch2.set_as_analog(); Self::new_inner( @@ -488,14 +477,14 @@ impl<'d, T: Instance> Dac<'d, T, Blocking> { /// By default, triggering is disabled, but it can be enabled using the `set_trigger()` /// method on the underlying channels. #[cfg(all(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7), not(any(stm32h56x, stm32h57x))))] - pub fn new_internal(peri: impl Peripheral

+ 'd) -> Self { + pub fn new_internal(peri: Peri<'d, T>) -> Self { Self::new_inner(peri, None, None, Mode::NormalInternalUnbuffered) } } impl<'d, T: Instance, M: PeriMode> Dac<'d, T, M> { fn new_inner( - _peri: impl Peripheral

+ 'd, + _peri: Peri<'d, T>, dma_ch1: Option>, dma_ch2: Option>, #[cfg(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7))] mode: Mode, @@ -572,7 +561,7 @@ trait SealedInstance { /// DAC instance. #[allow(private_bounds)] -pub trait Instance: SealedInstance + RccPeripheral + 'static {} +pub trait Instance: SealedInstance + PeripheralType + RccPeripheral + 'static {} /// Channel 1 marker type. pub enum Ch1 {} diff --git a/embassy-stm32/src/dcmi.rs b/embassy-stm32/src/dcmi.rs index 4ba4e824e..d05faee21 100644 --- a/embassy-stm32/src/dcmi.rs +++ b/embassy-stm32/src/dcmi.rs @@ -3,13 +3,13 @@ use core::future::poll_fn; use core::marker::PhantomData; use core::task::Poll; -use embassy_hal_internal::{into_ref, PeripheralRef}; +use embassy_hal_internal::PeripheralType; use embassy_sync::waitqueue::AtomicWaker; use crate::dma::Transfer; use crate::gpio::{AfType, Pull}; use crate::interrupt::typelevel::Interrupt; -use crate::{interrupt, rcc, Peripheral}; +use crate::{interrupt, rcc, Peri}; /// Interrupt handler. pub struct InterruptHandler { @@ -106,8 +106,7 @@ impl Default for Config { macro_rules! config_pins { ($($pin:ident),*) => { - into_ref!($($pin),*); - critical_section::with(|_| { + critical_section::with(|_| { $( $pin.set_as_af($pin.af_num(), AfType::input(Pull::None)); )* @@ -117,8 +116,8 @@ macro_rules! config_pins { /// DCMI driver. pub struct Dcmi<'d, T: Instance, Dma: FrameDma> { - inner: PeripheralRef<'d, T>, - dma: PeripheralRef<'d, Dma>, + inner: Peri<'d, T>, + dma: Peri<'d, Dma>, } impl<'d, T, Dma> Dcmi<'d, T, Dma> @@ -128,23 +127,22 @@ where { /// Create a new DCMI driver with 8 data bits. pub fn new_8bit( - peri: impl Peripheral

+ 'd, - dma: impl Peripheral

+ 'd, + peri: Peri<'d, T>, + dma: Peri<'d, Dma>, _irq: impl interrupt::typelevel::Binding> + 'd, - d0: impl Peripheral

> + 'd, - d1: impl Peripheral

> + 'd, - d2: impl Peripheral

> + 'd, - d3: impl Peripheral

> + 'd, - d4: impl Peripheral

> + 'd, - d5: impl Peripheral

> + 'd, - d6: impl Peripheral

> + 'd, - d7: impl Peripheral

> + 'd, - v_sync: impl Peripheral

> + 'd, - h_sync: impl Peripheral

> + 'd, - pixclk: impl Peripheral

> + 'd, + d0: Peri<'d, impl D0Pin>, + d1: Peri<'d, impl D1Pin>, + d2: Peri<'d, impl D2Pin>, + d3: Peri<'d, impl D3Pin>, + d4: Peri<'d, impl D4Pin>, + d5: Peri<'d, impl D5Pin>, + d6: Peri<'d, impl D6Pin>, + d7: Peri<'d, impl D7Pin>, + v_sync: Peri<'d, impl VSyncPin>, + h_sync: Peri<'d, impl HSyncPin>, + pixclk: Peri<'d, impl PixClkPin>, config: Config, ) -> Self { - into_ref!(peri, dma); config_pins!(d0, d1, d2, d3, d4, d5, d6, d7); config_pins!(v_sync, h_sync, pixclk); @@ -153,25 +151,24 @@ where /// Create a new DCMI driver with 10 data bits. pub fn new_10bit( - peri: impl Peripheral

+ 'd, - dma: impl Peripheral

+ 'd, + peri: Peri<'d, T>, + dma: Peri<'d, Dma>, _irq: impl interrupt::typelevel::Binding> + 'd, - d0: impl Peripheral

> + 'd, - d1: impl Peripheral

> + 'd, - d2: impl Peripheral

> + 'd, - d3: impl Peripheral

> + 'd, - d4: impl Peripheral

> + 'd, - d5: impl Peripheral

> + 'd, - d6: impl Peripheral

> + 'd, - d7: impl Peripheral

> + 'd, - d8: impl Peripheral

> + 'd, - d9: impl Peripheral

> + 'd, - v_sync: impl Peripheral

> + 'd, - h_sync: impl Peripheral

> + 'd, - pixclk: impl Peripheral

> + 'd, + d0: Peri<'d, impl D0Pin>, + d1: Peri<'d, impl D1Pin>, + d2: Peri<'d, impl D2Pin>, + d3: Peri<'d, impl D3Pin>, + d4: Peri<'d, impl D4Pin>, + d5: Peri<'d, impl D5Pin>, + d6: Peri<'d, impl D6Pin>, + d7: Peri<'d, impl D7Pin>, + d8: Peri<'d, impl D8Pin>, + d9: Peri<'d, impl D9Pin>, + v_sync: Peri<'d, impl VSyncPin>, + h_sync: Peri<'d, impl HSyncPin>, + pixclk: Peri<'d, impl PixClkPin>, config: Config, ) -> Self { - into_ref!(peri, dma); config_pins!(d0, d1, d2, d3, d4, d5, d6, d7, d8, d9); config_pins!(v_sync, h_sync, pixclk); @@ -180,27 +177,26 @@ where /// Create a new DCMI driver with 12 data bits. pub fn new_12bit( - peri: impl Peripheral

+ 'd, - dma: impl Peripheral

+ 'd, + peri: Peri<'d, T>, + dma: Peri<'d, Dma>, _irq: impl interrupt::typelevel::Binding> + 'd, - d0: impl Peripheral

> + 'd, - d1: impl Peripheral

> + 'd, - d2: impl Peripheral

> + 'd, - d3: impl Peripheral

> + 'd, - d4: impl Peripheral

> + 'd, - d5: impl Peripheral

> + 'd, - d6: impl Peripheral

> + 'd, - d7: impl Peripheral

> + 'd, - d8: impl Peripheral

> + 'd, - d9: impl Peripheral

> + 'd, - d10: impl Peripheral

> + 'd, - d11: impl Peripheral

> + 'd, - v_sync: impl Peripheral

> + 'd, - h_sync: impl Peripheral

> + 'd, - pixclk: impl Peripheral

> + 'd, + d0: Peri<'d, impl D0Pin>, + d1: Peri<'d, impl D1Pin>, + d2: Peri<'d, impl D2Pin>, + d3: Peri<'d, impl D3Pin>, + d4: Peri<'d, impl D4Pin>, + d5: Peri<'d, impl D5Pin>, + d6: Peri<'d, impl D6Pin>, + d7: Peri<'d, impl D7Pin>, + d8: Peri<'d, impl D8Pin>, + d9: Peri<'d, impl D9Pin>, + d10: Peri<'d, impl D10Pin>, + d11: Peri<'d, impl D11Pin>, + v_sync: Peri<'d, impl VSyncPin>, + h_sync: Peri<'d, impl HSyncPin>, + pixclk: Peri<'d, impl PixClkPin>, config: Config, ) -> Self { - into_ref!(peri, dma); config_pins!(d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11); config_pins!(v_sync, h_sync, pixclk); @@ -209,29 +205,28 @@ where /// Create a new DCMI driver with 14 data bits. pub fn new_14bit( - peri: impl Peripheral

+ 'd, - dma: impl Peripheral

+ 'd, + peri: Peri<'d, T>, + dma: Peri<'d, Dma>, _irq: impl interrupt::typelevel::Binding> + 'd, - d0: impl Peripheral

> + 'd, - d1: impl Peripheral

> + 'd, - d2: impl Peripheral

> + 'd, - d3: impl Peripheral

> + 'd, - d4: impl Peripheral

> + 'd, - d5: impl Peripheral

> + 'd, - d6: impl Peripheral

> + 'd, - d7: impl Peripheral

> + 'd, - d8: impl Peripheral

> + 'd, - d9: impl Peripheral

> + 'd, - d10: impl Peripheral

> + 'd, - d11: impl Peripheral

> + 'd, - d12: impl Peripheral

> + 'd, - d13: impl Peripheral

> + 'd, - v_sync: impl Peripheral

> + 'd, - h_sync: impl Peripheral

> + 'd, - pixclk: impl Peripheral

> + 'd, + d0: Peri<'d, impl D0Pin>, + d1: Peri<'d, impl D1Pin>, + d2: Peri<'d, impl D2Pin>, + d3: Peri<'d, impl D3Pin>, + d4: Peri<'d, impl D4Pin>, + d5: Peri<'d, impl D5Pin>, + d6: Peri<'d, impl D6Pin>, + d7: Peri<'d, impl D7Pin>, + d8: Peri<'d, impl D8Pin>, + d9: Peri<'d, impl D9Pin>, + d10: Peri<'d, impl D10Pin>, + d11: Peri<'d, impl D11Pin>, + d12: Peri<'d, impl D12Pin>, + d13: Peri<'d, impl D13Pin>, + v_sync: Peri<'d, impl VSyncPin>, + h_sync: Peri<'d, impl HSyncPin>, + pixclk: Peri<'d, impl PixClkPin>, config: Config, ) -> Self { - into_ref!(peri, dma); config_pins!(d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11, d12, d13); config_pins!(v_sync, h_sync, pixclk); @@ -240,21 +235,20 @@ where /// Create a new DCMI driver with 8 data bits, with embedded synchronization. pub fn new_es_8bit( - peri: impl Peripheral

+ 'd, - dma: impl Peripheral

+ 'd, + peri: Peri<'d, T>, + dma: Peri<'d, Dma>, _irq: impl interrupt::typelevel::Binding> + 'd, - d0: impl Peripheral

> + 'd, - d1: impl Peripheral

> + 'd, - d2: impl Peripheral

> + 'd, - d3: impl Peripheral

> + 'd, - d4: impl Peripheral

> + 'd, - d5: impl Peripheral

> + 'd, - d6: impl Peripheral

> + 'd, - d7: impl Peripheral

> + 'd, - pixclk: impl Peripheral

> + 'd, + d0: Peri<'d, impl D0Pin>, + d1: Peri<'d, impl D1Pin>, + d2: Peri<'d, impl D2Pin>, + d3: Peri<'d, impl D3Pin>, + d4: Peri<'d, impl D4Pin>, + d5: Peri<'d, impl D5Pin>, + d6: Peri<'d, impl D6Pin>, + d7: Peri<'d, impl D7Pin>, + pixclk: Peri<'d, impl PixClkPin>, config: Config, ) -> Self { - into_ref!(peri, dma); config_pins!(d0, d1, d2, d3, d4, d5, d6, d7); config_pins!(pixclk); @@ -263,23 +257,22 @@ where /// Create a new DCMI driver with 10 data bits, with embedded synchronization. pub fn new_es_10bit( - peri: impl Peripheral

+ 'd, - dma: impl Peripheral

+ 'd, + peri: Peri<'d, T>, + dma: Peri<'d, Dma>, _irq: impl interrupt::typelevel::Binding> + 'd, - d0: impl Peripheral

> + 'd, - d1: impl Peripheral

> + 'd, - d2: impl Peripheral

> + 'd, - d3: impl Peripheral

> + 'd, - d4: impl Peripheral

> + 'd, - d5: impl Peripheral

> + 'd, - d6: impl Peripheral

> + 'd, - d7: impl Peripheral

> + 'd, - d8: impl Peripheral

> + 'd, - d9: impl Peripheral

> + 'd, - pixclk: impl Peripheral

> + 'd, + d0: Peri<'d, impl D0Pin>, + d1: Peri<'d, impl D1Pin>, + d2: Peri<'d, impl D2Pin>, + d3: Peri<'d, impl D3Pin>, + d4: Peri<'d, impl D4Pin>, + d5: Peri<'d, impl D5Pin>, + d6: Peri<'d, impl D6Pin>, + d7: Peri<'d, impl D7Pin>, + d8: Peri<'d, impl D8Pin>, + d9: Peri<'d, impl D9Pin>, + pixclk: Peri<'d, impl PixClkPin>, config: Config, ) -> Self { - into_ref!(peri, dma); config_pins!(d0, d1, d2, d3, d4, d5, d6, d7, d8, d9); config_pins!(pixclk); @@ -288,25 +281,24 @@ where /// Create a new DCMI driver with 12 data bits, with embedded synchronization. pub fn new_es_12bit( - peri: impl Peripheral

+ 'd, - dma: impl Peripheral

+ 'd, + peri: Peri<'d, T>, + dma: Peri<'d, Dma>, _irq: impl interrupt::typelevel::Binding> + 'd, - d0: impl Peripheral

> + 'd, - d1: impl Peripheral

> + 'd, - d2: impl Peripheral

> + 'd, - d3: impl Peripheral

> + 'd, - d4: impl Peripheral

> + 'd, - d5: impl Peripheral

> + 'd, - d6: impl Peripheral

> + 'd, - d7: impl Peripheral

> + 'd, - d8: impl Peripheral

> + 'd, - d9: impl Peripheral

> + 'd, - d10: impl Peripheral

> + 'd, - d11: impl Peripheral

> + 'd, - pixclk: impl Peripheral

> + 'd, + d0: Peri<'d, impl D0Pin>, + d1: Peri<'d, impl D1Pin>, + d2: Peri<'d, impl D2Pin>, + d3: Peri<'d, impl D3Pin>, + d4: Peri<'d, impl D4Pin>, + d5: Peri<'d, impl D5Pin>, + d6: Peri<'d, impl D6Pin>, + d7: Peri<'d, impl D7Pin>, + d8: Peri<'d, impl D8Pin>, + d9: Peri<'d, impl D9Pin>, + d10: Peri<'d, impl D10Pin>, + d11: Peri<'d, impl D11Pin>, + pixclk: Peri<'d, impl PixClkPin>, config: Config, ) -> Self { - into_ref!(peri, dma); config_pins!(d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11); config_pins!(pixclk); @@ -315,27 +307,26 @@ where /// Create a new DCMI driver with 14 data bits, with embedded synchronization. pub fn new_es_14bit( - peri: impl Peripheral

+ 'd, - dma: impl Peripheral

+ 'd, + peri: Peri<'d, T>, + dma: Peri<'d, Dma>, _irq: impl interrupt::typelevel::Binding> + 'd, - d0: impl Peripheral

> + 'd, - d1: impl Peripheral

> + 'd, - d2: impl Peripheral

> + 'd, - d3: impl Peripheral

> + 'd, - d4: impl Peripheral

> + 'd, - d5: impl Peripheral

> + 'd, - d6: impl Peripheral

> + 'd, - d7: impl Peripheral

> + 'd, - d8: impl Peripheral

> + 'd, - d9: impl Peripheral

> + 'd, - d10: impl Peripheral

> + 'd, - d11: impl Peripheral

> + 'd, - d12: impl Peripheral

> + 'd, - d13: impl Peripheral

> + 'd, - pixclk: impl Peripheral

> + 'd, + d0: Peri<'d, impl D0Pin>, + d1: Peri<'d, impl D1Pin>, + d2: Peri<'d, impl D2Pin>, + d3: Peri<'d, impl D3Pin>, + d4: Peri<'d, impl D4Pin>, + d5: Peri<'d, impl D5Pin>, + d6: Peri<'d, impl D6Pin>, + d7: Peri<'d, impl D7Pin>, + d8: Peri<'d, impl D8Pin>, + d9: Peri<'d, impl D9Pin>, + d10: Peri<'d, impl D10Pin>, + d11: Peri<'d, impl D11Pin>, + d12: Peri<'d, impl D12Pin>, + d13: Peri<'d, impl D13Pin>, + pixclk: Peri<'d, impl PixClkPin>, config: Config, ) -> Self { - into_ref!(peri, dma); config_pins!(d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11, d12, d13); config_pins!(pixclk); @@ -343,8 +334,8 @@ where } fn new_inner( - peri: PeripheralRef<'d, T>, - dma: PeripheralRef<'d, Dma>, + peri: Peri<'d, T>, + dma: Peri<'d, Dma>, config: Config, use_embedded_synchronization: bool, edm: u8, @@ -396,7 +387,7 @@ where let r = self.inner.regs(); let src = r.dr().as_ptr() as *mut u32; let request = self.dma.request(); - let dma_read = unsafe { Transfer::new_read(&mut self.dma, request, src, buffer, Default::default()) }; + let dma_read = unsafe { Transfer::new_read(self.dma.reborrow(), request, src, buffer, Default::default()) }; Self::clear_interrupt_flags(); Self::enable_irqs(); @@ -435,7 +426,7 @@ trait SealedInstance: crate::rcc::RccPeripheral { /// DCMI instance. #[allow(private_bounds)] -pub trait Instance: SealedInstance + 'static { +pub trait Instance: SealedInstance + PeripheralType + 'static { /// Interrupt for this instance. type Interrupt: interrupt::typelevel::Interrupt; } diff --git a/embassy-stm32/src/dma/dma_bdma.rs b/embassy-stm32/src/dma/dma_bdma.rs index d31f4d01a..7dbbe7b72 100644 --- a/embassy-stm32/src/dma/dma_bdma.rs +++ b/embassy-stm32/src/dma/dma_bdma.rs @@ -3,7 +3,7 @@ use core::pin::Pin; use core::sync::atomic::{fence, AtomicUsize, Ordering}; use core::task::{Context, Poll, Waker}; -use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; +use embassy_hal_internal::Peri; use embassy_sync::waitqueue::AtomicWaker; use super::ringbuffer::{DmaCtrl, Error, ReadableDmaRingBuffer, WritableDmaRingBuffer}; @@ -571,13 +571,13 @@ impl AnyChannel { /// DMA transfer. #[must_use = "futures do nothing unless you `.await` or poll them"] pub struct Transfer<'a> { - channel: PeripheralRef<'a, AnyChannel>, + channel: Peri<'a, AnyChannel>, } impl<'a> Transfer<'a> { /// Create a new read DMA transfer (peripheral to memory). pub unsafe fn new_read( - channel: impl Peripheral

+ 'a, + channel: Peri<'a, impl Channel>, request: Request, peri_addr: *mut W, buf: &'a mut [W], @@ -588,16 +588,14 @@ impl<'a> Transfer<'a> { /// Create a new read DMA transfer (peripheral to memory), using raw pointers. pub unsafe fn new_read_raw( - channel: impl Peripheral

+ 'a, + channel: Peri<'a, impl Channel>, request: Request, peri_addr: *mut W, buf: *mut [W], options: TransferOptions, ) -> Self { - into_ref!(channel); - Self::new_inner( - channel.map_into(), + channel.into(), request, Dir::PeripheralToMemory, peri_addr as *const u32, @@ -612,7 +610,7 @@ impl<'a> Transfer<'a> { /// Create a new write DMA transfer (memory to peripheral). pub unsafe fn new_write( - channel: impl Peripheral

+ 'a, + channel: Peri<'a, impl Channel>, request: Request, buf: &'a [MW], peri_addr: *mut PW, @@ -623,16 +621,14 @@ impl<'a> Transfer<'a> { /// Create a new write DMA transfer (memory to peripheral), using raw pointers. pub unsafe fn new_write_raw( - channel: impl Peripheral

+ 'a, + channel: Peri<'a, impl Channel>, request: Request, buf: *const [MW], peri_addr: *mut PW, options: TransferOptions, ) -> Self { - into_ref!(channel); - Self::new_inner( - channel.map_into(), + channel.into(), request, Dir::MemoryToPeripheral, peri_addr as *const u32, @@ -647,17 +643,15 @@ impl<'a> Transfer<'a> { /// Create a new write DMA transfer (memory to peripheral), writing the same value repeatedly. pub unsafe fn new_write_repeated( - channel: impl Peripheral

+ 'a, + channel: Peri<'a, impl Channel>, request: Request, repeated: &'a W, count: usize, peri_addr: *mut W, options: TransferOptions, ) -> Self { - into_ref!(channel); - Self::new_inner( - channel.map_into(), + channel.into(), request, Dir::MemoryToPeripheral, peri_addr as *const u32, @@ -671,7 +665,7 @@ impl<'a> Transfer<'a> { } unsafe fn new_inner( - channel: PeripheralRef<'a, AnyChannel>, + channel: Peri<'a, AnyChannel>, _request: Request, dir: Dir, peri_addr: *const u32, @@ -769,7 +763,7 @@ impl<'a> Future for Transfer<'a> { // ============================== -struct DmaCtrlImpl<'a>(PeripheralRef<'a, AnyChannel>); +struct DmaCtrlImpl<'a>(Peri<'a, AnyChannel>); impl<'a> DmaCtrl for DmaCtrlImpl<'a> { fn get_remaining_transfers(&self) -> usize { @@ -795,21 +789,20 @@ impl<'a> DmaCtrl for DmaCtrlImpl<'a> { /// Ringbuffer for receiving data using DMA circular mode. pub struct ReadableRingBuffer<'a, W: Word> { - channel: PeripheralRef<'a, AnyChannel>, + channel: Peri<'a, AnyChannel>, ringbuf: ReadableDmaRingBuffer<'a, W>, } impl<'a, W: Word> ReadableRingBuffer<'a, W> { /// Create a new ring buffer. pub unsafe fn new( - channel: impl Peripheral

+ 'a, + channel: Peri<'a, impl Channel>, _request: Request, peri_addr: *mut W, buffer: &'a mut [W], mut options: TransferOptions, ) -> Self { - into_ref!(channel); - let channel: PeripheralRef<'a, AnyChannel> = channel.map_into(); + let channel: Peri<'a, AnyChannel> = channel.into(); let buffer_ptr = buffer.as_mut_ptr(); let len = buffer.len(); @@ -948,21 +941,20 @@ impl<'a, W: Word> Drop for ReadableRingBuffer<'a, W> { /// Ringbuffer for writing data using DMA circular mode. pub struct WritableRingBuffer<'a, W: Word> { - channel: PeripheralRef<'a, AnyChannel>, + channel: Peri<'a, AnyChannel>, ringbuf: WritableDmaRingBuffer<'a, W>, } impl<'a, W: Word> WritableRingBuffer<'a, W> { /// Create a new ring buffer. pub unsafe fn new( - channel: impl Peripheral

+ 'a, + channel: Peri<'a, impl Channel>, _request: Request, peri_addr: *mut W, buffer: &'a mut [W], mut options: TransferOptions, ) -> Self { - into_ref!(channel); - let channel: PeripheralRef<'a, AnyChannel> = channel.map_into(); + let channel: Peri<'a, AnyChannel> = channel.into(); let len = buffer.len(); let dir = Dir::MemoryToPeripheral; diff --git a/embassy-stm32/src/dma/gpdma.rs b/embassy-stm32/src/dma/gpdma.rs index 799b8b355..ade70fb55 100644 --- a/embassy-stm32/src/dma/gpdma.rs +++ b/embassy-stm32/src/dma/gpdma.rs @@ -5,7 +5,7 @@ use core::pin::Pin; use core::sync::atomic::{fence, Ordering}; use core::task::{Context, Poll}; -use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; +use embassy_hal_internal::Peri; use embassy_sync::waitqueue::AtomicWaker; use super::word::{Word, WordSize}; @@ -109,13 +109,13 @@ impl AnyChannel { /// DMA transfer. #[must_use = "futures do nothing unless you `.await` or poll them"] pub struct Transfer<'a> { - channel: PeripheralRef<'a, AnyChannel>, + channel: Peri<'a, AnyChannel>, } impl<'a> Transfer<'a> { /// Create a new read DMA transfer (peripheral to memory). pub unsafe fn new_read( - channel: impl Peripheral

+ 'a, + channel: Peri<'a, impl Channel>, request: Request, peri_addr: *mut W, buf: &'a mut [W], @@ -126,16 +126,14 @@ impl<'a> Transfer<'a> { /// Create a new read DMA transfer (peripheral to memory), using raw pointers. pub unsafe fn new_read_raw( - channel: impl Peripheral

+ 'a, + channel: Peri<'a, impl Channel>, request: Request, peri_addr: *mut W, buf: *mut [W], options: TransferOptions, ) -> Self { - into_ref!(channel); - Self::new_inner( - channel.map_into(), + channel.into(), request, Dir::PeripheralToMemory, peri_addr as *const u32, @@ -150,7 +148,7 @@ impl<'a> Transfer<'a> { /// Create a new write DMA transfer (memory to peripheral). pub unsafe fn new_write( - channel: impl Peripheral

+ 'a, + channel: Peri<'a, impl Channel>, request: Request, buf: &'a [MW], peri_addr: *mut PW, @@ -161,16 +159,14 @@ impl<'a> Transfer<'a> { /// Create a new write DMA transfer (memory to peripheral), using raw pointers. pub unsafe fn new_write_raw( - channel: impl Peripheral

+ 'a, + channel: Peri<'a, impl Channel>, request: Request, buf: *const [MW], peri_addr: *mut PW, options: TransferOptions, ) -> Self { - into_ref!(channel); - Self::new_inner( - channel.map_into(), + channel.into(), request, Dir::MemoryToPeripheral, peri_addr as *const u32, @@ -185,17 +181,15 @@ impl<'a> Transfer<'a> { /// Create a new write DMA transfer (memory to peripheral), writing the same value repeatedly. pub unsafe fn new_write_repeated( - channel: impl Peripheral

+ 'a, + channel: Peri<'a, impl Channel>, request: Request, repeated: &'a MW, count: usize, peri_addr: *mut PW, options: TransferOptions, ) -> Self { - into_ref!(channel); - Self::new_inner( - channel.map_into(), + channel.into(), request, Dir::MemoryToPeripheral, peri_addr as *const u32, @@ -209,7 +203,7 @@ impl<'a> Transfer<'a> { } unsafe fn new_inner( - channel: PeripheralRef<'a, AnyChannel>, + channel: Peri<'a, AnyChannel>, request: Request, dir: Dir, peri_addr: *const u32, diff --git a/embassy-stm32/src/dma/mod.rs b/embassy-stm32/src/dma/mod.rs index ac4a0f98e..d3b070a6d 100644 --- a/embassy-stm32/src/dma/mod.rs +++ b/embassy-stm32/src/dma/mod.rs @@ -22,7 +22,7 @@ pub(crate) use util::*; pub(crate) mod ringbuffer; pub mod word; -use embassy_hal_internal::{impl_peripheral, Peripheral}; +use embassy_hal_internal::{impl_peripheral, PeripheralType}; use crate::interrupt; @@ -51,17 +51,7 @@ pub(crate) trait ChannelInterrupt { /// DMA channel. #[allow(private_bounds)] -pub trait Channel: SealedChannel + Peripheral

+ Into + 'static { - /// Type-erase (degrade) this pin into an `AnyChannel`. - /// - /// This converts DMA channel singletons (`DMA1_CH3`, `DMA2_CH1`, ...), which - /// are all different types, into the same type. It is useful for - /// creating arrays of channels, or avoiding generics. - #[inline] - fn degrade(self) -> AnyChannel { - AnyChannel { id: self.id() } - } -} +pub trait Channel: SealedChannel + PeripheralType + Into + 'static {} macro_rules! dma_channel_impl { ($channel_peri:ident, $index:expr) => { @@ -79,8 +69,10 @@ macro_rules! dma_channel_impl { impl crate::dma::Channel for crate::peripherals::$channel_peri {} impl From for crate::dma::AnyChannel { - fn from(x: crate::peripherals::$channel_peri) -> Self { - crate::dma::Channel::degrade(x) + fn from(val: crate::peripherals::$channel_peri) -> Self { + Self { + id: crate::dma::SealedChannel::id(&val), + } } } }; diff --git a/embassy-stm32/src/dma/util.rs b/embassy-stm32/src/dma/util.rs index 5e1158182..8bf89e2fe 100644 --- a/embassy-stm32/src/dma/util.rs +++ b/embassy-stm32/src/dma/util.rs @@ -1,13 +1,12 @@ -use embassy_hal_internal::PeripheralRef; - use super::word::Word; use super::{AnyChannel, Request, Transfer, TransferOptions}; +use crate::Peri; /// Convenience wrapper, contains a channel and a request number. /// /// Commonly used in peripheral drivers that own DMA channels. pub(crate) struct ChannelAndRequest<'d> { - pub channel: PeripheralRef<'d, AnyChannel>, + pub channel: Peri<'d, AnyChannel>, pub request: Request, } @@ -18,7 +17,7 @@ impl<'d> ChannelAndRequest<'d> { buf: &'a mut [W], options: TransferOptions, ) -> Transfer<'a> { - Transfer::new_read(&mut self.channel, self.request, peri_addr, buf, options) + Transfer::new_read(self.channel.reborrow(), self.request, peri_addr, buf, options) } pub unsafe fn read_raw<'a, W: Word>( @@ -27,7 +26,7 @@ impl<'d> ChannelAndRequest<'d> { buf: *mut [W], options: TransferOptions, ) -> Transfer<'a> { - Transfer::new_read_raw(&mut self.channel, self.request, peri_addr, buf, options) + Transfer::new_read_raw(self.channel.reborrow(), self.request, peri_addr, buf, options) } pub unsafe fn write<'a, W: Word>( @@ -36,7 +35,7 @@ impl<'d> ChannelAndRequest<'d> { peri_addr: *mut W, options: TransferOptions, ) -> Transfer<'a> { - Transfer::new_write(&mut self.channel, self.request, buf, peri_addr, options) + Transfer::new_write(self.channel.reborrow(), self.request, buf, peri_addr, options) } pub unsafe fn write_raw<'a, MW: Word, PW: Word>( @@ -45,7 +44,7 @@ impl<'d> ChannelAndRequest<'d> { peri_addr: *mut PW, options: TransferOptions, ) -> Transfer<'a> { - Transfer::new_write_raw(&mut self.channel, self.request, buf, peri_addr, options) + Transfer::new_write_raw(self.channel.reborrow(), self.request, buf, peri_addr, options) } #[allow(dead_code)] @@ -56,6 +55,13 @@ impl<'d> ChannelAndRequest<'d> { peri_addr: *mut W, options: TransferOptions, ) -> Transfer<'a> { - Transfer::new_write_repeated(&mut self.channel, self.request, repeated, count, peri_addr, options) + Transfer::new_write_repeated( + self.channel.reborrow(), + self.request, + repeated, + count, + peri_addr, + options, + ) } } diff --git a/embassy-stm32/src/dsihost.rs b/embassy-stm32/src/dsihost.rs index 77c3d95c3..e97ccd9d0 100644 --- a/embassy-stm32/src/dsihost.rs +++ b/embassy-stm32/src/dsihost.rs @@ -2,12 +2,12 @@ use core::marker::PhantomData; -use embassy_hal_internal::{into_ref, PeripheralRef}; +use embassy_hal_internal::PeripheralType; //use crate::gpio::{AnyPin, SealedPin}; use crate::gpio::{AfType, AnyPin, OutputType, Speed}; use crate::rcc::{self, RccPeripheral}; -use crate::{peripherals, Peripheral}; +use crate::{peripherals, Peri}; /// Performs a busy-wait delay for a specified number of microseconds. pub fn blocking_delay_ms(ms: u32) { @@ -69,14 +69,12 @@ impl From for u8 { /// DSIHOST driver. pub struct DsiHost<'d, T: Instance> { _peri: PhantomData<&'d mut T>, - _te: PeripheralRef<'d, AnyPin>, + _te: Peri<'d, AnyPin>, } impl<'d, T: Instance> DsiHost<'d, T> { /// Note: Full-Duplex modes are not supported at this time - pub fn new(_peri: impl Peripheral

+ 'd, te: impl Peripheral

> + 'd) -> Self { - into_ref!(te); - + pub fn new(_peri: Peri<'d, T>, te: Peri<'d, impl TePin>) -> Self { rcc::enable_and_reset::(); // Set Tearing Enable pin according to CubeMx example @@ -88,7 +86,7 @@ impl<'d, T: Instance> DsiHost<'d, T> { */ Self { _peri: PhantomData, - _te: te.map_into(), + _te: te.into(), } } @@ -412,7 +410,7 @@ trait SealedInstance: crate::rcc::SealedRccPeripheral { /// DSI instance trait. #[allow(private_bounds)] -pub trait Instance: SealedInstance + RccPeripheral + 'static {} +pub trait Instance: SealedInstance + PeripheralType + RccPeripheral + 'static {} pin_trait!(TePin, Instance); diff --git a/embassy-stm32/src/dts/mod.rs b/embassy-stm32/src/dts/mod.rs index 58d7cf841..1f39c8db5 100644 --- a/embassy-stm32/src/dts/mod.rs +++ b/embassy-stm32/src/dts/mod.rs @@ -4,13 +4,13 @@ use core::future::poll_fn; use core::sync::atomic::{compiler_fence, Ordering}; use core::task::Poll; -use embassy_hal_internal::{into_ref, PeripheralRef}; +use embassy_hal_internal::Peri; use embassy_sync::waitqueue::AtomicWaker; use crate::interrupt::InterruptExt; use crate::peripherals::DTS; use crate::time::Hertz; -use crate::{interrupt, pac, rcc, Peripheral}; +use crate::{interrupt, pac, rcc}; mod tsel; pub use tsel::TriggerSel; @@ -72,7 +72,7 @@ const MAX_DTS_CLK_FREQ: Hertz = Hertz::mhz(1); /// Digital temperature sensor driver. pub struct Dts<'d> { - _peri: PeripheralRef<'d, DTS>, + _peri: Peri<'d, DTS>, } static WAKER: AtomicWaker = AtomicWaker::new(); @@ -80,11 +80,10 @@ static WAKER: AtomicWaker = AtomicWaker::new(); impl<'d> Dts<'d> { /// Create a new temperature sensor driver. pub fn new( - _peri: impl Peripheral

+ 'd, + _peri: Peri<'d, DTS>, _irq: impl interrupt::typelevel::Binding + 'd, config: Config, ) -> Self { - into_ref!(_peri); rcc::enable_and_reset::(); let prescaler = rcc::frequency::() / MAX_DTS_CLK_FREQ; diff --git a/embassy-stm32/src/eth/mod.rs b/embassy-stm32/src/eth/mod.rs index 109ceeeb3..97d7b4347 100644 --- a/embassy-stm32/src/eth/mod.rs +++ b/embassy-stm32/src/eth/mod.rs @@ -9,6 +9,7 @@ mod generic_phy; use core::mem::MaybeUninit; use core::task::Context; +use embassy_hal_internal::PeripheralType; use embassy_net_driver::{Capabilities, HardwareAddress, LinkState}; use embassy_sync::waitqueue::AtomicWaker; @@ -199,7 +200,7 @@ trait SealedInstance { /// Ethernet instance. #[allow(private_bounds)] -pub trait Instance: SealedInstance + RccPeripheral + Send + 'static {} +pub trait Instance: SealedInstance + PeripheralType + RccPeripheral + Send + 'static {} impl SealedInstance for crate::peripherals::ETH { fn regs() -> crate::pac::eth::Eth { diff --git a/embassy-stm32/src/eth/v1/mod.rs b/embassy-stm32/src/eth/v1/mod.rs index e12ac2fef..640191d69 100644 --- a/embassy-stm32/src/eth/v1/mod.rs +++ b/embassy-stm32/src/eth/v1/mod.rs @@ -6,7 +6,7 @@ mod tx_desc; use core::marker::PhantomData; use core::sync::atomic::{fence, Ordering}; -use embassy_hal_internal::{into_ref, PeripheralRef}; +use embassy_hal_internal::Peri; use stm32_metapac::eth::vals::{Apcs, Cr, Dm, DmaomrSr, Fes, Ftf, Ifg, MbProgress, Mw, Pbl, Rsf, St, Tsf}; pub(crate) use self::rx_desc::{RDes, RDesRing}; @@ -15,6 +15,7 @@ use super::*; #[cfg(eth_v1a)] use crate::gpio::Pull; use crate::gpio::{AfType, AnyPin, OutputType, SealedPin, Speed}; +use crate::interrupt; use crate::interrupt::InterruptExt; #[cfg(eth_v1a)] use crate::pac::AFIO; @@ -22,7 +23,6 @@ use crate::pac::AFIO; use crate::pac::SYSCFG; use crate::pac::{ETH, RCC}; use crate::rcc::SealedRccPeripheral; -use crate::{interrupt, Peripheral}; /// Interrupt handler. pub struct InterruptHandler {} @@ -47,11 +47,11 @@ impl interrupt::typelevel::Handler for InterruptHandl /// Ethernet driver. pub struct Ethernet<'d, T: Instance, P: Phy> { - _peri: PeripheralRef<'d, T>, + _peri: Peri<'d, T>, pub(crate) tx: TDesRing<'d>, pub(crate) rx: RDesRing<'d>, - pins: [PeripheralRef<'d, AnyPin>; 9], + pins: [Peri<'d, AnyPin>; 9], pub(crate) phy: P, pub(crate) station_management: EthernetStationManagement, pub(crate) mac_addr: [u8; 6], @@ -95,22 +95,20 @@ impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> { /// safety: the returned instance is not leak-safe pub fn new( queue: &'d mut PacketQueue, - peri: impl Peripheral

+ 'd, + peri: Peri<'d, T>, _irq: impl interrupt::typelevel::Binding + 'd, - ref_clk: impl Peripheral

> + 'd, - mdio: impl Peripheral

> + 'd, - mdc: impl Peripheral

> + 'd, - crs: impl Peripheral

> + 'd, - rx_d0: impl Peripheral

> + 'd, - rx_d1: impl Peripheral

> + 'd, - tx_d0: impl Peripheral

> + 'd, - tx_d1: impl Peripheral

> + 'd, - tx_en: impl Peripheral

> + 'd, + ref_clk: Peri<'d, impl RefClkPin>, + mdio: Peri<'d, impl MDIOPin>, + mdc: Peri<'d, impl MDCPin>, + crs: Peri<'d, impl CRSPin>, + rx_d0: Peri<'d, impl RXD0Pin>, + rx_d1: Peri<'d, impl RXD1Pin>, + tx_d0: Peri<'d, impl TXD0Pin>, + tx_d1: Peri<'d, impl TXD1Pin>, + tx_en: Peri<'d, impl TXEnPin>, phy: P, mac_addr: [u8; 6], ) -> Self { - into_ref!(peri, ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en); - // Enable the necessary Clocks #[cfg(eth_v1a)] critical_section::with(|_| { @@ -213,15 +211,15 @@ impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> { }; let pins = [ - ref_clk.map_into(), - mdio.map_into(), - mdc.map_into(), - crs.map_into(), - rx_d0.map_into(), - rx_d1.map_into(), - tx_d0.map_into(), - tx_d1.map_into(), - tx_en.map_into(), + ref_clk.into(), + mdio.into(), + mdc.into(), + crs.into(), + rx_d0.into(), + rx_d1.into(), + tx_d0.into(), + tx_d1.into(), + tx_en.into(), ]; let mut this = Self { diff --git a/embassy-stm32/src/eth/v2/mod.rs b/embassy-stm32/src/eth/v2/mod.rs index 26e4eeb63..034c5dd88 100644 --- a/embassy-stm32/src/eth/v2/mod.rs +++ b/embassy-stm32/src/eth/v2/mod.rs @@ -3,16 +3,16 @@ mod descriptors; use core::marker::PhantomData; use core::sync::atomic::{fence, Ordering}; -use embassy_hal_internal::{into_ref, PeripheralRef}; +use embassy_hal_internal::Peri; use stm32_metapac::syscfg::vals::EthSelPhy; pub(crate) use self::descriptors::{RDes, RDesRing, TDes, TDesRing}; use super::*; use crate::gpio::{AfType, AnyPin, OutputType, SealedPin as _, Speed}; +use crate::interrupt; use crate::interrupt::InterruptExt; use crate::pac::ETH; use crate::rcc::SealedRccPeripheral; -use crate::{interrupt, Peripheral}; /// Interrupt handler. pub struct InterruptHandler {} @@ -37,7 +37,7 @@ impl interrupt::typelevel::Handler for InterruptHandl /// Ethernet driver. pub struct Ethernet<'d, T: Instance, P: Phy> { - _peri: PeripheralRef<'d, T>, + _peri: Peri<'d, T>, pub(crate) tx: TDesRing<'d>, pub(crate) rx: RDesRing<'d>, pins: Pins<'d>, @@ -48,8 +48,8 @@ pub struct Ethernet<'d, T: Instance, P: Phy> { /// Pins of ethernet driver. enum Pins<'d> { - Rmii([PeripheralRef<'d, AnyPin>; 9]), - Mii([PeripheralRef<'d, AnyPin>; 14]), + Rmii([Peri<'d, AnyPin>; 9]), + Mii([Peri<'d, AnyPin>; 14]), } macro_rules! config_pins { @@ -67,17 +67,17 @@ impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> { /// Create a new RMII ethernet driver using 9 pins. pub fn new( queue: &'d mut PacketQueue, - peri: impl Peripheral

+ 'd, + peri: Peri<'d, T>, irq: impl interrupt::typelevel::Binding + 'd, - ref_clk: impl Peripheral

> + 'd, - mdio: impl Peripheral

> + 'd, - mdc: impl Peripheral

> + 'd, - crs: impl Peripheral

> + 'd, - rx_d0: impl Peripheral

> + 'd, - rx_d1: impl Peripheral

> + 'd, - tx_d0: impl Peripheral

> + 'd, - tx_d1: impl Peripheral

> + 'd, - tx_en: impl Peripheral

> + 'd, + ref_clk: Peri<'d, impl RefClkPin>, + mdio: Peri<'d, impl MDIOPin>, + mdc: Peri<'d, impl MDCPin>, + crs: Peri<'d, impl CRSPin>, + rx_d0: Peri<'d, impl RXD0Pin>, + rx_d1: Peri<'d, impl RXD1Pin>, + tx_d0: Peri<'d, impl TXD0Pin>, + tx_d1: Peri<'d, impl TXD1Pin>, + tx_en: Peri<'d, impl TXEnPin>, phy: P, mac_addr: [u8; 6], ) -> Self { @@ -92,19 +92,18 @@ impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> { crate::pac::SYSCFG.pmcr().modify(|w| w.set_eth_sel_phy(EthSelPhy::RMII)); }); - into_ref!(ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en); config_pins!(ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en); let pins = Pins::Rmii([ - ref_clk.map_into(), - mdio.map_into(), - mdc.map_into(), - crs.map_into(), - rx_d0.map_into(), - rx_d1.map_into(), - tx_d0.map_into(), - tx_d1.map_into(), - tx_en.map_into(), + ref_clk.into(), + mdio.into(), + mdc.into(), + crs.into(), + rx_d0.into(), + rx_d1.into(), + tx_d0.into(), + tx_d1.into(), + tx_en.into(), ]); Self::new_inner(queue, peri, irq, pins, phy, mac_addr) @@ -113,22 +112,22 @@ impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> { /// Create a new MII ethernet driver using 14 pins. pub fn new_mii( queue: &'d mut PacketQueue, - peri: impl Peripheral

+ 'd, + peri: Peri<'d, T>, irq: impl interrupt::typelevel::Binding + 'd, - rx_clk: impl Peripheral

> + 'd, - tx_clk: impl Peripheral

> + 'd, - mdio: impl Peripheral

> + 'd, - mdc: impl Peripheral

> + 'd, - rxdv: impl Peripheral

> + 'd, - rx_d0: impl Peripheral

> + 'd, - rx_d1: impl Peripheral

> + 'd, - rx_d2: impl Peripheral

> + 'd, - rx_d3: impl Peripheral

> + 'd, - tx_d0: impl Peripheral

> + 'd, - tx_d1: impl Peripheral

> + 'd, - tx_d2: impl Peripheral

> + 'd, - tx_d3: impl Peripheral

> + 'd, - tx_en: impl Peripheral

> + 'd, + rx_clk: Peri<'d, impl RXClkPin>, + tx_clk: Peri<'d, impl TXClkPin>, + mdio: Peri<'d, impl MDIOPin>, + mdc: Peri<'d, impl MDCPin>, + rxdv: Peri<'d, impl RXDVPin>, + rx_d0: Peri<'d, impl RXD0Pin>, + rx_d1: Peri<'d, impl RXD1Pin>, + rx_d2: Peri<'d, impl RXD2Pin>, + rx_d3: Peri<'d, impl RXD3Pin>, + tx_d0: Peri<'d, impl TXD0Pin>, + tx_d1: Peri<'d, impl TXD1Pin>, + tx_d2: Peri<'d, impl TXD2Pin>, + tx_d3: Peri<'d, impl TXD3Pin>, + tx_en: Peri<'d, impl TXEnPin>, phy: P, mac_addr: [u8; 6], ) -> Self { @@ -145,24 +144,23 @@ impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> { .modify(|w| w.set_eth_sel_phy(EthSelPhy::MII_GMII)); }); - into_ref!(rx_clk, tx_clk, mdio, mdc, rxdv, rx_d0, rx_d1, rx_d2, rx_d3, tx_d0, tx_d1, tx_d2, tx_d3, tx_en); config_pins!(rx_clk, tx_clk, mdio, mdc, rxdv, rx_d0, rx_d1, rx_d2, rx_d3, tx_d0, tx_d1, tx_d2, tx_d3, tx_en); let pins = Pins::Mii([ - rx_clk.map_into(), - tx_clk.map_into(), - mdio.map_into(), - mdc.map_into(), - rxdv.map_into(), - rx_d0.map_into(), - rx_d1.map_into(), - rx_d2.map_into(), - rx_d3.map_into(), - tx_d0.map_into(), - tx_d1.map_into(), - tx_d2.map_into(), - tx_d3.map_into(), - tx_en.map_into(), + rx_clk.into(), + tx_clk.into(), + mdio.into(), + mdc.into(), + rxdv.into(), + rx_d0.into(), + rx_d1.into(), + rx_d2.into(), + rx_d3.into(), + tx_d0.into(), + tx_d1.into(), + tx_d2.into(), + tx_d3.into(), + tx_en.into(), ]); Self::new_inner(queue, peri, irq, pins, phy, mac_addr) @@ -170,7 +168,7 @@ impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> { fn new_inner( queue: &'d mut PacketQueue, - peri: impl Peripheral

+ 'd, + peri: Peri<'d, T>, _irq: impl interrupt::typelevel::Binding + 'd, pins: Pins<'d>, phy: P, @@ -254,7 +252,7 @@ impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> { }; let mut this = Self { - _peri: peri.into_ref(), + _peri: peri, tx: TDesRing::new(&mut queue.tx_desc, &mut queue.tx_buf), rx: RDesRing::new(&mut queue.rx_desc, &mut queue.rx_buf), pins, diff --git a/embassy-stm32/src/exti.rs b/embassy-stm32/src/exti.rs index 9604c5149..9fce78f95 100644 --- a/embassy-stm32/src/exti.rs +++ b/embassy-stm32/src/exti.rs @@ -5,13 +5,13 @@ use core::marker::PhantomData; use core::pin::Pin; use core::task::{Context, Poll}; -use embassy_hal_internal::{impl_peripheral, into_ref}; +use embassy_hal_internal::{impl_peripheral, PeripheralType}; use embassy_sync::waitqueue::AtomicWaker; use crate::gpio::{AnyPin, Input, Level, Pin as GpioPin, Pull}; use crate::pac::exti::regs::Lines; use crate::pac::EXTI; -use crate::{interrupt, pac, peripherals, Peripheral}; +use crate::{interrupt, pac, peripherals, Peri}; const EXTI_COUNT: usize = 16; static EXTI_WAKERS: [AtomicWaker; EXTI_COUNT] = [const { AtomicWaker::new() }; EXTI_COUNT]; @@ -105,13 +105,7 @@ impl<'d> Unpin for ExtiInput<'d> {} impl<'d> ExtiInput<'d> { /// Create an EXTI input. - pub fn new( - pin: impl Peripheral

+ 'd, - ch: impl Peripheral

+ 'd, - pull: Pull, - ) -> Self { - into_ref!(pin, ch); - + pub fn new(pin: Peri<'d, T>, ch: Peri<'d, T::ExtiChannel>, pull: Pull) -> Self { // Needed if using AnyPin+AnyChannel. assert_eq!(pin.pin(), ch.number()); @@ -338,23 +332,12 @@ trait SealedChannel {} /// EXTI channel trait. #[allow(private_bounds)] -pub trait Channel: SealedChannel + Sized { +pub trait Channel: PeripheralType + SealedChannel + Sized { /// Get the EXTI channel number. fn number(&self) -> u8; - - /// Type-erase (degrade) this channel into an `AnyChannel`. - /// - /// This converts EXTI channel singletons (`EXTI0`, `EXTI1`, ...), which - /// are all different types, into the same type. It is useful for - /// creating arrays of channels, or avoiding generics. - fn degrade(self) -> AnyChannel { - AnyChannel { - number: self.number() as u8, - } - } } -/// Type-erased (degraded) EXTI channel. +/// Type-erased EXTI channel. /// /// This represents ownership over any EXTI channel, known at runtime. pub struct AnyChannel { @@ -377,6 +360,14 @@ macro_rules! impl_exti { $number } } + + impl From for AnyChannel { + fn from(val: peripherals::$type) -> Self { + Self { + number: val.number() as u8, + } + } + } }; } diff --git a/embassy-stm32/src/flash/asynch.rs b/embassy-stm32/src/flash/asynch.rs index 9468ac632..599b7bb4e 100644 --- a/embassy-stm32/src/flash/asynch.rs +++ b/embassy-stm32/src/flash/asynch.rs @@ -2,7 +2,6 @@ use core::marker::PhantomData; use core::sync::atomic::{fence, Ordering}; use embassy_hal_internal::drop::OnDrop; -use embassy_hal_internal::into_ref; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::mutex::Mutex; @@ -12,18 +11,16 @@ use super::{ }; use crate::interrupt::InterruptExt; use crate::peripherals::FLASH; -use crate::{interrupt, Peripheral}; +use crate::{interrupt, Peri}; pub(super) static REGION_ACCESS: Mutex = Mutex::new(()); impl<'d> Flash<'d, Async> { /// Create a new flash driver with async capabilities. pub fn new( - p: impl Peripheral

+ 'd, + p: Peri<'d, FLASH>, _irq: impl interrupt::typelevel::Binding + 'd, ) -> Self { - into_ref!(p); - crate::interrupt::FLASH.unpend(); unsafe { crate::interrupt::FLASH.enable() }; diff --git a/embassy-stm32/src/flash/common.rs b/embassy-stm32/src/flash/common.rs index 0004a7488..1376ca4b4 100644 --- a/embassy-stm32/src/flash/common.rs +++ b/embassy-stm32/src/flash/common.rs @@ -2,27 +2,24 @@ use core::marker::PhantomData; use core::sync::atomic::{fence, Ordering}; use embassy_hal_internal::drop::OnDrop; -use embassy_hal_internal::{into_ref, PeripheralRef}; use super::{ family, Async, Blocking, Error, FlashBank, FlashLayout, FlashRegion, FlashSector, FLASH_SIZE, MAX_ERASE_SIZE, READ_SIZE, WRITE_SIZE, }; +use crate::Peri; use crate::_generated::FLASH_BASE; use crate::peripherals::FLASH; -use crate::Peripheral; /// Internal flash memory driver. pub struct Flash<'d, MODE = Async> { - pub(crate) inner: PeripheralRef<'d, FLASH>, + pub(crate) inner: Peri<'d, FLASH>, pub(crate) _mode: PhantomData, } impl<'d> Flash<'d, Blocking> { /// Create a new flash driver, usable in blocking mode. - pub fn new_blocking(p: impl Peripheral

+ 'd) -> Self { - into_ref!(p); - + pub fn new_blocking(p: Peri<'d, FLASH>) -> Self { Self { inner: p, _mode: PhantomData, diff --git a/embassy-stm32/src/flash/f4.rs b/embassy-stm32/src/flash/f4.rs index 86afdce8a..687eabaeb 100644 --- a/embassy-stm32/src/flash/f4.rs +++ b/embassy-stm32/src/flash/f4.rs @@ -13,8 +13,7 @@ use crate::pac; mod alt_regions { use core::marker::PhantomData; - use embassy_hal_internal::PeripheralRef; - + use crate::Peri; use crate::_generated::flash_regions::{OTPRegion, BANK1_REGION1, BANK1_REGION2, BANK1_REGION3, OTP_REGION}; use crate::_generated::FLASH_SIZE; use crate::flash::{asynch, Async, Bank1Region1, Bank1Region2, Blocking, Error, Flash, FlashBank, FlashRegion}; @@ -50,10 +49,10 @@ mod alt_regions { &ALT_BANK2_REGION3, ]; - pub struct AltBank1Region3<'d, MODE = Async>(pub &'static FlashRegion, PeripheralRef<'d, FLASH>, PhantomData); - pub struct AltBank2Region1<'d, MODE = Async>(pub &'static FlashRegion, PeripheralRef<'d, FLASH>, PhantomData); - pub struct AltBank2Region2<'d, MODE = Async>(pub &'static FlashRegion, PeripheralRef<'d, FLASH>, PhantomData); - pub struct AltBank2Region3<'d, MODE = Async>(pub &'static FlashRegion, PeripheralRef<'d, FLASH>, PhantomData); + pub struct AltBank1Region3<'d, MODE = Async>(pub &'static FlashRegion, Peri<'d, FLASH>, PhantomData); + pub struct AltBank2Region1<'d, MODE = Async>(pub &'static FlashRegion, Peri<'d, FLASH>, PhantomData); + pub struct AltBank2Region2<'d, MODE = Async>(pub &'static FlashRegion, Peri<'d, FLASH>, PhantomData); + pub struct AltBank2Region3<'d, MODE = Async>(pub &'static FlashRegion, Peri<'d, FLASH>, PhantomData); pub struct AltFlashLayout<'d, MODE = Async> { pub bank1_region1: Bank1Region1<'d, MODE>, diff --git a/embassy-stm32/src/fmc.rs b/embassy-stm32/src/fmc.rs index 83b49a3dd..71ca775cb 100644 --- a/embassy-stm32/src/fmc.rs +++ b/embassy-stm32/src/fmc.rs @@ -1,10 +1,10 @@ //! Flexible Memory Controller (FMC) / Flexible Static Memory Controller (FSMC) use core::marker::PhantomData; -use embassy_hal_internal::into_ref; +use embassy_hal_internal::PeripheralType; use crate::gpio::{AfType, OutputType, Pull, Speed}; -use crate::{rcc, Peripheral}; +use crate::{rcc, Peri}; /// FMC driver pub struct Fmc<'d, T: Instance> { @@ -21,7 +21,7 @@ where /// /// **Note:** This is currently used to provide access to some basic FMC functions /// for manual configuration for memory types that stm32-fmc does not support. - pub fn new_raw(_instance: impl Peripheral

+ 'd) -> Self { + pub fn new_raw(_instance: Peri<'d, T>) -> Self { Self { peri: PhantomData } } @@ -74,8 +74,7 @@ where macro_rules! config_pins { ($($pin:ident),*) => { - into_ref!($($pin),*); - $( + $( $pin.set_as_af($pin.af_num(), AfType::output_pull(OutputType::PushPull, Speed::VeryHigh, Pull::Up)); )* }; @@ -92,12 +91,12 @@ macro_rules! fmc_sdram_constructor { )) => { /// Create a new FMC instance. pub fn $name( - _instance: impl Peripheral

+ 'd, - $($addr_pin_name: impl Peripheral

> + 'd),*, - $($ba_pin_name: impl Peripheral

> + 'd),*, - $($d_pin_name: impl Peripheral

> + 'd),*, - $($nbl_pin_name: impl Peripheral

> + 'd),*, - $($ctrl_pin_name: impl Peripheral

> + 'd),*, + _instance: Peri<'d, T>, + $($addr_pin_name: Peri<'d, impl $addr_signal>),*, + $($ba_pin_name: Peri<'d, impl $ba_signal>),*, + $($d_pin_name: Peri<'d, impl $d_signal>),*, + $($nbl_pin_name: Peri<'d, impl $nbl_signal>),*, + $($ctrl_pin_name: Peri<'d, impl $ctrl_signal>),*, chip: CHIP ) -> stm32_fmc::Sdram, CHIP> { @@ -245,7 +244,7 @@ trait SealedInstance: crate::rcc::RccPeripheral { /// FMC instance trait. #[allow(private_bounds)] -pub trait Instance: SealedInstance + 'static {} +pub trait Instance: SealedInstance + PeripheralType + 'static {} foreach_peripheral!( (fmc, $inst:ident) => { diff --git a/embassy-stm32/src/gpio.rs b/embassy-stm32/src/gpio.rs index 65e1bfb8c..bb37c4194 100644 --- a/embassy-stm32/src/gpio.rs +++ b/embassy-stm32/src/gpio.rs @@ -4,10 +4,10 @@ use core::convert::Infallible; use critical_section::CriticalSection; -use embassy_hal_internal::{impl_peripheral, into_ref, PeripheralRef}; +use embassy_hal_internal::{impl_peripheral, Peri, PeripheralType}; use crate::pac::gpio::{self, vals}; -use crate::{peripherals, Peripheral}; +use crate::peripherals; /// GPIO flexible pin. /// @@ -15,7 +15,7 @@ use crate::{peripherals, Peripheral}; /// set while not in output mode, so the pin's level will be 'remembered' when it is not in output /// mode. pub struct Flex<'d> { - pub(crate) pin: PeripheralRef<'d, AnyPin>, + pub(crate) pin: Peri<'d, AnyPin>, } impl<'d> Flex<'d> { @@ -25,10 +25,9 @@ impl<'d> Flex<'d> { /// before the pin is put into output mode. /// #[inline] - pub fn new(pin: impl Peripheral

+ 'd) -> Self { - into_ref!(pin); + pub fn new(pin: Peri<'d, impl Pin>) -> Self { // Pin will be in disconnected state. - Self { pin: pin.map_into() } + Self { pin: pin.into() } } /// Put the pin into input mode. @@ -310,7 +309,7 @@ pub struct Input<'d> { impl<'d> Input<'d> { /// Create GPIO input driver for a [Pin] with the provided [Pull] configuration. #[inline] - pub fn new(pin: impl Peripheral

+ 'd, pull: Pull) -> Self { + pub fn new(pin: Peri<'d, impl Pin>, pull: Pull) -> Self { let mut pin = Flex::new(pin); pin.set_as_input(pull); Self { pin } @@ -375,7 +374,7 @@ pub struct Output<'d> { impl<'d> Output<'d> { /// Create GPIO output driver for a [Pin] with the provided [Level] and [Speed] configuration. #[inline] - pub fn new(pin: impl Peripheral

+ 'd, initial_output: Level, speed: Speed) -> Self { + pub fn new(pin: Peri<'d, impl Pin>, initial_output: Level, speed: Speed) -> Self { let mut pin = Flex::new(pin); match initial_output { Level::High => pin.set_high(), @@ -440,7 +439,7 @@ pub struct OutputOpenDrain<'d> { impl<'d> OutputOpenDrain<'d> { /// Create a new GPIO open drain output driver for a [Pin] with the provided [Level] and [Speed]. #[inline] - pub fn new(pin: impl Peripheral

+ 'd, initial_output: Level, speed: Speed) -> Self { + pub fn new(pin: Peri<'d, impl Pin>, initial_output: Level, speed: Speed) -> Self { let mut pin = Flex::new(pin); match initial_output { Level::High => pin.set_high(), @@ -454,7 +453,7 @@ impl<'d> OutputOpenDrain<'d> { /// and [Pull]. #[inline] #[cfg(gpio_v2)] - pub fn new_pull(pin: impl Peripheral

+ 'd, initial_output: Level, speed: Speed, pull: Pull) -> Self { + pub fn new_pull(pin: Peri<'d, impl Pin>, initial_output: Level, speed: Speed, pull: Pull) -> Self { let mut pin = Flex::new(pin); match initial_output { Level::High => pin.set_high(), @@ -780,7 +779,7 @@ pub(crate) trait SealedPin { /// GPIO pin trait. #[allow(private_bounds)] -pub trait Pin: Peripheral

+ Into + SealedPin + Sized + 'static { +pub trait Pin: PeripheralType + Into + SealedPin + Sized + 'static { /// EXTI channel assigned to this pin. /// /// For example, PC4 uses EXTI4. @@ -798,18 +797,6 @@ pub trait Pin: Peripheral

+ Into + SealedPin + Sized + 'static fn port(&self) -> u8 { self._port() } - - /// Type-erase (degrade) this pin into an `AnyPin`. - /// - /// This converts pin singletons (`PA5`, `PB6`, ...), which - /// are all different types, into the same type. It is useful for - /// creating arrays of pins, or avoiding generics. - #[inline] - fn degrade(self) -> AnyPin { - AnyPin { - pin_port: self.pin_port(), - } - } } /// Type-erased GPIO pin @@ -822,8 +809,8 @@ impl AnyPin { /// /// `pin_port` is `port_num * 16 + pin_num`, where `port_num` is 0 for port `A`, 1 for port `B`, etc... #[inline] - pub unsafe fn steal(pin_port: u8) -> Self { - Self { pin_port } + pub unsafe fn steal(pin_port: u8) -> Peri<'static, Self> { + Peri::new_unchecked(Self { pin_port }) } #[inline] @@ -867,8 +854,10 @@ foreach_pin!( } impl From for AnyPin { - fn from(x: peripherals::$pin_name) -> Self { - x.degrade() + fn from(val: peripherals::$pin_name) -> Self { + Self { + pin_port: val.pin_port(), + } } } }; diff --git a/embassy-stm32/src/hash/mod.rs b/embassy-stm32/src/hash/mod.rs index 3951e9d63..1258e8923 100644 --- a/embassy-stm32/src/hash/mod.rs +++ b/embassy-stm32/src/hash/mod.rs @@ -8,7 +8,7 @@ use core::ptr; #[cfg(hash_v2)] use core::task::Poll; -use embassy_hal_internal::{into_ref, PeripheralRef}; +use embassy_hal_internal::PeripheralType; use embassy_sync::waitqueue::AtomicWaker; use stm32_metapac::hash::regs::*; @@ -19,7 +19,7 @@ use crate::interrupt::typelevel::Interrupt; use crate::mode::Async; use crate::mode::{Blocking, Mode}; use crate::peripherals::HASH; -use crate::{interrupt, pac, peripherals, rcc, Peripheral}; +use crate::{interrupt, pac, peripherals, rcc, Peri}; #[cfg(hash_v1)] const NUM_CONTEXT_REGS: usize = 51; @@ -119,7 +119,7 @@ type HmacKey<'k> = Option<&'k [u8]>; /// HASH driver. pub struct Hash<'d, T: Instance, M: Mode> { - _peripheral: PeripheralRef<'d, T>, + _peripheral: Peri<'d, T>, _phantom: PhantomData, #[cfg(hash_v2)] dma: Option>, @@ -128,11 +128,10 @@ pub struct Hash<'d, T: Instance, M: Mode> { impl<'d, T: Instance> Hash<'d, T, Blocking> { /// Instantiates, resets, and enables the HASH peripheral. pub fn new_blocking( - peripheral: impl Peripheral

+ 'd, + peripheral: Peri<'d, T>, _irq: impl interrupt::typelevel::Binding> + 'd, ) -> Self { rcc::enable_and_reset::(); - into_ref!(peripheral); let instance = Self { _peripheral: peripheral, _phantom: PhantomData, @@ -396,12 +395,11 @@ impl<'d, T: Instance, M: Mode> Hash<'d, T, M> { impl<'d, T: Instance> Hash<'d, T, Async> { /// Instantiates, resets, and enables the HASH peripheral. pub fn new( - peripheral: impl Peripheral

+ 'd, - dma: impl Peripheral

> + 'd, + peripheral: Peri<'d, T>, + dma: Peri<'d, impl Dma>, _irq: impl interrupt::typelevel::Binding> + 'd, ) -> Self { rcc::enable_and_reset::(); - into_ref!(peripheral, dma); let instance = Self { _peripheral: peripheral, _phantom: PhantomData, @@ -583,7 +581,7 @@ trait SealedInstance { /// HASH instance trait. #[allow(private_bounds)] -pub trait Instance: SealedInstance + Peripheral

+ crate::rcc::RccPeripheral + 'static + Send { +pub trait Instance: SealedInstance + PeripheralType + crate::rcc::RccPeripheral + 'static + Send { /// Interrupt for this HASH instance. type Interrupt: interrupt::typelevel::Interrupt; } diff --git a/embassy-stm32/src/hrtim/mod.rs b/embassy-stm32/src/hrtim/mod.rs index d9b7c16fb..1d0594125 100644 --- a/embassy-stm32/src/hrtim/mod.rs +++ b/embassy-stm32/src/hrtim/mod.rs @@ -4,12 +4,12 @@ mod traits; use core::marker::PhantomData; -use embassy_hal_internal::{into_ref, PeripheralRef}; +use embassy_hal_internal::Peri; pub use traits::Instance; use crate::gpio::{AfType, AnyPin, OutputType, Speed}; +use crate::rcc; use crate::time::Hertz; -use crate::{rcc, Peripheral}; /// HRTIM burst controller instance. pub struct BurstController { @@ -62,13 +62,13 @@ pub trait AdvancedChannel: SealedAdvancedChannel {} /// HRTIM PWM pin. pub struct PwmPin<'d, T, C> { - _pin: PeripheralRef<'d, AnyPin>, + _pin: Peri<'d, AnyPin>, phantom: PhantomData<(T, C)>, } /// HRTIM complementary PWM pin. pub struct ComplementaryPwmPin<'d, T, C> { - _pin: PeripheralRef<'d, AnyPin>, + _pin: Peri<'d, AnyPin>, phantom: PhantomData<(T, C)>, } @@ -76,8 +76,7 @@ macro_rules! advanced_channel_impl { ($new_chx:ident, $channel:tt, $ch_num:expr, $pin_trait:ident, $complementary_pin_trait:ident) => { impl<'d, T: Instance> PwmPin<'d, T, $channel> { #[doc = concat!("Create a new ", stringify!($channel), " PWM pin instance.")] - pub fn $new_chx(pin: impl Peripheral

> + 'd) -> Self { - into_ref!(pin); + pub fn $new_chx(pin: Peri<'d, impl $pin_trait>) -> Self { critical_section::with(|_| { pin.set_low(); pin.set_as_af( @@ -86,7 +85,7 @@ macro_rules! advanced_channel_impl { ); }); PwmPin { - _pin: pin.map_into(), + _pin: pin.into(), phantom: PhantomData, } } @@ -94,8 +93,7 @@ macro_rules! advanced_channel_impl { impl<'d, T: Instance> ComplementaryPwmPin<'d, T, $channel> { #[doc = concat!("Create a new ", stringify!($channel), " complementary PWM pin instance.")] - pub fn $new_chx(pin: impl Peripheral

> + 'd) -> Self { - into_ref!(pin); + pub fn $new_chx(pin: Peri<'d, impl $complementary_pin_trait>) -> Self { critical_section::with(|_| { pin.set_low(); pin.set_as_af( @@ -104,7 +102,7 @@ macro_rules! advanced_channel_impl { ); }); ComplementaryPwmPin { - _pin: pin.map_into(), + _pin: pin.into(), phantom: PhantomData, } } @@ -129,7 +127,7 @@ advanced_channel_impl!(new_chf, ChF, 5, ChannelFPin, ChannelFComplementaryPin); /// Struct used to divide a high resolution timer into multiple channels pub struct AdvancedPwm<'d, T: Instance> { - _inner: PeripheralRef<'d, T>, + _inner: Peri<'d, T>, /// Master instance. pub master: Master, /// Burst controller. @@ -154,7 +152,7 @@ impl<'d, T: Instance> AdvancedPwm<'d, T> { /// /// This splits the HRTIM into its constituent parts, which you can then use individually. pub fn new( - tim: impl Peripheral

+ 'd, + tim: Peri<'d, T>, _cha: Option>>, _chan: Option>>, _chb: Option>>, @@ -171,9 +169,7 @@ impl<'d, T: Instance> AdvancedPwm<'d, T> { Self::new_inner(tim) } - fn new_inner(tim: impl Peripheral

+ 'd) -> Self { - into_ref!(tim); - + fn new_inner(tim: Peri<'d, T>) -> Self { rcc::enable_and_reset::(); #[cfg(stm32f334)] diff --git a/embassy-stm32/src/hrtim/traits.rs b/embassy-stm32/src/hrtim/traits.rs index 75f9971e2..6c0661146 100644 --- a/embassy-stm32/src/hrtim/traits.rs +++ b/embassy-stm32/src/hrtim/traits.rs @@ -1,3 +1,5 @@ +use embassy_hal_internal::PeripheralType; + use crate::rcc::RccPeripheral; use crate::time::Hertz; @@ -153,7 +155,7 @@ pub(crate) trait SealedInstance: RccPeripheral { /// HRTIM instance trait. #[allow(private_bounds)] -pub trait Instance: SealedInstance + 'static {} +pub trait Instance: SealedInstance + PeripheralType + 'static {} foreach_interrupt! { ($inst:ident, hrtim, HRTIM, MASTER, $irq:ident) => { diff --git a/embassy-stm32/src/hsem/mod.rs b/embassy-stm32/src/hsem/mod.rs index 06ab7a9bc..31527bcdb 100644 --- a/embassy-stm32/src/hsem/mod.rs +++ b/embassy-stm32/src/hsem/mod.rs @@ -1,13 +1,14 @@ //! Hardware Semaphore (HSEM) +use embassy_hal_internal::PeripheralType; + +use crate::pac; +use crate::rcc::RccPeripheral; // TODO: This code works for all HSEM implemenations except for the STM32WBA52/4/5xx MCUs. // Those MCUs have a different HSEM implementation (Secure semaphore lock support, // Privileged / unprivileged semaphore lock support, Semaphore lock protection via semaphore attribute), // which is not yet supported by this code. -use embassy_hal_internal::{into_ref, PeripheralRef}; - -use crate::rcc::RccPeripheral; -use crate::{pac, Peripheral}; +use crate::Peri; /// HSEM error. #[derive(Debug)] @@ -73,13 +74,12 @@ fn core_id_to_index(core: CoreId) -> usize { /// HSEM driver pub struct HardwareSemaphore<'d, T: Instance> { - _peri: PeripheralRef<'d, T>, + _peri: Peri<'d, T>, } impl<'d, T: Instance> HardwareSemaphore<'d, T> { /// Creates a new HardwareSemaphore instance. - pub fn new(peripheral: impl Peripheral

+ 'd) -> Self { - into_ref!(peripheral); + pub fn new(peripheral: Peri<'d, T>) -> Self { HardwareSemaphore { _peri: peripheral } } @@ -177,7 +177,7 @@ trait SealedInstance { /// HSEM instance trait. #[allow(private_bounds)] -pub trait Instance: SealedInstance + RccPeripheral + Send + 'static {} +pub trait Instance: SealedInstance + PeripheralType + RccPeripheral + Send + 'static {} impl SealedInstance for crate::peripherals::HSEM { fn regs() -> crate::pac::hsem::Hsem { diff --git a/embassy-stm32/src/hspi/mod.rs b/embassy-stm32/src/hspi/mod.rs index 54b442481..62bc0e979 100644 --- a/embassy-stm32/src/hspi/mod.rs +++ b/embassy-stm32/src/hspi/mod.rs @@ -13,15 +13,15 @@ pub mod enums; use core::marker::PhantomData; use embassy_embedded_hal::{GetConfig, SetConfig}; -use embassy_hal_internal::{into_ref, PeripheralRef}; +use embassy_hal_internal::{Peri, PeripheralType}; pub use enums::*; use crate::dma::{word, ChannelAndRequest}; use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed}; use crate::mode::{Async, Blocking, Mode as PeriMode}; use crate::pac::hspi::Hspi as Regs; +use crate::peripherals; use crate::rcc::{self, RccPeripheral}; -use crate::{peripherals, Peripheral}; /// HSPI driver config. #[derive(Clone, Copy)] @@ -163,27 +163,27 @@ pub enum HspiError { /// HSPI driver. pub struct Hspi<'d, T: Instance, M: PeriMode> { - _peri: PeripheralRef<'d, T>, - sck: Option>, - d0: Option>, - d1: Option>, - d2: Option>, - d3: Option>, - d4: Option>, - d5: Option>, - d6: Option>, - d7: Option>, - d8: Option>, - d9: Option>, - d10: Option>, - d11: Option>, - d12: Option>, - d13: Option>, - d14: Option>, - d15: Option>, - nss: Option>, - dqs0: Option>, - dqs1: Option>, + _peri: Peri<'d, T>, + sck: Option>, + d0: Option>, + d1: Option>, + d2: Option>, + d3: Option>, + d4: Option>, + d5: Option>, + d6: Option>, + d7: Option>, + d8: Option>, + d9: Option>, + d10: Option>, + d11: Option>, + d12: Option>, + d13: Option>, + d14: Option>, + d15: Option>, + nss: Option>, + dqs0: Option>, + dqs1: Option>, dma: Option>, _phantom: PhantomData, config: Config, @@ -247,34 +247,32 @@ impl<'d, T: Instance, M: PeriMode> Hspi<'d, T, M> { } fn new_inner( - peri: impl Peripheral

+ 'd, - d0: Option>, - d1: Option>, - d2: Option>, - d3: Option>, - d4: Option>, - d5: Option>, - d6: Option>, - d7: Option>, - d8: Option>, - d9: Option>, - d10: Option>, - d11: Option>, - d12: Option>, - d13: Option>, - d14: Option>, - d15: Option>, - sck: Option>, - nss: Option>, - dqs0: Option>, - dqs1: Option>, + peri: Peri<'d, T>, + d0: Option>, + d1: Option>, + d2: Option>, + d3: Option>, + d4: Option>, + d5: Option>, + d6: Option>, + d7: Option>, + d8: Option>, + d9: Option>, + d10: Option>, + d11: Option>, + d12: Option>, + d13: Option>, + d14: Option>, + d15: Option>, + sck: Option>, + nss: Option>, + dqs0: Option>, + dqs1: Option>, dma: Option>, config: Config, width: HspiWidth, dual_memory_mode: bool, ) -> Self { - into_ref!(peri); - // System configuration rcc::enable_and_reset::(); @@ -579,11 +577,11 @@ impl<'d, T: Instance, M: PeriMode> Hspi<'d, T, M> { impl<'d, T: Instance> Hspi<'d, T, Blocking> { /// Create new blocking HSPI driver for single spi external chip pub fn new_blocking_singlespi( - peri: impl Peripheral

+ 'd, - sck: impl Peripheral

> + 'd, - d0: impl Peripheral

> + 'd, - d1: impl Peripheral

> + 'd, - nss: impl Peripheral

> + 'd, + peri: Peri<'d, T>, + sck: Peri<'d, impl SckPin>, + d0: Peri<'d, impl D0Pin>, + d1: Peri<'d, impl D1Pin>, + nss: Peri<'d, impl NSSPin>, config: Config, ) -> Self { Self::new_inner( @@ -620,18 +618,18 @@ impl<'d, T: Instance> Hspi<'d, T, Blocking> { /// Create new blocking HSPI driver for octospi external chip pub fn new_blocking_octospi( - peri: impl Peripheral

+ 'd, - sck: impl Peripheral

> + 'd, - d0: impl Peripheral

> + 'd, - d1: impl Peripheral

> + 'd, - d2: impl Peripheral

> + 'd, - d3: impl Peripheral

> + 'd, - d4: impl Peripheral

> + 'd, - d5: impl Peripheral

> + 'd, - d6: impl Peripheral

> + 'd, - d7: impl Peripheral

> + 'd, - nss: impl Peripheral

> + 'd, - dqs0: impl Peripheral

> + 'd, + peri: Peri<'d, T>, + sck: Peri<'d, impl SckPin>, + d0: Peri<'d, impl D0Pin>, + d1: Peri<'d, impl D1Pin>, + d2: Peri<'d, impl D2Pin>, + d3: Peri<'d, impl D3Pin>, + d4: Peri<'d, impl D4Pin>, + d5: Peri<'d, impl D5Pin>, + d6: Peri<'d, impl D6Pin>, + d7: Peri<'d, impl D7Pin>, + nss: Peri<'d, impl NSSPin>, + dqs0: Peri<'d, impl DQS0Pin>, config: Config, ) -> Self { Self::new_inner( @@ -670,12 +668,12 @@ impl<'d, T: Instance> Hspi<'d, T, Blocking> { impl<'d, T: Instance> Hspi<'d, T, Async> { /// Create new HSPI driver for a single spi external chip pub fn new_singlespi( - peri: impl Peripheral

+ 'd, - sck: impl Peripheral

> + 'd, - d0: impl Peripheral

> + 'd, - d1: impl Peripheral

> + 'd, - nss: impl Peripheral

> + 'd, - dma: impl Peripheral

> + 'd, + peri: Peri<'d, T>, + sck: Peri<'d, impl SckPin>, + d0: Peri<'d, impl D0Pin>, + d1: Peri<'d, impl D1Pin>, + nss: Peri<'d, impl NSSPin>, + dma: Peri<'d, impl HspiDma>, config: Config, ) -> Self { Self::new_inner( @@ -712,19 +710,19 @@ impl<'d, T: Instance> Hspi<'d, T, Async> { /// Create new HSPI driver for octospi external chip pub fn new_octospi( - peri: impl Peripheral

+ 'd, - sck: impl Peripheral

> + 'd, - d0: impl Peripheral

> + 'd, - d1: impl Peripheral

> + 'd, - d2: impl Peripheral

> + 'd, - d3: impl Peripheral

> + 'd, - d4: impl Peripheral

> + 'd, - d5: impl Peripheral

> + 'd, - d6: impl Peripheral

> + 'd, - d7: impl Peripheral

> + 'd, - nss: impl Peripheral

> + 'd, - dqs0: impl Peripheral

> + 'd, - dma: impl Peripheral

> + 'd, + peri: Peri<'d, T>, + sck: Peri<'d, impl SckPin>, + d0: Peri<'d, impl D0Pin>, + d1: Peri<'d, impl D1Pin>, + d2: Peri<'d, impl D2Pin>, + d3: Peri<'d, impl D3Pin>, + d4: Peri<'d, impl D4Pin>, + d5: Peri<'d, impl D5Pin>, + d6: Peri<'d, impl D6Pin>, + d7: Peri<'d, impl D7Pin>, + nss: Peri<'d, impl NSSPin>, + dqs0: Peri<'d, impl DQS0Pin>, + dma: Peri<'d, impl HspiDma>, config: Config, ) -> Self { Self::new_inner( @@ -943,7 +941,7 @@ pub(crate) trait SealedInstance { /// HSPI instance trait. #[allow(private_bounds)] -pub trait Instance: Peripheral

+ SealedInstance + RccPeripheral {} +pub trait Instance: SealedInstance + PeripheralType + RccPeripheral {} pin_trait!(SckPin, Instance); pin_trait!(NckPin, Instance); diff --git a/embassy-stm32/src/i2c/mod.rs b/embassy-stm32/src/i2c/mod.rs index 3a9954663..1689fdb84 100644 --- a/embassy-stm32/src/i2c/mod.rs +++ b/embassy-stm32/src/i2c/mod.rs @@ -9,7 +9,7 @@ use core::future::Future; use core::iter; use core::marker::PhantomData; -use embassy_hal_internal::{Peripheral, PeripheralRef}; +use embassy_hal_internal::Peri; use embassy_sync::waitqueue::AtomicWaker; #[cfg(feature = "time")] use embassy_time::{Duration, Instant}; @@ -131,8 +131,8 @@ pub struct I2c<'d, M: Mode> { info: &'static Info, state: &'static State, kernel_clock: Hertz, - scl: Option>, - sda: Option>, + scl: Option>, + sda: Option>, tx_dma: Option>, rx_dma: Option>, #[cfg(feature = "time")] @@ -143,14 +143,14 @@ pub struct I2c<'d, M: Mode> { impl<'d> I2c<'d, Async> { /// Create a new I2C driver. pub fn new( - peri: impl Peripheral

+ 'd, - scl: impl Peripheral

> + 'd, - sda: impl Peripheral

> + 'd, + peri: Peri<'d, T>, + scl: Peri<'d, impl SclPin>, + sda: Peri<'d, impl SdaPin>, _irq: impl interrupt::typelevel::Binding> + interrupt::typelevel::Binding> + 'd, - tx_dma: impl Peripheral

> + 'd, - rx_dma: impl Peripheral

> + 'd, + tx_dma: Peri<'d, impl TxDma>, + rx_dma: Peri<'d, impl RxDma>, freq: Hertz, config: Config, ) -> Self { @@ -169,9 +169,9 @@ impl<'d> I2c<'d, Async> { impl<'d> I2c<'d, Blocking> { /// Create a new blocking I2C driver. pub fn new_blocking( - peri: impl Peripheral

+ 'd, - scl: impl Peripheral

> + 'd, - sda: impl Peripheral

> + 'd, + peri: Peri<'d, T>, + scl: Peri<'d, impl SclPin>, + sda: Peri<'d, impl SdaPin>, freq: Hertz, config: Config, ) -> Self { @@ -190,9 +190,9 @@ impl<'d> I2c<'d, Blocking> { impl<'d, M: Mode> I2c<'d, M> { /// Create a new I2C driver. fn new_inner( - _peri: impl Peripheral

+ 'd, - scl: Option>, - sda: Option>, + _peri: Peri<'d, T>, + scl: Option>, + sda: Option>, tx_dma: Option>, rx_dma: Option>, freq: Hertz, diff --git a/embassy-stm32/src/i2s.rs b/embassy-stm32/src/i2s.rs index ce166d718..5005a5cdb 100644 --- a/embassy-stm32/src/i2s.rs +++ b/embassy-stm32/src/i2s.rs @@ -1,7 +1,6 @@ //! Inter-IC Sound (I2S) use embassy_futures::join::join; -use embassy_hal_internal::into_ref; use stm32_metapac::spi::vals; use crate::dma::{ringbuffer, ChannelAndRequest, ReadableRingBuffer, TransferOptions, WritableRingBuffer}; @@ -9,7 +8,7 @@ use crate::gpio::{AfType, AnyPin, OutputType, SealedPin, Speed}; use crate::mode::Async; use crate::spi::{Config as SpiConfig, RegsExt as _, *}; use crate::time::Hertz; -use crate::{Peripheral, PeripheralRef}; +use crate::Peri; /// I2S mode #[derive(Copy, Clone)] @@ -225,11 +224,11 @@ pub struct I2S<'d, W: Word> { #[allow(dead_code)] mode: Mode, spi: Spi<'d, Async>, - txsd: Option>, - rxsd: Option>, - ws: Option>, - ck: Option>, - mck: Option>, + txsd: Option>, + rxsd: Option>, + ws: Option>, + ck: Option>, + mck: Option>, tx_ring_buffer: Option>, rx_ring_buffer: Option>, } @@ -237,12 +236,12 @@ pub struct I2S<'d, W: Word> { impl<'d, W: Word> I2S<'d, W> { /// Create a transmitter driver. pub fn new_txonly( - peri: impl Peripheral

+ 'd, - sd: impl Peripheral

> + 'd, - ws: impl Peripheral

> + 'd, - ck: impl Peripheral

> + 'd, - mck: impl Peripheral

> + 'd, - txdma: impl Peripheral

> + 'd, + peri: Peri<'d, T>, + sd: Peri<'d, impl MosiPin>, + ws: Peri<'d, impl WsPin>, + ck: Peri<'d, impl CkPin>, + mck: Peri<'d, impl MckPin>, + txdma: Peri<'d, impl TxDma>, txdma_buf: &'d mut [W], freq: Hertz, config: Config, @@ -264,11 +263,11 @@ impl<'d, W: Word> I2S<'d, W> { /// Create a transmitter driver without a master clock pin. pub fn new_txonly_nomck( - peri: impl Peripheral

+ 'd, - sd: impl Peripheral

> + 'd, - ws: impl Peripheral

> + 'd, - ck: impl Peripheral

> + 'd, - txdma: impl Peripheral

> + 'd, + peri: Peri<'d, T>, + sd: Peri<'d, impl MosiPin>, + ws: Peri<'d, impl WsPin>, + ck: Peri<'d, impl CkPin>, + txdma: Peri<'d, impl TxDma>, txdma_buf: &'d mut [W], freq: Hertz, config: Config, @@ -290,12 +289,12 @@ impl<'d, W: Word> I2S<'d, W> { /// Create a receiver driver. pub fn new_rxonly( - peri: impl Peripheral

+ 'd, - sd: impl Peripheral

> + 'd, - ws: impl Peripheral

> + 'd, - ck: impl Peripheral

> + 'd, - mck: impl Peripheral

> + 'd, - rxdma: impl Peripheral

> + 'd, + peri: Peri<'d, T>, + sd: Peri<'d, impl MisoPin>, + ws: Peri<'d, impl WsPin>, + ck: Peri<'d, impl CkPin>, + mck: Peri<'d, impl MckPin>, + rxdma: Peri<'d, impl RxDma>, rxdma_buf: &'d mut [W], freq: Hertz, config: Config, @@ -318,15 +317,15 @@ impl<'d, W: Word> I2S<'d, W> { #[cfg(spi_v3)] /// Create a full duplex driver. pub fn new_full_duplex( - peri: impl Peripheral

+ 'd, - txsd: impl Peripheral

> + 'd, - rxsd: impl Peripheral

> + 'd, - ws: impl Peripheral

> + 'd, - ck: impl Peripheral

> + 'd, - mck: impl Peripheral

> + 'd, - txdma: impl Peripheral

> + 'd, + peri: Peri<'d, T>, + txsd: Peri<'d, impl MosiPin>, + rxsd: Peri<'d, impl MisoPin>, + ws: Peri<'d, impl WsPin>, + ck: Peri<'d, impl CkPin>, + mck: Peri<'d, impl MckPin>, + txdma: Peri<'d, impl TxDma>, txdma_buf: &'d mut [W], - rxdma: impl Peripheral

> + 'd, + rxdma: Peri<'d, impl RxDma>, rxdma_buf: &'d mut [W], freq: Hertz, config: Config, @@ -466,20 +465,18 @@ impl<'d, W: Word> I2S<'d, W> { } fn new_inner( - peri: impl Peripheral

+ 'd, - txsd: Option>, - rxsd: Option>, - ws: impl Peripheral

> + 'd, - ck: impl Peripheral

> + 'd, - mck: Option>, + peri: Peri<'d, T>, + txsd: Option>, + rxsd: Option>, + ws: Peri<'d, impl WsPin>, + ck: Peri<'d, impl CkPin>, + mck: Option>, txdma: Option<(ChannelAndRequest<'d>, &'d mut [W])>, rxdma: Option<(ChannelAndRequest<'d>, &'d mut [W])>, freq: Hertz, config: Config, function: Function, ) -> Self { - into_ref!(ws, ck); - ws.set_as_af(ws.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh)); ck.set_as_af(ck.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh)); @@ -583,11 +580,11 @@ impl<'d, W: Word> I2S<'d, W> { Self { mode: config.mode, spi, - txsd: txsd.map(|w| w.map_into()), - rxsd: rxsd.map(|w| w.map_into()), - ws: Some(ws.map_into()), - ck: Some(ck.map_into()), - mck: mck.map(|w| w.map_into()), + txsd: txsd.map(|w| w.into()), + rxsd: rxsd.map(|w| w.into()), + ws: Some(ws.into()), + ck: Some(ck.into()), + mck: mck.map(|w| w.into()), tx_ring_buffer: txdma.map(|(ch, buf)| unsafe { WritableRingBuffer::new(ch.channel, ch.request, regs.tx_ptr(), buf, opts) }), diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index c37908dbc..4d7aac81f 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -211,7 +211,7 @@ macro_rules! bind_interrupts { // Reexports pub use _generated::{peripherals, Peripherals}; -pub use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; +pub use embassy_hal_internal::{Peri, PeripheralType}; #[cfg(feature = "unstable-pac")] pub use stm32_metapac as pac; #[cfg(not(feature = "unstable-pac"))] diff --git a/embassy-stm32/src/lptim/mod.rs b/embassy-stm32/src/lptim/mod.rs index 1649cc5b4..e0ddba1c7 100644 --- a/embassy-stm32/src/lptim/mod.rs +++ b/embassy-stm32/src/lptim/mod.rs @@ -10,6 +10,7 @@ use crate::rcc::RccPeripheral; mod channel; #[cfg(any(lptim_v2a, lptim_v2b))] pub use channel::Channel; +use embassy_hal_internal::PeripheralType; pin_trait!(OutputPin, BasicInstance); pin_trait!(Channel1Pin, BasicInstance); @@ -22,7 +23,7 @@ pub(crate) trait SealedBasicInstance: RccPeripheral {} /// LPTIM basic instance trait. #[allow(private_bounds)] -pub trait BasicInstance: SealedBasicInstance + 'static {} +pub trait BasicInstance: PeripheralType + SealedBasicInstance + 'static {} /// LPTIM instance trait. #[allow(private_bounds)] diff --git a/embassy-stm32/src/lptim/pwm.rs b/embassy-stm32/src/lptim/pwm.rs index 132f5815e..2f2d7ba01 100644 --- a/embassy-stm32/src/lptim/pwm.rs +++ b/embassy-stm32/src/lptim/pwm.rs @@ -2,7 +2,7 @@ use core::marker::PhantomData; -use embassy_hal_internal::{into_ref, PeripheralRef}; +use embassy_hal_internal::Peri; use super::timer::Timer; #[cfg(not(any(lptim_v2a, lptim_v2b)))] @@ -14,7 +14,6 @@ use super::{BasicInstance, Instance}; use crate::gpio::Pull; use crate::gpio::{AfType, AnyPin, OutputType, Speed}; use crate::time::Hertz; -use crate::Peripheral; /// Output marker type. pub enum Output {} @@ -27,7 +26,7 @@ pub enum Ch2 {} /// /// This wraps a pin to make it usable with PWM. pub struct PwmPin<'d, T, C> { - _pin: PeripheralRef<'d, AnyPin>, + _pin: Peri<'d, AnyPin>, phantom: PhantomData<(T, C)>, } @@ -48,8 +47,7 @@ macro_rules! channel_impl { ($new_chx:ident, $new_chx_with_config:ident, $channel:ident, $pin_trait:ident) => { impl<'d, T: BasicInstance> PwmPin<'d, T, $channel> { #[doc = concat!("Create a new ", stringify!($channel), " PWM pin instance.")] - pub fn $new_chx(pin: impl Peripheral

> + 'd) -> Self { - into_ref!(pin); + pub fn $new_chx(pin: Peri<'d, impl $pin_trait>) -> Self { critical_section::with(|_| { pin.set_low(); pin.set_as_af( @@ -58,16 +56,12 @@ macro_rules! channel_impl { ); }); PwmPin { - _pin: pin.map_into(), + _pin: pin.into(), phantom: PhantomData, } } #[doc = concat!("Create a new ", stringify!($channel), " PWM pin instance with config.")] - pub fn $new_chx_with_config( - pin: impl Peripheral

> + 'd, - pin_config: PwmPinConfig, - ) -> Self { - into_ref!(pin); + pub fn $new_chx_with_config(pin: Peri<'d, impl $pin_trait>, pin_config: PwmPinConfig) -> Self { critical_section::with(|_| { pin.set_low(); pin.set_as_af( @@ -79,7 +73,7 @@ macro_rules! channel_impl { ); }); PwmPin { - _pin: pin.map_into(), + _pin: pin.into(), phantom: PhantomData, } } @@ -102,7 +96,7 @@ pub struct Pwm<'d, T: Instance> { #[cfg(not(any(lptim_v2a, lptim_v2b)))] impl<'d, T: Instance> Pwm<'d, T> { /// Create a new PWM driver. - pub fn new(tim: impl Peripheral

+ 'd, _output_pin: PwmPin<'d, T, Output>, freq: Hertz) -> Self { + pub fn new(tim: Peri<'d, T>, _output_pin: PwmPin<'d, T, Output>, freq: Hertz) -> Self { Self::new_inner(tim, freq) } @@ -128,7 +122,7 @@ impl<'d, T: Instance> Pwm<'d, T> { impl<'d, T: Instance> Pwm<'d, T> { /// Create a new PWM driver. pub fn new( - tim: impl Peripheral

+ 'd, + tim: Peri<'d, T>, _ch1_pin: Option>, _ch2_pin: Option>, freq: Hertz, @@ -174,7 +168,7 @@ impl<'d, T: Instance> Pwm<'d, T> { } impl<'d, T: Instance> Pwm<'d, T> { - fn new_inner(tim: impl Peripheral

+ 'd, freq: Hertz) -> Self { + fn new_inner(tim: Peri<'d, T>, freq: Hertz) -> Self { let mut this = Self { inner: Timer::new(tim) }; this.inner.enable(); diff --git a/embassy-stm32/src/lptim/timer/mod.rs b/embassy-stm32/src/lptim/timer/mod.rs index e62fcab49..a629be62b 100644 --- a/embassy-stm32/src/lptim/timer/mod.rs +++ b/embassy-stm32/src/lptim/timer/mod.rs @@ -1,7 +1,7 @@ //! Low-level timer driver. mod prescaler; -use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; +use embassy_hal_internal::Peri; #[cfg(any(lptim_v2a, lptim_v2b))] use super::channel::Channel; @@ -17,14 +17,12 @@ use crate::time::Hertz; /// Low-level timer driver. pub struct Timer<'d, T: Instance> { - _tim: PeripheralRef<'d, T>, + _tim: Peri<'d, T>, } impl<'d, T: Instance> Timer<'d, T> { /// Create a new timer driver. - pub fn new(tim: impl Peripheral

+ 'd) -> Self { - into_ref!(tim); - + pub fn new(tim: Peri<'d, T>) -> Self { rcc::enable_and_reset::(); Self { _tim: tim } diff --git a/embassy-stm32/src/ltdc.rs b/embassy-stm32/src/ltdc.rs index 16210b7dc..0f6ef569c 100644 --- a/embassy-stm32/src/ltdc.rs +++ b/embassy-stm32/src/ltdc.rs @@ -6,7 +6,7 @@ use core::future::poll_fn; use core::marker::PhantomData; use core::task::Poll; -use embassy_hal_internal::{into_ref, PeripheralRef}; +use embassy_hal_internal::PeripheralType; use embassy_sync::waitqueue::AtomicWaker; use stm32_metapac::ltdc::regs::Dccr; use stm32_metapac::ltdc::vals::{Bf1, Bf2, Cfuif, Clif, Crrif, Cterrif, Pf, Vbr}; @@ -14,7 +14,7 @@ use stm32_metapac::ltdc::vals::{Bf1, Bf2, Cfuif, Clif, Crrif, Cterrif, Pf, Vbr}; use crate::gpio::{AfType, OutputType, Speed}; use crate::interrupt::typelevel::Interrupt; use crate::interrupt::{self}; -use crate::{peripherals, rcc, Peripheral}; +use crate::{peripherals, rcc, Peri}; static LTDC_WAKER: AtomicWaker = AtomicWaker::new(); @@ -83,7 +83,7 @@ pub enum PolarityActive { /// LTDC driver. pub struct Ltdc<'d, T: Instance> { - _peri: PeripheralRef<'d, T>, + _peri: Peri<'d, T>, } /// LTDC interrupt handler. @@ -178,47 +178,45 @@ impl interrupt::typelevel::Handler for InterruptHandl impl<'d, T: Instance> Ltdc<'d, T> { // Create a new LTDC driver without specifying color and control pins. This is typically used if you want to drive a display though a DsiHost /// Note: Full-Duplex modes are not supported at this time - pub fn new(peri: impl Peripheral

+ 'd) -> Self { + pub fn new(peri: Peri<'d, T>) -> Self { Self::setup_clocks(); - into_ref!(peri); Self { _peri: peri } } /// Create a new LTDC driver. 8 pins per color channel for blue, green and red #[allow(clippy::too_many_arguments)] pub fn new_with_pins( - peri: impl Peripheral

+ 'd, + peri: Peri<'d, T>, _irq: impl interrupt::typelevel::Binding> + 'd, - clk: impl Peripheral

> + 'd, - hsync: impl Peripheral

> + 'd, - vsync: impl Peripheral

> + 'd, - b0: impl Peripheral

> + 'd, - b1: impl Peripheral

> + 'd, - b2: impl Peripheral

> + 'd, - b3: impl Peripheral

> + 'd, - b4: impl Peripheral

> + 'd, - b5: impl Peripheral

> + 'd, - b6: impl Peripheral

> + 'd, - b7: impl Peripheral

> + 'd, - g0: impl Peripheral

> + 'd, - g1: impl Peripheral

> + 'd, - g2: impl Peripheral

> + 'd, - g3: impl Peripheral

> + 'd, - g4: impl Peripheral

> + 'd, - g5: impl Peripheral

> + 'd, - g6: impl Peripheral

> + 'd, - g7: impl Peripheral

> + 'd, - r0: impl Peripheral

> + 'd, - r1: impl Peripheral

> + 'd, - r2: impl Peripheral

> + 'd, - r3: impl Peripheral

> + 'd, - r4: impl Peripheral

> + 'd, - r5: impl Peripheral

> + 'd, - r6: impl Peripheral

> + 'd, - r7: impl Peripheral

> + 'd, + clk: Peri<'d, impl ClkPin>, + hsync: Peri<'d, impl HsyncPin>, + vsync: Peri<'d, impl VsyncPin>, + b0: Peri<'d, impl B0Pin>, + b1: Peri<'d, impl B1Pin>, + b2: Peri<'d, impl B2Pin>, + b3: Peri<'d, impl B3Pin>, + b4: Peri<'d, impl B4Pin>, + b5: Peri<'d, impl B5Pin>, + b6: Peri<'d, impl B6Pin>, + b7: Peri<'d, impl B7Pin>, + g0: Peri<'d, impl G0Pin>, + g1: Peri<'d, impl G1Pin>, + g2: Peri<'d, impl G2Pin>, + g3: Peri<'d, impl G3Pin>, + g4: Peri<'d, impl G4Pin>, + g5: Peri<'d, impl G5Pin>, + g6: Peri<'d, impl G6Pin>, + g7: Peri<'d, impl G7Pin>, + r0: Peri<'d, impl R0Pin>, + r1: Peri<'d, impl R1Pin>, + r2: Peri<'d, impl R2Pin>, + r3: Peri<'d, impl R3Pin>, + r4: Peri<'d, impl R4Pin>, + r5: Peri<'d, impl R5Pin>, + r6: Peri<'d, impl R6Pin>, + r7: Peri<'d, impl R7Pin>, ) -> Self { Self::setup_clocks(); - into_ref!(peri); new_pin!(clk, AfType::output(OutputType::PushPull, Speed::VeryHigh)); new_pin!(hsync, AfType::output(OutputType::PushPull, Speed::VeryHigh)); new_pin!(vsync, AfType::output(OutputType::PushPull, Speed::VeryHigh)); @@ -529,7 +527,7 @@ trait SealedInstance: crate::rcc::SealedRccPeripheral { /// LTDC instance trait. #[allow(private_bounds)] -pub trait Instance: SealedInstance + Peripheral

+ crate::rcc::RccPeripheral + 'static + Send { +pub trait Instance: SealedInstance + PeripheralType + crate::rcc::RccPeripheral + 'static + Send { /// Interrupt for this LTDC instance. type Interrupt: interrupt::typelevel::Interrupt; } diff --git a/embassy-stm32/src/macros.rs b/embassy-stm32/src/macros.rs index 000773e2d..2c181a254 100644 --- a/embassy-stm32/src/macros.rs +++ b/embassy-stm32/src/macros.rs @@ -14,7 +14,7 @@ macro_rules! peri_trait { /// Peripheral instance trait. #[allow(private_bounds)] - pub trait Instance: crate::Peripheral

+ SealedInstance + crate::rcc::RccPeripheral { + pub trait Instance: SealedInstance + crate::PeripheralType + crate::rcc::RccPeripheral { $($( /// Interrupt for this peripheral. type $irq: crate::interrupt::typelevel::Interrupt; @@ -88,10 +88,10 @@ macro_rules! dma_trait_impl { #[allow(unused)] macro_rules! new_dma_nonopt { ($name:ident) => {{ - let dma = $name.into_ref(); + let dma = $name; let request = dma.request(); crate::dma::ChannelAndRequest { - channel: dma.map_into(), + channel: dma.into(), request, } }}; @@ -99,10 +99,10 @@ macro_rules! new_dma_nonopt { macro_rules! new_dma { ($name:ident) => {{ - let dma = $name.into_ref(); + let dma = $name; let request = dma.request(); Some(crate::dma::ChannelAndRequest { - channel: dma.map_into(), + channel: dma.into(), request, }) }}; @@ -110,8 +110,8 @@ macro_rules! new_dma { macro_rules! new_pin { ($name:ident, $af_type:expr) => {{ - let pin = $name.into_ref(); + let pin = $name; pin.set_as_af(pin.af_num(), $af_type); - Some(pin.map_into()) + Some(pin.into()) }}; } diff --git a/embassy-stm32/src/opamp.rs b/embassy-stm32/src/opamp.rs index c7610f4b5..a81493c1b 100644 --- a/embassy-stm32/src/opamp.rs +++ b/embassy-stm32/src/opamp.rs @@ -1,10 +1,10 @@ //! Operational Amplifier (OPAMP) #![macro_use] -use embassy_hal_internal::{into_ref, PeripheralRef}; +use embassy_hal_internal::PeripheralType; use crate::pac::opamp::vals::*; -use crate::Peripheral; +use crate::Peri; /// Gain #[allow(missing_docs)] @@ -52,16 +52,14 @@ pub struct OpAmpInternalOutput<'d, T: Instance> { /// OpAmp driver. pub struct OpAmp<'d, T: Instance> { - _inner: PeripheralRef<'d, T>, + _inner: Peri<'d, T>, } impl<'d, T: Instance> OpAmp<'d, T> { /// Create a new driver instance. /// /// Does not enable the opamp, but does set the speed mode on some families. - pub fn new(opamp: impl Peripheral

+ 'd, #[cfg(opamp_g4)] speed: OpAmpSpeed) -> Self { - into_ref!(opamp); - + pub fn new(opamp: Peri<'d, T>, #[cfg(opamp_g4)] speed: OpAmpSpeed) -> Self { #[cfg(opamp_g4)] T::regs().csr().modify(|w| { w.set_opahsm(speed.into()); @@ -82,12 +80,10 @@ impl<'d, T: Instance> OpAmp<'d, T> { /// [`OpAmpOutput`] is dropped. pub fn buffer_ext( &mut self, - in_pin: impl Peripheral

+ crate::gpio::Pin>, - out_pin: impl Peripheral

+ crate::gpio::Pin>, + in_pin: Peri<'_, impl NonInvertingPin + crate::gpio::Pin>, + out_pin: Peri<'_, impl OutputPin + crate::gpio::Pin>, gain: OpAmpGain, ) -> OpAmpOutput<'_, T> { - into_ref!(in_pin); - into_ref!(out_pin); in_pin.set_as_analog(); out_pin.set_as_analog(); @@ -119,11 +115,7 @@ impl<'d, T: Instance> OpAmp<'d, T> { /// directly used as an ADC input. The opamp will be disabled when the /// [`OpAmpOutput`] is dropped. #[cfg(opamp_g4)] - pub fn buffer_dac( - &mut self, - out_pin: impl Peripheral

+ crate::gpio::Pin>, - ) -> OpAmpOutput<'_, T> { - into_ref!(out_pin); + pub fn buffer_dac(&mut self, out_pin: Peri<'_, impl OutputPin + crate::gpio::Pin>) -> OpAmpOutput<'_, T> { out_pin.set_as_analog(); T::regs().csr().modify(|w| { @@ -149,10 +141,9 @@ impl<'d, T: Instance> OpAmp<'d, T> { #[cfg(opamp_g4)] pub fn buffer_int( &mut self, - pin: impl Peripheral

+ crate::gpio::Pin>, + pin: Peri<'_, impl NonInvertingPin + crate::gpio::Pin>, gain: OpAmpGain, ) -> OpAmpInternalOutput<'_, T> { - into_ref!(pin); pin.set_as_analog(); // PGA_GAIN value may have different meaning in different MCU serials, use with caution. @@ -211,7 +202,7 @@ pub(crate) trait SealedOutputPin {} /// Opamp instance trait. #[allow(private_bounds)] -pub trait Instance: SealedInstance + 'static {} +pub trait Instance: SealedInstance + PeripheralType + 'static {} /// Non-inverting pin trait. #[allow(private_bounds)] pub trait NonInvertingPin: SealedNonInvertingPin {} diff --git a/embassy-stm32/src/ospi/mod.rs b/embassy-stm32/src/ospi/mod.rs index 5dff3c4c3..74edfd5e4 100644 --- a/embassy-stm32/src/ospi/mod.rs +++ b/embassy-stm32/src/ospi/mod.rs @@ -8,7 +8,7 @@ pub mod enums; use core::marker::PhantomData; use embassy_embedded_hal::{GetConfig, SetConfig}; -use embassy_hal_internal::{into_ref, PeripheralRef}; +use embassy_hal_internal::PeripheralType; pub use enums::*; use stm32_metapac::octospi::vals::{PhaseMode, SizeInBits}; @@ -19,7 +19,7 @@ use crate::pac::octospi::{vals, Octospi as Regs}; #[cfg(octospim_v1)] use crate::pac::octospim::Octospim; use crate::rcc::{self, RccPeripheral}; -use crate::{peripherals, Peripheral}; +use crate::{peripherals, Peri}; /// OPSI driver config. #[derive(Clone, Copy)] @@ -160,18 +160,18 @@ pub enum OspiError { /// OSPI driver. pub struct Ospi<'d, T: Instance, M: PeriMode> { - _peri: PeripheralRef<'d, T>, - sck: Option>, - d0: Option>, - d1: Option>, - d2: Option>, - d3: Option>, - d4: Option>, - d5: Option>, - d6: Option>, - d7: Option>, - nss: Option>, - dqs: Option>, + _peri: Peri<'d, T>, + sck: Option>, + d0: Option>, + d1: Option>, + d2: Option>, + d3: Option>, + d4: Option>, + d5: Option>, + d6: Option>, + d7: Option>, + nss: Option>, + dqs: Option>, dma: Option>, _phantom: PhantomData, config: Config, @@ -245,25 +245,23 @@ impl<'d, T: Instance, M: PeriMode> Ospi<'d, T, M> { } fn new_inner( - peri: impl Peripheral

+ 'd, - d0: Option>, - d1: Option>, - d2: Option>, - d3: Option>, - d4: Option>, - d5: Option>, - d6: Option>, - d7: Option>, - sck: Option>, - nss: Option>, - dqs: Option>, + peri: Peri<'d, T>, + d0: Option>, + d1: Option>, + d2: Option>, + d3: Option>, + d4: Option>, + d5: Option>, + d6: Option>, + d7: Option>, + sck: Option>, + nss: Option>, + dqs: Option>, dma: Option>, config: Config, width: OspiWidth, dual_quad: bool, ) -> Self { - into_ref!(peri); - #[cfg(octospim_v1)] { // RCC for octospim should be enabled before writing register @@ -685,11 +683,11 @@ impl<'d, T: Instance, M: PeriMode> Ospi<'d, T, M> { impl<'d, T: Instance> Ospi<'d, T, Blocking> { /// Create new blocking OSPI driver for a single spi external chip pub fn new_blocking_singlespi( - peri: impl Peripheral

+ 'd, - sck: impl Peripheral

> + 'd, - d0: impl Peripheral

> + 'd, - d1: impl Peripheral

> + 'd, - nss: impl Peripheral

> + 'd, + peri: Peri<'d, T>, + sck: Peri<'d, impl SckPin>, + d0: Peri<'d, impl D0Pin>, + d1: Peri<'d, impl D1Pin>, + nss: Peri<'d, impl NSSPin>, config: Config, ) -> Self { Self::new_inner( @@ -717,11 +715,11 @@ impl<'d, T: Instance> Ospi<'d, T, Blocking> { /// Create new blocking OSPI driver for a dualspi external chip pub fn new_blocking_dualspi( - peri: impl Peripheral

+ 'd, - sck: impl Peripheral

> + 'd, - d0: impl Peripheral

> + 'd, - d1: impl Peripheral

> + 'd, - nss: impl Peripheral

> + 'd, + peri: Peri<'d, T>, + sck: Peri<'d, impl SckPin>, + d0: Peri<'d, impl D0Pin>, + d1: Peri<'d, impl D1Pin>, + nss: Peri<'d, impl NSSPin>, config: Config, ) -> Self { Self::new_inner( @@ -749,13 +747,13 @@ impl<'d, T: Instance> Ospi<'d, T, Blocking> { /// Create new blocking OSPI driver for a quadspi external chip pub fn new_blocking_quadspi( - peri: impl Peripheral

+ 'd, - sck: impl Peripheral

> + 'd, - d0: impl Peripheral

> + 'd, - d1: impl Peripheral

> + 'd, - d2: impl Peripheral

> + 'd, - d3: impl Peripheral

> + 'd, - nss: impl Peripheral

> + 'd, + peri: Peri<'d, T>, + sck: Peri<'d, impl SckPin>, + d0: Peri<'d, impl D0Pin>, + d1: Peri<'d, impl D1Pin>, + d2: Peri<'d, impl D2Pin>, + d3: Peri<'d, impl D3Pin>, + nss: Peri<'d, impl NSSPin>, config: Config, ) -> Self { Self::new_inner( @@ -783,17 +781,17 @@ impl<'d, T: Instance> Ospi<'d, T, Blocking> { /// Create new blocking OSPI driver for two quadspi external chips pub fn new_blocking_dualquadspi( - peri: impl Peripheral

+ 'd, - sck: impl Peripheral

> + 'd, - d0: impl Peripheral

> + 'd, - d1: impl Peripheral

> + 'd, - d2: impl Peripheral

> + 'd, - d3: impl Peripheral

> + 'd, - d4: impl Peripheral

> + 'd, - d5: impl Peripheral

> + 'd, - d6: impl Peripheral

> + 'd, - d7: impl Peripheral

> + 'd, - nss: impl Peripheral

> + 'd, + peri: Peri<'d, T>, + sck: Peri<'d, impl SckPin>, + d0: Peri<'d, impl D0Pin>, + d1: Peri<'d, impl D1Pin>, + d2: Peri<'d, impl D2Pin>, + d3: Peri<'d, impl D3Pin>, + d4: Peri<'d, impl D4Pin>, + d5: Peri<'d, impl D5Pin>, + d6: Peri<'d, impl D6Pin>, + d7: Peri<'d, impl D7Pin>, + nss: Peri<'d, impl NSSPin>, config: Config, ) -> Self { Self::new_inner( @@ -821,17 +819,17 @@ impl<'d, T: Instance> Ospi<'d, T, Blocking> { /// Create new blocking OSPI driver for octospi external chips pub fn new_blocking_octospi( - peri: impl Peripheral

+ 'd, - sck: impl Peripheral

> + 'd, - d0: impl Peripheral

> + 'd, - d1: impl Peripheral

> + 'd, - d2: impl Peripheral

> + 'd, - d3: impl Peripheral

> + 'd, - d4: impl Peripheral

> + 'd, - d5: impl Peripheral

> + 'd, - d6: impl Peripheral

> + 'd, - d7: impl Peripheral

> + 'd, - nss: impl Peripheral

> + 'd, + peri: Peri<'d, T>, + sck: Peri<'d, impl SckPin>, + d0: Peri<'d, impl D0Pin>, + d1: Peri<'d, impl D1Pin>, + d2: Peri<'d, impl D2Pin>, + d3: Peri<'d, impl D3Pin>, + d4: Peri<'d, impl D4Pin>, + d5: Peri<'d, impl D5Pin>, + d6: Peri<'d, impl D6Pin>, + d7: Peri<'d, impl D7Pin>, + nss: Peri<'d, impl NSSPin>, config: Config, ) -> Self { Self::new_inner( @@ -861,12 +859,12 @@ impl<'d, T: Instance> Ospi<'d, T, Blocking> { impl<'d, T: Instance> Ospi<'d, T, Async> { /// Create new blocking OSPI driver for a single spi external chip pub fn new_singlespi( - peri: impl Peripheral

+ 'd, - sck: impl Peripheral

> + 'd, - d0: impl Peripheral

> + 'd, - d1: impl Peripheral

> + 'd, - nss: impl Peripheral

> + 'd, - dma: impl Peripheral

> + 'd, + peri: Peri<'d, T>, + sck: Peri<'d, impl SckPin>, + d0: Peri<'d, impl D0Pin>, + d1: Peri<'d, impl D1Pin>, + nss: Peri<'d, impl NSSPin>, + dma: Peri<'d, impl OctoDma>, config: Config, ) -> Self { Self::new_inner( @@ -894,12 +892,12 @@ impl<'d, T: Instance> Ospi<'d, T, Async> { /// Create new blocking OSPI driver for a dualspi external chip pub fn new_dualspi( - peri: impl Peripheral

+ 'd, - sck: impl Peripheral

> + 'd, - d0: impl Peripheral

> + 'd, - d1: impl Peripheral

> + 'd, - nss: impl Peripheral

> + 'd, - dma: impl Peripheral

> + 'd, + peri: Peri<'d, T>, + sck: Peri<'d, impl SckPin>, + d0: Peri<'d, impl D0Pin>, + d1: Peri<'d, impl D1Pin>, + nss: Peri<'d, impl NSSPin>, + dma: Peri<'d, impl OctoDma>, config: Config, ) -> Self { Self::new_inner( @@ -927,14 +925,14 @@ impl<'d, T: Instance> Ospi<'d, T, Async> { /// Create new blocking OSPI driver for a quadspi external chip pub fn new_quadspi( - peri: impl Peripheral

+ 'd, - sck: impl Peripheral

> + 'd, - d0: impl Peripheral

> + 'd, - d1: impl Peripheral

> + 'd, - d2: impl Peripheral

> + 'd, - d3: impl Peripheral

> + 'd, - nss: impl Peripheral

> + 'd, - dma: impl Peripheral

> + 'd, + peri: Peri<'d, T>, + sck: Peri<'d, impl SckPin>, + d0: Peri<'d, impl D0Pin>, + d1: Peri<'d, impl D1Pin>, + d2: Peri<'d, impl D2Pin>, + d3: Peri<'d, impl D3Pin>, + nss: Peri<'d, impl NSSPin>, + dma: Peri<'d, impl OctoDma>, config: Config, ) -> Self { Self::new_inner( @@ -962,18 +960,18 @@ impl<'d, T: Instance> Ospi<'d, T, Async> { /// Create new blocking OSPI driver for two quadspi external chips pub fn new_dualquadspi( - peri: impl Peripheral

+ 'd, - sck: impl Peripheral

> + 'd, - d0: impl Peripheral

> + 'd, - d1: impl Peripheral

> + 'd, - d2: impl Peripheral

> + 'd, - d3: impl Peripheral

> + 'd, - d4: impl Peripheral

> + 'd, - d5: impl Peripheral

> + 'd, - d6: impl Peripheral

> + 'd, - d7: impl Peripheral

> + 'd, - nss: impl Peripheral

> + 'd, - dma: impl Peripheral

> + 'd, + peri: Peri<'d, T>, + sck: Peri<'d, impl SckPin>, + d0: Peri<'d, impl D0Pin>, + d1: Peri<'d, impl D1Pin>, + d2: Peri<'d, impl D2Pin>, + d3: Peri<'d, impl D3Pin>, + d4: Peri<'d, impl D4Pin>, + d5: Peri<'d, impl D5Pin>, + d6: Peri<'d, impl D6Pin>, + d7: Peri<'d, impl D7Pin>, + nss: Peri<'d, impl NSSPin>, + dma: Peri<'d, impl OctoDma>, config: Config, ) -> Self { Self::new_inner( @@ -1001,18 +999,18 @@ impl<'d, T: Instance> Ospi<'d, T, Async> { /// Create new blocking OSPI driver for octospi external chips pub fn new_octospi( - peri: impl Peripheral

+ 'd, - sck: impl Peripheral

> + 'd, - d0: impl Peripheral

> + 'd, - d1: impl Peripheral

> + 'd, - d2: impl Peripheral

> + 'd, - d3: impl Peripheral

> + 'd, - d4: impl Peripheral

> + 'd, - d5: impl Peripheral

> + 'd, - d6: impl Peripheral

> + 'd, - d7: impl Peripheral

> + 'd, - nss: impl Peripheral

> + 'd, - dma: impl Peripheral

> + 'd, + peri: Peri<'d, T>, + sck: Peri<'d, impl SckPin>, + d0: Peri<'d, impl D0Pin>, + d1: Peri<'d, impl D1Pin>, + d2: Peri<'d, impl D2Pin>, + d3: Peri<'d, impl D3Pin>, + d4: Peri<'d, impl D4Pin>, + d5: Peri<'d, impl D5Pin>, + d6: Peri<'d, impl D6Pin>, + d7: Peri<'d, impl D7Pin>, + nss: Peri<'d, impl NSSPin>, + dma: Peri<'d, impl OctoDma>, config: Config, ) -> Self { Self::new_inner( @@ -1221,12 +1219,12 @@ pub(crate) trait SealedInstance { /// OSPI instance trait. #[cfg(octospim_v1)] #[allow(private_bounds)] -pub trait Instance: Peripheral

+ SealedInstance + RccPeripheral + SealedOctospimInstance {} +pub trait Instance: SealedInstance + PeripheralType + RccPeripheral + SealedOctospimInstance {} /// OSPI instance trait. #[cfg(not(octospim_v1))] #[allow(private_bounds)] -pub trait Instance: Peripheral

+ SealedInstance + RccPeripheral {} +pub trait Instance: SealedInstance + PeripheralType + RccPeripheral {} pin_trait!(SckPin, Instance); pin_trait!(NckPin, Instance); diff --git a/embassy-stm32/src/qspi/mod.rs b/embassy-stm32/src/qspi/mod.rs index 411e533c9..0df057c53 100644 --- a/embassy-stm32/src/qspi/mod.rs +++ b/embassy-stm32/src/qspi/mod.rs @@ -6,7 +6,7 @@ pub mod enums; use core::marker::PhantomData; -use embassy_hal_internal::{into_ref, PeripheralRef}; +use embassy_hal_internal::PeripheralType; use enums::*; use crate::dma::ChannelAndRequest; @@ -14,7 +14,7 @@ use crate::gpio::{AfType, AnyPin, OutputType, Pull, Speed}; use crate::mode::{Async, Blocking, Mode as PeriMode}; use crate::pac::quadspi::Quadspi as Regs; use crate::rcc::{self, RccPeripheral}; -use crate::{peripherals, Peripheral}; +use crate::{peripherals, Peri}; /// QSPI transfer configuration. pub struct TransferConfig { @@ -75,13 +75,13 @@ impl Default for Config { /// QSPI driver. #[allow(dead_code)] pub struct Qspi<'d, T: Instance, M: PeriMode> { - _peri: PeripheralRef<'d, T>, - sck: Option>, - d0: Option>, - d1: Option>, - d2: Option>, - d3: Option>, - nss: Option>, + _peri: Peri<'d, T>, + sck: Option>, + d0: Option>, + d1: Option>, + d2: Option>, + d3: Option>, + nss: Option>, dma: Option>, _phantom: PhantomData, config: Config, @@ -89,19 +89,17 @@ pub struct Qspi<'d, T: Instance, M: PeriMode> { impl<'d, T: Instance, M: PeriMode> Qspi<'d, T, M> { fn new_inner( - peri: impl Peripheral

+ 'd, - d0: Option>, - d1: Option>, - d2: Option>, - d3: Option>, - sck: Option>, - nss: Option>, + peri: Peri<'d, T>, + d0: Option>, + d1: Option>, + d2: Option>, + d3: Option>, + sck: Option>, + nss: Option>, dma: Option>, config: Config, fsel: FlashSelection, ) -> Self { - into_ref!(peri); - rcc::enable_and_reset::(); while T::REGS.sr().read().busy() {} @@ -272,13 +270,13 @@ impl<'d, T: Instance, M: PeriMode> Qspi<'d, T, M> { impl<'d, T: Instance> Qspi<'d, T, Blocking> { /// Create a new QSPI driver for bank 1, in blocking mode. pub fn new_blocking_bank1( - peri: impl Peripheral

+ 'd, - d0: impl Peripheral

> + 'd, - d1: impl Peripheral

> + 'd, - d2: impl Peripheral

> + 'd, - d3: impl Peripheral

> + 'd, - sck: impl Peripheral

> + 'd, - nss: impl Peripheral

> + 'd, + peri: Peri<'d, T>, + d0: Peri<'d, impl BK1D0Pin>, + d1: Peri<'d, impl BK1D1Pin>, + d2: Peri<'d, impl BK1D2Pin>, + d3: Peri<'d, impl BK1D3Pin>, + sck: Peri<'d, impl SckPin>, + nss: Peri<'d, impl BK1NSSPin>, config: Config, ) -> Self { Self::new_inner( @@ -300,13 +298,13 @@ impl<'d, T: Instance> Qspi<'d, T, Blocking> { /// Create a new QSPI driver for bank 2, in blocking mode. pub fn new_blocking_bank2( - peri: impl Peripheral

+ 'd, - d0: impl Peripheral

> + 'd, - d1: impl Peripheral

> + 'd, - d2: impl Peripheral

> + 'd, - d3: impl Peripheral

> + 'd, - sck: impl Peripheral

> + 'd, - nss: impl Peripheral

> + 'd, + peri: Peri<'d, T>, + d0: Peri<'d, impl BK2D0Pin>, + d1: Peri<'d, impl BK2D1Pin>, + d2: Peri<'d, impl BK2D2Pin>, + d3: Peri<'d, impl BK2D3Pin>, + sck: Peri<'d, impl SckPin>, + nss: Peri<'d, impl BK2NSSPin>, config: Config, ) -> Self { Self::new_inner( @@ -330,14 +328,14 @@ impl<'d, T: Instance> Qspi<'d, T, Blocking> { impl<'d, T: Instance> Qspi<'d, T, Async> { /// Create a new QSPI driver for bank 1. pub fn new_bank1( - peri: impl Peripheral

+ 'd, - d0: impl Peripheral

> + 'd, - d1: impl Peripheral

> + 'd, - d2: impl Peripheral

> + 'd, - d3: impl Peripheral

> + 'd, - sck: impl Peripheral

> + 'd, - nss: impl Peripheral

> + 'd, - dma: impl Peripheral

> + 'd, + peri: Peri<'d, T>, + d0: Peri<'d, impl BK1D0Pin>, + d1: Peri<'d, impl BK1D1Pin>, + d2: Peri<'d, impl BK1D2Pin>, + d3: Peri<'d, impl BK1D3Pin>, + sck: Peri<'d, impl SckPin>, + nss: Peri<'d, impl BK1NSSPin>, + dma: Peri<'d, impl QuadDma>, config: Config, ) -> Self { Self::new_inner( @@ -359,14 +357,14 @@ impl<'d, T: Instance> Qspi<'d, T, Async> { /// Create a new QSPI driver for bank 2. pub fn new_bank2( - peri: impl Peripheral

+ 'd, - d0: impl Peripheral

> + 'd, - d1: impl Peripheral

> + 'd, - d2: impl Peripheral

> + 'd, - d3: impl Peripheral

> + 'd, - sck: impl Peripheral

> + 'd, - nss: impl Peripheral

> + 'd, - dma: impl Peripheral

> + 'd, + peri: Peri<'d, T>, + d0: Peri<'d, impl BK2D0Pin>, + d1: Peri<'d, impl BK2D1Pin>, + d2: Peri<'d, impl BK2D2Pin>, + d3: Peri<'d, impl BK2D3Pin>, + sck: Peri<'d, impl SckPin>, + nss: Peri<'d, impl BK2NSSPin>, + dma: Peri<'d, impl QuadDma>, config: Config, ) -> Self { Self::new_inner( @@ -465,7 +463,7 @@ trait SealedInstance { /// QSPI instance trait. #[allow(private_bounds)] -pub trait Instance: Peripheral

+ SealedInstance + RccPeripheral {} +pub trait Instance: SealedInstance + PeripheralType + RccPeripheral {} pin_trait!(SckPin, Instance); pin_trait!(BK1D0Pin, Instance); diff --git a/embassy-stm32/src/rcc/mco.rs b/embassy-stm32/src/rcc/mco.rs index d1ce14c86..c50e071fb 100644 --- a/embassy-stm32/src/rcc/mco.rs +++ b/embassy-stm32/src/rcc/mco.rs @@ -1,6 +1,6 @@ use core::marker::PhantomData; -use embassy_hal_internal::into_ref; +use embassy_hal_internal::PeripheralType; use crate::gpio::{AfType, OutputType, Speed}; #[cfg(not(any(stm32f1, rcc_f0v1, rcc_f3v1, rcc_f37)))] @@ -32,7 +32,7 @@ pub use crate::pac::rcc::vals::Mcosel as McoSource; ))] pub use crate::pac::rcc::vals::{Mco1sel as Mco1Source, Mco2sel as Mco2Source}; use crate::pac::RCC; -use crate::{peripherals, Peripheral}; +use crate::{peripherals, Peri}; #[cfg(any(stm32f1, rcc_f0v1, rcc_f3v1, rcc_f37))] #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] @@ -43,7 +43,7 @@ pub enum McoPrescaler { pub(crate) trait SealedMcoInstance {} #[allow(private_bounds)] -pub trait McoInstance: SealedMcoInstance + 'static { +pub trait McoInstance: PeripheralType + SealedMcoInstance + 'static { type Source; #[doc(hidden)] @@ -91,14 +91,7 @@ pub struct Mco<'d, T: McoInstance> { impl<'d, T: McoInstance> Mco<'d, T> { /// Create a new MCO instance. - pub fn new( - _peri: impl Peripheral

+ 'd, - pin: impl Peripheral

> + 'd, - source: T::Source, - prescaler: McoPrescaler, - ) -> Self { - into_ref!(pin); - + pub fn new(_peri: Peri<'d, T>, pin: Peri<'d, impl McoPin>, source: T::Source, prescaler: McoPrescaler) -> Self { critical_section::with(|_| unsafe { T::_apply_clock_settings(source, prescaler); pin.set_as_af(pin.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh)); diff --git a/embassy-stm32/src/rng.rs b/embassy-stm32/src/rng.rs index b96200e5e..250a08a39 100644 --- a/embassy-stm32/src/rng.rs +++ b/embassy-stm32/src/rng.rs @@ -5,12 +5,12 @@ use core::future::poll_fn; use core::marker::PhantomData; use core::task::Poll; -use embassy_hal_internal::{into_ref, PeripheralRef}; +use embassy_hal_internal::PeripheralType; use embassy_sync::waitqueue::AtomicWaker; use rand_core::{CryptoRng, RngCore}; use crate::interrupt::typelevel::Interrupt; -use crate::{interrupt, pac, peripherals, rcc, Peripheral}; +use crate::{interrupt, pac, peripherals, rcc, Peri}; static RNG_WAKER: AtomicWaker = AtomicWaker::new(); @@ -43,17 +43,16 @@ impl interrupt::typelevel::Handler for InterruptHandl /// RNG driver. pub struct Rng<'d, T: Instance> { - _inner: PeripheralRef<'d, T>, + _inner: Peri<'d, T>, } impl<'d, T: Instance> Rng<'d, T> { /// Create a new RNG driver. pub fn new( - inner: impl Peripheral

+ 'd, + inner: Peri<'d, T>, _irq: impl interrupt::typelevel::Binding> + 'd, ) -> Self { rcc::enable_and_reset::(); - into_ref!(inner); let mut random = Self { _inner: inner }; random.reset(); @@ -228,7 +227,7 @@ trait SealedInstance { /// RNG instance trait. #[allow(private_bounds)] -pub trait Instance: SealedInstance + Peripheral

+ crate::rcc::RccPeripheral + 'static + Send { +pub trait Instance: SealedInstance + PeripheralType + crate::rcc::RccPeripheral + 'static + Send { /// Interrupt for this RNG instance. type Interrupt: interrupt::typelevel::Interrupt; } diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs index c2919e2bd..b16c6fdca 100644 --- a/embassy-stm32/src/rtc/mod.rs +++ b/embassy-stm32/src/rtc/mod.rs @@ -29,9 +29,9 @@ use crate::time::Hertz; mod _version; #[allow(unused_imports)] pub use _version::*; -use embassy_hal_internal::Peripheral; use crate::peripherals::RTC; +use crate::Peri; /// Errors that can occur on methods on [RtcClock] #[non_exhaustive] @@ -151,7 +151,7 @@ pub enum RtcCalibrationCyclePeriod { impl Rtc { /// Create a new RTC instance. - pub fn new(_rtc: impl Peripheral

, rtc_config: RtcConfig) -> Self { + pub fn new(_rtc: Peri<'static, RTC>, rtc_config: RtcConfig) -> Self { #[cfg(not(any(stm32l0, stm32f3, stm32l1, stm32f0, stm32f2)))] crate::rcc::enable_and_reset::(); diff --git a/embassy-stm32/src/sai/mod.rs b/embassy-stm32/src/sai/mod.rs index 39ed44712..0c9c27797 100644 --- a/embassy-stm32/src/sai/mod.rs +++ b/embassy-stm32/src/sai/mod.rs @@ -4,7 +4,7 @@ use core::marker::PhantomData; -use embassy_hal_internal::{into_ref, PeripheralRef}; +use embassy_hal_internal::PeripheralType; pub use crate::dma::word; #[cfg(not(gpdma))] @@ -12,7 +12,7 @@ use crate::dma::{ringbuffer, Channel, ReadableRingBuffer, Request, TransferOptio use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed}; use crate::pac::sai::{vals, Sai as Regs}; use crate::rcc::{self, RccPeripheral}; -use crate::{peripherals, Peripheral}; +use crate::{peripherals, Peri}; /// SAI error #[derive(Debug, PartialEq, Eq, Clone, Copy)] @@ -679,7 +679,7 @@ fn get_af_types(mode: Mode, tx_rx: TxRx) -> (AfType, AfType) { #[cfg(not(gpdma))] fn get_ring_buffer<'d, T: Instance, W: word::Word>( - dma: impl Peripheral

+ 'd, + dma: Peri<'d, impl Channel>, dma_buf: &'d mut [W], request: Request, sub_block: WhichSubBlock, @@ -718,16 +718,15 @@ fn update_synchronous_config(config: &mut Config) { } /// SAI subblock instance. -pub struct SubBlock<'d, T, S: SubBlockInstance> { - peri: PeripheralRef<'d, T>, +pub struct SubBlock<'d, T: Instance, S: SubBlockInstance> { + peri: Peri<'d, T>, _phantom: PhantomData, } /// Split the main SAIx peripheral into the two subblocks. /// /// You can then create a [`Sai`] driver for each each half. -pub fn split_subblocks<'d, T: Instance>(peri: impl Peripheral

+ 'd) -> (SubBlock<'d, T, A>, SubBlock<'d, T, B>) { - into_ref!(peri); +pub fn split_subblocks<'d, T: Instance>(peri: Peri<'d, T>) -> (SubBlock<'d, T, A>, SubBlock<'d, T, B>) { rcc::enable_and_reset::(); ( @@ -744,11 +743,11 @@ pub fn split_subblocks<'d, T: Instance>(peri: impl Peripheral

+ 'd) -> (S /// SAI sub-block driver. pub struct Sai<'d, T: Instance, W: word::Word> { - _peri: PeripheralRef<'d, T>, - sd: Option>, - fs: Option>, - sck: Option>, - mclk: Option>, + _peri: Peri<'d, T>, + sd: Option>, + fs: Option>, + sck: Option>, + mclk: Option>, #[cfg(gpdma)] ring_buffer: PhantomData, #[cfg(not(gpdma))] @@ -763,16 +762,14 @@ impl<'d, T: Instance, W: word::Word> Sai<'d, T, W> { /// You can obtain the [`SubBlock`] with [`split_subblocks`]. pub fn new_asynchronous_with_mclk( peri: SubBlock<'d, T, S>, - sck: impl Peripheral

> + 'd, - sd: impl Peripheral

> + 'd, - fs: impl Peripheral

> + 'd, - mclk: impl Peripheral

> + 'd, - dma: impl Peripheral

> + 'd, + sck: Peri<'d, impl SckPin>, + sd: Peri<'d, impl SdPin>, + fs: Peri<'d, impl FsPin>, + mclk: Peri<'d, impl MclkPin>, + dma: Peri<'d, impl Channel + Dma>, dma_buf: &'d mut [W], mut config: Config, ) -> Self { - into_ref!(mclk); - let (_sd_af_type, ck_af_type) = get_af_types(config.mode, config.tx_rx); mclk.set_as_af(mclk.af_num(), ck_af_type); @@ -788,15 +785,14 @@ impl<'d, T: Instance, W: word::Word> Sai<'d, T, W> { /// You can obtain the [`SubBlock`] with [`split_subblocks`]. pub fn new_asynchronous( peri: SubBlock<'d, T, S>, - sck: impl Peripheral

> + 'd, - sd: impl Peripheral

> + 'd, - fs: impl Peripheral

> + 'd, - dma: impl Peripheral

> + 'd, + sck: Peri<'d, impl SckPin>, + sd: Peri<'d, impl SdPin>, + fs: Peri<'d, impl FsPin>, + dma: Peri<'d, impl Channel + Dma>, dma_buf: &'d mut [W], config: Config, ) -> Self { let peri = peri.peri; - into_ref!(peri, dma, sck, sd, fs); let (sd_af_type, ck_af_type) = get_af_types(config.mode, config.tx_rx); sd.set_as_af(sd.af_num(), sd_af_type); @@ -809,10 +805,10 @@ impl<'d, T: Instance, W: word::Word> Sai<'d, T, W> { Self::new_inner( peri, sub_block, - Some(sck.map_into()), + Some(sck.into()), None, - Some(sd.map_into()), - Some(fs.map_into()), + Some(sd.into()), + Some(fs.into()), get_ring_buffer::(dma, dma_buf, request, sub_block, config.tx_rx), config, ) @@ -823,15 +819,14 @@ impl<'d, T: Instance, W: word::Word> Sai<'d, T, W> { /// You can obtain the [`SubBlock`] with [`split_subblocks`]. pub fn new_synchronous( peri: SubBlock<'d, T, S>, - sd: impl Peripheral

> + 'd, - dma: impl Peripheral

> + 'd, + sd: Peri<'d, impl SdPin>, + dma: Peri<'d, impl Channel + Dma>, dma_buf: &'d mut [W], mut config: Config, ) -> Self { update_synchronous_config(&mut config); let peri = peri.peri; - into_ref!(dma, peri, sd); let (sd_af_type, _ck_af_type) = get_af_types(config.mode, config.tx_rx); sd.set_as_af(sd.af_num(), sd_af_type); @@ -844,7 +839,7 @@ impl<'d, T: Instance, W: word::Word> Sai<'d, T, W> { sub_block, None, None, - Some(sd.map_into()), + Some(sd.into()), None, get_ring_buffer::(dma, dma_buf, request, sub_block, config.tx_rx), config, @@ -852,12 +847,12 @@ impl<'d, T: Instance, W: word::Word> Sai<'d, T, W> { } fn new_inner( - peri: impl Peripheral

+ 'd, + peri: Peri<'d, T>, sub_block: WhichSubBlock, - sck: Option>, - mclk: Option>, - sd: Option>, - fs: Option>, + sck: Option>, + mclk: Option>, + sd: Option>, + fs: Option>, ring_buffer: RingBuffer<'d, W>, config: Config, ) -> Self { @@ -947,7 +942,7 @@ impl<'d, T: Instance, W: word::Word> Sai<'d, T, W> { } Self { - _peri: peri.into_ref(), + _peri: peri, sub_block, sck, mclk, @@ -1106,7 +1101,7 @@ impl SubBlockInstance for B {} /// SAI instance trait. #[allow(private_bounds)] -pub trait Instance: Peripheral

+ SealedInstance + RccPeripheral {} +pub trait Instance: SealedInstance + PeripheralType + RccPeripheral {} pin_trait!(SckPin, Instance, SubBlockInstance); pin_trait!(FsPin, Instance, SubBlockInstance); diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs index d8671caf7..8f3c45f50 100644 --- a/embassy-stm32/src/sdmmc/mod.rs +++ b/embassy-stm32/src/sdmmc/mod.rs @@ -8,7 +8,7 @@ use core::ops::{Deref, DerefMut}; use core::task::Poll; use embassy_hal_internal::drop::OnDrop; -use embassy_hal_internal::{into_ref, PeripheralRef}; +use embassy_hal_internal::{Peri, PeripheralType}; use embassy_sync::waitqueue::AtomicWaker; use sdio_host::{BusWidth, CardCapacity, CardStatus, CurrentState, SDStatus, CID, CSD, OCR, SCR}; @@ -21,7 +21,7 @@ use crate::interrupt::typelevel::Interrupt; use crate::pac::sdmmc::Sdmmc as RegBlock; use crate::rcc::{self, RccPeripheral}; use crate::time::Hertz; -use crate::{interrupt, peripherals, Peripheral}; +use crate::{interrupt, peripherals}; /// Interrupt handler. pub struct InterruptHandler { @@ -303,16 +303,16 @@ impl Default for Config { /// Sdmmc device pub struct Sdmmc<'d, T: Instance> { - _peri: PeripheralRef<'d, T>, + _peri: Peri<'d, T>, #[cfg(sdmmc_v1)] dma: ChannelAndRequest<'d>, - clk: PeripheralRef<'d, AnyPin>, - cmd: PeripheralRef<'d, AnyPin>, - d0: PeripheralRef<'d, AnyPin>, - d1: Option>, - d2: Option>, - d3: Option>, + clk: Peri<'d, AnyPin>, + cmd: Peri<'d, AnyPin>, + d0: Peri<'d, AnyPin>, + d1: Option>, + d2: Option>, + d3: Option>, config: Config, /// Current clock to card @@ -338,16 +338,14 @@ const DATA_AF: AfType = CMD_AF; impl<'d, T: Instance> Sdmmc<'d, T> { /// Create a new SDMMC driver, with 1 data lane. pub fn new_1bit( - sdmmc: impl Peripheral

+ 'd, + sdmmc: Peri<'d, T>, _irq: impl interrupt::typelevel::Binding> + 'd, - dma: impl Peripheral

> + 'd, - clk: impl Peripheral

> + 'd, - cmd: impl Peripheral

> + 'd, - d0: impl Peripheral

> + 'd, + dma: Peri<'d, impl SdmmcDma>, + clk: Peri<'d, impl CkPin>, + cmd: Peri<'d, impl CmdPin>, + d0: Peri<'d, impl D0Pin>, config: Config, ) -> Self { - into_ref!(dma, clk, cmd, d0); - critical_section::with(|_| { clk.set_as_af(clk.af_num(), CLK_AF); cmd.set_as_af(cmd.af_num(), CMD_AF); @@ -357,9 +355,9 @@ impl<'d, T: Instance> Sdmmc<'d, T> { Self::new_inner( sdmmc, new_dma_nonopt!(dma), - clk.map_into(), - cmd.map_into(), - d0.map_into(), + clk.into(), + cmd.into(), + d0.into(), None, None, None, @@ -369,19 +367,17 @@ impl<'d, T: Instance> Sdmmc<'d, T> { /// Create a new SDMMC driver, with 4 data lanes. pub fn new_4bit( - sdmmc: impl Peripheral

+ 'd, + sdmmc: Peri<'d, T>, _irq: impl interrupt::typelevel::Binding> + 'd, - dma: impl Peripheral

> + 'd, - clk: impl Peripheral

> + 'd, - cmd: impl Peripheral

> + 'd, - d0: impl Peripheral

> + 'd, - d1: impl Peripheral

> + 'd, - d2: impl Peripheral

> + 'd, - d3: impl Peripheral

> + 'd, + dma: Peri<'d, impl SdmmcDma>, + clk: Peri<'d, impl CkPin>, + cmd: Peri<'d, impl CmdPin>, + d0: Peri<'d, impl D0Pin>, + d1: Peri<'d, impl D1Pin>, + d2: Peri<'d, impl D2Pin>, + d3: Peri<'d, impl D3Pin>, config: Config, ) -> Self { - into_ref!(clk, cmd, d0, d1, d2, d3); - critical_section::with(|_| { clk.set_as_af(clk.af_num(), CLK_AF); cmd.set_as_af(cmd.af_num(), CMD_AF); @@ -394,12 +390,12 @@ impl<'d, T: Instance> Sdmmc<'d, T> { Self::new_inner( sdmmc, new_dma_nonopt!(dma), - clk.map_into(), - cmd.map_into(), - d0.map_into(), - Some(d1.map_into()), - Some(d2.map_into()), - Some(d3.map_into()), + clk.into(), + cmd.into(), + d0.into(), + Some(d1.into()), + Some(d2.into()), + Some(d3.into()), config, ) } @@ -409,47 +405,34 @@ impl<'d, T: Instance> Sdmmc<'d, T> { impl<'d, T: Instance> Sdmmc<'d, T> { /// Create a new SDMMC driver, with 1 data lane. pub fn new_1bit( - sdmmc: impl Peripheral

+ 'd, + sdmmc: Peri<'d, T>, _irq: impl interrupt::typelevel::Binding> + 'd, - clk: impl Peripheral

> + 'd, - cmd: impl Peripheral

> + 'd, - d0: impl Peripheral

> + 'd, + clk: Peri<'d, impl CkPin>, + cmd: Peri<'d, impl CmdPin>, + d0: Peri<'d, impl D0Pin>, config: Config, ) -> Self { - into_ref!(clk, cmd, d0); - critical_section::with(|_| { clk.set_as_af(clk.af_num(), CLK_AF); cmd.set_as_af(cmd.af_num(), CMD_AF); d0.set_as_af(d0.af_num(), DATA_AF); }); - Self::new_inner( - sdmmc, - clk.map_into(), - cmd.map_into(), - d0.map_into(), - None, - None, - None, - config, - ) + Self::new_inner(sdmmc, clk.into(), cmd.into(), d0.into(), None, None, None, config) } /// Create a new SDMMC driver, with 4 data lanes. pub fn new_4bit( - sdmmc: impl Peripheral

+ 'd, + sdmmc: Peri<'d, T>, _irq: impl interrupt::typelevel::Binding> + 'd, - clk: impl Peripheral

> + 'd, - cmd: impl Peripheral

> + 'd, - d0: impl Peripheral

> + 'd, - d1: impl Peripheral

> + 'd, - d2: impl Peripheral

> + 'd, - d3: impl Peripheral

> + 'd, + clk: Peri<'d, impl CkPin>, + cmd: Peri<'d, impl CmdPin>, + d0: Peri<'d, impl D0Pin>, + d1: Peri<'d, impl D1Pin>, + d2: Peri<'d, impl D2Pin>, + d3: Peri<'d, impl D3Pin>, config: Config, ) -> Self { - into_ref!(clk, cmd, d0, d1, d2, d3); - critical_section::with(|_| { clk.set_as_af(clk.af_num(), CLK_AF); cmd.set_as_af(cmd.af_num(), CMD_AF); @@ -461,12 +444,12 @@ impl<'d, T: Instance> Sdmmc<'d, T> { Self::new_inner( sdmmc, - clk.map_into(), - cmd.map_into(), - d0.map_into(), - Some(d1.map_into()), - Some(d2.map_into()), - Some(d3.map_into()), + clk.into(), + cmd.into(), + d0.into(), + Some(d1.into()), + Some(d2.into()), + Some(d3.into()), config, ) } @@ -474,18 +457,16 @@ impl<'d, T: Instance> Sdmmc<'d, T> { impl<'d, T: Instance> Sdmmc<'d, T> { fn new_inner( - sdmmc: impl Peripheral

+ 'd, + sdmmc: Peri<'d, T>, #[cfg(sdmmc_v1)] dma: ChannelAndRequest<'d>, - clk: PeripheralRef<'d, AnyPin>, - cmd: PeripheralRef<'d, AnyPin>, - d0: PeripheralRef<'d, AnyPin>, - d1: Option>, - d2: Option>, - d3: Option>, + clk: Peri<'d, AnyPin>, + cmd: Peri<'d, AnyPin>, + d0: Peri<'d, AnyPin>, + d1: Option>, + d2: Option>, + d3: Option>, config: Config, ) -> Self { - into_ref!(sdmmc); - rcc::enable_and_reset::(); T::Interrupt::unpend(); @@ -1478,7 +1459,7 @@ trait SealedInstance { /// SDMMC instance trait. #[allow(private_bounds)] -pub trait Instance: SealedInstance + RccPeripheral + 'static { +pub trait Instance: SealedInstance + PeripheralType + RccPeripheral + 'static { /// Interrupt for this instance. type Interrupt: interrupt::typelevel::Interrupt; } diff --git a/embassy-stm32/src/spdifrx/mod.rs b/embassy-stm32/src/spdifrx/mod.rs index a205780ad..08dba04fe 100644 --- a/embassy-stm32/src/spdifrx/mod.rs +++ b/embassy-stm32/src/spdifrx/mod.rs @@ -4,7 +4,6 @@ use core::marker::PhantomData; -use embassy_hal_internal::{into_ref, PeripheralRef}; use embassy_sync::waitqueue::AtomicWaker; use crate::dma::ringbuffer::Error as RingbufferError; @@ -16,7 +15,7 @@ use crate::gpio::{AfType, AnyPin, Pull, SealedPin as _}; use crate::interrupt::typelevel::Interrupt; use crate::pac::spdifrx::Spdifrx as Regs; use crate::rcc::{RccInfo, SealedRccPeripheral}; -use crate::{interrupt, peripherals, Peripheral}; +use crate::{interrupt, peripherals, Peri}; /// Possible S/PDIF preamble types. #[allow(dead_code)] @@ -36,10 +35,10 @@ enum PreambleType { macro_rules! new_spdifrx_pin { ($name:ident, $af_type:expr) => {{ - let pin = $name.into_ref(); + let pin = $name; let input_sel = pin.input_sel(); pin.set_as_af(pin.af_num(), $af_type); - (Some(pin.map_into()), input_sel) + (Some(pin.into()), input_sel) }}; } @@ -61,8 +60,8 @@ macro_rules! impl_spdifrx_pin { /// Data is read by DMAs and stored in a ring buffer. #[cfg(not(gpdma))] pub struct Spdifrx<'d, T: Instance> { - _peri: PeripheralRef<'d, T>, - spdifrx_in: Option>, + _peri: Peri<'d, T>, + spdifrx_in: Option>, data_ring_buffer: ReadableRingBuffer<'d, u32>, } @@ -131,18 +130,16 @@ impl<'d, T: Instance> Spdifrx<'d, T> { /// Create a new `Spdifrx` instance. pub fn new( - peri: impl Peripheral

+ 'd, + peri: Peri<'d, T>, _irq: impl interrupt::typelevel::Binding> + 'd, config: Config, - spdifrx_in: impl Peripheral

> + 'd, - data_dma: impl Peripheral

> + 'd, + spdifrx_in: Peri<'d, impl InPin>, + data_dma: Peri<'d, impl Channel + Dma>, data_dma_buf: &'d mut [u32], ) -> Self { let (spdifrx_in, input_sel) = new_spdifrx_pin!(spdifrx_in, AfType::input(Pull::None)); Self::setup(config, input_sel); - into_ref!(peri, data_dma); - let regs = T::info().regs; let dr_request = data_dma.request(); let dr_ring_buffer = diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs index a43da1b5a..6578aa1aa 100644 --- a/embassy-stm32/src/spi/mod.rs +++ b/embassy-stm32/src/spi/mod.rs @@ -6,7 +6,6 @@ use core::ptr; use embassy_embedded_hal::SetConfig; use embassy_futures::join::join; -use embassy_hal_internal::PeripheralRef; pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; use crate::dma::{word, ChannelAndRequest}; @@ -15,7 +14,7 @@ use crate::mode::{Async, Blocking, Mode as PeriMode}; use crate::pac::spi::{regs, vals, Spi as Regs}; use crate::rcc::{RccInfo, SealedRccPeripheral}; use crate::time::Hertz; -use crate::Peripheral; +use crate::Peri; /// SPI error. #[derive(Debug, PartialEq, Eq, Clone, Copy)] @@ -130,9 +129,9 @@ impl Config { pub struct Spi<'d, M: PeriMode> { pub(crate) info: &'static Info, kernel_clock: Hertz, - sck: Option>, - mosi: Option>, - miso: Option>, + sck: Option>, + mosi: Option>, + miso: Option>, tx_dma: Option>, rx_dma: Option>, _phantom: PhantomData, @@ -142,10 +141,10 @@ pub struct Spi<'d, M: PeriMode> { impl<'d, M: PeriMode> Spi<'d, M> { fn new_inner( - _peri: impl Peripheral

+ 'd, - sck: Option>, - mosi: Option>, - miso: Option>, + _peri: Peri<'d, T>, + sck: Option>, + mosi: Option>, + miso: Option>, tx_dma: Option>, rx_dma: Option>, config: Config, @@ -465,10 +464,10 @@ impl<'d, M: PeriMode> Spi<'d, M> { impl<'d> Spi<'d, Blocking> { /// Create a new blocking SPI driver. pub fn new_blocking( - peri: impl Peripheral

+ 'd, - sck: impl Peripheral

> + 'd, - mosi: impl Peripheral

> + 'd, - miso: impl Peripheral

> + 'd, + peri: Peri<'d, T>, + sck: Peri<'d, impl SckPin>, + mosi: Peri<'d, impl MosiPin>, + miso: Peri<'d, impl MisoPin>, config: Config, ) -> Self { Self::new_inner( @@ -484,9 +483,9 @@ impl<'d> Spi<'d, Blocking> { /// Create a new blocking SPI driver, in RX-only mode (only MISO pin, no MOSI). pub fn new_blocking_rxonly( - peri: impl Peripheral

+ 'd, - sck: impl Peripheral

> + 'd, - miso: impl Peripheral

> + 'd, + peri: Peri<'d, T>, + sck: Peri<'d, impl SckPin>, + miso: Peri<'d, impl MisoPin>, config: Config, ) -> Self { Self::new_inner( @@ -502,9 +501,9 @@ impl<'d> Spi<'d, Blocking> { /// Create a new blocking SPI driver, in TX-only mode (only MOSI pin, no MISO). pub fn new_blocking_txonly( - peri: impl Peripheral

+ 'd, - sck: impl Peripheral

> + 'd, - mosi: impl Peripheral

> + 'd, + peri: Peri<'d, T>, + sck: Peri<'d, impl SckPin>, + mosi: Peri<'d, impl MosiPin>, config: Config, ) -> Self { Self::new_inner( @@ -522,8 +521,8 @@ impl<'d> Spi<'d, Blocking> { /// /// This can be useful for bit-banging non-SPI protocols. pub fn new_blocking_txonly_nosck( - peri: impl Peripheral

+ 'd, - mosi: impl Peripheral

> + 'd, + peri: Peri<'d, T>, + mosi: Peri<'d, impl MosiPin>, config: Config, ) -> Self { Self::new_inner( @@ -541,12 +540,12 @@ impl<'d> Spi<'d, Blocking> { impl<'d> Spi<'d, Async> { /// Create a new SPI driver. pub fn new( - peri: impl Peripheral

+ 'd, - sck: impl Peripheral

> + 'd, - mosi: impl Peripheral

> + 'd, - miso: impl Peripheral

> + 'd, - tx_dma: impl Peripheral

> + 'd, - rx_dma: impl Peripheral

> + 'd, + peri: Peri<'d, T>, + sck: Peri<'d, impl SckPin>, + mosi: Peri<'d, impl MosiPin>, + miso: Peri<'d, impl MisoPin>, + tx_dma: Peri<'d, impl TxDma>, + rx_dma: Peri<'d, impl RxDma>, config: Config, ) -> Self { Self::new_inner( @@ -562,11 +561,11 @@ impl<'d> Spi<'d, Async> { /// Create a new SPI driver, in RX-only mode (only MISO pin, no MOSI). pub fn new_rxonly( - peri: impl Peripheral

+ 'd, - sck: impl Peripheral

> + 'd, - miso: impl Peripheral

> + 'd, - #[cfg(any(spi_v1, spi_f1, spi_v2))] tx_dma: impl Peripheral

> + 'd, - rx_dma: impl Peripheral

> + 'd, + peri: Peri<'d, T>, + sck: Peri<'d, impl SckPin>, + miso: Peri<'d, impl MisoPin>, + #[cfg(any(spi_v1, spi_f1, spi_v2))] tx_dma: Peri<'d, impl TxDma>, + rx_dma: Peri<'d, impl RxDma>, config: Config, ) -> Self { Self::new_inner( @@ -585,10 +584,10 @@ impl<'d> Spi<'d, Async> { /// Create a new SPI driver, in TX-only mode (only MOSI pin, no MISO). pub fn new_txonly( - peri: impl Peripheral

+ 'd, - sck: impl Peripheral

> + 'd, - mosi: impl Peripheral

> + 'd, - tx_dma: impl Peripheral

> + 'd, + peri: Peri<'d, T>, + sck: Peri<'d, impl SckPin>, + mosi: Peri<'d, impl MosiPin>, + tx_dma: Peri<'d, impl TxDma>, config: Config, ) -> Self { Self::new_inner( @@ -606,9 +605,9 @@ impl<'d> Spi<'d, Async> { /// /// This can be useful for bit-banging non-SPI protocols. pub fn new_txonly_nosck( - peri: impl Peripheral

+ 'd, - mosi: impl Peripheral

> + 'd, - tx_dma: impl Peripheral

> + 'd, + peri: Peri<'d, T>, + mosi: Peri<'d, impl MosiPin>, + tx_dma: Peri<'d, impl TxDma>, config: Config, ) -> Self { Self::new_inner( @@ -625,9 +624,9 @@ impl<'d> Spi<'d, Async> { #[cfg(stm32wl)] /// Useful for on chip peripherals like SUBGHZ which are hardwired. pub fn new_subghz( - peri: impl Peripheral

+ 'd, - tx_dma: impl Peripheral

> + 'd, - rx_dma: impl Peripheral

> + 'd, + peri: Peri<'d, T>, + tx_dma: Peri<'d, impl TxDma>, + rx_dma: Peri<'d, impl RxDma>, ) -> Self { // see RM0453 rev 1 section 7.2.13 page 291 // The SUBGHZSPI_SCK frequency is obtained by PCLK3 divided by two. @@ -644,7 +643,7 @@ impl<'d> Spi<'d, Async> { #[allow(dead_code)] pub(crate) fn new_internal( - peri: impl Peripheral

+ 'd, + peri: Peri<'d, T>, tx_dma: Option>, rx_dma: Option>, config: Config, diff --git a/embassy-stm32/src/timer/complementary_pwm.rs b/embassy-stm32/src/timer/complementary_pwm.rs index 02c01e900..f543bafab 100644 --- a/embassy-stm32/src/timer/complementary_pwm.rs +++ b/embassy-stm32/src/timer/complementary_pwm.rs @@ -2,7 +2,6 @@ use core::marker::PhantomData; -use embassy_hal_internal::{into_ref, PeripheralRef}; use stm32_metapac::timer::vals::Ckd; use super::low_level::{CountingMode, OutputPolarity, Timer}; @@ -14,13 +13,13 @@ use super::{ use crate::gpio::{AnyPin, OutputType}; use crate::time::Hertz; use crate::timer::low_level::OutputCompareMode; -use crate::Peripheral; +use crate::Peri; /// Complementary PWM pin wrapper. /// /// This wraps a pin to make it usable with PWM. pub struct ComplementaryPwmPin<'d, T, C> { - _pin: PeripheralRef<'d, AnyPin>, + _pin: Peri<'d, AnyPin>, phantom: PhantomData<(T, C)>, } @@ -28,8 +27,7 @@ macro_rules! complementary_channel_impl { ($new_chx:ident, $channel:ident, $pin_trait:ident) => { impl<'d, T: AdvancedInstance4Channel> ComplementaryPwmPin<'d, T, $channel> { #[doc = concat!("Create a new ", stringify!($channel), " complementary PWM pin instance.")] - pub fn $new_chx(pin: impl Peripheral

> + 'd, output_type: OutputType) -> Self { - into_ref!(pin); + pub fn $new_chx(pin: Peri<'d, impl $pin_trait>, output_type: OutputType) -> Self { critical_section::with(|_| { pin.set_low(); pin.set_as_af( @@ -38,7 +36,7 @@ macro_rules! complementary_channel_impl { ); }); ComplementaryPwmPin { - _pin: pin.map_into(), + _pin: pin.into(), phantom: PhantomData, } } @@ -60,7 +58,7 @@ impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> { /// Create a new complementary PWM driver. #[allow(clippy::too_many_arguments)] pub fn new( - tim: impl Peripheral

+ 'd, + tim: Peri<'d, T>, _ch1: Option>, _ch1n: Option>, _ch2: Option>, @@ -75,7 +73,7 @@ impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> { Self::new_inner(tim, freq, counting_mode) } - fn new_inner(tim: impl Peripheral

+ 'd, freq: Hertz, counting_mode: CountingMode) -> Self { + fn new_inner(tim: Peri<'d, T>, freq: Hertz, counting_mode: CountingMode) -> Self { let mut this = Self { inner: Timer::new(tim) }; this.inner.set_counting_mode(counting_mode); diff --git a/embassy-stm32/src/timer/input_capture.rs b/embassy-stm32/src/timer/input_capture.rs index b7c13343c..0450f14fa 100644 --- a/embassy-stm32/src/timer/input_capture.rs +++ b/embassy-stm32/src/timer/input_capture.rs @@ -5,8 +5,6 @@ use core::marker::PhantomData; use core::pin::Pin; use core::task::{Context, Poll}; -use embassy_hal_internal::{into_ref, PeripheralRef}; - use super::low_level::{CountingMode, FilterValue, InputCaptureMode, InputTISelection, Timer}; use super::{ CaptureCompareInterruptHandler, Channel, Channel1Pin, Channel2Pin, Channel3Pin, Channel4Pin, @@ -15,7 +13,7 @@ use super::{ use crate::gpio::{AfType, AnyPin, Pull}; use crate::interrupt::typelevel::{Binding, Interrupt}; use crate::time::Hertz; -use crate::Peripheral; +use crate::Peri; /// Channel 1 marker type. pub enum Ch1 {} @@ -30,7 +28,7 @@ pub enum Ch4 {} /// /// This wraps a pin to make it usable with capture. pub struct CapturePin<'d, T, C> { - _pin: PeripheralRef<'d, AnyPin>, + _pin: Peri<'d, AnyPin>, phantom: PhantomData<(T, C)>, } @@ -38,11 +36,10 @@ macro_rules! channel_impl { ($new_chx:ident, $channel:ident, $pin_trait:ident) => { impl<'d, T: GeneralInstance4Channel> CapturePin<'d, T, $channel> { #[doc = concat!("Create a new ", stringify!($channel), " capture pin instance.")] - pub fn $new_chx(pin: impl Peripheral

> + 'd, pull: Pull) -> Self { - into_ref!(pin); + pub fn $new_chx(pin: Peri<'d, impl $pin_trait>, pull: Pull) -> Self { pin.set_as_af(pin.af_num(), AfType::input(pull)); CapturePin { - _pin: pin.map_into(), + _pin: pin.into(), phantom: PhantomData, } } @@ -63,7 +60,7 @@ pub struct InputCapture<'d, T: GeneralInstance4Channel> { impl<'d, T: GeneralInstance4Channel> InputCapture<'d, T> { /// Create a new input capture driver. pub fn new( - tim: impl Peripheral

+ 'd, + tim: Peri<'d, T>, _ch1: Option>, _ch2: Option>, _ch3: Option>, @@ -75,7 +72,7 @@ impl<'d, T: GeneralInstance4Channel> InputCapture<'d, T> { Self::new_inner(tim, freq, counting_mode) } - fn new_inner(tim: impl Peripheral

+ 'd, freq: Hertz, counting_mode: CountingMode) -> Self { + fn new_inner(tim: Peri<'d, T>, freq: Hertz, counting_mode: CountingMode) -> Self { let mut this = Self { inner: Timer::new(tim) }; this.inner.set_counting_mode(counting_mode); diff --git a/embassy-stm32/src/timer/low_level.rs b/embassy-stm32/src/timer/low_level.rs index 5b0c95109..8fc32c1f3 100644 --- a/embassy-stm32/src/timer/low_level.rs +++ b/embassy-stm32/src/timer/low_level.rs @@ -8,7 +8,7 @@ use core::mem::ManuallyDrop; -use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; +use embassy_hal_internal::Peri; // Re-export useful enums pub use stm32_metapac::timer::vals::{FilterValue, Sms as SlaveMode, Ts as TriggerSource}; @@ -181,7 +181,7 @@ impl From for bool { /// Low-level timer driver. pub struct Timer<'d, T: CoreInstance> { - tim: PeripheralRef<'d, T>, + tim: Peri<'d, T>, } impl<'d, T: CoreInstance> Drop for Timer<'d, T> { @@ -192,9 +192,7 @@ impl<'d, T: CoreInstance> Drop for Timer<'d, T> { impl<'d, T: CoreInstance> Timer<'d, T> { /// Create a new timer driver. - pub fn new(tim: impl Peripheral

+ 'd) -> Self { - into_ref!(tim); - + pub fn new(tim: Peri<'d, T>) -> Self { rcc::enable_and_reset::(); Self { tim } diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs index 97740c2ed..765a3d9fa 100644 --- a/embassy-stm32/src/timer/mod.rs +++ b/embassy-stm32/src/timer/mod.rs @@ -2,7 +2,7 @@ use core::marker::PhantomData; -use embassy_hal_internal::Peripheral; +use embassy_hal_internal::PeripheralType; use embassy_sync::waitqueue::AtomicWaker; #[cfg(not(stm32l0))] @@ -66,7 +66,7 @@ impl State { } } -trait SealedInstance: RccPeripheral + Peripheral

{ +trait SealedInstance: RccPeripheral + PeripheralType { /// Async state for this timer fn state() -> &'static State; } diff --git a/embassy-stm32/src/timer/pwm_input.rs b/embassy-stm32/src/timer/pwm_input.rs index e3eb6042a..98b798634 100644 --- a/embassy-stm32/src/timer/pwm_input.rs +++ b/embassy-stm32/src/timer/pwm_input.rs @@ -1,12 +1,10 @@ //! PWM Input driver. -use embassy_hal_internal::into_ref; - use super::low_level::{CountingMode, InputCaptureMode, InputTISelection, SlaveMode, Timer, TriggerSource}; use super::{Channel, Channel1Pin, Channel2Pin, GeneralInstance4Channel}; use crate::gpio::{AfType, Pull}; use crate::time::Hertz; -use crate::Peripheral; +use crate::Peri; /// PWM Input driver. pub struct PwmInput<'d, T: GeneralInstance4Channel> { @@ -16,34 +14,20 @@ pub struct PwmInput<'d, T: GeneralInstance4Channel> { impl<'d, T: GeneralInstance4Channel> PwmInput<'d, T> { /// Create a new PWM input driver. - pub fn new( - tim: impl Peripheral

+ 'd, - pin: impl Peripheral

> + 'd, - pull: Pull, - freq: Hertz, - ) -> Self { - into_ref!(pin); - + pub fn new(tim: Peri<'d, T>, pin: Peri<'d, impl Channel1Pin>, pull: Pull, freq: Hertz) -> Self { pin.set_as_af(pin.af_num(), AfType::input(pull)); Self::new_inner(tim, freq, Channel::Ch1, Channel::Ch2) } /// Create a new PWM input driver. - pub fn new_alt( - tim: impl Peripheral

+ 'd, - pin: impl Peripheral

> + 'd, - pull: Pull, - freq: Hertz, - ) -> Self { - into_ref!(pin); - + pub fn new_alt(tim: Peri<'d, T>, pin: Peri<'d, impl Channel2Pin>, pull: Pull, freq: Hertz) -> Self { pin.set_as_af(pin.af_num(), AfType::input(pull)); Self::new_inner(tim, freq, Channel::Ch2, Channel::Ch1) } - fn new_inner(tim: impl Peripheral

+ 'd, freq: Hertz, ch1: Channel, ch2: Channel) -> Self { + fn new_inner(tim: Peri<'d, T>, freq: Hertz, ch1: Channel, ch2: Channel) -> Self { let mut inner = Timer::new(tim); inner.set_counting_mode(CountingMode::EdgeAlignedUp); diff --git a/embassy-stm32/src/timer/qei.rs b/embassy-stm32/src/timer/qei.rs index fc5835414..bac290f28 100644 --- a/embassy-stm32/src/timer/qei.rs +++ b/embassy-stm32/src/timer/qei.rs @@ -2,13 +2,12 @@ use core::marker::PhantomData; -use embassy_hal_internal::{into_ref, PeripheralRef}; use stm32_metapac::timer::vals; use super::low_level::Timer; use super::{Channel1Pin, Channel2Pin, GeneralInstance4Channel}; use crate::gpio::{AfType, AnyPin, Pull}; -use crate::Peripheral; +use crate::Peri; /// Counting direction pub enum Direction { @@ -25,7 +24,7 @@ pub enum Ch2 {} /// Wrapper for using a pin with QEI. pub struct QeiPin<'d, T, Channel> { - _pin: PeripheralRef<'d, AnyPin>, + _pin: Peri<'d, AnyPin>, phantom: PhantomData<(T, Channel)>, } @@ -33,14 +32,13 @@ macro_rules! channel_impl { ($new_chx:ident, $channel:ident, $pin_trait:ident) => { impl<'d, T: GeneralInstance4Channel> QeiPin<'d, T, $channel> { #[doc = concat!("Create a new ", stringify!($channel), " QEI pin instance.")] - pub fn $new_chx(pin: impl Peripheral

> + 'd) -> Self { - into_ref!(pin); + pub fn $new_chx(pin: Peri<'d, impl $pin_trait>) -> Self { critical_section::with(|_| { pin.set_low(); pin.set_as_af(pin.af_num(), AfType::input(Pull::None)); }); QeiPin { - _pin: pin.map_into(), + _pin: pin.into(), phantom: PhantomData, } } @@ -58,11 +56,11 @@ pub struct Qei<'d, T: GeneralInstance4Channel> { impl<'d, T: GeneralInstance4Channel> Qei<'d, T> { /// Create a new quadrature decoder driver. - pub fn new(tim: impl Peripheral

+ 'd, _ch1: QeiPin<'d, T, Ch1>, _ch2: QeiPin<'d, T, Ch2>) -> Self { + pub fn new(tim: Peri<'d, T>, _ch1: QeiPin<'d, T, Ch1>, _ch2: QeiPin<'d, T, Ch2>) -> Self { Self::new_inner(tim) } - fn new_inner(tim: impl Peripheral

+ 'd) -> Self { + fn new_inner(tim: Peri<'d, T>) -> Self { let inner = Timer::new(tim); let r = inner.regs_gp16(); diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs index c5a366cd5..54ab7d0d5 100644 --- a/embassy-stm32/src/timer/simple_pwm.rs +++ b/embassy-stm32/src/timer/simple_pwm.rs @@ -3,15 +3,13 @@ use core::marker::PhantomData; use core::mem::ManuallyDrop; -use embassy_hal_internal::{into_ref, PeripheralRef}; - use super::low_level::{CountingMode, OutputCompareMode, OutputPolarity, Timer}; use super::{Channel, Channel1Pin, Channel2Pin, Channel3Pin, Channel4Pin, GeneralInstance4Channel, TimerBits}; #[cfg(gpio_v2)] use crate::gpio::Pull; use crate::gpio::{AfType, AnyPin, OutputType, Speed}; use crate::time::Hertz; -use crate::Peripheral; +use crate::Peri; /// Channel 1 marker type. pub enum Ch1 {} @@ -26,7 +24,7 @@ pub enum Ch4 {} /// /// This wraps a pin to make it usable with PWM. pub struct PwmPin<'d, T, C> { - _pin: PeripheralRef<'d, AnyPin>, + _pin: Peri<'d, AnyPin>, phantom: PhantomData<(T, C)>, } @@ -47,24 +45,19 @@ macro_rules! channel_impl { ($new_chx:ident, $new_chx_with_config:ident, $channel:ident, $pin_trait:ident) => { impl<'d, T: GeneralInstance4Channel> PwmPin<'d, T, $channel> { #[doc = concat!("Create a new ", stringify!($channel), " PWM pin instance.")] - pub fn $new_chx(pin: impl Peripheral

> + 'd, output_type: OutputType) -> Self { - into_ref!(pin); + pub fn $new_chx(pin: Peri<'d, impl $pin_trait>, output_type: OutputType) -> Self { critical_section::with(|_| { pin.set_low(); pin.set_as_af(pin.af_num(), AfType::output(output_type, Speed::VeryHigh)); }); PwmPin { - _pin: pin.map_into(), + _pin: pin.into(), phantom: PhantomData, } } #[doc = concat!("Create a new ", stringify!($channel), " PWM pin instance with config.")] - pub fn $new_chx_with_config( - pin: impl Peripheral

> + 'd, - pin_config: PwmPinConfig, - ) -> Self { - into_ref!(pin); + pub fn $new_chx_with_config(pin: Peri<'d, impl $pin_trait>, pin_config: PwmPinConfig) -> Self { critical_section::with(|_| { pin.set_low(); pin.set_as_af( @@ -76,7 +69,7 @@ macro_rules! channel_impl { ); }); PwmPin { - _pin: pin.map_into(), + _pin: pin.into(), phantom: PhantomData, } } @@ -202,7 +195,7 @@ pub struct SimplePwm<'d, T: GeneralInstance4Channel> { impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> { /// Create a new simple PWM driver. pub fn new( - tim: impl Peripheral

+ 'd, + tim: Peri<'d, T>, _ch1: Option>, _ch2: Option>, _ch3: Option>, @@ -213,7 +206,7 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> { Self::new_inner(tim, freq, counting_mode) } - fn new_inner(tim: impl Peripheral

+ 'd, freq: Hertz, counting_mode: CountingMode) -> Self { + fn new_inner(tim: Peri<'d, T>, freq: Hertz, counting_mode: CountingMode) -> Self { let mut this = Self { inner: Timer::new(tim) }; this.inner.set_counting_mode(counting_mode); @@ -331,14 +324,7 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> { /// /// Note: /// you will need to provide corresponding TIMx_UP DMA channel to use this method. - pub async fn waveform_up( - &mut self, - dma: impl Peripheral

>, - channel: Channel, - duty: &[u16], - ) { - into_ref!(dma); - + pub async fn waveform_up(&mut self, dma: Peri<'_, impl super::UpDma>, channel: Channel, duty: &[u16]) { #[allow(clippy::let_unit_value)] // eg. stm32f334 let req = dma.request(); @@ -368,7 +354,7 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> { }; Transfer::new_write( - &mut dma, + dma, req, duty, self.inner.regs_1ch().ccr(channel.index()).as_ptr() as *mut u16, @@ -399,11 +385,9 @@ macro_rules! impl_waveform_chx { ($fn_name:ident, $dma_ch:ident, $cc_ch:ident) => { impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> { /// Generate a sequence of PWM waveform - pub async fn $fn_name(&mut self, dma: impl Peripheral

>, duty: &[u16]) { + pub async fn $fn_name(&mut self, dma: Peri<'_, impl super::$dma_ch>, duty: &[u16]) { use crate::pac::timer::vals::Ccds; - into_ref!(dma); - #[allow(clippy::let_unit_value)] // eg. stm32f334 let req = dma.request(); @@ -443,7 +427,7 @@ macro_rules! impl_waveform_chx { match self.inner.bits() { TimerBits::Bits16 => { Transfer::new_write( - &mut dma, + dma, req, duty, self.inner.regs_gp16().ccr(cc_channel.index()).as_ptr() as *mut u16, @@ -458,7 +442,7 @@ macro_rules! impl_waveform_chx { #[cfg(any(bdma, gpdma))] Transfer::new_write( - &mut dma, + dma, req, duty, self.inner.regs_gp16().ccr(cc_channel.index()).as_ptr() as *mut u32, diff --git a/embassy-stm32/src/tsc/mod.rs b/embassy-stm32/src/tsc/mod.rs index 0d5c27465..9359d83e9 100644 --- a/embassy-stm32/src/tsc/mod.rs +++ b/embassy-stm32/src/tsc/mod.rs @@ -98,6 +98,7 @@ use core::marker::PhantomData; pub use acquisition_banks::*; pub use config::*; +use embassy_hal_internal::PeripheralType; use embassy_sync::waitqueue::AtomicWaker; pub use errors::*; pub use io_pin::*; @@ -106,7 +107,7 @@ pub use tsc::*; pub use types::*; use crate::rcc::RccPeripheral; -use crate::{interrupt, peripherals, Peripheral}; +use crate::{interrupt, peripherals}; #[cfg(tsc_v1)] const TSC_NUM_GROUPS: usize = 6; @@ -142,7 +143,7 @@ pub(crate) trait SealedInstance { /// TSC instance trait #[allow(private_bounds)] -pub trait Instance: Peripheral

+ SealedInstance + RccPeripheral { +pub trait Instance: SealedInstance + PeripheralType + RccPeripheral { /// Interrupt for this TSC instance type Interrupt: interrupt::typelevel::Interrupt; } diff --git a/embassy-stm32/src/tsc/pin_groups.rs b/embassy-stm32/src/tsc/pin_groups.rs index 1f3aafa35..6f914a94e 100644 --- a/embassy-stm32/src/tsc/pin_groups.rs +++ b/embassy-stm32/src/tsc/pin_groups.rs @@ -1,13 +1,11 @@ use core::marker::PhantomData; use core::ops::BitOr; -use embassy_hal_internal::{into_ref, PeripheralRef}; - use super::errors::GroupError; use super::io_pin::*; use super::Instance; use crate::gpio::{AfType, AnyPin, OutputType, Speed}; -use crate::Peripheral; +use crate::Peri; /// Pin type definition to control IO parameters #[derive(PartialEq, Clone, Copy)] @@ -23,7 +21,7 @@ pub enum PinType { /// Pin struct that maintains usage #[allow(missing_docs)] pub struct Pin<'d, T, Group> { - _pin: PeripheralRef<'d, AnyPin>, + _pin: Peri<'d, AnyPin>, role: PinType, tsc_io_pin: IOPin, phantom: PhantomData<(T, Group)>, @@ -426,17 +424,13 @@ macro_rules! trait_to_io_pin { macro_rules! impl_set_io { ($method:ident, $group:ident, $trait:ident, $index:expr) => { #[doc = concat!("Create a new pin1 for ", stringify!($group), " TSC group instance.")] - pub fn $method( - &mut self, - pin: impl Peripheral

> + 'd, - ) -> IOPinWithRole<$group, Role> { - into_ref!(pin); + pub fn $method(&mut self, pin: Peri<'d, impl $trait>) -> IOPinWithRole<$group, Role> { critical_section::with(|_| { pin.set_low(); pin.set_as_af(pin.af_num(), AfType::output(Role::output_type(), Speed::VeryHigh)); let tsc_io_pin = trait_to_io_pin!($trait); let new_pin = Pin { - _pin: pin.map_into(), + _pin: pin.into(), role: Role::pin_type(), tsc_io_pin, phantom: PhantomData, diff --git a/embassy-stm32/src/tsc/tsc.rs b/embassy-stm32/src/tsc/tsc.rs index 17d2da82f..e92479c26 100644 --- a/embassy-stm32/src/tsc/tsc.rs +++ b/embassy-stm32/src/tsc/tsc.rs @@ -3,7 +3,7 @@ use core::marker::PhantomData; use core::ops::BitOr; use core::task::Poll; -use embassy_hal_internal::{into_ref, PeripheralRef}; +use embassy_hal_internal::Peri; use super::acquisition_banks::*; use super::config::*; @@ -14,7 +14,7 @@ use super::types::*; use super::{Instance, InterruptHandler, TSC_NUM_GROUPS}; use crate::interrupt::typelevel::Interrupt; use crate::mode::{Async, Blocking, Mode as PeriMode}; -use crate::{interrupt, rcc, Peripheral}; +use crate::{interrupt, rcc}; /// Internal structure holding masks for different types of TSC IOs. /// @@ -31,7 +31,7 @@ struct IOMasks { /// TSC driver pub struct Tsc<'d, T: Instance, K: PeriMode> { - _peri: PeripheralRef<'d, T>, + _peri: Peri<'d, T>, _pin_groups: PinGroups<'d, T>, state: State, config: Config, @@ -218,13 +218,7 @@ impl<'d, T: Instance, K: PeriMode> Tsc<'d, T, K> { groups } - fn new_inner( - peri: impl Peripheral

+ 'd, - pin_groups: PinGroups<'d, T>, - config: Config, - ) -> Result { - into_ref!(peri); - + fn new_inner(peri: Peri<'d, T>, pin_groups: PinGroups<'d, T>, config: Config) -> Result { pin_groups.check()?; let masks = IOMasks { @@ -410,7 +404,7 @@ impl<'d, T: Instance, K: PeriMode> Drop for Tsc<'d, T, K> { impl<'d, T: Instance> Tsc<'d, T, Async> { /// Create a Tsc instance that can be awaited for completion pub fn new_async( - peri: impl Peripheral

+ 'd, + peri: Peri<'d, T>, pin_groups: PinGroups<'d, T>, config: Config, _irq: impl interrupt::typelevel::Binding> + 'd, @@ -441,11 +435,7 @@ impl<'d, T: Instance> Tsc<'d, T, Async> { impl<'d, T: Instance> Tsc<'d, T, Blocking> { /// Create a Tsc instance that must be polled for completion - pub fn new_blocking( - peri: impl Peripheral

+ 'd, - pin_groups: PinGroups<'d, T>, - config: Config, - ) -> Result { + pub fn new_blocking(peri: Peri<'d, T>, pin_groups: PinGroups<'d, T>, config: Config) -> Result { Self::new_inner(peri, pin_groups, config) } diff --git a/embassy-stm32/src/ucpd.rs b/embassy-stm32/src/ucpd.rs index c40ee8ad0..87693f148 100644 --- a/embassy-stm32/src/ucpd.rs +++ b/embassy-stm32/src/ucpd.rs @@ -20,15 +20,15 @@ use core::sync::atomic::{AtomicBool, Ordering}; use core::task::Poll; use embassy_hal_internal::drop::OnDrop; -use embassy_hal_internal::{into_ref, Peripheral}; +use embassy_hal_internal::PeripheralType; use embassy_sync::waitqueue::AtomicWaker; use crate::dma::{ChannelAndRequest, TransferOptions}; -use crate::interrupt; use crate::interrupt::typelevel::Interrupt; use crate::pac::ucpd::vals::{Anamode, Ccenable, PscUsbpdclk, Txmode}; pub use crate::pac::ucpd::vals::{Phyccsel as CcSel, Rxordset, TypecVstateCc as CcVState}; use crate::rcc::{self, RccPeripheral}; +use crate::{interrupt, Peri}; pub(crate) fn init( _cs: critical_section::CriticalSection, @@ -122,13 +122,12 @@ pub struct Ucpd<'d, T: Instance> { impl<'d, T: Instance> Ucpd<'d, T> { /// Creates a new UCPD driver instance. pub fn new( - _peri: impl Peripheral

+ 'd, + _peri: Peri<'d, T>, _irq: impl interrupt::typelevel::Binding> + 'd, - cc1: impl Peripheral

> + 'd, - cc2: impl Peripheral

> + 'd, + cc1: Peri<'d, impl Cc1Pin>, + cc2: Peri<'d, impl Cc2Pin>, config: Config, ) -> Self { - into_ref!(cc1, cc2); cc1.set_as_analog(); cc2.set_as_analog(); @@ -208,8 +207,8 @@ impl<'d, T: Instance> Ucpd<'d, T> { /// and a Power Delivery (PD) PHY with receiver and transmitter. pub fn split_pd_phy( self, - rx_dma: impl Peripheral

> + 'd, - tx_dma: impl Peripheral

> + 'd, + rx_dma: Peri<'d, impl RxDma>, + tx_dma: Peri<'d, impl TxDma>, cc_sel: CcSel, ) -> (CcPhy<'d, T>, PdPhy<'d, T>) { let r = T::REGS; @@ -229,7 +228,6 @@ impl<'d, T: Instance> Ucpd<'d, T> { // Both parts must be dropped before the peripheral can be disabled. T::state().drop_not_ready.store(true, Ordering::Relaxed); - into_ref!(rx_dma, tx_dma); let rx_dma_req = rx_dma.request(); let tx_dma_req = tx_dma.request(); ( @@ -237,11 +235,11 @@ impl<'d, T: Instance> Ucpd<'d, T> { PdPhy { _lifetime: PhantomData, rx_dma: ChannelAndRequest { - channel: rx_dma.map_into(), + channel: rx_dma.into(), request: rx_dma_req, }, tx_dma: ChannelAndRequest { - channel: tx_dma.map_into(), + channel: tx_dma.into(), request: tx_dma_req, }, }, @@ -689,7 +687,7 @@ trait SealedInstance { /// UCPD instance trait. #[allow(private_bounds)] -pub trait Instance: SealedInstance + RccPeripheral { +pub trait Instance: SealedInstance + PeripheralType + RccPeripheral { /// Interrupt for this instance. type Interrupt: crate::interrupt::typelevel::Interrupt; } diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs index 7fa9ee08e..b1640b6dc 100644 --- a/embassy-stm32/src/usart/buffered.rs +++ b/embassy-stm32/src/usart/buffered.rs @@ -6,7 +6,7 @@ use core::task::Poll; use embassy_embedded_hal::SetConfig; use embassy_hal_internal::atomic_ring_buffer::RingBuffer; -use embassy_hal_internal::{Peripheral, PeripheralRef}; +use embassy_hal_internal::Peri; use embassy_sync::waitqueue::AtomicWaker; #[cfg(not(any(usart_v1, usart_v2)))] @@ -159,9 +159,9 @@ pub struct BufferedUartTx<'d> { info: &'static Info, state: &'static State, kernel_clock: Hertz, - tx: Option>, - cts: Option>, - de: Option>, + tx: Option>, + cts: Option>, + de: Option>, is_borrowed: bool, } @@ -172,8 +172,8 @@ pub struct BufferedUartRx<'d> { info: &'static Info, state: &'static State, kernel_clock: Hertz, - rx: Option>, - rts: Option>, + rx: Option>, + rts: Option>, is_borrowed: bool, } @@ -207,10 +207,10 @@ impl<'d> SetConfig for BufferedUartTx<'d> { impl<'d> BufferedUart<'d> { /// Create a new bidirectional buffered UART driver pub fn new( - peri: impl Peripheral

+ 'd, + peri: Peri<'d, T>, _irq: impl interrupt::typelevel::Binding> + 'd, - rx: impl Peripheral

> + 'd, - tx: impl Peripheral

> + 'd, + rx: Peri<'d, impl RxPin>, + tx: Peri<'d, impl TxPin>, tx_buffer: &'d mut [u8], rx_buffer: &'d mut [u8], config: Config, @@ -230,12 +230,12 @@ impl<'d> BufferedUart<'d> { /// Create a new bidirectional buffered UART driver with request-to-send and clear-to-send pins pub fn new_with_rtscts( - peri: impl Peripheral

+ 'd, + peri: Peri<'d, T>, _irq: impl interrupt::typelevel::Binding> + 'd, - rx: impl Peripheral

> + 'd, - tx: impl Peripheral

> + 'd, - rts: impl Peripheral

> + 'd, - cts: impl Peripheral

> + 'd, + rx: Peri<'d, impl RxPin>, + tx: Peri<'d, impl TxPin>, + rts: Peri<'d, impl RtsPin>, + cts: Peri<'d, impl CtsPin>, tx_buffer: &'d mut [u8], rx_buffer: &'d mut [u8], config: Config, @@ -255,11 +255,11 @@ impl<'d> BufferedUart<'d> { /// Create a new bidirectional buffered UART driver with only the RTS pin as the DE pin pub fn new_with_rts_as_de( - peri: impl Peripheral

+ 'd, + peri: Peri<'d, T>, _irq: impl interrupt::typelevel::Binding> + 'd, - rx: impl Peripheral

> + 'd, - tx: impl Peripheral

> + 'd, - rts: impl Peripheral

> + 'd, + rx: Peri<'d, impl RxPin>, + tx: Peri<'d, impl TxPin>, + rts: Peri<'d, impl RtsPin>, tx_buffer: &'d mut [u8], rx_buffer: &'d mut [u8], config: Config, @@ -279,11 +279,11 @@ impl<'d> BufferedUart<'d> { /// Create a new bidirectional buffered UART driver with only the request-to-send pin pub fn new_with_rts( - peri: impl Peripheral

+ 'd, + peri: Peri<'d, T>, _irq: impl interrupt::typelevel::Binding> + 'd, - rx: impl Peripheral

> + 'd, - tx: impl Peripheral

> + 'd, - rts: impl Peripheral

> + 'd, + rx: Peri<'d, impl RxPin>, + tx: Peri<'d, impl TxPin>, + rts: Peri<'d, impl RtsPin>, tx_buffer: &'d mut [u8], rx_buffer: &'d mut [u8], config: Config, @@ -304,11 +304,11 @@ impl<'d> BufferedUart<'d> { /// Create a new bidirectional buffered UART driver with a driver-enable pin #[cfg(not(any(usart_v1, usart_v2)))] pub fn new_with_de( - peri: impl Peripheral

+ 'd, + peri: Peri<'d, T>, _irq: impl interrupt::typelevel::Binding> + 'd, - rx: impl Peripheral

> + 'd, - tx: impl Peripheral

> + 'd, - de: impl Peripheral

> + 'd, + rx: Peri<'d, impl RxPin>, + tx: Peri<'d, impl TxPin>, + de: Peri<'d, impl DePin>, tx_buffer: &'d mut [u8], rx_buffer: &'d mut [u8], config: Config, @@ -339,8 +339,8 @@ impl<'d> BufferedUart<'d> { /// on the line must be managed by software (for instance by using a centralized arbiter). #[doc(alias("HDSEL"))] pub fn new_half_duplex( - peri: impl Peripheral

+ 'd, - tx: impl Peripheral

> + 'd, + peri: Peri<'d, T>, + tx: Peri<'d, impl TxPin>, _irq: impl interrupt::typelevel::Binding> + 'd, tx_buffer: &'d mut [u8], rx_buffer: &'d mut [u8], @@ -379,8 +379,8 @@ impl<'d> BufferedUart<'d> { #[cfg(not(any(usart_v1, usart_v2)))] #[doc(alias("HDSEL"))] pub fn new_half_duplex_on_rx( - peri: impl Peripheral

+ 'd, - rx: impl Peripheral

> + 'd, + peri: Peri<'d, T>, + rx: Peri<'d, impl RxPin>, _irq: impl interrupt::typelevel::Binding> + 'd, tx_buffer: &'d mut [u8], rx_buffer: &'d mut [u8], @@ -405,12 +405,12 @@ impl<'d> BufferedUart<'d> { } fn new_inner( - _peri: impl Peripheral

+ 'd, - rx: Option>, - tx: Option>, - rts: Option>, - cts: Option>, - de: Option>, + _peri: Peri<'d, T>, + rx: Option>, + tx: Option>, + rts: Option>, + cts: Option>, + de: Option>, tx_buffer: &'d mut [u8], rx_buffer: &'d mut [u8], config: Config, @@ -505,17 +505,17 @@ impl<'d> BufferedUart<'d> { info: self.tx.info, state: self.tx.state, kernel_clock: self.tx.kernel_clock, - tx: self.tx.tx.as_mut().map(PeripheralRef::reborrow), - cts: self.tx.cts.as_mut().map(PeripheralRef::reborrow), - de: self.tx.de.as_mut().map(PeripheralRef::reborrow), + tx: self.tx.tx.as_mut().map(Peri::reborrow), + cts: self.tx.cts.as_mut().map(Peri::reborrow), + de: self.tx.de.as_mut().map(Peri::reborrow), is_borrowed: true, }, BufferedUartRx { info: self.rx.info, state: self.rx.state, kernel_clock: self.rx.kernel_clock, - rx: self.rx.rx.as_mut().map(PeripheralRef::reborrow), - rts: self.rx.rts.as_mut().map(PeripheralRef::reborrow), + rx: self.rx.rx.as_mut().map(Peri::reborrow), + rts: self.rx.rts.as_mut().map(Peri::reborrow), is_borrowed: true, }, ) diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index 568067360..675e90c7f 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -9,7 +9,7 @@ use core::task::Poll; use embassy_embedded_hal::SetConfig; use embassy_hal_internal::drop::OnDrop; -use embassy_hal_internal::PeripheralRef; +use embassy_hal_internal::PeripheralType; use embassy_sync::waitqueue::AtomicWaker; use futures_util::future::{select, Either}; @@ -30,7 +30,7 @@ use crate::pac::usart::Usart as Regs; use crate::pac::usart::{regs, vals}; use crate::rcc::{RccInfo, SealedRccPeripheral}; use crate::time::Hertz; -use crate::Peripheral; +use crate::Peri; /// Interrupt handler. pub struct InterruptHandler { @@ -348,9 +348,9 @@ pub struct UartTx<'d, M: Mode> { info: &'static Info, state: &'static State, kernel_clock: Hertz, - tx: Option>, - cts: Option>, - de: Option>, + tx: Option>, + cts: Option>, + de: Option>, tx_dma: Option>, duplex: Duplex, _phantom: PhantomData, @@ -398,8 +398,8 @@ pub struct UartRx<'d, M: Mode> { info: &'static Info, state: &'static State, kernel_clock: Hertz, - rx: Option>, - rts: Option>, + rx: Option>, + rts: Option>, rx_dma: Option>, detect_previous_overrun: bool, #[cfg(any(usart_v1, usart_v2))] @@ -419,9 +419,9 @@ impl<'d, M: Mode> SetConfig for UartRx<'d, M> { impl<'d> UartTx<'d, Async> { /// Useful if you only want Uart Tx. It saves 1 pin and consumes a little less power. pub fn new( - peri: impl Peripheral

+ 'd, - tx: impl Peripheral

> + 'd, - tx_dma: impl Peripheral

> + 'd, + peri: Peri<'d, T>, + tx: Peri<'d, impl TxPin>, + tx_dma: Peri<'d, impl TxDma>, config: Config, ) -> Result { Self::new_inner( @@ -435,10 +435,10 @@ impl<'d> UartTx<'d, Async> { /// Create a new tx-only UART with a clear-to-send pin pub fn new_with_cts( - peri: impl Peripheral

+ 'd, - tx: impl Peripheral

> + 'd, - cts: impl Peripheral

> + 'd, - tx_dma: impl Peripheral

> + 'd, + peri: Peri<'d, T>, + tx: Peri<'d, impl TxPin>, + cts: Peri<'d, impl CtsPin>, + tx_dma: Peri<'d, impl TxDma>, config: Config, ) -> Result { Self::new_inner( @@ -478,8 +478,8 @@ impl<'d> UartTx<'d, Blocking> { /// /// Useful if you only want Uart Tx. It saves 1 pin and consumes a little less power. pub fn new_blocking( - peri: impl Peripheral

+ 'd, - tx: impl Peripheral

> + 'd, + peri: Peri<'d, T>, + tx: Peri<'d, impl TxPin>, config: Config, ) -> Result { Self::new_inner( @@ -493,9 +493,9 @@ impl<'d> UartTx<'d, Blocking> { /// Create a new blocking tx-only UART with a clear-to-send pin pub fn new_blocking_with_cts( - peri: impl Peripheral

+ 'd, - tx: impl Peripheral

> + 'd, - cts: impl Peripheral

> + 'd, + peri: Peri<'d, T>, + tx: Peri<'d, impl TxPin>, + cts: Peri<'d, impl CtsPin>, config: Config, ) -> Result { Self::new_inner( @@ -510,9 +510,9 @@ impl<'d> UartTx<'d, Blocking> { impl<'d, M: Mode> UartTx<'d, M> { fn new_inner( - _peri: impl Peripheral

+ 'd, - tx: Option>, - cts: Option>, + _peri: Peri<'d, T>, + tx: Option>, + cts: Option>, tx_dma: Option>, config: Config, ) -> Result { @@ -650,10 +650,10 @@ impl<'d> UartRx<'d, Async> { /// /// Useful if you only want Uart Rx. It saves 1 pin and consumes a little less power. pub fn new( - peri: impl Peripheral

+ 'd, + peri: Peri<'d, T>, _irq: impl interrupt::typelevel::Binding> + 'd, - rx: impl Peripheral

> + 'd, - rx_dma: impl Peripheral

> + 'd, + rx: Peri<'d, impl RxPin>, + rx_dma: Peri<'d, impl RxDma>, config: Config, ) -> Result { Self::new_inner( @@ -667,11 +667,11 @@ impl<'d> UartRx<'d, Async> { /// Create a new rx-only UART with a request-to-send pin pub fn new_with_rts( - peri: impl Peripheral

+ 'd, + peri: Peri<'d, T>, _irq: impl interrupt::typelevel::Binding> + 'd, - rx: impl Peripheral

> + 'd, - rts: impl Peripheral

> + 'd, - rx_dma: impl Peripheral

> + 'd, + rx: Peri<'d, impl RxPin>, + rts: Peri<'d, impl RtsPin>, + rx_dma: Peri<'d, impl RxDma>, config: Config, ) -> Result { Self::new_inner( @@ -908,8 +908,8 @@ impl<'d> UartRx<'d, Blocking> { /// /// Useful if you only want Uart Rx. It saves 1 pin and consumes a little less power. pub fn new_blocking( - peri: impl Peripheral

+ 'd, - rx: impl Peripheral

> + 'd, + peri: Peri<'d, T>, + rx: Peri<'d, impl RxPin>, config: Config, ) -> Result { Self::new_inner(peri, new_pin!(rx, AfType::input(config.rx_pull)), None, None, config) @@ -917,9 +917,9 @@ impl<'d> UartRx<'d, Blocking> { /// Create a new rx-only UART with a request-to-send pin pub fn new_blocking_with_rts( - peri: impl Peripheral

+ 'd, - rx: impl Peripheral

> + 'd, - rts: impl Peripheral

> + 'd, + peri: Peri<'d, T>, + rx: Peri<'d, impl RxPin>, + rts: Peri<'d, impl RtsPin>, config: Config, ) -> Result { Self::new_inner( @@ -934,9 +934,9 @@ impl<'d> UartRx<'d, Blocking> { impl<'d, M: Mode> UartRx<'d, M> { fn new_inner( - _peri: impl Peripheral

+ 'd, - rx: Option>, - rts: Option>, + _peri: Peri<'d, T>, + rx: Option>, + rts: Option>, rx_dma: Option>, config: Config, ) -> Result { @@ -1104,12 +1104,12 @@ fn drop_tx_rx(info: &Info, state: &State) { impl<'d> Uart<'d, Async> { /// Create a new bidirectional UART pub fn new( - peri: impl Peripheral

+ 'd, - rx: impl Peripheral

> + 'd, - tx: impl Peripheral

> + 'd, + peri: Peri<'d, T>, + rx: Peri<'d, impl RxPin>, + tx: Peri<'d, impl TxPin>, _irq: impl interrupt::typelevel::Binding> + 'd, - tx_dma: impl Peripheral

> + 'd, - rx_dma: impl Peripheral

> + 'd, + tx_dma: Peri<'d, impl TxDma>, + rx_dma: Peri<'d, impl RxDma>, config: Config, ) -> Result { Self::new_inner( @@ -1127,14 +1127,14 @@ impl<'d> Uart<'d, Async> { /// Create a new bidirectional UART with request-to-send and clear-to-send pins pub fn new_with_rtscts( - peri: impl Peripheral

+ 'd, - rx: impl Peripheral

> + 'd, - tx: impl Peripheral

> + 'd, + peri: Peri<'d, T>, + rx: Peri<'d, impl RxPin>, + tx: Peri<'d, impl TxPin>, _irq: impl interrupt::typelevel::Binding> + 'd, - rts: impl Peripheral

> + 'd, - cts: impl Peripheral

> + 'd, - tx_dma: impl Peripheral

> + 'd, - rx_dma: impl Peripheral

> + 'd, + rts: Peri<'d, impl RtsPin>, + cts: Peri<'d, impl CtsPin>, + tx_dma: Peri<'d, impl TxDma>, + rx_dma: Peri<'d, impl RxDma>, config: Config, ) -> Result { Self::new_inner( @@ -1153,13 +1153,13 @@ impl<'d> Uart<'d, Async> { #[cfg(not(any(usart_v1, usart_v2)))] /// Create a new bidirectional UART with a driver-enable pin pub fn new_with_de( - peri: impl Peripheral

+ 'd, - rx: impl Peripheral

> + 'd, - tx: impl Peripheral

> + 'd, + peri: Peri<'d, T>, + rx: Peri<'d, impl RxPin>, + tx: Peri<'d, impl TxPin>, _irq: impl interrupt::typelevel::Binding> + 'd, - de: impl Peripheral

> + 'd, - tx_dma: impl Peripheral

> + 'd, - rx_dma: impl Peripheral

> + 'd, + de: Peri<'d, impl DePin>, + tx_dma: Peri<'d, impl TxDma>, + rx_dma: Peri<'d, impl RxDma>, config: Config, ) -> Result { Self::new_inner( @@ -1188,11 +1188,11 @@ impl<'d> Uart<'d, Async> { /// on the line must be managed by software (for instance by using a centralized arbiter). #[doc(alias("HDSEL"))] pub fn new_half_duplex( - peri: impl Peripheral

+ 'd, - tx: impl Peripheral

> + 'd, + peri: Peri<'d, T>, + tx: Peri<'d, impl TxPin>, _irq: impl interrupt::typelevel::Binding> + 'd, - tx_dma: impl Peripheral

> + 'd, - rx_dma: impl Peripheral

> + 'd, + tx_dma: Peri<'d, impl TxDma>, + rx_dma: Peri<'d, impl RxDma>, mut config: Config, readback: HalfDuplexReadback, half_duplex: HalfDuplexConfig, @@ -1228,11 +1228,11 @@ impl<'d> Uart<'d, Async> { #[cfg(not(any(usart_v1, usart_v2)))] #[doc(alias("HDSEL"))] pub fn new_half_duplex_on_rx( - peri: impl Peripheral

+ 'd, - rx: impl Peripheral

> + 'd, + peri: Peri<'d, T>, + rx: Peri<'d, impl RxPin>, _irq: impl interrupt::typelevel::Binding> + 'd, - tx_dma: impl Peripheral

> + 'd, - rx_dma: impl Peripheral

> + 'd, + tx_dma: Peri<'d, impl TxDma>, + rx_dma: Peri<'d, impl RxDma>, mut config: Config, readback: HalfDuplexReadback, half_duplex: HalfDuplexConfig, @@ -1277,9 +1277,9 @@ impl<'d> Uart<'d, Async> { impl<'d> Uart<'d, Blocking> { /// Create a new blocking bidirectional UART. pub fn new_blocking( - peri: impl Peripheral

+ 'd, - rx: impl Peripheral

> + 'd, - tx: impl Peripheral

> + 'd, + peri: Peri<'d, T>, + rx: Peri<'d, impl RxPin>, + tx: Peri<'d, impl TxPin>, config: Config, ) -> Result { Self::new_inner( @@ -1297,11 +1297,11 @@ impl<'d> Uart<'d, Blocking> { /// Create a new bidirectional UART with request-to-send and clear-to-send pins pub fn new_blocking_with_rtscts( - peri: impl Peripheral

+ 'd, - rx: impl Peripheral

> + 'd, - tx: impl Peripheral

> + 'd, - rts: impl Peripheral

> + 'd, - cts: impl Peripheral

> + 'd, + peri: Peri<'d, T>, + rx: Peri<'d, impl RxPin>, + tx: Peri<'d, impl TxPin>, + rts: Peri<'d, impl RtsPin>, + cts: Peri<'d, impl CtsPin>, config: Config, ) -> Result { Self::new_inner( @@ -1320,10 +1320,10 @@ impl<'d> Uart<'d, Blocking> { #[cfg(not(any(usart_v1, usart_v2)))] /// Create a new bidirectional UART with a driver-enable pin pub fn new_blocking_with_de( - peri: impl Peripheral

+ 'd, - rx: impl Peripheral

> + 'd, - tx: impl Peripheral

> + 'd, - de: impl Peripheral

> + 'd, + peri: Peri<'d, T>, + rx: Peri<'d, impl RxPin>, + tx: Peri<'d, impl TxPin>, + de: Peri<'d, impl DePin>, config: Config, ) -> Result { Self::new_inner( @@ -1351,8 +1351,8 @@ impl<'d> Uart<'d, Blocking> { /// on the line must be managed by software (for instance by using a centralized arbiter). #[doc(alias("HDSEL"))] pub fn new_blocking_half_duplex( - peri: impl Peripheral

+ 'd, - tx: impl Peripheral

> + 'd, + peri: Peri<'d, T>, + tx: Peri<'d, impl TxPin>, mut config: Config, readback: HalfDuplexReadback, half_duplex: HalfDuplexConfig, @@ -1388,8 +1388,8 @@ impl<'d> Uart<'d, Blocking> { #[cfg(not(any(usart_v1, usart_v2)))] #[doc(alias("HDSEL"))] pub fn new_blocking_half_duplex_on_rx( - peri: impl Peripheral

+ 'd, - rx: impl Peripheral

> + 'd, + peri: Peri<'d, T>, + rx: Peri<'d, impl RxPin>, mut config: Config, readback: HalfDuplexReadback, half_duplex: HalfDuplexConfig, @@ -1413,12 +1413,12 @@ impl<'d> Uart<'d, Blocking> { impl<'d, M: Mode> Uart<'d, M> { fn new_inner( - _peri: impl Peripheral

+ 'd, - rx: Option>, - tx: Option>, - rts: Option>, - cts: Option>, - de: Option>, + _peri: Peri<'d, T>, + rx: Option>, + tx: Option>, + rts: Option>, + cts: Option>, + de: Option>, tx_dma: Option>, rx_dma: Option>, config: Config, @@ -2050,7 +2050,7 @@ pub(crate) trait SealedInstance: crate::rcc::RccPeripheral { /// USART peripheral instance trait. #[allow(private_bounds)] -pub trait Instance: Peripheral

+ SealedInstance + 'static + Send { +pub trait Instance: SealedInstance + PeripheralType + 'static + Send { /// Interrupt for this peripheral. type Interrupt: interrupt::typelevel::Interrupt; } diff --git a/embassy-stm32/src/usart/ringbuffered.rs b/embassy-stm32/src/usart/ringbuffered.rs index ffd4ee544..600e72582 100644 --- a/embassy-stm32/src/usart/ringbuffered.rs +++ b/embassy-stm32/src/usart/ringbuffered.rs @@ -4,7 +4,6 @@ use core::sync::atomic::{compiler_fence, Ordering}; use core::task::Poll; use embassy_embedded_hal::SetConfig; -use embassy_hal_internal::PeripheralRef; use embedded_io_async::ReadReady; use futures_util::future::{select, Either}; @@ -18,6 +17,7 @@ use crate::mode::Async; use crate::pac::usart::regs; use crate::time::Hertz; use crate::usart::{Regs, Sr}; +use crate::Peri; /// Rx-only Ring-buffered UART Driver /// @@ -26,8 +26,8 @@ pub struct RingBufferedUartRx<'d> { info: &'static Info, state: &'static State, kernel_clock: Hertz, - rx: Option>, - rts: Option>, + rx: Option>, + rts: Option>, ring_buf: ReadableRingBuffer<'d, u8>, } diff --git a/embassy-stm32/src/usb/otg.rs b/embassy-stm32/src/usb/otg.rs index d3c7978e4..51429b8cc 100644 --- a/embassy-stm32/src/usb/otg.rs +++ b/embassy-stm32/src/usb/otg.rs @@ -1,6 +1,6 @@ use core::marker::PhantomData; -use embassy_hal_internal::{into_ref, Peripheral}; +use embassy_hal_internal::PeripheralType; use embassy_usb_driver::{EndpointAddress, EndpointAllocError, EndpointType, Event, Unsupported}; use embassy_usb_synopsys_otg::otg_v1::vals::Dspd; use embassy_usb_synopsys_otg::otg_v1::Otg; @@ -11,9 +11,9 @@ use embassy_usb_synopsys_otg::{ }; use crate::gpio::{AfType, OutputType, Speed}; -use crate::interrupt; use crate::interrupt::typelevel::Interrupt; use crate::rcc::{self, RccPeripheral}; +use crate::{interrupt, Peri}; const MAX_EP_COUNT: usize = 9; @@ -32,8 +32,7 @@ impl interrupt::typelevel::Handler for InterruptHandl macro_rules! config_ulpi_pins { ($($pin:ident),*) => { - into_ref!($($pin),*); - critical_section::with(|_| { + critical_section::with(|_| { $( $pin.set_as_af($pin.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh)); )* @@ -62,15 +61,13 @@ impl<'d, T: Instance> Driver<'d, T> { /// Must be large enough to fit all OUT endpoint max packet sizes. /// Endpoint allocation will fail if it is too small. pub fn new_fs( - _peri: impl Peripheral

+ 'd, + _peri: Peri<'d, T>, _irq: impl interrupt::typelevel::Binding> + 'd, - dp: impl Peripheral

> + 'd, - dm: impl Peripheral

> + 'd, + dp: Peri<'d, impl DpPin>, + dm: Peri<'d, impl DmPin>, ep_out_buffer: &'d mut [u8], config: Config, ) -> Self { - into_ref!(dp, dm); - dp.set_as_af(dp.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh)); dm.set_as_af(dm.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh)); @@ -100,17 +97,16 @@ impl<'d, T: Instance> Driver<'d, T> { /// Must be large enough to fit all OUT endpoint max packet sizes. /// Endpoint allocation will fail if it is too small. pub fn new_hs( - _peri: impl Peripheral

+ 'd, + _peri: Peri<'d, T>, _irq: impl interrupt::typelevel::Binding> + 'd, - _dp: impl Peripheral

> + 'd, - _dm: impl Peripheral

> + 'd, + _dp: Peri<'d, impl DpPin>, + _dm: Peri<'d, impl DmPin>, ep_out_buffer: &'d mut [u8], config: Config, ) -> Self { // For STM32U5 High speed pins need to be left in analog mode #[cfg(not(all(stm32u5, peri_usb_otg_hs)))] { - into_ref!(_dp, _dm); _dp.set_as_af(_dp.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh)); _dm.set_as_af(_dm.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh)); } @@ -139,20 +135,20 @@ impl<'d, T: Instance> Driver<'d, T> { /// Must be large enough to fit all OUT endpoint max packet sizes. /// Endpoint allocation will fail if it is too small. pub fn new_fs_ulpi( - _peri: impl Peripheral

+ 'd, + _peri: Peri<'d, T>, _irq: impl interrupt::typelevel::Binding> + 'd, - ulpi_clk: impl Peripheral

> + 'd, - ulpi_dir: impl Peripheral

> + 'd, - ulpi_nxt: impl Peripheral

> + 'd, - ulpi_stp: impl Peripheral

> + 'd, - ulpi_d0: impl Peripheral

> + 'd, - ulpi_d1: impl Peripheral

> + 'd, - ulpi_d2: impl Peripheral

> + 'd, - ulpi_d3: impl Peripheral

> + 'd, - ulpi_d4: impl Peripheral

> + 'd, - ulpi_d5: impl Peripheral

> + 'd, - ulpi_d6: impl Peripheral

> + 'd, - ulpi_d7: impl Peripheral

> + 'd, + ulpi_clk: Peri<'d, impl UlpiClkPin>, + ulpi_dir: Peri<'d, impl UlpiDirPin>, + ulpi_nxt: Peri<'d, impl UlpiNxtPin>, + ulpi_stp: Peri<'d, impl UlpiStpPin>, + ulpi_d0: Peri<'d, impl UlpiD0Pin>, + ulpi_d1: Peri<'d, impl UlpiD1Pin>, + ulpi_d2: Peri<'d, impl UlpiD2Pin>, + ulpi_d3: Peri<'d, impl UlpiD3Pin>, + ulpi_d4: Peri<'d, impl UlpiD4Pin>, + ulpi_d5: Peri<'d, impl UlpiD5Pin>, + ulpi_d6: Peri<'d, impl UlpiD6Pin>, + ulpi_d7: Peri<'d, impl UlpiD7Pin>, ep_out_buffer: &'d mut [u8], config: Config, ) -> Self { @@ -185,20 +181,20 @@ impl<'d, T: Instance> Driver<'d, T> { /// Must be large enough to fit all OUT endpoint max packet sizes. /// Endpoint allocation will fail if it is too small. pub fn new_hs_ulpi( - _peri: impl Peripheral

+ 'd, + _peri: Peri<'d, T>, _irq: impl interrupt::typelevel::Binding> + 'd, - ulpi_clk: impl Peripheral

> + 'd, - ulpi_dir: impl Peripheral

> + 'd, - ulpi_nxt: impl Peripheral

> + 'd, - ulpi_stp: impl Peripheral

> + 'd, - ulpi_d0: impl Peripheral

> + 'd, - ulpi_d1: impl Peripheral

> + 'd, - ulpi_d2: impl Peripheral

> + 'd, - ulpi_d3: impl Peripheral

> + 'd, - ulpi_d4: impl Peripheral

> + 'd, - ulpi_d5: impl Peripheral

> + 'd, - ulpi_d6: impl Peripheral

> + 'd, - ulpi_d7: impl Peripheral

> + 'd, + ulpi_clk: Peri<'d, impl UlpiClkPin>, + ulpi_dir: Peri<'d, impl UlpiDirPin>, + ulpi_nxt: Peri<'d, impl UlpiNxtPin>, + ulpi_stp: Peri<'d, impl UlpiStpPin>, + ulpi_d0: Peri<'d, impl UlpiD0Pin>, + ulpi_d1: Peri<'d, impl UlpiD1Pin>, + ulpi_d2: Peri<'d, impl UlpiD2Pin>, + ulpi_d3: Peri<'d, impl UlpiD3Pin>, + ulpi_d4: Peri<'d, impl UlpiD4Pin>, + ulpi_d5: Peri<'d, impl UlpiD5Pin>, + ulpi_d6: Peri<'d, impl UlpiD6Pin>, + ulpi_d7: Peri<'d, impl UlpiD7Pin>, ep_out_buffer: &'d mut [u8], config: Config, ) -> Self { @@ -411,7 +407,7 @@ trait SealedInstance { /// USB instance trait. #[allow(private_bounds)] -pub trait Instance: SealedInstance + RccPeripheral + 'static { +pub trait Instance: SealedInstance + PeripheralType + RccPeripheral + 'static { /// Interrupt for this USB instance. type Interrupt: interrupt::typelevel::Interrupt; } diff --git a/embassy-stm32/src/usb/usb.rs b/embassy-stm32/src/usb/usb.rs index 6682374d3..0b878915a 100644 --- a/embassy-stm32/src/usb/usb.rs +++ b/embassy-stm32/src/usb/usb.rs @@ -5,7 +5,7 @@ use core::marker::PhantomData; use core::sync::atomic::{AtomicBool, Ordering}; use core::task::Poll; -use embassy_hal_internal::into_ref; +use embassy_hal_internal::PeripheralType; use embassy_sync::waitqueue::AtomicWaker; use embassy_usb_driver as driver; use embassy_usb_driver::{ @@ -16,7 +16,7 @@ use crate::pac::usb::regs; use crate::pac::usb::vals::{EpType, Stat}; use crate::pac::USBRAM; use crate::rcc::RccPeripheral; -use crate::{interrupt, Peripheral}; +use crate::{interrupt, Peri}; /// Interrupt handler. pub struct InterruptHandler { @@ -290,13 +290,12 @@ impl<'d, T: Instance> Driver<'d, T> { /// Create a new USB driver with start-of-frame (SOF) output. #[cfg(not(stm32l1))] pub fn new_with_sof( - _usb: impl Peripheral

+ 'd, + _usb: Peri<'d, T>, _irq: impl interrupt::typelevel::Binding> + 'd, - dp: impl Peripheral

> + 'd, - dm: impl Peripheral

> + 'd, - sof: impl Peripheral

> + 'd, + dp: Peri<'d, impl DpPin>, + dm: Peri<'d, impl DmPin>, + sof: Peri<'d, impl SofPin>, ) -> Self { - into_ref!(sof); { use crate::gpio::{AfType, OutputType, Speed}; sof.set_as_af(sof.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh)); @@ -307,13 +306,11 @@ impl<'d, T: Instance> Driver<'d, T> { /// Create a new USB driver. pub fn new( - _usb: impl Peripheral

+ 'd, + _usb: Peri<'d, T>, _irq: impl interrupt::typelevel::Binding> + 'd, - dp: impl Peripheral

> + 'd, - dm: impl Peripheral

> + 'd, + dp: Peri<'d, impl DpPin>, + dm: Peri<'d, impl DmPin>, ) -> Self { - into_ref!(dp, dm); - super::common_init::(); let regs = T::regs(); @@ -1236,7 +1233,7 @@ trait SealedInstance { /// USB instance trait. #[allow(private_bounds)] -pub trait Instance: SealedInstance + RccPeripheral + 'static { +pub trait Instance: SealedInstance + PeripheralType + RccPeripheral + 'static { /// Interrupt for this USB instance. type Interrupt: interrupt::typelevel::Interrupt; } diff --git a/embassy-stm32/src/wdg/mod.rs b/embassy-stm32/src/wdg/mod.rs index ab21c4b6b..fb5c3d930 100644 --- a/embassy-stm32/src/wdg/mod.rs +++ b/embassy-stm32/src/wdg/mod.rs @@ -1,10 +1,11 @@ //! Watchdog Timer (IWDG, WWDG) use core::marker::PhantomData; -use embassy_hal_internal::{into_ref, Peripheral}; +use embassy_hal_internal::PeripheralType; use stm32_metapac::iwdg::vals::{Key, Pr}; use crate::rcc::LSI_FREQ; +use crate::Peri; /// Independent watchdog (IWDG) driver. pub struct IndependentWatchdog<'d, T: Instance> { @@ -29,9 +30,7 @@ impl<'d, T: Instance> IndependentWatchdog<'d, T> { /// /// [Self] has to be started with [Self::unleash()]. /// Once timer expires, MCU will be reset. To prevent this, timer must be reloaded by repeatedly calling [Self::pet()] within timeout interval. - pub fn new(_instance: impl Peripheral

+ 'd, timeout_us: u32) -> Self { - into_ref!(_instance); - + pub fn new(_instance: Peri<'d, T>, timeout_us: u32) -> Self { // Find lowest prescaler value, which makes watchdog period longer or equal to timeout. // This iterates from 4 (2^2) to 256 (2^8). let psc_power = unwrap!((2..=8).find(|psc_power| { @@ -86,7 +85,7 @@ trait SealedInstance { /// IWDG instance trait. #[allow(private_bounds)] -pub trait Instance: SealedInstance {} +pub trait Instance: SealedInstance + PeripheralType {} foreach_peripheral!( (iwdg, $inst:ident) => { diff --git a/examples/nrf52840-rtic/src/bin/blinky.rs b/examples/nrf52840-rtic/src/bin/blinky.rs index 5a074ea17..719e22729 100644 --- a/examples/nrf52840-rtic/src/bin/blinky.rs +++ b/examples/nrf52840-rtic/src/bin/blinky.rs @@ -8,7 +8,7 @@ use {defmt_rtt as _, panic_probe as _}; mod app { use defmt::info; use embassy_nrf::gpio::{Level, Output, OutputDrive}; - use embassy_nrf::peripherals; + use embassy_nrf::{peripherals, Peri}; use embassy_time::Timer; #[shared] @@ -28,7 +28,7 @@ mod app { } #[task(priority = 1)] - async fn blink(_cx: blink::Context, pin: peripherals::P0_13) { + async fn blink(_cx: blink::Context, pin: Peri<'static, peripherals::P0_13>) { let mut led = Output::new(pin, Level::Low, OutputDrive::Standard); loop { diff --git a/examples/nrf52840/src/bin/channel_sender_receiver.rs b/examples/nrf52840/src/bin/channel_sender_receiver.rs index 29f70f91c..74c62ca20 100644 --- a/examples/nrf52840/src/bin/channel_sender_receiver.rs +++ b/examples/nrf52840/src/bin/channel_sender_receiver.rs @@ -3,7 +3,8 @@ use defmt::unwrap; use embassy_executor::Spawner; -use embassy_nrf::gpio::{AnyPin, Level, Output, OutputDrive, Pin}; +use embassy_nrf::gpio::{AnyPin, Level, Output, OutputDrive}; +use embassy_nrf::Peri; use embassy_sync::blocking_mutex::raw::NoopRawMutex; use embassy_sync::channel::{Channel, Receiver, Sender}; use embassy_time::Timer; @@ -28,7 +29,7 @@ async fn send_task(sender: Sender<'static, NoopRawMutex, LedState, 1>) { } #[embassy_executor::task] -async fn recv_task(led: AnyPin, receiver: Receiver<'static, NoopRawMutex, LedState, 1>) { +async fn recv_task(led: Peri<'static, AnyPin>, receiver: Receiver<'static, NoopRawMutex, LedState, 1>) { let mut led = Output::new(led, Level::Low, OutputDrive::Standard); loop { @@ -45,5 +46,5 @@ async fn main(spawner: Spawner) { let channel = CHANNEL.init(Channel::new()); unwrap!(spawner.spawn(send_task(channel.sender()))); - unwrap!(spawner.spawn(recv_task(p.P0_13.degrade(), channel.receiver()))); + unwrap!(spawner.spawn(recv_task(p.P0_13.into(), channel.receiver()))); } diff --git a/examples/nrf52840/src/bin/pdm_continuous.rs b/examples/nrf52840/src/bin/pdm_continuous.rs index e948203a5..0d76636b0 100644 --- a/examples/nrf52840/src/bin/pdm_continuous.rs +++ b/examples/nrf52840/src/bin/pdm_continuous.rs @@ -20,14 +20,14 @@ bind_interrupts!(struct Irqs { #[embassy_executor::main] async fn main(_p: Spawner) { - let mut p = embassy_nrf::init(Default::default()); + let p = embassy_nrf::init(Default::default()); let mut config = Config::default(); // Pins are correct for the onboard microphone on the Feather nRF52840 Sense. config.frequency = Frequency::_1280K; // 16 kHz sample rate config.ratio = Ratio::RATIO80; config.operation_mode = OperationMode::Mono; config.gain_left = I7F1::from_bits(5); // 2.5 dB - let mut pdm = Pdm::new(p.PDM, Irqs, &mut p.P0_00, &mut p.P0_01, config); + let mut pdm = Pdm::new(p.PDM, Irqs, p.P0_00, p.P0_01, config); let mut bufs = [[0; 1024]; 2]; diff --git a/examples/nrf52840/src/bin/qspi_lowpower.rs b/examples/nrf52840/src/bin/qspi_lowpower.rs index 516c9b481..238a0d941 100644 --- a/examples/nrf52840/src/bin/qspi_lowpower.rs +++ b/examples/nrf52840/src/bin/qspi_lowpower.rs @@ -37,14 +37,14 @@ async fn main(_p: Spawner) { }); let mut q = qspi::Qspi::new( - &mut p.QSPI, + p.QSPI.reborrow(), Irqs, - &mut p.P0_19, - &mut p.P0_17, - &mut p.P0_20, - &mut p.P0_21, - &mut p.P0_22, - &mut p.P0_23, + p.P0_19.reborrow(), + p.P0_17.reborrow(), + p.P0_20.reborrow(), + p.P0_21.reborrow(), + p.P0_22.reborrow(), + p.P0_23.reborrow(), config, ); diff --git a/examples/nrf52840/src/bin/saadc.rs b/examples/nrf52840/src/bin/saadc.rs index 653b7d606..cf2d860ab 100644 --- a/examples/nrf52840/src/bin/saadc.rs +++ b/examples/nrf52840/src/bin/saadc.rs @@ -16,7 +16,7 @@ bind_interrupts!(struct Irqs { async fn main(_p: Spawner) { let mut p = embassy_nrf::init(Default::default()); let config = Config::default(); - let channel_config = ChannelConfig::single_ended(&mut p.P0_02); + let channel_config = ChannelConfig::single_ended(p.P0_02.reborrow()); let mut saadc = Saadc::new(p.SAADC, Irqs, config, [channel_config]); loop { diff --git a/examples/nrf52840/src/bin/saadc_continuous.rs b/examples/nrf52840/src/bin/saadc_continuous.rs index f76fa3570..e8f169c8c 100644 --- a/examples/nrf52840/src/bin/saadc_continuous.rs +++ b/examples/nrf52840/src/bin/saadc_continuous.rs @@ -18,9 +18,9 @@ bind_interrupts!(struct Irqs { async fn main(_p: Spawner) { let mut p = embassy_nrf::init(Default::default()); let config = Config::default(); - let channel_1_config = ChannelConfig::single_ended(&mut p.P0_02); - let channel_2_config = ChannelConfig::single_ended(&mut p.P0_03); - let channel_3_config = ChannelConfig::single_ended(&mut p.P0_04); + let channel_1_config = ChannelConfig::single_ended(p.P0_02.reborrow()); + let channel_2_config = ChannelConfig::single_ended(p.P0_03.reborrow()); + let channel_3_config = ChannelConfig::single_ended(p.P0_04.reborrow()); let mut saadc = Saadc::new( p.SAADC, Irqs, @@ -40,9 +40,9 @@ async fn main(_p: Spawner) { saadc .run_task_sampler( - &mut p.TIMER0, - &mut p.PPI_CH0, - &mut p.PPI_CH1, + p.TIMER0.reborrow(), + p.PPI_CH0.reborrow(), + p.PPI_CH1.reborrow(), Frequency::F1MHz, 1000, // We want to sample at 1KHz &mut bufs, diff --git a/examples/nrf52840/src/bin/twim_lowpower.rs b/examples/nrf52840/src/bin/twim_lowpower.rs index e2efbdd8d..8a6f958eb 100644 --- a/examples/nrf52840/src/bin/twim_lowpower.rs +++ b/examples/nrf52840/src/bin/twim_lowpower.rs @@ -32,7 +32,13 @@ async fn main(_p: Spawner) { let config = twim::Config::default(); // Create the TWIM instance with borrowed singletons, so they're not consumed. - let mut twi = Twim::new(&mut p.TWISPI0, Irqs, &mut p.P0_03, &mut p.P0_04, config); + let mut twi = Twim::new( + p.TWISPI0.reborrow(), + Irqs, + p.P0_03.reborrow(), + p.P0_04.reborrow(), + config, + ); info!("Reading..."); diff --git a/examples/nrf9160/src/bin/modem_tcp_client.rs b/examples/nrf9160/src/bin/modem_tcp_client.rs index 35900cdd8..2ba964b1f 100644 --- a/examples/nrf9160/src/bin/modem_tcp_client.rs +++ b/examples/nrf9160/src/bin/modem_tcp_client.rs @@ -13,9 +13,9 @@ use embassy_net::{Ipv4Cidr, Stack, StackResources}; use embassy_net_nrf91::context::Status; use embassy_net_nrf91::{context, Runner, State, TraceBuffer, TraceReader}; use embassy_nrf::buffered_uarte::{self, BufferedUarteTx}; -use embassy_nrf::gpio::{AnyPin, Level, Output, OutputDrive, Pin}; +use embassy_nrf::gpio::{AnyPin, Level, Output, OutputDrive}; use embassy_nrf::uarte::Baudrate; -use embassy_nrf::{bind_interrupts, interrupt, peripherals, uarte}; +use embassy_nrf::{bind_interrupts, interrupt, peripherals, uarte, Peri}; use embassy_time::{Duration, Timer}; use embedded_io_async::Write; use heapless::Vec; @@ -91,7 +91,7 @@ fn status_to_config(status: &Status) -> embassy_net::ConfigV4 { } #[embassy_executor::task] -async fn blink_task(pin: AnyPin) { +async fn blink_task(pin: Peri<'static, AnyPin>) { let mut led = Output::new(pin, Level::Low, OutputDrive::Standard); loop { led.set_high(); @@ -112,7 +112,7 @@ async fn main(spawner: Spawner) { info!("Hello World!"); - unwrap!(spawner.spawn(blink_task(p.P0_02.degrade()))); + unwrap!(spawner.spawn(blink_task(p.P0_02.into()))); let ipc_mem = unsafe { let ipc_start = &__start_ipc as *const u8 as *mut MaybeUninit; diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index cde804a15..4fc1d35d6 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml @@ -30,7 +30,7 @@ serde = { version = "1.0.203", default-features = false, features = ["derive"] } serde-json-core = "0.5.1" # for assign resources example -assign-resources = { git = "https://github.com/adamgreig/assign-resources", rev = "94ad10e2729afdf0fd5a77cd12e68409a982f58a" } +assign-resources = { git = "https://github.com/adamgreig/assign-resources", rev = "bd22cb7a92031fb16f74a5da42469d466c33383e" } #cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } cortex-m = { version = "0.7.6", features = ["inline-asm"] } diff --git a/examples/rp/src/bin/adc_dma.rs b/examples/rp/src/bin/adc_dma.rs index f755cf5bf..b42c13fde 100644 --- a/examples/rp/src/bin/adc_dma.rs +++ b/examples/rp/src/bin/adc_dma.rs @@ -38,13 +38,13 @@ async fn main(_spawner: Spawner) { // Read 100 samples from a single channel let mut buf = [0_u16; BLOCK_SIZE]; let div = 479; // 100kHz sample rate (48Mhz / 100kHz - 1) - adc.read_many(&mut pin, &mut buf, div, &mut dma).await.unwrap(); + adc.read_many(&mut pin, &mut buf, div, dma.reborrow()).await.unwrap(); info!("single: {:?} ...etc", buf[..8]); // Read 100 samples from 4 channels interleaved let mut buf = [0_u16; { BLOCK_SIZE * NUM_CHANNELS }]; let div = 119; // 100kHz sample rate (48Mhz / 100kHz * 4ch - 1) - adc.read_many_multichannel(&mut pins, &mut buf, div, &mut dma) + adc.read_many_multichannel(&mut pins, &mut buf, div, dma.reborrow()) .await .unwrap(); info!("multi: {:?} ...etc", buf[..NUM_CHANNELS * 2]); diff --git a/examples/rp/src/bin/assign_resources.rs b/examples/rp/src/bin/assign_resources.rs index ff6eff4a2..341f54d22 100644 --- a/examples/rp/src/bin/assign_resources.rs +++ b/examples/rp/src/bin/assign_resources.rs @@ -16,6 +16,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_rp::gpio::{Level, Output}; use embassy_rp::peripherals::{self, PIN_20, PIN_21}; +use embassy_rp::Peri; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; @@ -38,7 +39,11 @@ async fn main(spawner: Spawner) { // 1) Assigning a resource to a task by passing parts of the peripherals. #[embassy_executor::task] -async fn double_blinky_manually_assigned(_spawner: Spawner, pin_20: PIN_20, pin_21: PIN_21) { +async fn double_blinky_manually_assigned( + _spawner: Spawner, + pin_20: Peri<'static, PIN_20>, + pin_21: Peri<'static, PIN_21>, +) { let mut led_20 = Output::new(pin_20, Level::Low); let mut led_21 = Output::new(pin_21, Level::High); diff --git a/examples/rp/src/bin/blinky_two_channels.rs b/examples/rp/src/bin/blinky_two_channels.rs index b2eec2a21..51e139e94 100644 --- a/examples/rp/src/bin/blinky_two_channels.rs +++ b/examples/rp/src/bin/blinky_two_channels.rs @@ -11,7 +11,7 @@ use embassy_rp::gpio; use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; use embassy_sync::channel::{Channel, Sender}; use embassy_time::{Duration, Ticker}; -use gpio::{AnyPin, Level, Output}; +use gpio::{Level, Output}; use {defmt_rtt as _, panic_probe as _}; enum LedState { @@ -22,7 +22,7 @@ static CHANNEL: Channel = Channel::new(); #[embassy_executor::main] async fn main(spawner: Spawner) { let p = embassy_rp::init(Default::default()); - let mut led = Output::new(AnyPin::from(p.PIN_25), Level::High); + let mut led = Output::new(p.PIN_25, Level::High); let dt = 100 * 1_000_000; let k = 1.003; diff --git a/examples/rp/src/bin/blinky_two_tasks.rs b/examples/rp/src/bin/blinky_two_tasks.rs index a57b513d6..67a9108c0 100644 --- a/examples/rp/src/bin/blinky_two_tasks.rs +++ b/examples/rp/src/bin/blinky_two_tasks.rs @@ -11,7 +11,7 @@ use embassy_rp::gpio; use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; use embassy_sync::mutex::Mutex; use embassy_time::{Duration, Ticker}; -use gpio::{AnyPin, Level, Output}; +use gpio::{Level, Output}; use {defmt_rtt as _, panic_probe as _}; type LedType = Mutex>>; @@ -21,7 +21,7 @@ static LED: LedType = Mutex::new(None); async fn main(spawner: Spawner) { let p = embassy_rp::init(Default::default()); // set the content of the global LED reference to the real LED pin - let led = Output::new(AnyPin::from(p.PIN_25), Level::High); + let led = Output::new(p.PIN_25, Level::High); // inner scope is so that once the mutex is written to, the MutexGuard is dropped, thus the // Mutex is released { diff --git a/examples/rp/src/bin/orchestrate_tasks.rs b/examples/rp/src/bin/orchestrate_tasks.rs index 7ff004860..5e2775793 100644 --- a/examples/rp/src/bin/orchestrate_tasks.rs +++ b/examples/rp/src/bin/orchestrate_tasks.rs @@ -24,7 +24,7 @@ use embassy_futures::select::{select, Either}; use embassy_rp::adc::{Adc, Channel, Config, InterruptHandler}; use embassy_rp::clocks::RoscRng; use embassy_rp::gpio::{Input, Pull}; -use embassy_rp::{bind_interrupts, peripherals}; +use embassy_rp::{bind_interrupts, peripherals, Peri}; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::mutex::Mutex; use embassy_sync::{channel, signal}; diff --git a/examples/rp/src/bin/pio_async.rs b/examples/rp/src/bin/pio_async.rs index 08c702347..bf6dbee69 100644 --- a/examples/rp/src/bin/pio_async.rs +++ b/examples/rp/src/bin/pio_async.rs @@ -4,10 +4,10 @@ #![no_main] use defmt::info; use embassy_executor::Spawner; -use embassy_rp::bind_interrupts; use embassy_rp::peripherals::PIO0; use embassy_rp::pio::program::pio_asm; use embassy_rp::pio::{Common, Config, InterruptHandler, Irq, Pio, PioPin, ShiftDirection, StateMachine}; +use embassy_rp::{bind_interrupts, Peri}; use fixed::traits::ToFixed; use fixed_macro::types::U56F8; use {defmt_rtt as _, panic_probe as _}; @@ -16,7 +16,7 @@ bind_interrupts!(struct Irqs { PIO0_IRQ_0 => InterruptHandler; }); -fn setup_pio_task_sm0<'a>(pio: &mut Common<'a, PIO0>, sm: &mut StateMachine<'a, PIO0, 0>, pin: impl PioPin) { +fn setup_pio_task_sm0<'d>(pio: &mut Common<'d, PIO0>, sm: &mut StateMachine<'d, PIO0, 0>, pin: Peri<'d, impl PioPin>) { // Setup sm0 // Send data serially to pin @@ -50,7 +50,7 @@ async fn pio_task_sm0(mut sm: StateMachine<'static, PIO0, 0>) { } } -fn setup_pio_task_sm1<'a>(pio: &mut Common<'a, PIO0>, sm: &mut StateMachine<'a, PIO0, 1>) { +fn setup_pio_task_sm1<'d>(pio: &mut Common<'d, PIO0>, sm: &mut StateMachine<'d, PIO0, 1>) { // Setupm sm1 // Read 0b10101 repeatedly until ISR is full @@ -80,7 +80,7 @@ async fn pio_task_sm1(mut sm: StateMachine<'static, PIO0, 1>) { } } -fn setup_pio_task_sm2<'a>(pio: &mut Common<'a, PIO0>, sm: &mut StateMachine<'a, PIO0, 2>) { +fn setup_pio_task_sm2<'d>(pio: &mut Common<'d, PIO0>, sm: &mut StateMachine<'d, PIO0, 2>) { // Setup sm2 // Repeatedly trigger IRQ 3 diff --git a/examples/rp/src/bin/pio_dma.rs b/examples/rp/src/bin/pio_dma.rs index da6e47a1b..64d603ba4 100644 --- a/examples/rp/src/bin/pio_dma.rs +++ b/examples/rp/src/bin/pio_dma.rs @@ -5,10 +5,10 @@ use defmt::info; use embassy_executor::Spawner; use embassy_futures::join::join; +use embassy_rp::bind_interrupts; use embassy_rp::peripherals::PIO0; use embassy_rp::pio::program::pio_asm; use embassy_rp::pio::{Config, InterruptHandler, Pio, ShiftConfig, ShiftDirection}; -use embassy_rp::{bind_interrupts, Peripheral}; use fixed::traits::ToFixed; use fixed_macro::types::U56F8; use {defmt_rtt as _, panic_probe as _}; @@ -62,8 +62,8 @@ async fn main(_spawner: Spawner) { sm.set_config(&cfg); sm.set_enable(true); - let mut dma_out_ref = p.DMA_CH0.into_ref(); - let mut dma_in_ref = p.DMA_CH1.into_ref(); + let mut dma_out_ref = p.DMA_CH0; + let mut dma_in_ref = p.DMA_CH1; let mut dout = [0x12345678u32; 29]; for i in 1..dout.len() { dout[i] = (dout[i - 1] & 0x0fff_ffff) * 13 + 7; diff --git a/examples/rp/src/bin/pio_i2s.rs b/examples/rp/src/bin/pio_i2s.rs index 447100ddf..192c8f854 100644 --- a/examples/rp/src/bin/pio_i2s.rs +++ b/examples/rp/src/bin/pio_i2s.rs @@ -14,6 +14,7 @@ use core::mem; use embassy_executor::Spawner; use embassy_rp::bind_interrupts; +use embassy_rp::bootsel::is_bootsel_pressed; use embassy_rp::peripherals::PIO0; use embassy_rp::pio::{InterruptHandler, Pio}; use embassy_rp::pio_programs::i2s::{PioI2sOut, PioI2sOutProgram}; @@ -70,7 +71,11 @@ async fn main(_spawner: Spawner) { let dma_future = i2s.write(front_buffer); // fade in audio when bootsel is pressed - let fade_target = if p.BOOTSEL.is_pressed() { i32::MAX } else { 0 }; + let fade_target = if is_bootsel_pressed(p.BOOTSEL.reborrow()) { + i32::MAX + } else { + 0 + }; // fill back buffer with fresh audio samples before awaiting the dma future for s in back_buffer.iter_mut() { diff --git a/examples/rp/src/bin/pwm.rs b/examples/rp/src/bin/pwm.rs index 2f5f94870..04374323d 100644 --- a/examples/rp/src/bin/pwm.rs +++ b/examples/rp/src/bin/pwm.rs @@ -11,6 +11,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_rp::peripherals::{PIN_25, PIN_4, PWM_SLICE2, PWM_SLICE4}; use embassy_rp::pwm::{Config, Pwm, SetDutyCycle}; +use embassy_rp::Peri; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; @@ -26,7 +27,7 @@ async fn main(spawner: Spawner) { /// Using the onboard led, if You are using a different Board than plain Pico2 (i.e. W variant) /// you must use another slice & pin and an appropriate resistor. #[embassy_executor::task] -async fn pwm_set_config(slice4: PWM_SLICE4, pin25: PIN_25) { +async fn pwm_set_config(slice4: Peri<'static, PWM_SLICE4>, pin25: Peri<'static, PIN_25>) { let mut c = Config::default(); c.top = 32_768; c.compare_b = 8; @@ -44,7 +45,7 @@ async fn pwm_set_config(slice4: PWM_SLICE4, pin25: PIN_25) { /// /// Using GP4 in Slice2, make sure to use an appropriate resistor. #[embassy_executor::task] -async fn pwm_set_dutycycle(slice2: PWM_SLICE2, pin4: PIN_4) { +async fn pwm_set_dutycycle(slice2: Peri<'static, PWM_SLICE2>, pin4: Peri<'static, PIN_4>) { // If we aim for a specific frequency, here is how we can calculate the top value. // The top value sets the period of the PWM cycle, so a counter goes from 0 to top and then wraps around to 0. // Every such wraparound is one PWM cycle. So here is how we get 25KHz: diff --git a/examples/rp/src/bin/shared_bus.rs b/examples/rp/src/bin/shared_bus.rs index c6cb5d64c..9267dfccb 100644 --- a/examples/rp/src/bin/shared_bus.rs +++ b/examples/rp/src/bin/shared_bus.rs @@ -8,7 +8,7 @@ use embassy_embedded_hal::shared_bus::asynch::i2c::I2cDevice; use embassy_embedded_hal::shared_bus::asynch::spi::SpiDevice; use embassy_executor::Spawner; use embassy_rp::bind_interrupts; -use embassy_rp::gpio::{AnyPin, Level, Output}; +use embassy_rp::gpio::{Level, Output}; use embassy_rp::i2c::{self, I2c, InterruptHandler}; use embassy_rp::peripherals::{I2C1, SPI1}; use embassy_rp::spi::{self, Spi}; @@ -45,8 +45,8 @@ async fn main(spawner: Spawner) { let spi_bus = SPI_BUS.init(Mutex::new(spi)); // Chip select pins for the SPI devices - let cs_a = Output::new(AnyPin::from(p.PIN_0), Level::High); - let cs_b = Output::new(AnyPin::from(p.PIN_1), Level::High); + let cs_a = Output::new(p.PIN_0, Level::High); + let cs_b = Output::new(p.PIN_1, Level::High); spawner.must_spawn(spi_task_a(spi_bus, cs_a)); spawner.must_spawn(spi_task_b(spi_bus, cs_b)); diff --git a/examples/rp/src/bin/zerocopy.rs b/examples/rp/src/bin/zerocopy.rs index 39f03c8e4..d1fb0eb00 100644 --- a/examples/rp/src/bin/zerocopy.rs +++ b/examples/rp/src/bin/zerocopy.rs @@ -9,9 +9,9 @@ use core::sync::atomic::{AtomicU16, Ordering}; use defmt::*; use embassy_executor::Spawner; use embassy_rp::adc::{self, Adc, Async, Config, InterruptHandler}; -use embassy_rp::bind_interrupts; use embassy_rp::gpio::Pull; use embassy_rp::peripherals::DMA_CH0; +use embassy_rp::{bind_interrupts, Peri}; use embassy_sync::blocking_mutex::raw::NoopRawMutex; use embassy_sync::zerocopy_channel::{Channel, Receiver, Sender}; use embassy_time::{Duration, Ticker, Timer}; @@ -31,7 +31,7 @@ static MAX: AtomicU16 = AtomicU16::new(0); struct AdcParts { adc: Adc<'static, Async>, pin: adc::Channel<'static>, - dma: DMA_CH0, + dma: Peri<'static, DMA_CH0>, } #[embassy_executor::main] @@ -70,7 +70,10 @@ async fn producer(mut sender: Sender<'static, NoopRawMutex, SampleBuffer>, mut a let buf = sender.send().await; // Fill it with data - adc.adc.read_many(&mut adc.pin, buf, 1, &mut adc.dma).await.unwrap(); + adc.adc + .read_many(&mut adc.pin, buf, 1, adc.dma.reborrow()) + .await + .unwrap(); // Notify the channel that the buffer is now ready to be received sender.send_done(); diff --git a/examples/rp235x/Cargo.toml b/examples/rp235x/Cargo.toml index 4e9c93e7c..c9e0ee120 100644 --- a/examples/rp235x/Cargo.toml +++ b/examples/rp235x/Cargo.toml @@ -28,7 +28,7 @@ serde = { version = "1.0.203", default-features = false, features = ["derive"] } serde-json-core = "0.5.1" # for assign resources example -assign-resources = { git = "https://github.com/adamgreig/assign-resources", rev = "94ad10e2729afdf0fd5a77cd12e68409a982f58a" } +assign-resources = { git = "https://github.com/adamgreig/assign-resources", rev = "bd22cb7a92031fb16f74a5da42469d466c33383e" } # for TB6612FNG example tb6612fng = "1.0.0" diff --git a/examples/rp235x/src/bin/adc_dma.rs b/examples/rp235x/src/bin/adc_dma.rs index f755cf5bf..b42c13fde 100644 --- a/examples/rp235x/src/bin/adc_dma.rs +++ b/examples/rp235x/src/bin/adc_dma.rs @@ -38,13 +38,13 @@ async fn main(_spawner: Spawner) { // Read 100 samples from a single channel let mut buf = [0_u16; BLOCK_SIZE]; let div = 479; // 100kHz sample rate (48Mhz / 100kHz - 1) - adc.read_many(&mut pin, &mut buf, div, &mut dma).await.unwrap(); + adc.read_many(&mut pin, &mut buf, div, dma.reborrow()).await.unwrap(); info!("single: {:?} ...etc", buf[..8]); // Read 100 samples from 4 channels interleaved let mut buf = [0_u16; { BLOCK_SIZE * NUM_CHANNELS }]; let div = 119; // 100kHz sample rate (48Mhz / 100kHz * 4ch - 1) - adc.read_many_multichannel(&mut pins, &mut buf, div, &mut dma) + adc.read_many_multichannel(&mut pins, &mut buf, div, dma.reborrow()) .await .unwrap(); info!("multi: {:?} ...etc", buf[..NUM_CHANNELS * 2]); diff --git a/examples/rp235x/src/bin/assign_resources.rs b/examples/rp235x/src/bin/assign_resources.rs index ff6eff4a2..341f54d22 100644 --- a/examples/rp235x/src/bin/assign_resources.rs +++ b/examples/rp235x/src/bin/assign_resources.rs @@ -16,6 +16,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_rp::gpio::{Level, Output}; use embassy_rp::peripherals::{self, PIN_20, PIN_21}; +use embassy_rp::Peri; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; @@ -38,7 +39,11 @@ async fn main(spawner: Spawner) { // 1) Assigning a resource to a task by passing parts of the peripherals. #[embassy_executor::task] -async fn double_blinky_manually_assigned(_spawner: Spawner, pin_20: PIN_20, pin_21: PIN_21) { +async fn double_blinky_manually_assigned( + _spawner: Spawner, + pin_20: Peri<'static, PIN_20>, + pin_21: Peri<'static, PIN_21>, +) { let mut led_20 = Output::new(pin_20, Level::Low); let mut led_21 = Output::new(pin_21, Level::High); diff --git a/examples/rp235x/src/bin/blinky_two_channels.rs b/examples/rp235x/src/bin/blinky_two_channels.rs index b2eec2a21..51e139e94 100644 --- a/examples/rp235x/src/bin/blinky_two_channels.rs +++ b/examples/rp235x/src/bin/blinky_two_channels.rs @@ -11,7 +11,7 @@ use embassy_rp::gpio; use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; use embassy_sync::channel::{Channel, Sender}; use embassy_time::{Duration, Ticker}; -use gpio::{AnyPin, Level, Output}; +use gpio::{Level, Output}; use {defmt_rtt as _, panic_probe as _}; enum LedState { @@ -22,7 +22,7 @@ static CHANNEL: Channel = Channel::new(); #[embassy_executor::main] async fn main(spawner: Spawner) { let p = embassy_rp::init(Default::default()); - let mut led = Output::new(AnyPin::from(p.PIN_25), Level::High); + let mut led = Output::new(p.PIN_25, Level::High); let dt = 100 * 1_000_000; let k = 1.003; diff --git a/examples/rp235x/src/bin/blinky_two_tasks.rs b/examples/rp235x/src/bin/blinky_two_tasks.rs index a57b513d6..67a9108c0 100644 --- a/examples/rp235x/src/bin/blinky_two_tasks.rs +++ b/examples/rp235x/src/bin/blinky_two_tasks.rs @@ -11,7 +11,7 @@ use embassy_rp::gpio; use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; use embassy_sync::mutex::Mutex; use embassy_time::{Duration, Ticker}; -use gpio::{AnyPin, Level, Output}; +use gpio::{Level, Output}; use {defmt_rtt as _, panic_probe as _}; type LedType = Mutex>>; @@ -21,7 +21,7 @@ static LED: LedType = Mutex::new(None); async fn main(spawner: Spawner) { let p = embassy_rp::init(Default::default()); // set the content of the global LED reference to the real LED pin - let led = Output::new(AnyPin::from(p.PIN_25), Level::High); + let led = Output::new(p.PIN_25, Level::High); // inner scope is so that once the mutex is written to, the MutexGuard is dropped, thus the // Mutex is released { diff --git a/examples/rp235x/src/bin/pio_async.rs b/examples/rp235x/src/bin/pio_async.rs index 08c702347..baf567b58 100644 --- a/examples/rp235x/src/bin/pio_async.rs +++ b/examples/rp235x/src/bin/pio_async.rs @@ -4,10 +4,10 @@ #![no_main] use defmt::info; use embassy_executor::Spawner; -use embassy_rp::bind_interrupts; use embassy_rp::peripherals::PIO0; use embassy_rp::pio::program::pio_asm; use embassy_rp::pio::{Common, Config, InterruptHandler, Irq, Pio, PioPin, ShiftDirection, StateMachine}; +use embassy_rp::{bind_interrupts, Peri}; use fixed::traits::ToFixed; use fixed_macro::types::U56F8; use {defmt_rtt as _, panic_probe as _}; @@ -16,7 +16,7 @@ bind_interrupts!(struct Irqs { PIO0_IRQ_0 => InterruptHandler; }); -fn setup_pio_task_sm0<'a>(pio: &mut Common<'a, PIO0>, sm: &mut StateMachine<'a, PIO0, 0>, pin: impl PioPin) { +fn setup_pio_task_sm0<'a>(pio: &mut Common<'a, PIO0>, sm: &mut StateMachine<'a, PIO0, 0>, pin: Peri<'a, impl PioPin>) { // Setup sm0 // Send data serially to pin diff --git a/examples/rp235x/src/bin/pio_dma.rs b/examples/rp235x/src/bin/pio_dma.rs index da6e47a1b..64d603ba4 100644 --- a/examples/rp235x/src/bin/pio_dma.rs +++ b/examples/rp235x/src/bin/pio_dma.rs @@ -5,10 +5,10 @@ use defmt::info; use embassy_executor::Spawner; use embassy_futures::join::join; +use embassy_rp::bind_interrupts; use embassy_rp::peripherals::PIO0; use embassy_rp::pio::program::pio_asm; use embassy_rp::pio::{Config, InterruptHandler, Pio, ShiftConfig, ShiftDirection}; -use embassy_rp::{bind_interrupts, Peripheral}; use fixed::traits::ToFixed; use fixed_macro::types::U56F8; use {defmt_rtt as _, panic_probe as _}; @@ -62,8 +62,8 @@ async fn main(_spawner: Spawner) { sm.set_config(&cfg); sm.set_enable(true); - let mut dma_out_ref = p.DMA_CH0.into_ref(); - let mut dma_in_ref = p.DMA_CH1.into_ref(); + let mut dma_out_ref = p.DMA_CH0; + let mut dma_in_ref = p.DMA_CH1; let mut dout = [0x12345678u32; 29]; for i in 1..dout.len() { dout[i] = (dout[i - 1] & 0x0fff_ffff) * 13 + 7; diff --git a/examples/rp235x/src/bin/pio_rotary_encoder_rxf.rs b/examples/rp235x/src/bin/pio_rotary_encoder_rxf.rs index 0216c131b..ccc601661 100644 --- a/examples/rp235x/src/bin/pio_rotary_encoder_rxf.rs +++ b/examples/rp235x/src/bin/pio_rotary_encoder_rxf.rs @@ -9,7 +9,7 @@ use embassy_executor::Spawner; use embassy_rp::gpio::Pull; use embassy_rp::peripherals::PIO0; use embassy_rp::pio::program::pio_asm; -use embassy_rp::{bind_interrupts, pio}; +use embassy_rp::{bind_interrupts, pio, Peri}; use embassy_time::Timer; use fixed::traits::ToFixed; use pio::{Common, Config, FifoJoin, Instance, InterruptHandler, Pio, PioPin, ShiftDirection, StateMachine}; @@ -37,8 +37,8 @@ impl<'d, T: Instance, const SM: usize> PioEncoder<'d, T, SM> { pub fn new( pio: &mut Common<'d, T>, mut sm: StateMachine<'d, T, SM>, - pin_a: impl PioPin, - pin_b: impl PioPin, + pin_a: Peri<'d, impl PioPin>, + pin_b: Peri<'d, impl PioPin>, ) -> Self { let mut pin_a = pio.make_pio_pin(pin_a); let mut pin_b = pio.make_pio_pin(pin_b); diff --git a/examples/rp235x/src/bin/pwm.rs b/examples/rp235x/src/bin/pwm.rs index a3c0f7e49..da1acc18a 100644 --- a/examples/rp235x/src/bin/pwm.rs +++ b/examples/rp235x/src/bin/pwm.rs @@ -11,6 +11,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_rp::peripherals::{PIN_25, PIN_4, PWM_SLICE2, PWM_SLICE4}; use embassy_rp::pwm::{Config, Pwm, SetDutyCycle}; +use embassy_rp::Peri; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; @@ -26,7 +27,7 @@ async fn main(spawner: Spawner) { /// Using the onboard led, if You are using a different Board than plain Pico2 (i.e. W variant) /// you must use another slice & pin and an appropriate resistor. #[embassy_executor::task] -async fn pwm_set_config(slice4: PWM_SLICE4, pin25: PIN_25) { +async fn pwm_set_config(slice4: Peri<'static, PWM_SLICE4>, pin25: Peri<'static, PIN_25>) { let mut c = Config::default(); c.top = 32_768; c.compare_b = 8; @@ -44,7 +45,7 @@ async fn pwm_set_config(slice4: PWM_SLICE4, pin25: PIN_25) { /// /// Using GP4 in Slice2, make sure to use an appropriate resistor. #[embassy_executor::task] -async fn pwm_set_dutycycle(slice2: PWM_SLICE2, pin4: PIN_4) { +async fn pwm_set_dutycycle(slice2: Peri<'static, PWM_SLICE2>, pin4: Peri<'static, PIN_4>) { // If we aim for a specific frequency, here is how we can calculate the top value. // The top value sets the period of the PWM cycle, so a counter goes from 0 to top and then wraps around to 0. // Every such wraparound is one PWM cycle. So here is how we get 25KHz: diff --git a/examples/rp235x/src/bin/pwm_tb6612fng_motor_driver.rs b/examples/rp235x/src/bin/pwm_tb6612fng_motor_driver.rs index 3b700884c..2cfb2038d 100644 --- a/examples/rp235x/src/bin/pwm_tb6612fng_motor_driver.rs +++ b/examples/rp235x/src/bin/pwm_tb6612fng_motor_driver.rs @@ -10,7 +10,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_rp::config::Config; use embassy_rp::gpio::Output; -use embassy_rp::{gpio, peripherals, pwm}; +use embassy_rp::{gpio, peripherals, pwm, Peri}; use embassy_time::{Duration, Timer}; use tb6612fng::{DriveCommand, Motor, Tb6612fng}; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/rp235x/src/bin/shared_bus.rs b/examples/rp235x/src/bin/shared_bus.rs index c6cb5d64c..9267dfccb 100644 --- a/examples/rp235x/src/bin/shared_bus.rs +++ b/examples/rp235x/src/bin/shared_bus.rs @@ -8,7 +8,7 @@ use embassy_embedded_hal::shared_bus::asynch::i2c::I2cDevice; use embassy_embedded_hal::shared_bus::asynch::spi::SpiDevice; use embassy_executor::Spawner; use embassy_rp::bind_interrupts; -use embassy_rp::gpio::{AnyPin, Level, Output}; +use embassy_rp::gpio::{Level, Output}; use embassy_rp::i2c::{self, I2c, InterruptHandler}; use embassy_rp::peripherals::{I2C1, SPI1}; use embassy_rp::spi::{self, Spi}; @@ -45,8 +45,8 @@ async fn main(spawner: Spawner) { let spi_bus = SPI_BUS.init(Mutex::new(spi)); // Chip select pins for the SPI devices - let cs_a = Output::new(AnyPin::from(p.PIN_0), Level::High); - let cs_b = Output::new(AnyPin::from(p.PIN_1), Level::High); + let cs_a = Output::new(p.PIN_0, Level::High); + let cs_b = Output::new(p.PIN_1, Level::High); spawner.must_spawn(spi_task_a(spi_bus, cs_a)); spawner.must_spawn(spi_task_b(spi_bus, cs_b)); diff --git a/examples/rp235x/src/bin/zerocopy.rs b/examples/rp235x/src/bin/zerocopy.rs index 39f03c8e4..d1fb0eb00 100644 --- a/examples/rp235x/src/bin/zerocopy.rs +++ b/examples/rp235x/src/bin/zerocopy.rs @@ -9,9 +9,9 @@ use core::sync::atomic::{AtomicU16, Ordering}; use defmt::*; use embassy_executor::Spawner; use embassy_rp::adc::{self, Adc, Async, Config, InterruptHandler}; -use embassy_rp::bind_interrupts; use embassy_rp::gpio::Pull; use embassy_rp::peripherals::DMA_CH0; +use embassy_rp::{bind_interrupts, Peri}; use embassy_sync::blocking_mutex::raw::NoopRawMutex; use embassy_sync::zerocopy_channel::{Channel, Receiver, Sender}; use embassy_time::{Duration, Ticker, Timer}; @@ -31,7 +31,7 @@ static MAX: AtomicU16 = AtomicU16::new(0); struct AdcParts { adc: Adc<'static, Async>, pin: adc::Channel<'static>, - dma: DMA_CH0, + dma: Peri<'static, DMA_CH0>, } #[embassy_executor::main] @@ -70,7 +70,10 @@ async fn producer(mut sender: Sender<'static, NoopRawMutex, SampleBuffer>, mut a let buf = sender.send().await; // Fill it with data - adc.adc.read_many(&mut adc.pin, buf, 1, &mut adc.dma).await.unwrap(); + adc.adc + .read_many(&mut adc.pin, buf, 1, adc.dma.reborrow()) + .await + .unwrap(); // Notify the channel that the buffer is now ready to be received sender.send_done(); diff --git a/examples/stm32c0/src/bin/adc.rs b/examples/stm32c0/src/bin/adc.rs index 10481f4d2..1f54b0b18 100644 --- a/examples/stm32c0/src/bin/adc.rs +++ b/examples/stm32c0/src/bin/adc.rs @@ -36,7 +36,8 @@ async fn main(_spawner: Spawner) { ); let channels_seqence: [&mut AnyAdcChannel; 3] = [&mut vref, &mut temp, &mut pin0]; - adc.read(&mut dma, channels_seqence.into_iter(), &mut read_buffer).await; + adc.read(dma.reborrow(), channels_seqence.into_iter(), &mut read_buffer) + .await; // Values are ordered according to hardware ADC channel number! info!( "DMA ADC read in set: vref = {}, temp = {}, pin0 = {}.", @@ -45,7 +46,7 @@ async fn main(_spawner: Spawner) { let hw_channel_selection: u32 = (1 << temp.get_hw_channel()) + (1 << vref.get_hw_channel()) + (1 << pin0.get_hw_channel()); - adc.read_in_hw_order(&mut dma, hw_channel_selection, Scandir::UP, &mut read_buffer) + adc.read_in_hw_order(dma.reborrow(), hw_channel_selection, Scandir::UP, &mut read_buffer) .await; info!( "DMA ADC read in hardware order: vref = {}, temp = {}, pin0 = {}.", diff --git a/examples/stm32f0/src/bin/button_controlled_blink.rs b/examples/stm32f0/src/bin/button_controlled_blink.rs index 4465483d9..744df3e3b 100644 --- a/examples/stm32f0/src/bin/button_controlled_blink.rs +++ b/examples/stm32f0/src/bin/button_controlled_blink.rs @@ -8,14 +8,15 @@ use core::sync::atomic::{AtomicU32, Ordering}; use defmt::info; use embassy_executor::Spawner; use embassy_stm32::exti::ExtiInput; -use embassy_stm32::gpio::{AnyPin, Level, Output, Pin, Pull, Speed}; +use embassy_stm32::gpio::{AnyPin, Level, Output, Pull, Speed}; +use embassy_stm32::Peri; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; static BLINK_MS: AtomicU32 = AtomicU32::new(0); #[embassy_executor::task] -async fn led_task(led: AnyPin) { +async fn led_task(led: Peri<'static, AnyPin>) { // Configure the LED pin as a push pull output and obtain handler. // On the Nucleo F091RC there's an on-board LED connected to pin PA5. let mut led = Output::new(led, Level::Low, Speed::Low); @@ -45,7 +46,7 @@ async fn main(spawner: Spawner) { BLINK_MS.store(del_var, Ordering::Relaxed); // Spawn LED blinking task - spawner.spawn(led_task(p.PA5.degrade())).unwrap(); + spawner.spawn(led_task(p.PA5.into())).unwrap(); loop { // Check if button got pressed diff --git a/examples/stm32f1/src/bin/input_capture.rs b/examples/stm32f1/src/bin/input_capture.rs index 5e2dab9e6..6fe8e0b50 100644 --- a/examples/stm32f1/src/bin/input_capture.rs +++ b/examples/stm32f1/src/bin/input_capture.rs @@ -7,14 +7,14 @@ use embassy_stm32::gpio::{Level, Output, Pull, Speed}; use embassy_stm32::time::khz; use embassy_stm32::timer::input_capture::{CapturePin, InputCapture}; use embassy_stm32::timer::{self, Channel}; -use embassy_stm32::{bind_interrupts, peripherals}; +use embassy_stm32::{bind_interrupts, peripherals, Peri}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; /// Connect PA2 and PC13 with a 1k Ohm resistor #[embassy_executor::task] -async fn blinky(led: peripherals::PC13) { +async fn blinky(led: Peri<'static, peripherals::PC13>) { let mut led = Output::new(led, Level::High, Speed::Low); loop { diff --git a/examples/stm32f1/src/bin/pwm_input.rs b/examples/stm32f1/src/bin/pwm_input.rs index f74853d4e..afbef3edb 100644 --- a/examples/stm32f1/src/bin/pwm_input.rs +++ b/examples/stm32f1/src/bin/pwm_input.rs @@ -6,14 +6,14 @@ use embassy_executor::Spawner; use embassy_stm32::gpio::{Level, Output, Pull, Speed}; use embassy_stm32::time::khz; use embassy_stm32::timer::pwm_input::PwmInput; -use embassy_stm32::{bind_interrupts, peripherals, timer}; +use embassy_stm32::{bind_interrupts, peripherals, timer, Peri}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; /// Connect PA0 and PC13 with a 1k Ohm resistor #[embassy_executor::task] -async fn blinky(led: peripherals::PC13) { +async fn blinky(led: Peri<'static, peripherals::PC13>) { let mut led = Output::new(led, Level::High, Speed::Low); loop { diff --git a/examples/stm32f1/src/bin/usb_serial.rs b/examples/stm32f1/src/bin/usb_serial.rs index ee99acf41..77ec307b9 100644 --- a/examples/stm32f1/src/bin/usb_serial.rs +++ b/examples/stm32f1/src/bin/usb_serial.rs @@ -47,7 +47,7 @@ async fn main(_spawner: Spawner) { // Pull the D+ pin down to send a RESET condition to the USB bus. // This forced reset is needed only for development, without it host // will not reset your device when you upload new firmware. - let _dp = Output::new(&mut p.PA12, Level::Low, Speed::Low); + let _dp = Output::new(p.PA12.reborrow(), Level::Low, Speed::Low); Timer::after_millis(10).await; } diff --git a/examples/stm32f334/src/bin/opamp.rs b/examples/stm32f334/src/bin/opamp.rs index 2dbf1bdab..b30445ead 100644 --- a/examples/stm32f334/src/bin/opamp.rs +++ b/examples/stm32f334/src/bin/opamp.rs @@ -48,7 +48,7 @@ async fn main(_spawner: Spawner) -> ! { let mut vrefint = adc.enable_vref(); let mut temperature = adc.enable_temperature(); - let mut buffer = opamp.buffer_ext(&mut p.PA7, &mut p.PA6, OpAmpGain::Mul1); + let mut buffer = opamp.buffer_ext(p.PA7.reborrow(), p.PA6.reborrow(), OpAmpGain::Mul1); loop { let vref = adc.read(&mut vrefint).await; diff --git a/examples/stm32f4/src/bin/can.rs b/examples/stm32f4/src/bin/can.rs index 8e3beee24..fd90e0d6d 100644 --- a/examples/stm32f4/src/bin/can.rs +++ b/examples/stm32f4/src/bin/can.rs @@ -30,7 +30,7 @@ async fn main(_spawner: Spawner) { // To synchronise to the bus the RX input needs to see a high level. // Use `mem::forget()` to release the borrow on the pin but keep the // pull-up resistor enabled. - let rx_pin = Input::new(&mut p.PA11, Pull::Up); + let rx_pin = Input::new(p.PA11.reborrow(), Pull::Up); core::mem::forget(rx_pin); let mut can = Can::new(p.CAN1, p.PA11, p.PA12, Irqs); diff --git a/examples/stm32f4/src/bin/flash_async.rs b/examples/stm32f4/src/bin/flash_async.rs index 493a536f3..755713542 100644 --- a/examples/stm32f4/src/bin/flash_async.rs +++ b/examples/stm32f4/src/bin/flash_async.rs @@ -3,9 +3,9 @@ use defmt::{info, unwrap}; use embassy_executor::Spawner; -use embassy_stm32::bind_interrupts; use embassy_stm32::flash::{Flash, InterruptHandler}; -use embassy_stm32::gpio::{AnyPin, Level, Output, Pin, Speed}; +use embassy_stm32::gpio::{AnyPin, Level, Output, Speed}; +use embassy_stm32::{bind_interrupts, Peri}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; @@ -21,14 +21,14 @@ async fn main(spawner: Spawner) { let mut f = Flash::new(p.FLASH, Irqs); // Led should blink uninterrupted during ~2sec erase operation - spawner.spawn(blinky(p.PB7.degrade())).unwrap(); + spawner.spawn(blinky(p.PB7.into())).unwrap(); // Test on bank 2 in order not to stall CPU. test_flash(&mut f, 1024 * 1024, 128 * 1024).await; } #[embassy_executor::task] -async fn blinky(p: AnyPin) { +async fn blinky(p: Peri<'static, AnyPin>) { let mut led = Output::new(p, Level::High, Speed::Low); loop { diff --git a/examples/stm32f4/src/bin/input_capture.rs b/examples/stm32f4/src/bin/input_capture.rs index 49de33d2b..fe5e2bdfc 100644 --- a/examples/stm32f4/src/bin/input_capture.rs +++ b/examples/stm32f4/src/bin/input_capture.rs @@ -7,14 +7,14 @@ use embassy_stm32::gpio::{Level, Output, Pull, Speed}; use embassy_stm32::time::khz; use embassy_stm32::timer::input_capture::{CapturePin, InputCapture}; use embassy_stm32::timer::{self, Channel}; -use embassy_stm32::{bind_interrupts, peripherals}; +use embassy_stm32::{bind_interrupts, peripherals, Peri}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; /// Connect PB2 and PB10 with a 1k Ohm resistor #[embassy_executor::task] -async fn blinky(led: peripherals::PB2) { +async fn blinky(led: Peri<'static, peripherals::PB2>) { let mut led = Output::new(led, Level::High, Speed::Low); loop { diff --git a/examples/stm32f4/src/bin/pwm_input.rs b/examples/stm32f4/src/bin/pwm_input.rs index ce200549d..465cbe4f5 100644 --- a/examples/stm32f4/src/bin/pwm_input.rs +++ b/examples/stm32f4/src/bin/pwm_input.rs @@ -6,14 +6,14 @@ use embassy_executor::Spawner; use embassy_stm32::gpio::{Level, Output, Pull, Speed}; use embassy_stm32::time::khz; use embassy_stm32::timer::pwm_input::PwmInput; -use embassy_stm32::{bind_interrupts, peripherals, timer}; +use embassy_stm32::{bind_interrupts, peripherals, timer, Peri}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; /// Connect PB2 and PA6 with a 1k Ohm resistor #[embassy_executor::task] -async fn blinky(led: peripherals::PB2) { +async fn blinky(led: Peri<'static, peripherals::PB2>) { let mut led = Output::new(led, Level::High, Speed::Low); loop { diff --git a/examples/stm32f4/src/bin/ws2812_pwm.rs b/examples/stm32f4/src/bin/ws2812_pwm.rs index 3ab93d6e0..ca924e181 100644 --- a/examples/stm32f4/src/bin/ws2812_pwm.rs +++ b/examples/stm32f4/src/bin/ws2812_pwm.rs @@ -92,7 +92,7 @@ async fn main(_spawner: Spawner) { loop { for &color in color_list { // with &mut, we can easily reuse same DMA channel multiple times - ws2812_pwm.waveform_up(&mut dp.DMA1_CH2, pwm_channel, color).await; + ws2812_pwm.waveform_up(dp.DMA1_CH2.reborrow(), pwm_channel, color).await; // ws2812 need at least 50 us low level input to confirm the input data and change it's state Timer::after_micros(50).await; // wait until ticker tick diff --git a/examples/stm32f7/src/bin/can.rs b/examples/stm32f7/src/bin/can.rs index a82e335a9..58ba940a8 100644 --- a/examples/stm32f7/src/bin/can.rs +++ b/examples/stm32f7/src/bin/can.rs @@ -42,7 +42,7 @@ async fn main(spawner: Spawner) { // To synchronise to the bus the RX input needs to see a high level. // Use `mem::forget()` to release the borrow on the pin but keep the // pull-up resistor enabled. - let rx_pin = Input::new(&mut p.PA15, Pull::Up); + let rx_pin = Input::new(p.PA15.reborrow(), Pull::Up); core::mem::forget(rx_pin); static CAN: StaticCell> = StaticCell::new(); diff --git a/examples/stm32g0/src/bin/adc_dma.rs b/examples/stm32g0/src/bin/adc_dma.rs index 3713e5a21..d7515933c 100644 --- a/examples/stm32g0/src/bin/adc_dma.rs +++ b/examples/stm32g0/src/bin/adc_dma.rs @@ -25,7 +25,7 @@ async fn main(_spawner: Spawner) { loop { adc.read( - &mut dma, + dma.reborrow(), [ (&mut vrefint_channel, SampleTime::CYCLES160_5), (&mut pa0, SampleTime::CYCLES160_5), diff --git a/examples/stm32g0/src/bin/input_capture.rs b/examples/stm32g0/src/bin/input_capture.rs index bc814cb13..08df4e043 100644 --- a/examples/stm32g0/src/bin/input_capture.rs +++ b/examples/stm32g0/src/bin/input_capture.rs @@ -16,14 +16,14 @@ use embassy_stm32::time::khz; use embassy_stm32::timer::input_capture::{CapturePin, InputCapture}; use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm}; use embassy_stm32::timer::Channel; -use embassy_stm32::{bind_interrupts, peripherals, timer}; +use embassy_stm32::{bind_interrupts, peripherals, timer, Peri}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; // Connect PB1 and PA6 with a 1k Ohm resistor #[embassy_executor::task] -async fn blinky(led: peripherals::PB1) { +async fn blinky(led: Peri<'static, peripherals::PB1>) { let mut led = Output::new(led, Level::High, Speed::Low); loop { diff --git a/examples/stm32g0/src/bin/pwm_input.rs b/examples/stm32g0/src/bin/pwm_input.rs index db9cf4f8a..9d6b5fe97 100644 --- a/examples/stm32g0/src/bin/pwm_input.rs +++ b/examples/stm32g0/src/bin/pwm_input.rs @@ -14,13 +14,13 @@ use embassy_stm32::gpio::{Level, Output, OutputType, Pull, Speed}; use embassy_stm32::time::khz; use embassy_stm32::timer::pwm_input::PwmInput; use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm}; -use embassy_stm32::{bind_interrupts, peripherals, timer}; +use embassy_stm32::{bind_interrupts, peripherals, timer, Peri}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; // Connect PB1 and PA6 with a 1k Ohm resistor #[embassy_executor::task] -async fn blinky(led: peripherals::PB1) { +async fn blinky(led: Peri<'static, peripherals::PB1>) { let mut led = Output::new(led, Level::High, Speed::Low); loop { diff --git a/examples/stm32g4/src/bin/adc_dma.rs b/examples/stm32g4/src/bin/adc_dma.rs index 970623b32..202704085 100644 --- a/examples/stm32g4/src/bin/adc_dma.rs +++ b/examples/stm32g4/src/bin/adc_dma.rs @@ -41,7 +41,7 @@ async fn main(_spawner: Spawner) { loop { adc.read( - &mut dma, + dma.reborrow(), [ (&mut vrefint_channel, SampleTime::CYCLES247_5), (&mut pa0, SampleTime::CYCLES247_5), diff --git a/examples/stm32h5/src/bin/cordic.rs b/examples/stm32h5/src/bin/cordic.rs index 73e873574..cbf854704 100644 --- a/examples/stm32h5/src/bin/cordic.rs +++ b/examples/stm32h5/src/bin/cordic.rs @@ -11,7 +11,7 @@ async fn main(_spawner: Spawner) { let mut dp = embassy_stm32::init(Default::default()); let mut cordic = cordic::Cordic::new( - &mut dp.CORDIC, + dp.CORDIC.reborrow(), unwrap!(cordic::Config::new( cordic::Function::Sin, Default::default(), @@ -59,8 +59,8 @@ async fn main(_spawner: Spawner) { let cnt1 = unwrap!( cordic .async_calc_32bit( - &mut dp.GPDMA1_CH0, - &mut dp.GPDMA1_CH1, + dp.GPDMA1_CH0.reborrow(), + dp.GPDMA1_CH1.reborrow(), &input_buf[..arg1.len() - 1], // limit input buf to its actual length &mut output_u32, true, diff --git a/examples/stm32h5/src/bin/stop.rs b/examples/stm32h5/src/bin/stop.rs index 0d14c0668..e650791c5 100644 --- a/examples/stm32h5/src/bin/stop.rs +++ b/examples/stm32h5/src/bin/stop.rs @@ -10,7 +10,7 @@ use embassy_stm32::gpio::{AnyPin, Level, Output, Speed}; use embassy_stm32::low_power::Executor; use embassy_stm32::rcc::{HSIPrescaler, LsConfig}; use embassy_stm32::rtc::{Rtc, RtcConfig}; -use embassy_stm32::Config; +use embassy_stm32::{Config, Peri}; use embassy_time::Timer; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; @@ -48,7 +48,7 @@ async fn async_main(spawner: Spawner) { } #[embassy_executor::task] -async fn blinky(led: AnyPin) { +async fn blinky(led: Peri<'static, AnyPin>) { let mut led = Output::new(led, Level::Low, Speed::Low); loop { info!("high"); diff --git a/examples/stm32h7/src/bin/adc_dma.rs b/examples/stm32h7/src/bin/adc_dma.rs index 0b905d227..dc775f18a 100644 --- a/examples/stm32h7/src/bin/adc_dma.rs +++ b/examples/stm32h7/src/bin/adc_dma.rs @@ -57,7 +57,7 @@ async fn main(_spawner: Spawner) { loop { adc.read( - &mut dma, + dma.reborrow(), [ (&mut vrefint_channel, SampleTime::CYCLES387_5), (&mut pc0, SampleTime::CYCLES810_5), diff --git a/examples/stm32h7/src/bin/dac_dma.rs b/examples/stm32h7/src/bin/dac_dma.rs index 98c9f1e90..8314754bc 100644 --- a/examples/stm32h7/src/bin/dac_dma.rs +++ b/examples/stm32h7/src/bin/dac_dma.rs @@ -10,6 +10,7 @@ use embassy_stm32::peripherals::{DAC1, TIM6, TIM7}; use embassy_stm32::rcc::frequency; use embassy_stm32::time::Hertz; use embassy_stm32::timer::low_level::Timer; +use embassy_stm32::Peri; use micromath::F32Ext; use {defmt_rtt as _, panic_probe as _}; @@ -57,7 +58,7 @@ async fn main(spawner: Spawner) { } #[embassy_executor::task] -async fn dac_task1(tim: TIM6, mut dac: DacCh1<'static, DAC1, Async>) { +async fn dac_task1(tim: Peri<'static, TIM6>, mut dac: DacCh1<'static, DAC1, Async>) { let data: &[u8; 256] = &calculate_array::<256>(); info!("TIM6 frequency is {}", frequency::()); @@ -100,7 +101,7 @@ async fn dac_task1(tim: TIM6, mut dac: DacCh1<'static, DAC1, Async>) { } #[embassy_executor::task] -async fn dac_task2(tim: TIM7, mut dac: DacCh2<'static, DAC1, Async>) { +async fn dac_task2(tim: Peri<'static, TIM7>, mut dac: DacCh2<'static, DAC1, Async>) { let data: &[u8; 256] = &calculate_array::<256>(); info!("TIM7 frequency is {}", frequency::()); diff --git a/examples/stm32h7/src/bin/low_level_timer_api.rs b/examples/stm32h7/src/bin/low_level_timer_api.rs index b796996ea..8de31ea5b 100644 --- a/examples/stm32h7/src/bin/low_level_timer_api.rs +++ b/examples/stm32h7/src/bin/low_level_timer_api.rs @@ -7,7 +7,7 @@ use embassy_stm32::gpio::{AfType, Flex, OutputType, Speed}; use embassy_stm32::time::{khz, Hertz}; use embassy_stm32::timer::low_level::{OutputCompareMode, Timer as LLTimer}; use embassy_stm32::timer::{Channel, Channel1Pin, Channel2Pin, Channel3Pin, Channel4Pin, GeneralInstance32bit4Channel}; -use embassy_stm32::{into_ref, Config, Peripheral}; +use embassy_stm32::{Config, Peri}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; @@ -66,15 +66,13 @@ pub struct SimplePwm32<'d, T: GeneralInstance32bit4Channel> { impl<'d, T: GeneralInstance32bit4Channel> SimplePwm32<'d, T> { pub fn new( - tim: impl Peripheral

+ 'd, - ch1: impl Peripheral

> + 'd, - ch2: impl Peripheral

> + 'd, - ch3: impl Peripheral

> + 'd, - ch4: impl Peripheral

> + 'd, + tim: Peri<'d, T>, + ch1: Peri<'d, impl Channel1Pin>, + ch2: Peri<'d, impl Channel2Pin>, + ch3: Peri<'d, impl Channel3Pin>, + ch4: Peri<'d, impl Channel4Pin>, freq: Hertz, ) -> Self { - into_ref!(ch1, ch2, ch3, ch4); - let af1 = ch1.af_num(); let af2 = ch2.af_num(); let af3 = ch3.af_num(); diff --git a/examples/stm32h723/src/bin/spdifrx.rs b/examples/stm32h723/src/bin/spdifrx.rs index 69ef5cd07..bc8249ced 100644 --- a/examples/stm32h723/src/bin/spdifrx.rs +++ b/examples/stm32h723/src/bin/spdifrx.rs @@ -77,14 +77,19 @@ async fn main(_spawner: Spawner) { }; let mut sai_transmitter = new_sai_transmitter( - &mut p.SAI4, - &mut p.PD13, - &mut p.PC1, - &mut p.PD12, - &mut p.BDMA_CH0, + p.SAI4.reborrow(), + p.PD13.reborrow(), + p.PC1.reborrow(), + p.PD12.reborrow(), + p.BDMA_CH0.reborrow(), sai_buffer, ); - let mut spdif_receiver = new_spdif_receiver(&mut p.SPDIFRX1, &mut p.PD7, &mut p.DMA2_CH7, spdifrx_buffer); + let mut spdif_receiver = new_spdif_receiver( + p.SPDIFRX1.reborrow(), + p.PD7.reborrow(), + p.DMA2_CH7.reborrow(), + spdifrx_buffer, + ); spdif_receiver.start(); let mut renew_sai = false; @@ -96,11 +101,11 @@ async fn main(_spawner: Spawner) { trace!("Renew SAI."); drop(sai_transmitter); sai_transmitter = new_sai_transmitter( - &mut p.SAI4, - &mut p.PD13, - &mut p.PC1, - &mut p.PD12, - &mut p.BDMA_CH0, + p.SAI4.reborrow(), + p.PD13.reborrow(), + p.PC1.reborrow(), + p.PD12.reborrow(), + p.BDMA_CH0.reborrow(), sai_buffer, ); } @@ -111,7 +116,12 @@ async fn main(_spawner: Spawner) { Err(spdifrx::Error::RingbufferError(_)) => { trace!("SPDIFRX ringbuffer error. Renew."); drop(spdif_receiver); - spdif_receiver = new_spdif_receiver(&mut p.SPDIFRX1, &mut p.PD7, &mut p.DMA2_CH7, spdifrx_buffer); + spdif_receiver = new_spdif_receiver( + p.SPDIFRX1.reborrow(), + p.PD7.reborrow(), + p.DMA2_CH7.reborrow(), + spdifrx_buffer, + ); spdif_receiver.start(); continue; } diff --git a/examples/stm32l4/src/bin/dac_dma.rs b/examples/stm32l4/src/bin/dac_dma.rs index 6c9219080..cde24f411 100644 --- a/examples/stm32l4/src/bin/dac_dma.rs +++ b/examples/stm32l4/src/bin/dac_dma.rs @@ -10,6 +10,7 @@ use embassy_stm32::peripherals::{DAC1, TIM6, TIM7}; use embassy_stm32::rcc::frequency; use embassy_stm32::time::Hertz; use embassy_stm32::timer::low_level::Timer; +use embassy_stm32::Peri; use micromath::F32Ext; use {defmt_rtt as _, panic_probe as _}; @@ -28,7 +29,7 @@ async fn main(spawner: Spawner) { } #[embassy_executor::task] -async fn dac_task1(tim: TIM6, mut dac: DacCh1<'static, DAC1, Async>) { +async fn dac_task1(tim: Peri<'static, TIM6>, mut dac: DacCh1<'static, DAC1, Async>) { let data: &[u8; 256] = &calculate_array::<256>(); info!("TIM6 frequency is {}", frequency::()); @@ -71,7 +72,7 @@ async fn dac_task1(tim: TIM6, mut dac: DacCh1<'static, DAC1, Async>) { } #[embassy_executor::task] -async fn dac_task2(tim: TIM7, mut dac: DacCh2<'static, DAC1, Async>) { +async fn dac_task2(tim: Peri<'static, TIM7>, mut dac: DacCh2<'static, DAC1, Async>) { let data: &[u8; 256] = &calculate_array::<256>(); info!("TIM7 frequency is {}", frequency::()); diff --git a/examples/stm32l5/src/bin/stop.rs b/examples/stm32l5/src/bin/stop.rs index 32a736de8..d7a1efea9 100644 --- a/examples/stm32l5/src/bin/stop.rs +++ b/examples/stm32l5/src/bin/stop.rs @@ -7,7 +7,7 @@ use embassy_stm32::gpio::{AnyPin, Level, Output, Speed}; use embassy_stm32::low_power::Executor; use embassy_stm32::rcc::LsConfig; use embassy_stm32::rtc::{Rtc, RtcConfig}; -use embassy_stm32::Config; +use embassy_stm32::{Config, Peri}; use embassy_time::Timer; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; @@ -39,7 +39,7 @@ async fn async_main(spawner: Spawner) { } #[embassy_executor::task] -async fn blinky(led: AnyPin) -> ! { +async fn blinky(led: Peri<'static, AnyPin>) -> ! { let mut led = Output::new(led, Level::Low, Speed::Low); loop { info!("high"); diff --git a/examples/stm32u5/src/bin/adc.rs b/examples/stm32u5/src/bin/adc.rs index 6ba21cc63..d2aa28087 100644 --- a/examples/stm32u5/src/bin/adc.rs +++ b/examples/stm32u5/src/bin/adc.rs @@ -72,7 +72,7 @@ async fn main(_spawner: embassy_executor::Spawner) { let mut measurements = [0u16; 2]; adc1.read( - &mut p.GPDMA1_CH0, + p.GPDMA1_CH0.reborrow(), [ (&mut degraded11, adc::SampleTime::CYCLES160_5), (&mut degraded12, adc::SampleTime::CYCLES160_5), @@ -96,7 +96,7 @@ async fn main(_spawner: embassy_executor::Spawner) { // The channels must be in ascending order and can't repeat for ADC4 adc4.read( - &mut p.GPDMA1_CH1, + p.GPDMA1_CH1.reborrow(), [&mut degraded42, &mut degraded41].into_iter(), &mut measurements, ) diff --git a/tests/nrf/src/bin/buffered_uart.rs b/tests/nrf/src/bin/buffered_uart.rs index 04f32832f..2eecafb95 100644 --- a/tests/nrf/src/bin/buffered_uart.rs +++ b/tests/nrf/src/bin/buffered_uart.rs @@ -25,14 +25,14 @@ async fn main(_spawner: Spawner) { // test teardown + recreate of the buffereduarte works fine. for _ in 0..2 { let u = BufferedUarte::new( - &mut peri!(p, UART0), - &mut p.TIMER0, - &mut p.PPI_CH0, - &mut p.PPI_CH1, - &mut p.PPI_GROUP0, + peri!(p, UART0).reborrow(), + p.TIMER0.reborrow(), + p.PPI_CH0.reborrow(), + p.PPI_CH1.reborrow(), + p.PPI_GROUP0.reborrow(), irqs!(UART0_BUFFERED), - &mut peri!(p, PIN_A), - &mut peri!(p, PIN_B), + peri!(p, PIN_A).reborrow(), + peri!(p, PIN_B).reborrow(), config.clone(), &mut rx_buffer, &mut tx_buffer, diff --git a/tests/nrf/src/bin/buffered_uart_halves.rs b/tests/nrf/src/bin/buffered_uart_halves.rs index bdf5ad726..adfba509d 100644 --- a/tests/nrf/src/bin/buffered_uart_halves.rs +++ b/tests/nrf/src/bin/buffered_uart_halves.rs @@ -27,21 +27,21 @@ async fn main(_spawner: Spawner) { const COUNT: usize = 40_000; let mut tx = BufferedUarteTx::new( - &mut peri!(p, UART1), + peri!(p, UART1).reborrow(), irqs!(UART1_BUFFERED), - &mut peri!(p, PIN_A), + peri!(p, PIN_A).reborrow(), config.clone(), &mut tx_buffer, ); let mut rx = BufferedUarteRx::new( - &mut peri!(p, UART0), - &mut p.TIMER0, - &mut p.PPI_CH0, - &mut p.PPI_CH1, - &mut p.PPI_GROUP0, + peri!(p, UART0).reborrow(), + p.TIMER0.reborrow(), + p.PPI_CH0.reborrow(), + p.PPI_CH1.reborrow(), + p.PPI_GROUP0.reborrow(), irqs!(UART0_BUFFERED), - &mut peri!(p, PIN_B), + peri!(p, PIN_B).reborrow(), config.clone(), &mut rx_buffer, ); diff --git a/tests/nrf/src/bin/buffered_uart_spam.rs b/tests/nrf/src/bin/buffered_uart_spam.rs index cf9ca50d2..24ddd06f3 100644 --- a/tests/nrf/src/bin/buffered_uart_spam.rs +++ b/tests/nrf/src/bin/buffered_uart_spam.rs @@ -27,7 +27,11 @@ async fn main(_spawner: Spawner) { let mut rx_buffer = [0u8; 1024]; - mem::forget(Output::new(&mut peri!(p, PIN_A), Level::High, OutputDrive::Standard)); + mem::forget(Output::new( + peri!(p, PIN_A).reborrow(), + Level::High, + OutputDrive::Standard, + )); let mut u = BufferedUarteRx::new( peri!(p, UART0), diff --git a/tests/nrf/src/bin/spim.rs b/tests/nrf/src/bin/spim.rs index c2ec90b88..2b38f0409 100644 --- a/tests/nrf/src/bin/spim.rs +++ b/tests/nrf/src/bin/spim.rs @@ -17,11 +17,11 @@ async fn main(_spawner: Spawner) { let mut config = spim::Config::default(); config.frequency = spim::Frequency::M1; let mut spim = Spim::new( - &mut peri!(p, SPIM0), + peri!(p, SPIM0).reborrow(), irqs!(SPIM0), - &mut peri!(p, PIN_X), - &mut peri!(p, PIN_A), // MISO - &mut peri!(p, PIN_B), // MOSI + peri!(p, PIN_X).reborrow(), + peri!(p, PIN_A).reborrow(), // MISO + peri!(p, PIN_B).reborrow(), // MOSI config.clone(), ); let data = [ diff --git a/tests/nrf/src/bin/uart_halves.rs b/tests/nrf/src/bin/uart_halves.rs index f48ea43a1..a462f80ce 100644 --- a/tests/nrf/src/bin/uart_halves.rs +++ b/tests/nrf/src/bin/uart_halves.rs @@ -19,8 +19,18 @@ async fn main(_spawner: Spawner) { config.parity = uarte::Parity::EXCLUDED; config.baudrate = uarte::Baudrate::BAUD1M; - let mut tx = UarteTx::new(&mut peri!(p, UART0), irqs!(UART0), &mut peri!(p, PIN_A), config.clone()); - let mut rx = UarteRx::new(&mut peri!(p, UART1), irqs!(UART1), &mut peri!(p, PIN_B), config.clone()); + let mut tx = UarteTx::new( + peri!(p, UART0).reborrow(), + irqs!(UART0), + peri!(p, PIN_A).reborrow(), + config.clone(), + ); + let mut rx = UarteRx::new( + peri!(p, UART1).reborrow(), + irqs!(UART1), + peri!(p, PIN_B).reborrow(), + config.clone(), + ); let data = [ 0x42, 0x43, 0x44, 0x45, 0x66, 0x12, 0x23, 0x34, 0x45, 0x19, 0x91, 0xaa, 0xff, 0xa5, 0x5a, 0x77, diff --git a/tests/nrf/src/bin/uart_split.rs b/tests/nrf/src/bin/uart_split.rs index 70d8b2e33..f24903297 100644 --- a/tests/nrf/src/bin/uart_split.rs +++ b/tests/nrf/src/bin/uart_split.rs @@ -21,10 +21,10 @@ async fn main(_spawner: Spawner) { config.baudrate = uarte::Baudrate::BAUD9600; let uarte = Uarte::new( - &mut peri!(p, UART0), + peri!(p, UART0).reborrow(), irqs!(UART0), - &mut peri!(p, PIN_A), - &mut peri!(p, PIN_B), + peri!(p, PIN_A).reborrow(), + peri!(p, PIN_B).reborrow(), config.clone(), ); let (mut tx, mut rx) = uarte.split(); diff --git a/tests/rp/src/bin/adc.rs b/tests/rp/src/bin/adc.rs index 87e9709cc..c2175bc03 100644 --- a/tests/rp/src/bin/adc.rs +++ b/tests/rp/src/bin/adc.rs @@ -30,12 +30,12 @@ async fn main(_spawner: Spawner) { { { - let mut p = Channel::new_pin(&mut a, Pull::Down); + let mut p = Channel::new_pin(a.reborrow(), Pull::Down); defmt::assert!(adc.blocking_read(&mut p).unwrap() < 0b01_0000_0000); defmt::assert!(adc.read(&mut p).await.unwrap() < 0b01_0000_0000); } { - let mut p = Channel::new_pin(&mut a, Pull::Up); + let mut p = Channel::new_pin(a.reborrow(), Pull::Up); defmt::assert!(adc.blocking_read(&mut p).unwrap() > 0b11_0000_0000); defmt::assert!(adc.read(&mut p).await.unwrap() > 0b11_0000_0000); } @@ -43,21 +43,21 @@ async fn main(_spawner: Spawner) { // not bothering with async reads from now on { { - let mut p = Channel::new_pin(&mut b, Pull::Down); + let mut p = Channel::new_pin(b.reborrow(), Pull::Down); defmt::assert!(adc.blocking_read(&mut p).unwrap() < 0b01_0000_0000); } { - let mut p = Channel::new_pin(&mut b, Pull::Up); + let mut p = Channel::new_pin(b.reborrow(), Pull::Up); defmt::assert!(adc.blocking_read(&mut p).unwrap() > 0b11_0000_0000); } } { { - let mut p = Channel::new_pin(&mut c, Pull::Down); + let mut p = Channel::new_pin(c.reborrow(), Pull::Down); defmt::assert!(adc.blocking_read(&mut p).unwrap() < 0b01_0000_0000); } { - let mut p = Channel::new_pin(&mut c, Pull::Up); + let mut p = Channel::new_pin(c.reborrow(), Pull::Up); defmt::assert!(adc.blocking_read(&mut p).unwrap() > 0b11_0000_0000); } } @@ -65,15 +65,15 @@ async fn main(_spawner: Spawner) { // gp29 is connected to vsys through a 200k/100k divider, // adding pulls should change the value let low = { - let mut p = Channel::new_pin(&mut d, Pull::Down); + let mut p = Channel::new_pin(d.reborrow(), Pull::Down); adc.blocking_read(&mut p).unwrap() }; let none = { - let mut p = Channel::new_pin(&mut d, Pull::None); + let mut p = Channel::new_pin(d.reborrow(), Pull::None); adc.blocking_read(&mut p).unwrap() }; let up = { - let mut p = Channel::new_pin(&mut d, Pull::Up); + let mut p = Channel::new_pin(d.reborrow(), Pull::Up); adc.blocking_read(&mut p).unwrap() }; defmt::assert!(low < none); @@ -81,7 +81,7 @@ async fn main(_spawner: Spawner) { } { let temp = convert_to_celsius( - adc.read(&mut Channel::new_temp_sensor(&mut p.ADC_TEMP_SENSOR)) + adc.read(&mut Channel::new_temp_sensor(p.ADC_TEMP_SENSOR.reborrow())) .await .unwrap(), ); @@ -97,14 +97,29 @@ async fn main(_spawner: Spawner) { let mut low = [0u16; 16]; let mut none = [0u8; 16]; let mut up = [Sample::default(); 16]; - adc.read_many(&mut Channel::new_pin(&mut d, Pull::Down), &mut low, 1, &mut p.DMA_CH0) - .await - .unwrap(); - adc.read_many(&mut Channel::new_pin(&mut d, Pull::None), &mut none, 1, &mut p.DMA_CH0) - .await - .unwrap(); - adc.read_many_raw(&mut Channel::new_pin(&mut d, Pull::Up), &mut up, 1, &mut p.DMA_CH0) - .await; + adc.read_many( + &mut Channel::new_pin(d.reborrow(), Pull::Down), + &mut low, + 1, + p.DMA_CH0.reborrow(), + ) + .await + .unwrap(); + adc.read_many( + &mut Channel::new_pin(d.reborrow(), Pull::None), + &mut none, + 1, + p.DMA_CH0.reborrow(), + ) + .await + .unwrap(); + adc.read_many_raw( + &mut Channel::new_pin(d.reborrow(), Pull::Up), + &mut up, + 1, + p.DMA_CH0.reborrow(), + ) + .await; defmt::assert!(low.iter().zip(none.iter()).all(|(l, n)| *l >> 4 < *n as u16)); defmt::assert!(up.iter().all(|s| s.good())); defmt::assert!(none.iter().zip(up.iter()).all(|(n, u)| (*n as u16) < u.value())); @@ -112,10 +127,10 @@ async fn main(_spawner: Spawner) { { let mut temp = [0u16; 16]; adc.read_many( - &mut Channel::new_temp_sensor(&mut p.ADC_TEMP_SENSOR), + &mut Channel::new_temp_sensor(p.ADC_TEMP_SENSOR.reborrow()), &mut temp, 1, - &mut p.DMA_CH0, + p.DMA_CH0.reborrow(), ) .await .unwrap(); @@ -126,10 +141,10 @@ async fn main(_spawner: Spawner) { { let mut multi = [0u16; 2]; let mut channels = [ - Channel::new_pin(&mut a, Pull::Up), - Channel::new_temp_sensor(&mut p.ADC_TEMP_SENSOR), + Channel::new_pin(a.reborrow(), Pull::Up), + Channel::new_temp_sensor(p.ADC_TEMP_SENSOR.reborrow()), ]; - adc.read_many_multichannel(&mut channels, &mut multi, 1, &mut p.DMA_CH0) + adc.read_many_multichannel(&mut channels, &mut multi, 1, p.DMA_CH0.reborrow()) .await .unwrap(); defmt::assert!(multi[0] > 3_000); diff --git a/tests/rp/src/bin/bootsel.rs b/tests/rp/src/bin/bootsel.rs index e88d8bf6c..aa123ab03 100644 --- a/tests/rp/src/bin/bootsel.rs +++ b/tests/rp/src/bin/bootsel.rs @@ -4,12 +4,13 @@ teleprobe_meta::target!(b"rpi-pico"); use defmt::{assert_eq, *}; use embassy_executor::Spawner; +use embassy_rp::bootsel::is_bootsel_pressed; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] async fn main(_spawner: Spawner) { - let mut p = embassy_rp::init(Default::default()); + let p = embassy_rp::init(Default::default()); info!("Hello World!"); // add some delay to give an attached debug probe time to parse the @@ -18,7 +19,7 @@ async fn main(_spawner: Spawner) { // https://github.com/knurling-rs/defmt/pull/683 Timer::after_millis(10).await; - assert_eq!(p.BOOTSEL.is_pressed(), false); + assert_eq!(is_bootsel_pressed(p.BOOTSEL), false); info!("Test OK"); cortex_m::asm::bkpt(); diff --git a/tests/rp/src/bin/gpio.rs b/tests/rp/src/bin/gpio.rs index 6c37ac5be..614b6317a 100644 --- a/tests/rp/src/bin/gpio.rs +++ b/tests/rp/src/bin/gpio.rs @@ -21,10 +21,10 @@ async fn main(_spawner: Spawner) { // Test initial output { - let b = Input::new(&mut b, Pull::None); + let b = Input::new(b.reborrow(), Pull::None); { - let a = Output::new(&mut a, Level::Low); + let a = Output::new(a.reborrow(), Level::Low); delay(); assert!(b.is_low()); assert!(!b.is_high()); @@ -32,7 +32,7 @@ async fn main(_spawner: Spawner) { assert!(!a.is_set_high()); } { - let mut a = Output::new(&mut a, Level::High); + let mut a = Output::new(a.reborrow(), Level::High); delay(); assert!(!b.is_low()); assert!(b.is_high()); @@ -69,10 +69,10 @@ async fn main(_spawner: Spawner) { // Test input no pull { - let b = Input::new(&mut b, Pull::None); + let b = Input::new(b.reborrow(), Pull::None); // no pull, the status is undefined - let mut a = Output::new(&mut a, Level::Low); + let mut a = Output::new(a.reborrow(), Level::Low); delay(); assert!(b.is_low()); a.set_high(); @@ -83,11 +83,11 @@ async fn main(_spawner: Spawner) { // Test input pulldown #[cfg(feature = "rp2040")] { - let b = Input::new(&mut b, Pull::Down); + let b = Input::new(b.reborrow(), Pull::Down); delay(); assert!(b.is_low()); - let mut a = Output::new(&mut a, Level::Low); + let mut a = Output::new(a.reborrow(), Level::Low); delay(); assert!(b.is_low()); a.set_high(); @@ -97,11 +97,11 @@ async fn main(_spawner: Spawner) { // Test input pullup { - let b = Input::new(&mut b, Pull::Up); + let b = Input::new(b.reborrow(), Pull::Up); delay(); assert!(b.is_high()); - let mut a = Output::new(&mut a, Level::Low); + let mut a = Output::new(a.reborrow(), Level::Low); delay(); assert!(b.is_low()); a.set_high(); @@ -112,8 +112,8 @@ async fn main(_spawner: Spawner) { // OUTPUT OPEN DRAIN #[cfg(feature = "rp2040")] { - let mut b = OutputOpenDrain::new(&mut b, Level::High); - let mut a = Flex::new(&mut a); + let mut b = OutputOpenDrain::new(b.reborrow(), Level::High); + let mut a = Flex::new(a.reborrow()); a.set_as_input(); // When an OutputOpenDrain is high, it doesn't drive the pin. @@ -170,12 +170,12 @@ async fn main(_spawner: Spawner) { // Test initial output { //Flex pin configured as input - let mut b = Flex::new(&mut b); + let mut b = Flex::new(b.reborrow()); b.set_as_input(); { //Flex pin configured as output - let mut a = Flex::new(&mut a); //Flex pin configured as output + let mut a = Flex::new(a.reborrow()); //Flex pin configured as output a.set_low(); // Pin state must be set before configuring the pin, thus we avoid unknown state a.set_as_output(); delay(); @@ -183,7 +183,7 @@ async fn main(_spawner: Spawner) { } { //Flex pin configured as output - let mut a = Flex::new(&mut a); + let mut a = Flex::new(a.reborrow()); a.set_high(); a.set_as_output(); @@ -194,10 +194,10 @@ async fn main(_spawner: Spawner) { // Test input no pull { - let mut b = Flex::new(&mut b); + let mut b = Flex::new(b.reborrow()); b.set_as_input(); // no pull by default. - let mut a = Flex::new(&mut a); + let mut a = Flex::new(a.reborrow()); a.set_low(); a.set_as_output(); @@ -211,13 +211,13 @@ async fn main(_spawner: Spawner) { // Test input pulldown #[cfg(feature = "rp2040")] { - let mut b = Flex::new(&mut b); + let mut b = Flex::new(b.reborrow()); b.set_as_input(); b.set_pull(Pull::Down); delay(); assert!(b.is_low()); - let mut a = Flex::new(&mut a); + let mut a = Flex::new(a.reborrow()); a.set_low(); a.set_as_output(); delay(); @@ -229,13 +229,13 @@ async fn main(_spawner: Spawner) { // Test input pullup { - let mut b = Flex::new(&mut b); + let mut b = Flex::new(b.reborrow()); b.set_as_input(); b.set_pull(Pull::Up); delay(); assert!(b.is_high()); - let mut a = Flex::new(&mut a); + let mut a = Flex::new(a.reborrow()); a.set_high(); a.set_as_output(); delay(); diff --git a/tests/rp/src/bin/gpio_async.rs b/tests/rp/src/bin/gpio_async.rs index 39e3d6337..72fb0910d 100644 --- a/tests/rp/src/bin/gpio_async.rs +++ b/tests/rp/src/bin/gpio_async.rs @@ -22,8 +22,8 @@ async fn main(_spawner: Spawner) { { info!("test wait_for_high"); - let mut output = Output::new(&mut output_pin, Level::Low); - let mut input = Input::new(&mut input_pin, Pull::None); + let mut output = Output::new(output_pin.reborrow(), Level::Low); + let mut input = Input::new(input_pin.reborrow(), Pull::None); assert!(input.is_low(), "input was expected to be low"); @@ -43,8 +43,8 @@ async fn main(_spawner: Spawner) { { info!("test wait_for_low"); - let mut output = Output::new(&mut output_pin, Level::High); - let mut input = Input::new(&mut input_pin, Pull::None); + let mut output = Output::new(output_pin.reborrow(), Level::High); + let mut input = Input::new(input_pin.reborrow(), Pull::None); assert!(input.is_high(), "input was expected to be high"); @@ -63,8 +63,8 @@ async fn main(_spawner: Spawner) { { info!("test wait_for_rising_edge"); - let mut output = Output::new(&mut output_pin, Level::Low); - let mut input = Input::new(&mut input_pin, Pull::None); + let mut output = Output::new(output_pin.reborrow(), Level::Low); + let mut input = Input::new(input_pin.reborrow(), Pull::None); assert!(input.is_low(), "input was expected to be low"); @@ -83,8 +83,8 @@ async fn main(_spawner: Spawner) { { info!("test wait_for_falling_edge"); - let mut output = Output::new(&mut output_pin, Level::High); - let mut input = Input::new(&mut input_pin, Pull::None); + let mut output = Output::new(output_pin.reborrow(), Level::High); + let mut input = Input::new(input_pin.reborrow(), Pull::None); assert!(input.is_high(), "input was expected to be high"); @@ -103,8 +103,8 @@ async fn main(_spawner: Spawner) { { info!("test wait_for_any_edge (falling)"); - let mut output = Output::new(&mut output_pin, Level::High); - let mut input = Input::new(&mut input_pin, Pull::None); + let mut output = Output::new(output_pin.reborrow(), Level::High); + let mut input = Input::new(input_pin.reborrow(), Pull::None); assert!(input.is_high(), "input was expected to be high"); @@ -123,8 +123,8 @@ async fn main(_spawner: Spawner) { { info!("test wait_for_any_edge (rising)"); - let mut output = Output::new(&mut output_pin, Level::Low); - let mut input = Input::new(&mut input_pin, Pull::None); + let mut output = Output::new(output_pin.reborrow(), Level::Low); + let mut input = Input::new(input_pin.reborrow(), Pull::None); assert!(input.is_low(), "input was expected to be low"); diff --git a/tests/rp/src/bin/gpio_multicore.rs b/tests/rp/src/bin/gpio_multicore.rs index 3caa8ef35..857f36975 100644 --- a/tests/rp/src/bin/gpio_multicore.rs +++ b/tests/rp/src/bin/gpio_multicore.rs @@ -10,6 +10,7 @@ use embassy_executor::Executor; use embassy_rp::gpio::{Input, Level, Output, Pull}; use embassy_rp::multicore::{spawn_core1, Stack}; use embassy_rp::peripherals::{PIN_0, PIN_1}; +use embassy_rp::Peri; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::channel::Channel; use static_cell::StaticCell; @@ -37,7 +38,7 @@ fn main() -> ! { } #[embassy_executor::task] -async fn core0_task(p: PIN_0) { +async fn core0_task(p: Peri<'static, PIN_0>) { info!("CORE0 is running"); let mut pin = Output::new(p, Level::Low); @@ -54,7 +55,7 @@ async fn core0_task(p: PIN_0) { } #[embassy_executor::task] -async fn core1_task(p: PIN_1) { +async fn core1_task(p: Peri<'static, PIN_1>) { info!("CORE1 is running"); CHANNEL0.receive().await; diff --git a/tests/rp/src/bin/pwm.rs b/tests/rp/src/bin/pwm.rs index d8ee78dcd..5f890cd50 100644 --- a/tests/rp/src/bin/pwm.rs +++ b/tests/rp/src/bin/pwm.rs @@ -33,7 +33,7 @@ async fn main(_spawner: Spawner) { // Test free-running clock { - let pwm = Pwm::new_free(&mut p.PWM_SLICE3, cfg.clone()); + let pwm = Pwm::new_free(p.PWM_SLICE3.reborrow(), cfg.clone()); cortex_m::asm::delay(125); let ctr = pwm.counter(); assert!(ctr > 0); @@ -50,8 +50,8 @@ async fn main(_spawner: Spawner) { // Test output from A { - let pin1 = Input::new(&mut p9, Pull::None); - let _pwm = Pwm::new_output_a(&mut p.PWM_SLICE3, &mut p6, cfg.clone()); + let pin1 = Input::new(p9.reborrow(), Pull::None); + let _pwm = Pwm::new_output_a(p.PWM_SLICE3.reborrow(), p6.reborrow(), cfg.clone()); Timer::after_millis(1).await; assert_eq!(pin1.is_low(), invert_a); Timer::after_millis(5).await; @@ -64,8 +64,8 @@ async fn main(_spawner: Spawner) { // Test output from B { - let pin2 = Input::new(&mut p11, Pull::None); - let _pwm = Pwm::new_output_b(&mut p.PWM_SLICE3, &mut p7, cfg.clone()); + let pin2 = Input::new(p11.reborrow(), Pull::None); + let _pwm = Pwm::new_output_b(p.PWM_SLICE3.reborrow(), p7.reborrow(), cfg.clone()); Timer::after_millis(1).await; assert_ne!(pin2.is_low(), invert_a); Timer::after_millis(5).await; @@ -78,9 +78,9 @@ async fn main(_spawner: Spawner) { // Test output from A+B { - let pin1 = Input::new(&mut p9, Pull::None); - let pin2 = Input::new(&mut p11, Pull::None); - let _pwm = Pwm::new_output_ab(&mut p.PWM_SLICE3, &mut p6, &mut p7, cfg.clone()); + let pin1 = Input::new(p9.reborrow(), Pull::None); + let pin2 = Input::new(p11.reborrow(), Pull::None); + let _pwm = Pwm::new_output_ab(p.PWM_SLICE3.reborrow(), p6.reborrow(), p7.reborrow(), cfg.clone()); Timer::after_millis(1).await; assert_eq!(pin1.is_low(), invert_a); assert_ne!(pin2.is_low(), invert_a); @@ -99,8 +99,14 @@ async fn main(_spawner: Spawner) { // Test level-gated #[cfg(feature = "rp2040")] { - let mut pin2 = Output::new(&mut p11, Level::Low); - let pwm = Pwm::new_input(&mut p.PWM_SLICE3, &mut p7, Pull::None, InputMode::Level, cfg.clone()); + let mut pin2 = Output::new(p11.reborrow(), Level::Low); + let pwm = Pwm::new_input( + p.PWM_SLICE3.reborrow(), + p7.reborrow(), + Pull::None, + InputMode::Level, + cfg.clone(), + ); assert_eq!(pwm.counter(), 0); Timer::after_millis(5).await; assert_eq!(pwm.counter(), 0); @@ -117,10 +123,10 @@ async fn main(_spawner: Spawner) { // Test rising-gated #[cfg(feature = "rp2040")] { - let mut pin2 = Output::new(&mut p11, Level::Low); + let mut pin2 = Output::new(p11.reborrow(), Level::Low); let pwm = Pwm::new_input( - &mut p.PWM_SLICE3, - &mut p7, + p.PWM_SLICE3.reborrow(), + p7.reborrow(), Pull::None, InputMode::RisingEdge, cfg.clone(), @@ -139,10 +145,10 @@ async fn main(_spawner: Spawner) { // Test falling-gated #[cfg(feature = "rp2040")] { - let mut pin2 = Output::new(&mut p11, Level::High); + let mut pin2 = Output::new(p11.reborrow(), Level::High); let pwm = Pwm::new_input( - &mut p.PWM_SLICE3, - &mut p7, + p.PWM_SLICE3.reborrow(), + p7.reborrow(), Pull::None, InputMode::FallingEdge, cfg.clone(), @@ -160,10 +166,10 @@ async fn main(_spawner: Spawner) { // pull-down { - let pin2 = Input::new(&mut p11, Pull::None); + let pin2 = Input::new(p11.reborrow(), Pull::None); Pwm::new_input( - &mut p.PWM_SLICE3, - &mut p7, + p.PWM_SLICE3.reborrow(), + p7.reborrow(), Pull::Down, InputMode::FallingEdge, cfg.clone(), @@ -174,10 +180,10 @@ async fn main(_spawner: Spawner) { // pull-up { - let pin2 = Input::new(&mut p11, Pull::None); + let pin2 = Input::new(p11.reborrow(), Pull::None); Pwm::new_input( - &mut p.PWM_SLICE3, - &mut p7, + p.PWM_SLICE3.reborrow(), + p7.reborrow(), Pull::Up, InputMode::FallingEdge, cfg.clone(), diff --git a/tests/rp/src/bin/uart.rs b/tests/rp/src/bin/uart.rs index 67cfa6bc8..84744ab77 100644 --- a/tests/rp/src/bin/uart.rs +++ b/tests/rp/src/bin/uart.rs @@ -56,7 +56,7 @@ async fn main(_spawner: Spawner) { { let config = Config::default(); - let mut uart = Uart::new_blocking(&mut uart, &mut tx, &mut rx, config); + let mut uart = Uart::new_blocking(uart.reborrow(), tx.reborrow(), rx.reborrow(), config); // We can't send too many bytes, they have to fit in the FIFO. // This is because we aren't sending+receiving at the same time. @@ -69,7 +69,7 @@ async fn main(_spawner: Spawner) { info!("test overflow detection"); { let config = Config::default(); - let mut uart = Uart::new_blocking(&mut uart, &mut tx, &mut rx, config); + let mut uart = Uart::new_blocking(uart.reborrow(), tx.reborrow(), rx.reborrow(), config); let data = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, @@ -93,7 +93,7 @@ async fn main(_spawner: Spawner) { info!("test break detection"); { let config = Config::default(); - let mut uart = Uart::new_blocking(&mut uart, &mut tx, &mut rx, config); + let mut uart = Uart::new_blocking(uart.reborrow(), tx.reborrow(), rx.reborrow(), config); // break on empty fifo uart.send_break(20).await; @@ -113,11 +113,11 @@ async fn main(_spawner: Spawner) { // parity detection. here we bitbang to not require two uarts. info!("test parity error detection"); { - let mut pin = Output::new(&mut tx, Level::High); + let mut pin = Output::new(tx.reborrow(), Level::High); let mut config = Config::default(); config.baudrate = 1000; config.parity = Parity::ParityEven; - let mut uart = UartRx::new_blocking(&mut uart, &mut rx, config); + let mut uart = UartRx::new_blocking(uart.reborrow(), rx.reborrow(), config); async fn chr(pin: &mut Output<'_>, v: u8, parity: u8) { send(pin, v, Some(parity != 0)).await; @@ -140,10 +140,10 @@ async fn main(_spawner: Spawner) { // framing error detection. here we bitbang because there's no other way. info!("test framing error detection"); { - let mut pin = Output::new(&mut tx, Level::High); + let mut pin = Output::new(tx.reborrow(), Level::High); let mut config = Config::default(); config.baudrate = 1000; - let mut uart = UartRx::new_blocking(&mut uart, &mut rx, config); + let mut uart = UartRx::new_blocking(uart.reborrow(), rx.reborrow(), config); async fn chr(pin: &mut Output<'_>, v: u8, good: bool) { if good { diff --git a/tests/rp/src/bin/uart_buffered.rs b/tests/rp/src/bin/uart_buffered.rs index a543320e0..b270a60ce 100644 --- a/tests/rp/src/bin/uart_buffered.rs +++ b/tests/rp/src/bin/uart_buffered.rs @@ -73,7 +73,15 @@ async fn main(_spawner: Spawner) { let config = Config::default(); let tx_buf = &mut [0u8; 16]; let rx_buf = &mut [0u8; 16]; - let mut uart = BufferedUart::new(&mut uart, Irqs, &mut tx, &mut rx, tx_buf, rx_buf, config); + let mut uart = BufferedUart::new( + uart.reborrow(), + Irqs, + tx.reborrow(), + rx.reborrow(), + tx_buf, + rx_buf, + config, + ); // Make sure we send more bytes than fits in the FIFO, to test the actual // bufferedUart. @@ -93,7 +101,15 @@ async fn main(_spawner: Spawner) { let config = Config::default(); let tx_buf = &mut [0u8; 16]; let rx_buf = &mut [0u8; 16]; - let mut uart = BufferedUart::new(&mut uart, Irqs, &mut tx, &mut rx, tx_buf, rx_buf, config); + let mut uart = BufferedUart::new( + uart.reborrow(), + Irqs, + tx.reborrow(), + rx.reborrow(), + tx_buf, + rx_buf, + config, + ); // Make sure we send more bytes than fits in the FIFO, to test the actual // bufferedUart. @@ -128,7 +144,15 @@ async fn main(_spawner: Spawner) { config.baudrate = 1000; let tx_buf = &mut [0u8; 16]; let rx_buf = &mut [0u8; 16]; - let mut uart = BufferedUart::new(&mut uart, Irqs, &mut tx, &mut rx, tx_buf, rx_buf, config); + let mut uart = BufferedUart::new( + uart.reborrow(), + Irqs, + tx.reborrow(), + rx.reborrow(), + tx_buf, + rx_buf, + config, + ); // break on empty buffer uart.send_break(20).await; @@ -156,13 +180,13 @@ async fn main(_spawner: Spawner) { // parity detection. here we bitbang to not require two uarts. info!("test parity error detection"); { - let mut pin = Output::new(&mut tx, Level::High); + let mut pin = Output::new(tx.reborrow(), Level::High); // choose a very slow baud rate to make tests reliable even with O0 let mut config = Config::default(); config.baudrate = 1000; config.parity = Parity::ParityEven; let rx_buf = &mut [0u8; 16]; - let mut uart = BufferedUartRx::new(&mut uart, Irqs, &mut rx, rx_buf, config); + let mut uart = BufferedUartRx::new(uart.reborrow(), Irqs, rx.reborrow(), rx_buf, config); async fn chr(pin: &mut Output<'_>, v: u8, parity: u32) { send(pin, v, Some(parity != 0)).await; @@ -204,12 +228,12 @@ async fn main(_spawner: Spawner) { // framing error detection. here we bitbang because there's no other way. info!("test framing error detection"); { - let mut pin = Output::new(&mut tx, Level::High); + let mut pin = Output::new(tx.reborrow(), Level::High); // choose a very slow baud rate to make tests reliable even with O0 let mut config = Config::default(); config.baudrate = 1000; let rx_buf = &mut [0u8; 16]; - let mut uart = BufferedUartRx::new(&mut uart, Irqs, &mut rx, rx_buf, config); + let mut uart = BufferedUartRx::new(uart.reborrow(), Irqs, rx.reborrow(), rx_buf, config); async fn chr(pin: &mut Output<'_>, v: u8, good: bool) { if good { diff --git a/tests/rp/src/bin/uart_dma.rs b/tests/rp/src/bin/uart_dma.rs index bdf94e78c..a09101223 100644 --- a/tests/rp/src/bin/uart_dma.rs +++ b/tests/rp/src/bin/uart_dma.rs @@ -65,12 +65,12 @@ async fn main(_spawner: Spawner) { { let config = Config::default(); let mut uart = Uart::new( - &mut uart, - &mut tx, - &mut rx, + uart.reborrow(), + tx.reborrow(), + rx.reborrow(), Irqs, - &mut p.DMA_CH0, - &mut p.DMA_CH1, + p.DMA_CH0.reborrow(), + p.DMA_CH1.reborrow(), config, ); @@ -86,12 +86,12 @@ async fn main(_spawner: Spawner) { { let config = Config::default(); let mut uart = Uart::new( - &mut uart, - &mut tx, - &mut rx, + uart.reborrow(), + tx.reborrow(), + rx.reborrow(), Irqs, - &mut p.DMA_CH0, - &mut p.DMA_CH1, + p.DMA_CH0.reborrow(), + p.DMA_CH1.reborrow(), config, ); @@ -115,12 +115,12 @@ async fn main(_spawner: Spawner) { { let config = Config::default(); let (mut tx, mut rx) = Uart::new( - &mut uart, - &mut tx, - &mut rx, + uart.reborrow(), + tx.reborrow(), + rx.reborrow(), Irqs, - &mut p.DMA_CH0, - &mut p.DMA_CH1, + p.DMA_CH0.reborrow(), + p.DMA_CH1.reborrow(), config, ) .split(); @@ -156,12 +156,12 @@ async fn main(_spawner: Spawner) { // parity detection. here we bitbang to not require two uarts. info!("test parity error detection"); { - let mut pin = Output::new(&mut tx, Level::High); + let mut pin = Output::new(tx.reborrow(), Level::High); // choose a very slow baud rate to make tests reliable even with O0 let mut config = Config::default(); config.baudrate = 1000; config.parity = Parity::ParityEven; - let mut uart = UartRx::new(&mut uart, &mut rx, Irqs, &mut p.DMA_CH0, config); + let mut uart = UartRx::new(uart.reborrow(), rx.reborrow(), Irqs, p.DMA_CH0.reborrow(), config); async fn chr(pin: &mut Output<'_>, v: u8, parity: u32) { send(pin, v, Some(parity != 0)).await; @@ -202,11 +202,11 @@ async fn main(_spawner: Spawner) { // framing error detection. here we bitbang because there's no other way. info!("test framing error detection"); { - let mut pin = Output::new(&mut tx, Level::High); + let mut pin = Output::new(tx.reborrow(), Level::High); // choose a very slow baud rate to make tests reliable even with O0 let mut config = Config::default(); config.baudrate = 1000; - let mut uart = UartRx::new(&mut uart, &mut rx, Irqs, &mut p.DMA_CH0, config); + let mut uart = UartRx::new(uart.reborrow(), rx.reborrow(), Irqs, p.DMA_CH0.reborrow(), config); async fn chr(pin: &mut Output<'_>, v: u8, good: bool) { if good { diff --git a/tests/stm32/src/bin/can.rs b/tests/stm32/src/bin/can.rs index 85a5f8d83..778d88a7b 100644 --- a/tests/stm32/src/bin/can.rs +++ b/tests/stm32/src/bin/can.rs @@ -43,7 +43,7 @@ async fn main(_spawner: Spawner) { // To synchronise to the bus the RX input needs to see a high level. // Use `mem::forget()` to release the borrow on the pin but keep the // pull-up resistor enabled. - let rx_pin = Input::new(&mut rx, Pull::Up); + let rx_pin = Input::new(rx.reborrow(), Pull::Up); core::mem::forget(rx_pin); let mut can = embassy_stm32::can::Can::new(can, rx, tx, Irqs); diff --git a/tests/stm32/src/bin/cordic.rs b/tests/stm32/src/bin/cordic.rs index 879ad56b6..e86eea58b 100644 --- a/tests/stm32/src/bin/cordic.rs +++ b/tests/stm32/src/bin/cordic.rs @@ -82,8 +82,8 @@ async fn main(_spawner: Spawner) { let cnt1 = defmt::unwrap!( cordic .async_calc_32bit( - &mut write_dma, - &mut read_dma, + write_dma.reborrow(), + read_dma.reborrow(), &input_q1_31[2..], &mut output_q1_31[cnt0..], true, diff --git a/tests/stm32/src/bin/gpio.rs b/tests/stm32/src/bin/gpio.rs index 4a2584b4e..40b03201c 100644 --- a/tests/stm32/src/bin/gpio.rs +++ b/tests/stm32/src/bin/gpio.rs @@ -20,10 +20,10 @@ async fn main(_spawner: Spawner) { // Test initial output { - let b = Input::new(&mut b, Pull::None); + let b = Input::new(b.reborrow(), Pull::None); { - let a = Output::new(&mut a, Level::Low, Speed::Low); + let a = Output::new(a.reborrow(), Level::Low, Speed::Low); delay(); assert!(b.is_low()); assert!(!b.is_high()); @@ -31,7 +31,7 @@ async fn main(_spawner: Spawner) { assert!(!a.is_set_high()); } { - let mut a = Output::new(&mut a, Level::High, Speed::Low); + let mut a = Output::new(a.reborrow(), Level::High, Speed::Low); delay(); assert!(!b.is_low()); assert!(b.is_high()); @@ -68,10 +68,10 @@ async fn main(_spawner: Spawner) { // Test input no pull { - let b = Input::new(&mut b, Pull::None); + let b = Input::new(b.reborrow(), Pull::None); // no pull, the status is undefined - let mut a = Output::new(&mut a, Level::Low, Speed::Low); + let mut a = Output::new(a.reborrow(), Level::Low, Speed::Low); delay(); assert!(b.is_low()); a.set_high(); @@ -81,11 +81,11 @@ async fn main(_spawner: Spawner) { // Test input pulldown { - let b = Input::new(&mut b, Pull::Down); + let b = Input::new(b.reborrow(), Pull::Down); delay(); assert!(b.is_low()); - let mut a = Output::new(&mut a, Level::Low, Speed::Low); + let mut a = Output::new(a.reborrow(), Level::Low, Speed::Low); delay(); assert!(b.is_low()); a.set_high(); @@ -95,11 +95,11 @@ async fn main(_spawner: Spawner) { // Test input pullup { - let b = Input::new(&mut b, Pull::Up); + let b = Input::new(b.reborrow(), Pull::Up); delay(); assert!(b.is_high()); - let mut a = Output::new(&mut a, Level::Low, Speed::Low); + let mut a = Output::new(a.reborrow(), Level::Low, Speed::Low); delay(); assert!(b.is_low()); a.set_high(); @@ -109,10 +109,10 @@ async fn main(_spawner: Spawner) { // Test output open drain { - let b = Input::new(&mut b, Pull::Down); + let b = Input::new(b.reborrow(), Pull::Down); // no pull, the status is undefined - let mut a = OutputOpenDrain::new(&mut a, Level::Low, Speed::Low); + let mut a = OutputOpenDrain::new(a.reborrow(), Level::Low, Speed::Low); delay(); assert!(b.is_low()); a.set_high(); // High-Z output @@ -124,12 +124,12 @@ async fn main(_spawner: Spawner) { // Test initial output { //Flex pin configured as input - let mut b = Flex::new(&mut b); + let mut b = Flex::new(b.reborrow()); b.set_as_input(Pull::None); { //Flex pin configured as output - let mut a = Flex::new(&mut a); //Flex pin configured as output + let mut a = Flex::new(a.reborrow()); //Flex pin configured as output a.set_low(); // Pin state must be set before configuring the pin, thus we avoid unknown state a.set_as_output(Speed::Low); delay(); @@ -137,7 +137,7 @@ async fn main(_spawner: Spawner) { } { //Flex pin configured as output - let mut a = Flex::new(&mut a); + let mut a = Flex::new(a.reborrow()); a.set_high(); a.set_as_output(Speed::Low); @@ -148,10 +148,10 @@ async fn main(_spawner: Spawner) { // Test input no pull { - let mut b = Flex::new(&mut b); + let mut b = Flex::new(b.reborrow()); b.set_as_input(Pull::None); // no pull, the status is undefined - let mut a = Flex::new(&mut a); + let mut a = Flex::new(a.reborrow()); a.set_low(); a.set_as_output(Speed::Low); @@ -164,12 +164,12 @@ async fn main(_spawner: Spawner) { // Test input pulldown { - let mut b = Flex::new(&mut b); + let mut b = Flex::new(b.reborrow()); b.set_as_input(Pull::Down); delay(); assert!(b.is_low()); - let mut a = Flex::new(&mut a); + let mut a = Flex::new(a.reborrow()); a.set_low(); a.set_as_output(Speed::Low); delay(); @@ -181,12 +181,12 @@ async fn main(_spawner: Spawner) { // Test input pullup { - let mut b = Flex::new(&mut b); + let mut b = Flex::new(b.reborrow()); b.set_as_input(Pull::Up); delay(); assert!(b.is_high()); - let mut a = Flex::new(&mut a); + let mut a = Flex::new(a.reborrow()); a.set_high(); a.set_as_output(Speed::Low); delay(); @@ -198,10 +198,10 @@ async fn main(_spawner: Spawner) { // Test output open drain { - let mut b = Flex::new(&mut b); + let mut b = Flex::new(b.reborrow()); b.set_as_input(Pull::Down); - let mut a = Flex::new(&mut a); + let mut a = Flex::new(a.reborrow()); a.set_low(); a.set_as_input_output(Speed::Low); delay(); diff --git a/tests/stm32/src/bin/sdmmc.rs b/tests/stm32/src/bin/sdmmc.rs index a6bc117c0..07f17b569 100644 --- a/tests/stm32/src/bin/sdmmc.rs +++ b/tests/stm32/src/bin/sdmmc.rs @@ -40,15 +40,15 @@ async fn main(_spawner: Spawner) { // ======== Try 4bit. ============== info!("initializing in 4-bit mode..."); let mut s = Sdmmc::new_4bit( - &mut sdmmc, + sdmmc.reborrow(), Irqs, - &mut dma, - &mut clk, - &mut cmd, - &mut d0, - &mut d1, - &mut d2, - &mut d3, + dma.reborrow(), + clk.reborrow(), + cmd.reborrow(), + d0.reborrow(), + d1.reborrow(), + d2.reborrow(), + d3.reborrow(), Default::default(), ); @@ -89,12 +89,12 @@ async fn main(_spawner: Spawner) { // ======== Try 1bit. ============== info!("initializing in 1-bit mode..."); let mut s = Sdmmc::new_1bit( - &mut sdmmc, + sdmmc.reborrow(), Irqs, - &mut dma, - &mut clk, - &mut cmd, - &mut d0, + dma.reborrow(), + clk.reborrow(), + cmd.reborrow(), + d0.reborrow(), Default::default(), ); diff --git a/tests/stm32/src/bin/spi.rs b/tests/stm32/src/bin/spi.rs index 9712a8c5a..e8310866a 100644 --- a/tests/stm32/src/bin/spi.rs +++ b/tests/stm32/src/bin/spi.rs @@ -25,10 +25,10 @@ async fn main(_spawner: Spawner) { spi_config.frequency = Hertz(1_000_000); let mut spi = Spi::new_blocking( - &mut spi_peri, - &mut sck, // Arduino D13 - &mut mosi, // Arduino D11 - &mut miso, // Arduino D12 + spi_peri.reborrow(), + sck.reborrow(), // Arduino D13 + mosi.reborrow(), // Arduino D11 + miso.reborrow(), // Arduino D12 spi_config, ); @@ -43,20 +43,20 @@ async fn main(_spawner: Spawner) { defmt::assert!(!embassy_stm32::pac::RCC.apb2enr().read().spi1en()); // test rx-only configuration - let mut spi = Spi::new_blocking_rxonly(&mut spi_peri, &mut sck, &mut miso, spi_config); - let mut mosi_out = Output::new(&mut mosi, Level::Low, Speed::VeryHigh); + let mut spi = Spi::new_blocking_rxonly(spi_peri.reborrow(), sck.reborrow(), miso.reborrow(), spi_config); + let mut mosi_out = Output::new(mosi.reborrow(), Level::Low, Speed::VeryHigh); test_rx::(&mut spi, &mut mosi_out); test_rx::(&mut spi, &mut mosi_out); drop(spi); drop(mosi_out); - let mut spi = Spi::new_blocking_txonly(&mut spi_peri, &mut sck, &mut mosi, spi_config); + let mut spi = Spi::new_blocking_txonly(spi_peri.reborrow(), sck.reborrow(), mosi.reborrow(), spi_config); test_tx::(&mut spi); test_tx::(&mut spi); drop(spi); - let mut spi = Spi::new_blocking_txonly_nosck(&mut spi_peri, &mut mosi, spi_config); + let mut spi = Spi::new_blocking_txonly_nosck(spi_peri.reborrow(), mosi.reborrow(), spi_config); test_tx::(&mut spi); test_tx::(&mut spi); drop(spi); diff --git a/tests/stm32/src/bin/spi_dma.rs b/tests/stm32/src/bin/spi_dma.rs index 307409a16..b4fdb8faa 100644 --- a/tests/stm32/src/bin/spi_dma.rs +++ b/tests/stm32/src/bin/spi_dma.rs @@ -27,12 +27,12 @@ async fn main(_spawner: Spawner) { spi_config.frequency = Hertz(1_000_000); let mut spi = Spi::new( - &mut spi_peri, - &mut sck, // Arduino D13 - &mut mosi, // Arduino D11 - &mut miso, // Arduino D12 - &mut tx_dma, - &mut rx_dma, + spi_peri.reborrow(), + sck.reborrow(), // Arduino D13 + mosi.reborrow(), // Arduino D11 + miso.reborrow(), // Arduino D12 + tx_dma.reborrow(), + rx_dma.reborrow(), spi_config, ); @@ -42,28 +42,34 @@ async fn main(_spawner: Spawner) { // test rx-only configuration let mut spi = Spi::new_rxonly( - &mut spi_peri, - &mut sck, - &mut miso, + spi_peri.reborrow(), + sck.reborrow(), + miso.reborrow(), // SPIv1/f1 requires txdma even if rxonly. #[cfg(not(feature = "spi-v345"))] - &mut tx_dma, - &mut rx_dma, + tx_dma.reborrow(), + rx_dma.reborrow(), spi_config, ); - let mut mosi_out = Output::new(&mut mosi, Level::Low, Speed::VeryHigh); + let mut mosi_out = Output::new(mosi.reborrow(), Level::Low, Speed::VeryHigh); test_rx::(&mut spi, &mut mosi_out).await; test_rx::(&mut spi, &mut mosi_out).await; drop(spi); drop(mosi_out); - let mut spi = Spi::new_txonly(&mut spi_peri, &mut sck, &mut mosi, &mut tx_dma, spi_config); + let mut spi = Spi::new_txonly( + spi_peri.reborrow(), + sck.reborrow(), + mosi.reborrow(), + tx_dma.reborrow(), + spi_config, + ); test_tx::(&mut spi).await; test_tx::(&mut spi).await; drop(spi); - let mut spi = Spi::new_txonly_nosck(&mut spi_peri, &mut mosi, &mut tx_dma, spi_config); + let mut spi = Spi::new_txonly_nosck(spi_peri.reborrow(), mosi.reborrow(), tx_dma.reborrow(), spi_config); test_tx::(&mut spi).await; test_tx::(&mut spi).await; drop(spi); diff --git a/tests/stm32/src/bin/ucpd.rs b/tests/stm32/src/bin/ucpd.rs index bd7b35d6b..97aefe1a0 100644 --- a/tests/stm32/src/bin/ucpd.rs +++ b/tests/stm32/src/bin/ucpd.rs @@ -9,7 +9,7 @@ use defmt::{assert, assert_eq}; use embassy_executor::Spawner; use embassy_futures::join::join; use embassy_stm32::ucpd::{self, CcPhy, CcPull, CcSel, CcVState, RxError, Ucpd}; -use embassy_stm32::{bind_interrupts, peripherals}; +use embassy_stm32::{bind_interrupts, peripherals, Peri}; use embassy_time::Timer; bind_interrupts!(struct Irqs { @@ -28,8 +28,8 @@ async fn wait_for_vstate(cc_phy: &mut CcPhy<'_, T>, vstate: C async fn source( mut ucpd: Ucpd<'static, peripherals::UCPD1>, - rx_dma: peripherals::DMA1_CH1, - tx_dma: peripherals::DMA1_CH2, + rx_dma: Peri<'static, peripherals::DMA1_CH1>, + tx_dma: Peri<'static, peripherals::DMA1_CH2>, ) { debug!("source: setting default current pull-up"); ucpd.cc_phy().set_pull(CcPull::SourceDefaultUsb); @@ -65,8 +65,8 @@ async fn source( async fn sink( mut ucpd: Ucpd<'static, peripherals::UCPD2>, - rx_dma: peripherals::DMA1_CH3, - tx_dma: peripherals::DMA1_CH4, + rx_dma: Peri<'static, peripherals::DMA1_CH3>, + tx_dma: Peri<'static, peripherals::DMA1_CH4>, ) { debug!("sink: setting pull down"); ucpd.cc_phy().set_pull(CcPull::Sink); diff --git a/tests/stm32/src/bin/usart.rs b/tests/stm32/src/bin/usart.rs index 2f601ad0e..129c7b692 100644 --- a/tests/stm32/src/bin/usart.rs +++ b/tests/stm32/src/bin/usart.rs @@ -22,7 +22,7 @@ async fn main(_spawner: Spawner) { { let config = Config::default(); - let mut usart = Uart::new_blocking(&mut usart, &mut rx, &mut tx, config).unwrap(); + let mut usart = Uart::new_blocking(usart.reborrow(), rx.reborrow(), tx.reborrow(), config).unwrap(); // We can't send too many bytes, they have to fit in the FIFO. // This is because we aren't sending+receiving at the same time. @@ -45,7 +45,7 @@ async fn main(_spawner: Spawner) { // Test error handling with with an overflow error { let config = Config::default(); - let mut usart = Uart::new_blocking(&mut usart, &mut rx, &mut tx, config).unwrap(); + let mut usart = Uart::new_blocking(usart.reborrow(), rx.reborrow(), tx.reborrow(), config).unwrap(); // Send enough bytes to fill the RX FIFOs off all USART versions. let data = [0; 64]; @@ -75,7 +75,7 @@ async fn main(_spawner: Spawner) { let mut config = Config::default(); config.baudrate = baudrate; - let mut usart = match Uart::new_blocking(&mut usart, &mut rx, &mut tx, config) { + let mut usart = match Uart::new_blocking(usart.reborrow(), rx.reborrow(), tx.reborrow(), config) { Ok(x) => x, Err(ConfigError::BaudrateTooHigh) => { info!("baudrate too high"); From d17d43735f46fe808e7c9756d7192222b7d2ee2a Mon Sep 17 00:00:00 2001 From: Sebastian Quilitz Date: Thu, 27 Mar 2025 16:50:26 +0000 Subject: [PATCH 0881/1217] embassy-rp: Move Spinlock implementation out of critical_section_impl --- embassy-rp/src/critical_section_impl.rs | 43 +------------- embassy-rp/src/lib.rs | 1 + embassy-rp/src/spinlock.rs | 75 +++++++++++++++++++++++++ 3 files changed, 77 insertions(+), 42 deletions(-) create mode 100644 embassy-rp/src/spinlock.rs diff --git a/embassy-rp/src/critical_section_impl.rs b/embassy-rp/src/critical_section_impl.rs index d233e6fab..2e4e8f716 100644 --- a/embassy-rp/src/critical_section_impl.rs +++ b/embassy-rp/src/critical_section_impl.rs @@ -1,6 +1,7 @@ use core::sync::atomic::{AtomicU8, Ordering}; use crate::pac; +use crate::spinlock::Spinlock; struct RpSpinlockCs; critical_section::set_impl!(RpSpinlockCs); @@ -92,46 +93,4 @@ impl RpSpinlockCs { } } -pub struct Spinlock(core::marker::PhantomData<()>) -where - Spinlock: SpinlockValid; - -impl Spinlock -where - Spinlock: SpinlockValid, -{ - /// Try to claim the spinlock. Will return `Some(Self)` if the lock is obtained, and `None` if the lock is - /// already in use somewhere else. - pub fn try_claim() -> Option { - let lock = pac::SIO.spinlock(N).read(); - if lock > 0 { - Some(Self(core::marker::PhantomData)) - } else { - None - } - } - - /// Clear a locked spin-lock. - /// - /// # Safety - /// - /// Only call this function if you hold the spin-lock. - pub unsafe fn release() { - // Write (any value): release the lock - pac::SIO.spinlock(N).write_value(1); - } -} - -impl Drop for Spinlock -where - Spinlock: SpinlockValid, -{ - fn drop(&mut self) { - // This is safe because we own the object, and hence hold the lock. - unsafe { Self::release() } - } -} - pub(crate) type Spinlock31 = Spinlock<31>; -pub trait SpinlockValid {} -impl SpinlockValid for Spinlock<31> {} diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs index 35099d07b..01d26b8e9 100644 --- a/embassy-rp/src/lib.rs +++ b/embassy-rp/src/lib.rs @@ -41,6 +41,7 @@ pub mod rom_data; #[cfg(feature = "rp2040")] pub mod rtc; pub mod spi; +mod spinlock; #[cfg(feature = "time-driver")] pub mod time_driver; #[cfg(feature = "_rp235x")] diff --git a/embassy-rp/src/spinlock.rs b/embassy-rp/src/spinlock.rs new file mode 100644 index 000000000..7effd2ae0 --- /dev/null +++ b/embassy-rp/src/spinlock.rs @@ -0,0 +1,75 @@ +use crate::pac; + +pub struct Spinlock(core::marker::PhantomData<()>) +where + Spinlock: SpinlockValid; + +impl Spinlock +where + Spinlock: SpinlockValid, +{ + /// Try to claim the spinlock. Will return `Some(Self)` if the lock is obtained, and `None` if the lock is + /// already in use somewhere else. + pub fn try_claim() -> Option { + let lock = pac::SIO.spinlock(N).read(); + if lock > 0 { + Some(Self(core::marker::PhantomData)) + } else { + None + } + } + + /// Clear a locked spin-lock. + /// + /// # Safety + /// + /// Only call this function if you hold the spin-lock. + pub unsafe fn release() { + // Write (any value): release the lock + pac::SIO.spinlock(N).write_value(1); + } +} + +impl Drop for Spinlock +where + Spinlock: SpinlockValid, +{ + fn drop(&mut self) { + // This is safe because we own the object, and hence hold the lock. + unsafe { Self::release() } + } +} + +pub trait SpinlockValid {} +impl SpinlockValid for Spinlock<0> {} +impl SpinlockValid for Spinlock<1> {} +impl SpinlockValid for Spinlock<2> {} +impl SpinlockValid for Spinlock<3> {} +impl SpinlockValid for Spinlock<4> {} +impl SpinlockValid for Spinlock<5> {} +impl SpinlockValid for Spinlock<6> {} +impl SpinlockValid for Spinlock<7> {} +impl SpinlockValid for Spinlock<8> {} +impl SpinlockValid for Spinlock<9> {} +impl SpinlockValid for Spinlock<10> {} +impl SpinlockValid for Spinlock<11> {} +impl SpinlockValid for Spinlock<12> {} +impl SpinlockValid for Spinlock<13> {} +impl SpinlockValid for Spinlock<14> {} +impl SpinlockValid for Spinlock<15> {} +impl SpinlockValid for Spinlock<16> {} +impl SpinlockValid for Spinlock<17> {} +impl SpinlockValid for Spinlock<18> {} +impl SpinlockValid for Spinlock<19> {} +impl SpinlockValid for Spinlock<20> {} +impl SpinlockValid for Spinlock<21> {} +impl SpinlockValid for Spinlock<22> {} +impl SpinlockValid for Spinlock<23> {} +impl SpinlockValid for Spinlock<24> {} +impl SpinlockValid for Spinlock<25> {} +impl SpinlockValid for Spinlock<26> {} +impl SpinlockValid for Spinlock<27> {} +impl SpinlockValid for Spinlock<28> {} +impl SpinlockValid for Spinlock<29> {} +impl SpinlockValid for Spinlock<30> {} +impl SpinlockValid for Spinlock<31> {} From 0621087f6ff12d1e6fc0d566fabc2ca9130f633f Mon Sep 17 00:00:00 2001 From: techmccat Date: Thu, 27 Mar 2025 17:42:55 +0100 Subject: [PATCH 0882/1217] stm32: allow using LSI/LSE as SYSCLK on g0/c0 --- embassy-stm32/src/rcc/c0.rs | 7 +++++-- embassy-stm32/src/rcc/g0.rs | 7 +++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/embassy-stm32/src/rcc/c0.rs b/embassy-stm32/src/rcc/c0.rs index 04cbe83ed..4ec8e7780 100644 --- a/embassy-stm32/src/rcc/c0.rs +++ b/embassy-stm32/src/rcc/c0.rs @@ -3,6 +3,7 @@ pub use crate::pac::rcc::vals::{ Hpre as AHBPrescaler, Hsidiv as HsiSysDiv, Hsikerdiv as HsiKerDiv, Ppre as APBPrescaler, Sw as Sysclk, }; use crate::pac::{FLASH, RCC}; +use crate::rcc::LSI_FREQ; use crate::time::Hertz; /// HSI speed @@ -121,9 +122,13 @@ pub(crate) unsafe fn init(config: Config) { } }; + let rtc = config.ls.init(); + let sys = match config.sys { Sysclk::HSISYS => unwrap!(hsisys), Sysclk::HSE => unwrap!(hse), + Sysclk::LSI => { assert!(config.ls.lsi); LSI_FREQ } + Sysclk::LSE => unwrap!(config.ls.lse).frequency, _ => unreachable!(), }; @@ -162,8 +167,6 @@ pub(crate) unsafe fn init(config: Config) { RCC.cr().modify(|w| w.set_hsion(false)); } - let rtc = config.ls.init(); - config.mux.init(); set_clocks!( diff --git a/embassy-stm32/src/rcc/g0.rs b/embassy-stm32/src/rcc/g0.rs index f55b18290..c84ac5166 100644 --- a/embassy-stm32/src/rcc/g0.rs +++ b/embassy-stm32/src/rcc/g0.rs @@ -5,6 +5,7 @@ pub use crate::pac::rcc::vals::{ Pllr as PllRDiv, Pllsrc as PllSource, Ppre as APBPrescaler, Sw as Sysclk, }; use crate::pac::{FLASH, PWR, RCC}; +use crate::rcc::LSI_FREQ; use crate::time::Hertz; /// HSI speed @@ -234,10 +235,14 @@ pub(crate) unsafe fn init(config: Config) { }) .unwrap_or_default(); + let rtc = config.ls.init(); + let sys = match config.sys { Sysclk::HSI => unwrap!(hsisys), Sysclk::HSE => unwrap!(hse), Sysclk::PLL1_R => unwrap!(pll.pll_r), + Sysclk::LSI => { assert!(config.ls.lsi); LSI_FREQ } + Sysclk::LSE => unwrap!(config.ls.lse).frequency, _ => unreachable!(), }; @@ -286,8 +291,6 @@ pub(crate) unsafe fn init(config: Config) { PWR.cr1().modify(|w| w.set_lpr(true)); } - let rtc = config.ls.init(); - config.mux.init(); set_clocks!( From ce578b62b8ac7d1d4ad3a96e7a085e6f3c0722eb Mon Sep 17 00:00:00 2001 From: techmccat Date: Fri, 28 Mar 2025 10:45:14 +0100 Subject: [PATCH 0883/1217] stm32: run cargo fmt --- embassy-stm32/src/rcc/c0.rs | 5 ++++- embassy-stm32/src/rcc/g0.rs | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/rcc/c0.rs b/embassy-stm32/src/rcc/c0.rs index 4ec8e7780..0b749bcff 100644 --- a/embassy-stm32/src/rcc/c0.rs +++ b/embassy-stm32/src/rcc/c0.rs @@ -127,7 +127,10 @@ pub(crate) unsafe fn init(config: Config) { let sys = match config.sys { Sysclk::HSISYS => unwrap!(hsisys), Sysclk::HSE => unwrap!(hse), - Sysclk::LSI => { assert!(config.ls.lsi); LSI_FREQ } + Sysclk::LSI => { + assert!(config.ls.lsi); + LSI_FREQ + } Sysclk::LSE => unwrap!(config.ls.lse).frequency, _ => unreachable!(), }; diff --git a/embassy-stm32/src/rcc/g0.rs b/embassy-stm32/src/rcc/g0.rs index c84ac5166..2dbf62a9f 100644 --- a/embassy-stm32/src/rcc/g0.rs +++ b/embassy-stm32/src/rcc/g0.rs @@ -241,7 +241,10 @@ pub(crate) unsafe fn init(config: Config) { Sysclk::HSI => unwrap!(hsisys), Sysclk::HSE => unwrap!(hse), Sysclk::PLL1_R => unwrap!(pll.pll_r), - Sysclk::LSI => { assert!(config.ls.lsi); LSI_FREQ } + Sysclk::LSI => { + assert!(config.ls.lsi); + LSI_FREQ + } Sysclk::LSE => unwrap!(config.ls.lse).frequency, _ => unreachable!(), }; From 695a6da322aa2d75c8f702b2ed8b67f9ad12c3a0 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Fri, 28 Mar 2025 18:59:02 +0100 Subject: [PATCH 0884/1217] Statically allocate task pools on stable Rust. Thanks @0e4ef622 for the awesome idea of how to do it and the first implementation. Co-Authored-By: Matthew Tran <0e4ef622@gmail.com> --- embassy-executor-macros/src/macros/task.rs | 38 +++- embassy-executor/Cargo.toml | 95 ---------- embassy-executor/README.md | 27 +-- embassy-executor/build.rs | 92 --------- embassy-executor/src/lib.rs | 176 ++++++++++-------- examples/boot/application/nrf/Cargo.toml | 2 +- examples/boot/application/rp/Cargo.toml | 2 +- examples/boot/application/stm32f3/Cargo.toml | 2 +- examples/boot/application/stm32f7/Cargo.toml | 2 +- examples/boot/application/stm32h7/Cargo.toml | 2 +- examples/boot/application/stm32l0/Cargo.toml | 2 +- examples/boot/application/stm32l1/Cargo.toml | 2 +- examples/boot/application/stm32l4/Cargo.toml | 2 +- .../boot/application/stm32wb-dfu/Cargo.toml | 2 +- examples/boot/application/stm32wl/Cargo.toml | 2 +- examples/lpc55s69/Cargo.toml | 2 +- examples/mspm0c1104/Cargo.toml | 2 +- examples/mspm0g3507/Cargo.toml | 2 +- examples/mspm0g3519/Cargo.toml | 2 +- examples/mspm0l1306/Cargo.toml | 2 +- examples/mspm0l2228/Cargo.toml | 2 +- examples/nrf51/Cargo.toml | 2 +- examples/nrf52810/Cargo.toml | 2 +- examples/nrf52840/Cargo.toml | 2 +- examples/nrf5340/Cargo.toml | 2 +- examples/nrf54l15/Cargo.toml | 2 +- examples/nrf9151/ns/Cargo.toml | 2 +- examples/nrf9151/s/Cargo.toml | 2 +- examples/nrf9160/Cargo.toml | 2 +- examples/rp/Cargo.toml | 2 +- examples/rp235x/Cargo.toml | 2 +- examples/std/Cargo.toml | 2 +- examples/stm32f4/Cargo.toml | 2 +- examples/stm32f469/Cargo.toml | 2 +- examples/stm32f7/Cargo.toml | 2 +- examples/stm32h5/Cargo.toml | 2 +- examples/stm32h7/Cargo.toml | 2 +- examples/stm32h723/Cargo.toml | 2 +- examples/stm32h735/Cargo.toml | 2 +- examples/stm32h755cm4/Cargo.toml | 2 +- examples/stm32h755cm7/Cargo.toml | 2 +- examples/stm32h7b0/Cargo.toml | 2 +- examples/stm32h7rs/Cargo.toml | 2 +- examples/stm32l4/Cargo.toml | 2 +- examples/stm32l432/Cargo.toml | 2 +- examples/stm32l5/Cargo.toml | 2 +- examples/stm32u5/Cargo.toml | 2 +- examples/stm32wb/Cargo.toml | 2 +- examples/stm32wba/Cargo.toml | 2 +- examples/stm32wl/Cargo.toml | 2 +- tests/nrf/Cargo.toml | 2 +- tests/rp/Cargo.toml | 2 +- tests/stm32/Cargo.toml | 2 +- 53 files changed, 187 insertions(+), 337 deletions(-) diff --git a/embassy-executor-macros/src/macros/task.rs b/embassy-executor-macros/src/macros/task.rs index e8134c6a9..8a2a7fdb9 100644 --- a/embassy-executor-macros/src/macros/task.rs +++ b/embassy-executor-macros/src/macros/task.rs @@ -145,9 +145,43 @@ pub fn run(args: TokenStream, item: TokenStream) -> TokenStream { }; #[cfg(not(feature = "nightly"))] let mut task_outer_body = quote! { + const fn __task_pool_size(_: F) -> usize + where + F: #embassy_executor::_export::TaskFn, + { + ::core::mem::size_of::< + #embassy_executor::raw::TaskPool + >() + } + const fn __task_pool_align(_: F) -> usize + where + F: #embassy_executor::_export::TaskFn, + { + ::core::mem::align_of::< + #embassy_executor::raw::TaskPool + >() + } + + const fn __task_pool_new(_: F) -> #embassy_executor::raw::TaskPool + where + F: #embassy_executor::_export::TaskFn, + { + #embassy_executor::raw::TaskPool::new() + } + + const fn __task_pool_get(_: F) -> &'static #embassy_executor::raw::TaskPool + where + F: #embassy_executor::_export::TaskFn + { + unsafe { &*POOL.get().cast() } + } + const POOL_SIZE: usize = #pool_size; - static POOL: #embassy_executor::_export::TaskPoolRef = #embassy_executor::_export::TaskPoolRef::new(); - unsafe { POOL.get::<_, POOL_SIZE>()._spawn_async_fn(move || #task_inner_ident(#(#full_args,)*)) } + static POOL: #embassy_executor::_export::TaskPoolHolder< + {__task_pool_size(#task_inner_ident)}, + {__task_pool_align(#task_inner_ident)}, + > = unsafe { ::core::mem::transmute(__task_pool_new(#task_inner_ident)) }; + unsafe { __task_pool_get(#task_inner_ident)._spawn_async_fn(move || #task_inner_ident(#(#full_args,)*)) } }; let task_outer_attrs = task_inner.attrs.clone(); diff --git a/embassy-executor/Cargo.toml b/embassy-executor/Cargo.toml index d6f24ce84..79d899c61 100644 --- a/embassy-executor/Cargo.toml +++ b/embassy-executor/Cargo.toml @@ -108,98 +108,3 @@ timer-item-payload-size-2 = ["_timer-item-payload"] timer-item-payload-size-4 = ["_timer-item-payload"] ## 8 bytes timer-item-payload-size-8 = ["_timer-item-payload"] - -#! ### Task Arena Size -#! Sets the [task arena](#task-arena) size. Necessary if you’re not using `nightly`. -#! -#!

-#! Preconfigured Task Arena Sizes: -#! -#! - -# BEGIN AUTOGENERATED CONFIG FEATURES -# Generated by gen_config.py. DO NOT EDIT. -## 64 -task-arena-size-64 = [] -## 128 -task-arena-size-128 = [] -## 192 -task-arena-size-192 = [] -## 256 -task-arena-size-256 = [] -## 320 -task-arena-size-320 = [] -## 384 -task-arena-size-384 = [] -## 512 -task-arena-size-512 = [] -## 640 -task-arena-size-640 = [] -## 768 -task-arena-size-768 = [] -## 1024 -task-arena-size-1024 = [] -## 1280 -task-arena-size-1280 = [] -## 1536 -task-arena-size-1536 = [] -## 2048 -task-arena-size-2048 = [] -## 2560 -task-arena-size-2560 = [] -## 3072 -task-arena-size-3072 = [] -## 4096 (default) -task-arena-size-4096 = [] # Default -## 5120 -task-arena-size-5120 = [] -## 6144 -task-arena-size-6144 = [] -## 8192 -task-arena-size-8192 = [] -## 10240 -task-arena-size-10240 = [] -## 12288 -task-arena-size-12288 = [] -## 16384 -task-arena-size-16384 = [] -## 20480 -task-arena-size-20480 = [] -## 24576 -task-arena-size-24576 = [] -## 32768 -task-arena-size-32768 = [] -## 40960 -task-arena-size-40960 = [] -## 49152 -task-arena-size-49152 = [] -## 65536 -task-arena-size-65536 = [] -## 81920 -task-arena-size-81920 = [] -## 98304 -task-arena-size-98304 = [] -## 131072 -task-arena-size-131072 = [] -## 163840 -task-arena-size-163840 = [] -## 196608 -task-arena-size-196608 = [] -## 262144 -task-arena-size-262144 = [] -## 327680 -task-arena-size-327680 = [] -## 393216 -task-arena-size-393216 = [] -## 524288 -task-arena-size-524288 = [] -## 655360 -task-arena-size-655360 = [] -## 786432 -task-arena-size-786432 = [] -## 1048576 -task-arena-size-1048576 = [] - -# END AUTOGENERATED CONFIG FEATURES - -#!
diff --git a/embassy-executor/README.md b/embassy-executor/README.md index 074c73555..85f15edbb 100644 --- a/embassy-executor/README.md +++ b/embassy-executor/README.md @@ -3,35 +3,10 @@ An async/await executor designed for embedded usage. - No `alloc`, no heap needed. -- With nightly Rust, task futures can be fully statically allocated. +- Tasks are statically allocated. Each task gets its own `static`, with the exact size to hold the task (or multiple instances of it, if using `pool_size`) calculated automatically at compile time. If tasks don't fit in RAM, this is detected at compile time by the linker. Runtime panics due to running out of memory are not possible. - No "fixed capacity" data structures, executor works with 1 or 1000 tasks without needing config/tuning. - Integrated timer queue: sleeping is easy, just do `Timer::after_secs(1).await;`. - No busy-loop polling: CPU sleeps when there's no work to do, using interrupts or `WFE/SEV`. - Efficient polling: a wake will only poll the woken task, not all of them. - Fair: a task can't monopolize CPU time even if it's constantly being woken. All other tasks get a chance to run before a given task gets polled for the second time. - Creating multiple executor instances is supported, to run tasks with multiple priority levels. This allows higher-priority tasks to preempt lower-priority tasks. - -## Task arena - -When the `nightly` Cargo feature is not enabled, `embassy-executor` allocates tasks out of an arena (a very simple bump allocator). - -If the task arena gets full, the program will panic at runtime. To guarantee this doesn't happen, you must set the size to the sum of sizes of all tasks. - -Tasks are allocated from the arena when spawned for the first time. If the task exits, the allocation is not released to the arena, but can be reused to spawn the task again. For multiple-instance tasks (like `#[embassy_executor::task(pool_size = 4)]`), the first spawn will allocate memory for all instances. This is done for performance and to increase predictability (for example, spawning at least 1 instance of every task at boot guarantees an immediate panic if the arena is too small, while allocating instances on-demand could delay the panic to only when the program is under load). - -The arena size can be configured in two ways: - -- Via Cargo features: enable a Cargo feature like `task-arena-size-8192`. Only a selection of values - is available, see [Task Area Sizes](#task-arena-size) for reference. -- Via environment variables at build time: set the variable named `EMBASSY_EXECUTOR_TASK_ARENA_SIZE`. For example - `EMBASSY_EXECUTOR_TASK_ARENA_SIZE=4321 cargo build`. You can also set them in the `[env]` section of `.cargo/config.toml`. - Any value can be set, unlike with Cargo features. - -Environment variables take precedence over Cargo features. If two Cargo features are enabled for the same setting -with different values, compilation fails. - -## Statically allocating tasks - -When using nightly Rust, enable the `nightly` Cargo feature. This will make `embassy-executor` use the `type_alias_impl_trait` feature to allocate all tasks in `static`s. Each task gets its own `static`, with the exact size to hold the task (or multiple instances of it, if using `pool_size`) calculated automatically at compile time. If tasks don't fit in RAM, this is detected at compile time by the linker. Runtime panics due to running out of memory are not possible. - -The configured arena size is ignored, no arena is used at all. diff --git a/embassy-executor/build.rs b/embassy-executor/build.rs index 8a41d7503..37becde3e 100644 --- a/embassy-executor/build.rs +++ b/embassy-executor/build.rs @@ -1,99 +1,7 @@ -use std::collections::HashMap; -use std::fmt::Write; -use std::path::PathBuf; -use std::{env, fs}; - #[path = "./build_common.rs"] mod common; -static CONFIGS: &[(&str, usize)] = &[ - // BEGIN AUTOGENERATED CONFIG FEATURES - // Generated by gen_config.py. DO NOT EDIT. - ("TASK_ARENA_SIZE", 4096), - // END AUTOGENERATED CONFIG FEATURES -]; - -struct ConfigState { - value: usize, - seen_feature: bool, - seen_env: bool, -} - fn main() { - let crate_name = env::var("CARGO_PKG_NAME") - .unwrap() - .to_ascii_uppercase() - .replace('-', "_"); - - // only rebuild if build.rs changed. Otherwise Cargo will rebuild if any - // other file changed. - println!("cargo:rerun-if-changed=build.rs"); - - // Rebuild if config envvar changed. - for (name, _) in CONFIGS { - println!("cargo:rerun-if-env-changed={crate_name}_{name}"); - } - - let mut configs = HashMap::new(); - for (name, default) in CONFIGS { - configs.insert( - *name, - ConfigState { - value: *default, - seen_env: false, - seen_feature: false, - }, - ); - } - - let prefix = format!("{crate_name}_"); - for (var, value) in env::vars() { - if let Some(name) = var.strip_prefix(&prefix) { - let Some(cfg) = configs.get_mut(name) else { - panic!("Unknown env var {name}") - }; - - let Ok(value) = value.parse::() else { - panic!("Invalid value for env var {name}: {value}") - }; - - cfg.value = value; - cfg.seen_env = true; - } - - if let Some(feature) = var.strip_prefix("CARGO_FEATURE_") { - if let Some(i) = feature.rfind('_') { - let name = &feature[..i]; - let value = &feature[i + 1..]; - if let Some(cfg) = configs.get_mut(name) { - let Ok(value) = value.parse::() else { - panic!("Invalid value for feature {name}: {value}") - }; - - // envvars take priority. - if !cfg.seen_env { - if cfg.seen_feature { - panic!("multiple values set for feature {}: {} and {}", name, cfg.value, value); - } - - cfg.value = value; - cfg.seen_feature = true; - } - } - } - } - } - - let mut data = String::new(); - - for (name, cfg) in &configs { - writeln!(&mut data, "pub const {}: usize = {};", name, cfg.value).unwrap(); - } - - let out_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap()); - let out_file = out_dir.join("config.rs").to_string_lossy().to_string(); - fs::write(out_file, data).unwrap(); - let mut rustc_cfgs = common::CfgSet::new(); common::set_target_cfgs(&mut rustc_cfgs); } diff --git a/embassy-executor/src/lib.rs b/embassy-executor/src/lib.rs index d816539ac..5485f6a6a 100644 --- a/embassy-executor/src/lib.rs +++ b/embassy-executor/src/lib.rs @@ -50,101 +50,129 @@ pub mod raw; mod spawner; pub use spawner::*; -mod config { - #![allow(unused)] - include!(concat!(env!("OUT_DIR"), "/config.rs")); -} - /// Implementation details for embassy macros. /// Do not use. Used for macros and HALs only. Not covered by semver guarantees. #[doc(hidden)] #[cfg(not(feature = "nightly"))] pub mod _export { - use core::alloc::Layout; - use core::cell::{Cell, UnsafeCell}; + use core::cell::UnsafeCell; use core::future::Future; use core::mem::MaybeUninit; - use core::ptr::null_mut; - use critical_section::{CriticalSection, Mutex}; - - use crate::raw::TaskPool; - - struct Arena { - buf: UnsafeCell>, - ptr: Mutex>, + pub trait TaskFn: Copy { + type Fut: Future + 'static; } - unsafe impl Sync for Arena {} - unsafe impl Send for Arena {} - - impl Arena { - const fn new() -> Self { - Self { - buf: UnsafeCell::new(MaybeUninit::uninit()), - ptr: Mutex::new(Cell::new(null_mut())), + macro_rules! task_fn_impl { + ($($Tn:ident),*) => { + impl TaskFn<($($Tn,)*)> for F + where + F: Copy + FnOnce($($Tn,)*) -> Fut, + Fut: Future + 'static, + { + type Fut = Fut; } - } + }; + } - fn alloc(&'static self, cs: CriticalSection) -> &'static mut MaybeUninit { - let layout = Layout::new::(); + task_fn_impl!(); + task_fn_impl!(T0); + task_fn_impl!(T0, T1); + task_fn_impl!(T0, T1, T2); + task_fn_impl!(T0, T1, T2, T3); + task_fn_impl!(T0, T1, T2, T3, T4); + task_fn_impl!(T0, T1, T2, T3, T4, T5); + task_fn_impl!(T0, T1, T2, T3, T4, T5, T6); + task_fn_impl!(T0, T1, T2, T3, T4, T5, T6, T7); + task_fn_impl!(T0, T1, T2, T3, T4, T5, T6, T7, T8); + task_fn_impl!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9); + task_fn_impl!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10); + task_fn_impl!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11); + task_fn_impl!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12); + task_fn_impl!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13); + task_fn_impl!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14); + task_fn_impl!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15); - let start = self.buf.get().cast::(); - let end = unsafe { start.add(N) }; + #[allow(private_bounds)] + #[repr(C)] + pub struct TaskPoolHolder + where + Align: Alignment, + { + data: UnsafeCell<[MaybeUninit; SIZE]>, + align: Align, + } - let mut ptr = self.ptr.borrow(cs).get(); - if ptr.is_null() { - ptr = self.buf.get().cast::(); - } + unsafe impl Send for TaskPoolHolder where Align: Alignment {} + unsafe impl Sync for TaskPoolHolder where Align: Alignment {} - let bytes_left = (end as usize) - (ptr as usize); - let align_offset = (ptr as usize).next_multiple_of(layout.align()) - (ptr as usize); - - if align_offset + layout.size() > bytes_left { - panic!("embassy-executor: task arena is full. You must increase the arena size, see the documentation for details: https://docs.embassy.dev/embassy-executor/"); - } - - let res = unsafe { ptr.add(align_offset) }; - let ptr = unsafe { ptr.add(align_offset + layout.size()) }; - - self.ptr.borrow(cs).set(ptr); - - unsafe { &mut *(res as *mut MaybeUninit) } + #[allow(private_bounds)] + impl TaskPoolHolder + where + Align: Alignment, + { + pub const fn get(&self) -> *const u8 { + self.data.get().cast() } } - static ARENA: Arena<{ crate::config::TASK_ARENA_SIZE }> = Arena::new(); + #[allow(private_bounds)] + #[repr(transparent)] + pub struct Align([::Archetype; 0]) + where + Self: Alignment; - pub struct TaskPoolRef { - // type-erased `&'static mut TaskPool` - // Needed because statics can't have generics. - ptr: Mutex>, + trait Alignment { + /// A zero-sized type of particular alignment. + type Archetype: Copy + Eq + PartialEq + Send + Sync + Unpin; } - unsafe impl Sync for TaskPoolRef {} - unsafe impl Send for TaskPoolRef {} - impl TaskPoolRef { - pub const fn new() -> Self { - Self { - ptr: Mutex::new(Cell::new(null_mut())), - } - } - - /// Get the pool for this ref, allocating it from the arena the first time. - /// - /// safety: for a given TaskPoolRef instance, must always call with the exact - /// same generic params. - pub unsafe fn get(&'static self) -> &'static TaskPool { - critical_section::with(|cs| { - let ptr = self.ptr.borrow(cs); - if ptr.get().is_null() { - let pool = ARENA.alloc::>(cs); - pool.write(TaskPool::new()); - ptr.set(pool as *mut _ as _); + macro_rules! aligns { + ($($AlignX:ident: $n:literal,)*) => { + $( + #[derive(Copy, Clone, Eq, PartialEq)] + #[repr(align($n))] + struct $AlignX {} + impl Alignment for Align<$n> { + type Archetype = $AlignX; } - - unsafe { &*(ptr.get() as *const _) } - }) - } + )* + }; } + + aligns!( + Align1: 1, + Align2: 2, + Align4: 4, + Align8: 8, + Align16: 16, + Align32: 32, + Align64: 64, + Align128: 128, + Align256: 256, + Align512: 512, + Align1024: 1024, + Align2048: 2048, + Align4096: 4096, + Align8192: 8192, + Align16384: 16384, + ); + #[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))] + aligns!( + Align32768: 32768, + Align65536: 65536, + Align131072: 131072, + Align262144: 262144, + Align524288: 524288, + Align1048576: 1048576, + Align2097152: 2097152, + Align4194304: 4194304, + Align8388608: 8388608, + Align16777216: 16777216, + Align33554432: 33554432, + Align67108864: 67108864, + Align134217728: 134217728, + Align268435456: 268435456, + Align536870912: 536870912, + ); } diff --git a/examples/boot/application/nrf/Cargo.toml b/examples/boot/application/nrf/Cargo.toml index 78227c49c..4ae0e6a77 100644 --- a/examples/boot/application/nrf/Cargo.toml +++ b/examples/boot/application/nrf/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.2", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["task-arena-size-16384", "arch-cortex-m", "executor-thread", "arch-cortex-m", "executor-thread"] } +embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [] } embassy-nrf = { version = "0.3.1", path = "../../../../embassy-nrf", features = ["time-driver-rtc1", "gpiote", ] } embassy-boot = { version = "0.4.0", path = "../../../../embassy-boot", features = [] } diff --git a/examples/boot/application/rp/Cargo.toml b/examples/boot/application/rp/Cargo.toml index 3f0d4cd78..fa4a7d44f 100644 --- a/examples/boot/application/rp/Cargo.toml +++ b/examples/boot/application/rp/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.2", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["task-arena-size-16384", "arch-cortex-m", "executor-thread", "arch-cortex-m", "executor-thread"] } +embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [] } embassy-rp = { version = "0.4.0", path = "../../../../embassy-rp", features = ["time-driver", "rp2040"] } embassy-boot-rp = { version = "0.5.0", path = "../../../../embassy-boot-rp", features = [] } diff --git a/examples/boot/application/stm32f3/Cargo.toml b/examples/boot/application/stm32f3/Cargo.toml index 2590e9c49..f32727ea8 100644 --- a/examples/boot/application/stm32f3/Cargo.toml +++ b/examples/boot/application/stm32f3/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.2", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread"] } +embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32f303re", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32" } diff --git a/examples/boot/application/stm32f7/Cargo.toml b/examples/boot/application/stm32f7/Cargo.toml index fac73afd7..6a5a500de 100644 --- a/examples/boot/application/stm32f7/Cargo.toml +++ b/examples/boot/application/stm32f7/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.2", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread"] } +embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32f767zi", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } diff --git a/examples/boot/application/stm32h7/Cargo.toml b/examples/boot/application/stm32h7/Cargo.toml index 587d303ab..dd3a32e45 100644 --- a/examples/boot/application/stm32h7/Cargo.toml +++ b/examples/boot/application/stm32h7/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.2", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread"] } +embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32h743zi", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } diff --git a/examples/boot/application/stm32l0/Cargo.toml b/examples/boot/application/stm32l0/Cargo.toml index b3c580d3d..0b9e9b96a 100644 --- a/examples/boot/application/stm32l0/Cargo.toml +++ b/examples/boot/application/stm32l0/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.2", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread"] } +embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32l072cz", "time-driver-any", "exti", "memory-x"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } diff --git a/examples/boot/application/stm32l1/Cargo.toml b/examples/boot/application/stm32l1/Cargo.toml index 8c49be914..490541a2e 100644 --- a/examples/boot/application/stm32l1/Cargo.toml +++ b/examples/boot/application/stm32l1/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.2", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread"] } +embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32l151cb-a", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } diff --git a/examples/boot/application/stm32l4/Cargo.toml b/examples/boot/application/stm32l4/Cargo.toml index 28c74303a..c3aa31161 100644 --- a/examples/boot/application/stm32l4/Cargo.toml +++ b/examples/boot/application/stm32l4/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.2", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread"] } +embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32l475vg", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } diff --git a/examples/boot/application/stm32wb-dfu/Cargo.toml b/examples/boot/application/stm32wb-dfu/Cargo.toml index deaf4c388..a89e2bb6e 100644 --- a/examples/boot/application/stm32wb-dfu/Cargo.toml +++ b/examples/boot/application/stm32wb-dfu/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.2", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread"] } +embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32wb55rg", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } diff --git a/examples/boot/application/stm32wl/Cargo.toml b/examples/boot/application/stm32wl/Cargo.toml index 890d0b510..f4d7ae712 100644 --- a/examples/boot/application/stm32wl/Cargo.toml +++ b/examples/boot/application/stm32wl/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.2", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread"] } +embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32wl55jc-cm4", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } diff --git a/examples/lpc55s69/Cargo.toml b/examples/lpc55s69/Cargo.toml index afd76f9ac..f5a6e6995 100644 --- a/examples/lpc55s69/Cargo.toml +++ b/examples/lpc55s69/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-nxp = { version = "0.1.0", path = "../../embassy-nxp", features = ["rt"] } -embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt"] } +embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt"] } embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt"] } panic-halt = "0.2.0" diff --git a/examples/mspm0c1104/Cargo.toml b/examples/mspm0c1104/Cargo.toml index 3996939a5..7c382482a 100644 --- a/examples/mspm0c1104/Cargo.toml +++ b/examples/mspm0c1104/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-mspm0 = { version = "0.1.0", path = "../../embassy-mspm0", features = ["mspm0c110x", "rt", "time-driver-any"] } -embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-128", "arch-cortex-m", "executor-thread", "executor-interrupt"] } +embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt"] } embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt"] } panic-halt = "0.2.0" diff --git a/examples/mspm0g3507/Cargo.toml b/examples/mspm0g3507/Cargo.toml index c1f304174..9bc82151c 100644 --- a/examples/mspm0g3507/Cargo.toml +++ b/examples/mspm0g3507/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-mspm0 = { version = "0.1.0", path = "../../embassy-mspm0", features = ["mspm0g350x", "rt", "time-driver-any"] } -embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-4096", "arch-cortex-m", "executor-thread", "executor-interrupt"] } +embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt"] } embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt"] } panic-halt = "0.2.0" diff --git a/examples/mspm0g3519/Cargo.toml b/examples/mspm0g3519/Cargo.toml index fc6f0e31b..a28ce2f11 100644 --- a/examples/mspm0g3519/Cargo.toml +++ b/examples/mspm0g3519/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-mspm0 = { version = "0.1.0", path = "../../embassy-mspm0", features = ["mspm0g351x", "rt", "time-driver-any"] } -embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-16384", "arch-cortex-m", "executor-thread", "executor-interrupt"] } +embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt"] } embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt"] } panic-halt = "0.2.0" diff --git a/examples/mspm0l1306/Cargo.toml b/examples/mspm0l1306/Cargo.toml index 6b87916b8..3962eb156 100644 --- a/examples/mspm0l1306/Cargo.toml +++ b/examples/mspm0l1306/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-mspm0 = { version = "0.1.0", path = "../../embassy-mspm0", features = ["mspm0l130x", "rt", "time-driver-any"] } -embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-1024", "arch-cortex-m", "executor-thread", "executor-interrupt"] } +embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt"] } embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt"] } panic-halt = "0.2.0" diff --git a/examples/mspm0l2228/Cargo.toml b/examples/mspm0l2228/Cargo.toml index 9474c2ced..abebcc00d 100644 --- a/examples/mspm0l2228/Cargo.toml +++ b/examples/mspm0l2228/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-mspm0 = { version = "0.1.0", path = "../../embassy-mspm0", features = ["mspm0l222x", "rt", "time-driver-any"] } -embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-1024", "arch-cortex-m", "executor-thread", "executor-interrupt"] } +embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt"] } embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt"] } panic-halt = "0.2.0" diff --git a/examples/nrf51/Cargo.toml b/examples/nrf51/Cargo.toml index b6760a428..97b5b924a 100644 --- a/examples/nrf51/Cargo.toml +++ b/examples/nrf51/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-4096", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } +embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.3.1", path = "../../embassy-nrf", features = ["defmt", "nrf51", "gpiote", "time-driver-rtc1", "unstable-pac", "time", "rt"] } diff --git a/examples/nrf52810/Cargo.toml b/examples/nrf52810/Cargo.toml index 297a52537..cd59b86c3 100644 --- a/examples/nrf52810/Cargo.toml +++ b/examples/nrf52810/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } +embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.3.1", path = "../../embassy-nrf", features = ["defmt", "nrf52810", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } diff --git a/examples/nrf52840/Cargo.toml b/examples/nrf52840/Cargo.toml index f479d6af6..902193f3a 100644 --- a/examples/nrf52840/Cargo.toml +++ b/examples/nrf52840/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } +embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.3.1", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } embassy-net = { version = "0.7.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } diff --git a/examples/nrf5340/Cargo.toml b/examples/nrf5340/Cargo.toml index 2a83633b4..459c43221 100644 --- a/examples/nrf5340/Cargo.toml +++ b/examples/nrf5340/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] } +embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.3.1", path = "../../embassy-nrf", features = ["defmt", "nrf5340-app-s", "time-driver-rtc1", "gpiote", "unstable-pac"] } embassy-net = { version = "0.7.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } diff --git a/examples/nrf54l15/Cargo.toml b/examples/nrf54l15/Cargo.toml index 12808fc2a..8848065d8 100644 --- a/examples/nrf54l15/Cargo.toml +++ b/examples/nrf54l15/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } +embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.3.1", path = "../../embassy-nrf", features = ["defmt", "nrf54l15-app-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } diff --git a/examples/nrf9151/ns/Cargo.toml b/examples/nrf9151/ns/Cargo.toml index 27def8455..03f38fd63 100644 --- a/examples/nrf9151/ns/Cargo.toml +++ b/examples/nrf9151/ns/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-executor = { version = "0.7.0", path = "../../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } +embassy-executor = { version = "0.7.0", path = "../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.3.1", path = "../../../embassy-nrf", features = ["defmt", "nrf9120-ns", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } diff --git a/examples/nrf9151/s/Cargo.toml b/examples/nrf9151/s/Cargo.toml index e57f199c6..ba88f6da3 100644 --- a/examples/nrf9151/s/Cargo.toml +++ b/examples/nrf9151/s/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-executor = { version = "0.7.0", path = "../../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } +embassy-executor = { version = "0.7.0", path = "../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.3.1", path = "../../../embassy-nrf", features = ["defmt", "nrf9120-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } diff --git a/examples/nrf9160/Cargo.toml b/examples/nrf9160/Cargo.toml index 6965ce202..a720f2d61 100644 --- a/examples/nrf9160/Cargo.toml +++ b/examples/nrf9160/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } +embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.3.1", path = "../../embassy-nrf", features = ["defmt", "nrf9160-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } embassy-net-nrf91 = { version = "0.1.0", path = "../../embassy-net-nrf91", features = ["defmt"] } diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index 4fc1d35d6..45ca30e4c 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-embedded-hal = { version = "0.3.0", path = "../../embassy-embedded-hal", features = ["defmt"] } embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-98304", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } +embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-rp = { version = "0.4.0", path = "../../embassy-rp", features = ["defmt", "unstable-pac", "time-driver", "critical-section-impl", "rp2040"] } embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/rp235x/Cargo.toml b/examples/rp235x/Cargo.toml index c9e0ee120..345a915af 100644 --- a/examples/rp235x/Cargo.toml +++ b/examples/rp235x/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-embedded-hal = { version = "0.3.0", path = "../../embassy-embedded-hal", features = ["defmt"] } embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-98304", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } +embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-rp = { version = "0.4.0", path = "../../embassy-rp", features = ["defmt", "unstable-pac", "time-driver", "critical-section-impl", "rp235xa", "binary-info"] } embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/std/Cargo.toml b/examples/std/Cargo.toml index a32e75d08..f00953167 100644 --- a/examples/std/Cargo.toml +++ b/examples/std/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["log"] } -embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-std", "executor-thread", "log"] } +embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-std", "executor-thread", "log"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["log", "std", ] } embassy-net = { version = "0.7.0", path = "../../embassy-net", features=[ "log", "medium-ethernet", "medium-ip", "tcp", "udp", "dns", "dhcpv4", "proto-ipv6"] } embassy-net-tuntap = { version = "0.1.0", path = "../../embassy-net-tuntap" } diff --git a/examples/stm32f4/Cargo.toml b/examples/stm32f4/Cargo.toml index e611564eb..7aa4354ca 100644 --- a/examples/stm32f4/Cargo.toml +++ b/examples/stm32f4/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32f429zi to your chip name, if necessary. embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = ["defmt", "stm32f429zi", "unstable-pac", "memory-x", "time-driver-tim4", "exti", "chrono"] } embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } +embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defmt" ] } embassy-net = { version = "0.7.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", ] } diff --git a/examples/stm32f469/Cargo.toml b/examples/stm32f469/Cargo.toml index 2c0c9a6c8..4d403bae8 100644 --- a/examples/stm32f469/Cargo.toml +++ b/examples/stm32f469/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Specific examples only for stm32f469 embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = ["defmt", "stm32f469ni", "unstable-pac", "memory-x", "time-driver-any", "exti", "chrono"] } -embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } +embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } defmt = "0.3" diff --git a/examples/stm32f7/Cargo.toml b/examples/stm32f7/Cargo.toml index e8b246184..9fbe2efc3 100644 --- a/examples/stm32f7/Cargo.toml +++ b/examples/stm32f7/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32f777zi to your chip name, if necessary. embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = ["defmt", "stm32f777zi", "memory-x", "unstable-pac", "time-driver-any", "exti"] } embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] } +embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.7.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } embedded-io-async = { version = "0.6.1" } diff --git a/examples/stm32h5/Cargo.toml b/examples/stm32h5/Cargo.toml index 5b80e5486..5631ff746 100644 --- a/examples/stm32h5/Cargo.toml +++ b/examples/stm32h5/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32h563zi to your chip name, if necessary. embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = ["defmt", "stm32h563zi", "memory-x", "time-driver-any", "exti", "unstable-pac", "low-power"] } embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] } +embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.7.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6"] } embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/stm32h7/Cargo.toml b/examples/stm32h7/Cargo.toml index 4c18bb21c..2f98542bb 100644 --- a/examples/stm32h7/Cargo.toml +++ b/examples/stm32h7/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = ["defmt", "stm32h743bi", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } embassy-embedded-hal = { version = "0.3.0", path = "../../embassy-embedded-hal" } -embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } +embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.7.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/stm32h723/Cargo.toml b/examples/stm32h723/Cargo.toml index 148d09dd6..749fd78ae 100644 --- a/examples/stm32h723/Cargo.toml +++ b/examples/stm32h723/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32h723zg to your chip name, if necessary. embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = ["defmt", "stm32h723zg", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } +embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32h735/Cargo.toml b/examples/stm32h735/Cargo.toml index 1ae6ed253..4d31dedf1 100644 --- a/examples/stm32h735/Cargo.toml +++ b/examples/stm32h735/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = ["defmt", "stm32h735ig", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } embassy-embedded-hal = { version = "0.3.0", path = "../../embassy-embedded-hal" } -embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } +embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32h755cm4/Cargo.toml b/examples/stm32h755cm4/Cargo.toml index e3efa0aa2..7c17bc766 100644 --- a/examples/stm32h755cm4/Cargo.toml +++ b/examples/stm32h755cm4/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = ["defmt", "stm32h755zi-cm4", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } embassy-embedded-hal = { version = "0.3.0", path = "../../embassy-embedded-hal" } -embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } +embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.7.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/stm32h755cm7/Cargo.toml b/examples/stm32h755cm7/Cargo.toml index 1f05c71b5..3186929a8 100644 --- a/examples/stm32h755cm7/Cargo.toml +++ b/examples/stm32h755cm7/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = ["defmt", "stm32h755zi-cm7", "time-driver-tim3", "exti", "memory-x", "unstable-pac", "chrono"] } embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } embassy-embedded-hal = { version = "0.3.0", path = "../../embassy-embedded-hal" } -embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } +embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.7.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/stm32h7b0/Cargo.toml b/examples/stm32h7b0/Cargo.toml index e0db3c0cd..e5f2dfe86 100644 --- a/examples/stm32h7b0/Cargo.toml +++ b/examples/stm32h7b0/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = ["defmt", "stm32h7b0vb", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } embassy-embedded-hal = { version = "0.3.0", path = "../../embassy-embedded-hal" } -embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } +embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.7.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/stm32h7rs/Cargo.toml b/examples/stm32h7rs/Cargo.toml index a47dbe21e..22d59be04 100644 --- a/examples/stm32h7rs/Cargo.toml +++ b/examples/stm32h7rs/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32h743bi to your chip name, if necessary. embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = ["defmt", "stm32h7s3l8", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } +embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.7.0", path = "../../embassy-net", features = ["defmt", "udp", "medium-ethernet", "medium-ip", "proto-ipv4"] } embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/stm32l4/Cargo.toml b/examples/stm32l4/Cargo.toml index 495c12936..b609110af 100644 --- a/examples/stm32l4/Cargo.toml +++ b/examples/stm32l4/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32l4s5vi to your chip name, if necessary. embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32l4r5zi", "memory-x", "time-driver-any", "exti", "chrono"] } embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] } +embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768", ] } embassy-embedded-hal = { version = "0.3.0", path = "../../embassy-embedded-hal" } embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/stm32l432/Cargo.toml b/examples/stm32l432/Cargo.toml index 71bff8667..e155b3e66 100644 --- a/examples/stm32l432/Cargo.toml +++ b/examples/stm32l432/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32l4s5vi to your chip name, if necessary. embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32l432kc", "memory-x", "time-driver-any", "exti", "chrono"] } embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = [ "defmt" ] } -embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = [ "task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt" ] } +embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = [ "arch-cortex-m", "executor-thread", "defmt" ] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = [ "defmt", "defmt-timestamp-uptime", "tick-hz-32_768" ] } defmt = "0.3" defmt-rtt = "0.4" diff --git a/examples/stm32l5/Cargo.toml b/examples/stm32l5/Cargo.toml index 7894abb38..fbf68c890 100644 --- a/examples/stm32l5/Cargo.toml +++ b/examples/stm32l5/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32l552ze to your chip name, if necessary. embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32l552ze", "time-driver-any", "exti", "memory-x", "low-power"] } embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] } +embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defmt"] } embassy-net = { version = "0.7.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } diff --git a/examples/stm32u5/Cargo.toml b/examples/stm32u5/Cargo.toml index 33e75cf1e..886c5cb2e 100644 --- a/examples/stm32u5/Cargo.toml +++ b/examples/stm32u5/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32u5g9zj to your chip name, if necessary. embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = ["defmt", "unstable-pac", "stm32u5g9zj", "time-driver-any", "memory-x" ] } embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] } +embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32wb/Cargo.toml b/examples/stm32wb/Cargo.toml index e9959b905..96f66f3af 100644 --- a/examples/stm32wb/Cargo.toml +++ b/examples/stm32wb/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [ "defmt", "stm32wb55rg", "time-driver-any", "memory-x", "exti"] } embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", features = ["defmt", "stm32wb55rg"] } embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] } +embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.7.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", ], optional=true } diff --git a/examples/stm32wba/Cargo.toml b/examples/stm32wba/Cargo.toml index 0f55bee39..60b09adb4 100644 --- a/examples/stm32wba/Cargo.toml +++ b/examples/stm32wba/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [ "defmt", "stm32wba55cg", "time-driver-any", "memory-x", "exti"] } embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] } +embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.7.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", ], optional=true } diff --git a/examples/stm32wl/Cargo.toml b/examples/stm32wl/Cargo.toml index 194e58459..6b677914e 100644 --- a/examples/stm32wl/Cargo.toml +++ b/examples/stm32wl/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32wl55jc-cm4 to your chip name, if necessary. embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = ["defmt", "stm32wl55jc-cm4", "time-driver-any", "memory-x", "unstable-pac", "exti", "chrono"] } embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-4096", "arch-cortex-m", "executor-thread", "defmt"] } +embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-embedded-hal = { version = "0.3.0", path = "../../embassy-embedded-hal" } diff --git a/tests/nrf/Cargo.toml b/tests/nrf/Cargo.toml index 6aa5e2bcc..410d62bdd 100644 --- a/tests/nrf/Cargo.toml +++ b/tests/nrf/Cargo.toml @@ -33,7 +33,7 @@ portable-atomic = { version = "1.6.0" } nrf51422 = ["embassy-nrf/nrf51", "portable-atomic/unsafe-assume-single-core"] nrf52832 = ["embassy-nrf/nrf52832", "easydma"] nrf52833 = ["embassy-nrf/nrf52833", "easydma", "two-uarts"] -nrf52840 = ["embassy-nrf/nrf52840", "easydma", "two-uarts", "embassy-executor/task-arena-size-16384"] +nrf52840 = ["embassy-nrf/nrf52840", "easydma", "two-uarts"] nrf5340 = ["embassy-nrf/nrf5340-app-s", "easydma", "two-uarts"] nrf9160 = ["embassy-nrf/nrf9160-s", "easydma", "two-uarts"] diff --git a/tests/rp/Cargo.toml b/tests/rp/Cargo.toml index 503c4d67b..1335aa84b 100644 --- a/tests/rp/Cargo.toml +++ b/tests/rp/Cargo.toml @@ -13,7 +13,7 @@ rp235xb = ["embassy-rp/rp235xb"] teleprobe-meta = "1.1" embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } -embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] } +embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", ] } embassy-rp = { version = "0.4.0", path = "../../embassy-rp", features = [ "defmt", "unstable-pac", "time-driver", "critical-section-impl", "intrinsics", "rom-v2-intrinsics", "run-from-ram"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml index 9c3b2780a..a676aee53 100644 --- a/tests/stm32/Cargo.toml +++ b/tests/stm32/Cargo.toml @@ -39,7 +39,7 @@ spi-v1 = [] spi-v345 = [] cryp = [] hash = [] -eth = ["embassy-executor/task-arena-size-16384"] +eth = [] rng = [] sdmmc = [] stop = ["embassy-stm32/low-power", "embassy-stm32/low-power-debug-with-sleep"] From 49badcff1a4f3e448f81a1703ee55e5bc2d368d4 Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Fri, 28 Mar 2025 17:45:41 -0400 Subject: [PATCH 0885/1217] RP235x watchdog doesn't have the double count bug --- embassy-rp/src/watchdog.rs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/embassy-rp/src/watchdog.rs b/embassy-rp/src/watchdog.rs index 760d6aac2..49cf03850 100644 --- a/embassy-rp/src/watchdog.rs +++ b/embassy-rp/src/watchdog.rs @@ -89,17 +89,25 @@ impl Watchdog { /// Start the watchdog timer pub fn start(&mut self, period: Duration) { + #[cfg(feature = "rp2040")] + const MAX_PERIOD: u32 = 0xFFFFFF / 2; + #[cfg(feature = "_rp235x")] const MAX_PERIOD: u32 = 0xFFFFFF; let delay_us = period.as_micros(); - if delay_us > (MAX_PERIOD / 2) as u64 { - panic!("Period cannot exceed {} microseconds", MAX_PERIOD / 2); + if delay_us > (MAX_PERIOD) as u64 { + panic!("Period cannot exceed {} microseconds", MAX_PERIOD); } let delay_us = delay_us as u32; // Due to a logic error, the watchdog decrements by 2 and // the load value must be compensated; see RP2040-E1 - self.load_value = delay_us * 2; + // This errata is fixed in the RP235x + if cfg!(feature = "rp2040") { + self.load_value = delay_us * 2; + } else { + self.load_value = delay_us; + } self.enable(false); self.configure_wdog_reset_triggers(); From 91cde689cc0c771ffeb3864eb41e88104d476b47 Mon Sep 17 00:00:00 2001 From: i509VCB Date: Sat, 22 Mar 2025 17:52:13 -0500 Subject: [PATCH 0886/1217] mspm0: blocking uart driver --- embassy-mspm0/Cargo.toml | 1 + embassy-mspm0/build.rs | 10 +- embassy-mspm0/src/gpio.rs | 71 ++ embassy-mspm0/src/lib.rs | 4 + embassy-mspm0/src/macros.rs | 9 + embassy-mspm0/src/uart.rs | 1085 +++++++++++++++++++++++++++ examples/mspm0c1104/Cargo.toml | 2 +- examples/mspm0c1104/src/bin/uart.rs | 35 + examples/mspm0g3507/Cargo.toml | 2 +- examples/mspm0g3507/src/bin/uart.rs | 35 + examples/mspm0g3519/Cargo.toml | 2 +- examples/mspm0g3519/src/bin/uart.rs | 35 + examples/mspm0l1306/Cargo.toml | 2 +- examples/mspm0l1306/src/bin/uart.rs | 35 + examples/mspm0l2228/Cargo.toml | 2 +- examples/mspm0l2228/src/bin/uart.rs | 35 + 16 files changed, 1355 insertions(+), 10 deletions(-) create mode 100644 embassy-mspm0/src/macros.rs create mode 100644 embassy-mspm0/src/uart.rs create mode 100644 examples/mspm0c1104/src/bin/uart.rs create mode 100644 examples/mspm0g3507/src/bin/uart.rs create mode 100644 examples/mspm0g3519/src/bin/uart.rs create mode 100644 examples/mspm0l1306/src/bin/uart.rs create mode 100644 examples/mspm0l2228/src/bin/uart.rs diff --git a/embassy-mspm0/Cargo.toml b/embassy-mspm0/Cargo.toml index 28a8e7724..df996ff4b 100644 --- a/embassy-mspm0/Cargo.toml +++ b/embassy-mspm0/Cargo.toml @@ -39,6 +39,7 @@ embedded-hal = { version = "1.0" } embedded-hal-async = { version = "1.0" } defmt = { version = "0.3", optional = true } +fixed = "1.29" log = { version = "0.4.14", optional = true } cortex-m-rt = ">=0.6.15,<0.8" cortex-m = "0.7.6" diff --git a/embassy-mspm0/build.rs b/embassy-mspm0/build.rs index 39d8b2f8a..08209df2a 100644 --- a/embassy-mspm0/build.rs +++ b/embassy-mspm0/build.rs @@ -381,7 +381,7 @@ fn generate_peripheral_instances() -> TokenStream { // Will be filled in when uart implementation is finished let _ = peri; let tokens = match peripheral.kind { - // "uart" => Some(quote! { impl_uart_instance!(#peri); }), + "uart" => Some(quote! { impl_uart_instance!(#peri); }), _ => None, }; @@ -412,10 +412,10 @@ fn generate_pin_trait_impls() -> TokenStream { let _ = pf; let tokens = match key { - // ("uart", "TX") => Some(quote! { impl_uart_tx_pin!(#peri, #pin_name, #pf); }), - // ("uart", "RX") => Some(quote! { impl_uart_rx_pin!(#peri, #pin_name, #pf); }), - // ("uart", "CTS") => Some(quote! { impl_uart_cts_pin!(#peri, #pin_name, #pf); }), - // ("uart", "RTS") => Some(quote! { impl_uart_rts_pin!(#peri, #pin_name, #pf); }), + ("uart", "TX") => Some(quote! { impl_uart_tx_pin!(#peri, #pin_name, #pf); }), + ("uart", "RX") => Some(quote! { impl_uart_rx_pin!(#peri, #pin_name, #pf); }), + ("uart", "CTS") => Some(quote! { impl_uart_cts_pin!(#peri, #pin_name, #pf); }), + ("uart", "RTS") => Some(quote! { impl_uart_rts_pin!(#peri, #pin_name, #pf); }), _ => None, }; diff --git a/embassy-mspm0/src/gpio.rs b/embassy-mspm0/src/gpio.rs index 2edadbc5a..7e6b01649 100644 --- a/embassy-mspm0/src/gpio.rs +++ b/embassy-mspm0/src/gpio.rs @@ -836,6 +836,31 @@ impl<'d> embedded_hal_async::digital::Wait for OutputOpenDrain<'d> { } } +#[derive(Copy, Clone)] +pub struct PfType { + pull: Pull, + input: bool, + invert: bool, +} + +impl PfType { + pub const fn input(pull: Pull, invert: bool) -> Self { + Self { + pull, + input: true, + invert, + } + } + + pub const fn output(pull: Pull, invert: bool) -> Self { + Self { + pull, + input: false, + invert, + } + } +} + /// The pin function to disconnect peripherals from the pin. /// /// This is also the pin function used to connect to analog peripherals, such as an ADC. @@ -907,6 +932,40 @@ pub(crate) trait SealedPin { (self.pin_port() % 32) as usize } + #[inline] + fn set_as_analog(&self) { + let pincm = pac::IOMUX.pincm(self._pin_cm() as usize); + + pincm.modify(|w| { + w.set_pf(DISCONNECT_PF); + w.set_pipu(false); + w.set_pipd(false); + }); + } + + fn update_pf(&self, ty: PfType) { + let pincm = pac::IOMUX.pincm(self._pin_cm() as usize); + let pf = pincm.read().pf(); + + set_pf(self._pin_cm() as usize, pf, ty); + } + + fn set_as_pf(&self, pf: u8, ty: PfType) { + set_pf(self._pin_cm() as usize, pf, ty) + } + + /// Set the pin as "disconnected", ie doing nothing and consuming the lowest + /// amount of power possible. + /// + /// This is currently the same as [`Self::set_as_analog()`] but is semantically different + /// really. Drivers should `set_as_disconnected()` pins when dropped. + /// + /// Note that this also disables the internal weak pull-up and pull-down resistors. + #[inline] + fn set_as_disconnected(&self) { + self.set_as_analog(); + } + #[inline] fn block(&self) -> gpio::Gpio { match self.pin_port() / 32 { @@ -920,6 +979,18 @@ pub(crate) trait SealedPin { } } +#[inline(never)] +fn set_pf(pincm: usize, pf: u8, ty: PfType) { + pac::IOMUX.pincm(pincm).modify(|w| { + w.set_pf(pf); + w.set_pc(true); + w.set_pipu(ty.pull == Pull::Up); + w.set_pipd(ty.pull == Pull::Down); + w.set_inena(ty.input); + w.set_inv(ty.invert); + }); +} + #[must_use = "futures do nothing unless you `.await` or poll them"] struct InputFuture<'d> { pin: Peri<'d, AnyPin>, diff --git a/embassy-mspm0/src/lib.rs b/embassy-mspm0/src/lib.rs index 99b7ed4a1..e8f5971d5 100644 --- a/embassy-mspm0/src/lib.rs +++ b/embassy-mspm0/src/lib.rs @@ -5,8 +5,12 @@ // This mod MUST go first, so that the others see its macros. pub(crate) mod fmt; +// This must be declared early as well for +mod macros; + pub mod gpio; pub mod timer; +pub mod uart; /// Operating modes for peripherals. pub mod mode { diff --git a/embassy-mspm0/src/macros.rs b/embassy-mspm0/src/macros.rs new file mode 100644 index 000000000..5355e7d59 --- /dev/null +++ b/embassy-mspm0/src/macros.rs @@ -0,0 +1,9 @@ +#![macro_use] + +macro_rules! new_pin { + ($name: ident, $pf_type: expr) => {{ + let pin = $name; + pin.set_as_pf(pin.pf_num(), $pf_type); + Some(pin.into()) + }}; +} diff --git a/embassy-mspm0/src/uart.rs b/embassy-mspm0/src/uart.rs new file mode 100644 index 000000000..45094a000 --- /dev/null +++ b/embassy-mspm0/src/uart.rs @@ -0,0 +1,1085 @@ +#![macro_use] + +use core::marker::PhantomData; +use core::sync::atomic::{compiler_fence, AtomicU32, Ordering}; + +use embassy_embedded_hal::SetConfig; +use embassy_hal_internal::PeripheralType; + +use crate::gpio::{AnyPin, PfType, Pull, SealedPin}; +use crate::interrupt::{Interrupt, InterruptExt}; +use crate::mode::{Blocking, Mode}; +use crate::pac::uart::{vals, Uart as Regs}; +use crate::Peri; + +/// The clock source for the UART. +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum ClockSel { + /// Use the low frequency clock. + /// + /// The LFCLK runs at 32.768 kHz. + LfClk, + + /// Use the middle frequency clock. + /// + /// The MCLK runs at 4 MHz. + MfClk, + // BusClk, + // BusClk depends on the timer's power domain. + // This will be implemented later. +} + +#[non_exhaustive] +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +/// The order of bits in byte. +pub enum BitOrder { + /// The most significant bit is first. + MsbFirst, + + /// The least significant bit is first. + LsbFirst, +} + +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +/// Number of data bits +pub enum DataBits { + /// 5 Data Bits + DataBits5, + + /// 6 Data Bits + DataBits6, + + /// 7 Data Bits + DataBits7, + + /// 8 Data Bits + DataBits8, +} + +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +/// Parity +pub enum Parity { + /// No parity + ParityNone, + + /// Even Parity + ParityEven, + + /// Odd Parity + ParityOdd, +} + +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +/// Number of stop bits +pub enum StopBits { + /// One stop bit + Stop1, + + /// Two stop bits + Stop2, +} + +#[non_exhaustive] +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +/// Config Error +pub enum ConfigError { + /// Rx or Tx not enabled + RxOrTxNotEnabled, + + /// The baud rate could not be configured with the given clocks. + InvalidBaudRate, +} + +#[non_exhaustive] +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +/// Config +pub struct Config { + /// UART clock source. + pub clock_source: ClockSel, + + /// Baud rate + pub baudrate: u32, + + /// Number of data bits. + pub data_bits: DataBits, + + /// Number of stop bits. + pub stop_bits: StopBits, + + /// Parity type. + pub parity: Parity, + + /// The order of bits in a transmitted/received byte. + pub msb_order: BitOrder, + + /// If true: the `TX` is internally connected to `RX`. + pub loop_back_enable: bool, + + // TODO: Pending way to check if uart is extended + // /// If true: [manchester coding] is used. + // /// + // /// [manchester coding]: https://en.wikipedia.org/wiki/Manchester_code + // pub manchester: bool, + + // TODO: majority voting + + // TODO: fifo level select - need power domain info in metapac + + // TODO: glitch suppression + /// If true: invert TX pin signal values (VDD = 0/mark, Gnd = 1/idle). + pub invert_tx: bool, + + /// If true: invert RX pin signal values (VDD = 0/mark, Gnd = 1/idle). + pub invert_rx: bool, + + /// If true: invert RTS pin signal values (VDD = 0/mark, Gnd = 1/idle). + pub invert_rts: bool, + + /// If true: invert CTS pin signal values (VDD = 0/mark, Gnd = 1/idle). + pub invert_cts: bool, + + /// Set the pull configuration for the TX pin. + pub tx_pull: Pull, + + /// Set the pull configuration for the RX pin. + pub rx_pull: Pull, + + /// Set the pull configuration for the RTS pin. + pub rts_pull: Pull, + + /// Set the pull configuration for the CTS pin. + pub cts_pull: Pull, +} + +impl Default for Config { + fn default() -> Self { + Self { + clock_source: ClockSel::MfClk, + baudrate: 115200, + data_bits: DataBits::DataBits8, + stop_bits: StopBits::Stop1, + parity: Parity::ParityNone, + // hardware default + msb_order: BitOrder::LsbFirst, + loop_back_enable: false, + // manchester: false, + invert_tx: false, + invert_rx: false, + invert_rts: false, + invert_cts: false, + tx_pull: Pull::None, + rx_pull: Pull::None, + rts_pull: Pull::None, + cts_pull: Pull::None, + } + } +} + +/// Bidirectional UART Driver, which acts as a combination of [`UartTx`] and [`UartRx`]. +/// +/// ### Notes on [`embedded_io::Read`] +/// +/// `embedded_io::Read` requires guarantees that the base [`UartRx`] cannot provide. +/// +/// See [`UartRx`] for more details, and see [`BufferedUart`] and [`RingBufferedUartRx`] +/// as alternatives that do provide the necessary guarantees for `embedded_io::Read`. +pub struct Uart<'d, M: Mode> { + tx: UartTx<'d, M>, + rx: UartRx<'d, M>, +} + +impl<'d, M: Mode> SetConfig for Uart<'d, M> { + type Config = Config; + type ConfigError = ConfigError; + + fn set_config(&mut self, config: &Self::Config) -> Result<(), Self::ConfigError> { + self.tx.set_config(config)?; + self.rx.set_config(config) + } +} + +/// Serial error +#[derive(Debug, Eq, PartialEq, Copy, Clone)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[non_exhaustive] +pub enum Error { + Framing, + + Noise, + + Overrun, + + Parity, + + Break, +} + +impl core::fmt::Display for Error { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let message = match self { + Self::Framing => "Framing Error", + Self::Noise => "Noise Error", + Self::Overrun => "RX Buffer Overrun", + Self::Parity => "Parity Check Error", + Self::Break => "Break Error", + }; + + write!(f, "{}", message) + } +} + +impl core::error::Error for Error {} + +/// Rx-only UART Driver. +/// +/// Can be obtained from [`Uart::split`], or can be constructed independently, +/// if you do not need the transmitting half of the driver. +pub struct UartRx<'d, M: Mode> { + info: &'static Info, + state: &'static State, + rx: Option>, + rts: Option>, + _phantom: PhantomData, +} + +impl<'d, M: Mode> SetConfig for UartRx<'d, M> { + type Config = Config; + type ConfigError = ConfigError; + + fn set_config(&mut self, config: &Self::Config) -> Result<(), Self::ConfigError> { + self.set_config(config) + } +} + +impl<'d> UartRx<'d, Blocking> { + /// Create a new rx-only UART with no hardware flow control. + /// + /// Useful if you only want Uart Rx. It saves 1 pin . + pub fn new_blocking( + peri: Peri<'d, T>, + rx: Peri<'d, impl RxPin>, + config: Config, + ) -> Result { + Self::new_inner(peri, new_pin!(rx, config.rx_pf()), None, config) + } + + /// Create a new rx-only UART with a request-to-send pin + pub fn new_blocking_with_rts( + peri: Peri<'d, T>, + rx: Peri<'d, impl RxPin>, + rts: Peri<'d, impl RtsPin>, + config: Config, + ) -> Result { + Self::new_inner( + peri, + new_pin!(rx, config.rx_pf()), + new_pin!(rts, config.rts_pf()), + config, + ) + } +} + +impl<'d, M: Mode> UartRx<'d, M> { + /// Reconfigure the driver + pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { + if let Some(ref rx) = self.rx { + rx.update_pf(config.rx_pf()); + } + + if let Some(ref rts) = self.rts { + rts.update_pf(config.rts_pf()); + } + + reconfigure(self.info, self.state, config) + } + + /// Perform a blocking read into `buffer` + pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { + let r = self.info.regs; + + for b in buffer { + // Wait if nothing has arrived yet. + while r.stat().read().rxfe() {} + + // Prevent the compiler from reading from buffer too early + compiler_fence(Ordering::Acquire); + *b = read_with_error(r)?; + } + + Ok(()) + } + + /// Set baudrate + pub fn set_baudrate(&self, baudrate: u32) -> Result<(), ConfigError> { + set_baudrate(&self.info, self.state.clock.load(Ordering::Relaxed), baudrate) + } +} + +impl<'d, M: Mode> Drop for UartRx<'d, M> { + fn drop(&mut self) { + self.rx.as_ref().map(|x| x.set_as_disconnected()); + self.rts.as_ref().map(|x| x.set_as_disconnected()); + } +} + +/// Tx-only UART Driver. +/// +/// Can be obtained from [`Uart::split`], or can be constructed independently, +/// if you do not need the receiving half of the driver. +pub struct UartTx<'d, M: Mode> { + info: &'static Info, + state: &'static State, + tx: Option>, + cts: Option>, + _phantom: PhantomData, +} + +impl<'d, M: Mode> SetConfig for UartTx<'d, M> { + type Config = Config; + type ConfigError = ConfigError; + + fn set_config(&mut self, config: &Self::Config) -> Result<(), Self::ConfigError> { + reconfigure(self.info, self.state, config) + } +} + +impl<'d> UartTx<'d, Blocking> { + /// Create a new blocking tx-only UART with no hardware flow control. + /// + /// Useful if you only want Uart Tx. It saves 1 pin. + pub fn new_blocking( + peri: Peri<'d, T>, + tx: Peri<'d, impl TxPin>, + config: Config, + ) -> Result { + Self::new_inner(peri, new_pin!(tx, config.tx_pf()), None, config) + } + + /// Create a new blocking tx-only UART with a clear-to-send pin + pub fn new_blocking_with_cts( + peri: Peri<'d, T>, + tx: Peri<'d, impl TxPin>, + cts: Peri<'d, impl CtsPin>, + config: Config, + ) -> Result { + Self::new_inner( + peri, + new_pin!(tx, config.tx_pf()), + new_pin!(cts, config.cts_pf()), + config, + ) + } +} + +impl<'d, M: Mode> UartTx<'d, M> { + /// Reconfigure the driver + pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { + if let Some(ref tx) = self.tx { + tx.update_pf(config.tx_pf()); + } + + if let Some(ref cts) = self.cts { + cts.update_pf(config.cts_pf()); + } + + reconfigure(self.info, self.state, config) + } + + /// Perform a blocking UART write + pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> { + let r = self.info.regs; + + for &b in buffer { + // Wait if there is no space + while !r.stat().read().txfe() {} + + // Prevent the compiler from writing to buffer too early + compiler_fence(Ordering::Release); + r.txdata().write(|w| { + w.set_data(b); + }); + } + + Ok(()) + } + + /// Block until transmission complete + pub fn blocking_flush(&mut self) -> Result<(), Error> { + let r = self.info.regs; + + // Wait until TX fifo/buffer is empty + while r.stat().read().txfe() {} + Ok(()) + } + + /// Send break character + pub fn send_break(&self) { + let r = self.info.regs; + + r.lcrh().modify(|w| { + w.set_brk(true); + }); + } + + /// Set baudrate + pub fn set_baudrate(&self, baudrate: u32) -> Result<(), ConfigError> { + set_baudrate(&self.info, self.state.clock.load(Ordering::Relaxed), baudrate) + } +} + +impl<'d, M: Mode> Drop for UartTx<'d, M> { + fn drop(&mut self) { + self.tx.as_ref().map(|x| x.set_as_disconnected()); + self.cts.as_ref().map(|x| x.set_as_disconnected()); + } +} + +impl<'d> Uart<'d, Blocking> { + /// Create a new blocking bidirectional UART. + pub fn new_blocking( + peri: Peri<'d, T>, + rx: Peri<'d, impl RxPin>, + tx: Peri<'d, impl TxPin>, + config: Config, + ) -> Result { + Self::new_inner( + peri, + new_pin!(rx, config.rx_pf()), + new_pin!(tx, config.tx_pf()), + None, + None, + config, + ) + } + + /// Create a new bidirectional UART with request-to-send and clear-to-send pins + pub fn new_blocking_with_rtscts( + peri: Peri<'d, T>, + rx: Peri<'d, impl RxPin>, + tx: Peri<'d, impl TxPin>, + rts: Peri<'d, impl RtsPin>, + cts: Peri<'d, impl CtsPin>, + config: Config, + ) -> Result { + Self::new_inner( + peri, + new_pin!(rx, config.rx_pf()), + new_pin!(tx, config.tx_pf()), + new_pin!(rts, config.rts_pf()), + new_pin!(cts, config.cts_pf()), + config, + ) + } +} + +impl<'d, M: Mode> Uart<'d, M> { + /// Perform a blocking write + pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> { + self.tx.blocking_write(buffer) + } + + /// Block until transmission complete + pub fn blocking_flush(&mut self) -> Result<(), Error> { + self.tx.blocking_flush() + } + + /// Perform a blocking read into `buffer` + pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { + self.rx.blocking_read(buffer) + } + + /// Split the Uart into a transmitter and receiver, which is + /// particularly useful when having two tasks correlating to + /// transmitting and receiving. + pub fn split(self) -> (UartTx<'d, M>, UartRx<'d, M>) { + (self.tx, self.rx) + } + + /// Split the Uart into a transmitter and receiver by mutable reference, + /// which is particularly useful when having two tasks correlating to + /// transmitting and receiving. + pub fn split_ref(&mut self) -> (&mut UartTx<'d, M>, &mut UartRx<'d, M>) { + (&mut self.tx, &mut self.rx) + } + + /// Send break character + pub fn send_break(&self) { + self.tx.send_break(); + } + + /// Set baudrate + pub fn set_baudrate(&self, baudrate: u32) -> Result<(), ConfigError> { + set_baudrate(&self.tx.info, self.tx.state.clock.load(Ordering::Relaxed), baudrate) + } +} + +/// Peripheral instance trait. +#[allow(private_bounds)] +pub trait Instance: SealedInstance + PeripheralType { + type Interrupt: crate::interrupt::typelevel::Interrupt; +} + +/// UART `TX` pin trait +pub trait TxPin: crate::gpio::Pin { + /// Get the PF number needed to use this pin as `TX`. + fn pf_num(&self) -> u8; +} + +/// UART `RX` pin trait +pub trait RxPin: crate::gpio::Pin { + /// Get the PF number needed to use this pin as `RX`. + fn pf_num(&self) -> u8; +} + +/// UART `CTS` pin trait +pub trait CtsPin: crate::gpio::Pin { + /// Get the PF number needed to use this pin as `CTS`. + fn pf_num(&self) -> u8; +} + +/// UART `RTS` pin trait +pub trait RtsPin: crate::gpio::Pin { + /// Get the PF number needed to use this pin as `RTS`. + fn pf_num(&self) -> u8; +} + +// ==== IMPL types ==== + +pub(crate) struct Info { + pub(crate) regs: Regs, + pub(crate) interrupt: Interrupt, +} + +pub(crate) struct State { + /// The clock rate of the UART. This might be configured. + pub(crate) clock: AtomicU32, +} + +impl<'d, M: Mode> UartRx<'d, M> { + fn new_inner( + _peri: Peri<'d, T>, + rx: Option>, + rts: Option>, + config: Config, + ) -> Result { + let mut this = Self { + info: T::info(), + state: T::state(), + rx, + rts, + _phantom: PhantomData, + }; + this.enable_and_configure(&config)?; + + Ok(this) + } + + fn enable_and_configure(&mut self, config: &Config) -> Result<(), ConfigError> { + let info = self.info; + + enable(info.regs); + configure(info, self.state, config, true, self.rts.is_some(), false, false)?; + + Ok(()) + } +} + +impl<'d, M: Mode> UartTx<'d, M> { + fn new_inner( + _peri: Peri<'d, T>, + tx: Option>, + cts: Option>, + config: Config, + ) -> Result { + let mut this = Self { + info: T::info(), + state: T::state(), + tx, + cts, + _phantom: PhantomData, + }; + this.enable_and_configure(&config)?; + + Ok(this) + } + + fn enable_and_configure(&mut self, config: &Config) -> Result<(), ConfigError> { + let info = self.info; + let state = self.state; + + enable(info.regs); + configure(info, state, config, false, false, true, self.cts.is_some())?; + + Ok(()) + } +} + +impl<'d, M: Mode> Uart<'d, M> { + fn new_inner( + _peri: Peri<'d, T>, + rx: Option>, + tx: Option>, + rts: Option>, + cts: Option>, + config: Config, + ) -> Result { + let info = T::info(); + let state = T::state(); + + let mut this = Self { + tx: UartTx { + info, + state, + tx, + cts, + _phantom: PhantomData, + }, + rx: UartRx { + info, + state, + rx, + rts, + _phantom: PhantomData, + }, + }; + this.enable_and_configure(&config)?; + + Ok(this) + } + + fn enable_and_configure(&mut self, config: &Config) -> Result<(), ConfigError> { + let info = self.rx.info; + let state = self.rx.state; + + enable(info.regs); + configure( + info, + state, + config, + true, + self.rx.rts.is_some(), + true, + self.tx.cts.is_some(), + )?; + + info.interrupt.unpend(); + unsafe { info.interrupt.enable() }; + + Ok(()) + } +} + +impl Config { + fn tx_pf(&self) -> PfType { + PfType::output(self.tx_pull, self.invert_tx) + } + + fn rx_pf(&self) -> PfType { + PfType::input(self.rx_pull, self.invert_rx) + } + + fn rts_pf(&self) -> PfType { + PfType::output(self.rts_pull, self.invert_rts) + } + + fn cts_pf(&self) -> PfType { + PfType::input(self.rts_pull, self.invert_rts) + } +} + +fn enable(regs: Regs) { + let gprcm = regs.gprcm(0); + + gprcm.rstctl().write(|w| { + w.set_resetstkyclr(true); + w.set_resetassert(true); + w.set_key(vals::ResetKey::KEY); + }); + + gprcm.pwren().write(|w| { + w.set_enable(true); + w.set_key(vals::PwrenKey::KEY); + }); +} + +fn configure( + info: &Info, + state: &State, + config: &Config, + enable_rx: bool, + enable_rts: bool, + enable_tx: bool, + enable_cts: bool, +) -> Result<(), ConfigError> { + let r = info.regs; + + if !enable_rx && !enable_tx { + return Err(ConfigError::RxOrTxNotEnabled); + } + + // SLAU846B says that clocks should be enabled before disabling the uart. + r.clksel().write(|w| match config.clock_source { + ClockSel::LfClk => { + w.set_lfclk_sel(true); + w.set_mfclk_sel(false); + w.set_busclk_sel(false); + } + ClockSel::MfClk => { + w.set_mfclk_sel(true); + w.set_lfclk_sel(false); + w.set_busclk_sel(false); + } + }); + + let clock = match config.clock_source { + ClockSel::LfClk => 32768, + ClockSel::MfClk => 4_000_000, + }; + + state.clock.store(clock, Ordering::Relaxed); + + info.regs.ctl0().modify(|w| { + w.set_lbe(config.loop_back_enable); + w.set_rxe(enable_rx); + w.set_txe(enable_tx); + // RXD_OUT_EN and TXD_OUT_EN? + w.set_menc(false); + w.set_mode(vals::Mode::UART); + w.set_rtsen(enable_rts); + w.set_ctsen(enable_cts); + // oversampling is set later + // TODO: config + w.set_fen(false); + // TODO: config + w.set_majvote(false); + w.set_msbfirst(matches!(config.msb_order, BitOrder::MsbFirst)); + }); + + info.regs.lcrh().modify(|w| { + let eps = if matches!(config.parity, Parity::ParityEven) { + vals::Eps::EVEN + } else { + vals::Eps::ODD + }; + + let wlen = match config.data_bits { + DataBits::DataBits5 => vals::Wlen::DATABIT5, + DataBits::DataBits6 => vals::Wlen::DATABIT6, + DataBits::DataBits7 => vals::Wlen::DATABIT7, + DataBits::DataBits8 => vals::Wlen::DATABIT8, + }; + + // Used in LIN mode only + w.set_brk(false); + w.set_pen(config.parity != Parity::ParityNone); + w.set_eps(eps); + w.set_stp2(matches!(config.stop_bits, StopBits::Stop2)); + w.set_wlen(wlen); + // appears to only be used in RS-485 mode. + w.set_sps(false); + // IDLE pattern? + w.set_sendidle(false); + // ignore extdir_setup and extdir_hold, only used in RS-485 mode. + }); + + set_baudrate_inner(info.regs, clock, config.baudrate)?; + + r.ctl0().modify(|w| { + w.set_enable(true); + }); + + Ok(()) +} + +fn reconfigure(info: &Info, state: &State, config: &Config) -> Result<(), ConfigError> { + info.interrupt.disable(); + let r = info.regs; + let ctl0 = r.ctl0().read(); + configure(info, state, config, ctl0.rxe(), ctl0.rtsen(), ctl0.txe(), ctl0.ctsen())?; + + info.interrupt.unpend(); + unsafe { info.interrupt.enable() }; + + Ok(()) +} + +/// Set the baud rate and clock settings. +/// +/// This should be done relatively late during configuration since some clock settings are invalid depending on mode. +fn set_baudrate(info: &Info, clock: u32, baudrate: u32) -> Result<(), ConfigError> { + let r = info.regs; + + info.interrupt.disable(); + + // Programming baud rate requires that the peripheral is disabled + critical_section::with(|_cs| { + r.ctl0().modify(|w| { + w.set_enable(false); + }); + }); + + // Wait for end of transmission per suggestion in SLAU 845 section 18.3.28 + while !r.stat().read().txfe() {} + + set_baudrate_inner(r, clock, baudrate)?; + + critical_section::with(|_cs| { + r.ctl0().modify(|w| { + w.set_enable(true); + }); + }); + + info.interrupt.unpend(); + unsafe { info.interrupt.enable() }; + + Ok(()) +} + +fn set_baudrate_inner(regs: Regs, clock: u32, baudrate: u32) -> Result<(), ConfigError> { + // Quoting SLAU846 section 18.2.3.4: + // "When IBRD = 0, FBRD is ignored and no data gets transferred by the UART." + const MIN_IBRD: u16 = 1; + + // FBRD can be 0 + // FBRD is at most a 6-bit number. + const MAX_FBRD: u8 = 2_u8.pow(6); + + const DIVS: [(u8, vals::Clkdiv); 8] = [ + (1, vals::Clkdiv::DIV_BY_1), + (2, vals::Clkdiv::DIV_BY_2), + (3, vals::Clkdiv::DIV_BY_3), + (4, vals::Clkdiv::DIV_BY_4), + (5, vals::Clkdiv::DIV_BY_5), + (6, vals::Clkdiv::DIV_BY_6), + (7, vals::Clkdiv::DIV_BY_7), + (8, vals::Clkdiv::DIV_BY_8), + ]; + + // Quoting from SLAU 846 section 18.2.3.4: + // "Select oversampling by 3 or 8 to achieve higher speed with UARTclk/8 or UARTclk/3. In this case + // the receiver tolerance to clock deviation is reduced." + // + // "Select oversampling by 16 to increase the tolerance of the receiver to clock deviations. The + // maximum speed is limited to UARTclk/16." + // + // Based on these requirements, prioritize higher oversampling first to increase tolerance to clock + // deviation. If no valid BRD valud can be found satisifying the highest sample rate, then reduce + // sample rate until valid parameters are found. + const OVS: [(u8, vals::Hse); 3] = [(16, vals::Hse::OVS16), (8, vals::Hse::OVS8), (3, vals::Hse::OVS3)]; + + // 3x oversampling is not supported with manchester coding, DALI or IrDA. + let x3_invalid = { + let ctl0 = regs.ctl0().read(); + let irctl = regs.irctl().read(); + + ctl0.menc() || matches!(ctl0.mode(), vals::Mode::DALI) || irctl.iren() + }; + let mut found = None; + + for &(oversampling, hse_value) in &OVS { + if matches!(hse_value, vals::Hse::OVS3) && !x3_invalid { + continue; + } + + for &(div, div_value) in &DIVS { + let Some((ibrd, fbrd)) = calculate_brd(clock, div, baudrate, oversampling) else { + continue; + }; + + if ibrd < MIN_IBRD || fbrd > MAX_FBRD { + continue; + } + + found = Some((hse_value, div_value, ibrd, fbrd)); + } + } + + let Some((hse, div, ibrd, fbrd)) = found else { + return Err(ConfigError::InvalidBaudRate); + }; + + regs.clkdiv().write(|w| { + w.set_ratio(div); + }); + + regs.ibrd().write(|w| { + w.set_divint(ibrd); + }); + + regs.fbrd().write(|w| { + w.set_divfrac(fbrd); + }); + + regs.ctl0().modify(|w| { + w.set_hse(hse); + }); + + Ok(()) +} + +/// Calculate the integer and fractional parts of the `BRD` value. +/// +/// Returns [`None`] if calculating this results in overflows. +/// +/// Values returned are `(ibrd, fbrd)` +fn calculate_brd(clock: u32, div: u8, baud: u32, oversampling: u8) -> Option<(u16, u8)> { + use fixed::types::U26F6; + + // Calculate BRD according to SLAU 846 section 18.2.3.4. + // + // BRD is a 22-bit value with 16 integer bits and 6 fractional bits. + // + // uart_clock = clock / div + // brd = ibrd.fbrd = uart_clock / (oversampling * baud)" + // + // It is tempting to rearrange the equation such that there is only a single division in + // order to reduce error. However this is wrong since the denominator ends up being too + // small to represent in 6 fraction bits. This means that FBRD would always be 0. + // + // Calculations are done in a U16F6 format. However the fixed crate has no such representation. + // U26F6 is used since it has the same number of fractional bits and we verify at the end that + // the integer part did not overflow. + let clock = U26F6::from_num(clock); + let div = U26F6::from_num(div); + let oversampling = U26F6::from_num(oversampling); + let baud = U26F6::from_num(baud); + + let uart_clock = clock.checked_div(div)?; + + // oversampling * baud + let denom = oversampling.checked_mul(baud)?; + // uart_clock / (oversampling * baud) + let brd = uart_clock.checked_div(denom)?; + + // Checked is used to determine overflow in the 10 most singificant bits since the + // actual representation of BRD is U16F6. + let ibrd = brd.checked_to_num::()?; + + // We need to scale FBRD's representation to an integer. + let fbrd_scale = U26F6::from_num(2_u32.checked_pow(U26F6::FRAC_NBITS)?); + + // It is suggested that 0.5 is added to ensure that any fractional parts round up to the next + // integer. If it doesn't round up then it'll get discarded which is okay. + let half = U26F6::from_num(1) / U26F6::from_num(2); + // fbrd = INT(((FRAC(BRD) * 64) + 0.5)) + let fbrd = brd + .frac() + .checked_mul(fbrd_scale)? + .checked_add(half)? + .checked_to_num::()?; + + Some((ibrd, fbrd)) +} + +fn read_with_error(r: Regs) -> Result { + let rx = r.rxdata().read(); + + if rx.frmerr() { + return Err(Error::Framing); + } else if rx.parerr() { + return Err(Error::Parity); + } else if rx.brkerr() { + return Err(Error::Break); + } else if rx.ovrerr() { + return Err(Error::Overrun); + } else if rx.nerr() { + return Err(Error::Noise); + } + + Ok(rx.data()) +} + +pub(crate) trait SealedInstance { + fn info() -> &'static Info; + fn state() -> &'static State; +} + +macro_rules! impl_uart_instance { + ($instance: ident) => { + impl crate::uart::SealedInstance for crate::peripherals::$instance { + fn info() -> &'static crate::uart::Info { + use crate::interrupt::typelevel::Interrupt; + use crate::uart::Info; + + const INFO: Info = Info { + regs: crate::pac::$instance, + interrupt: crate::interrupt::typelevel::$instance::IRQ, + }; + &INFO + } + + fn state() -> &'static crate::uart::State { + use crate::interrupt::typelevel::Interrupt; + use crate::uart::State; + + static STATE: State = State { + clock: core::sync::atomic::AtomicU32::new(0), + }; + &STATE + } + } + + impl crate::uart::Instance for crate::peripherals::$instance { + type Interrupt = crate::interrupt::typelevel::$instance; + } + }; +} + +macro_rules! impl_uart_tx_pin { + ($instance: ident, $pin: ident, $pf: expr) => { + impl crate::uart::TxPin for crate::peripherals::$pin { + fn pf_num(&self) -> u8 { + $pf + } + } + }; +} + +macro_rules! impl_uart_rx_pin { + ($instance: ident, $pin: ident, $pf: expr) => { + impl crate::uart::RxPin for crate::peripherals::$pin { + fn pf_num(&self) -> u8 { + $pf + } + } + }; +} + +macro_rules! impl_uart_cts_pin { + ($instance: ident, $pin: ident, $pf: expr) => { + impl crate::uart::CtsPin for crate::peripherals::$pin { + fn pf_num(&self) -> u8 { + $pf + } + } + }; +} + +macro_rules! impl_uart_rts_pin { + ($instance: ident, $pin: ident, $pf: expr) => { + impl crate::uart::RtsPin for crate::peripherals::$pin { + fn pf_num(&self) -> u8 { + $pf + } + } + }; +} + +#[cfg(test)] +mod tests { + use super::calculate_brd; + + /// This is a smoke test based on the example in SLAU 846 section 18.2.3.4. + #[test] + fn datasheet() { + let brd = calculate_brd(40_000_000, 1, 19200, 16); + + assert!(matches!(brd, Some((130, 13)))); + } +} diff --git a/examples/mspm0c1104/Cargo.toml b/examples/mspm0c1104/Cargo.toml index 7c382482a..ba64a578d 100644 --- a/examples/mspm0c1104/Cargo.toml +++ b/examples/mspm0c1104/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-mspm0 = { version = "0.1.0", path = "../../embassy-mspm0", features = ["mspm0c110x", "rt", "time-driver-any"] } +embassy-mspm0 = { version = "0.1.0", path = "../../embassy-mspm0", features = ["mspm0c110x", "defmt", "rt", "time-driver-any"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt"] } embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt"] } diff --git a/examples/mspm0c1104/src/bin/uart.rs b/examples/mspm0c1104/src/bin/uart.rs new file mode 100644 index 000000000..da611aaac --- /dev/null +++ b/examples/mspm0c1104/src/bin/uart.rs @@ -0,0 +1,35 @@ +//! Example of using blocking uart +//! +//! This uses the virtual COM port provided on the LP-MSPM0C1104 board. + +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_mspm0::uart::{Config, Uart}; +use {defmt_rtt as _, panic_halt as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) -> ! { + info!("Hello world!"); + + let p = embassy_mspm0::init(Default::default()); + + let instance = p.UART0; + let tx = p.PA27; + let rx = p.PA26; + + let config = Config::default(); + let mut uart = unwrap!(Uart::new_blocking(instance, rx, tx, config)); + + unwrap!(uart.blocking_write(b"Hello Embassy World!\r\n")); + info!("wrote Hello, starting echo"); + + let mut buf = [0u8; 1]; + + loop { + unwrap!(uart.blocking_read(&mut buf)); + unwrap!(uart.blocking_write(&buf)); + } +} diff --git a/examples/mspm0g3507/Cargo.toml b/examples/mspm0g3507/Cargo.toml index 9bc82151c..f6fed091d 100644 --- a/examples/mspm0g3507/Cargo.toml +++ b/examples/mspm0g3507/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-mspm0 = { version = "0.1.0", path = "../../embassy-mspm0", features = ["mspm0g350x", "rt", "time-driver-any"] } +embassy-mspm0 = { version = "0.1.0", path = "../../embassy-mspm0", features = ["mspm0g350x", "defmt", "rt", "time-driver-any"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt"] } embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt"] } diff --git a/examples/mspm0g3507/src/bin/uart.rs b/examples/mspm0g3507/src/bin/uart.rs new file mode 100644 index 000000000..7e7e6db0e --- /dev/null +++ b/examples/mspm0g3507/src/bin/uart.rs @@ -0,0 +1,35 @@ +//! Example of using blocking uart +//! +//! This uses the virtual COM port provided on the LP-MSPM0G3507 board. + +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_mspm0::uart::{Config, Uart}; +use {defmt_rtt as _, panic_halt as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) -> ! { + info!("Hello world!"); + + let p = embassy_mspm0::init(Default::default()); + + let instance = p.UART0; + let tx = p.PA10; + let rx = p.PA11; + + let config = Config::default(); + let mut uart = unwrap!(Uart::new_blocking(instance, rx, tx, config)); + + unwrap!(uart.blocking_write(b"Hello Embassy World!\r\n")); + info!("wrote Hello, starting echo"); + + let mut buf = [0u8; 1]; + + loop { + unwrap!(uart.blocking_read(&mut buf)); + unwrap!(uart.blocking_write(&buf)); + } +} diff --git a/examples/mspm0g3519/Cargo.toml b/examples/mspm0g3519/Cargo.toml index a28ce2f11..1662e1f8d 100644 --- a/examples/mspm0g3519/Cargo.toml +++ b/examples/mspm0g3519/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-mspm0 = { version = "0.1.0", path = "../../embassy-mspm0", features = ["mspm0g351x", "rt", "time-driver-any"] } +embassy-mspm0 = { version = "0.1.0", path = "../../embassy-mspm0", features = ["mspm0g351x", "defmt", "rt", "time-driver-any"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt"] } embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt"] } diff --git a/examples/mspm0g3519/src/bin/uart.rs b/examples/mspm0g3519/src/bin/uart.rs new file mode 100644 index 000000000..498377c61 --- /dev/null +++ b/examples/mspm0g3519/src/bin/uart.rs @@ -0,0 +1,35 @@ +//! Example of using blocking uart +//! +//! This uses the virtual COM port provided on the LP-MSPM0G3519 board. + +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_mspm0::uart::{Config, Uart}; +use {defmt_rtt as _, panic_halt as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) -> ! { + info!("Hello world!"); + + let p = embassy_mspm0::init(Default::default()); + + let instance = p.UART0; + let tx = p.PA10; + let rx = p.PA11; + + let config = Config::default(); + let mut uart = unwrap!(Uart::new_blocking(instance, rx, tx, config)); + + unwrap!(uart.blocking_write(b"Hello Embassy World!\r\n")); + info!("wrote Hello, starting echo"); + + let mut buf = [0u8; 1]; + + loop { + unwrap!(uart.blocking_read(&mut buf)); + unwrap!(uart.blocking_write(&buf)); + } +} diff --git a/examples/mspm0l1306/Cargo.toml b/examples/mspm0l1306/Cargo.toml index 3962eb156..609b3f205 100644 --- a/examples/mspm0l1306/Cargo.toml +++ b/examples/mspm0l1306/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-mspm0 = { version = "0.1.0", path = "../../embassy-mspm0", features = ["mspm0l130x", "rt", "time-driver-any"] } +embassy-mspm0 = { version = "0.1.0", path = "../../embassy-mspm0", features = ["mspm0l130x", "defmt", "rt", "time-driver-any"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt"] } embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt"] } diff --git a/examples/mspm0l1306/src/bin/uart.rs b/examples/mspm0l1306/src/bin/uart.rs new file mode 100644 index 000000000..95c56fdd3 --- /dev/null +++ b/examples/mspm0l1306/src/bin/uart.rs @@ -0,0 +1,35 @@ +//! Example of using blocking uart +//! +//! This uses the virtual COM port provided on the LP-MSPM0L1306 board. + +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_mspm0::uart::{Config, Uart}; +use {defmt_rtt as _, panic_halt as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) -> ! { + info!("Hello world!"); + + let p = embassy_mspm0::init(Default::default()); + + let instance = p.UART0; + let tx = p.PA8; + let rx = p.PA9; + + let config = Config::default(); + let mut uart = unwrap!(Uart::new_blocking(instance, rx, tx, config)); + + unwrap!(uart.blocking_write(b"Hello Embassy World!\r\n")); + info!("wrote Hello, starting echo"); + + let mut buf = [0u8; 1]; + + loop { + unwrap!(uart.blocking_read(&mut buf)); + unwrap!(uart.blocking_write(&buf)); + } +} diff --git a/examples/mspm0l2228/Cargo.toml b/examples/mspm0l2228/Cargo.toml index abebcc00d..bbca011a1 100644 --- a/examples/mspm0l2228/Cargo.toml +++ b/examples/mspm0l2228/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-mspm0 = { version = "0.1.0", path = "../../embassy-mspm0", features = ["mspm0l222x", "rt", "time-driver-any"] } +embassy-mspm0 = { version = "0.1.0", path = "../../embassy-mspm0", features = ["mspm0l222x", "defmt", "rt", "time-driver-any"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt"] } embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt"] } diff --git a/examples/mspm0l2228/src/bin/uart.rs b/examples/mspm0l2228/src/bin/uart.rs new file mode 100644 index 000000000..a266add47 --- /dev/null +++ b/examples/mspm0l2228/src/bin/uart.rs @@ -0,0 +1,35 @@ +//! Example of using blocking uart +//! +//! This uses the virtual COM port provided on the LP-MSPM0L2228 board. + +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_mspm0::uart::{Config, Uart}; +use {defmt_rtt as _, panic_halt as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) -> ! { + info!("Hello world!"); + + let p = embassy_mspm0::init(Default::default()); + + let instance = p.UART0; + let tx = p.PA10; + let rx = p.PA11; + + let config = Config::default(); + let mut uart = unwrap!(Uart::new_blocking(instance, rx, tx, config)); + + unwrap!(uart.blocking_write(b"Hello Embassy World!\r\n")); + info!("wrote Hello, starting echo"); + + let mut buf = [0u8; 1]; + + loop { + unwrap!(uart.blocking_read(&mut buf)); + unwrap!(uart.blocking_write(&buf)); + } +} From c72e2c5d100fd42acdd3a39f6250c112c2a37495 Mon Sep 17 00:00:00 2001 From: Matthew Tran <0e4ef622@gmail.com> Date: Sat, 29 Mar 2025 02:45:38 -0500 Subject: [PATCH 0887/1217] Add test --- embassy-executor/tests/ui.rs | 1 + embassy-executor/tests/ui/type_error.rs | 8 ++++++++ embassy-executor/tests/ui/type_error.stderr | 7 +++++++ 3 files changed, 16 insertions(+) create mode 100644 embassy-executor/tests/ui/type_error.rs create mode 100644 embassy-executor/tests/ui/type_error.stderr diff --git a/embassy-executor/tests/ui.rs b/embassy-executor/tests/ui.rs index be4679485..278a4b903 100644 --- a/embassy-executor/tests/ui.rs +++ b/embassy-executor/tests/ui.rs @@ -19,5 +19,6 @@ fn ui() { t.compile_fail("tests/ui/not_async.rs"); t.compile_fail("tests/ui/self_ref.rs"); t.compile_fail("tests/ui/self.rs"); + t.compile_fail("tests/ui/type_error.rs"); t.compile_fail("tests/ui/where_clause.rs"); } diff --git a/embassy-executor/tests/ui/type_error.rs b/embassy-executor/tests/ui/type_error.rs new file mode 100644 index 000000000..1734bc6c4 --- /dev/null +++ b/embassy-executor/tests/ui/type_error.rs @@ -0,0 +1,8 @@ +#![cfg_attr(feature = "nightly", feature(impl_trait_in_assoc_type))] + +#[embassy_executor::task] +async fn task() { + 5 +} + +fn main() {} diff --git a/embassy-executor/tests/ui/type_error.stderr b/embassy-executor/tests/ui/type_error.stderr new file mode 100644 index 000000000..bce315811 --- /dev/null +++ b/embassy-executor/tests/ui/type_error.stderr @@ -0,0 +1,7 @@ +error[E0308]: mismatched types + --> tests/ui/type_error.rs:5:5 + | +4 | async fn task() { + | - help: try adding a return type: `-> i32` +5 | 5 + | ^ expected `()`, found integer From 35b353ab948256f4ae959767a7652c24bd42cd57 Mon Sep 17 00:00:00 2001 From: Matthew Tran <0e4ef622@gmail.com> Date: Sat, 29 Mar 2025 02:06:49 -0500 Subject: [PATCH 0888/1217] Fix ugly compiler errors --- embassy-executor-macros/src/macros/task.rs | 26 +++++++++++++--------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/embassy-executor-macros/src/macros/task.rs b/embassy-executor-macros/src/macros/task.rs index 8a2a7fdb9..e5523c5cd 100644 --- a/embassy-executor-macros/src/macros/task.rs +++ b/embassy-executor-macros/src/macros/task.rs @@ -145,33 +145,39 @@ pub fn run(args: TokenStream, item: TokenStream) -> TokenStream { }; #[cfg(not(feature = "nightly"))] let mut task_outer_body = quote! { - const fn __task_pool_size(_: F) -> usize + // We use Fut instead of F::Fut because F::Fut causes the compiler to generate some ugly + // unrelated errors when the task has a compile error. + const fn __task_pool_size(_: F) -> usize where - F: #embassy_executor::_export::TaskFn, + F: #embassy_executor::_export::TaskFn, + Fut: ::core::future::Future + 'static, { ::core::mem::size_of::< - #embassy_executor::raw::TaskPool + #embassy_executor::raw::TaskPool >() } - const fn __task_pool_align(_: F) -> usize + const fn __task_pool_align(_: F) -> usize where - F: #embassy_executor::_export::TaskFn, + F: #embassy_executor::_export::TaskFn, + Fut: ::core::future::Future + 'static, { ::core::mem::align_of::< - #embassy_executor::raw::TaskPool + #embassy_executor::raw::TaskPool >() } - const fn __task_pool_new(_: F) -> #embassy_executor::raw::TaskPool + const fn __task_pool_new(_: F) -> #embassy_executor::raw::TaskPool where - F: #embassy_executor::_export::TaskFn, + F: #embassy_executor::_export::TaskFn, + Fut: ::core::future::Future + 'static, { #embassy_executor::raw::TaskPool::new() } - const fn __task_pool_get(_: F) -> &'static #embassy_executor::raw::TaskPool + const fn __task_pool_get(_: F) -> &'static #embassy_executor::raw::TaskPool where - F: #embassy_executor::_export::TaskFn + F: #embassy_executor::_export::TaskFn, + Fut: ::core::future::Future + 'static, { unsafe { &*POOL.get().cast() } } From 034e9fc218f1a348f451f56a5b9f3941fc046b1a Mon Sep 17 00:00:00 2001 From: Matthew Tran <0e4ef622@gmail.com> Date: Sat, 29 Mar 2025 02:45:48 -0500 Subject: [PATCH 0889/1217] Move macro helper functions to embassy-executor --- embassy-executor-macros/src/macros/task.rs | 35 ++-------------------- embassy-executor/src/lib.rs | 26 ++++++++++++++++ 2 files changed, 29 insertions(+), 32 deletions(-) diff --git a/embassy-executor-macros/src/macros/task.rs b/embassy-executor-macros/src/macros/task.rs index e5523c5cd..91d6beee8 100644 --- a/embassy-executor-macros/src/macros/task.rs +++ b/embassy-executor-macros/src/macros/task.rs @@ -145,35 +145,6 @@ pub fn run(args: TokenStream, item: TokenStream) -> TokenStream { }; #[cfg(not(feature = "nightly"))] let mut task_outer_body = quote! { - // We use Fut instead of F::Fut because F::Fut causes the compiler to generate some ugly - // unrelated errors when the task has a compile error. - const fn __task_pool_size(_: F) -> usize - where - F: #embassy_executor::_export::TaskFn, - Fut: ::core::future::Future + 'static, - { - ::core::mem::size_of::< - #embassy_executor::raw::TaskPool - >() - } - const fn __task_pool_align(_: F) -> usize - where - F: #embassy_executor::_export::TaskFn, - Fut: ::core::future::Future + 'static, - { - ::core::mem::align_of::< - #embassy_executor::raw::TaskPool - >() - } - - const fn __task_pool_new(_: F) -> #embassy_executor::raw::TaskPool - where - F: #embassy_executor::_export::TaskFn, - Fut: ::core::future::Future + 'static, - { - #embassy_executor::raw::TaskPool::new() - } - const fn __task_pool_get(_: F) -> &'static #embassy_executor::raw::TaskPool where F: #embassy_executor::_export::TaskFn, @@ -184,9 +155,9 @@ pub fn run(args: TokenStream, item: TokenStream) -> TokenStream { const POOL_SIZE: usize = #pool_size; static POOL: #embassy_executor::_export::TaskPoolHolder< - {__task_pool_size(#task_inner_ident)}, - {__task_pool_align(#task_inner_ident)}, - > = unsafe { ::core::mem::transmute(__task_pool_new(#task_inner_ident)) }; + {#embassy_executor::_export::task_pool_size::<_, _, _, POOL_SIZE>(#task_inner_ident)}, + {#embassy_executor::_export::task_pool_align::<_, _, _, POOL_SIZE>(#task_inner_ident)}, + > = unsafe { ::core::mem::transmute(#embassy_executor::_export::task_pool_new::<_, _, _, POOL_SIZE>(#task_inner_ident)) }; unsafe { __task_pool_get(#task_inner_ident)._spawn_async_fn(move || #task_inner_ident(#(#full_args,)*)) } }; diff --git a/embassy-executor/src/lib.rs b/embassy-executor/src/lib.rs index 5485f6a6a..d6bd63665 100644 --- a/embassy-executor/src/lib.rs +++ b/embassy-executor/src/lib.rs @@ -59,6 +59,8 @@ pub mod _export { use core::future::Future; use core::mem::MaybeUninit; + use crate::raw::TaskPool; + pub trait TaskFn: Copy { type Fut: Future + 'static; } @@ -116,6 +118,30 @@ pub mod _export { } } + pub const fn task_pool_size(_: F) -> usize + where + F: TaskFn, + Fut: Future + 'static, + { + size_of::>() + } + + pub const fn task_pool_align(_: F) -> usize + where + F: TaskFn, + Fut: Future + 'static, + { + align_of::>() + } + + pub const fn task_pool_new(_: F) -> TaskPool + where + F: TaskFn, + Fut: Future + 'static, + { + TaskPool::new() + } + #[allow(private_bounds)] #[repr(transparent)] pub struct Align([::Archetype; 0]) From ca8be1c976b82a368622899fdf7192294bd81363 Mon Sep 17 00:00:00 2001 From: elagil Date: Sat, 29 Mar 2025 22:01:54 +0100 Subject: [PATCH 0890/1217] fix: stm32g4 calibration delays --- embassy-stm32/src/adc/g4.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/embassy-stm32/src/adc/g4.rs b/embassy-stm32/src/adc/g4.rs index 6a00e788e..6b9182ad6 100644 --- a/embassy-stm32/src/adc/g4.rs +++ b/embassy-stm32/src/adc/g4.rs @@ -171,7 +171,7 @@ impl<'d, T: Instance> Adc<'d, T> { reg.set_advregen(true); }); - blocking_delay_us(10); + blocking_delay_us(20); } fn configure_differential_inputs(&mut self) { @@ -191,6 +191,8 @@ impl<'d, T: Instance> Adc<'d, T> { while T::regs().cr().read().adcal() {} + blocking_delay_us(20); + T::regs().cr().modify(|w| { w.set_adcaldif(Adcaldif::DIFFERENTIAL); }); @@ -198,6 +200,8 @@ impl<'d, T: Instance> Adc<'d, T> { T::regs().cr().modify(|w| w.set_adcal(true)); while T::regs().cr().read().adcal() {} + + blocking_delay_us(20); } fn enable(&mut self) { From f396579dff18eea80555ed56a4905ce9d9fab574 Mon Sep 17 00:00:00 2001 From: Cyril Marpaud <9333398+cyril-marpaud@users.noreply.github.com> Date: Mon, 31 Mar 2025 13:07:03 +0200 Subject: [PATCH 0891/1217] docs: fix a typo --- embassy-sync/src/zerocopy_channel.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-sync/src/zerocopy_channel.rs b/embassy-sync/src/zerocopy_channel.rs index ad6fe74c5..e3e5b2538 100644 --- a/embassy-sync/src/zerocopy_channel.rs +++ b/embassy-sync/src/zerocopy_channel.rs @@ -195,7 +195,7 @@ pub struct Receiver<'a, M: RawMutex, T> { } impl<'a, M: RawMutex, T> Receiver<'a, M, T> { - /// Creates one further [`Sender`] over the same channel. + /// Creates one further [`Receiver`] over the same channel. pub fn borrow(&mut self) -> Receiver<'_, M, T> { Receiver { channel: self.channel } } From aa5ecbdb56aa5c3cf35d5c0512c0a0e2a3739cee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Mon, 31 Mar 2025 13:16:11 +0200 Subject: [PATCH 0892/1217] Remove task arena FAQ --- docs/pages/faq.adoc | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/docs/pages/faq.adoc b/docs/pages/faq.adoc index f95ccf48b..88e0c3330 100644 --- a/docs/pages/faq.adoc +++ b/docs/pages/faq.adoc @@ -169,29 +169,6 @@ Note that the git revision should match any other embassy patches or git depende ** make `main` spawn everything, then enable link:https://docs.rs/cortex-m/latest/cortex_m/peripheral/struct.SCB.html#method.set_sleeponexit[SCB.SLEEPONEXIT] and `loop { cortex_m::asm::wfi() }` ** *Note:* If you need 2 priority levels, using 2 interrupt executors is better than 1 thread executor + 1 interrupt executor. -== How do I set up the task arenas on stable? - -When you aren't using the `nightly` feature of `embassy-executor`, the executor uses a bump allocator, which may require configuration. - -Something like this error will occur at **compile time** if the task arena is *too large* for the target's RAM: - -[source,plain] ----- -rust-lld: error: section '.bss' will not fit in region 'RAM': overflowed by _ bytes -rust-lld: error: section '.uninit' will not fit in region 'RAM': overflowed by _ bytes ----- - -And this message will appear at **runtime** if the task arena is *too small* for the tasks running: - -[source,plain] ----- -ERROR panicked at 'embassy-executor: task arena is full. You must increase the arena size, see the documentation for details: https://docs.embassy.dev/embassy-executor/' ----- - -NOTE: If all tasks are spawned at startup, this panic will occur immediately. - -Check out link:https://docs.embassy.dev/embassy-executor/git/cortex-m/index.html#task-arena[Task Arena Documentation] for more details. - == Can I use manual ISRs alongside Embassy? Yes! This can be useful if you need to respond to an event as fast as possible, and the latency caused by the usual “ISR, wake, return from ISR, context switch to woken task†flow is too much for your application. Simply define a `#[interrupt] fn INTERRUPT_NAME() {}` handler as you would link:https://docs.rust-embedded.org/book/start/interrupts.html[in any other embedded rust project]. From 280d21a6b415a1c856d08d338afd829b41e9b0b8 Mon Sep 17 00:00:00 2001 From: Anton Lazarev Date: Mon, 24 Mar 2025 10:49:47 -0700 Subject: [PATCH 0893/1217] update sdio-host to 0.6 --- embassy-stm32/Cargo.toml | 2 +- embassy-stm32/src/sdmmc/mod.rs | 20 ++++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 8204a0fea..8468436d8 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -70,7 +70,7 @@ cortex-m-rt = ">=0.6.15,<0.8" cortex-m = "0.7.6" futures-util = { version = "0.3.30", default-features = false } rand_core = "0.6.3" -sdio-host = "0.5.0" +sdio-host = "0.6.0" critical-section = "1.1" #stm32-metapac = { version = "16" } stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-4a964af03b298de30ff9f84fcfa890bcab4ce609" } diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs index 8f3c45f50..3cfae7ee1 100644 --- a/embassy-stm32/src/sdmmc/mod.rs +++ b/embassy-stm32/src/sdmmc/mod.rs @@ -10,7 +10,7 @@ use core::task::Poll; use embassy_hal_internal::drop::OnDrop; use embassy_hal_internal::{Peri, PeripheralType}; use embassy_sync::waitqueue::AtomicWaker; -use sdio_host::{BusWidth, CardCapacity, CardStatus, CurrentState, SDStatus, CID, CSD, OCR, SCR}; +use sdio_host::sd::{BusWidth, CardCapacity, CardStatus, CurrentState, SDStatus, CID, CSD, OCR, SCR, SD}; #[cfg(sdmmc_v1)] use crate::dma::ChannelAndRequest; @@ -162,13 +162,13 @@ pub struct Card { /// The type of this card pub card_type: CardCapacity, /// Operation Conditions Register - pub ocr: OCR, + pub ocr: OCR, /// Relative Card Address pub rca: u32, /// Card ID - pub cid: CID, + pub cid: CID, /// Card Specific Data - pub csd: CSD, + pub csd: CSD, /// SD CARD Configuration Register pub scr: SCR, /// SD Status @@ -765,7 +765,7 @@ impl<'d, T: Instance> Sdmmc<'d, T> { } /// Query the card status (CMD13, returns R1) - fn read_status(&self, card: &Card) -> Result { + fn read_status(&self, card: &Card) -> Result, Error> { let regs = T::regs(); let rca = card.rca; @@ -1089,7 +1089,7 @@ impl<'d, T: Instance> Sdmmc<'d, T> { Err(Error::Crc) => (), Err(err) => return Err(err), } - let ocr: OCR = regs.respr(0).read().cardstatus().into(); + let ocr: OCR = regs.respr(0).read().cardstatus().into(); if !ocr.is_busy() { // Power up done break ocr; @@ -1098,9 +1098,9 @@ impl<'d, T: Instance> Sdmmc<'d, T> { if ocr.high_capacity() { // Card is SDHC or SDXC or SDUC - card.card_type = CardCapacity::SDHC; + card.card_type = CardCapacity::HighCapacity; } else { - card.card_type = CardCapacity::SDSC; + card.card_type = CardCapacity::StandardCapacity; } card.ocr = ocr; @@ -1193,7 +1193,7 @@ impl<'d, T: Instance> Sdmmc<'d, T> { // Always read 1 block of 512 bytes // SDSC cards are byte addressed hence the blockaddress is in multiples of 512 bytes let address = match card_capacity { - CardCapacity::SDSC => block_idx * 512, + CardCapacity::StandardCapacity => block_idx * 512, _ => block_idx, }; Self::cmd(Cmd::set_block_length(512), false)?; // CMD16 @@ -1252,7 +1252,7 @@ impl<'d, T: Instance> Sdmmc<'d, T> { // Always read 1 block of 512 bytes // SDSC cards are byte addressed hence the blockaddress is in multiples of 512 bytes let address = match card.card_type { - CardCapacity::SDSC => block_idx * 512, + CardCapacity::StandardCapacity => block_idx * 512, _ => block_idx, }; Self::cmd(Cmd::set_block_length(512), false)?; // CMD16 From d22a7a3a9668d8d163068ffc4f4b4c3478cb5a1c Mon Sep 17 00:00:00 2001 From: Anton Lazarev Date: Mon, 24 Mar 2025 10:50:25 -0700 Subject: [PATCH 0894/1217] update sdio-host to 0.9 --- embassy-stm32/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 8468436d8..33eb39584 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -70,7 +70,7 @@ cortex-m-rt = ">=0.6.15,<0.8" cortex-m = "0.7.6" futures-util = { version = "0.3.30", default-features = false } rand_core = "0.6.3" -sdio-host = "0.6.0" +sdio-host = "0.9.0" critical-section = "1.1" #stm32-metapac = { version = "16" } stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-4a964af03b298de30ff9f84fcfa890bcab4ce609" } From 5d01712d840af0b48c4d85a1f9347a157991f88e Mon Sep 17 00:00:00 2001 From: Anton Lazarev Date: Mon, 24 Mar 2025 12:47:08 -0700 Subject: [PATCH 0895/1217] use upstream command definitions --- embassy-stm32/src/sdmmc/mod.rs | 206 +++++++++------------------------ 1 file changed, 55 insertions(+), 151 deletions(-) diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs index 3cfae7ee1..2229347f4 100644 --- a/embassy-stm32/src/sdmmc/mod.rs +++ b/embassy-stm32/src/sdmmc/mod.rs @@ -10,7 +10,11 @@ use core::task::Poll; use embassy_hal_internal::drop::OnDrop; use embassy_hal_internal::{Peri, PeripheralType}; use embassy_sync::waitqueue::AtomicWaker; -use sdio_host::sd::{BusWidth, CardCapacity, CardStatus, CurrentState, SDStatus, CID, CSD, OCR, SCR, SD}; +use sdio_host::{ + common_cmd::{self, Resp, ResponseLen}, + sd::{BusWidth, CardCapacity, CardStatus, CurrentState, SDStatus, CIC, CID, CSD, OCR, RCA, SCR, SD}, + sd_cmd, Cmd, +}; #[cfg(sdmmc_v1)] use crate::dma::ChannelAndRequest; @@ -136,6 +140,8 @@ pub enum Error { UnsupportedCardVersion, /// Unsupported card type. UnsupportedCardType, + /// Unsupported voltage. + UnsupportedVoltage, /// CRC error. Crc, /// No card inserted. @@ -149,13 +155,6 @@ pub enum Error { StBitErr, } -/// A SD command -struct Cmd { - cmd: u8, - arg: u32, - resp: Response, -} - #[derive(Clone, Copy, Debug, Default)] /// SD Card pub struct Card { @@ -164,7 +163,7 @@ pub struct Card { /// Operation Conditions Register pub ocr: OCR, /// Relative Card Address - pub rca: u32, + pub rca: u16, /// Card ID pub cid: CID, /// Card Specific Data @@ -189,22 +188,12 @@ enum PowerCtrl { On = 0b11, } -#[repr(u32)] -#[allow(dead_code)] -#[allow(non_camel_case_types)] -enum CmdAppOper { - VOLTAGE_WINDOW_SD = 0x8010_0000, - HIGH_CAPACITY = 0x4000_0000, - SDMMC_STD_CAPACITY = 0x0000_0000, - SDMMC_CHECK_PATTERN = 0x0000_01AA, - SD_SWITCH_1_8V_CAPACITY = 0x0100_0000, -} - -#[derive(Eq, PartialEq, Copy, Clone)] -enum Response { - None = 0, - Short = 1, - Long = 3, +fn get_waitresp_val(rlen: ResponseLen) -> u8 { + match rlen { + common_cmd::ResponseLen::Zero => 0, + common_cmd::ResponseLen::R48 => 1, + common_cmd::ResponseLen::R136 => 3, + } } /// Calculate clock divisor. Returns a SDMMC_CK less than or equal to @@ -710,7 +699,7 @@ impl<'d, T: Instance> Sdmmc<'d, T> { 6, ); InterruptHandler::::data_interrupts(true); - Self::cmd(Cmd::cmd6(set_function), true)?; // CMD6 + Self::cmd(sd_cmd::cmd6(set_function), true)?; // CMD6 let res = poll_fn(|cx| { T::state().register(cx.waker()); @@ -769,7 +758,7 @@ impl<'d, T: Instance> Sdmmc<'d, T> { let regs = T::regs(); let rca = card.rca; - Self::cmd(Cmd::card_status(rca << 16), false)?; // CMD13 + Self::cmd(common_cmd::card_status(rca, false), false)?; // CMD13 let r1 = regs.respr(0).read().cardstatus(); Ok(r1.into()) @@ -785,8 +774,8 @@ impl<'d, T: Instance> Sdmmc<'d, T> { None => &mut CmdBlock::new(), }; - Self::cmd(Cmd::set_block_length(64), false)?; // CMD16 - Self::cmd(Cmd::app_cmd(rca << 16), false)?; // APP + Self::cmd(common_cmd::set_block_length(64), false)?; // CMD16 + Self::cmd(common_cmd::app_cmd(rca), false)?; // APP let status = cmd_block; @@ -803,7 +792,7 @@ impl<'d, T: Instance> Sdmmc<'d, T> { 6, ); InterruptHandler::::data_interrupts(true); - Self::cmd(Cmd::card_status(0), true)?; + Self::cmd(sd_cmd::sd_status(), true)?; let res = poll_fn(|cx| { T::state().register(cx.waker()); @@ -846,9 +835,9 @@ impl<'d, T: Instance> Sdmmc<'d, T> { /// _Stand-by State_ fn select_card(&self, card: Option<&Card>) -> Result<(), Error> { // Determine Relative Card Address (RCA) of given card - let rca = card.map(|c| c.rca << 16).unwrap_or(0); + let rca = card.map(|c| c.rca).unwrap_or(0); - let r = Self::cmd(Cmd::sel_desel_card(rca), false); + let r = Self::cmd(common_cmd::select_card(rca), false); match (r, rca) { (Err(Error::Timeout), 0) => Ok(()), _ => r, @@ -891,8 +880,8 @@ impl<'d, T: Instance> Sdmmc<'d, T> { async fn get_scr(&mut self, card: &mut Card) -> Result<(), Error> { // Read the 64-bit SCR register - Self::cmd(Cmd::set_block_length(8), false)?; // CMD16 - Self::cmd(Cmd::app_cmd(card.rca << 16), false)?; + Self::cmd(common_cmd::set_block_length(8), false)?; // CMD16 + Self::cmd(common_cmd::app_cmd(card.rca), false)?; let cmd_block = match self.cmd_block.as_deref_mut() { Some(x) => x, @@ -913,7 +902,7 @@ impl<'d, T: Instance> Sdmmc<'d, T> { 3, ); InterruptHandler::::data_interrupts(true); - Self::cmd(Cmd::cmd51(), true)?; + Self::cmd(sd_cmd::send_scr(), true)?; let res = poll_fn(|cx| { T::state().register(cx.waker()); @@ -952,7 +941,7 @@ impl<'d, T: Instance> Sdmmc<'d, T> { /// Send command to card #[allow(unused_variables)] - fn cmd(cmd: Cmd, data: bool) -> Result<(), Error> { + fn cmd(cmd: Cmd, data: bool) -> Result<(), Error> { let regs = T::regs(); Self::clear_interrupt_flags(); @@ -965,7 +954,7 @@ impl<'d, T: Instance> Sdmmc<'d, T> { // Command index and start CP State Machine regs.cmdr().write(|w| { w.set_waitint(false); - w.set_waitresp(cmd.resp as u8); + w.set_waitresp(get_waitresp_val(cmd.response_len())); w.set_cmdindex(cmd.cmd); w.set_cpsmen(true); @@ -980,7 +969,7 @@ impl<'d, T: Instance> Sdmmc<'d, T> { }); let mut status; - if cmd.resp == Response::None { + if cmd.response_len() == ResponseLen::Zero { // Wait for CMDSENT or a timeout while { status = regs.star().read(); @@ -1016,7 +1005,7 @@ impl<'d, T: Instance> Sdmmc<'d, T> { // Command index and start CP State Machine regs.cmdr().write(|w| { w.set_waitint(false); - w.set_waitresp(Response::Short as u8); + w.set_waitresp(get_waitresp_val(ResponseLen::R48)); w.set_cmdindex(12); w.set_cpsmen(true); @@ -1061,29 +1050,30 @@ impl<'d, T: Instance> Sdmmc<'d, T> { }); regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::On as u8)); - Self::cmd(Cmd::idle(), false)?; + Self::cmd(common_cmd::idle(), false)?; // Check if cards supports CMD8 (with pattern) - Self::cmd(Cmd::hs_send_ext_csd(0x1AA), false)?; - let r1 = regs.respr(0).read().cardstatus(); + Self::cmd(sd_cmd::send_if_cond(1, 0xAA), false)?; + let cic = CIC::from(regs.respr(0).read().cardstatus()); - let mut card = if r1 == 0x1AA { - // Card echoed back the pattern. Must be at least v2 - Card::default() - } else { + if cic.pattern() != 0xAA { return Err(Error::UnsupportedCardVersion); - }; + } + + if cic.voltage_accepted() & 1 == 0 { + return Err(Error::UnsupportedVoltage); + } + + let mut card = Card::default(); let ocr = loop { // Signal that next command is a app command - Self::cmd(Cmd::app_cmd(0), false)?; // CMD55 - - let arg = CmdAppOper::VOLTAGE_WINDOW_SD as u32 - | CmdAppOper::HIGH_CAPACITY as u32 - | CmdAppOper::SD_SWITCH_1_8V_CAPACITY as u32; + Self::cmd(common_cmd::app_cmd(0), false)?; // CMD55 + // 3.2-3.3V + let voltage_window = 1 << 5; // Initialize card - match Self::cmd(Cmd::app_op_cmd(arg), false) { + match Self::cmd(sd_cmd::sd_send_op_cond(true, false, true, voltage_window), false) { // ACMD41 Ok(_) => (), Err(Error::Crc) => (), @@ -1104,7 +1094,7 @@ impl<'d, T: Instance> Sdmmc<'d, T> { } card.ocr = ocr; - Self::cmd(Cmd::all_send_cid(), false)?; // CMD2 + Self::cmd(common_cmd::all_send_cid(), false)?; // CMD2 let cid0 = regs.respr(0).read().cardstatus() as u128; let cid1 = regs.respr(1).read().cardstatus() as u128; let cid2 = regs.respr(2).read().cardstatus() as u128; @@ -1112,10 +1102,11 @@ impl<'d, T: Instance> Sdmmc<'d, T> { let cid = (cid0 << 96) | (cid1 << 64) | (cid2 << 32) | (cid3); card.cid = cid.into(); - Self::cmd(Cmd::send_rel_addr(), false)?; - card.rca = regs.respr(0).read().cardstatus() >> 16; + Self::cmd(sd_cmd::send_relative_address(), false)?; + let rca = RCA::::from(regs.respr(0).read().cardstatus()); + card.rca = rca.address(); - Self::cmd(Cmd::send_csd(card.rca << 16), false)?; + Self::cmd(common_cmd::send_csd(card.rca), false)?; let csd0 = regs.respr(0).read().cardstatus() as u128; let csd1 = regs.respr(1).read().cardstatus() as u128; let csd2 = regs.respr(2).read().cardstatus() as u128; @@ -1133,8 +1124,8 @@ impl<'d, T: Instance> Sdmmc<'d, T> { BusWidth::Four if card.scr.bus_width_four() => (BusWidth::Four, 2), _ => (BusWidth::One, 0), }; - Self::cmd(Cmd::app_cmd(card.rca << 16), false)?; - Self::cmd(Cmd::cmd6(acmd_arg), false)?; + Self::cmd(common_cmd::app_cmd(card.rca), false)?; + Self::cmd(sd_cmd::cmd6(acmd_arg), false)?; // CPSMACT and DPSMACT must be 0 to set WIDBUS Self::wait_idle(); @@ -1196,7 +1187,7 @@ impl<'d, T: Instance> Sdmmc<'d, T> { CardCapacity::StandardCapacity => block_idx * 512, _ => block_idx, }; - Self::cmd(Cmd::set_block_length(512), false)?; // CMD16 + Self::cmd(common_cmd::set_block_length(512), false)?; // CMD16 let regs = T::regs(); let on_drop = OnDrop::new(|| Self::on_drop()); @@ -1210,7 +1201,7 @@ impl<'d, T: Instance> Sdmmc<'d, T> { 9, ); InterruptHandler::::data_interrupts(true); - Self::cmd(Cmd::read_single_block(address), true)?; + Self::cmd(common_cmd::read_single_block(address), true)?; let res = poll_fn(|cx| { T::state().register(cx.waker()); @@ -1255,20 +1246,20 @@ impl<'d, T: Instance> Sdmmc<'d, T> { CardCapacity::StandardCapacity => block_idx * 512, _ => block_idx, }; - Self::cmd(Cmd::set_block_length(512), false)?; // CMD16 + Self::cmd(common_cmd::set_block_length(512), false)?; // CMD16 let regs = T::regs(); let on_drop = OnDrop::new(|| Self::on_drop()); // sdmmc_v1 uses different cmd/dma order than v2, but only for writes #[cfg(sdmmc_v1)] - Self::cmd(Cmd::write_single_block(address), true)?; + Self::cmd(common_cmd::write_single_block(address), true)?; let transfer = self.prepare_datapath_write(buffer, 512, 9); InterruptHandler::::data_interrupts(true); #[cfg(sdmmc_v2)] - Self::cmd(Cmd::write_single_block(address), true)?; + Self::cmd(common_cmd::write_single_block(address), true)?; let res = poll_fn(|cx| { T::state().register(cx.waker()); @@ -1363,93 +1354,6 @@ impl<'d, T: Instance> Drop for Sdmmc<'d, T> { } } -/// SD card Commands -impl Cmd { - const fn new(cmd: u8, arg: u32, resp: Response) -> Cmd { - Cmd { cmd, arg, resp } - } - - /// CMD0: Idle - const fn idle() -> Cmd { - Cmd::new(0, 0, Response::None) - } - - /// CMD2: Send CID - const fn all_send_cid() -> Cmd { - Cmd::new(2, 0, Response::Long) - } - - /// CMD3: Send Relative Address - const fn send_rel_addr() -> Cmd { - Cmd::new(3, 0, Response::Short) - } - - /// CMD6: Switch Function Command - /// ACMD6: Bus Width - const fn cmd6(arg: u32) -> Cmd { - Cmd::new(6, arg, Response::Short) - } - - /// CMD7: Select one card and put it into the _Tranfer State_ - const fn sel_desel_card(rca: u32) -> Cmd { - Cmd::new(7, rca, Response::Short) - } - - /// CMD8: - const fn hs_send_ext_csd(arg: u32) -> Cmd { - Cmd::new(8, arg, Response::Short) - } - - /// CMD9: - const fn send_csd(rca: u32) -> Cmd { - Cmd::new(9, rca, Response::Long) - } - - /// CMD12: - //const fn stop_transmission() -> Cmd { - // Cmd::new(12, 0, Response::Short) - //} - - /// CMD13: Ask card to send status register - /// ACMD13: SD Status - const fn card_status(rca: u32) -> Cmd { - Cmd::new(13, rca, Response::Short) - } - - /// CMD16: - const fn set_block_length(blocklen: u32) -> Cmd { - Cmd::new(16, blocklen, Response::Short) - } - - /// CMD17: Block Read - const fn read_single_block(addr: u32) -> Cmd { - Cmd::new(17, addr, Response::Short) - } - - /// CMD18: Multiple Block Read - //const fn read_multiple_blocks(addr: u32) -> Cmd { - // Cmd::new(18, addr, Response::Short) - //} - - /// CMD24: Block Write - const fn write_single_block(addr: u32) -> Cmd { - Cmd::new(24, addr, Response::Short) - } - - const fn app_op_cmd(arg: u32) -> Cmd { - Cmd::new(41, arg, Response::Short) - } - - const fn cmd51() -> Cmd { - Cmd::new(51, 0, Response::Short) - } - - /// App Command. Indicates that next command will be a app command - const fn app_cmd(rca: u32) -> Cmd { - Cmd::new(55, rca, Response::Short) - } -} - ////////////////////////////////////////////////////// trait SealedInstance { From 14bb4ee9e414137f318f64e82d808d4012e30680 Mon Sep 17 00:00:00 2001 From: Anton Lazarev Date: Mon, 31 Mar 2025 11:43:35 -0700 Subject: [PATCH 0896/1217] use ready_for_data status to determine when write has finished `read_sd_status` works, but it's somewhat of a hack, but also won't work on eMMC devices. The official spec for both SD and eMMC recommends using this method. --- embassy-stm32/src/sdmmc/mod.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs index 2229347f4..a28fd51e8 100644 --- a/embassy-stm32/src/sdmmc/mod.rs +++ b/embassy-stm32/src/sdmmc/mod.rs @@ -1292,12 +1292,12 @@ impl<'d, T: Instance> Sdmmc<'d, T> { // TODO: Make this configurable let mut timeout: u32 = 0x00FF_FFFF; - // Try to read card status (ACMD13) + let card = self.card.as_ref().unwrap(); while timeout > 0 { - match self.read_sd_status().await { - Ok(_) => return Ok(()), - Err(Error::Timeout) => (), // Try again - Err(e) => return Err(e), + let status = self.read_status(card)?; + + if status.ready_for_data() { + return Ok(()); } timeout -= 1; } From 5325f1d911753e76a6b56d7747b816d24a7eb172 Mon Sep 17 00:00:00 2001 From: Anton Lazarev Date: Tue, 25 Mar 2025 06:29:16 -0700 Subject: [PATCH 0897/1217] scaffold eMMC support --- embassy-stm32/src/sdmmc/mod.rs | 710 ++++++++++++++++++--------------- 1 file changed, 395 insertions(+), 315 deletions(-) diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs index a28fd51e8..6dbb524b7 100644 --- a/embassy-stm32/src/sdmmc/mod.rs +++ b/embassy-stm32/src/sdmmc/mod.rs @@ -10,11 +10,10 @@ use core::task::Poll; use embassy_hal_internal::drop::OnDrop; use embassy_hal_internal::{Peri, PeripheralType}; use embassy_sync::waitqueue::AtomicWaker; -use sdio_host::{ - common_cmd::{self, Resp, ResponseLen}, - sd::{BusWidth, CardCapacity, CardStatus, CurrentState, SDStatus, CIC, CID, CSD, OCR, RCA, SCR, SD}, - sd_cmd, Cmd, -}; +use sdio_host::common_cmd::{self, Resp, ResponseLen}; +use sdio_host::emmc::{ExtCSD, EMMC}; +use sdio_host::sd::{BusWidth, CardCapacity, CardStatus, CurrentState, SDStatus, CIC, CID, CSD, OCR, RCA, SCR, SD}; +use sdio_host::{sd_cmd, Cmd}; #[cfg(sdmmc_v1)] use crate::dma::ChannelAndRequest; @@ -174,12 +173,21 @@ pub struct Card { pub status: SDStatus, } -impl Card { - /// Size in bytes - pub fn size(&self) -> u64 { - // SDHC / SDXC / SDUC - u64::from(self.csd.block_count()) * 512 - } +#[derive(Clone, Copy, Debug, Default)] +/// eMMC storage +pub struct Emmc { + /// The capacity of this card + pub capacity: CardCapacity, + /// Operation Conditions Register + pub ocr: OCR, + /// Relative Card Address + pub rca: u16, + /// Card ID + pub cid: CID, + /// Card Specific Data + pub csd: CSD, + /// Extended Card Specific Data + pub ext_csd: ExtCSD, } #[repr(u8)] @@ -290,6 +298,61 @@ impl Default for Config { } } +/// Peripheral that can be operated over SDMMC +#[derive(Clone, Copy, Debug)] +pub enum SdmmcPeripheral { + /// SD Card + SdCard(Card), + /// eMMC memory + Emmc(Emmc), +} + +impl SdmmcPeripheral { + /// Get this peripheral's address on the SDMMC bus + fn get_address(&self) -> u16 { + match self { + Self::SdCard(c) => c.rca, + Self::Emmc(e) => e.rca, + } + } + /// Is this a standard or high capacity peripheral? + fn get_capacity(&self) -> CardCapacity { + match self { + Self::SdCard(c) => c.card_type, + Self::Emmc(e) => e.capacity, + } + } + /// Size in bytes + fn size(&self) -> u64 { + match self { + // SDHC / SDXC / SDUC + Self::SdCard(c) => u64::from(c.csd.block_count()) * 512, + // capacity > 2GB + Self::Emmc(e) => u64::from(e.ext_csd.sector_count()) * 512, + } + } + + /// Get a mutable reference to the SD Card. + /// + /// Panics if there is another peripheral instead. + fn get_sd_card(&mut self) -> &mut Card { + match *self { + Self::SdCard(ref mut c) => c, + _ => unreachable!("SD only"), + } + } + + /// Get a mutable reference to the eMMC. + /// + /// Panics if there is another peripheral instead. + fn get_emmc(&mut self) -> &mut Emmc { + match *self { + Self::Emmc(ref mut e) => e, + _ => unreachable!("eMMC only"), + } + } +} + /// Sdmmc device pub struct Sdmmc<'d, T: Instance> { _peri: Peri<'d, T>, @@ -309,7 +372,7 @@ pub struct Sdmmc<'d, T: Instance> { /// Current signalling scheme to card signalling: Signalling, /// Card - card: Option, + card: Option, /// An optional buffer to be used for commands /// This should be used if there are special memory location requirements for dma @@ -662,101 +725,13 @@ impl<'d, T: Instance> Sdmmc<'d, T> { Ok(()) } - /// Switch mode using CMD6. - /// - /// Attempt to set a new signalling mode. The selected - /// signalling mode is returned. Expects the current clock - /// frequency to be > 12.5MHz. - async fn switch_signalling_mode(&mut self, signalling: Signalling) -> Result { - // NB PLSS v7_10 4.3.10.4: "the use of SET_BLK_LEN command is not - // necessary" - - let set_function = 0x8000_0000 - | match signalling { - // See PLSS v7_10 Table 4-11 - Signalling::DDR50 => 0xFF_FF04, - Signalling::SDR104 => 0xFF_1F03, - Signalling::SDR50 => 0xFF_1F02, - Signalling::SDR25 => 0xFF_FF01, - Signalling::SDR12 => 0xFF_FF00, - }; - - let status = match self.cmd_block.as_deref_mut() { - Some(x) => x, - None => &mut CmdBlock::new(), - }; - - // Arm `OnDrop` after the buffer, so it will be dropped first - let regs = T::regs(); - let on_drop = OnDrop::new(|| Self::on_drop()); - - let transfer = Self::prepare_datapath_read( - &self.config, - #[cfg(sdmmc_v1)] - &mut self.dma, - status.as_mut(), - 64, - 6, - ); - InterruptHandler::::data_interrupts(true); - Self::cmd(sd_cmd::cmd6(set_function), true)?; // CMD6 - - let res = poll_fn(|cx| { - T::state().register(cx.waker()); - let status = regs.star().read(); - - if status.dcrcfail() { - return Poll::Ready(Err(Error::Crc)); - } - if status.dtimeout() { - return Poll::Ready(Err(Error::Timeout)); - } - #[cfg(sdmmc_v1)] - if status.stbiterr() { - return Poll::Ready(Err(Error::StBitErr)); - } - if status.dataend() { - return Poll::Ready(Ok(())); - } - Poll::Pending - }) - .await; - Self::clear_interrupt_flags(); - - // Host is allowed to use the new functions at least 8 - // clocks after the end of the switch command - // transaction. We know the current clock period is < 80ns, - // so a total delay of 640ns is required here - for _ in 0..300 { - cortex_m::asm::nop(); - } - - match res { - Ok(_) => { - on_drop.defuse(); - Self::stop_datapath(); - drop(transfer); - - // Function Selection of Function Group 1 - let selection = (u32::from_be(status[4]) >> 24) & 0xF; - - match selection { - 0 => Ok(Signalling::SDR12), - 1 => Ok(Signalling::SDR25), - 2 => Ok(Signalling::SDR50), - 3 => Ok(Signalling::SDR104), - 4 => Ok(Signalling::DDR50), - _ => Err(Error::UnsupportedCardType), - } - } - Err(e) => Err(e), - } - } - /// Query the card status (CMD13, returns R1) - fn read_status(&self, card: &Card) -> Result, Error> { + fn read_status(&self, card: &SdmmcPeripheral) -> Result, Error> + where + CardStatus: From, + { let regs = T::regs(); - let rca = card.rca; + let rca = card.get_address(); Self::cmd(common_cmd::card_status(rca, false), false)?; // CMD13 @@ -764,78 +739,13 @@ impl<'d, T: Instance> Sdmmc<'d, T> { Ok(r1.into()) } - /// Reads the SD Status (ACMD13) - async fn read_sd_status(&mut self) -> Result<(), Error> { - let card = self.card.as_mut().ok_or(Error::NoCard)?; - let rca = card.rca; - - let cmd_block = match self.cmd_block.as_deref_mut() { - Some(x) => x, - None => &mut CmdBlock::new(), - }; - - Self::cmd(common_cmd::set_block_length(64), false)?; // CMD16 - Self::cmd(common_cmd::app_cmd(rca), false)?; // APP - - let status = cmd_block; - - // Arm `OnDrop` after the buffer, so it will be dropped first - let regs = T::regs(); - let on_drop = OnDrop::new(|| Self::on_drop()); - - let transfer = Self::prepare_datapath_read( - &self.config, - #[cfg(sdmmc_v1)] - &mut self.dma, - status.as_mut(), - 64, - 6, - ); - InterruptHandler::::data_interrupts(true); - Self::cmd(sd_cmd::sd_status(), true)?; - - let res = poll_fn(|cx| { - T::state().register(cx.waker()); - let status = regs.star().read(); - - if status.dcrcfail() { - return Poll::Ready(Err(Error::Crc)); - } - if status.dtimeout() { - return Poll::Ready(Err(Error::Timeout)); - } - #[cfg(sdmmc_v1)] - if status.stbiterr() { - return Poll::Ready(Err(Error::StBitErr)); - } - if status.dataend() { - return Poll::Ready(Ok(())); - } - Poll::Pending - }) - .await; - Self::clear_interrupt_flags(); - - if res.is_ok() { - on_drop.defuse(); - Self::stop_datapath(); - drop(transfer); - - for byte in status.iter_mut() { - *byte = u32::from_be(*byte); - } - self.card.as_mut().unwrap().status = status.0.into(); - } - res - } - /// Select one card and place it into the _Tranfer State_ /// /// If `None` is specifed for `card`, all cards are put back into /// _Stand-by State_ - fn select_card(&self, card: Option<&Card>) -> Result<(), Error> { + fn select_card(&self, rca: Option) -> Result<(), Error> { // Determine Relative Card Address (RCA) of given card - let rca = card.map(|c| c.rca).unwrap_or(0); + let rca = rca.unwrap_or(0); let r = Self::cmd(common_cmd::select_card(rca), false); match (r, rca) { @@ -878,67 +788,6 @@ impl<'d, T: Instance> Sdmmc<'d, T> { }); } - async fn get_scr(&mut self, card: &mut Card) -> Result<(), Error> { - // Read the 64-bit SCR register - Self::cmd(common_cmd::set_block_length(8), false)?; // CMD16 - Self::cmd(common_cmd::app_cmd(card.rca), false)?; - - let cmd_block = match self.cmd_block.as_deref_mut() { - Some(x) => x, - None => &mut CmdBlock::new(), - }; - let scr = &mut cmd_block.0[..2]; - - // Arm `OnDrop` after the buffer, so it will be dropped first - let regs = T::regs(); - let on_drop = OnDrop::new(|| Self::on_drop()); - - let transfer = Self::prepare_datapath_read( - &self.config, - #[cfg(sdmmc_v1)] - &mut self.dma, - scr, - 8, - 3, - ); - InterruptHandler::::data_interrupts(true); - Self::cmd(sd_cmd::send_scr(), true)?; - - let res = poll_fn(|cx| { - T::state().register(cx.waker()); - let status = regs.star().read(); - - if status.dcrcfail() { - return Poll::Ready(Err(Error::Crc)); - } - if status.dtimeout() { - return Poll::Ready(Err(Error::Timeout)); - } - #[cfg(sdmmc_v1)] - if status.stbiterr() { - return Poll::Ready(Err(Error::StBitErr)); - } - if status.dataend() { - return Poll::Ready(Ok(())); - } - Poll::Pending - }) - .await; - Self::clear_interrupt_flags(); - - if res.is_ok() { - on_drop.defuse(); - Self::stop_datapath(); - drop(transfer); - - unsafe { - let scr_bytes = &*(&scr as *const _ as *const [u8; 8]); - card.scr = SCR(u64::from_be_bytes(*scr_bytes)); - } - } - res - } - /// Send command to card #[allow(unused_variables)] fn cmd(cmd: Cmd, data: bool) -> Result<(), Error> { @@ -1024,6 +873,170 @@ impl<'d, T: Instance> Sdmmc<'d, T> { Self::stop_datapath(); } + /// Read a data block. + #[inline] + pub async fn read_block(&mut self, block_idx: u32, buffer: &mut DataBlock) -> Result<(), Error> { + let card_capacity = self.card()?.get_capacity(); + + // NOTE(unsafe) DataBlock uses align 4 + let buffer = unsafe { &mut *((&mut buffer.0) as *mut [u8; 512] as *mut [u32; 128]) }; + + // Always read 1 block of 512 bytes + // SDSC cards are byte addressed hence the blockaddress is in multiples of 512 bytes + let address = match card_capacity { + CardCapacity::StandardCapacity => block_idx * 512, + _ => block_idx, + }; + Self::cmd(common_cmd::set_block_length(512), false)?; // CMD16 + + let regs = T::regs(); + let on_drop = OnDrop::new(|| Self::on_drop()); + + let transfer = Self::prepare_datapath_read( + &self.config, + #[cfg(sdmmc_v1)] + &mut self.dma, + buffer, + 512, + 9, + ); + InterruptHandler::::data_interrupts(true); + Self::cmd(common_cmd::read_single_block(address), true)?; + + let res = poll_fn(|cx| { + T::state().register(cx.waker()); + let status = regs.star().read(); + + if status.dcrcfail() { + return Poll::Ready(Err(Error::Crc)); + } + if status.dtimeout() { + return Poll::Ready(Err(Error::Timeout)); + } + #[cfg(sdmmc_v1)] + if status.stbiterr() { + return Poll::Ready(Err(Error::StBitErr)); + } + if status.dataend() { + return Poll::Ready(Ok(())); + } + Poll::Pending + }) + .await; + Self::clear_interrupt_flags(); + + if res.is_ok() { + on_drop.defuse(); + Self::stop_datapath(); + drop(transfer); + } + res + } + + /// Write a data block. + pub async fn write_block(&mut self, block_idx: u32, buffer: &DataBlock) -> Result<(), Error> { + let card = self.card.as_mut().ok_or(Error::NoCard)?; + + // NOTE(unsafe) DataBlock uses align 4 + let buffer = unsafe { &*((&buffer.0) as *const [u8; 512] as *const [u32; 128]) }; + + // Always read 1 block of 512 bytes + // SDSC cards are byte addressed hence the blockaddress is in multiples of 512 bytes + let address = match card.get_capacity() { + CardCapacity::StandardCapacity => block_idx * 512, + _ => block_idx, + }; + Self::cmd(common_cmd::set_block_length(512), false)?; // CMD16 + + let regs = T::regs(); + let on_drop = OnDrop::new(|| Self::on_drop()); + + // sdmmc_v1 uses different cmd/dma order than v2, but only for writes + #[cfg(sdmmc_v1)] + Self::cmd(common_cmd::write_single_block(address), true)?; + + let transfer = self.prepare_datapath_write(buffer, 512, 9); + InterruptHandler::::data_interrupts(true); + + #[cfg(sdmmc_v2)] + Self::cmd(common_cmd::write_single_block(address), true)?; + + let res = poll_fn(|cx| { + T::state().register(cx.waker()); + let status = regs.star().read(); + + if status.dcrcfail() { + return Poll::Ready(Err(Error::Crc)); + } + if status.dtimeout() { + return Poll::Ready(Err(Error::Timeout)); + } + #[cfg(sdmmc_v1)] + if status.stbiterr() { + return Poll::Ready(Err(Error::StBitErr)); + } + if status.dataend() { + return Poll::Ready(Ok(())); + } + Poll::Pending + }) + .await; + Self::clear_interrupt_flags(); + + match res { + Ok(_) => { + on_drop.defuse(); + Self::stop_datapath(); + drop(transfer); + + // TODO: Make this configurable + let mut timeout: u32 = 0x00FF_FFFF; + + let card = self.card.as_ref().unwrap(); + while timeout > 0 { + let ready_for_data = match card { + SdmmcPeripheral::Emmc(_) => self.read_status::(card)?.ready_for_data(), + SdmmcPeripheral::SdCard(_) => self.read_status::(card)?.ready_for_data(), + }; + + if ready_for_data { + return Ok(()); + } + timeout -= 1; + } + Err(Error::SoftwareTimeout) + } + Err(e) => Err(e), + } + } + + /// Get a reference to the initialized card + /// + /// # Errors + /// + /// Returns Error::NoCard if [`init_card`](#method.init_card) + /// has not previously succeeded + #[inline] + pub fn card(&self) -> Result<&SdmmcPeripheral, Error> { + self.card.as_ref().ok_or(Error::NoCard) + } + + /// Get the current SDMMC bus clock + pub fn clock(&self) -> Hertz { + self.clock + } + + /// Set a specific cmd buffer rather than using the default stack allocated one. + /// This is required if stack RAM cannot be used with DMA and usually manifests + /// itself as an indefinite wait on a dma transfer because the dma peripheral + /// cannot access the memory. + pub fn set_cmd_block(&mut self, cmd_block: &'d mut CmdBlock) { + self.cmd_block = Some(cmd_block) + } +} + +/// SD only +impl<'d, T: Instance> Sdmmc<'d, T> { /// Initializes card (if present) and sets the bus at the specified frequency. pub async fn init_card(&mut self, freq: Hertz) -> Result<(), Error> { let regs = T::regs(); @@ -1114,7 +1127,7 @@ impl<'d, T: Instance> Sdmmc<'d, T> { let csd = (csd0 << 96) | (csd1 << 64) | (csd2 << 32) | (csd3); card.csd = csd.into(); - self.select_card(Some(&card))?; + self.select_card(Some(card.rca))?; self.get_scr(&mut card).await?; @@ -1148,7 +1161,7 @@ impl<'d, T: Instance> Sdmmc<'d, T> { self.clkcr_set_clkdiv(25_000_000, width)?; } - self.card = Some(card); + self.card = Some(SdmmcPeripheral::SdCard(card)); // Read status self.read_sd_status().await?; @@ -1161,7 +1174,7 @@ impl<'d, T: Instance> Sdmmc<'d, T> { // Set final clock frequency self.clkcr_set_clkdiv(freq.0, width)?; - if self.read_status(&card)?.state() != CurrentState::Transfer { + if self.read_status::(self.card.as_ref().unwrap())?.state() != CurrentState::Transfer { return Err(Error::SignalingSwitchFailed); } } @@ -1173,22 +1186,34 @@ impl<'d, T: Instance> Sdmmc<'d, T> { Ok(()) } - /// Read a data block. - #[inline] - pub async fn read_block(&mut self, block_idx: u32, buffer: &mut DataBlock) -> Result<(), Error> { - let card_capacity = self.card()?.card_type; + /// Switch mode using CMD6. + /// + /// Attempt to set a new signalling mode. The selected + /// signalling mode is returned. Expects the current clock + /// frequency to be > 12.5MHz. + /// + /// SD only. + async fn switch_signalling_mode(&mut self, signalling: Signalling) -> Result { + let _ = self.card.as_mut().ok_or(Error::NoCard)?.get_sd_card(); + // NB PLSS v7_10 4.3.10.4: "the use of SET_BLK_LEN command is not + // necessary" - // NOTE(unsafe) DataBlock uses align 4 - let buffer = unsafe { &mut *((&mut buffer.0) as *mut [u8; 512] as *mut [u32; 128]) }; + let set_function = 0x8000_0000 + | match signalling { + // See PLSS v7_10 Table 4-11 + Signalling::DDR50 => 0xFF_FF04, + Signalling::SDR104 => 0xFF_1F03, + Signalling::SDR50 => 0xFF_1F02, + Signalling::SDR25 => 0xFF_FF01, + Signalling::SDR12 => 0xFF_FF00, + }; - // Always read 1 block of 512 bytes - // SDSC cards are byte addressed hence the blockaddress is in multiples of 512 bytes - let address = match card_capacity { - CardCapacity::StandardCapacity => block_idx * 512, - _ => block_idx, + let status = match self.cmd_block.as_deref_mut() { + Some(x) => x, + None => &mut CmdBlock::new(), }; - Self::cmd(common_cmd::set_block_length(512), false)?; // CMD16 + // Arm `OnDrop` after the buffer, so it will be dropped first let regs = T::regs(); let on_drop = OnDrop::new(|| Self::on_drop()); @@ -1196,12 +1221,93 @@ impl<'d, T: Instance> Sdmmc<'d, T> { &self.config, #[cfg(sdmmc_v1)] &mut self.dma, - buffer, - 512, - 9, + status.as_mut(), + 64, + 6, ); InterruptHandler::::data_interrupts(true); - Self::cmd(common_cmd::read_single_block(address), true)?; + Self::cmd(sd_cmd::cmd6(set_function), true)?; // CMD6 + + let res = poll_fn(|cx| { + T::state().register(cx.waker()); + let status = regs.star().read(); + + if status.dcrcfail() { + return Poll::Ready(Err(Error::Crc)); + } + if status.dtimeout() { + return Poll::Ready(Err(Error::Timeout)); + } + #[cfg(sdmmc_v1)] + if status.stbiterr() { + return Poll::Ready(Err(Error::StBitErr)); + } + if status.dataend() { + return Poll::Ready(Ok(())); + } + Poll::Pending + }) + .await; + Self::clear_interrupt_flags(); + + // Host is allowed to use the new functions at least 8 + // clocks after the end of the switch command + // transaction. We know the current clock period is < 80ns, + // so a total delay of 640ns is required here + for _ in 0..300 { + cortex_m::asm::nop(); + } + + match res { + Ok(_) => { + on_drop.defuse(); + Self::stop_datapath(); + drop(transfer); + + // Function Selection of Function Group 1 + let selection = (u32::from_be(status[4]) >> 24) & 0xF; + + match selection { + 0 => Ok(Signalling::SDR12), + 1 => Ok(Signalling::SDR25), + 2 => Ok(Signalling::SDR50), + 3 => Ok(Signalling::SDR104), + 4 => Ok(Signalling::DDR50), + _ => Err(Error::UnsupportedCardType), + } + } + Err(e) => Err(e), + } + } + + /// Reads the SCR register. + /// + /// SD only. + async fn get_scr(&mut self, card: &mut Card) -> Result<(), Error> { + // Read the 64-bit SCR register + Self::cmd(common_cmd::set_block_length(8), false)?; // CMD16 + Self::cmd(common_cmd::app_cmd(card.rca), false)?; + + let cmd_block = match self.cmd_block.as_deref_mut() { + Some(x) => x, + None => &mut CmdBlock::new(), + }; + let scr = &mut cmd_block.0[..2]; + + // Arm `OnDrop` after the buffer, so it will be dropped first + let regs = T::regs(); + let on_drop = OnDrop::new(|| Self::on_drop()); + + let transfer = Self::prepare_datapath_read( + &self.config, + #[cfg(sdmmc_v1)] + &mut self.dma, + scr, + 8, + 3, + ); + InterruptHandler::::data_interrupts(true); + Self::cmd(sd_cmd::send_scr(), true)?; let res = poll_fn(|cx| { T::state().register(cx.waker()); @@ -1229,37 +1335,46 @@ impl<'d, T: Instance> Sdmmc<'d, T> { on_drop.defuse(); Self::stop_datapath(); drop(transfer); + + unsafe { + let scr_bytes = &*(&scr as *const _ as *const [u8; 8]); + card.scr = SCR(u64::from_be_bytes(*scr_bytes)); + } } res } - /// Write a data block. - pub async fn write_block(&mut self, block_idx: u32, buffer: &DataBlock) -> Result<(), Error> { - let card = self.card.as_mut().ok_or(Error::NoCard)?; + /// Reads the SD Status (ACMD13) + /// + /// SD only. + async fn read_sd_status(&mut self) -> Result<(), Error> { + let card = self.card.as_mut().ok_or(Error::NoCard)?.get_sd_card(); + let rca = card.rca; - // NOTE(unsafe) DataBlock uses align 4 - let buffer = unsafe { &*((&buffer.0) as *const [u8; 512] as *const [u32; 128]) }; - - // Always read 1 block of 512 bytes - // SDSC cards are byte addressed hence the blockaddress is in multiples of 512 bytes - let address = match card.card_type { - CardCapacity::StandardCapacity => block_idx * 512, - _ => block_idx, + let cmd_block = match self.cmd_block.as_deref_mut() { + Some(x) => x, + None => &mut CmdBlock::new(), }; - Self::cmd(common_cmd::set_block_length(512), false)?; // CMD16 + Self::cmd(common_cmd::set_block_length(64), false)?; // CMD16 + Self::cmd(common_cmd::app_cmd(rca), false)?; // APP + + let status = cmd_block; + + // Arm `OnDrop` after the buffer, so it will be dropped first let regs = T::regs(); let on_drop = OnDrop::new(|| Self::on_drop()); - // sdmmc_v1 uses different cmd/dma order than v2, but only for writes - #[cfg(sdmmc_v1)] - Self::cmd(common_cmd::write_single_block(address), true)?; - - let transfer = self.prepare_datapath_write(buffer, 512, 9); + let transfer = Self::prepare_datapath_read( + &self.config, + #[cfg(sdmmc_v1)] + &mut self.dma, + status.as_mut(), + 64, + 6, + ); InterruptHandler::::data_interrupts(true); - - #[cfg(sdmmc_v2)] - Self::cmd(common_cmd::write_single_block(address), true)?; + Self::cmd(sd_cmd::sd_status(), true)?; let res = poll_fn(|cx| { T::state().register(cx.waker()); @@ -1283,52 +1398,17 @@ impl<'d, T: Instance> Sdmmc<'d, T> { .await; Self::clear_interrupt_flags(); - match res { - Ok(_) => { - on_drop.defuse(); - Self::stop_datapath(); - drop(transfer); + if res.is_ok() { + on_drop.defuse(); + Self::stop_datapath(); + drop(transfer); - // TODO: Make this configurable - let mut timeout: u32 = 0x00FF_FFFF; - - let card = self.card.as_ref().unwrap(); - while timeout > 0 { - let status = self.read_status(card)?; - - if status.ready_for_data() { - return Ok(()); - } - timeout -= 1; - } - Err(Error::SoftwareTimeout) + for byte in status.iter_mut() { + *byte = u32::from_be(*byte); } - Err(e) => Err(e), + card.status = status.0.into(); } - } - - /// Get a reference to the initialized card - /// - /// # Errors - /// - /// Returns Error::NoCard if [`init_card`](#method.init_card) - /// has not previously succeeded - #[inline] - pub fn card(&self) -> Result<&Card, Error> { - self.card.as_ref().ok_or(Error::NoCard) - } - - /// Get the current SDMMC bus clock - pub fn clock(&self) -> Hertz { - self.clock - } - - /// Set a specific cmd buffer rather than using the default stack allocated one. - /// This is required if stack RAM cannot be used with DMA and usually manifests - /// itself as an indefinite wait on a dma transfer because the dma peripheral - /// cannot access the memory. - pub fn set_cmd_block(&mut self, cmd_block: &'d mut CmdBlock) { - self.cmd_block = Some(cmd_block) + res } } From 57731a78963e1afa3dfecc70321ae407e2095a16 Mon Sep 17 00:00:00 2001 From: Anton Lazarev Date: Tue, 25 Mar 2025 08:25:08 -0700 Subject: [PATCH 0898/1217] support eMMC --- embassy-stm32/src/sdmmc/mod.rs | 185 ++++++++++++++++++++++++++++++++- 1 file changed, 184 insertions(+), 1 deletion(-) diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs index 6dbb524b7..f92c0260b 100644 --- a/embassy-stm32/src/sdmmc/mod.rs +++ b/embassy-stm32/src/sdmmc/mod.rs @@ -13,7 +13,7 @@ use embassy_sync::waitqueue::AtomicWaker; use sdio_host::common_cmd::{self, Resp, ResponseLen}; use sdio_host::emmc::{ExtCSD, EMMC}; use sdio_host::sd::{BusWidth, CardCapacity, CardStatus, CurrentState, SDStatus, CIC, CID, CSD, OCR, RCA, SCR, SD}; -use sdio_host::{sd_cmd, Cmd}; +use sdio_host::{emmc_cmd, sd_cmd, Cmd}; #[cfg(sdmmc_v1)] use crate::dma::ChannelAndRequest; @@ -1412,6 +1412,189 @@ impl<'d, T: Instance> Sdmmc<'d, T> { } } +/// eMMC only. +impl<'d, T: Instance> Sdmmc<'d, T> { + /// Initializes eMMC and sets the bus at the specified frequency. + pub async fn init_emmc(&mut self, freq: Hertz) -> Result<(), Error> { + let regs = T::regs(); + let ker_ck = T::frequency(); + + let bus_width = match self.d3.is_some() { + true => BusWidth::Four, + false => BusWidth::One, + }; + + // While the SD/SDIO card or eMMC is in identification mode, + // the SDMMC_CK frequency must be no more than 400 kHz. + let (_bypass, clkdiv, init_clock) = unwrap!(clk_div(ker_ck, SD_INIT_FREQ.0)); + self.clock = init_clock; + + // CPSMACT and DPSMACT must be 0 to set WIDBUS + Self::wait_idle(); + + regs.clkcr().modify(|w| { + w.set_widbus(0); + w.set_clkdiv(clkdiv); + #[cfg(sdmmc_v1)] + w.set_bypass(_bypass); + }); + + regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::On as u8)); + Self::cmd(common_cmd::idle(), false)?; + + let mut card = Emmc::default(); + + let ocr = loop { + let high_voltage = 0b0 << 7; + let access_mode = 0b10 << 29; + let op_cond = high_voltage | access_mode | 0b1_1111_1111 << 15; + // Initialize card + match Self::cmd(emmc_cmd::send_op_cond(op_cond), false) { + Ok(_) => (), + Err(Error::Crc) => (), + Err(err) => return Err(err), + } + let ocr: OCR = regs.respr(0).read().cardstatus().into(); + if !ocr.is_busy() { + // Power up done + break ocr; + } + }; + + card.capacity = if ocr.access_mode() == 0b10 { + // Card is SDHC or SDXC or SDUC + CardCapacity::HighCapacity + } else { + CardCapacity::StandardCapacity + }; + card.ocr = ocr; + + Self::cmd(common_cmd::all_send_cid(), false)?; // CMD2 + let cid0 = regs.respr(0).read().cardstatus() as u128; + let cid1 = regs.respr(1).read().cardstatus() as u128; + let cid2 = regs.respr(2).read().cardstatus() as u128; + let cid3 = regs.respr(3).read().cardstatus() as u128; + let cid = (cid0 << 96) | (cid1 << 64) | (cid2 << 32) | (cid3); + card.cid = cid.into(); + + card.rca = 1u16.into(); + Self::cmd(emmc_cmd::assign_relative_address(card.rca), false)?; + + Self::cmd(common_cmd::send_csd(card.rca), false)?; + let csd0 = regs.respr(0).read().cardstatus() as u128; + let csd1 = regs.respr(1).read().cardstatus() as u128; + let csd2 = regs.respr(2).read().cardstatus() as u128; + let csd3 = regs.respr(3).read().cardstatus() as u128; + let csd = (csd0 << 96) | (csd1 << 64) | (csd2 << 32) | (csd3); + card.csd = csd.into(); + + self.select_card(Some(card.rca))?; + + // Set bus width + let (width, widbus) = match bus_width { + BusWidth::Eight => (BusWidth::Eight, 2), + BusWidth::Four => (BusWidth::Four, 1), + _ => (BusWidth::One, 0), + }; + // Write bus width to ExtCSD byte 183 + Self::cmd( + emmc_cmd::modify_ext_csd(emmc_cmd::AccessMode::WriteByte, 183, widbus), + false, + )?; + + self.card = Some(SdmmcPeripheral::Emmc(card)); + + // Wait for ready after R1b response + loop { + let status = self.read_status::(self.card.as_ref().unwrap())?; + + if status.ready_for_data() { + break; + } + } + + // CPSMACT and DPSMACT must be 0 to set WIDBUS + Self::wait_idle(); + + regs.clkcr().modify(|w| w.set_widbus(widbus)); + + // Set Clock + if freq.0 <= 25_000_000 { + // Final clock frequency + self.clkcr_set_clkdiv(freq.0, width)?; + } else { + // Switch to max clock for SDR12 + self.clkcr_set_clkdiv(25_000_000, width)?; + } + + // Read status + self.read_ext_csd().await?; + + Ok(()) + } + + /// Gets the EXT_CSD register. + /// + /// eMMC only. + async fn read_ext_csd(&mut self) -> Result<(), Error> { + let card = self.card.as_mut().ok_or(Error::NoCard)?.get_emmc(); + + // Note: cmd_block can't be used because ExtCSD is too long to fit. + let mut data_block = DataBlock([0u8; 512]); + + // NOTE(unsafe) DataBlock uses align 4 + let buffer = unsafe { &mut *((&mut data_block.0) as *mut [u8; 512] as *mut [u32; 128]) }; + + Self::cmd(common_cmd::set_block_length(512), false).unwrap(); // CMD16 + + // Arm `OnDrop` after the buffer, so it will be dropped first + let regs = T::regs(); + let on_drop = OnDrop::new(|| Self::on_drop()); + + let transfer = Self::prepare_datapath_read( + &self.config, + #[cfg(sdmmc_v1)] + &mut self.dma, + buffer, + 512, + 9, + ); + InterruptHandler::::data_interrupts(true); + Self::cmd(emmc_cmd::send_ext_csd(), true)?; + + let res = poll_fn(|cx| { + T::state().register(cx.waker()); + let status = regs.star().read(); + + if status.dcrcfail() { + return Poll::Ready(Err(Error::Crc)); + } + if status.dtimeout() { + return Poll::Ready(Err(Error::Timeout)); + } + #[cfg(sdmmc_v1)] + if status.stbiterr() { + return Poll::Ready(Err(Error::StBitErr)); + } + if status.dataend() { + return Poll::Ready(Ok(())); + } + Poll::Pending + }) + .await; + Self::clear_interrupt_flags(); + + if res.is_ok() { + on_drop.defuse(); + Self::stop_datapath(); + drop(transfer); + + card.ext_csd = unsafe { core::mem::transmute::<_, [u32; 128]>(data_block.0) }.into(); + } + res + } +} + impl<'d, T: Instance> Drop for Sdmmc<'d, T> { fn drop(&mut self) { T::Interrupt::disable(); From b92eb948b5de521205e3a8bb81548662c7fc5c1d Mon Sep 17 00:00:00 2001 From: Anton Lazarev Date: Wed, 26 Mar 2025 23:23:22 -0700 Subject: [PATCH 0899/1217] fix d6->d7 typo from build.rs --- embassy-stm32/build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 798133162..dd69a472a 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -1049,7 +1049,7 @@ fn main() { (("sdmmc", "D4"), quote!(crate::sdmmc::D4Pin)), (("sdmmc", "D5"), quote!(crate::sdmmc::D5Pin)), (("sdmmc", "D6"), quote!(crate::sdmmc::D6Pin)), - (("sdmmc", "D6"), quote!(crate::sdmmc::D7Pin)), + (("sdmmc", "D7"), quote!(crate::sdmmc::D7Pin)), (("sdmmc", "D8"), quote!(crate::sdmmc::D8Pin)), (("quadspi", "BK1_IO0"), quote!(crate::qspi::BK1D0Pin)), (("quadspi", "BK1_IO1"), quote!(crate::qspi::BK1D1Pin)), From 0a231505d8225f3f36f39b0be1ded4304fb7ccca Mon Sep 17 00:00:00 2001 From: Anton Lazarev Date: Wed, 26 Mar 2025 23:26:11 -0700 Subject: [PATCH 0900/1217] support 8 lane data bus --- embassy-stm32/src/sdmmc/mod.rs | 162 ++++++++++++++++++++++++++++++++- 1 file changed, 158 insertions(+), 4 deletions(-) diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs index f92c0260b..a0c3573a9 100644 --- a/embassy-stm32/src/sdmmc/mod.rs +++ b/embassy-stm32/src/sdmmc/mod.rs @@ -145,6 +145,8 @@ pub enum Error { Crc, /// No card inserted. NoCard, + /// 8-lane buses are not supported for SD cards. + BusWidth, /// Bad clock supplied to the SDMMC peripheral. BadClock, /// Signaling switch failed. @@ -365,6 +367,10 @@ pub struct Sdmmc<'d, T: Instance> { d1: Option>, d2: Option>, d3: Option>, + d4: Option>, + d5: Option>, + d6: Option>, + d7: Option>, config: Config, /// Current clock to card @@ -413,6 +419,10 @@ impl<'d, T: Instance> Sdmmc<'d, T> { None, None, None, + None, + None, + None, + None, config, ) } @@ -448,6 +458,60 @@ impl<'d, T: Instance> Sdmmc<'d, T> { Some(d1.into()), Some(d2.into()), Some(d3.into()), + None, + None, + None, + None, + config, + ) + } +} + +#[cfg(sdmmc_v1)] +impl<'d, T: Instance> Sdmmc<'d, T> { + /// Create a new SDMMC driver, with 8 data lanes. + pub fn new_8bit( + sdmmc: Peri<'d, T>, + _irq: impl interrupt::typelevel::Binding> + 'd, + dma: Peri<'d, impl SdmmcDma>, + clk: Peri<'d, impl CkPin>, + cmd: Peri<'d, impl CmdPin>, + d0: Peri<'d, impl D0Pin>, + d1: Peri<'d, impl D1Pin>, + d2: Peri<'d, impl D2Pin>, + d3: Peri<'d, impl D3Pin>, + d4: Peri<'d, impl D4Pin>, + d5: Peri<'d, impl D5Pin>, + d6: Peri<'d, impl D6Pin>, + d7: Peri<'d, impl D7Pin>, + config: Config, + ) -> Self { + critical_section::with(|_| { + clk.set_as_af(clk.af_num(), CLK_AF); + cmd.set_as_af(cmd.af_num(), CMD_AF); + d0.set_as_af(d0.af_num(), DATA_AF); + d1.set_as_af(d1.af_num(), DATA_AF); + d2.set_as_af(d2.af_num(), DATA_AF); + d3.set_as_af(d3.af_num(), DATA_AF); + d4.set_as_af(d4.af_num(), DATA_AF); + d5.set_as_af(d5.af_num(), DATA_AF); + d6.set_as_af(d6.af_num(), DATA_AF); + d7.set_as_af(d7.af_num(), DATA_AF); + }); + + Self::new_inner( + sdmmc, + new_dma_nonopt!(dma), + clk.into(), + cmd.into(), + d0.into(), + Some(d1.into()), + Some(d2.into()), + Some(d3.into()), + Some(d4.into()), + Some(d5.into()), + Some(d6.into()), + Some(d7.into()), config, ) } @@ -470,7 +534,20 @@ impl<'d, T: Instance> Sdmmc<'d, T> { d0.set_as_af(d0.af_num(), DATA_AF); }); - Self::new_inner(sdmmc, clk.into(), cmd.into(), d0.into(), None, None, None, config) + Self::new_inner( + sdmmc, + clk.into(), + cmd.into(), + d0.into(), + None, + None, + None, + None, + None, + None, + None, + config, + ) } /// Create a new SDMMC driver, with 4 data lanes. @@ -502,6 +579,58 @@ impl<'d, T: Instance> Sdmmc<'d, T> { Some(d1.into()), Some(d2.into()), Some(d3.into()), + None, + None, + None, + None, + config, + ) + } +} + +#[cfg(sdmmc_v2)] +impl<'d, T: Instance> Sdmmc<'d, T> { + /// Create a new SDMMC driver, with 8 data lanes. + pub fn new_8bit( + sdmmc: Peri<'d, T>, + _irq: impl interrupt::typelevel::Binding> + 'd, + clk: Peri<'d, impl CkPin>, + cmd: Peri<'d, impl CmdPin>, + d0: Peri<'d, impl D0Pin>, + d1: Peri<'d, impl D1Pin>, + d2: Peri<'d, impl D2Pin>, + d3: Peri<'d, impl D3Pin>, + d4: Peri<'d, impl D4Pin>, + d5: Peri<'d, impl D5Pin>, + d6: Peri<'d, impl D6Pin>, + d7: Peri<'d, impl D7Pin>, + config: Config, + ) -> Self { + critical_section::with(|_| { + clk.set_as_af(clk.af_num(), CLK_AF); + cmd.set_as_af(cmd.af_num(), CMD_AF); + d0.set_as_af(d0.af_num(), DATA_AF); + d1.set_as_af(d1.af_num(), DATA_AF); + d2.set_as_af(d2.af_num(), DATA_AF); + d3.set_as_af(d3.af_num(), DATA_AF); + d4.set_as_af(d4.af_num(), DATA_AF); + d5.set_as_af(d5.af_num(), DATA_AF); + d6.set_as_af(d6.af_num(), DATA_AF); + d7.set_as_af(d7.af_num(), DATA_AF); + }); + + Self::new_inner( + sdmmc, + clk.into(), + cmd.into(), + d0.into(), + Some(d1.into()), + Some(d2.into()), + Some(d3.into()), + Some(d4.into()), + Some(d5.into()), + Some(d6.into()), + Some(d7.into()), config, ) } @@ -517,6 +646,10 @@ impl<'d, T: Instance> Sdmmc<'d, T> { d1: Option>, d2: Option>, d3: Option>, + d4: Option>, + d5: Option>, + d6: Option>, + d7: Option>, config: Config, ) -> Self { rcc::enable_and_reset::(); @@ -555,6 +688,10 @@ impl<'d, T: Instance> Sdmmc<'d, T> { d1, d2, d3, + d4, + d5, + d6, + d7, config, clock: SD_INIT_FREQ, @@ -1039,6 +1176,10 @@ impl<'d, T: Instance> Sdmmc<'d, T> { impl<'d, T: Instance> Sdmmc<'d, T> { /// Initializes card (if present) and sets the bus at the specified frequency. pub async fn init_card(&mut self, freq: Hertz) -> Result<(), Error> { + if self.d7.is_some() { + return Err(Error::BusWidth); + } + let regs = T::regs(); let ker_ck = T::frequency(); @@ -1419,9 +1560,10 @@ impl<'d, T: Instance> Sdmmc<'d, T> { let regs = T::regs(); let ker_ck = T::frequency(); - let bus_width = match self.d3.is_some() { - true => BusWidth::Four, - false => BusWidth::One, + let bus_width = match (self.d3.is_some(), self.d7.is_some()) { + (true, true) => BusWidth::Eight, + (true, false) => BusWidth::Four, + _ => BusWidth::One, }; // While the SD/SDIO card or eMMC is in identification mode, @@ -1613,6 +1755,18 @@ impl<'d, T: Instance> Drop for Sdmmc<'d, T> { if let Some(x) = &mut self.d3 { x.set_as_disconnected(); } + if let Some(x) = &mut self.d4 { + x.set_as_disconnected(); + } + if let Some(x) = &mut self.d5 { + x.set_as_disconnected(); + } + if let Some(x) = &mut self.d6 { + x.set_as_disconnected(); + } + if let Some(x) = &mut self.d7 { + x.set_as_disconnected(); + } }); } } From dc31bfd8295c3626794e0b1b38804af2acc59053 Mon Sep 17 00:00:00 2001 From: Anton Lazarev Date: Fri, 28 Mar 2025 15:54:47 -0700 Subject: [PATCH 0901/1217] refactor to reduce code duplication --- embassy-stm32/src/sdmmc/mod.rs | 581 ++++++++++++------------------ examples/stm32f4/src/bin/sdmmc.rs | 2 +- examples/stm32f7/src/bin/sdmmc.rs | 2 +- examples/stm32h7/src/bin/sdmmc.rs | 2 +- tests/stm32/src/bin/sdmmc.rs | 4 +- 5 files changed, 233 insertions(+), 358 deletions(-) diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs index a0c3573a9..63868e5ae 100644 --- a/embassy-stm32/src/sdmmc/mod.rs +++ b/embassy-stm32/src/sdmmc/mod.rs @@ -1010,35 +1010,10 @@ impl<'d, T: Instance> Sdmmc<'d, T> { Self::stop_datapath(); } - /// Read a data block. + /// Wait for a previously started datapath transfer to complete from an interrupt. #[inline] - pub async fn read_block(&mut self, block_idx: u32, buffer: &mut DataBlock) -> Result<(), Error> { - let card_capacity = self.card()?.get_capacity(); - - // NOTE(unsafe) DataBlock uses align 4 - let buffer = unsafe { &mut *((&mut buffer.0) as *mut [u8; 512] as *mut [u32; 128]) }; - - // Always read 1 block of 512 bytes - // SDSC cards are byte addressed hence the blockaddress is in multiples of 512 bytes - let address = match card_capacity { - CardCapacity::StandardCapacity => block_idx * 512, - _ => block_idx, - }; - Self::cmd(common_cmd::set_block_length(512), false)?; // CMD16 - + async fn complete_datapath_transfer() -> Result<(), Error> { let regs = T::regs(); - let on_drop = OnDrop::new(|| Self::on_drop()); - - let transfer = Self::prepare_datapath_read( - &self.config, - #[cfg(sdmmc_v1)] - &mut self.dma, - buffer, - 512, - 9, - ); - InterruptHandler::::data_interrupts(true); - Self::cmd(common_cmd::read_single_block(address), true)?; let res = poll_fn(|cx| { T::state().register(cx.waker()); @@ -1060,8 +1035,43 @@ impl<'d, T: Instance> Sdmmc<'d, T> { Poll::Pending }) .await; + Self::clear_interrupt_flags(); + res + } + + /// Read a data block. + #[inline] + pub async fn read_block(&mut self, block_idx: u32, buffer: &mut DataBlock) -> Result<(), Error> { + let card_capacity = self.card()?.get_capacity(); + + // NOTE(unsafe) DataBlock uses align 4 + let buffer = unsafe { &mut *((&mut buffer.0) as *mut [u8; 512] as *mut [u32; 128]) }; + + // Always read 1 block of 512 bytes + // SDSC cards are byte addressed hence the blockaddress is in multiples of 512 bytes + let address = match card_capacity { + CardCapacity::StandardCapacity => block_idx * 512, + _ => block_idx, + }; + Self::cmd(common_cmd::set_block_length(512), false)?; // CMD16 + + let on_drop = OnDrop::new(|| Self::on_drop()); + + let transfer = Self::prepare_datapath_read( + &self.config, + #[cfg(sdmmc_v1)] + &mut self.dma, + buffer, + 512, + 9, + ); + InterruptHandler::::data_interrupts(true); + Self::cmd(common_cmd::read_single_block(address), true)?; + + let res = Self::complete_datapath_transfer().await; + if res.is_ok() { on_drop.defuse(); Self::stop_datapath(); @@ -1085,7 +1095,6 @@ impl<'d, T: Instance> Sdmmc<'d, T> { }; Self::cmd(common_cmd::set_block_length(512), false)?; // CMD16 - let regs = T::regs(); let on_drop = OnDrop::new(|| Self::on_drop()); // sdmmc_v1 uses different cmd/dma order than v2, but only for writes @@ -1098,27 +1107,7 @@ impl<'d, T: Instance> Sdmmc<'d, T> { #[cfg(sdmmc_v2)] Self::cmd(common_cmd::write_single_block(address), true)?; - let res = poll_fn(|cx| { - T::state().register(cx.waker()); - let status = regs.star().read(); - - if status.dcrcfail() { - return Poll::Ready(Err(Error::Crc)); - } - if status.dtimeout() { - return Poll::Ready(Err(Error::Timeout)); - } - #[cfg(sdmmc_v1)] - if status.stbiterr() { - return Poll::Ready(Err(Error::StBitErr)); - } - if status.dataend() { - return Poll::Ready(Ok(())); - } - Poll::Pending - }) - .await; - Self::clear_interrupt_flags(); + let res = Self::complete_datapath_transfer().await; match res { Ok(_) => { @@ -1151,8 +1140,8 @@ impl<'d, T: Instance> Sdmmc<'d, T> { /// /// # Errors /// - /// Returns Error::NoCard if [`init_card`](#method.init_card) - /// has not previously succeeded + /// Returns Error::NoCard if [`init_sd_card`](#method.init_sd_card) or + /// [`init_emmc`](#method.init_emmc) has not previously succeeded #[inline] pub fn card(&self) -> Result<&SdmmcPeripheral, Error> { self.card.as_ref().ok_or(Error::NoCard) @@ -1170,22 +1159,20 @@ impl<'d, T: Instance> Sdmmc<'d, T> { pub fn set_cmd_block(&mut self, cmd_block: &'d mut CmdBlock) { self.cmd_block = Some(cmd_block) } -} - -/// SD only -impl<'d, T: Instance> Sdmmc<'d, T> { - /// Initializes card (if present) and sets the bus at the specified frequency. - pub async fn init_card(&mut self, freq: Hertz) -> Result<(), Error> { - if self.d7.is_some() { - return Err(Error::BusWidth); - } + async fn init_internal(&mut self, freq: Hertz, mut card: SdmmcPeripheral) -> Result<(), Error> { let regs = T::regs(); let ker_ck = T::frequency(); - let bus_width = match self.d3.is_some() { - true => BusWidth::Four, - false => BusWidth::One, + let bus_width = match (self.d3.is_some(), self.d7.is_some()) { + (true, true) => { + if matches!(card, SdmmcPeripheral::SdCard(_)) { + return Err(Error::BusWidth); + } + BusWidth::Eight + } + (true, false) => BusWidth::Four, + _ => BusWidth::One, }; // While the SD/SDIO card or eMMC is in identification mode, @@ -1206,47 +1193,75 @@ impl<'d, T: Instance> Sdmmc<'d, T> { regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::On as u8)); Self::cmd(common_cmd::idle(), false)?; - // Check if cards supports CMD8 (with pattern) - Self::cmd(sd_cmd::send_if_cond(1, 0xAA), false)?; - let cic = CIC::from(regs.respr(0).read().cardstatus()); + match card { + SdmmcPeripheral::SdCard(ref mut card) => { + // Check if cards supports CMD8 (with pattern) + Self::cmd(sd_cmd::send_if_cond(1, 0xAA), false)?; + let cic = CIC::from(regs.respr(0).read().cardstatus()); - if cic.pattern() != 0xAA { - return Err(Error::UnsupportedCardVersion); - } + if cic.pattern() != 0xAA { + return Err(Error::UnsupportedCardVersion); + } - if cic.voltage_accepted() & 1 == 0 { - return Err(Error::UnsupportedVoltage); - } + if cic.voltage_accepted() & 1 == 0 { + return Err(Error::UnsupportedVoltage); + } - let mut card = Card::default(); + let ocr = loop { + // Signal that next command is a app command + Self::cmd(common_cmd::app_cmd(0), false)?; // CMD55 - let ocr = loop { - // Signal that next command is a app command - Self::cmd(common_cmd::app_cmd(0), false)?; // CMD55 + // 3.2-3.3V + let voltage_window = 1 << 5; + // Initialize card + match Self::cmd(sd_cmd::sd_send_op_cond(true, false, true, voltage_window), false) { + // ACMD41 + Ok(_) => (), + Err(Error::Crc) => (), + Err(err) => return Err(err), + } + let ocr: OCR = regs.respr(0).read().cardstatus().into(); + if !ocr.is_busy() { + // Power up done + break ocr; + } + }; - // 3.2-3.3V - let voltage_window = 1 << 5; - // Initialize card - match Self::cmd(sd_cmd::sd_send_op_cond(true, false, true, voltage_window), false) { - // ACMD41 - Ok(_) => (), - Err(Error::Crc) => (), - Err(err) => return Err(err), + if ocr.high_capacity() { + // Card is SDHC or SDXC or SDUC + card.card_type = CardCapacity::HighCapacity; + } else { + card.card_type = CardCapacity::StandardCapacity; + } + card.ocr = ocr; } - let ocr: OCR = regs.respr(0).read().cardstatus().into(); - if !ocr.is_busy() { - // Power up done - break ocr; - } - }; + SdmmcPeripheral::Emmc(ref mut emmc) => { + let ocr = loop { + let high_voltage = 0b0 << 7; + let access_mode = 0b10 << 29; + let op_cond = high_voltage | access_mode | 0b1_1111_1111 << 15; + // Initialize card + match Self::cmd(emmc_cmd::send_op_cond(op_cond), false) { + Ok(_) => (), + Err(Error::Crc) => (), + Err(err) => return Err(err), + } + let ocr: OCR = regs.respr(0).read().cardstatus().into(); + if !ocr.is_busy() { + // Power up done + break ocr; + } + }; - if ocr.high_capacity() { - // Card is SDHC or SDXC or SDUC - card.card_type = CardCapacity::HighCapacity; - } else { - card.card_type = CardCapacity::StandardCapacity; + emmc.capacity = if ocr.access_mode() == 0b10 { + // Card is SDHC or SDXC or SDUC + CardCapacity::HighCapacity + } else { + CardCapacity::StandardCapacity + }; + emmc.ocr = ocr; + } } - card.ocr = ocr; Self::cmd(common_cmd::all_send_cid(), false)?; // CMD2 let cid0 = regs.respr(0).read().cardstatus() as u128; @@ -1254,79 +1269,139 @@ impl<'d, T: Instance> Sdmmc<'d, T> { let cid2 = regs.respr(2).read().cardstatus() as u128; let cid3 = regs.respr(3).read().cardstatus() as u128; let cid = (cid0 << 96) | (cid1 << 64) | (cid2 << 32) | (cid3); - card.cid = cid.into(); - Self::cmd(sd_cmd::send_relative_address(), false)?; - let rca = RCA::::from(regs.respr(0).read().cardstatus()); - card.rca = rca.address(); + match card { + SdmmcPeripheral::SdCard(ref mut card) => { + card.cid = cid.into(); - Self::cmd(common_cmd::send_csd(card.rca), false)?; + Self::cmd(sd_cmd::send_relative_address(), false)?; + let rca = RCA::::from(regs.respr(0).read().cardstatus()); + card.rca = rca.address(); + } + SdmmcPeripheral::Emmc(ref mut emmc) => { + emmc.cid = cid.into(); + + emmc.rca = 1u16.into(); + Self::cmd(emmc_cmd::assign_relative_address(emmc.rca), false)?; + } + } + + Self::cmd(common_cmd::send_csd(card.get_address()), false)?; let csd0 = regs.respr(0).read().cardstatus() as u128; let csd1 = regs.respr(1).read().cardstatus() as u128; let csd2 = regs.respr(2).read().cardstatus() as u128; let csd3 = regs.respr(3).read().cardstatus() as u128; let csd = (csd0 << 96) | (csd1 << 64) | (csd2 << 32) | (csd3); - card.csd = csd.into(); - self.select_card(Some(card.rca))?; + self.select_card(Some(card.get_address()))?; - self.get_scr(&mut card).await?; + let bus_width = match card { + SdmmcPeripheral::SdCard(ref mut card) => { + card.csd = csd.into(); + + self.get_scr(card).await?; + + if !card.scr.bus_width_four() { + BusWidth::One + } else { + BusWidth::Four + } + } + SdmmcPeripheral::Emmc(ref mut emmc) => { + emmc.csd = csd.into(); + + bus_width + } + }; // Set bus width - let (width, acmd_arg) = match bus_width { - BusWidth::Eight => unimplemented!(), - BusWidth::Four if card.scr.bus_width_four() => (BusWidth::Four, 2), - _ => (BusWidth::One, 0), + let widbus = match bus_width { + BusWidth::Eight => 2, + BusWidth::Four => 1, + BusWidth::One => 0, + _ => unreachable!(), }; - Self::cmd(common_cmd::app_cmd(card.rca), false)?; - Self::cmd(sd_cmd::cmd6(acmd_arg), false)?; - // CPSMACT and DPSMACT must be 0 to set WIDBUS - Self::wait_idle(); + match card { + SdmmcPeripheral::SdCard(ref mut card) => { + let acmd_arg = match bus_width { + BusWidth::Four if card.scr.bus_width_four() => 2, + _ => 0, + }; + Self::cmd(common_cmd::app_cmd(card.rca), false)?; + Self::cmd(sd_cmd::cmd6(acmd_arg), false)?; + } + SdmmcPeripheral::Emmc(_) => { + // Write bus width to ExtCSD byte 183 + Self::cmd( + emmc_cmd::modify_ext_csd(emmc_cmd::AccessMode::WriteByte, 183, widbus), + false, + )?; - regs.clkcr().modify(|w| { - w.set_widbus(match width { - BusWidth::One => 0, - BusWidth::Four => 1, - BusWidth::Eight => 2, - _ => panic!("Invalid Bus Width"), - }) - }); + // Wait for ready after R1b response + loop { + let status = self.read_status::(&card)?; - // Set Clock - if freq.0 <= 25_000_000 { - // Final clock frequency - self.clkcr_set_clkdiv(freq.0, width)?; - } else { - // Switch to max clock for SDR12 - self.clkcr_set_clkdiv(25_000_000, width)?; - } - - self.card = Some(SdmmcPeripheral::SdCard(card)); - - // Read status - self.read_sd_status().await?; - - if freq.0 > 25_000_000 { - // Switch to SDR25 - self.signalling = self.switch_signalling_mode(Signalling::SDR25).await?; - - if self.signalling == Signalling::SDR25 { - // Set final clock frequency - self.clkcr_set_clkdiv(freq.0, width)?; - - if self.read_status::(self.card.as_ref().unwrap())?.state() != CurrentState::Transfer { - return Err(Error::SignalingSwitchFailed); + if status.ready_for_data() { + break; + } } } } - // Read status after signalling change - self.read_sd_status().await?; + // CPSMACT and DPSMACT must be 0 to set WIDBUS + Self::wait_idle(); + + regs.clkcr().modify(|w| w.set_widbus(widbus)); + + // Set Clock + if freq.0 <= 25_000_000 { + // Final clock frequency + self.clkcr_set_clkdiv(freq.0, bus_width)?; + } else { + // Switch to max clock for SDR12 + self.clkcr_set_clkdiv(25_000_000, bus_width)?; + } + + self.card = Some(card); + + match card { + SdmmcPeripheral::SdCard(_) => { + // Read status + self.read_sd_status().await?; + + if freq.0 > 25_000_000 { + // Switch to SDR25 + self.signalling = self.switch_signalling_mode(Signalling::SDR25).await?; + + if self.signalling == Signalling::SDR25 { + // Set final clock frequency + self.clkcr_set_clkdiv(freq.0, bus_width)?; + + if self.read_status::(self.card.as_ref().unwrap())?.state() != CurrentState::Transfer { + return Err(Error::SignalingSwitchFailed); + } + } + } + + // Read status after signalling change + self.read_sd_status().await?; + } + SdmmcPeripheral::Emmc(_) => { + self.read_ext_csd().await?; + } + } Ok(()) } + /// Initializes card (if present) and sets the bus at the specified frequency. + /// + /// SD only. + pub async fn init_sd_card(&mut self, freq: Hertz) -> Result<(), Error> { + self.init_internal(freq, SdmmcPeripheral::SdCard(Card::default())).await + } + /// Switch mode using CMD6. /// /// Attempt to set a new signalling mode. The selected @@ -1355,7 +1430,6 @@ impl<'d, T: Instance> Sdmmc<'d, T> { }; // Arm `OnDrop` after the buffer, so it will be dropped first - let regs = T::regs(); let on_drop = OnDrop::new(|| Self::on_drop()); let transfer = Self::prepare_datapath_read( @@ -1369,27 +1443,7 @@ impl<'d, T: Instance> Sdmmc<'d, T> { InterruptHandler::::data_interrupts(true); Self::cmd(sd_cmd::cmd6(set_function), true)?; // CMD6 - let res = poll_fn(|cx| { - T::state().register(cx.waker()); - let status = regs.star().read(); - - if status.dcrcfail() { - return Poll::Ready(Err(Error::Crc)); - } - if status.dtimeout() { - return Poll::Ready(Err(Error::Timeout)); - } - #[cfg(sdmmc_v1)] - if status.stbiterr() { - return Poll::Ready(Err(Error::StBitErr)); - } - if status.dataend() { - return Poll::Ready(Ok(())); - } - Poll::Pending - }) - .await; - Self::clear_interrupt_flags(); + let res = Self::complete_datapath_transfer().await; // Host is allowed to use the new functions at least 8 // clocks after the end of the switch command @@ -1436,7 +1490,6 @@ impl<'d, T: Instance> Sdmmc<'d, T> { let scr = &mut cmd_block.0[..2]; // Arm `OnDrop` after the buffer, so it will be dropped first - let regs = T::regs(); let on_drop = OnDrop::new(|| Self::on_drop()); let transfer = Self::prepare_datapath_read( @@ -1450,27 +1503,7 @@ impl<'d, T: Instance> Sdmmc<'d, T> { InterruptHandler::::data_interrupts(true); Self::cmd(sd_cmd::send_scr(), true)?; - let res = poll_fn(|cx| { - T::state().register(cx.waker()); - let status = regs.star().read(); - - if status.dcrcfail() { - return Poll::Ready(Err(Error::Crc)); - } - if status.dtimeout() { - return Poll::Ready(Err(Error::Timeout)); - } - #[cfg(sdmmc_v1)] - if status.stbiterr() { - return Poll::Ready(Err(Error::StBitErr)); - } - if status.dataend() { - return Poll::Ready(Ok(())); - } - Poll::Pending - }) - .await; - Self::clear_interrupt_flags(); + let res = Self::complete_datapath_transfer().await; if res.is_ok() { on_drop.defuse(); @@ -1503,7 +1536,6 @@ impl<'d, T: Instance> Sdmmc<'d, T> { let status = cmd_block; // Arm `OnDrop` after the buffer, so it will be dropped first - let regs = T::regs(); let on_drop = OnDrop::new(|| Self::on_drop()); let transfer = Self::prepare_datapath_read( @@ -1517,27 +1549,7 @@ impl<'d, T: Instance> Sdmmc<'d, T> { InterruptHandler::::data_interrupts(true); Self::cmd(sd_cmd::sd_status(), true)?; - let res = poll_fn(|cx| { - T::state().register(cx.waker()); - let status = regs.star().read(); - - if status.dcrcfail() { - return Poll::Ready(Err(Error::Crc)); - } - if status.dtimeout() { - return Poll::Ready(Err(Error::Timeout)); - } - #[cfg(sdmmc_v1)] - if status.stbiterr() { - return Poll::Ready(Err(Error::StBitErr)); - } - if status.dataend() { - return Poll::Ready(Ok(())); - } - Poll::Pending - }) - .await; - Self::clear_interrupt_flags(); + let res = Self::complete_datapath_transfer().await; if res.is_ok() { on_drop.defuse(); @@ -1551,128 +1563,12 @@ impl<'d, T: Instance> Sdmmc<'d, T> { } res } -} -/// eMMC only. -impl<'d, T: Instance> Sdmmc<'d, T> { /// Initializes eMMC and sets the bus at the specified frequency. + /// + /// eMMC only. pub async fn init_emmc(&mut self, freq: Hertz) -> Result<(), Error> { - let regs = T::regs(); - let ker_ck = T::frequency(); - - let bus_width = match (self.d3.is_some(), self.d7.is_some()) { - (true, true) => BusWidth::Eight, - (true, false) => BusWidth::Four, - _ => BusWidth::One, - }; - - // While the SD/SDIO card or eMMC is in identification mode, - // the SDMMC_CK frequency must be no more than 400 kHz. - let (_bypass, clkdiv, init_clock) = unwrap!(clk_div(ker_ck, SD_INIT_FREQ.0)); - self.clock = init_clock; - - // CPSMACT and DPSMACT must be 0 to set WIDBUS - Self::wait_idle(); - - regs.clkcr().modify(|w| { - w.set_widbus(0); - w.set_clkdiv(clkdiv); - #[cfg(sdmmc_v1)] - w.set_bypass(_bypass); - }); - - regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::On as u8)); - Self::cmd(common_cmd::idle(), false)?; - - let mut card = Emmc::default(); - - let ocr = loop { - let high_voltage = 0b0 << 7; - let access_mode = 0b10 << 29; - let op_cond = high_voltage | access_mode | 0b1_1111_1111 << 15; - // Initialize card - match Self::cmd(emmc_cmd::send_op_cond(op_cond), false) { - Ok(_) => (), - Err(Error::Crc) => (), - Err(err) => return Err(err), - } - let ocr: OCR = regs.respr(0).read().cardstatus().into(); - if !ocr.is_busy() { - // Power up done - break ocr; - } - }; - - card.capacity = if ocr.access_mode() == 0b10 { - // Card is SDHC or SDXC or SDUC - CardCapacity::HighCapacity - } else { - CardCapacity::StandardCapacity - }; - card.ocr = ocr; - - Self::cmd(common_cmd::all_send_cid(), false)?; // CMD2 - let cid0 = regs.respr(0).read().cardstatus() as u128; - let cid1 = regs.respr(1).read().cardstatus() as u128; - let cid2 = regs.respr(2).read().cardstatus() as u128; - let cid3 = regs.respr(3).read().cardstatus() as u128; - let cid = (cid0 << 96) | (cid1 << 64) | (cid2 << 32) | (cid3); - card.cid = cid.into(); - - card.rca = 1u16.into(); - Self::cmd(emmc_cmd::assign_relative_address(card.rca), false)?; - - Self::cmd(common_cmd::send_csd(card.rca), false)?; - let csd0 = regs.respr(0).read().cardstatus() as u128; - let csd1 = regs.respr(1).read().cardstatus() as u128; - let csd2 = regs.respr(2).read().cardstatus() as u128; - let csd3 = regs.respr(3).read().cardstatus() as u128; - let csd = (csd0 << 96) | (csd1 << 64) | (csd2 << 32) | (csd3); - card.csd = csd.into(); - - self.select_card(Some(card.rca))?; - - // Set bus width - let (width, widbus) = match bus_width { - BusWidth::Eight => (BusWidth::Eight, 2), - BusWidth::Four => (BusWidth::Four, 1), - _ => (BusWidth::One, 0), - }; - // Write bus width to ExtCSD byte 183 - Self::cmd( - emmc_cmd::modify_ext_csd(emmc_cmd::AccessMode::WriteByte, 183, widbus), - false, - )?; - - self.card = Some(SdmmcPeripheral::Emmc(card)); - - // Wait for ready after R1b response - loop { - let status = self.read_status::(self.card.as_ref().unwrap())?; - - if status.ready_for_data() { - break; - } - } - - // CPSMACT and DPSMACT must be 0 to set WIDBUS - Self::wait_idle(); - - regs.clkcr().modify(|w| w.set_widbus(widbus)); - - // Set Clock - if freq.0 <= 25_000_000 { - // Final clock frequency - self.clkcr_set_clkdiv(freq.0, width)?; - } else { - // Switch to max clock for SDR12 - self.clkcr_set_clkdiv(25_000_000, width)?; - } - - // Read status - self.read_ext_csd().await?; - - Ok(()) + self.init_internal(freq, SdmmcPeripheral::Emmc(Emmc::default())).await } /// Gets the EXT_CSD register. @@ -1690,7 +1586,6 @@ impl<'d, T: Instance> Sdmmc<'d, T> { Self::cmd(common_cmd::set_block_length(512), false).unwrap(); // CMD16 // Arm `OnDrop` after the buffer, so it will be dropped first - let regs = T::regs(); let on_drop = OnDrop::new(|| Self::on_drop()); let transfer = Self::prepare_datapath_read( @@ -1704,27 +1599,7 @@ impl<'d, T: Instance> Sdmmc<'d, T> { InterruptHandler::::data_interrupts(true); Self::cmd(emmc_cmd::send_ext_csd(), true)?; - let res = poll_fn(|cx| { - T::state().register(cx.waker()); - let status = regs.star().read(); - - if status.dcrcfail() { - return Poll::Ready(Err(Error::Crc)); - } - if status.dtimeout() { - return Poll::Ready(Err(Error::Timeout)); - } - #[cfg(sdmmc_v1)] - if status.stbiterr() { - return Poll::Ready(Err(Error::StBitErr)); - } - if status.dataend() { - return Poll::Ready(Ok(())); - } - Poll::Pending - }) - .await; - Self::clear_interrupt_flags(); + let res = Self::complete_datapath_transfer().await; if res.is_ok() { on_drop.defuse(); diff --git a/examples/stm32f4/src/bin/sdmmc.rs b/examples/stm32f4/src/bin/sdmmc.rs index 66e4e527c..e97b63925 100644 --- a/examples/stm32f4/src/bin/sdmmc.rs +++ b/examples/stm32f4/src/bin/sdmmc.rs @@ -59,7 +59,7 @@ async fn main(_spawner: Spawner) { let mut err = None; loop { - match sdmmc.init_card(mhz(24)).await { + match sdmmc.init_sd_card(mhz(24)).await { Ok(_) => break, Err(e) => { if err != Some(e) { diff --git a/examples/stm32f7/src/bin/sdmmc.rs b/examples/stm32f7/src/bin/sdmmc.rs index 6d36ef518..787bef25e 100644 --- a/examples/stm32f7/src/bin/sdmmc.rs +++ b/examples/stm32f7/src/bin/sdmmc.rs @@ -54,7 +54,7 @@ async fn main(_spawner: Spawner) { // Should print 400kHz for initialization info!("Configured clock: {}", sdmmc.clock().0); - unwrap!(sdmmc.init_card(mhz(25)).await); + unwrap!(sdmmc.init_sd_card(mhz(25)).await); let card = unwrap!(sdmmc.card()); diff --git a/examples/stm32h7/src/bin/sdmmc.rs b/examples/stm32h7/src/bin/sdmmc.rs index abe2d4ba7..96840d8ff 100644 --- a/examples/stm32h7/src/bin/sdmmc.rs +++ b/examples/stm32h7/src/bin/sdmmc.rs @@ -53,7 +53,7 @@ async fn main(_spawner: Spawner) -> ! { // Should print 400kHz for initialization info!("Configured clock: {}", sdmmc.clock().0); - unwrap!(sdmmc.init_card(mhz(25)).await); + unwrap!(sdmmc.init_sd_card(mhz(25)).await); let card = unwrap!(sdmmc.card()); diff --git a/tests/stm32/src/bin/sdmmc.rs b/tests/stm32/src/bin/sdmmc.rs index 07f17b569..c1ed45588 100644 --- a/tests/stm32/src/bin/sdmmc.rs +++ b/tests/stm32/src/bin/sdmmc.rs @@ -54,7 +54,7 @@ async fn main(_spawner: Spawner) { let mut err = None; loop { - match s.init_card(mhz(24)).await { + match s.init_sd_card(mhz(24)).await { Ok(_) => break, Err(e) => { if err != Some(e) { @@ -100,7 +100,7 @@ async fn main(_spawner: Spawner) { let mut err = None; loop { - match s.init_card(mhz(24)).await { + match s.init_sd_card(mhz(24)).await { Ok(_) => break, Err(e) => { if err != Some(e) { From 882e2180a4ec7f448ea4ddaccf2a65e6757654c7 Mon Sep 17 00:00:00 2001 From: James Munns Date: Tue, 1 Apr 2025 14:06:04 +0200 Subject: [PATCH 0902/1217] Add docs, add `task_end` trace point --- embassy-executor/src/raw/mod.rs | 12 +++ embassy-executor/src/raw/trace.rs | 149 ++++++++++++++++++++++++++++++ 2 files changed, 161 insertions(+) diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs index e38a2af66..73f4f00ee 100644 --- a/embassy-executor/src/raw/mod.rs +++ b/embassy-executor/src/raw/mod.rs @@ -138,6 +138,12 @@ impl TaskRef { pub(crate) fn as_ptr(self) -> *const TaskHeader { self.ptr.as_ptr() } + + /// Get the ID for a task + #[cfg(feature = "trace")] + pub fn as_id(self) -> u32 { + self.ptr.as_ptr() as u32 + } } /// Raw storage in which a task can be spawned. @@ -224,6 +230,9 @@ impl TaskStorage { // Make sure we despawn last, so that other threads can only spawn the task // after we're done with it. this.raw.state.despawn(); + + #[cfg(feature = "trace")] + trace::task_end(self, &task); } Poll::Pending => {} } @@ -420,6 +429,9 @@ impl SyncExecutor { /// /// Same as [`Executor::poll`], plus you must only call this on the thread this executor was created. pub(crate) unsafe fn poll(&'static self) { + #[cfg(feature = "trace")] + trace::poll_start(self); + self.run_queue.dequeue_all(|p| { let task = p.header(); diff --git a/embassy-executor/src/raw/trace.rs b/embassy-executor/src/raw/trace.rs index b34387b58..57222d60b 100644 --- a/embassy-executor/src/raw/trace.rs +++ b/embassy-executor/src/raw/trace.rs @@ -1,15 +1,156 @@ #![allow(unused)] use crate::raw::{SyncExecutor, TaskRef}; +//! # Tracing +//! +//! The `trace` feature enables a number of callbacks that can be used to track the +//! lifecycle of tasks and/or executors. +//! +//! Callbacks will have one or both of the following IDs passed to them: +//! +//! 1. A `task_id`, a `u32` value unique to a task for the duration of the time it is valid +//! 2. An `executor_id`, a `u32` value unique to an executor for the duration of the time it is +//! valid +//! +//! Today, both `task_id` and `executor_id` are u32s containing the least significant 32 bits of +//! the address of the task or executor, however this is NOT a stable guarantee, and MAY change +//! at any time. +//! +//! IDs are only guaranteed to be unique for the duration of time the item is valid. If a task +//! ends, and is respond, it MAY or MAY NOT have the same ID. For tasks, this time is defined +//! as the time between `_embassy_trace_task_new` and `_embassy_trace_task_end` for a given task. +//! For executors, this time is not defined, but is often "forever" for practical embedded +//! programs. +//! +//! Callbacks can be used by enabling the `trace` feature, and providing implementations of the +//! `extern "Rust"` functions below. All callbacks must be implemented. +//! +//! ## Stability +//! +//! The `trace` interface is considered unstable. Callbacks may change, be added, or be removed +//! in any minor or trivial release. +//! +//! ## Task Tracing lifecycle +//! +//! ```text +//! ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ +//! │(1) │ +//! │ │ +//! â•”â•â•â•â•â–¼â•â•â•â•â•— (2) ┌─────────┠(3) ┌─────────┠│ +//! │ â•‘ SPAWNED ║────▶│ WAITING │────▶│ RUNNING │ +//! ╚â•â•â•â•â•â•â•â•â•╠└─────────┘ └─────────┘ │ +//! │ â–² â–² │ │ │ +//! │ (4) │ │(6) │ +//! │ │ â”” ─ ─ ┘ │ │ +//! │ │ │ │ +//! │ ┌──────┠(5) │ │ ┌─────┠+//! │ IDLE │◀────────────────┘ └─▶│ END │ │ +//! │ └──────┘ └─────┘ +//! ┌──────────────────────┠│ +//! â”” ┤ Task Trace Lifecycle │─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ +//! └──────────────────────┘ +//! ``` +//! +//! 1. A task is spawned. `_embassy_trace_task_new` is called +//! 2. A task is enqueued for the first time, `_embassy_trace_task_ready_begin` is called +//! 3. A task is polled, `_embassy_trace_task_exec_begin` is called +//! 4. WHILE a task is polled, the task is re-awoken, and `_embassy_trace_task_ready_begin` is +//! called. The task does not IMMEDIATELY move state, until polling is complete and the +//! RUNNING state is existed. `_embassy_trace_task_exec_end` is called when polling is +//! complete, marking the transition to WAITING +//! 5. Polling is complete, `_embassy_trace_task_exec_end` is called +//! 6. The task has completed, and `_embassy_trace_task_end` is called. +//! +//! ## Executor Tracing lifecycle +//! +//! ```text +//! ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ +//! │(1) │ +//! │ │ +//! â•”â•â•â•â–¼â•â•â•— (2) ┌────────────┠(3) ┌─────────┠│ +//! │ â•‘ IDLE ║──────────▶│ SCHEDULING │──────▶│ POLLING │ +//! ╚â•â•â•â•â•â•╠└────────────┘ └─────────┘ │ +//! │ â–² │ â–² │ +//! │ (5) │ │ (4) │ │ +//! │ └──────────────┘ └────────────┘ +//! ┌──────────────────────────┠│ +//! â”” ┤ Executor Trace Lifecycle │─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ +//! └──────────────────────────┘ +//! ``` +//! +//! 1. The executor is started (no associated trace) +//! 2. A task on this executor is awoken. `_embassy_trace_task_ready_begin` is called +//! when this occurs, and `_embassy_trace_poll_start` is called when the executor +//! actually begins running. +//! 3. The executor has decided a task to poll. `_embassy_trace_task_exec_begin` is called. +//! 4. The executor finishes polling the task. `_embassy_trace_task_exec_end` is called. +//! 5. The executor has finished polling tasks. `_embassy_trace_executor_idle` is called. + #[cfg(not(feature = "rtos-trace"))] extern "Rust" { + /// This callback is called when the executor begins polling. This will always + /// be paired with a later call to `_embassy_trace_executor_idle`. + /// + /// This marks the EXECUTOR state transition from IDLE -> SCHEDULING. + fn _embassy_trace_poll_start(executor_id: u32); + + /// This callback is called AFTER a task is initialized/allocated, and BEFORE + /// it is enqueued to run for the first time. If the task ends (and does not + /// loop "forever"), there will be a matching call to `_embassy_trace_task_end`. + /// + /// Tasks start life in the SPAWNED state. fn _embassy_trace_task_new(executor_id: u32, task_id: u32); + + /// This callback is called AFTER a task is destructed/freed. This will always + /// have a prior matching call to `_embassy_trace_task_new`. + fn _embassy_trace_task_end(executor_id: u32, task_id: u32); + + /// This callback is called AFTER a task has been dequeued from the runqueue, + /// and BEFORE the task is polled. There will always be a matching call to + /// `_embassy_trace_task_exec_end`. + /// + /// This marks the TASK state transition from WAITING -> RUNNING + /// This marks the EXECUTOR state transition from SCHEDULING -> POLLING fn _embassy_trace_task_exec_begin(executor_id: u32, task_id: u32); + + /// This callback is called AFTER a task has completed polling. There will + /// always be a matching call to `_embassy_trace_task_exec_begin`. + /// + /// This marks the TASK state transition from either: + /// * RUNNING -> IDLE - if there were no `_embassy_trace_task_ready_begin` events + /// for this task since the last `_embassy_trace_task_exec_begin` for THIS task + /// * RUNNING -> WAITING - if there WAS a `_embassy_trace_task_ready_begin` event + /// for this task since the last `_embassy_trace_task_exec_begin` for THIS task + /// + /// This marks the EXECUTOR state transition from POLLING -> SCHEDULING fn _embassy_trace_task_exec_end(excutor_id: u32, task_id: u32); + + /// This callback is called AFTER the waker for a task is awoken, and BEFORE it + /// is added to the run queue. + /// + /// If the given task is currently RUNNING, this marks no state change, BUT the + /// RUNNING task will then move to the WAITING stage when polling is complete. + /// + /// If the given task is currently IDLE, this marks the TASK state transition + /// from IDLE -> WAITING. fn _embassy_trace_task_ready_begin(executor_id: u32, task_id: u32); + + /// This callback is called AFTER all dequeued tasks in a single call to poll + /// have been processed. This will always be paired with a call to + /// `_embassy_trace_executor_idle`. + /// + /// This marks the EXECUTOR state transition from fn _embassy_trace_executor_idle(executor_id: u32); } +#[inline] +pub(crate) fn poll_start(executor: &SyncExecutor) { + #[cfg(not(feature = "rtos-trace"))] + unsafe { + _embassy_trace_poll_start(executor as *const _ as u32) + } +} + #[inline] pub(crate) fn task_new(executor: &SyncExecutor, task: &TaskRef) { #[cfg(not(feature = "rtos-trace"))] @@ -21,6 +162,14 @@ pub(crate) fn task_new(executor: &SyncExecutor, task: &TaskRef) { rtos_trace::trace::task_new(task.as_ptr() as u32); } +#[inline] +pub(crate) fn task_end(executor: &SyncExecutor, task: &TaskRef) { + #[cfg(not(feature = "rtos-trace"))] + unsafe { + _embassy_trace_task_end(executor as *const _ as u32, task.as_ptr() as u32) + } +} + #[inline] pub(crate) fn task_ready_begin(executor: &SyncExecutor, task: &TaskRef) { #[cfg(not(feature = "rtos-trace"))] From 84cd416bed6a80d0fab4433c26ada9b16495b4c1 Mon Sep 17 00:00:00 2001 From: James Munns Date: Tue, 1 Apr 2025 14:11:42 +0200 Subject: [PATCH 0903/1217] Finish trailing sentence --- embassy-executor/src/raw/trace.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-executor/src/raw/trace.rs b/embassy-executor/src/raw/trace.rs index 57222d60b..efb74b3d2 100644 --- a/embassy-executor/src/raw/trace.rs +++ b/embassy-executor/src/raw/trace.rs @@ -139,7 +139,7 @@ extern "Rust" { /// have been processed. This will always be paired with a call to /// `_embassy_trace_executor_idle`. /// - /// This marks the EXECUTOR state transition from + /// This marks the EXECUTOR state transition from SCHEDULING -> IDLE fn _embassy_trace_executor_idle(executor_id: u32); } From 8a8e4500531342001977cdc99d6d107dd84be8e1 Mon Sep 17 00:00:00 2001 From: James Munns Date: Tue, 1 Apr 2025 14:12:58 +0200 Subject: [PATCH 0904/1217] Reorder doc comments for format reasons --- embassy-executor/src/raw/trace.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/embassy-executor/src/raw/trace.rs b/embassy-executor/src/raw/trace.rs index efb74b3d2..0952a9bc0 100644 --- a/embassy-executor/src/raw/trace.rs +++ b/embassy-executor/src/raw/trace.rs @@ -1,6 +1,3 @@ -#![allow(unused)] -use crate::raw::{SyncExecutor, TaskRef}; - //! # Tracing //! //! The `trace` feature enables a number of callbacks that can be used to track the @@ -86,6 +83,9 @@ use crate::raw::{SyncExecutor, TaskRef}; //! 4. The executor finishes polling the task. `_embassy_trace_task_exec_end` is called. //! 5. The executor has finished polling tasks. `_embassy_trace_executor_idle` is called. +#![allow(unused)] +use crate::raw::{SyncExecutor, TaskRef}; + #[cfg(not(feature = "rtos-trace"))] extern "Rust" { /// This callback is called when the executor begins polling. This will always From c3efb85b85eece9f706d232888e0fb70ee1270e4 Mon Sep 17 00:00:00 2001 From: James Munns Date: Tue, 1 Apr 2025 14:23:39 +0200 Subject: [PATCH 0905/1217] Fix task_end callback --- embassy-executor/src/raw/mod.rs | 5 ++++- embassy-executor/src/raw/trace.rs | 5 +++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs index 73f4f00ee..5b1f33a0e 100644 --- a/embassy-executor/src/raw/mod.rs +++ b/embassy-executor/src/raw/mod.rs @@ -219,6 +219,9 @@ impl TaskStorage { let mut cx = Context::from_waker(&waker); match future.poll(&mut cx) { Poll::Ready(_) => { + #[cfg(feature = "trace")] + let exec_ptr: *const SyncExecutor = this.raw.executor.load(Ordering::Relaxed); + // As the future has finished and this function will not be called // again, we can safely drop the future here. this.future.drop_in_place(); @@ -232,7 +235,7 @@ impl TaskStorage { this.raw.state.despawn(); #[cfg(feature = "trace")] - trace::task_end(self, &task); + trace::task_end(exec_ptr, &p); } Poll::Pending => {} } diff --git a/embassy-executor/src/raw/trace.rs b/embassy-executor/src/raw/trace.rs index 0952a9bc0..56724b0bb 100644 --- a/embassy-executor/src/raw/trace.rs +++ b/embassy-executor/src/raw/trace.rs @@ -84,6 +84,7 @@ //! 5. The executor has finished polling tasks. `_embassy_trace_executor_idle` is called. #![allow(unused)] + use crate::raw::{SyncExecutor, TaskRef}; #[cfg(not(feature = "rtos-trace"))] @@ -163,10 +164,10 @@ pub(crate) fn task_new(executor: &SyncExecutor, task: &TaskRef) { } #[inline] -pub(crate) fn task_end(executor: &SyncExecutor, task: &TaskRef) { +pub(crate) fn task_end(executor: *const SyncExecutor, task: &TaskRef) { #[cfg(not(feature = "rtos-trace"))] unsafe { - _embassy_trace_task_end(executor as *const _ as u32, task.as_ptr() as u32) + _embassy_trace_task_end(executor as u32, task.as_ptr() as u32) } } From 3e25a7be8670f06d577ebf011dc41e3c4752db95 Mon Sep 17 00:00:00 2001 From: James Munns Date: Tue, 1 Apr 2025 14:27:32 +0200 Subject: [PATCH 0906/1217] Small grammar fixes --- embassy-executor/src/raw/trace.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-executor/src/raw/trace.rs b/embassy-executor/src/raw/trace.rs index 56724b0bb..5480e77b9 100644 --- a/embassy-executor/src/raw/trace.rs +++ b/embassy-executor/src/raw/trace.rs @@ -14,7 +14,7 @@ //! at any time. //! //! IDs are only guaranteed to be unique for the duration of time the item is valid. If a task -//! ends, and is respond, it MAY or MAY NOT have the same ID. For tasks, this time is defined +//! ends, and is re-spawned, it MAY or MAY NOT have the same ID. For tasks, this valid time is defined //! as the time between `_embassy_trace_task_new` and `_embassy_trace_task_end` for a given task. //! For executors, this time is not defined, but is often "forever" for practical embedded //! programs. From 2e474b7df2466364964156e119b37bd8445169d7 Mon Sep 17 00:00:00 2001 From: James Munns Date: Tue, 1 Apr 2025 14:30:36 +0200 Subject: [PATCH 0907/1217] Remove notes about stability --- embassy-executor/src/raw/trace.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/embassy-executor/src/raw/trace.rs b/embassy-executor/src/raw/trace.rs index 5480e77b9..8fcf84658 100644 --- a/embassy-executor/src/raw/trace.rs +++ b/embassy-executor/src/raw/trace.rs @@ -22,11 +22,6 @@ //! Callbacks can be used by enabling the `trace` feature, and providing implementations of the //! `extern "Rust"` functions below. All callbacks must be implemented. //! -//! ## Stability -//! -//! The `trace` interface is considered unstable. Callbacks may change, be added, or be removed -//! in any minor or trivial release. -//! //! ## Task Tracing lifecycle //! //! ```text From ef3c1b87d16d17e312e869546fae00f895f68989 Mon Sep 17 00:00:00 2001 From: James Munns Date: Tue, 1 Apr 2025 14:35:21 +0200 Subject: [PATCH 0908/1217] Minor docs improvements --- embassy-executor/src/raw/trace.rs | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/embassy-executor/src/raw/trace.rs b/embassy-executor/src/raw/trace.rs index 8fcf84658..aba519c8f 100644 --- a/embassy-executor/src/raw/trace.rs +++ b/embassy-executor/src/raw/trace.rs @@ -33,7 +33,7 @@ //! ╚â•â•â•â•â•â•â•â•â•╠└─────────┘ └─────────┘ │ //! │ â–² â–² │ │ │ //! │ (4) │ │(6) │ -//! │ │ â”” ─ ─ ┘ │ │ +//! │ │(7) â”” ─ ─ ┘ │ │ //! │ │ │ │ //! │ ┌──────┠(5) │ │ ┌─────┠//! │ IDLE │◀────────────────┘ └─▶│ END │ │ @@ -43,7 +43,7 @@ //! └──────────────────────┘ //! ``` //! -//! 1. A task is spawned. `_embassy_trace_task_new` is called +//! 1. A task is spawned, `_embassy_trace_task_new` is called //! 2. A task is enqueued for the first time, `_embassy_trace_task_ready_begin` is called //! 3. A task is polled, `_embassy_trace_task_exec_begin` is called //! 4. WHILE a task is polled, the task is re-awoken, and `_embassy_trace_task_ready_begin` is @@ -51,7 +51,8 @@ //! RUNNING state is existed. `_embassy_trace_task_exec_end` is called when polling is //! complete, marking the transition to WAITING //! 5. Polling is complete, `_embassy_trace_task_exec_end` is called -//! 6. The task has completed, and `_embassy_trace_task_end` is called. +//! 6. The task has completed, and `_embassy_trace_task_end` is called +//! 7. A task is awoken, `_embassy_trace_task_ready_begin` is called //! //! ## Executor Tracing lifecycle //! @@ -73,10 +74,10 @@ //! 1. The executor is started (no associated trace) //! 2. A task on this executor is awoken. `_embassy_trace_task_ready_begin` is called //! when this occurs, and `_embassy_trace_poll_start` is called when the executor -//! actually begins running. -//! 3. The executor has decided a task to poll. `_embassy_trace_task_exec_begin` is called. -//! 4. The executor finishes polling the task. `_embassy_trace_task_exec_end` is called. -//! 5. The executor has finished polling tasks. `_embassy_trace_executor_idle` is called. +//! actually begins running +//! 3. The executor has decided a task to poll. `_embassy_trace_task_exec_begin` is called +//! 4. The executor finishes polling the task. `_embassy_trace_task_exec_end` is called +//! 5. The executor has finished polling tasks. `_embassy_trace_executor_idle` is called #![allow(unused)] @@ -129,6 +130,9 @@ extern "Rust" { /// /// If the given task is currently IDLE, this marks the TASK state transition /// from IDLE -> WAITING. + /// + /// NOTE: This may be called from an interrupt, outside the context of the current + /// task or executor. fn _embassy_trace_task_ready_begin(executor_id: u32, task_id: u32); /// This callback is called AFTER all dequeued tasks in a single call to poll From 47869d122ab68ea9a962ba749c523b94066d0763 Mon Sep 17 00:00:00 2001 From: Fredrik Reinholdsen Date: Thu, 27 Feb 2025 20:18:24 +0100 Subject: [PATCH 0909/1217] fix: Fix for #3888 async I2C read bug for introduced in #3887 in STM32 I2C v2 driver In fixing a different timing related bug, #3887, a new bug was introduced causing I2C reads longer than 255 bytes to timeout for some I2C devices, #3888. The issue was caused by incorrect branch order, and poll function being called unnecessarily. Async I2C read poll function now only looks for I2C transfer complete reload (TCR) interrupts, intead of TCR and transfer complete (TC) interrupts, since TC interrupts are not raised when AUTOEND bit is set. --- embassy-stm32/src/i2c/v2.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs index 1f53a995d..50a25754e 100644 --- a/embassy-stm32/src/i2c/v2.rs +++ b/embassy-stm32/src/i2c/v2.rs @@ -617,9 +617,10 @@ impl<'d> I2c<'d, Async> { restart, timeout, )?; - } else if remaining_len == 0 { - return Poll::Ready(Ok(())); - } else if !(isr.tcr() || isr.tc()) { + if total_len <= 255 { + return Poll::Ready(Ok(())); + } + } else if isr.tcr() { // poll_fn was woken without an interrupt present return Poll::Pending; } else { @@ -628,6 +629,11 @@ impl<'d> I2c<'d, Async> { if let Err(e) = Self::master_continue(self.info, remaining_len.min(255), !last_piece, timeout) { return Poll::Ready(Err(e)); } + // Return here if we are on last chunk, + // end of transfer will be awaited with the DMA below + if last_piece { + return Poll::Ready(Ok(())); + } self.info.regs.cr1().modify(|w| w.set_tcie(true)); } From 03061a081783f54ea6614d70dfd7f4b3d5256cbb Mon Sep 17 00:00:00 2001 From: Kelsey Maes Date: Wed, 2 Apr 2025 08:33:12 -0700 Subject: [PATCH 0910/1217] mspm0: Fix `set_pf_unchecked()` assertion --- embassy-mspm0/src/gpio.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-mspm0/src/gpio.rs b/embassy-mspm0/src/gpio.rs index 2edadbc5a..f9dcade4f 100644 --- a/embassy-mspm0/src/gpio.rs +++ b/embassy-mspm0/src/gpio.rs @@ -208,8 +208,8 @@ impl<'d> Flex<'d> { /// or technical reference manual for additional details. #[inline] pub fn set_pf_unchecked(&mut self, pf: u8) { - // Per SLAU893, PF is only 5 bits - assert!((pf & 0x3F) != 0, "PF is out of range"); + // Per SLAU893 and SLAU846B, PF is only 6 bits + assert_eq!(pf & 0xC0, 0, "PF is out of range"); let pincm = pac::IOMUX.pincm(self.pin.pin_cm() as usize); From b7e1b1ca941b3b92dede55f2a5b65fcad788ce42 Mon Sep 17 00:00:00 2001 From: James Munns Date: Thu, 3 Apr 2025 10:35:00 +0200 Subject: [PATCH 0911/1217] Fix some intra-doc links --- embassy-executor/src/arch/cortex_m.rs | 9 +++++---- embassy-executor/src/raw/waker.rs | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/embassy-executor/src/arch/cortex_m.rs b/embassy-executor/src/arch/cortex_m.rs index 5c517e0a2..1c9ddd8a0 100644 --- a/embassy-executor/src/arch/cortex_m.rs +++ b/embassy-executor/src/arch/cortex_m.rs @@ -143,7 +143,7 @@ mod interrupt { /// If this is not the case, you may use an interrupt from any unused peripheral. /// /// It is somewhat more complex to use, it's recommended to use the thread-mode - /// [`Executor`] instead, if it works for your use case. + /// [`Executor`](crate::Executor) instead, if it works for your use case. pub struct InterruptExecutor { started: Mutex>, executor: UnsafeCell>, @@ -179,11 +179,11 @@ mod interrupt { /// The executor keeps running in the background through the interrupt. /// /// This returns a [`SendSpawner`] you can use to spawn tasks on it. A [`SendSpawner`] - /// is returned instead of a [`Spawner`](embassy_executor::Spawner) because the executor effectively runs in a + /// is returned instead of a [`Spawner`](crate::Spawner) because the executor effectively runs in a /// different "thread" (the interrupt), so spawning tasks on it is effectively /// sending them. /// - /// To obtain a [`Spawner`](embassy_executor::Spawner) for this executor, use [`Spawner::for_current_executor()`](embassy_executor::Spawner::for_current_executor()) from + /// To obtain a [`Spawner`](crate::Spawner) for this executor, use [`Spawner::for_current_executor()`](crate::Spawner::for_current_executor()) from /// a task running in it. /// /// # Interrupt requirements @@ -195,6 +195,7 @@ mod interrupt { /// You must set the interrupt priority before calling this method. You MUST NOT /// do it after. /// + /// [`SendSpawner`]: crate::SendSpawner pub fn start(&'static self, irq: impl InterruptNumber) -> crate::SendSpawner { if critical_section::with(|cs| self.started.borrow(cs).replace(true)) { panic!("InterruptExecutor::start() called multiple times on the same executor."); @@ -215,7 +216,7 @@ mod interrupt { /// Get a SendSpawner for this executor /// - /// This returns a [`SendSpawner`] you can use to spawn tasks on this + /// This returns a [`SendSpawner`](crate::SendSpawner) you can use to spawn tasks on this /// executor. /// /// This MUST only be called on an executor that has already been started. diff --git a/embassy-executor/src/raw/waker.rs b/embassy-executor/src/raw/waker.rs index b7d57c314..d0d7b003d 100644 --- a/embassy-executor/src/raw/waker.rs +++ b/embassy-executor/src/raw/waker.rs @@ -26,7 +26,7 @@ pub(crate) unsafe fn from_task(p: TaskRef) -> Waker { /// (1 word) instead of full Wakers (2 words). This saves a bit of RAM and helps /// avoid dynamic dispatch. /// -/// You can use the returned task pointer to wake the task with [`wake_task`](super::wake_task). +/// You can use the returned task pointer to wake the task with [`wake_task`]. /// /// # Panics /// From 72832c1550201dba4629ee861b84143502465064 Mon Sep 17 00:00:00 2001 From: James Munns Date: Thu, 3 Apr 2025 19:01:00 +0200 Subject: [PATCH 0912/1217] embassy-rp: defensive change to ensure wakers are registered This change ensures that wakers are registered PRIOR to checking status in i2c `wait_on` helpers. --- embassy-rp/src/i2c.rs | 6 ++++-- embassy-rp/src/i2c_slave.rs | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/embassy-rp/src/i2c.rs b/embassy-rp/src/i2c.rs index adc38b73d..a983b7bc3 100644 --- a/embassy-rp/src/i2c.rs +++ b/embassy-rp/src/i2c.rs @@ -114,17 +114,19 @@ impl<'d, T: Instance> I2c<'d, T, Async> { } /// Calls `f` to check if we are ready or not. - /// If not, `g` is called once the waker is set (to eg enable the required interrupts). + /// If not, `g` is called once(to eg enable the required interrupts). + /// The waker will always be registered prior to calling `f`. async fn wait_on(&mut self, mut f: F, mut g: G) -> U where F: FnMut(&mut Self) -> Poll, G: FnMut(&mut Self), { future::poll_fn(|cx| { + // Register prior to checking the condition + T::waker().register(cx.waker()); let r = f(self); if r.is_pending() { - T::waker().register(cx.waker()); g(self); } r diff --git a/embassy-rp/src/i2c_slave.rs b/embassy-rp/src/i2c_slave.rs index d420030d8..7bc14511d 100644 --- a/embassy-rp/src/i2c_slave.rs +++ b/embassy-rp/src/i2c_slave.rs @@ -159,7 +159,8 @@ impl<'d, T: Instance> I2cSlave<'d, T> { } /// Calls `f` to check if we are ready or not. - /// If not, `g` is called once the waker is set (to eg enable the required interrupts). + /// If not, `g` is called once(to eg enable the required interrupts). + /// The waker will always be registered prior to calling `f`. #[inline(always)] async fn wait_on(&mut self, mut f: F, mut g: G) -> U where @@ -167,10 +168,11 @@ impl<'d, T: Instance> I2cSlave<'d, T> { G: FnMut(&mut Self), { future::poll_fn(|cx| { + // Register prior to checking the condition + T::waker().register(cx.waker()); let r = f(self); if r.is_pending() { - T::waker().register(cx.waker()); g(self); } From b2d9203af77821931dc79a70d4c42c2a03d82c27 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Fri, 4 Apr 2025 15:19:54 +0800 Subject: [PATCH 0913/1217] Bump stm32-data --- embassy-stm32/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 8204a0fea..4d0555d4a 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -73,7 +73,7 @@ rand_core = "0.6.3" sdio-host = "0.5.0" critical-section = "1.1" #stm32-metapac = { version = "16" } -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-4a964af03b298de30ff9f84fcfa890bcab4ce609" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-a7a30c9d54e7415709c463a537501691784672db" } vcell = "0.1.3" nb = "1.0.0" @@ -102,7 +102,7 @@ proc-macro2 = "1.0.36" quote = "1.0.15" #stm32-metapac = { version = "16", default-features = false, features = ["metadata"]} -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-4a964af03b298de30ff9f84fcfa890bcab4ce609", default-features = false, features = ["metadata"] } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-a7a30c9d54e7415709c463a537501691784672db", default-features = false, features = ["metadata"] } [features] default = ["rt"] From 6d384a1a39f586c86cabe912fef639336cdc1ac7 Mon Sep 17 00:00:00 2001 From: Rick Rogers Date: Fri, 31 Jan 2025 18:12:30 -0500 Subject: [PATCH 0914/1217] introduce stm32h7rs xspi --- embassy-stm32/build.rs | 78 ++ embassy-stm32/src/lib.rs | 2 + embassy-stm32/src/xspi/enums.rs | 385 +++++++++ embassy-stm32/src/xspi/mod.rs | 1427 +++++++++++++++++++++++++++++++ 4 files changed, 1892 insertions(+) create mode 100644 embassy-stm32/src/xspi/enums.rs create mode 100644 embassy-stm32/src/xspi/mod.rs diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 798133162..13ef74f16 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -116,6 +116,7 @@ fn main() { "peri_usb_otg_fs", "peri_usb_otg_hs", "peri_octospi2", + "peri_xspi2", ]); cfgs.declare_all(&["mco", "mco1", "mco2"]); @@ -1098,6 +1099,72 @@ fn main() { (("octospim", "P2_NCS"), quote!(crate::ospi::NSSPin)), (("octospim", "P2_CLK"), quote!(crate::ospi::SckPin)), (("octospim", "P2_NCLK"), quote!(crate::ospi::NckPin)), + (("xspi", "IO0"), quote!(crate::xspi::D0Pin)), + (("xspi", "IO1"), quote!(crate::xspi::D1Pin)), + (("xspi", "IO2"), quote!(crate::xspi::D2Pin)), + (("xspi", "IO3"), quote!(crate::xspi::D3Pin)), + (("xspi", "IO4"), quote!(crate::xspi::D4Pin)), + (("xspi", "IO5"), quote!(crate::xspi::D5Pin)), + (("xspi", "IO6"), quote!(crate::xspi::D6Pin)), + (("xspi", "IO7"), quote!(crate::xspi::D7Pin)), + (("xspi", "IO8"), quote!(crate::xspi::D8Pin)), + (("xspi", "IO9"), quote!(crate::xspi::D9Pin)), + (("xspi", "IO10"), quote!(crate::xspi::D10Pin)), + (("xspi", "IO11"), quote!(crate::xspi::D11Pin)), + (("xspi", "IO12"), quote!(crate::xspi::D12Pin)), + (("xspi", "IO13"), quote!(crate::xspi::D13Pin)), + (("xspi", "IO14"), quote!(crate::xspi::D14Pin)), + (("xspi", "IO15"), quote!(crate::xspi::D15Pin)), + (("xspi", "DQS0"), quote!(crate::xspi::DQS0Pin)), + (("xspi", "DQS1"), quote!(crate::xspi::DQS1Pin)), + (("xspi", "NCS1"), quote!(crate::xspi::NCS1Pin)), + (("xspi", "NCS2"), quote!(crate::xspi::NCS2Pin)), + (("xspi", "CLK"), quote!(crate::xspi::CLKPin)), + (("xspi", "NCLK"), quote!(crate::xspi::NCLKPin)), + (("xspim", "P1_IO0"), quote!(crate::xspi::D0Pin)), + (("xspim", "P1_IO1"), quote!(crate::xspi::D1Pin)), + (("xspim", "P1_IO2"), quote!(crate::xspi::D2Pin)), + (("xspim", "P1_IO3"), quote!(crate::xspi::D3Pin)), + (("xspim", "P1_IO4"), quote!(crate::xspi::D4Pin)), + (("xspim", "P1_IO5"), quote!(crate::xspi::D5Pin)), + (("xspim", "P1_IO6"), quote!(crate::xspi::D6Pin)), + (("xspim", "P1_IO7"), quote!(crate::xspi::D7Pin)), + (("xspim", "P1_IO8"), quote!(crate::xspi::D8Pin)), + (("xspim", "P1_IO9"), quote!(crate::xspi::D9Pin)), + (("xspim", "P1_IO10"), quote!(crate::xspi::D10Pin)), + (("xspim", "P1_IO11"), quote!(crate::xspi::D11Pin)), + (("xspim", "P1_IO12"), quote!(crate::xspi::D12Pin)), + (("xspim", "P1_IO13"), quote!(crate::xspi::D13Pin)), + (("xspim", "P1_IO14"), quote!(crate::xspi::D14Pin)), + (("xspim", "P1_IO15"), quote!(crate::xspi::D15Pin)), + (("xspim", "P1_DQS0"), quote!(crate::xspi::DQS0Pin)), + (("xspim", "P1_DQS1"), quote!(crate::xspi::DQS1Pin)), + (("xspim", "P1_NCS1"), quote!(crate::xspi::NCS1Pin)), + (("xspim", "P1_NCS2"), quote!(crate::xspi::NCS2Pin)), + (("xspim", "P1_CLK"), quote!(crate::xspi::CLKPin)), + (("xspim", "P1_NCLK"), quote!(crate::xspi::NCLKPin)), + (("xspim", "P2_IO0"), quote!(crate::xspi::D0Pin)), + (("xspim", "P2_IO1"), quote!(crate::xspi::D1Pin)), + (("xspim", "P2_IO2"), quote!(crate::xspi::D2Pin)), + (("xspim", "P2_IO3"), quote!(crate::xspi::D3Pin)), + (("xspim", "P2_IO4"), quote!(crate::xspi::D4Pin)), + (("xspim", "P2_IO5"), quote!(crate::xspi::D5Pin)), + (("xspim", "P2_IO6"), quote!(crate::xspi::D6Pin)), + (("xspim", "P2_IO7"), quote!(crate::xspi::D7Pin)), + (("xspim", "P2_IO8"), quote!(crate::xspi::D8Pin)), + (("xspim", "P2_IO9"), quote!(crate::xspi::D9Pin)), + (("xspim", "P2_IO10"), quote!(crate::xspi::D10Pin)), + (("xspim", "P2_IO11"), quote!(crate::xspi::D11Pin)), + (("xspim", "P2_IO12"), quote!(crate::xspi::D12Pin)), + (("xspim", "P2_IO13"), quote!(crate::xspi::D13Pin)), + (("xspim", "P2_IO14"), quote!(crate::xspi::D14Pin)), + (("xspim", "P2_IO15"), quote!(crate::xspi::D15Pin)), + (("xspim", "P2_DQS0"), quote!(crate::xspi::DQS0Pin)), + (("xspim", "P2_DQS1"), quote!(crate::xspi::DQS1Pin)), + (("xspim", "P2_NCS1"), quote!(crate::xspi::NCS1Pin)), + (("xspim", "P2_NCS2"), quote!(crate::xspi::NCS2Pin)), + (("xspim", "P2_CLK"), quote!(crate::xspi::CLKPin)), + (("xspim", "P2_NCLK"), quote!(crate::xspi::NCLKPin)), (("hspi", "IO0"), quote!(crate::hspi::D0Pin)), (("hspi", "IO1"), quote!(crate::hspi::D1Pin)), (("hspi", "IO2"), quote!(crate::hspi::D2Pin)), @@ -1190,6 +1257,17 @@ fn main() { peri = format_ident!("{}", "OCTOSPI1"); } + // XSPIM is special + if p.name == "XSPIM" { + if pin.signal.starts_with("P1") { + peri = format_ident!("{}", "XSPI1"); + } else if pin.signal.starts_with("P2") { + peri = format_ident!("{}", "XSPI2"); + } else { + panic! {"malformed XSPIM pin: {:?}", pin} + } + } + g.extend(quote! { pin_trait_impl!(#tr, #peri, #pin_name, #af); }) diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 4d7aac81f..226293a9d 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -127,6 +127,8 @@ pub mod usart; pub mod usb; #[cfg(iwdg)] pub mod wdg; +#[cfg(xspi)] +pub mod xspi; // This must go last, so that it sees all the impl_foo! macros defined earlier. pub(crate) mod _generated { diff --git a/embassy-stm32/src/xspi/enums.rs b/embassy-stm32/src/xspi/enums.rs new file mode 100644 index 000000000..4214dde37 --- /dev/null +++ b/embassy-stm32/src/xspi/enums.rs @@ -0,0 +1,385 @@ +//! Enums used in Xspi configuration. +#[allow(dead_code)] +#[derive(Copy, Clone)] +pub(crate) enum XspiMode { + IndirectWrite, + IndirectRead, + AutoPolling, + MemoryMapped, +} + +impl Into for XspiMode { + fn into(self) -> u8 { + match self { + XspiMode::IndirectWrite => 0b00, + XspiMode::IndirectRead => 0b01, + XspiMode::AutoPolling => 0b10, + XspiMode::MemoryMapped => 0b11, + } + } +} + +/// Xspi lane width +#[allow(dead_code)] +#[derive(Copy, Clone)] +pub enum XspiWidth { + /// None + NONE, + /// Single lane + SING, + /// Dual lanes + DUAL, + /// Quad lanes + QUAD, + /// Eight lanes + OCTO, +} + +impl Into for XspiWidth { + fn into(self) -> u8 { + match self { + XspiWidth::NONE => 0b00, + XspiWidth::SING => 0b01, + XspiWidth::DUAL => 0b10, + XspiWidth::QUAD => 0b11, + XspiWidth::OCTO => 0b100, + } + } +} + +/// Flash bank selection +#[allow(dead_code)] +#[derive(Copy, Clone)] +pub enum FlashSelection { + /// Bank 1 + Flash1, + /// Bank 2 + Flash2, +} + +impl Into for FlashSelection { + fn into(self) -> bool { + match self { + FlashSelection::Flash1 => false, + FlashSelection::Flash2 => true, + } + } +} + +/// Wrap Size +#[allow(dead_code)] +#[allow(missing_docs)] +#[derive(Copy, Clone)] +pub enum WrapSize { + None, + _16Bytes, + _32Bytes, + _64Bytes, + _128Bytes, +} + +impl Into for WrapSize { + fn into(self) -> u8 { + match self { + WrapSize::None => 0x00, + WrapSize::_16Bytes => 0x02, + WrapSize::_32Bytes => 0x03, + WrapSize::_64Bytes => 0x04, + WrapSize::_128Bytes => 0x05, + } + } +} + +/// Memory Type +#[allow(missing_docs)] +#[allow(dead_code)] +#[derive(Copy, Clone)] +pub enum MemoryType { + Micron, + Macronix, + Standard, + MacronixRam, + HyperBusMemory, + HyperBusRegister, +} + +impl Into for MemoryType { + fn into(self) -> u8 { + match self { + MemoryType::Micron => 0x00, + MemoryType::Macronix => 0x01, + MemoryType::Standard => 0x02, + MemoryType::MacronixRam => 0x03, + MemoryType::HyperBusMemory => 0x04, + MemoryType::HyperBusRegister => 0x04, + } + } +} + +/// Xspi memory size. +#[allow(missing_docs)] +#[derive(Copy, Clone)] +pub enum MemorySize { + _1KiB, + _2KiB, + _4KiB, + _8KiB, + _16KiB, + _32KiB, + _64KiB, + _128KiB, + _256KiB, + _512KiB, + _1MiB, + _2MiB, + _4MiB, + _8MiB, + _16MiB, + _32MiB, + _64MiB, + _128MiB, + _256MiB, + _512MiB, + _1GiB, + _2GiB, + _4GiB, + Other(u8), +} + +impl Into for MemorySize { + fn into(self) -> u8 { + match self { + MemorySize::_1KiB => 9, + MemorySize::_2KiB => 10, + MemorySize::_4KiB => 11, + MemorySize::_8KiB => 12, + MemorySize::_16KiB => 13, + MemorySize::_32KiB => 14, + MemorySize::_64KiB => 15, + MemorySize::_128KiB => 16, + MemorySize::_256KiB => 17, + MemorySize::_512KiB => 18, + MemorySize::_1MiB => 19, + MemorySize::_2MiB => 20, + MemorySize::_4MiB => 21, + MemorySize::_8MiB => 22, + MemorySize::_16MiB => 23, + MemorySize::_32MiB => 24, + MemorySize::_64MiB => 25, + MemorySize::_128MiB => 26, + MemorySize::_256MiB => 27, + MemorySize::_512MiB => 28, + MemorySize::_1GiB => 29, + MemorySize::_2GiB => 30, + MemorySize::_4GiB => 31, + MemorySize::Other(val) => val, + } + } +} + +/// Xspi Address size +#[derive(Copy, Clone)] +pub enum AddressSize { + /// 8-bit address + _8Bit, + /// 16-bit address + _16Bit, + /// 24-bit address + _24bit, + /// 32-bit address + _32bit, +} + +impl Into for AddressSize { + fn into(self) -> u8 { + match self { + AddressSize::_8Bit => 0b00, + AddressSize::_16Bit => 0b01, + AddressSize::_24bit => 0b10, + AddressSize::_32bit => 0b11, + } + } +} + +/// Time the Chip Select line stays high. +#[allow(missing_docs)] +#[derive(Copy, Clone)] +pub enum ChipSelectHighTime { + _1Cycle, + _2Cycle, + _3Cycle, + _4Cycle, + _5Cycle, + _6Cycle, + _7Cycle, + _8Cycle, +} + +impl Into for ChipSelectHighTime { + fn into(self) -> u8 { + match self { + ChipSelectHighTime::_1Cycle => 0, + ChipSelectHighTime::_2Cycle => 1, + ChipSelectHighTime::_3Cycle => 2, + ChipSelectHighTime::_4Cycle => 3, + ChipSelectHighTime::_5Cycle => 4, + ChipSelectHighTime::_6Cycle => 5, + ChipSelectHighTime::_7Cycle => 6, + ChipSelectHighTime::_8Cycle => 7, + } + } +} + +/// FIFO threshold. +#[allow(missing_docs)] +#[derive(Copy, Clone)] +pub enum FIFOThresholdLevel { + _1Bytes, + _2Bytes, + _3Bytes, + _4Bytes, + _5Bytes, + _6Bytes, + _7Bytes, + _8Bytes, + _9Bytes, + _10Bytes, + _11Bytes, + _12Bytes, + _13Bytes, + _14Bytes, + _15Bytes, + _16Bytes, + _17Bytes, + _18Bytes, + _19Bytes, + _20Bytes, + _21Bytes, + _22Bytes, + _23Bytes, + _24Bytes, + _25Bytes, + _26Bytes, + _27Bytes, + _28Bytes, + _29Bytes, + _30Bytes, + _31Bytes, + _32Bytes, +} + +impl Into for FIFOThresholdLevel { + fn into(self) -> u8 { + match self { + FIFOThresholdLevel::_1Bytes => 0, + FIFOThresholdLevel::_2Bytes => 1, + FIFOThresholdLevel::_3Bytes => 2, + FIFOThresholdLevel::_4Bytes => 3, + FIFOThresholdLevel::_5Bytes => 4, + FIFOThresholdLevel::_6Bytes => 5, + FIFOThresholdLevel::_7Bytes => 6, + FIFOThresholdLevel::_8Bytes => 7, + FIFOThresholdLevel::_9Bytes => 8, + FIFOThresholdLevel::_10Bytes => 9, + FIFOThresholdLevel::_11Bytes => 10, + FIFOThresholdLevel::_12Bytes => 11, + FIFOThresholdLevel::_13Bytes => 12, + FIFOThresholdLevel::_14Bytes => 13, + FIFOThresholdLevel::_15Bytes => 14, + FIFOThresholdLevel::_16Bytes => 15, + FIFOThresholdLevel::_17Bytes => 16, + FIFOThresholdLevel::_18Bytes => 17, + FIFOThresholdLevel::_19Bytes => 18, + FIFOThresholdLevel::_20Bytes => 19, + FIFOThresholdLevel::_21Bytes => 20, + FIFOThresholdLevel::_22Bytes => 21, + FIFOThresholdLevel::_23Bytes => 22, + FIFOThresholdLevel::_24Bytes => 23, + FIFOThresholdLevel::_25Bytes => 24, + FIFOThresholdLevel::_26Bytes => 25, + FIFOThresholdLevel::_27Bytes => 26, + FIFOThresholdLevel::_28Bytes => 27, + FIFOThresholdLevel::_29Bytes => 28, + FIFOThresholdLevel::_30Bytes => 29, + FIFOThresholdLevel::_31Bytes => 30, + FIFOThresholdLevel::_32Bytes => 31, + } + } +} + +/// Dummy cycle count +#[allow(missing_docs)] +#[derive(Copy, Clone)] +pub enum DummyCycles { + _0, + _1, + _2, + _3, + _4, + _5, + _6, + _7, + _8, + _9, + _10, + _11, + _12, + _13, + _14, + _15, + _16, + _17, + _18, + _19, + _20, + _21, + _22, + _23, + _24, + _25, + _26, + _27, + _28, + _29, + _30, + _31, +} + +impl Into for DummyCycles { + fn into(self) -> u8 { + match self { + DummyCycles::_0 => 0, + DummyCycles::_1 => 1, + DummyCycles::_2 => 2, + DummyCycles::_3 => 3, + DummyCycles::_4 => 4, + DummyCycles::_5 => 5, + DummyCycles::_6 => 6, + DummyCycles::_7 => 7, + DummyCycles::_8 => 8, + DummyCycles::_9 => 9, + DummyCycles::_10 => 10, + DummyCycles::_11 => 11, + DummyCycles::_12 => 12, + DummyCycles::_13 => 13, + DummyCycles::_14 => 14, + DummyCycles::_15 => 15, + DummyCycles::_16 => 16, + DummyCycles::_17 => 17, + DummyCycles::_18 => 18, + DummyCycles::_19 => 19, + DummyCycles::_20 => 20, + DummyCycles::_21 => 21, + DummyCycles::_22 => 22, + DummyCycles::_23 => 23, + DummyCycles::_24 => 24, + DummyCycles::_25 => 25, + DummyCycles::_26 => 26, + DummyCycles::_27 => 27, + DummyCycles::_28 => 28, + DummyCycles::_29 => 29, + DummyCycles::_30 => 30, + DummyCycles::_31 => 31, + } + } +} diff --git a/embassy-stm32/src/xspi/mod.rs b/embassy-stm32/src/xspi/mod.rs new file mode 100644 index 000000000..b2fdebe75 --- /dev/null +++ b/embassy-stm32/src/xspi/mod.rs @@ -0,0 +1,1427 @@ +//! XSPI Serial Peripheral Interface +//! + +#![macro_use] + +pub mod enums; + +use core::marker::PhantomData; + +use embassy_embedded_hal::{GetConfig, SetConfig}; +use embassy_hal_internal::{into_ref, PeripheralRef}; +pub use enums::*; + +use crate::dma::{word, ChannelAndRequest}; +use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed}; +use crate::mode::{Async, Blocking, Mode as PeriMode}; +use crate::pac::xspi::{vals::*, Xspi as Regs}; +#[cfg(xspim_v2_1)] +use crate::pac::xspim::Xspim; +use crate::rcc::{self, RccPeripheral}; +use crate::{peripherals, Peripheral}; + +/// XPSI driver config. +#[derive(Clone, Copy)] +pub struct Config { + /// Fifo threshold used by the peripheral to generate the interrupt indicating data + /// or space is available in the FIFO + pub fifo_threshold: FIFOThresholdLevel, + /// Indicates the type of external device connected + pub memory_type: MemoryType, // Need to add an additional enum to provide this public interface + /// Defines the size of the external device connected to the XSPI corresponding + /// to the number of address bits required to access the device + pub device_size: MemorySize, + /// Sets the minimum number of clock cycles that the chip select signal must be held high + /// between commands + pub chip_select_high_time: ChipSelectHighTime, + /// Enables the free running clock + pub free_running_clock: bool, + /// Sets the clock level when the device is not selected + pub clock_mode: bool, + /// Indicates the wrap size corresponding to the external device configuration + pub wrap_size: WrapSize, + /// Specified the prescaler factor used for generating the external clock based + /// on the AHB clock + pub clock_prescaler: u8, + /// Allows the delay of 1/2 cycle the data sampling to account for external + /// signal delays + pub sample_shifting: bool, + /// Allows hold to 1/4 cycle the data + pub delay_hold_quarter_cycle: bool, + /// Enables the transaction boundary feature and defines the boundary to release + /// the chip select + pub chip_select_boundary: u8, + /// Enables communication regulation feature. Chip select is released when the other + /// XSpi requests access to the bus + pub max_transfer: u8, + /// Enables the refresh feature, chip select is released every refresh + 1 clock cycles + pub refresh: u32, +} + +impl Default for Config { + fn default() -> Self { + Self { + fifo_threshold: FIFOThresholdLevel::_16Bytes, // 32 bytes FIFO, half capacity + memory_type: MemoryType::Micron, + device_size: MemorySize::Other(0), + chip_select_high_time: ChipSelectHighTime::_5Cycle, + free_running_clock: false, + clock_mode: false, + wrap_size: WrapSize::None, + clock_prescaler: 0, + sample_shifting: false, + delay_hold_quarter_cycle: false, + chip_select_boundary: 0, // Acceptable range 0 to 31 + max_transfer: 0, + refresh: 0, + } + } +} + +/// XSPI transfer configuration. +pub struct TransferConfig { + /// Instruction width (IMODE) + pub iwidth: XspiWidth, + /// Instruction Id + pub instruction: Option, + /// Number of Instruction Bytes + pub isize: AddressSize, + /// Instruction Double Transfer rate enable + pub idtr: bool, + + /// Address width (ADMODE) + pub adwidth: XspiWidth, + /// Device memory address + pub address: Option, + /// Number of Address Bytes + pub adsize: AddressSize, + /// Address Double Transfer rate enable + pub addtr: bool, + + /// Alternate bytes width (ABMODE) + pub abwidth: XspiWidth, + /// Alternate Bytes + pub alternate_bytes: Option, + /// Number of Alternate Bytes + pub absize: AddressSize, + /// Alternate Bytes Double Transfer rate enable + pub abdtr: bool, + + /// Data width (DMODE) + pub dwidth: XspiWidth, + /// Data buffer + pub ddtr: bool, + + /// Number of dummy cycles (DCYC) + pub dummy: DummyCycles, +} + +impl Default for TransferConfig { + fn default() -> Self { + Self { + iwidth: XspiWidth::NONE, + instruction: None, + isize: AddressSize::_8Bit, + idtr: false, + + adwidth: XspiWidth::NONE, + address: None, + adsize: AddressSize::_8Bit, + addtr: false, + + abwidth: XspiWidth::NONE, + alternate_bytes: None, + absize: AddressSize::_8Bit, + abdtr: false, + + dwidth: XspiWidth::NONE, + ddtr: false, + + dummy: DummyCycles::_0, + } + } +} + +/// Error used for Xspi implementation +#[derive(Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum XspiError { + /// Peripheral configuration is invalid + InvalidConfiguration, + /// Operation configuration is invalid + InvalidCommand, + /// Size zero buffer passed to instruction + EmptyBuffer, +} + +/// XSPI driver. +pub struct Xspi<'d, T: Instance, M: PeriMode> { + _peri: PeripheralRef<'d, T>, + clk: Option>, + d0: Option>, + d1: Option>, + d2: Option>, + d3: Option>, + d4: Option>, + d5: Option>, + d6: Option>, + d7: Option>, + d8: Option>, + d9: Option>, + d10: Option>, + d11: Option>, + d12: Option>, + d13: Option>, + d14: Option>, + d15: Option>, + ncs1: Option>, + ncs2: Option>, + dqs0: Option>, + dqs1: Option>, + dma: Option>, + _phantom: PhantomData, + config: Config, + width: XspiWidth, +} + +impl<'d, T: Instance, M: PeriMode> Xspi<'d, T, M> { + /// Enter memory mode. + /// The Input `read_config` is used to configure the read operation in memory mode + pub fn enable_memory_mapped_mode( + &mut self, + read_config: TransferConfig, + write_config: TransferConfig, + ) -> Result<(), XspiError> { + // Use configure command to set read config + self.configure_command(&read_config, None)?; + + let reg = T::REGS; + while reg.xspi_sr().read().busy() {} + + reg.xspi_ccr().modify(|r| { + r.set_dqse(XspiCcrDqse::B_0X0); + }); + + // Set wrting configurations, there are separate registers for write configurations in memory mapped mode + reg.xspi_wccr().modify(|w| { + w.set_imode(XspiWccrImode::from_bits(write_config.iwidth.into())); + let idtr = match write_config.idtr { + true => XspiWccrIdtr::B_0X1, + false => XspiWccrIdtr::B_0X0, + }; + w.set_idtr(idtr); + w.set_isize(XspiWccrIsize::from_bits(write_config.isize.into())); + + w.set_admode(XspiWccrAdmode::from_bits(write_config.adwidth.into())); + let addtr = match write_config.idtr { + true => XspiWccrAddtr::B_0X1, + false => XspiWccrAddtr::B_0X0, + }; + w.set_addtr(addtr); + w.set_adsize(XspiWccrAdsize::from_bits(write_config.adsize.into())); + + w.set_dmode(XspiWccrDmode::from_bits(write_config.dwidth.into())); + let ddtr = match write_config.idtr { + true => XspiWccrDdtr::B_0X1, + false => XspiWccrDdtr::B_0X0, + }; + w.set_ddtr(ddtr); + + w.set_abmode(XspiWccrAbmode::from_bits(write_config.abwidth.into())); + w.set_dqse(XspiWccrDqse::B_0X1); + }); + + reg.xspi_wtcr().modify(|w| w.set_dcyc(write_config.dummy.into())); + + // Enable memory mapped mode + reg.xspi_cr().modify(|r| { + r.set_fmode(Fmode::B_0X3); + r.set_tcen(Tcen::B_0X0); + }); + Ok(()) + } + + /// Quit from memory mapped mode + pub fn disable_memory_mapped_mode(&mut self) { + let reg = T::REGS; + + reg.xspi_cr().modify(|r| { + r.set_fmode(Fmode::B_0X0); + r.set_abort(Abort::B_0X1); + r.set_dmaen(Dmaen::B_0X0); + r.set_en(En::B_0X0); + }); + + // Clear transfer complete flag + reg.xspi_fcr().write(|w| w.set_ctcf(true)); + + // Re-enable ospi + reg.xspi_cr().modify(|r| { + r.set_en(En::B_0X1); + }); + } + + fn new_inner( + peri: impl Peripheral

+ 'd, + d0: Option>, + d1: Option>, + d2: Option>, + d3: Option>, + d4: Option>, + d5: Option>, + d6: Option>, + d7: Option>, + d8: Option>, + d9: Option>, + d10: Option>, + d11: Option>, + d12: Option>, + d13: Option>, + d14: Option>, + d15: Option>, + clk: Option>, + ncs1: Option>, + ncs2: Option>, + dqs0: Option>, + dqs1: Option>, + dma: Option>, + config: Config, + width: XspiWidth, + dual_quad: bool, + ) -> Self { + into_ref!(peri); + + #[cfg(xspim_v2_1)] + { + // RCC for xspim should be enabled before writing register + crate::pac::RCC.ahb5enr().modify(|w| w.set_iomngren(true)); + + // Disable XSPI peripheral first + T::REGS.xspi_cr().modify(|w| { + w.set_en(En::B_0X0); + }); + + // XSPI IO Manager has been enabled before + T::SPIM_REGS.xspim_cr().modify(|w| { + w.set_muxen(false); + w.set_req2ack_time(0xff); + }); + } + + // System configuration + rcc::enable_and_reset::(); + while T::REGS.xspi_sr().read().busy() {} + + // Device configuration + T::REGS.xspi_dcr1().modify(|w| { + w.set_devsize(config.device_size.into()); + w.set_mtyp(Mtyp::from_bits(config.memory_type.into())); + w.set_csht(Csht::from_bits(config.chip_select_high_time.into())); + w.set_frck(Frck::B_0X0); + w.set_ckmode(Ckmode::from_bits(config.clock_mode.into())); + }); + + T::REGS.xspi_dcr2().modify(|w| { + w.set_wrapsize(Wrapsize::from_bits(config.wrap_size.into())); + }); + + T::REGS.xspi_dcr3().modify(|w| { + w.set_csbound(Csbound::from_bits(config.chip_select_boundary.into())); + #[cfg(xspi_v2_1)] + { + w.set_maxtran(Maxtran::from_bits(config.max_transfer.into())); + } + }); + + T::REGS.xspi_dcr4().modify(|w| { + w.set_refresh(Refresh::from_bits(config.refresh.into())); + }); + + T::REGS.xspi_cr().modify(|w| { + w.set_fthres(Fthres::from_bits(config.fifo_threshold.into())); + }); + + // Wait for busy flag to clear + while T::REGS.xspi_sr().read().busy() {} + + T::REGS.xspi_dcr2().modify(|w| { + w.set_prescaler(Prescaler::from_bits(config.clock_prescaler.into())); + }); + + T::REGS.xspi_cr().modify(|w| { + w.set_dmm(match dual_quad { + true => Dmm::B_0X1, + false => Dmm::B_0X0, + }); + }); + + T::REGS.xspi_tcr().modify(|w| { + w.set_sshift(match config.sample_shifting { + true => XspiTcrSshift::B_0X1, + false => XspiTcrSshift::B_0X0, + }); + w.set_dhqc(match config.delay_hold_quarter_cycle { + true => XspiTcrDhqc::B_0X1, + false => XspiTcrDhqc::B_0X0, + }); + }); + + // Enable peripheral + T::REGS.xspi_cr().modify(|w| { + w.set_en(En::B_0X1); + }); + + // Free running clock needs to be set after peripheral enable + if config.free_running_clock { + T::REGS.xspi_dcr1().modify(|w| { + w.set_frck(match config.free_running_clock { + true => Frck::B_0X1, + false => Frck::B_0X0, + }); + }); + } + + Self { + _peri: peri, + clk, + d0, + d1, + d2, + d3, + d4, + d5, + d6, + d7, + d8, + d9, + d10, + d11, + d12, + d13, + d14, + d15, + ncs1, + ncs2, + dqs0, + dqs1, + dma, + _phantom: PhantomData, + config, + width, + } + } + + // Function to configure the peripheral for the requested command + fn configure_command(&mut self, command: &TransferConfig, data_len: Option) -> Result<(), XspiError> { + // Check that transaction doesn't use more than hardware initialized pins + if >::into(command.iwidth) > >::into(self.width) + || >::into(command.adwidth) > >::into(self.width) + || >::into(command.abwidth) > >::into(self.width) + || >::into(command.dwidth) > >::into(self.width) + { + return Err(XspiError::InvalidCommand); + } + + T::REGS.xspi_cr().modify(|w| { + w.set_fmode(0.into()); + }); + + // Configure alternate bytes + if let Some(ab) = command.alternate_bytes { + T::REGS.xspi_abr().write(|v| v.set_alternate(ab)); + T::REGS.xspi_ccr().modify(|w| { + w.set_abmode(XspiCcrAbmode::from_bits(command.abwidth.into())); + w.set_abdtr(XspiCcrAbdtr::from_bits(command.abdtr.into())); + w.set_absize(XspiCcrAbsize::from_bits(command.absize.into())); + }) + } + + // Configure dummy cycles + T::REGS.xspi_tcr().modify(|w| { + w.set_dcyc(command.dummy.into()); + }); + + // Configure data + if let Some(data_length) = data_len { + T::REGS.xspi_dlr().write(|v| { + v.set_dl((data_length - 1) as u32); + }) + } else { + T::REGS.xspi_dlr().write(|v| { + v.set_dl((0) as u32); + }) + } + + // Configure instruction/address/data modes + T::REGS.xspi_ccr().modify(|w| { + w.set_imode(XspiCcrImode::from_bits(command.iwidth.into())); + w.set_idtr(match command.idtr { + true => XspiCcrIdtr::B_0X1, + false => XspiCcrIdtr::B_0X0, + }); + w.set_isize(XspiCcrIsize::from_bits(command.isize.into())); + + w.set_admode(XspiCcrAdmode::from_bits(command.adwidth.into())); + w.set_addtr(match command.idtr { + true => XspiCcrAddtr::B_0X1, + false => XspiCcrAddtr::B_0X0, + }); + w.set_adsize(XspiCcrAdsize::from_bits(command.adsize.into())); + + w.set_dmode(XspiCcrDmode::from_bits(command.dwidth.into())); + w.set_ddtr(match command.ddtr { + true => XspiCcrDdtr::B_0X1, + false => XspiCcrDdtr::B_0X0, + }); + }); + + // Set information required to initiate transaction + if let Some(instruction) = command.instruction { + if let Some(address) = command.address { + T::REGS.xspi_ir().write(|v| { + v.set_instruction(instruction); + }); + + T::REGS.xspi_ar().write(|v| { + v.set_address(address); + }); + } else { + // Double check requirements for delay hold and sample shifting + // if let None = command.data_len { + // if self.config.delay_hold_quarter_cycle && command.idtr { + // T::REGS.xspi_ccr().modify(|w| { + // w.set_ddtr(true); + // }); + // } + // } + + warn!("instruction: {:#x}", instruction); + T::REGS.xspi_ir().write(|v| { + v.set_instruction(instruction); + }); + } + } else { + if let Some(address) = command.address { + T::REGS.xspi_ar().write(|v| { + v.set_address(address); + }); + } else { + // The only single phase transaction supported is instruction only + return Err(XspiError::InvalidCommand); + } + } + + Ok(()) + } + + /// Function used to control or configure the target device without data transfer + pub fn blocking_command(&mut self, command: &TransferConfig) -> Result<(), XspiError> { + // Wait for peripheral to be free + while T::REGS.xspi_sr().read().busy() {} + + // Need additional validation that command configuration doesn't have data set + self.configure_command(command, None)?; + + // Transaction initiated by setting final configuration, i.e the instruction register + while !T::REGS.xspi_sr().read().tcf() {} + T::REGS.xspi_fcr().write(|w| { + w.set_ctcf(true); + }); + + Ok(()) + } + + /// Blocking read with byte by byte data transfer + pub fn blocking_read(&mut self, buf: &mut [W], transaction: TransferConfig) -> Result<(), XspiError> { + if buf.is_empty() { + return Err(XspiError::EmptyBuffer); + } + + // Wait for peripheral to be free + while T::REGS.xspi_sr().read().busy() {} + + // Ensure DMA is not enabled for this transaction + T::REGS.xspi_cr().modify(|w| { + w.set_dmaen(Dmaen::B_0X0); + }); + + // self.configure_command(&transaction, Some(buf.len()))?; + self.configure_command(&transaction, Some(buf.len())).unwrap(); + + let current_address = T::REGS.xspi_ar().read().address(); + let current_instruction = T::REGS.xspi_ir().read().instruction(); + + // For a indirect read transaction, the transaction begins when the instruction/address is set + T::REGS + .xspi_cr() + .modify(|v| v.set_fmode(Fmode::from_bits(XspiMode::IndirectRead.into()))); + if T::REGS.xspi_ccr().read().admode() == XspiCcrAdmode::B_0X0 { + T::REGS.xspi_ir().write(|v| v.set_instruction(current_instruction)); + } else { + T::REGS.xspi_ar().write(|v| v.set_address(current_address)); + } + + for idx in 0..buf.len() { + while !T::REGS.xspi_sr().read().tcf() && !T::REGS.xspi_sr().read().ftf() {} + buf[idx] = unsafe { (T::REGS.xspi_dr().as_ptr() as *mut W).read_volatile() }; + } + + while !T::REGS.xspi_sr().read().tcf() {} + T::REGS.xspi_fcr().write(|v| v.set_ctcf(true)); + + Ok(()) + } + + /// Blocking write with byte by byte data transfer + pub fn blocking_write(&mut self, buf: &[W], transaction: TransferConfig) -> Result<(), XspiError> { + if buf.is_empty() { + return Err(XspiError::EmptyBuffer); + } + + // Wait for peripheral to be free + while T::REGS.xspi_sr().read().busy() {} + + T::REGS.xspi_cr().modify(|w| { + w.set_dmaen(Dmaen::B_0X0); + }); + + self.configure_command(&transaction, Some(buf.len()))?; + + T::REGS + .xspi_cr() + .modify(|v| v.set_fmode(Fmode::from_bits(XspiMode::IndirectWrite.into()))); + + for idx in 0..buf.len() { + while !T::REGS.xspi_sr().read().ftf() {} + unsafe { (T::REGS.xspi_dr().as_ptr() as *mut W).write_volatile(buf[idx]) }; + } + + while !T::REGS.xspi_sr().read().tcf() {} + T::REGS.xspi_fcr().write(|v| v.set_ctcf(true)); + + Ok(()) + } + + /// Set new bus configuration + pub fn set_config(&mut self, config: &Config) { + // Wait for busy flag to clear + while T::REGS.xspi_sr().read().busy() {} + + // Disable DMA channel while configuring the peripheral + T::REGS.xspi_cr().modify(|w| { + w.set_dmaen(Dmaen::B_0X0); + }); + + // Device configuration + T::REGS.xspi_dcr1().modify(|w| { + w.set_devsize(config.device_size.into()); + w.set_mtyp(Mtyp::from_bits(config.memory_type.into())); + w.set_csht(Csht::from_bits(config.chip_select_high_time.into())); + w.set_frck(Frck::B_0X0); + w.set_ckmode(match config.clock_mode { + true => Ckmode::B_0X1, + false => Ckmode::B_0X0, + }); + }); + + T::REGS.xspi_dcr2().modify(|w| { + w.set_wrapsize(Wrapsize::from_bits(config.wrap_size.into())); + }); + + T::REGS.xspi_dcr3().modify(|w| { + w.set_csbound(Csbound::from_bits(config.chip_select_boundary.into())); + #[cfg(xspi_v2_1)] + { + w.set_maxtran(Maxtran::from_bits(config.max_transfer.into())); + } + }); + + T::REGS.xspi_dcr4().modify(|w| { + w.set_refresh(Refresh::from_bits(config.refresh.into())); + }); + + T::REGS.xspi_cr().modify(|w| { + w.set_fthres(Fthres::from_bits(config.fifo_threshold.into())); + }); + + // Wait for busy flag to clear + while T::REGS.xspi_sr().read().busy() {} + + T::REGS.xspi_dcr2().modify(|w| { + w.set_prescaler(Prescaler::from_bits(config.clock_prescaler.into())); + }); + + T::REGS.xspi_tcr().modify(|w| { + w.set_sshift(match config.sample_shifting { + true => XspiTcrSshift::B_0X1, + false => XspiTcrSshift::B_0X0, + }); + w.set_dhqc(match config.delay_hold_quarter_cycle { + true => XspiTcrDhqc::B_0X1, + false => XspiTcrDhqc::B_0X0, + }); + }); + + // Enable peripheral + T::REGS.xspi_cr().modify(|w| { + w.set_en(En::B_0X1); + }); + + // Free running clock needs to be set after peripheral enable + if config.free_running_clock { + T::REGS.xspi_dcr1().modify(|w| { + w.set_frck(match config.free_running_clock { + true => Frck::B_0X1, + false => Frck::B_0X0, + }); + }); + } + + self.config = *config; + } + + /// Get current configuration + pub fn get_config(&self) -> Config { + self.config + } +} + +impl<'d, T: Instance> Xspi<'d, T, Blocking> { + /// Create new blocking XSPI driver for a single spi external chip + pub fn new_blocking_singlespi( + peri: impl Peripheral

+ 'd, + clk: impl Peripheral

> + 'd, + d0: impl Peripheral

> + 'd, + d1: impl Peripheral

> + 'd, + ncs: impl Peripheral

> + 'd, + config: Config, + ) -> Self { + Self::new_inner( + peri, + new_pin!(d0, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + new_pin!(d1, AfType::input(Pull::None)), + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + new_pin!(clk, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + new_pin!(ncs, AfType::output(OutputType::OpenDrain, Speed::VeryHigh)), + None, + None, + None, + None, + config, + XspiWidth::SING, + false, + ) + } + + /// Create new blocking XSPI driver for a dualspi external chip + pub fn new_blocking_dualspi( + peri: impl Peripheral

+ 'd, + clk: impl Peripheral

> + 'd, + d0: impl Peripheral

> + 'd, + d1: impl Peripheral

> + 'd, + ncs: impl Peripheral

> + 'd, + config: Config, + ) -> Self { + Self::new_inner( + peri, + new_pin!(d0, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + new_pin!(d1, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + new_pin!(clk, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + new_pin!( + ncs, + AfType::output_pull(OutputType::PushPull, Speed::VeryHigh, Pull::Up) + ), + None, + None, + None, + None, + config, + XspiWidth::DUAL, + false, + ) + } + + /// Create new blocking XSPI driver for a quadspi external chip + pub fn new_blocking_quadspi( + peri: impl Peripheral

+ 'd, + clk: impl Peripheral

> + 'd, + d0: impl Peripheral

> + 'd, + d1: impl Peripheral

> + 'd, + d2: impl Peripheral

> + 'd, + d3: impl Peripheral

> + 'd, + ncs: impl Peripheral

> + 'd, + config: Config, + ) -> Self { + Self::new_inner( + peri, + new_pin!(d0, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + new_pin!(d1, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + new_pin!(d2, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + new_pin!(d3, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + new_pin!(clk, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + new_pin!( + ncs, + AfType::output_pull(OutputType::PushPull, Speed::VeryHigh, Pull::Up) + ), + None, + None, + None, + None, + config, + XspiWidth::QUAD, + false, + ) + } + + /// Create new blocking XSPI driver for two quadspi external chips + pub fn new_blocking_dualquadspi( + peri: impl Peripheral

+ 'd, + clk: impl Peripheral

> + 'd, + d0: impl Peripheral

> + 'd, + d1: impl Peripheral

> + 'd, + d2: impl Peripheral

> + 'd, + d3: impl Peripheral

> + 'd, + d4: impl Peripheral

> + 'd, + d5: impl Peripheral

> + 'd, + d6: impl Peripheral

> + 'd, + d7: impl Peripheral

> + 'd, + ncs: impl Peripheral

> + 'd, + config: Config, + ) -> Self { + Self::new_inner( + peri, + new_pin!(d0, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + new_pin!(d1, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + new_pin!(d2, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + new_pin!(d3, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + new_pin!(d4, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + new_pin!(d5, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + new_pin!(d6, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + new_pin!(d7, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + None, + None, + None, + None, + None, + None, + None, + None, + new_pin!(clk, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + new_pin!( + ncs, + AfType::output_pull(OutputType::PushPull, Speed::VeryHigh, Pull::Up) + ), + None, + None, + None, + None, + config, + XspiWidth::QUAD, + true, + ) + } + + /// Create new blocking XSPI driver for xspi external chips + pub fn new_blocking_xspi( + peri: impl Peripheral

+ 'd, + clk: impl Peripheral

> + 'd, + d0: impl Peripheral

> + 'd, + d1: impl Peripheral

> + 'd, + d2: impl Peripheral

> + 'd, + d3: impl Peripheral

> + 'd, + d4: impl Peripheral

> + 'd, + d5: impl Peripheral

> + 'd, + d6: impl Peripheral

> + 'd, + d7: impl Peripheral

> + 'd, + ncs: impl Peripheral

> + 'd, + config: Config, + ) -> Self { + Self::new_inner( + peri, + new_pin!(d0, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + new_pin!(d1, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + new_pin!(d2, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + new_pin!(d3, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + new_pin!(d4, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + new_pin!(d5, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + new_pin!(d6, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + new_pin!(d7, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + None, + None, + None, + None, + None, + None, + None, + None, + new_pin!(clk, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + new_pin!( + ncs, + AfType::output_pull(OutputType::PushPull, Speed::VeryHigh, Pull::Up) + ), + None, + None, + None, + None, + config, + XspiWidth::OCTO, + false, + ) + } +} + +impl<'d, T: Instance> Xspi<'d, T, Async> { + /// Create new blocking XSPI driver for a single spi external chip + pub fn new_singlespi( + peri: impl Peripheral

+ 'd, + clk: impl Peripheral

> + 'd, + d0: impl Peripheral

> + 'd, + d1: impl Peripheral

> + 'd, + ncs: impl Peripheral

> + 'd, + dma: impl Peripheral

> + 'd, + config: Config, + ) -> Self { + Self::new_inner( + peri, + new_pin!(d0, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + new_pin!(d1, AfType::input(Pull::None)), + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + new_pin!(clk, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + new_pin!(ncs, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + None, + None, + None, + new_dma!(dma), + config, + XspiWidth::SING, + false, + ) + } + + /// Create new blocking XSPI driver for a dualspi external chip + pub fn new_dualspi( + peri: impl Peripheral

+ 'd, + clk: impl Peripheral

> + 'd, + d0: impl Peripheral

> + 'd, + d1: impl Peripheral

> + 'd, + ncs: impl Peripheral

> + 'd, + dma: impl Peripheral

> + 'd, + config: Config, + ) -> Self { + Self::new_inner( + peri, + new_pin!(d0, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + new_pin!(d1, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + new_pin!(clk, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + new_pin!( + ncs, + AfType::output_pull(OutputType::PushPull, Speed::VeryHigh, Pull::Up) + ), + None, + None, + None, + new_dma!(dma), + config, + XspiWidth::DUAL, + false, + ) + } + + /// Create new blocking XSPI driver for a quadspi external chip + pub fn new_quadspi( + peri: impl Peripheral

+ 'd, + clk: impl Peripheral

> + 'd, + d0: impl Peripheral

> + 'd, + d1: impl Peripheral

> + 'd, + d2: impl Peripheral

> + 'd, + d3: impl Peripheral

> + 'd, + ncs: impl Peripheral

> + 'd, + dma: impl Peripheral

> + 'd, + config: Config, + ) -> Self { + Self::new_inner( + peri, + new_pin!(d0, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + new_pin!(d1, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + new_pin!(d2, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + new_pin!(d3, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + new_pin!(clk, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + new_pin!( + ncs, + AfType::output_pull(OutputType::PushPull, Speed::VeryHigh, Pull::Up) + ), + None, + None, + None, + new_dma!(dma), + config, + XspiWidth::QUAD, + false, + ) + } + + /// Create new blocking XSPI driver for two quadspi external chips + pub fn new_dualquadspi( + peri: impl Peripheral

+ 'd, + clk: impl Peripheral

> + 'd, + d0: impl Peripheral

> + 'd, + d1: impl Peripheral

> + 'd, + d2: impl Peripheral

> + 'd, + d3: impl Peripheral

> + 'd, + d4: impl Peripheral

> + 'd, + d5: impl Peripheral

> + 'd, + d6: impl Peripheral

> + 'd, + d7: impl Peripheral

> + 'd, + ncs: impl Peripheral

> + 'd, + dma: impl Peripheral

> + 'd, + config: Config, + ) -> Self { + Self::new_inner( + peri, + new_pin!(d0, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + new_pin!(d1, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + new_pin!(d2, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + new_pin!(d3, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + new_pin!(d4, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + new_pin!(d5, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + new_pin!(d6, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + new_pin!(d7, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + None, + None, + None, + None, + None, + None, + None, + None, + new_pin!(clk, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + new_pin!( + ncs, + AfType::output_pull(OutputType::PushPull, Speed::VeryHigh, Pull::Up) + ), + None, + None, + None, + new_dma!(dma), + config, + XspiWidth::QUAD, + true, + ) + } + + /// Create new blocking XSPI driver for xspi external chips + pub fn new_xspi( + peri: impl Peripheral

+ 'd, + clk: impl Peripheral

> + 'd, + d0: impl Peripheral

> + 'd, + d1: impl Peripheral

> + 'd, + d2: impl Peripheral

> + 'd, + d3: impl Peripheral

> + 'd, + d4: impl Peripheral

> + 'd, + d5: impl Peripheral

> + 'd, + d6: impl Peripheral

> + 'd, + d7: impl Peripheral

> + 'd, + ncs: impl Peripheral

> + 'd, + dma: impl Peripheral

> + 'd, + config: Config, + ) -> Self { + Self::new_inner( + peri, + new_pin!(d0, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + new_pin!(d1, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + new_pin!(d2, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + new_pin!(d3, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + new_pin!(d4, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + new_pin!(d5, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + new_pin!(d6, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + new_pin!(d7, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + None, + None, + None, + None, + None, + None, + None, + None, + new_pin!(clk, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + new_pin!( + ncs, + AfType::output_pull(OutputType::PushPull, Speed::VeryHigh, Pull::Up) + ), + None, + None, + None, + new_dma!(dma), + config, + XspiWidth::OCTO, + false, + ) + } + + /// Blocking read with DMA transfer + pub fn blocking_read_dma(&mut self, buf: &mut [W], transaction: TransferConfig) -> Result<(), XspiError> { + if buf.is_empty() { + return Err(XspiError::EmptyBuffer); + } + + // Wait for peripheral to be free + while T::REGS.xspi_sr().read().busy() {} + + self.configure_command(&transaction, Some(buf.len()))?; + + let current_address = T::REGS.xspi_ar().read().address(); + let current_instruction = T::REGS.xspi_ir().read().instruction(); + + // For a indirect read transaction, the transaction begins when the instruction/address is set + T::REGS + .xspi_cr() + .modify(|v| v.set_fmode(Fmode::from_bits(XspiMode::IndirectRead.into()))); + if T::REGS.xspi_ccr().read().admode() == XspiCcrAdmode::B_0X0 { + T::REGS.xspi_ir().write(|v| v.set_instruction(current_instruction)); + } else { + T::REGS.xspi_ar().write(|v| v.set_address(current_address)); + } + + let transfer = unsafe { + self.dma + .as_mut() + .unwrap() + .read(T::REGS.xspi_dr().as_ptr() as *mut W, buf, Default::default()) + }; + + T::REGS.xspi_cr().modify(|w| w.set_dmaen(Dmaen::B_0X1)); + + transfer.blocking_wait(); + + finish_dma(T::REGS); + + Ok(()) + } + + /// Blocking write with DMA transfer + pub fn blocking_write_dma(&mut self, buf: &[W], transaction: TransferConfig) -> Result<(), XspiError> { + if buf.is_empty() { + return Err(XspiError::EmptyBuffer); + } + + // Wait for peripheral to be free + while T::REGS.xspi_sr().read().busy() {} + + self.configure_command(&transaction, Some(buf.len()))?; + T::REGS + .xspi_cr() + .modify(|v| v.set_fmode(Fmode::from_bits(XspiMode::IndirectWrite.into()))); + + let transfer = unsafe { + self.dma + .as_mut() + .unwrap() + .write(buf, T::REGS.xspi_dr().as_ptr() as *mut W, Default::default()) + }; + + T::REGS.xspi_cr().modify(|w| w.set_dmaen(Dmaen::B_0X1)); + + transfer.blocking_wait(); + + finish_dma(T::REGS); + + Ok(()) + } + + /// Asynchronous read from external device + pub async fn read(&mut self, buf: &mut [W], transaction: TransferConfig) -> Result<(), XspiError> { + if buf.is_empty() { + return Err(XspiError::EmptyBuffer); + } + + // Wait for peripheral to be free + while T::REGS.xspi_sr().read().busy() {} + + self.configure_command(&transaction, Some(buf.len()))?; + + let current_address = T::REGS.xspi_ar().read().address(); + let current_instruction = T::REGS.xspi_ir().read().instruction(); + + // For a indirect read transaction, the transaction begins when the instruction/address is set + T::REGS + .xspi_cr() + .modify(|v| v.set_fmode(Fmode::from_bits(XspiMode::IndirectRead.into()))); + if T::REGS.xspi_ccr().read().admode() == XspiCcrAdmode::B_0X0 { + T::REGS.xspi_ir().write(|v| v.set_instruction(current_instruction)); + } else { + T::REGS.xspi_ar().write(|v| v.set_address(current_address)); + } + + let transfer = unsafe { + self.dma + .as_mut() + .unwrap() + .read(T::REGS.xspi_dr().as_ptr() as *mut W, buf, Default::default()) + }; + + T::REGS.xspi_cr().modify(|w| w.set_dmaen(Dmaen::B_0X1)); + + transfer.await; + + finish_dma(T::REGS); + + Ok(()) + } + + /// Asynchronous write to external device + pub async fn write(&mut self, buf: &[W], transaction: TransferConfig) -> Result<(), XspiError> { + if buf.is_empty() { + return Err(XspiError::EmptyBuffer); + } + + // Wait for peripheral to be free + while T::REGS.xspi_sr().read().busy() {} + + self.configure_command(&transaction, Some(buf.len()))?; + T::REGS + .xspi_cr() + .modify(|v| v.set_fmode(Fmode::from_bits(XspiMode::IndirectWrite.into()))); + + let transfer = unsafe { + self.dma + .as_mut() + .unwrap() + .write(buf, T::REGS.xspi_dr().as_ptr() as *mut W, Default::default()) + }; + + T::REGS.xspi_cr().modify(|w| w.set_dmaen(Dmaen::B_0X1)); + + transfer.await; + + finish_dma(T::REGS); + + Ok(()) + } +} + +impl<'d, T: Instance, M: PeriMode> Drop for Xspi<'d, T, M> { + fn drop(&mut self) { + self.clk.as_ref().map(|x| x.set_as_disconnected()); + self.d0.as_ref().map(|x| x.set_as_disconnected()); + self.d1.as_ref().map(|x| x.set_as_disconnected()); + self.d2.as_ref().map(|x| x.set_as_disconnected()); + self.d3.as_ref().map(|x| x.set_as_disconnected()); + self.d4.as_ref().map(|x| x.set_as_disconnected()); + self.d5.as_ref().map(|x| x.set_as_disconnected()); + self.d6.as_ref().map(|x| x.set_as_disconnected()); + self.d7.as_ref().map(|x| x.set_as_disconnected()); + self.d8.as_ref().map(|x| x.set_as_disconnected()); + self.d9.as_ref().map(|x| x.set_as_disconnected()); + self.d10.as_ref().map(|x| x.set_as_disconnected()); + self.d11.as_ref().map(|x| x.set_as_disconnected()); + self.d12.as_ref().map(|x| x.set_as_disconnected()); + self.d13.as_ref().map(|x| x.set_as_disconnected()); + self.d14.as_ref().map(|x| x.set_as_disconnected()); + self.d15.as_ref().map(|x| x.set_as_disconnected()); + self.ncs1.as_ref().map(|x| x.set_as_disconnected()); + self.ncs2.as_ref().map(|x| x.set_as_disconnected()); + self.dqs0.as_ref().map(|x| x.set_as_disconnected()); + self.dqs1.as_ref().map(|x| x.set_as_disconnected()); + + rcc::disable::(); + } +} + +fn finish_dma(regs: Regs) { + while !regs.xspi_sr().read().tcf() {} + regs.xspi_fcr().write(|v| v.set_ctcf(true)); + + regs.xspi_cr().modify(|w| { + w.set_dmaen(Dmaen::B_0X0); + }); +} + +/// XSPI I/O manager instance trait. +#[cfg(xspim_v2_1)] +pub(crate) trait SealedXspimInstance { + const SPIM_REGS: Xspim; + const SPI_IDX: u8; +} + +/// XSPI instance trait. +pub(crate) trait SealedInstance { + const REGS: Regs; +} + +/// XSPI instance trait. +#[cfg(xspim_v2_1)] +#[allow(private_bounds)] +pub trait Instance: Peripheral

+ SealedInstance + RccPeripheral + SealedXspimInstance {} + +/// XSPI instance trait. +#[cfg(not(xspim_v2_1))] +#[allow(private_bounds)] +pub trait Instance: Peripheral

+ SealedInstance + RccPeripheral {} + +pin_trait!(D0Pin, Instance); +pin_trait!(D1Pin, Instance); +pin_trait!(D2Pin, Instance); +pin_trait!(D3Pin, Instance); +pin_trait!(D4Pin, Instance); +pin_trait!(D5Pin, Instance); +pin_trait!(D6Pin, Instance); +pin_trait!(D7Pin, Instance); +pin_trait!(D8Pin, Instance); +pin_trait!(D9Pin, Instance); +pin_trait!(D10Pin, Instance); +pin_trait!(D11Pin, Instance); +pin_trait!(D12Pin, Instance); +pin_trait!(D13Pin, Instance); +pin_trait!(D14Pin, Instance); +pin_trait!(D15Pin, Instance); +pin_trait!(DQS0Pin, Instance); +pin_trait!(DQS1Pin, Instance); +pin_trait!(NCS1Pin, Instance); +pin_trait!(NCS2Pin, Instance); +pin_trait!(CLKPin, Instance); +pin_trait!(NCLKPin, Instance); +dma_trait!(XDma, Instance); + +// Hard-coded the xspi index, for SPIM +#[cfg(xspim_v2_1)] +impl SealedXspimInstance for peripherals::XSPI1 { + const SPIM_REGS: Xspim = crate::pac::XSPIM; + const SPI_IDX: u8 = 1; +} + +// #[cfg(all(xspim_v2_1, peri_xspi2))] +#[cfg(xspim_v2_1)] +impl SealedXspimInstance for peripherals::XSPI2 { + const SPIM_REGS: Xspim = crate::pac::XSPIM; + const SPI_IDX: u8 = 2; +} + +#[cfg(xspim_v2_1)] +foreach_peripheral!( + (xspi, $inst:ident) => { + impl SealedInstance for peripherals::$inst { + const REGS: Regs = crate::pac::$inst; + } + + impl Instance for peripherals::$inst {} + }; +); + +#[cfg(not(xspim_v2_1))] +foreach_peripheral!( + (xspi, $inst:ident) => { + impl SealedInstance for peripherals::$inst { + const REGS: Regs = crate::pac::$inst; + } + + impl Instance for peripherals::$inst {} + }; +); + +impl<'d, T: Instance, M: PeriMode> SetConfig for Xspi<'d, T, M> { + type Config = Config; + type ConfigError = (); + fn set_config(&mut self, config: &Self::Config) -> Result<(), ()> { + self.set_config(config); + Ok(()) + } +} + +impl<'d, T: Instance, M: PeriMode> GetConfig for Xspi<'d, T, M> { + type Config = Config; + fn get_config(&self) -> Self::Config { + self.get_config() + } +} + +/// Word sizes usable for XSPI. +#[allow(private_bounds)] +pub trait Word: word::Word {} + +macro_rules! impl_word { + ($T:ty) => { + impl Word for $T {} + }; +} + +impl_word!(u8); +impl_word!(u16); +impl_word!(u32); From 36a5b02774a5254fd3a1b715515c84d04dee2d58 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Wed, 2 Apr 2025 11:16:31 +0800 Subject: [PATCH 0915/1217] stm32: Update xspi for stm32-metapac changes This is now closer to the original ospi, using more idiomatic naming. Some dead code is removed (previously was hidden by [allow(dead_code)]). --- embassy-stm32/build.rs | 8 +- embassy-stm32/src/xspi/enums.rs | 25 +-- embassy-stm32/src/xspi/mod.rs | 365 +++++++++++++++----------------- 3 files changed, 175 insertions(+), 223 deletions(-) diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 13ef74f16..fa9e3f953 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -62,7 +62,13 @@ fn main() { // generate one singleton per peripheral (with many exceptions...) for p in METADATA.peripherals { if let Some(r) = &p.registers { - if r.kind == "adccommon" || r.kind == "sai" || r.kind == "ucpd" || r.kind == "otg" || r.kind == "octospi" { + if r.kind == "adccommon" + || r.kind == "sai" + || r.kind == "ucpd" + || r.kind == "otg" + || r.kind == "octospi" + || r.kind == "xspi" + { // TODO: should we emit this for all peripherals? if so, we will need a list of all // possible peripherals across all chips, so that we can declare the configs // (replacing the hard-coded list of `peri_*` cfgs below) diff --git a/embassy-stm32/src/xspi/enums.rs b/embassy-stm32/src/xspi/enums.rs index 4214dde37..e02ec797e 100644 --- a/embassy-stm32/src/xspi/enums.rs +++ b/embassy-stm32/src/xspi/enums.rs @@ -1,10 +1,11 @@ //! Enums used in Xspi configuration. -#[allow(dead_code)] #[derive(Copy, Clone)] pub(crate) enum XspiMode { IndirectWrite, IndirectRead, + #[expect(dead_code)] AutoPolling, + #[expect(dead_code)] MemoryMapped, } @@ -20,7 +21,6 @@ impl Into for XspiMode { } /// Xspi lane width -#[allow(dead_code)] #[derive(Copy, Clone)] pub enum XspiWidth { /// None @@ -47,27 +47,7 @@ impl Into for XspiWidth { } } -/// Flash bank selection -#[allow(dead_code)] -#[derive(Copy, Clone)] -pub enum FlashSelection { - /// Bank 1 - Flash1, - /// Bank 2 - Flash2, -} - -impl Into for FlashSelection { - fn into(self) -> bool { - match self { - FlashSelection::Flash1 => false, - FlashSelection::Flash2 => true, - } - } -} - /// Wrap Size -#[allow(dead_code)] #[allow(missing_docs)] #[derive(Copy, Clone)] pub enum WrapSize { @@ -92,7 +72,6 @@ impl Into for WrapSize { /// Memory Type #[allow(missing_docs)] -#[allow(dead_code)] #[derive(Copy, Clone)] pub enum MemoryType { Micron, diff --git a/embassy-stm32/src/xspi/mod.rs b/embassy-stm32/src/xspi/mod.rs index b2fdebe75..3b5406a57 100644 --- a/embassy-stm32/src/xspi/mod.rs +++ b/embassy-stm32/src/xspi/mod.rs @@ -14,8 +14,9 @@ pub use enums::*; use crate::dma::{word, ChannelAndRequest}; use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed}; use crate::mode::{Async, Blocking, Mode as PeriMode}; -use crate::pac::xspi::{vals::*, Xspi as Regs}; -#[cfg(xspim_v2_1)] +use crate::pac::xspi::vals::*; +use crate::pac::xspi::Xspi as Regs; +#[cfg(xspim_v1)] use crate::pac::xspim::Xspim; use crate::rcc::{self, RccPeripheral}; use crate::{peripherals, Peripheral}; @@ -41,7 +42,7 @@ pub struct Config { /// Indicates the wrap size corresponding to the external device configuration pub wrap_size: WrapSize, /// Specified the prescaler factor used for generating the external clock based - /// on the AHB clock + /// on the AHB clock. 0 = Fkernel, 1 = Fkernel/2, 2 = Fkernel/3 etc. pub clock_prescaler: u8, /// Allows the delay of 1/2 cycle the data sampling to account for external /// signal delays @@ -196,47 +197,35 @@ impl<'d, T: Instance, M: PeriMode> Xspi<'d, T, M> { self.configure_command(&read_config, None)?; let reg = T::REGS; - while reg.xspi_sr().read().busy() {} + while reg.sr().read().busy() {} - reg.xspi_ccr().modify(|r| { - r.set_dqse(XspiCcrDqse::B_0X0); + reg.ccr().modify(|r| { + r.set_dqse(false); }); // Set wrting configurations, there are separate registers for write configurations in memory mapped mode - reg.xspi_wccr().modify(|w| { - w.set_imode(XspiWccrImode::from_bits(write_config.iwidth.into())); - let idtr = match write_config.idtr { - true => XspiWccrIdtr::B_0X1, - false => XspiWccrIdtr::B_0X0, - }; - w.set_idtr(idtr); - w.set_isize(XspiWccrIsize::from_bits(write_config.isize.into())); + reg.wccr().modify(|w| { + w.set_imode(WccrImode::from_bits(write_config.iwidth.into())); + w.set_idtr(write_config.idtr); + w.set_isize(WccrIsize::from_bits(write_config.isize.into())); - w.set_admode(XspiWccrAdmode::from_bits(write_config.adwidth.into())); - let addtr = match write_config.idtr { - true => XspiWccrAddtr::B_0X1, - false => XspiWccrAddtr::B_0X0, - }; - w.set_addtr(addtr); - w.set_adsize(XspiWccrAdsize::from_bits(write_config.adsize.into())); + w.set_admode(WccrAdmode::from_bits(write_config.adwidth.into())); + w.set_addtr(write_config.idtr); + w.set_adsize(WccrAdsize::from_bits(write_config.adsize.into())); - w.set_dmode(XspiWccrDmode::from_bits(write_config.dwidth.into())); - let ddtr = match write_config.idtr { - true => XspiWccrDdtr::B_0X1, - false => XspiWccrDdtr::B_0X0, - }; - w.set_ddtr(ddtr); + w.set_dmode(WccrDmode::from_bits(write_config.dwidth.into())); + w.set_ddtr(write_config.idtr); - w.set_abmode(XspiWccrAbmode::from_bits(write_config.abwidth.into())); - w.set_dqse(XspiWccrDqse::B_0X1); + w.set_abmode(WccrAbmode::from_bits(write_config.abwidth.into())); + w.set_dqse(true); }); - reg.xspi_wtcr().modify(|w| w.set_dcyc(write_config.dummy.into())); + reg.wtcr().modify(|w| w.set_dcyc(write_config.dummy.into())); // Enable memory mapped mode - reg.xspi_cr().modify(|r| { + reg.cr().modify(|r| { r.set_fmode(Fmode::B_0X3); - r.set_tcen(Tcen::B_0X0); + r.set_tcen(false); }); Ok(()) } @@ -245,19 +234,19 @@ impl<'d, T: Instance, M: PeriMode> Xspi<'d, T, M> { pub fn disable_memory_mapped_mode(&mut self) { let reg = T::REGS; - reg.xspi_cr().modify(|r| { + reg.cr().modify(|r| { r.set_fmode(Fmode::B_0X0); - r.set_abort(Abort::B_0X1); - r.set_dmaen(Dmaen::B_0X0); - r.set_en(En::B_0X0); + r.set_abort(true); + r.set_dmaen(false); + r.set_en(false); }); // Clear transfer complete flag - reg.xspi_fcr().write(|w| w.set_ctcf(true)); + reg.fcr().write(|w| w.set_ctcf(true)); // Re-enable ospi - reg.xspi_cr().modify(|r| { - r.set_en(En::B_0X1); + reg.cr().modify(|r| { + r.set_en(true); }); } @@ -291,18 +280,18 @@ impl<'d, T: Instance, M: PeriMode> Xspi<'d, T, M> { ) -> Self { into_ref!(peri); - #[cfg(xspim_v2_1)] + #[cfg(xspim_v1)] { // RCC for xspim should be enabled before writing register crate::pac::RCC.ahb5enr().modify(|w| w.set_iomngren(true)); // Disable XSPI peripheral first - T::REGS.xspi_cr().modify(|w| { - w.set_en(En::B_0X0); + T::REGS.cr().modify(|w| { + w.set_en(false); }); // XSPI IO Manager has been enabled before - T::SPIM_REGS.xspim_cr().modify(|w| { + T::SPIM_REGS.cr().modify(|w| { w.set_muxen(false); w.set_req2ack_time(0xff); }); @@ -310,74 +299,70 @@ impl<'d, T: Instance, M: PeriMode> Xspi<'d, T, M> { // System configuration rcc::enable_and_reset::(); - while T::REGS.xspi_sr().read().busy() {} + while T::REGS.sr().read().busy() {} // Device configuration - T::REGS.xspi_dcr1().modify(|w| { + T::REGS.dcr1().modify(|w| { w.set_devsize(config.device_size.into()); w.set_mtyp(Mtyp::from_bits(config.memory_type.into())); w.set_csht(Csht::from_bits(config.chip_select_high_time.into())); - w.set_frck(Frck::B_0X0); + w.set_frck(false); w.set_ckmode(Ckmode::from_bits(config.clock_mode.into())); }); - T::REGS.xspi_dcr2().modify(|w| { + T::REGS.dcr2().modify(|w| { w.set_wrapsize(Wrapsize::from_bits(config.wrap_size.into())); }); - T::REGS.xspi_dcr3().modify(|w| { + T::REGS.dcr3().modify(|w| { w.set_csbound(Csbound::from_bits(config.chip_select_boundary.into())); - #[cfg(xspi_v2_1)] + #[cfg(xspi_v1)] { w.set_maxtran(Maxtran::from_bits(config.max_transfer.into())); } }); - T::REGS.xspi_dcr4().modify(|w| { + T::REGS.dcr4().modify(|w| { w.set_refresh(Refresh::from_bits(config.refresh.into())); }); - T::REGS.xspi_cr().modify(|w| { + T::REGS.cr().modify(|w| { w.set_fthres(Fthres::from_bits(config.fifo_threshold.into())); }); // Wait for busy flag to clear - while T::REGS.xspi_sr().read().busy() {} + while T::REGS.sr().read().busy() {} - T::REGS.xspi_dcr2().modify(|w| { - w.set_prescaler(Prescaler::from_bits(config.clock_prescaler.into())); + T::REGS.dcr2().modify(|w| { + w.set_prescaler(config.clock_prescaler); }); - T::REGS.xspi_cr().modify(|w| { - w.set_dmm(match dual_quad { - true => Dmm::B_0X1, - false => Dmm::B_0X0, - }); + T::REGS.cr().modify(|w| { + w.set_dmm(dual_quad); }); - T::REGS.xspi_tcr().modify(|w| { - w.set_sshift(match config.sample_shifting { - true => XspiTcrSshift::B_0X1, - false => XspiTcrSshift::B_0X0, - }); - w.set_dhqc(match config.delay_hold_quarter_cycle { - true => XspiTcrDhqc::B_0X1, - false => XspiTcrDhqc::B_0X0, - }); + T::REGS.tcr().modify(|w| { + w.set_sshift(config.sample_shifting); + w.set_dhqc(config.delay_hold_quarter_cycle); + }); + + // TODO: at the moment only ncs1 seems to get passed in? + // Only one must be selected + assert!(!(ncs1.is_some() && ncs2.is_some())); + assert!(!(ncs1.is_none() && ncs2.is_none())); + T::REGS.cr().modify(|w| { + w.set_cssel(if ncs1.is_some() { Cssel::B_0X0 } else { Cssel::B_0X1 }); }); // Enable peripheral - T::REGS.xspi_cr().modify(|w| { - w.set_en(En::B_0X1); + T::REGS.cr().modify(|w| { + w.set_en(true); }); // Free running clock needs to be set after peripheral enable if config.free_running_clock { - T::REGS.xspi_dcr1().modify(|w| { - w.set_frck(match config.free_running_clock { - true => Frck::B_0X1, - false => Frck::B_0X0, - }); + T::REGS.dcr1().modify(|w| { + w.set_frck(config.free_running_clock); }); } @@ -422,87 +407,78 @@ impl<'d, T: Instance, M: PeriMode> Xspi<'d, T, M> { return Err(XspiError::InvalidCommand); } - T::REGS.xspi_cr().modify(|w| { + T::REGS.cr().modify(|w| { w.set_fmode(0.into()); }); // Configure alternate bytes if let Some(ab) = command.alternate_bytes { - T::REGS.xspi_abr().write(|v| v.set_alternate(ab)); - T::REGS.xspi_ccr().modify(|w| { - w.set_abmode(XspiCcrAbmode::from_bits(command.abwidth.into())); - w.set_abdtr(XspiCcrAbdtr::from_bits(command.abdtr.into())); - w.set_absize(XspiCcrAbsize::from_bits(command.absize.into())); + T::REGS.abr().write(|v| v.set_alternate(ab)); + T::REGS.ccr().modify(|w| { + w.set_abmode(CcrAbmode::from_bits(command.abwidth.into())); + w.set_abdtr(command.abdtr); + w.set_absize(CcrAbsize::from_bits(command.absize.into())); }) } // Configure dummy cycles - T::REGS.xspi_tcr().modify(|w| { + T::REGS.tcr().modify(|w| { w.set_dcyc(command.dummy.into()); }); // Configure data if let Some(data_length) = data_len { - T::REGS.xspi_dlr().write(|v| { + T::REGS.dlr().write(|v| { v.set_dl((data_length - 1) as u32); }) } else { - T::REGS.xspi_dlr().write(|v| { + T::REGS.dlr().write(|v| { v.set_dl((0) as u32); }) } // Configure instruction/address/data modes - T::REGS.xspi_ccr().modify(|w| { - w.set_imode(XspiCcrImode::from_bits(command.iwidth.into())); - w.set_idtr(match command.idtr { - true => XspiCcrIdtr::B_0X1, - false => XspiCcrIdtr::B_0X0, - }); - w.set_isize(XspiCcrIsize::from_bits(command.isize.into())); + T::REGS.ccr().modify(|w| { + w.set_imode(CcrImode::from_bits(command.iwidth.into())); + w.set_idtr(command.idtr); + w.set_isize(CcrIsize::from_bits(command.isize.into())); - w.set_admode(XspiCcrAdmode::from_bits(command.adwidth.into())); - w.set_addtr(match command.idtr { - true => XspiCcrAddtr::B_0X1, - false => XspiCcrAddtr::B_0X0, - }); - w.set_adsize(XspiCcrAdsize::from_bits(command.adsize.into())); + w.set_admode(CcrAdmode::from_bits(command.adwidth.into())); + w.set_addtr(command.idtr); + w.set_adsize(CcrAdsize::from_bits(command.adsize.into())); - w.set_dmode(XspiCcrDmode::from_bits(command.dwidth.into())); - w.set_ddtr(match command.ddtr { - true => XspiCcrDdtr::B_0X1, - false => XspiCcrDdtr::B_0X0, - }); + w.set_dmode(CcrDmode::from_bits(command.dwidth.into())); + w.set_ddtr(command.ddtr); }); // Set information required to initiate transaction if let Some(instruction) = command.instruction { if let Some(address) = command.address { - T::REGS.xspi_ir().write(|v| { + T::REGS.ir().write(|v| { v.set_instruction(instruction); }); - T::REGS.xspi_ar().write(|v| { + T::REGS.ar().write(|v| { v.set_address(address); }); } else { // Double check requirements for delay hold and sample shifting // if let None = command.data_len { // if self.config.delay_hold_quarter_cycle && command.idtr { - // T::REGS.xspi_ccr().modify(|w| { + // T::REGS.ccr().modify(|w| { // w.set_ddtr(true); // }); // } // } - warn!("instruction: {:#x}", instruction); - T::REGS.xspi_ir().write(|v| { + // warn!("instruction: {:#x}", instruction); + T::REGS.ir().write(|v| { v.set_instruction(instruction); }); } } else { if let Some(address) = command.address { - T::REGS.xspi_ar().write(|v| { + T::REGS.ar().write(|v| { v.set_address(address); }); } else { @@ -517,14 +493,14 @@ impl<'d, T: Instance, M: PeriMode> Xspi<'d, T, M> { /// Function used to control or configure the target device without data transfer pub fn blocking_command(&mut self, command: &TransferConfig) -> Result<(), XspiError> { // Wait for peripheral to be free - while T::REGS.xspi_sr().read().busy() {} + while T::REGS.sr().read().busy() {} // Need additional validation that command configuration doesn't have data set self.configure_command(command, None)?; // Transaction initiated by setting final configuration, i.e the instruction register - while !T::REGS.xspi_sr().read().tcf() {} - T::REGS.xspi_fcr().write(|w| { + while !T::REGS.sr().read().tcf() {} + T::REGS.fcr().write(|w| { w.set_ctcf(true); }); @@ -538,36 +514,36 @@ impl<'d, T: Instance, M: PeriMode> Xspi<'d, T, M> { } // Wait for peripheral to be free - while T::REGS.xspi_sr().read().busy() {} + while T::REGS.sr().read().busy() {} // Ensure DMA is not enabled for this transaction - T::REGS.xspi_cr().modify(|w| { - w.set_dmaen(Dmaen::B_0X0); + T::REGS.cr().modify(|w| { + w.set_dmaen(false); }); // self.configure_command(&transaction, Some(buf.len()))?; self.configure_command(&transaction, Some(buf.len())).unwrap(); - let current_address = T::REGS.xspi_ar().read().address(); - let current_instruction = T::REGS.xspi_ir().read().instruction(); + let current_address = T::REGS.ar().read().address(); + let current_instruction = T::REGS.ir().read().instruction(); // For a indirect read transaction, the transaction begins when the instruction/address is set T::REGS - .xspi_cr() + .cr() .modify(|v| v.set_fmode(Fmode::from_bits(XspiMode::IndirectRead.into()))); - if T::REGS.xspi_ccr().read().admode() == XspiCcrAdmode::B_0X0 { - T::REGS.xspi_ir().write(|v| v.set_instruction(current_instruction)); + if T::REGS.ccr().read().admode() == CcrAdmode::B_0X0 { + T::REGS.ir().write(|v| v.set_instruction(current_instruction)); } else { - T::REGS.xspi_ar().write(|v| v.set_address(current_address)); + T::REGS.ar().write(|v| v.set_address(current_address)); } for idx in 0..buf.len() { - while !T::REGS.xspi_sr().read().tcf() && !T::REGS.xspi_sr().read().ftf() {} - buf[idx] = unsafe { (T::REGS.xspi_dr().as_ptr() as *mut W).read_volatile() }; + while !T::REGS.sr().read().tcf() && !T::REGS.sr().read().ftf() {} + buf[idx] = unsafe { (T::REGS.dr().as_ptr() as *mut W).read_volatile() }; } - while !T::REGS.xspi_sr().read().tcf() {} - T::REGS.xspi_fcr().write(|v| v.set_ctcf(true)); + while !T::REGS.sr().read().tcf() {} + T::REGS.fcr().write(|v| v.set_ctcf(true)); Ok(()) } @@ -579,25 +555,25 @@ impl<'d, T: Instance, M: PeriMode> Xspi<'d, T, M> { } // Wait for peripheral to be free - while T::REGS.xspi_sr().read().busy() {} + while T::REGS.sr().read().busy() {} - T::REGS.xspi_cr().modify(|w| { - w.set_dmaen(Dmaen::B_0X0); + T::REGS.cr().modify(|w| { + w.set_dmaen(false); }); self.configure_command(&transaction, Some(buf.len()))?; T::REGS - .xspi_cr() + .cr() .modify(|v| v.set_fmode(Fmode::from_bits(XspiMode::IndirectWrite.into()))); for idx in 0..buf.len() { - while !T::REGS.xspi_sr().read().ftf() {} - unsafe { (T::REGS.xspi_dr().as_ptr() as *mut W).write_volatile(buf[idx]) }; + while !T::REGS.sr().read().ftf() {} + unsafe { (T::REGS.dr().as_ptr() as *mut W).write_volatile(buf[idx]) }; } - while !T::REGS.xspi_sr().read().tcf() {} - T::REGS.xspi_fcr().write(|v| v.set_ctcf(true)); + while !T::REGS.sr().read().tcf() {} + T::REGS.fcr().write(|v| v.set_ctcf(true)); Ok(()) } @@ -605,75 +581,66 @@ impl<'d, T: Instance, M: PeriMode> Xspi<'d, T, M> { /// Set new bus configuration pub fn set_config(&mut self, config: &Config) { // Wait for busy flag to clear - while T::REGS.xspi_sr().read().busy() {} + while T::REGS.sr().read().busy() {} // Disable DMA channel while configuring the peripheral - T::REGS.xspi_cr().modify(|w| { - w.set_dmaen(Dmaen::B_0X0); + T::REGS.cr().modify(|w| { + w.set_dmaen(false); }); // Device configuration - T::REGS.xspi_dcr1().modify(|w| { + T::REGS.dcr1().modify(|w| { w.set_devsize(config.device_size.into()); w.set_mtyp(Mtyp::from_bits(config.memory_type.into())); w.set_csht(Csht::from_bits(config.chip_select_high_time.into())); - w.set_frck(Frck::B_0X0); + w.set_frck(false); w.set_ckmode(match config.clock_mode { true => Ckmode::B_0X1, false => Ckmode::B_0X0, }); }); - T::REGS.xspi_dcr2().modify(|w| { + T::REGS.dcr2().modify(|w| { w.set_wrapsize(Wrapsize::from_bits(config.wrap_size.into())); }); - T::REGS.xspi_dcr3().modify(|w| { + T::REGS.dcr3().modify(|w| { w.set_csbound(Csbound::from_bits(config.chip_select_boundary.into())); - #[cfg(xspi_v2_1)] + #[cfg(xspi_v1)] { w.set_maxtran(Maxtran::from_bits(config.max_transfer.into())); } }); - T::REGS.xspi_dcr4().modify(|w| { + T::REGS.dcr4().modify(|w| { w.set_refresh(Refresh::from_bits(config.refresh.into())); }); - T::REGS.xspi_cr().modify(|w| { + T::REGS.cr().modify(|w| { w.set_fthres(Fthres::from_bits(config.fifo_threshold.into())); }); // Wait for busy flag to clear - while T::REGS.xspi_sr().read().busy() {} + while T::REGS.sr().read().busy() {} - T::REGS.xspi_dcr2().modify(|w| { - w.set_prescaler(Prescaler::from_bits(config.clock_prescaler.into())); + T::REGS.dcr2().modify(|w| { + w.set_prescaler(config.clock_prescaler); }); - T::REGS.xspi_tcr().modify(|w| { - w.set_sshift(match config.sample_shifting { - true => XspiTcrSshift::B_0X1, - false => XspiTcrSshift::B_0X0, - }); - w.set_dhqc(match config.delay_hold_quarter_cycle { - true => XspiTcrDhqc::B_0X1, - false => XspiTcrDhqc::B_0X0, - }); + T::REGS.tcr().modify(|w| { + w.set_sshift(config.sample_shifting); + w.set_dhqc(config.delay_hold_quarter_cycle); }); // Enable peripheral - T::REGS.xspi_cr().modify(|w| { - w.set_en(En::B_0X1); + T::REGS.cr().modify(|w| { + w.set_en(true); }); // Free running clock needs to be set after peripheral enable if config.free_running_clock { - T::REGS.xspi_dcr1().modify(|w| { - w.set_frck(match config.free_running_clock { - true => Frck::B_0X1, - false => Frck::B_0X0, - }); + T::REGS.dcr1().modify(|w| { + w.set_frck(config.free_running_clock); }); } @@ -1143,31 +1110,31 @@ impl<'d, T: Instance> Xspi<'d, T, Async> { } // Wait for peripheral to be free - while T::REGS.xspi_sr().read().busy() {} + while T::REGS.sr().read().busy() {} self.configure_command(&transaction, Some(buf.len()))?; - let current_address = T::REGS.xspi_ar().read().address(); - let current_instruction = T::REGS.xspi_ir().read().instruction(); + let current_address = T::REGS.ar().read().address(); + let current_instruction = T::REGS.ir().read().instruction(); // For a indirect read transaction, the transaction begins when the instruction/address is set T::REGS - .xspi_cr() + .cr() .modify(|v| v.set_fmode(Fmode::from_bits(XspiMode::IndirectRead.into()))); - if T::REGS.xspi_ccr().read().admode() == XspiCcrAdmode::B_0X0 { - T::REGS.xspi_ir().write(|v| v.set_instruction(current_instruction)); + if T::REGS.ccr().read().admode() == CcrAdmode::B_0X0 { + T::REGS.ir().write(|v| v.set_instruction(current_instruction)); } else { - T::REGS.xspi_ar().write(|v| v.set_address(current_address)); + T::REGS.ar().write(|v| v.set_address(current_address)); } let transfer = unsafe { self.dma .as_mut() .unwrap() - .read(T::REGS.xspi_dr().as_ptr() as *mut W, buf, Default::default()) + .read(T::REGS.dr().as_ptr() as *mut W, buf, Default::default()) }; - T::REGS.xspi_cr().modify(|w| w.set_dmaen(Dmaen::B_0X1)); + T::REGS.cr().modify(|w| w.set_dmaen(true)); transfer.blocking_wait(); @@ -1183,21 +1150,21 @@ impl<'d, T: Instance> Xspi<'d, T, Async> { } // Wait for peripheral to be free - while T::REGS.xspi_sr().read().busy() {} + while T::REGS.sr().read().busy() {} self.configure_command(&transaction, Some(buf.len()))?; T::REGS - .xspi_cr() + .cr() .modify(|v| v.set_fmode(Fmode::from_bits(XspiMode::IndirectWrite.into()))); let transfer = unsafe { self.dma .as_mut() .unwrap() - .write(buf, T::REGS.xspi_dr().as_ptr() as *mut W, Default::default()) + .write(buf, T::REGS.dr().as_ptr() as *mut W, Default::default()) }; - T::REGS.xspi_cr().modify(|w| w.set_dmaen(Dmaen::B_0X1)); + T::REGS.cr().modify(|w| w.set_dmaen(true)); transfer.blocking_wait(); @@ -1213,31 +1180,31 @@ impl<'d, T: Instance> Xspi<'d, T, Async> { } // Wait for peripheral to be free - while T::REGS.xspi_sr().read().busy() {} + while T::REGS.sr().read().busy() {} self.configure_command(&transaction, Some(buf.len()))?; - let current_address = T::REGS.xspi_ar().read().address(); - let current_instruction = T::REGS.xspi_ir().read().instruction(); + let current_address = T::REGS.ar().read().address(); + let current_instruction = T::REGS.ir().read().instruction(); // For a indirect read transaction, the transaction begins when the instruction/address is set T::REGS - .xspi_cr() + .cr() .modify(|v| v.set_fmode(Fmode::from_bits(XspiMode::IndirectRead.into()))); - if T::REGS.xspi_ccr().read().admode() == XspiCcrAdmode::B_0X0 { - T::REGS.xspi_ir().write(|v| v.set_instruction(current_instruction)); + if T::REGS.ccr().read().admode() == CcrAdmode::B_0X0 { + T::REGS.ir().write(|v| v.set_instruction(current_instruction)); } else { - T::REGS.xspi_ar().write(|v| v.set_address(current_address)); + T::REGS.ar().write(|v| v.set_address(current_address)); } let transfer = unsafe { self.dma .as_mut() .unwrap() - .read(T::REGS.xspi_dr().as_ptr() as *mut W, buf, Default::default()) + .read(T::REGS.dr().as_ptr() as *mut W, buf, Default::default()) }; - T::REGS.xspi_cr().modify(|w| w.set_dmaen(Dmaen::B_0X1)); + T::REGS.cr().modify(|w| w.set_dmaen(true)); transfer.await; @@ -1253,21 +1220,21 @@ impl<'d, T: Instance> Xspi<'d, T, Async> { } // Wait for peripheral to be free - while T::REGS.xspi_sr().read().busy() {} + while T::REGS.sr().read().busy() {} self.configure_command(&transaction, Some(buf.len()))?; T::REGS - .xspi_cr() + .cr() .modify(|v| v.set_fmode(Fmode::from_bits(XspiMode::IndirectWrite.into()))); let transfer = unsafe { self.dma .as_mut() .unwrap() - .write(buf, T::REGS.xspi_dr().as_ptr() as *mut W, Default::default()) + .write(buf, T::REGS.dr().as_ptr() as *mut W, Default::default()) }; - T::REGS.xspi_cr().modify(|w| w.set_dmaen(Dmaen::B_0X1)); + T::REGS.cr().modify(|w| w.set_dmaen(true)); transfer.await; @@ -1306,16 +1273,16 @@ impl<'d, T: Instance, M: PeriMode> Drop for Xspi<'d, T, M> { } fn finish_dma(regs: Regs) { - while !regs.xspi_sr().read().tcf() {} - regs.xspi_fcr().write(|v| v.set_ctcf(true)); + while !regs.sr().read().tcf() {} + regs.fcr().write(|v| v.set_ctcf(true)); - regs.xspi_cr().modify(|w| { - w.set_dmaen(Dmaen::B_0X0); + regs.cr().modify(|w| { + w.set_dmaen(false); }); } /// XSPI I/O manager instance trait. -#[cfg(xspim_v2_1)] +#[cfg(xspim_v1)] pub(crate) trait SealedXspimInstance { const SPIM_REGS: Xspim; const SPI_IDX: u8; @@ -1327,12 +1294,12 @@ pub(crate) trait SealedInstance { } /// XSPI instance trait. -#[cfg(xspim_v2_1)] +#[cfg(xspim_v1)] #[allow(private_bounds)] pub trait Instance: Peripheral

+ SealedInstance + RccPeripheral + SealedXspimInstance {} /// XSPI instance trait. -#[cfg(not(xspim_v2_1))] +#[cfg(not(xspim_v1))] #[allow(private_bounds)] pub trait Instance: Peripheral

+ SealedInstance + RccPeripheral {} @@ -1361,20 +1328,20 @@ pin_trait!(NCLKPin, Instance); dma_trait!(XDma, Instance); // Hard-coded the xspi index, for SPIM -#[cfg(xspim_v2_1)] +#[cfg(xspim_v1)] impl SealedXspimInstance for peripherals::XSPI1 { const SPIM_REGS: Xspim = crate::pac::XSPIM; const SPI_IDX: u8 = 1; } -// #[cfg(all(xspim_v2_1, peri_xspi2))] -#[cfg(xspim_v2_1)] +// Some cubedb files are missing XSPI2, for example STM32H7R3Z8 +#[cfg(all(xspim_v1, peri_xspi2))] impl SealedXspimInstance for peripherals::XSPI2 { const SPIM_REGS: Xspim = crate::pac::XSPIM; const SPI_IDX: u8 = 2; } -#[cfg(xspim_v2_1)] +#[cfg(xspim_v1)] foreach_peripheral!( (xspi, $inst:ident) => { impl SealedInstance for peripherals::$inst { @@ -1385,7 +1352,7 @@ foreach_peripheral!( }; ); -#[cfg(not(xspim_v2_1))] +#[cfg(not(xspim_v1))] foreach_peripheral!( (xspi, $inst:ident) => { impl SealedInstance for peripherals::$inst { From 65f849a589be78f8f5dce2311614982ee96bbae5 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Thu, 3 Apr 2025 10:48:29 +0800 Subject: [PATCH 0916/1217] stm32: xspi update for Peri --- embassy-stm32/src/xspi/mod.rs | 264 +++++++++++++++++----------------- 1 file changed, 131 insertions(+), 133 deletions(-) diff --git a/embassy-stm32/src/xspi/mod.rs b/embassy-stm32/src/xspi/mod.rs index 3b5406a57..c024b2ed6 100644 --- a/embassy-stm32/src/xspi/mod.rs +++ b/embassy-stm32/src/xspi/mod.rs @@ -8,7 +8,7 @@ pub mod enums; use core::marker::PhantomData; use embassy_embedded_hal::{GetConfig, SetConfig}; -use embassy_hal_internal::{into_ref, PeripheralRef}; +use embassy_hal_internal::PeripheralType; pub use enums::*; use crate::dma::{word, ChannelAndRequest}; @@ -19,7 +19,7 @@ use crate::pac::xspi::Xspi as Regs; #[cfg(xspim_v1)] use crate::pac::xspim::Xspim; use crate::rcc::{self, RccPeripheral}; -use crate::{peripherals, Peripheral}; +use crate::{peripherals, Peri}; /// XPSI driver config. #[derive(Clone, Copy)] @@ -157,28 +157,28 @@ pub enum XspiError { /// XSPI driver. pub struct Xspi<'d, T: Instance, M: PeriMode> { - _peri: PeripheralRef<'d, T>, - clk: Option>, - d0: Option>, - d1: Option>, - d2: Option>, - d3: Option>, - d4: Option>, - d5: Option>, - d6: Option>, - d7: Option>, - d8: Option>, - d9: Option>, - d10: Option>, - d11: Option>, - d12: Option>, - d13: Option>, - d14: Option>, - d15: Option>, - ncs1: Option>, - ncs2: Option>, - dqs0: Option>, - dqs1: Option>, + _peri: Peri<'d, T>, + clk: Option>, + d0: Option>, + d1: Option>, + d2: Option>, + d3: Option>, + d4: Option>, + d5: Option>, + d6: Option>, + d7: Option>, + d8: Option>, + d9: Option>, + d10: Option>, + d11: Option>, + d12: Option>, + d13: Option>, + d14: Option>, + d15: Option>, + ncs1: Option>, + ncs2: Option>, + dqs0: Option>, + dqs1: Option>, dma: Option>, _phantom: PhantomData, config: Config, @@ -251,35 +251,33 @@ impl<'d, T: Instance, M: PeriMode> Xspi<'d, T, M> { } fn new_inner( - peri: impl Peripheral

+ 'd, - d0: Option>, - d1: Option>, - d2: Option>, - d3: Option>, - d4: Option>, - d5: Option>, - d6: Option>, - d7: Option>, - d8: Option>, - d9: Option>, - d10: Option>, - d11: Option>, - d12: Option>, - d13: Option>, - d14: Option>, - d15: Option>, - clk: Option>, - ncs1: Option>, - ncs2: Option>, - dqs0: Option>, - dqs1: Option>, + peri: Peri<'d, T>, + d0: Option>, + d1: Option>, + d2: Option>, + d3: Option>, + d4: Option>, + d5: Option>, + d6: Option>, + d7: Option>, + d8: Option>, + d9: Option>, + d10: Option>, + d11: Option>, + d12: Option>, + d13: Option>, + d14: Option>, + d15: Option>, + clk: Option>, + ncs1: Option>, + ncs2: Option>, + dqs0: Option>, + dqs1: Option>, dma: Option>, config: Config, width: XspiWidth, dual_quad: bool, ) -> Self { - into_ref!(peri); - #[cfg(xspim_v1)] { // RCC for xspim should be enabled before writing register @@ -656,11 +654,11 @@ impl<'d, T: Instance, M: PeriMode> Xspi<'d, T, M> { impl<'d, T: Instance> Xspi<'d, T, Blocking> { /// Create new blocking XSPI driver for a single spi external chip pub fn new_blocking_singlespi( - peri: impl Peripheral

+ 'd, - clk: impl Peripheral

> + 'd, - d0: impl Peripheral

> + 'd, - d1: impl Peripheral

> + 'd, - ncs: impl Peripheral

> + 'd, + peri: Peri<'d, T>, + clk: Peri<'d, impl CLKPin>, + d0: Peri<'d, impl D0Pin>, + d1: Peri<'d, impl D1Pin>, + ncs: Peri<'d, impl NCS1Pin>, config: Config, ) -> Self { Self::new_inner( @@ -695,11 +693,11 @@ impl<'d, T: Instance> Xspi<'d, T, Blocking> { /// Create new blocking XSPI driver for a dualspi external chip pub fn new_blocking_dualspi( - peri: impl Peripheral

+ 'd, - clk: impl Peripheral

> + 'd, - d0: impl Peripheral

> + 'd, - d1: impl Peripheral

> + 'd, - ncs: impl Peripheral

> + 'd, + peri: Peri<'d, T>, + clk: Peri<'d, impl CLKPin>, + d0: Peri<'d, impl D0Pin>, + d1: Peri<'d, impl D1Pin>, + ncs: Peri<'d, impl NCS1Pin>, config: Config, ) -> Self { Self::new_inner( @@ -737,13 +735,13 @@ impl<'d, T: Instance> Xspi<'d, T, Blocking> { /// Create new blocking XSPI driver for a quadspi external chip pub fn new_blocking_quadspi( - peri: impl Peripheral

+ 'd, - clk: impl Peripheral

> + 'd, - d0: impl Peripheral

> + 'd, - d1: impl Peripheral

> + 'd, - d2: impl Peripheral

> + 'd, - d3: impl Peripheral

> + 'd, - ncs: impl Peripheral

> + 'd, + peri: Peri<'d, T>, + clk: Peri<'d, impl CLKPin>, + d0: Peri<'d, impl D0Pin>, + d1: Peri<'d, impl D1Pin>, + d2: Peri<'d, impl D2Pin>, + d3: Peri<'d, impl D3Pin>, + ncs: Peri<'d, impl NCS1Pin>, config: Config, ) -> Self { Self::new_inner( @@ -781,17 +779,17 @@ impl<'d, T: Instance> Xspi<'d, T, Blocking> { /// Create new blocking XSPI driver for two quadspi external chips pub fn new_blocking_dualquadspi( - peri: impl Peripheral

+ 'd, - clk: impl Peripheral

> + 'd, - d0: impl Peripheral

> + 'd, - d1: impl Peripheral

> + 'd, - d2: impl Peripheral

> + 'd, - d3: impl Peripheral

> + 'd, - d4: impl Peripheral

> + 'd, - d5: impl Peripheral

> + 'd, - d6: impl Peripheral

> + 'd, - d7: impl Peripheral

> + 'd, - ncs: impl Peripheral

> + 'd, + peri: Peri<'d, T>, + clk: Peri<'d, impl CLKPin>, + d0: Peri<'d, impl D0Pin>, + d1: Peri<'d, impl D1Pin>, + d2: Peri<'d, impl D2Pin>, + d3: Peri<'d, impl D3Pin>, + d4: Peri<'d, impl D4Pin>, + d5: Peri<'d, impl D5Pin>, + d6: Peri<'d, impl D6Pin>, + d7: Peri<'d, impl D7Pin>, + ncs: Peri<'d, impl NCS1Pin>, config: Config, ) -> Self { Self::new_inner( @@ -829,17 +827,17 @@ impl<'d, T: Instance> Xspi<'d, T, Blocking> { /// Create new blocking XSPI driver for xspi external chips pub fn new_blocking_xspi( - peri: impl Peripheral

+ 'd, - clk: impl Peripheral

> + 'd, - d0: impl Peripheral

> + 'd, - d1: impl Peripheral

> + 'd, - d2: impl Peripheral

> + 'd, - d3: impl Peripheral

> + 'd, - d4: impl Peripheral

> + 'd, - d5: impl Peripheral

> + 'd, - d6: impl Peripheral

> + 'd, - d7: impl Peripheral

> + 'd, - ncs: impl Peripheral

> + 'd, + peri: Peri<'d, T>, + clk: Peri<'d, impl CLKPin>, + d0: Peri<'d, impl D0Pin>, + d1: Peri<'d, impl D1Pin>, + d2: Peri<'d, impl D2Pin>, + d3: Peri<'d, impl D3Pin>, + d4: Peri<'d, impl D4Pin>, + d5: Peri<'d, impl D5Pin>, + d6: Peri<'d, impl D6Pin>, + d7: Peri<'d, impl D7Pin>, + ncs: Peri<'d, impl NCS1Pin>, config: Config, ) -> Self { Self::new_inner( @@ -879,12 +877,12 @@ impl<'d, T: Instance> Xspi<'d, T, Blocking> { impl<'d, T: Instance> Xspi<'d, T, Async> { /// Create new blocking XSPI driver for a single spi external chip pub fn new_singlespi( - peri: impl Peripheral

+ 'd, - clk: impl Peripheral

> + 'd, - d0: impl Peripheral

> + 'd, - d1: impl Peripheral

> + 'd, - ncs: impl Peripheral

> + 'd, - dma: impl Peripheral

> + 'd, + peri: Peri<'d, T>, + clk: Peri<'d, impl CLKPin>, + d0: Peri<'d, impl D0Pin>, + d1: Peri<'d, impl D1Pin>, + ncs: Peri<'d, impl NCS1Pin>, + dma: Peri<'d, impl XDma>, config: Config, ) -> Self { Self::new_inner( @@ -919,12 +917,12 @@ impl<'d, T: Instance> Xspi<'d, T, Async> { /// Create new blocking XSPI driver for a dualspi external chip pub fn new_dualspi( - peri: impl Peripheral

+ 'd, - clk: impl Peripheral

> + 'd, - d0: impl Peripheral

> + 'd, - d1: impl Peripheral

> + 'd, - ncs: impl Peripheral

> + 'd, - dma: impl Peripheral

> + 'd, + peri: Peri<'d, T>, + clk: Peri<'d, impl CLKPin>, + d0: Peri<'d, impl D0Pin>, + d1: Peri<'d, impl D1Pin>, + ncs: Peri<'d, impl NCS1Pin>, + dma: Peri<'d, impl XDma>, config: Config, ) -> Self { Self::new_inner( @@ -962,14 +960,14 @@ impl<'d, T: Instance> Xspi<'d, T, Async> { /// Create new blocking XSPI driver for a quadspi external chip pub fn new_quadspi( - peri: impl Peripheral

+ 'd, - clk: impl Peripheral

> + 'd, - d0: impl Peripheral

> + 'd, - d1: impl Peripheral

> + 'd, - d2: impl Peripheral

> + 'd, - d3: impl Peripheral

> + 'd, - ncs: impl Peripheral

> + 'd, - dma: impl Peripheral

> + 'd, + peri: Peri<'d, T>, + clk: Peri<'d, impl CLKPin>, + d0: Peri<'d, impl D0Pin>, + d1: Peri<'d, impl D1Pin>, + d2: Peri<'d, impl D2Pin>, + d3: Peri<'d, impl D3Pin>, + ncs: Peri<'d, impl NCS1Pin>, + dma: Peri<'d, impl XDma>, config: Config, ) -> Self { Self::new_inner( @@ -1007,18 +1005,18 @@ impl<'d, T: Instance> Xspi<'d, T, Async> { /// Create new blocking XSPI driver for two quadspi external chips pub fn new_dualquadspi( - peri: impl Peripheral

+ 'd, - clk: impl Peripheral

> + 'd, - d0: impl Peripheral

> + 'd, - d1: impl Peripheral

> + 'd, - d2: impl Peripheral

> + 'd, - d3: impl Peripheral

> + 'd, - d4: impl Peripheral

> + 'd, - d5: impl Peripheral

> + 'd, - d6: impl Peripheral

> + 'd, - d7: impl Peripheral

> + 'd, - ncs: impl Peripheral

> + 'd, - dma: impl Peripheral

> + 'd, + peri: Peri<'d, T>, + clk: Peri<'d, impl CLKPin>, + d0: Peri<'d, impl D0Pin>, + d1: Peri<'d, impl D1Pin>, + d2: Peri<'d, impl D2Pin>, + d3: Peri<'d, impl D3Pin>, + d4: Peri<'d, impl D4Pin>, + d5: Peri<'d, impl D5Pin>, + d6: Peri<'d, impl D6Pin>, + d7: Peri<'d, impl D7Pin>, + ncs: Peri<'d, impl NCS1Pin>, + dma: Peri<'d, impl XDma>, config: Config, ) -> Self { Self::new_inner( @@ -1056,18 +1054,18 @@ impl<'d, T: Instance> Xspi<'d, T, Async> { /// Create new blocking XSPI driver for xspi external chips pub fn new_xspi( - peri: impl Peripheral

+ 'd, - clk: impl Peripheral

> + 'd, - d0: impl Peripheral

> + 'd, - d1: impl Peripheral

> + 'd, - d2: impl Peripheral

> + 'd, - d3: impl Peripheral

> + 'd, - d4: impl Peripheral

> + 'd, - d5: impl Peripheral

> + 'd, - d6: impl Peripheral

> + 'd, - d7: impl Peripheral

> + 'd, - ncs: impl Peripheral

> + 'd, - dma: impl Peripheral

> + 'd, + peri: Peri<'d, T>, + clk: Peri<'d, impl CLKPin>, + d0: Peri<'d, impl D0Pin>, + d1: Peri<'d, impl D1Pin>, + d2: Peri<'d, impl D2Pin>, + d3: Peri<'d, impl D3Pin>, + d4: Peri<'d, impl D4Pin>, + d5: Peri<'d, impl D5Pin>, + d6: Peri<'d, impl D6Pin>, + d7: Peri<'d, impl D7Pin>, + ncs: Peri<'d, impl NCS1Pin>, + dma: Peri<'d, impl XDma>, config: Config, ) -> Self { Self::new_inner( @@ -1296,12 +1294,12 @@ pub(crate) trait SealedInstance { /// XSPI instance trait. #[cfg(xspim_v1)] #[allow(private_bounds)] -pub trait Instance: Peripheral

+ SealedInstance + RccPeripheral + SealedXspimInstance {} +pub trait Instance: SealedInstance + PeripheralType + RccPeripheral + SealedXspimInstance {} /// XSPI instance trait. #[cfg(not(xspim_v1))] #[allow(private_bounds)] -pub trait Instance: Peripheral

+ SealedInstance + RccPeripheral {} +pub trait Instance: SealedInstance + PeripheralType + RccPeripheral {} pin_trait!(D0Pin, Instance); pin_trait!(D1Pin, Instance); From e22fe7cbcfbbb68e4ad6ef7914bf8ed952fca8f4 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Wed, 2 Apr 2025 21:00:08 +0800 Subject: [PATCH 0917/1217] stm32: xspi wait for prescaler change This is documented as being required (and is done by stm32cube), hasn't been observed as a problem though. --- embassy-stm32/src/xspi/mod.rs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/embassy-stm32/src/xspi/mod.rs b/embassy-stm32/src/xspi/mod.rs index c024b2ed6..c315e2320 100644 --- a/embassy-stm32/src/xspi/mod.rs +++ b/embassy-stm32/src/xspi/mod.rs @@ -335,8 +335,17 @@ impl<'d, T: Instance, M: PeriMode> Xspi<'d, T, M> { w.set_prescaler(config.clock_prescaler); }); + // Wait for busy flag to clear after changing prescaler, during calibration + while T::REGS.sr().read().busy() {} + T::REGS.cr().modify(|w| { w.set_dmm(dual_quad); + + // TODO: at the moment only ncs1 seems to get passed in? + // Only one must be selected + assert!(!(ncs1.is_some() && ncs2.is_some())); + assert!(!(ncs1.is_none() && ncs2.is_none())); + w.set_cssel(if ncs1.is_some() { Cssel::B_0X0 } else { Cssel::B_0X1 }); }); T::REGS.tcr().modify(|w| { @@ -344,14 +353,6 @@ impl<'d, T: Instance, M: PeriMode> Xspi<'d, T, M> { w.set_dhqc(config.delay_hold_quarter_cycle); }); - // TODO: at the moment only ncs1 seems to get passed in? - // Only one must be selected - assert!(!(ncs1.is_some() && ncs2.is_some())); - assert!(!(ncs1.is_none() && ncs2.is_none())); - T::REGS.cr().modify(|w| { - w.set_cssel(if ncs1.is_some() { Cssel::B_0X0 } else { Cssel::B_0X1 }); - }); - // Enable peripheral T::REGS.cr().modify(|w| { w.set_en(true); From 6b80f3badaf722309f13accd0e8a7e0f04a837ce Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Fri, 4 Apr 2025 15:08:05 +0800 Subject: [PATCH 0918/1217] stm32: xspi: rework switching between ncs1 and ncs2 --- embassy-stm32/build.rs | 24 +++++++++--- embassy-stm32/src/macros.rs | 11 ++++++ embassy-stm32/src/xspi/mod.rs | 69 ++++++++++++++++++++++------------- 3 files changed, 73 insertions(+), 31 deletions(-) diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index fa9e3f953..b4e61878c 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -1123,8 +1123,8 @@ fn main() { (("xspi", "IO15"), quote!(crate::xspi::D15Pin)), (("xspi", "DQS0"), quote!(crate::xspi::DQS0Pin)), (("xspi", "DQS1"), quote!(crate::xspi::DQS1Pin)), - (("xspi", "NCS1"), quote!(crate::xspi::NCS1Pin)), - (("xspi", "NCS2"), quote!(crate::xspi::NCS2Pin)), + (("xspi", "NCS1"), quote!(crate::xspi::NCSPin)), + (("xspi", "NCS2"), quote!(crate::xspi::NCSPin)), (("xspi", "CLK"), quote!(crate::xspi::CLKPin)), (("xspi", "NCLK"), quote!(crate::xspi::NCLKPin)), (("xspim", "P1_IO0"), quote!(crate::xspi::D0Pin)), @@ -1145,8 +1145,8 @@ fn main() { (("xspim", "P1_IO15"), quote!(crate::xspi::D15Pin)), (("xspim", "P1_DQS0"), quote!(crate::xspi::DQS0Pin)), (("xspim", "P1_DQS1"), quote!(crate::xspi::DQS1Pin)), - (("xspim", "P1_NCS1"), quote!(crate::xspi::NCS1Pin)), - (("xspim", "P1_NCS2"), quote!(crate::xspi::NCS2Pin)), + (("xspim", "P1_NCS1"), quote!(crate::xspi::NCSPin)), + (("xspim", "P1_NCS2"), quote!(crate::xspi::NCSPin)), (("xspim", "P1_CLK"), quote!(crate::xspi::CLKPin)), (("xspim", "P1_NCLK"), quote!(crate::xspi::NCLKPin)), (("xspim", "P2_IO0"), quote!(crate::xspi::D0Pin)), @@ -1167,8 +1167,8 @@ fn main() { (("xspim", "P2_IO15"), quote!(crate::xspi::D15Pin)), (("xspim", "P2_DQS0"), quote!(crate::xspi::DQS0Pin)), (("xspim", "P2_DQS1"), quote!(crate::xspi::DQS1Pin)), - (("xspim", "P2_NCS1"), quote!(crate::xspi::NCS1Pin)), - (("xspim", "P2_NCS2"), quote!(crate::xspi::NCS2Pin)), + (("xspim", "P2_NCS1"), quote!(crate::xspi::NCSPin)), + (("xspim", "P2_NCS2"), quote!(crate::xspi::NCSPin)), (("xspim", "P2_CLK"), quote!(crate::xspi::CLKPin)), (("xspim", "P2_NCLK"), quote!(crate::xspi::NCLKPin)), (("hspi", "IO0"), quote!(crate::hspi::D0Pin)), @@ -1274,6 +1274,18 @@ fn main() { } } + // XSPI NCS pin to CSSEL mapping + if pin.signal.ends_with("NCS1") { + g.extend(quote! { + sel_trait_impl!(crate::xspi::NCSEither, #peri, #pin_name, 0); + }) + } + if pin.signal.ends_with("NCS2") { + g.extend(quote! { + sel_trait_impl!(crate::xspi::NCSEither, #peri, #pin_name, 1); + }) + } + g.extend(quote! { pin_trait_impl!(#tr, #peri, #pin_name, #af); }) diff --git a/embassy-stm32/src/macros.rs b/embassy-stm32/src/macros.rs index 2c181a254..7526bb180 100644 --- a/embassy-stm32/src/macros.rs +++ b/embassy-stm32/src/macros.rs @@ -60,6 +60,17 @@ macro_rules! pin_trait_impl { }; } +#[allow(unused_macros)] +macro_rules! sel_trait_impl { + (crate::$mod:ident::$trait:ident$(<$mode:ident>)?, $instance:ident, $pin:ident, $sel:expr) => { + impl crate::$mod::$trait for crate::peripherals::$pin { + fn sel(&self) -> u8 { + $sel + } + } + }; +} + // ==================== macro_rules! dma_trait { diff --git a/embassy-stm32/src/xspi/mod.rs b/embassy-stm32/src/xspi/mod.rs index c315e2320..bc3007fe8 100644 --- a/embassy-stm32/src/xspi/mod.rs +++ b/embassy-stm32/src/xspi/mod.rs @@ -175,8 +175,12 @@ pub struct Xspi<'d, T: Instance, M: PeriMode> { d13: Option>, d14: Option>, d15: Option>, - ncs1: Option>, - ncs2: Option>, + ncs: Option>, + // TODO: allow switching between multiple chips + ncs_alt: Option>, + // false if ncs == NCS1, true if ncs == NCS2 + // (ncs_alt will be the opposite to ncs). + _cssel_swap: bool, dqs0: Option>, dqs1: Option>, dma: Option>, @@ -269,8 +273,9 @@ impl<'d, T: Instance, M: PeriMode> Xspi<'d, T, M> { d14: Option>, d15: Option>, clk: Option>, - ncs1: Option>, - ncs2: Option>, + ncs_cssel: u8, + ncs: Option>, + ncs_alt: Option>, dqs0: Option>, dqs1: Option>, dma: Option>, @@ -341,11 +346,9 @@ impl<'d, T: Instance, M: PeriMode> Xspi<'d, T, M> { T::REGS.cr().modify(|w| { w.set_dmm(dual_quad); - // TODO: at the moment only ncs1 seems to get passed in? - // Only one must be selected - assert!(!(ncs1.is_some() && ncs2.is_some())); - assert!(!(ncs1.is_none() && ncs2.is_none())); - w.set_cssel(if ncs1.is_some() { Cssel::B_0X0 } else { Cssel::B_0X1 }); + assert!(ncs_alt.is_none(), "ncs_alt TODO"); + let cssel = if ncs_cssel == 0 { Cssel::B_0X0 } else { Cssel::B_0X1 }; + w.set_cssel(cssel); }); T::REGS.tcr().modify(|w| { @@ -384,8 +387,9 @@ impl<'d, T: Instance, M: PeriMode> Xspi<'d, T, M> { d13, d14, d15, - ncs1, - ncs2, + ncs, + ncs_alt, + _cssel_swap: ncs_cssel == 1, dqs0, dqs1, dma, @@ -659,7 +663,7 @@ impl<'d, T: Instance> Xspi<'d, T, Blocking> { clk: Peri<'d, impl CLKPin>, d0: Peri<'d, impl D0Pin>, d1: Peri<'d, impl D1Pin>, - ncs: Peri<'d, impl NCS1Pin>, + ncs: Peri<'d, impl NCSEither>, config: Config, ) -> Self { Self::new_inner( @@ -681,6 +685,7 @@ impl<'d, T: Instance> Xspi<'d, T, Blocking> { None, None, new_pin!(clk, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + ncs.sel(), new_pin!(ncs, AfType::output(OutputType::OpenDrain, Speed::VeryHigh)), None, None, @@ -698,7 +703,7 @@ impl<'d, T: Instance> Xspi<'d, T, Blocking> { clk: Peri<'d, impl CLKPin>, d0: Peri<'d, impl D0Pin>, d1: Peri<'d, impl D1Pin>, - ncs: Peri<'d, impl NCS1Pin>, + ncs: Peri<'d, impl NCSEither>, config: Config, ) -> Self { Self::new_inner( @@ -720,6 +725,7 @@ impl<'d, T: Instance> Xspi<'d, T, Blocking> { None, None, new_pin!(clk, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + ncs.sel(), new_pin!( ncs, AfType::output_pull(OutputType::PushPull, Speed::VeryHigh, Pull::Up) @@ -742,7 +748,7 @@ impl<'d, T: Instance> Xspi<'d, T, Blocking> { d1: Peri<'d, impl D1Pin>, d2: Peri<'d, impl D2Pin>, d3: Peri<'d, impl D3Pin>, - ncs: Peri<'d, impl NCS1Pin>, + ncs: Peri<'d, impl NCSEither>, config: Config, ) -> Self { Self::new_inner( @@ -764,6 +770,7 @@ impl<'d, T: Instance> Xspi<'d, T, Blocking> { None, None, new_pin!(clk, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + ncs.sel(), new_pin!( ncs, AfType::output_pull(OutputType::PushPull, Speed::VeryHigh, Pull::Up) @@ -790,7 +797,7 @@ impl<'d, T: Instance> Xspi<'d, T, Blocking> { d5: Peri<'d, impl D5Pin>, d6: Peri<'d, impl D6Pin>, d7: Peri<'d, impl D7Pin>, - ncs: Peri<'d, impl NCS1Pin>, + ncs: Peri<'d, impl NCSEither>, config: Config, ) -> Self { Self::new_inner( @@ -812,6 +819,7 @@ impl<'d, T: Instance> Xspi<'d, T, Blocking> { None, None, new_pin!(clk, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + ncs.sel(), new_pin!( ncs, AfType::output_pull(OutputType::PushPull, Speed::VeryHigh, Pull::Up) @@ -838,7 +846,7 @@ impl<'d, T: Instance> Xspi<'d, T, Blocking> { d5: Peri<'d, impl D5Pin>, d6: Peri<'d, impl D6Pin>, d7: Peri<'d, impl D7Pin>, - ncs: Peri<'d, impl NCS1Pin>, + ncs: Peri<'d, impl NCSEither>, config: Config, ) -> Self { Self::new_inner( @@ -860,6 +868,7 @@ impl<'d, T: Instance> Xspi<'d, T, Blocking> { None, None, new_pin!(clk, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + ncs.sel(), new_pin!( ncs, AfType::output_pull(OutputType::PushPull, Speed::VeryHigh, Pull::Up) @@ -882,7 +891,7 @@ impl<'d, T: Instance> Xspi<'d, T, Async> { clk: Peri<'d, impl CLKPin>, d0: Peri<'d, impl D0Pin>, d1: Peri<'d, impl D1Pin>, - ncs: Peri<'d, impl NCS1Pin>, + ncs: Peri<'d, impl NCSEither>, dma: Peri<'d, impl XDma>, config: Config, ) -> Self { @@ -905,6 +914,7 @@ impl<'d, T: Instance> Xspi<'d, T, Async> { None, None, new_pin!(clk, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + ncs.sel(), new_pin!(ncs, AfType::output(OutputType::PushPull, Speed::VeryHigh)), None, None, @@ -922,7 +932,7 @@ impl<'d, T: Instance> Xspi<'d, T, Async> { clk: Peri<'d, impl CLKPin>, d0: Peri<'d, impl D0Pin>, d1: Peri<'d, impl D1Pin>, - ncs: Peri<'d, impl NCS1Pin>, + ncs: Peri<'d, impl NCSEither>, dma: Peri<'d, impl XDma>, config: Config, ) -> Self { @@ -945,6 +955,7 @@ impl<'d, T: Instance> Xspi<'d, T, Async> { None, None, new_pin!(clk, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + ncs.sel(), new_pin!( ncs, AfType::output_pull(OutputType::PushPull, Speed::VeryHigh, Pull::Up) @@ -967,7 +978,7 @@ impl<'d, T: Instance> Xspi<'d, T, Async> { d1: Peri<'d, impl D1Pin>, d2: Peri<'d, impl D2Pin>, d3: Peri<'d, impl D3Pin>, - ncs: Peri<'d, impl NCS1Pin>, + ncs: Peri<'d, impl NCSEither>, dma: Peri<'d, impl XDma>, config: Config, ) -> Self { @@ -990,6 +1001,7 @@ impl<'d, T: Instance> Xspi<'d, T, Async> { None, None, new_pin!(clk, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + ncs.sel(), new_pin!( ncs, AfType::output_pull(OutputType::PushPull, Speed::VeryHigh, Pull::Up) @@ -1016,7 +1028,7 @@ impl<'d, T: Instance> Xspi<'d, T, Async> { d5: Peri<'d, impl D5Pin>, d6: Peri<'d, impl D6Pin>, d7: Peri<'d, impl D7Pin>, - ncs: Peri<'d, impl NCS1Pin>, + ncs: Peri<'d, impl NCSEither>, dma: Peri<'d, impl XDma>, config: Config, ) -> Self { @@ -1039,6 +1051,7 @@ impl<'d, T: Instance> Xspi<'d, T, Async> { None, None, new_pin!(clk, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + ncs.sel(), new_pin!( ncs, AfType::output_pull(OutputType::PushPull, Speed::VeryHigh, Pull::Up) @@ -1065,7 +1078,7 @@ impl<'d, T: Instance> Xspi<'d, T, Async> { d5: Peri<'d, impl D5Pin>, d6: Peri<'d, impl D6Pin>, d7: Peri<'d, impl D7Pin>, - ncs: Peri<'d, impl NCS1Pin>, + ncs: Peri<'d, impl NCSEither>, dma: Peri<'d, impl XDma>, config: Config, ) -> Self { @@ -1088,6 +1101,7 @@ impl<'d, T: Instance> Xspi<'d, T, Async> { None, None, new_pin!(clk, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + ncs.sel(), new_pin!( ncs, AfType::output_pull(OutputType::PushPull, Speed::VeryHigh, Pull::Up) @@ -1262,8 +1276,8 @@ impl<'d, T: Instance, M: PeriMode> Drop for Xspi<'d, T, M> { self.d13.as_ref().map(|x| x.set_as_disconnected()); self.d14.as_ref().map(|x| x.set_as_disconnected()); self.d15.as_ref().map(|x| x.set_as_disconnected()); - self.ncs1.as_ref().map(|x| x.set_as_disconnected()); - self.ncs2.as_ref().map(|x| x.set_as_disconnected()); + self.ncs.as_ref().map(|x| x.set_as_disconnected()); + self.ncs_alt.as_ref().map(|x| x.set_as_disconnected()); self.dqs0.as_ref().map(|x| x.set_as_disconnected()); self.dqs1.as_ref().map(|x| x.set_as_disconnected()); @@ -1320,12 +1334,17 @@ pin_trait!(D14Pin, Instance); pin_trait!(D15Pin, Instance); pin_trait!(DQS0Pin, Instance); pin_trait!(DQS1Pin, Instance); -pin_trait!(NCS1Pin, Instance); -pin_trait!(NCS2Pin, Instance); +pin_trait!(NCSPin, Instance); pin_trait!(CLKPin, Instance); pin_trait!(NCLKPin, Instance); dma_trait!(XDma, Instance); +/// Trait for either NCS1 or NCS2 pins +pub trait NCSEither: NCSPin { + /// Get the CSSEL for this NCS pin + fn sel(&self) -> u8; +} + // Hard-coded the xspi index, for SPIM #[cfg(xspim_v1)] impl SealedXspimInstance for peripherals::XSPI1 { From 5f7da4cfc8e1028a9cffb0c539d860a73e830f03 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Fri, 4 Apr 2025 15:41:35 +0800 Subject: [PATCH 0919/1217] stm32: xspi fixes and consistency Fix some incorrect DTR flags, fix _bit vs _Bit inconsistency (copied from qspi and ospi). Use the same NCS pullup for all constructors. xspi is now enabled in PWR register --- embassy-stm32/src/xspi/enums.rs | 8 ++++---- embassy-stm32/src/xspi/mod.rs | 29 +++++++++++++++++++++-------- 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/embassy-stm32/src/xspi/enums.rs b/embassy-stm32/src/xspi/enums.rs index e02ec797e..c96641180 100644 --- a/embassy-stm32/src/xspi/enums.rs +++ b/embassy-stm32/src/xspi/enums.rs @@ -160,9 +160,9 @@ impl Into for MemorySize { #[derive(Copy, Clone)] pub enum AddressSize { /// 8-bit address - _8Bit, + _8bit, /// 16-bit address - _16Bit, + _16bit, /// 24-bit address _24bit, /// 32-bit address @@ -172,8 +172,8 @@ pub enum AddressSize { impl Into for AddressSize { fn into(self) -> u8 { match self { - AddressSize::_8Bit => 0b00, - AddressSize::_16Bit => 0b01, + AddressSize::_8bit => 0b00, + AddressSize::_16bit => 0b01, AddressSize::_24bit => 0b10, AddressSize::_32bit => 0b11, } diff --git a/embassy-stm32/src/xspi/mod.rs b/embassy-stm32/src/xspi/mod.rs index bc3007fe8..44c10b961 100644 --- a/embassy-stm32/src/xspi/mod.rs +++ b/embassy-stm32/src/xspi/mod.rs @@ -122,17 +122,17 @@ impl Default for TransferConfig { Self { iwidth: XspiWidth::NONE, instruction: None, - isize: AddressSize::_8Bit, + isize: AddressSize::_8bit, idtr: false, adwidth: XspiWidth::NONE, address: None, - adsize: AddressSize::_8Bit, + adsize: AddressSize::_8bit, addtr: false, abwidth: XspiWidth::NONE, alternate_bytes: None, - absize: AddressSize::_8Bit, + absize: AddressSize::_8bit, abdtr: false, dwidth: XspiWidth::NONE, @@ -214,11 +214,11 @@ impl<'d, T: Instance, M: PeriMode> Xspi<'d, T, M> { w.set_isize(WccrIsize::from_bits(write_config.isize.into())); w.set_admode(WccrAdmode::from_bits(write_config.adwidth.into())); - w.set_addtr(write_config.idtr); + w.set_addtr(write_config.addtr); w.set_adsize(WccrAdsize::from_bits(write_config.adsize.into())); w.set_dmode(WccrDmode::from_bits(write_config.dwidth.into())); - w.set_ddtr(write_config.idtr); + w.set_ddtr(write_config.ddtr); w.set_abmode(WccrAbmode::from_bits(write_config.abwidth.into())); w.set_dqse(true); @@ -283,6 +283,13 @@ impl<'d, T: Instance, M: PeriMode> Xspi<'d, T, M> { width: XspiWidth, dual_quad: bool, ) -> Self { + // Enable the interface + match T::SPI_IDX { + 1 => crate::pac::PWR.csr2().modify(|r| r.set_en_xspim1(true)), + 2 => crate::pac::PWR.csr2().modify(|r| r.set_en_xspim2(true)), + _ => unreachable!(), + }; + #[cfg(xspim_v1)] { // RCC for xspim should be enabled before writing register @@ -447,7 +454,7 @@ impl<'d, T: Instance, M: PeriMode> Xspi<'d, T, M> { w.set_isize(CcrIsize::from_bits(command.isize.into())); w.set_admode(CcrAdmode::from_bits(command.adwidth.into())); - w.set_addtr(command.idtr); + w.set_addtr(command.addtr); w.set_adsize(CcrAdsize::from_bits(command.adsize.into())); w.set_dmode(CcrDmode::from_bits(command.dwidth.into())); @@ -686,7 +693,10 @@ impl<'d, T: Instance> Xspi<'d, T, Blocking> { None, new_pin!(clk, AfType::output(OutputType::PushPull, Speed::VeryHigh)), ncs.sel(), - new_pin!(ncs, AfType::output(OutputType::OpenDrain, Speed::VeryHigh)), + new_pin!( + ncs, + AfType::output_pull(OutputType::PushPull, Speed::VeryHigh, Pull::Up) + ), None, None, None, @@ -915,7 +925,10 @@ impl<'d, T: Instance> Xspi<'d, T, Async> { None, new_pin!(clk, AfType::output(OutputType::PushPull, Speed::VeryHigh)), ncs.sel(), - new_pin!(ncs, AfType::output(OutputType::PushPull, Speed::VeryHigh)), + new_pin!( + ncs, + AfType::output_pull(OutputType::PushPull, Speed::VeryHigh, Pull::Up) + ), None, None, None, From 43ef76b1b6c49085e1af06e0b1dd09a2d6c664e7 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Fri, 4 Apr 2025 15:47:32 +0800 Subject: [PATCH 0920/1217] Add stm32h7rs xpi_memory_mapped example Based on ospi_memory_mapped, targetting stm32h7s3 nucleo board. This works in single mode, no octo mode yet. --- .../stm32h7rs/src/bin/xspi_memory_mapped.rs | 448 ++++++++++++++++++ 1 file changed, 448 insertions(+) create mode 100644 examples/stm32h7rs/src/bin/xspi_memory_mapped.rs diff --git a/examples/stm32h7rs/src/bin/xspi_memory_mapped.rs b/examples/stm32h7rs/src/bin/xspi_memory_mapped.rs new file mode 100644 index 000000000..88d914180 --- /dev/null +++ b/examples/stm32h7rs/src/bin/xspi_memory_mapped.rs @@ -0,0 +1,448 @@ +#![no_main] +#![no_std] + +//! For Nucleo STM32H7S3L8 MB1737, has MX25UW25645GXDI00 +//! +//! TODO: Currently this only uses single SPI, pending flash chip documentation for octo SPI. + +use defmt::info; +use embassy_executor::Spawner; +use embassy_stm32::gpio::{Level, Output, Speed}; +use embassy_stm32::mode::Blocking; +use embassy_stm32::time::Hertz; +use embassy_stm32::xspi::{ + AddressSize, ChipSelectHighTime, DummyCycles, FIFOThresholdLevel, Instance, MemorySize, MemoryType, TransferConfig, + WrapSize, Xspi, XspiWidth, +}; +use embassy_stm32::Config; +use embassy_time::Timer; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + // RCC config + let mut config = Config::default(); + { + use embassy_stm32::rcc::*; + config.rcc.hse = Some(Hse { + freq: Hertz(24_000_000), + mode: HseMode::Oscillator, + }); + config.rcc.pll1 = Some(Pll { + source: PllSource::HSE, + prediv: PllPreDiv::DIV3, + mul: PllMul::MUL150, + divp: Some(PllDiv::DIV2), + divq: None, + divr: None, + }); + config.rcc.sys = Sysclk::PLL1_P; // 600 Mhz + config.rcc.ahb_pre = AHBPrescaler::DIV2; // 300 Mhz + config.rcc.apb1_pre = APBPrescaler::DIV2; // 150 Mhz + config.rcc.apb2_pre = APBPrescaler::DIV2; // 150 Mhz + config.rcc.apb4_pre = APBPrescaler::DIV2; // 150 Mhz + config.rcc.apb5_pre = APBPrescaler::DIV2; // 150 Mhz + config.rcc.voltage_scale = VoltageScale::HIGH; + } + + // Initialize peripherals + let p = embassy_stm32::init(config); + + let spi_config = embassy_stm32::xspi::Config { + fifo_threshold: FIFOThresholdLevel::_4Bytes, + memory_type: MemoryType::Macronix, + delay_hold_quarter_cycle: true, + // memory_type: MemoryType::Micron, + // delay_hold_quarter_cycle: false, + device_size: MemorySize::_32MiB, + chip_select_high_time: ChipSelectHighTime::_2Cycle, + free_running_clock: false, + clock_mode: false, + wrap_size: WrapSize::None, + // 300mhz / (4+1) = 60mhz. Unsure the limit, need to find a MX25UW25645GXDI00 datasheet. + clock_prescaler: 3, + sample_shifting: false, + chip_select_boundary: 0, + max_transfer: 0, + refresh: 0, + }; + + let mut cor = cortex_m::Peripherals::take().unwrap(); + + // Not necessary, but recommended if using XIP + cor.SCB.enable_icache(); + cor.SCB.enable_dcache(&mut cor.CPUID); + + let xspi = embassy_stm32::xspi::Xspi::new_blocking_xspi( + p.XSPI2, p.PN6, p.PN2, p.PN3, p.PN4, p.PN5, p.PN8, p.PN9, p.PN10, p.PN11, p.PN1, spi_config, + ); + + let mut flash = FlashMemory::new(xspi).await; + + let flash_id = flash.read_id(); + info!("FLASH ID: {=[u8]:x}", flash_id); + + let mut wr_buf = [0u8; 8]; + for i in 0..8 { + wr_buf[i] = 0x90 + i as u8; + } + let mut rd_buf = [0u8; 8]; + flash.erase_sector(0).await; + flash.write_memory(0, &wr_buf, true).await; + flash.read_memory(0, &mut rd_buf, true); + info!("WRITE BUF: {=[u8]:#X}", wr_buf); + info!("READ BUF: {=[u8]:#X}", rd_buf); + flash.enable_mm().await; + info!("Enabled memory mapped mode"); + + let first_u32 = unsafe { *(0x70000000 as *const u32) }; + assert_eq!(first_u32, 0x93929190); + info!("first_u32 {:08x}", first_u32); + + let second_u32 = unsafe { *(0x70000004 as *const u32) }; + assert_eq!(second_u32, 0x97969594); + info!("second_u32 {:08x}", first_u32); + + flash.disable_mm().await; + info!("Disabled memory mapped mode"); + + info!("DONE"); + // Output pin PE3 + let mut led = Output::new(p.PE3, Level::Low, Speed::Low); + + loop { + led.toggle(); + Timer::after_millis(1000).await; + } +} + +const MEMORY_PAGE_SIZE: usize = 8; + +const CMD_READ: u8 = 0x0B; +const _CMD_QUAD_READ: u8 = 0x6B; + +const CMD_WRITE_PG: u8 = 0x02; +const _CMD_QUAD_WRITE_PG: u8 = 0x32; + +const CMD_READ_ID: u8 = 0x9F; +const CMD_READ_ID_OCTO: u16 = 0x9F60; + +const CMD_ENABLE_RESET: u8 = 0x66; +const CMD_RESET: u8 = 0x99; + +const CMD_WRITE_ENABLE: u8 = 0x06; + +const CMD_CHIP_ERASE: u8 = 0xC7; +const CMD_SECTOR_ERASE: u8 = 0x20; +const CMD_BLOCK_ERASE_32K: u8 = 0x52; +const CMD_BLOCK_ERASE_64K: u8 = 0xD8; + +const CMD_READ_SR: u8 = 0x05; +const CMD_READ_CR: u8 = 0x35; + +const CMD_WRITE_SR: u8 = 0x01; +const CMD_WRITE_CR: u8 = 0x31; + +/// Implementation of access to flash chip. +/// +/// Chip commands are hardcoded as it depends on used chip. +/// This targets a MX25UW25645GXDI00. +pub struct FlashMemory { + xspi: Xspi<'static, I, Blocking>, +} + +impl FlashMemory { + pub async fn new(xspi: Xspi<'static, I, Blocking>) -> Self { + let mut memory = Self { xspi }; + + memory.reset_memory().await; + memory.enable_octo(); + memory + } + + async fn qpi_mode(&mut self) { + // Enter qpi mode + self.exec_command(0x38).await; + + // Set read param + let transaction = TransferConfig { + iwidth: XspiWidth::QUAD, + dwidth: XspiWidth::QUAD, + instruction: Some(0xC0), + ..Default::default() + }; + self.enable_write().await; + self.xspi.blocking_write(&[0x30_u8], transaction).unwrap(); + self.wait_write_finish(); + } + + pub async fn disable_mm(&mut self) { + self.xspi.disable_memory_mapped_mode(); + } + + pub async fn enable_mm(&mut self) { + self.qpi_mode().await; + + let read_config = TransferConfig { + iwidth: XspiWidth::SING, + isize: AddressSize::_8bit, + adwidth: XspiWidth::SING, + adsize: AddressSize::_24bit, + dwidth: XspiWidth::SING, + instruction: Some(CMD_READ as u32), + dummy: DummyCycles::_8, + ..Default::default() + }; + + let write_config = TransferConfig { + iwidth: XspiWidth::SING, + isize: AddressSize::_8bit, + adwidth: XspiWidth::SING, + adsize: AddressSize::_24bit, + dwidth: XspiWidth::SING, + instruction: Some(CMD_WRITE_PG as u32), + dummy: DummyCycles::_0, + ..Default::default() + }; + self.xspi.enable_memory_mapped_mode(read_config, write_config).unwrap(); + } + + fn enable_octo(&mut self) { + let cr = self.read_cr(); + // info!("Read cr: {:x}", cr); + self.write_cr(cr | 0x02); + // info!("Read cr after writing: {:x}", cr); + } + + pub fn disable_octo(&mut self) { + let cr = self.read_cr(); + self.write_cr(cr & (!(0x02))); + } + + async fn exec_command_4(&mut self, cmd: u8) { + let transaction = TransferConfig { + iwidth: XspiWidth::QUAD, + adwidth: XspiWidth::NONE, + // adsize: AddressSize::_24bit, + dwidth: XspiWidth::NONE, + instruction: Some(cmd as u32), + address: None, + dummy: DummyCycles::_0, + ..Default::default() + }; + self.xspi.blocking_command(&transaction).unwrap(); + } + + async fn exec_command(&mut self, cmd: u8) { + let transaction = TransferConfig { + iwidth: XspiWidth::SING, + adwidth: XspiWidth::NONE, + // adsize: AddressSize::_24bit, + dwidth: XspiWidth::NONE, + instruction: Some(cmd as u32), + address: None, + dummy: DummyCycles::_0, + ..Default::default() + }; + // info!("Excuting command: {:x}", transaction.instruction); + self.xspi.blocking_command(&transaction).unwrap(); + } + + pub async fn reset_memory(&mut self) { + self.exec_command_4(CMD_ENABLE_RESET).await; + self.exec_command_4(CMD_RESET).await; + self.exec_command(CMD_ENABLE_RESET).await; + self.exec_command(CMD_RESET).await; + self.wait_write_finish(); + } + + pub async fn enable_write(&mut self) { + self.exec_command(CMD_WRITE_ENABLE).await; + } + + pub fn read_id(&mut self) -> [u8; 3] { + let mut buffer = [0; 3]; + let transaction: TransferConfig = TransferConfig { + iwidth: XspiWidth::SING, + isize: AddressSize::_8bit, + adwidth: XspiWidth::NONE, + // adsize: AddressSize::_24bit, + dwidth: XspiWidth::SING, + instruction: Some(CMD_READ_ID as u32), + ..Default::default() + }; + // info!("Reading id: 0x{:X}", transaction.instruction); + self.xspi.blocking_read(&mut buffer, transaction).unwrap(); + buffer + } + + pub fn read_id_8(&mut self) -> [u8; 3] { + let mut buffer = [0; 3]; + let transaction: TransferConfig = TransferConfig { + iwidth: XspiWidth::OCTO, + isize: AddressSize::_16bit, + adwidth: XspiWidth::OCTO, + address: Some(0), + adsize: AddressSize::_32bit, + dwidth: XspiWidth::OCTO, + instruction: Some(CMD_READ_ID_OCTO as u32), + dummy: DummyCycles::_4, + ..Default::default() + }; + info!("Reading id: {:#X}", transaction.instruction); + self.xspi.blocking_read(&mut buffer, transaction).unwrap(); + buffer + } + + pub fn read_memory(&mut self, addr: u32, buffer: &mut [u8], use_dma: bool) { + let transaction = TransferConfig { + iwidth: XspiWidth::SING, + adwidth: XspiWidth::SING, + adsize: AddressSize::_24bit, + dwidth: XspiWidth::SING, + instruction: Some(CMD_READ as u32), + dummy: DummyCycles::_8, + // dwidth: XspiWidth::QUAD, + // instruction: Some(CMD_QUAD_READ as u32), + // dummy: DummyCycles::_8, + address: Some(addr), + ..Default::default() + }; + if use_dma { + self.xspi.blocking_read(buffer, transaction).unwrap(); + } else { + self.xspi.blocking_read(buffer, transaction).unwrap(); + } + } + + fn wait_write_finish(&mut self) { + while (self.read_sr() & 0x01) != 0 {} + } + + async fn perform_erase(&mut self, addr: u32, cmd: u8) { + let transaction = TransferConfig { + iwidth: XspiWidth::SING, + adwidth: XspiWidth::SING, + adsize: AddressSize::_24bit, + dwidth: XspiWidth::NONE, + instruction: Some(cmd as u32), + address: Some(addr), + dummy: DummyCycles::_0, + ..Default::default() + }; + self.enable_write().await; + self.xspi.blocking_command(&transaction).unwrap(); + self.wait_write_finish(); + } + + pub async fn erase_sector(&mut self, addr: u32) { + self.perform_erase(addr, CMD_SECTOR_ERASE).await; + } + + pub async fn erase_block_32k(&mut self, addr: u32) { + self.perform_erase(addr, CMD_BLOCK_ERASE_32K).await; + } + + pub async fn erase_block_64k(&mut self, addr: u32) { + self.perform_erase(addr, CMD_BLOCK_ERASE_64K).await; + } + + pub async fn erase_chip(&mut self) { + self.exec_command(CMD_CHIP_ERASE).await; + } + + async fn write_page(&mut self, addr: u32, buffer: &[u8], len: usize, use_dma: bool) { + assert!( + (len as u32 + (addr & 0x000000ff)) <= MEMORY_PAGE_SIZE as u32, + "write_page(): page write length exceeds page boundary (len = {}, addr = {:X}", + len, + addr + ); + + let transaction = TransferConfig { + iwidth: XspiWidth::SING, + adsize: AddressSize::_24bit, + adwidth: XspiWidth::SING, + dwidth: XspiWidth::SING, + instruction: Some(CMD_WRITE_PG as u32), + // dwidth: XspiWidth::QUAD, + // instruction: Some(CMD_QUAD_WRITE_PG as u32), + address: Some(addr), + dummy: DummyCycles::_0, + ..Default::default() + }; + self.enable_write().await; + if use_dma { + self.xspi.blocking_write(buffer, transaction).unwrap(); + } else { + self.xspi.blocking_write(buffer, transaction).unwrap(); + } + self.wait_write_finish(); + } + + pub async fn write_memory(&mut self, addr: u32, buffer: &[u8], use_dma: bool) { + let mut left = buffer.len(); + let mut place = addr; + let mut chunk_start = 0; + + while left > 0 { + let max_chunk_size = MEMORY_PAGE_SIZE - (place & 0x000000ff) as usize; + let chunk_size = if left >= max_chunk_size { max_chunk_size } else { left }; + let chunk = &buffer[chunk_start..(chunk_start + chunk_size)]; + self.write_page(place, chunk, chunk_size, use_dma).await; + place += chunk_size as u32; + left -= chunk_size; + chunk_start += chunk_size; + } + } + + fn read_register(&mut self, cmd: u8) -> u8 { + let mut buffer = [0; 1]; + let transaction: TransferConfig = TransferConfig { + iwidth: XspiWidth::SING, + isize: AddressSize::_8bit, + adwidth: XspiWidth::NONE, + adsize: AddressSize::_24bit, + dwidth: XspiWidth::SING, + instruction: Some(cmd as u32), + address: None, + dummy: DummyCycles::_0, + ..Default::default() + }; + self.xspi.blocking_read(&mut buffer, transaction).unwrap(); + // info!("Read w25q64 register: 0x{:x}", buffer[0]); + buffer[0] + } + + fn write_register(&mut self, cmd: u8, value: u8) { + let buffer = [value; 1]; + let transaction: TransferConfig = TransferConfig { + iwidth: XspiWidth::SING, + isize: AddressSize::_8bit, + instruction: Some(cmd as u32), + adsize: AddressSize::_24bit, + adwidth: XspiWidth::NONE, + dwidth: XspiWidth::SING, + address: None, + dummy: DummyCycles::_0, + ..Default::default() + }; + self.xspi.blocking_write(&buffer, transaction).unwrap(); + } + + pub fn read_sr(&mut self) -> u8 { + self.read_register(CMD_READ_SR) + } + + pub fn read_cr(&mut self) -> u8 { + self.read_register(CMD_READ_CR) + } + + pub fn write_sr(&mut self, value: u8) { + self.write_register(CMD_WRITE_SR, value); + } + + pub fn write_cr(&mut self, value: u8) { + self.write_register(CMD_WRITE_CR, value); + } +} From eee2d8c84d318b36a80759aad26e2303965c0565 Mon Sep 17 00:00:00 2001 From: Gabriel Smith Date: Fri, 28 Mar 2025 17:20:36 +0000 Subject: [PATCH 0921/1217] stm32/timer: Merge channel typestate structs --- embassy-stm32/src/timer/input_capture.rs | 10 +--------- embassy-stm32/src/timer/mod.rs | 9 +++++++++ embassy-stm32/src/timer/qei.rs | 6 +----- 3 files changed, 11 insertions(+), 14 deletions(-) diff --git a/embassy-stm32/src/timer/input_capture.rs b/embassy-stm32/src/timer/input_capture.rs index b7c13343c..4d59ac3dc 100644 --- a/embassy-stm32/src/timer/input_capture.rs +++ b/embassy-stm32/src/timer/input_capture.rs @@ -12,20 +12,12 @@ use super::{ CaptureCompareInterruptHandler, Channel, Channel1Pin, Channel2Pin, Channel3Pin, Channel4Pin, GeneralInstance4Channel, }; +pub use super::{Ch1, Ch2, Ch3, Ch4}; use crate::gpio::{AfType, AnyPin, Pull}; use crate::interrupt::typelevel::{Binding, Interrupt}; use crate::time::Hertz; use crate::Peripheral; -/// Channel 1 marker type. -pub enum Ch1 {} -/// Channel 2 marker type. -pub enum Ch2 {} -/// Channel 3 marker type. -pub enum Ch3 {} -/// Channel 4 marker type. -pub enum Ch4 {} - /// Capture pin wrapper. /// /// This wraps a pin to make it usable with capture. diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs index 97740c2ed..645556e8c 100644 --- a/embassy-stm32/src/timer/mod.rs +++ b/embassy-stm32/src/timer/mod.rs @@ -41,6 +41,15 @@ impl Channel { } } +/// Channel 1 marker type. +pub enum Ch1 {} +/// Channel 2 marker type. +pub enum Ch2 {} +/// Channel 3 marker type. +pub enum Ch3 {} +/// Channel 4 marker type. +pub enum Ch4 {} + /// Amount of bits of a timer. #[derive(Clone, Copy, PartialEq, Eq, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] diff --git a/embassy-stm32/src/timer/qei.rs b/embassy-stm32/src/timer/qei.rs index fc5835414..4fd883540 100644 --- a/embassy-stm32/src/timer/qei.rs +++ b/embassy-stm32/src/timer/qei.rs @@ -6,6 +6,7 @@ use embassy_hal_internal::{into_ref, PeripheralRef}; use stm32_metapac::timer::vals; use super::low_level::Timer; +pub use super::{Ch1, Ch2}; use super::{Channel1Pin, Channel2Pin, GeneralInstance4Channel}; use crate::gpio::{AfType, AnyPin, Pull}; use crate::Peripheral; @@ -18,11 +19,6 @@ pub enum Direction { Downcounting, } -/// Channel 1 marker type. -pub enum Ch1 {} -/// Channel 2 marker type. -pub enum Ch2 {} - /// Wrapper for using a pin with QEI. pub struct QeiPin<'d, T, Channel> { _pin: PeripheralRef<'d, AnyPin>, From f8e5c902665edf02f78fbb223ce14b3743fc543b Mon Sep 17 00:00:00 2001 From: Gabriel Smith Date: Wed, 2 Apr 2025 18:30:06 +0000 Subject: [PATCH 0922/1217] stm32/timer: Support one pulse mode Currently does not support output pins so it really is only useful to create delayed interrupts based on external signals. --- embassy-stm32/src/timer/low_level.rs | 30 +++ embassy-stm32/src/timer/mod.rs | 1 + embassy-stm32/src/timer/one_pulse.rs | 384 +++++++++++++++++++++++++++ 3 files changed, 415 insertions(+) create mode 100644 embassy-stm32/src/timer/one_pulse.rs diff --git a/embassy-stm32/src/timer/low_level.rs b/embassy-stm32/src/timer/low_level.rs index 5b0c95109..524c64c14 100644 --- a/embassy-stm32/src/timer/low_level.rs +++ b/embassy-stm32/src/timer/low_level.rs @@ -425,6 +425,36 @@ impl<'d, T: GeneralInstance1Channel> Timer<'d, T> { TimerBits::Bits32 => self.regs_gp32_unchecked().arr().read(), } } + + /// Set the max compare value. + /// + /// An update event is generated to load the new value. The update event is + /// generated such that it will not cause an interrupt or DMA request. + pub fn set_max_compare_value(&self, ticks: u32) { + match T::BITS { + TimerBits::Bits16 => { + let arr = unwrap!(u16::try_from(ticks)); + + let regs = self.regs_1ch(); + regs.arr().write(|r| r.set_arr(arr)); + + regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTER_ONLY)); + regs.egr().write(|r| r.set_ug(true)); + regs.cr1().modify(|r| r.set_urs(vals::Urs::ANY_EVENT)); + } + #[cfg(not(stm32l0))] + TimerBits::Bits32 => { + let arr = ticks; + + let regs = self.regs_gp32_unchecked(); + regs.arr().write_value(arr); + + regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTER_ONLY)); + regs.egr().write(|r| r.set_ug(true)); + regs.cr1().modify(|r| r.set_urs(vals::Urs::ANY_EVENT)); + } + } + } } impl<'d, T: GeneralInstance2Channel> Timer<'d, T> { diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs index 645556e8c..4a5aa5e00 100644 --- a/embassy-stm32/src/timer/mod.rs +++ b/embassy-stm32/src/timer/mod.rs @@ -9,6 +9,7 @@ use embassy_sync::waitqueue::AtomicWaker; pub mod complementary_pwm; pub mod input_capture; pub mod low_level; +pub mod one_pulse; pub mod pwm_input; pub mod qei; pub mod simple_pwm; diff --git a/embassy-stm32/src/timer/one_pulse.rs b/embassy-stm32/src/timer/one_pulse.rs new file mode 100644 index 000000000..43ba3dedf --- /dev/null +++ b/embassy-stm32/src/timer/one_pulse.rs @@ -0,0 +1,384 @@ +//! One pulse mode driver. + +use core::future::Future; +use core::marker::PhantomData; +use core::mem::ManuallyDrop; +use core::pin::Pin; +use core::task::{Context, Poll}; + +use super::low_level::{ + CountingMode, FilterValue, InputCaptureMode, InputTISelection, SlaveMode, Timer, TriggerSource, +}; +use super::{ + CaptureCompareInterruptHandler, Channel, Channel1Pin, Channel2Pin, ExternalTriggerPin, GeneralInstance4Channel, +}; +pub use super::{Ch1, Ch2}; +use crate::gpio::{AfType, AnyPin, Pull}; +use crate::interrupt::typelevel::{Binding, Interrupt}; +use crate::pac::timer::vals::Etp; +use crate::time::Hertz; +use crate::{into_ref, Peripheral, PeripheralRef}; + +/// External input marker type. +pub enum Ext {} + +/// External trigger pin trigger polarity. +#[derive(Clone, Copy)] +pub enum ExternalTriggerPolarity { + /// Rising edge only. + Rising, + /// Falling edge only. + Falling, +} + +impl From for Etp { + fn from(mode: ExternalTriggerPolarity) -> Self { + match mode { + ExternalTriggerPolarity::Rising => 0.into(), + ExternalTriggerPolarity::Falling => 1.into(), + } + } +} + +/// Trigger pin wrapper. +/// +/// This wraps a pin to make it usable as a timer trigger. +pub struct TriggerPin<'d, T, C> { + _pin: PeripheralRef<'d, AnyPin>, + phantom: PhantomData<(T, C)>, +} + +macro_rules! channel_impl { + ($new_chx:ident, $channel:ident, $pin_trait:ident) => { + impl<'d, T: GeneralInstance4Channel> TriggerPin<'d, T, $channel> { + #[doc = concat!("Create a new ", stringify!($channel), " trigger pin instance.")] + pub fn $new_chx(pin: impl Peripheral

> + 'd, pull: Pull) -> Self { + into_ref!(pin); + pin.set_as_af(pin.af_num(), AfType::input(pull)); + TriggerPin { + _pin: pin.map_into(), + phantom: PhantomData, + } + } + } + }; +} + +channel_impl!(new_ch1, Ch1, Channel1Pin); +channel_impl!(new_ch2, Ch2, Channel2Pin); +channel_impl!(new_ext, Ext, ExternalTriggerPin); + +/// One pulse driver. +/// +/// Generates a pulse after a trigger and some configurable delay. +pub struct OnePulse<'d, T: GeneralInstance4Channel> { + inner: Timer<'d, T>, +} + +impl<'d, T: GeneralInstance4Channel> OnePulse<'d, T> { + /// Create a new one pulse driver. + /// + /// The pulse is triggered by a channel 1 input pin on both rising and + /// falling edges. Channel 1 will unusable as an output. + pub fn new_ch1_edge_detect( + tim: impl Peripheral

+ 'd, + _pin: TriggerPin<'d, T, Ch1>, + _irq: impl Binding> + 'd, + freq: Hertz, + pulse_end: u32, + counting_mode: CountingMode, + ) -> Self { + let mut this = Self { inner: Timer::new(tim) }; + + this.inner.set_trigger_source(TriggerSource::TI1F_ED); + this.inner + .set_input_ti_selection(Channel::Ch1, InputTISelection::Normal); + this.inner + .set_input_capture_filter(Channel::Ch1, FilterValue::NO_FILTER); + this.new_inner(freq, pulse_end, counting_mode); + + this + } + + /// Create a new one pulse driver. + /// + /// The pulse is triggered by a channel 1 input pin. Channel 1 will unusable + /// as an output. + pub fn new_ch1( + tim: impl Peripheral

+ 'd, + _pin: TriggerPin<'d, T, Ch1>, + _irq: impl Binding> + 'd, + freq: Hertz, + pulse_end: u32, + counting_mode: CountingMode, + capture_mode: InputCaptureMode, + ) -> Self { + let mut this = Self { inner: Timer::new(tim) }; + + this.inner.set_trigger_source(TriggerSource::TI1FP1); + this.inner + .set_input_ti_selection(Channel::Ch1, InputTISelection::Normal); + this.inner + .set_input_capture_filter(Channel::Ch1, FilterValue::NO_FILTER); + this.inner.set_input_capture_mode(Channel::Ch1, capture_mode); + this.new_inner(freq, pulse_end, counting_mode); + + this + } + + /// Create a new one pulse driver. + /// + /// The pulse is triggered by a channel 2 input pin. Channel 2 will unusable + /// as an output. + pub fn new_ch2( + tim: impl Peripheral

+ 'd, + _pin: TriggerPin<'d, T, Ch1>, + _irq: impl Binding> + 'd, + freq: Hertz, + pulse_end: u32, + counting_mode: CountingMode, + capture_mode: InputCaptureMode, + ) -> Self { + let mut this = Self { inner: Timer::new(tim) }; + + this.inner.set_trigger_source(TriggerSource::TI2FP2); + this.inner + .set_input_ti_selection(Channel::Ch2, InputTISelection::Normal); + this.inner + .set_input_capture_filter(Channel::Ch2, FilterValue::NO_FILTER); + this.inner.set_input_capture_mode(Channel::Ch2, capture_mode); + this.new_inner(freq, pulse_end, counting_mode); + + this + } + + /// Create a new one pulse driver. + /// + /// The pulse is triggered by a external trigger input pin. + pub fn new_ext( + tim: impl Peripheral

+ 'd, + _pin: TriggerPin<'d, T, Ext>, + _irq: impl Binding> + 'd, + freq: Hertz, + pulse_end: u32, + counting_mode: CountingMode, + polarity: ExternalTriggerPolarity, + ) -> Self { + let mut this = Self { inner: Timer::new(tim) }; + + this.inner.regs_gp16().smcr().modify(|r| { + r.set_etp(polarity.into()); + // No pre-scaling + r.set_etps(0.into()); + // No filtering + r.set_etf(FilterValue::NO_FILTER); + }); + this.inner.set_trigger_source(TriggerSource::ETRF); + this.new_inner(freq, pulse_end, counting_mode); + + this + } + + fn new_inner(&mut self, freq: Hertz, pulse_end: u32, counting_mode: CountingMode) { + self.inner.set_counting_mode(counting_mode); + self.inner.set_tick_freq(freq); + self.inner.set_max_compare_value(pulse_end); + self.inner.regs_core().cr1().modify(|r| r.set_opm(true)); + // Required for advanced timers, see GeneralInstance4Channel for details + self.inner.enable_outputs(); + self.inner.set_slave_mode(SlaveMode::TRIGGER_MODE); + + T::CaptureCompareInterrupt::unpend(); + unsafe { T::CaptureCompareInterrupt::enable() }; + } + + /// Get the end of the pulse in ticks from the trigger. + pub fn pulse_end(&self) -> u32 { + let max = self.inner.get_max_compare_value(); + assert!(max < u32::MAX); + max + 1 + } + + /// Set the end of the pulse in ticks from the trigger. + pub fn set_pulse_end(&mut self, ticks: u32) { + self.inner.set_max_compare_value(ticks) + } + + /// Reset the timer on each trigger + #[cfg(not(stm32l0))] + pub fn set_reset_on_trigger(&mut self, reset: bool) { + let slave_mode = if reset { + SlaveMode::COMBINED_RESET_TRIGGER + } else { + SlaveMode::TRIGGER_MODE + }; + self.inner.set_slave_mode(slave_mode); + } + + /// Get a single channel + /// + /// If you need to use multiple channels, use [`Self::split`]. + pub fn channel(&mut self, channel: Channel) -> OnePulseChannel<'_, T> { + OnePulseChannel { + inner: unsafe { self.inner.clone_unchecked() }, + channel, + } + } + + /// Channel 1 + /// + /// This is just a convenience wrapper around [`Self::channel`]. + /// + /// If you need to use multiple channels, use [`Self::split`]. + pub fn ch1(&mut self) -> OnePulseChannel<'_, T> { + self.channel(Channel::Ch1) + } + + /// Channel 2 + /// + /// This is just a convenience wrapper around [`Self::channel`]. + /// + /// If you need to use multiple channels, use [`Self::split`]. + pub fn ch2(&mut self) -> OnePulseChannel<'_, T> { + self.channel(Channel::Ch2) + } + + /// Channel 3 + /// + /// This is just a convenience wrapper around [`Self::channel`]. + /// + /// If you need to use multiple channels, use [`Self::split`]. + pub fn ch3(&mut self) -> OnePulseChannel<'_, T> { + self.channel(Channel::Ch3) + } + + /// Channel 4 + /// + /// This is just a convenience wrapper around [`Self::channel`]. + /// + /// If you need to use multiple channels, use [`Self::split`]. + pub fn ch4(&mut self) -> OnePulseChannel<'_, T> { + self.channel(Channel::Ch4) + } + + /// Splits a [`OnePulse`] into four output channels. + // TODO: I hate the name "split" + pub fn split(self) -> OnePulseChannels<'static, T> + where + // must be static because the timer will never be dropped/disabled + 'd: 'static, + { + // without this, the timer would be disabled at the end of this function + let timer = ManuallyDrop::new(self.inner); + + let ch = |channel| OnePulseChannel { + inner: unsafe { timer.clone_unchecked() }, + channel, + }; + + OnePulseChannels { + ch1: ch(Channel::Ch1), + ch2: ch(Channel::Ch2), + ch3: ch(Channel::Ch3), + ch4: ch(Channel::Ch4), + } + } +} + +/// A group of four [`OnePulseChannel`]s, obtained from [`OnePulse::split`]. +pub struct OnePulseChannels<'d, T: GeneralInstance4Channel> { + /// Channel 1 + pub ch1: OnePulseChannel<'d, T>, + /// Channel 2 + pub ch2: OnePulseChannel<'d, T>, + /// Channel 3 + pub ch3: OnePulseChannel<'d, T>, + /// Channel 4 + pub ch4: OnePulseChannel<'d, T>, +} + +/// A single channel of a one pulse-configured timer, obtained from +/// [`OnePulse::split`],[`OnePulse::channel`], [`OnePulse::ch1`], etc. +/// +/// It is not possible to change the pulse end tick because the end tick +/// configuration is shared with all four channels. +pub struct OnePulseChannel<'d, T: GeneralInstance4Channel> { + inner: ManuallyDrop>, + channel: Channel, +} + +impl<'d, T: GeneralInstance4Channel> OnePulseChannel<'d, T> { + /// Get the end of the pulse in ticks from the trigger. + pub fn pulse_end(&self) -> u32 { + let max = self.inner.get_max_compare_value(); + assert!(max < u32::MAX); + max + 1 + } + + /// Get the width of the pulse in ticks. + pub fn pulse_width(&mut self) -> u32 { + self.pulse_end().saturating_sub(self.pulse_delay()) + } + + /// Get the start of the pulse in ticks from the trigger. + pub fn pulse_delay(&mut self) -> u32 { + self.inner.get_compare_value(self.channel) + } + + /// Set the start of the pulse in ticks from the trigger. + pub fn set_pulse_delay(&mut self, delay: u32) { + assert!(delay <= self.pulse_end()); + self.inner.set_compare_value(self.channel, delay); + } + + /// Set the pulse width in ticks. + pub fn set_pulse_width(&mut self, width: u32) { + assert!(width <= self.pulse_end()); + self.set_pulse_delay(self.pulse_end() - width); + } + + /// Waits until the trigger and following delay has passed. + pub async fn wait_for_pulse_start(&mut self) { + self.inner.enable_input_interrupt(self.channel, true); + + OnePulseFuture:: { + channel: self.channel, + phantom: PhantomData, + } + .await + } +} + +#[must_use = "futures do nothing unless you `.await` or poll them"] +struct OnePulseFuture { + channel: Channel, + phantom: PhantomData, +} + +impl<'d, T: GeneralInstance4Channel> Drop for OnePulseFuture { + fn drop(&mut self) { + critical_section::with(|_| { + let regs = unsafe { crate::pac::timer::TimGp16::from_ptr(T::regs()) }; + + // disable interrupt enable + regs.dier().modify(|w| w.set_ccie(self.channel.index(), false)); + }); + } +} + +impl<'d, T: GeneralInstance4Channel> Future for OnePulseFuture { + type Output = (); + + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + T::state().cc_waker[self.channel.index()].register(cx.waker()); + + let regs = unsafe { crate::pac::timer::TimGp16::from_ptr(T::regs()) }; + + let dier = regs.dier().read(); + if !dier.ccie(self.channel.index()) { + Poll::Ready(()) + } else { + Poll::Pending + } + } +} From e1e7a5ddb5b83ac865cae15f7204f8ca5b7a43f2 Mon Sep 17 00:00:00 2001 From: Kaspar Schleiser Date: Fri, 4 Apr 2025 22:07:02 +0200 Subject: [PATCH 0923/1217] embassy-time: don't select `critical-section` impl for std --- embassy-time/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-time/Cargo.toml b/embassy-time/Cargo.toml index 7aaae89f9..80a39dbf5 100644 --- a/embassy-time/Cargo.toml +++ b/embassy-time/Cargo.toml @@ -45,7 +45,7 @@ defmt-timestamp-uptime-tus = ["defmt"] ## Create a `MockDriver` that can be manually advanced for testing purposes. mock-driver = ["tick-hz-1_000_000", "dep:embassy-time-queue-utils"] ## Create a time driver for `std` environments. -std = ["tick-hz-1_000_000", "critical-section/std", "dep:embassy-time-queue-utils"] +std = ["tick-hz-1_000_000", "dep:embassy-time-queue-utils"] ## Create a time driver for WASM. wasm = ["dep:wasm-bindgen", "dep:js-sys", "dep:wasm-timer", "tick-hz-1_000_000", "dep:embassy-time-queue-utils"] From 3f87ce6f50865b04a56b50476aa6cc7a0f92f0e9 Mon Sep 17 00:00:00 2001 From: Kaspar Schleiser Date: Fri, 19 Jan 2024 11:03:00 +0100 Subject: [PATCH 0924/1217] embassy-executor: introduce `Executor::id()` --- embassy-executor/src/raw/mod.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs index 5b1f33a0e..56faa911d 100644 --- a/embassy-executor/src/raw/mod.rs +++ b/embassy-executor/src/raw/mod.rs @@ -555,6 +555,11 @@ impl Executor { pub fn spawner(&'static self) -> super::Spawner { super::Spawner::new(self) } + + /// Get a unique ID for this Executor. + pub fn id(&'static self) -> usize { + &self.inner as *const SyncExecutor as usize + } } /// Wake a task by `TaskRef`. From 89f3566419a4987a5fa1420993322456c1849fef Mon Sep 17 00:00:00 2001 From: Kaspar Schleiser Date: Mon, 22 Jan 2024 21:50:34 +0100 Subject: [PATCH 0925/1217] embassy_executor: introduce `Spawner::executor_id()` --- embassy-executor/src/spawner.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/embassy-executor/src/spawner.rs b/embassy-executor/src/spawner.rs index 9817a2870..ff243081c 100644 --- a/embassy-executor/src/spawner.rs +++ b/embassy-executor/src/spawner.rs @@ -173,6 +173,11 @@ impl Spawner { pub fn make_send(&self) -> SendSpawner { SendSpawner::new(&self.executor.inner) } + + /// Return the unique ID of this Spawner's Executor. + pub fn executor_id(&self) -> usize { + self.executor.id() + } } /// Handle to spawn tasks into an executor from any thread. From f1feedf19031d0c007628569add51ff89ae08447 Mon Sep 17 00:00:00 2001 From: Michael Gomez Date: Wed, 19 Mar 2025 20:44:16 -0700 Subject: [PATCH 0926/1217] BufferedUart initialization This change modifies UART initialization throughout Embassy to take pins before interrupts. Related to #1304. --- embassy-nrf/CHANGELOG.md | 2 ++ embassy-nrf/src/buffered_uarte.rs | 10 +++++----- embassy-nrf/src/uarte.rs | 4 ++-- embassy-rp/CHANGELOG.md | 1 + embassy-rp/src/uart/buffered.rs | 4 ++-- embassy-stm32/CHANGELOG.md | 5 ++++- embassy-stm32/src/usart/buffered.rs | 10 +++++----- examples/nrf52840/src/bin/buffered_uart.rs | 2 +- examples/nrf52840/src/bin/uart.rs | 2 +- examples/nrf52840/src/bin/uart_idle.rs | 2 +- examples/nrf52840/src/bin/uart_split.rs | 2 +- examples/nrf5340/src/bin/uart.rs | 2 +- examples/nrf9151/ns/src/bin/uart.rs | 2 +- examples/nrf9160/src/bin/modem_tcp_client.rs | 2 +- examples/rp/src/bin/uart_buffered_split.rs | 2 +- examples/rp235x/src/bin/uart_buffered_split.rs | 2 +- examples/stm32f4/src/bin/usart_buffered.rs | 2 +- examples/stm32g0/src/bin/usart_buffered.rs | 2 +- examples/stm32l0/src/bin/usart_irq.rs | 2 +- tests/nrf/src/bin/buffered_uart.rs | 2 +- tests/nrf/src/bin/buffered_uart_full.rs | 2 +- tests/nrf/src/bin/buffered_uart_halves.rs | 2 +- tests/nrf/src/bin/uart_split.rs | 2 +- tests/rp/src/bin/uart_buffered.rs | 6 +++--- 24 files changed, 40 insertions(+), 34 deletions(-) diff --git a/embassy-nrf/CHANGELOG.md b/embassy-nrf/CHANGELOG.md index b77688148..ffa7997f7 100644 --- a/embassy-nrf/CHANGELOG.md +++ b/embassy-nrf/CHANGELOG.md @@ -11,6 +11,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - bugfix: nrf twim return errors in async\_wait instead of waiting indefinitely - bugfix: fix missing setting input as disconnected. +- changed: Modify Uarte and BufferedUarte initialization to take pins before interrupts ([#3983](https://github.com/embassy-rs/embassy/pull/3983)) + ## 0.3.0 - 2025-01-06 diff --git a/embassy-nrf/src/buffered_uarte.rs b/embassy-nrf/src/buffered_uarte.rs index f939be004..29e126903 100644 --- a/embassy-nrf/src/buffered_uarte.rs +++ b/embassy-nrf/src/buffered_uarte.rs @@ -227,9 +227,9 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> { ppi_ch1: Peri<'d, impl ConfigurableChannel>, ppi_ch2: Peri<'d, impl ConfigurableChannel>, ppi_group: Peri<'d, impl Group>, - _irq: impl interrupt::typelevel::Binding> + 'd, rxd: Peri<'d, impl GpioPin>, txd: Peri<'d, impl GpioPin>, + _irq: impl interrupt::typelevel::Binding> + 'd, config: Config, rx_buffer: &'d mut [u8], tx_buffer: &'d mut [u8], @@ -262,11 +262,11 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> { ppi_ch1: Peri<'d, impl ConfigurableChannel>, ppi_ch2: Peri<'d, impl ConfigurableChannel>, ppi_group: Peri<'d, impl Group>, - _irq: impl interrupt::typelevel::Binding> + 'd, rxd: Peri<'d, impl GpioPin>, txd: Peri<'d, impl GpioPin>, cts: Peri<'d, impl GpioPin>, rts: Peri<'d, impl GpioPin>, + _irq: impl interrupt::typelevel::Binding> + 'd, config: Config, rx_buffer: &'d mut [u8], tx_buffer: &'d mut [u8], @@ -377,8 +377,8 @@ impl<'d, U: UarteInstance> BufferedUarteTx<'d, U> { /// Create a new BufferedUarteTx without hardware flow control. pub fn new( uarte: Peri<'d, U>, - _irq: impl interrupt::typelevel::Binding> + 'd, txd: Peri<'d, impl GpioPin>, + _irq: impl interrupt::typelevel::Binding> + 'd, config: Config, tx_buffer: &'d mut [u8], ) -> Self { @@ -392,9 +392,9 @@ impl<'d, U: UarteInstance> BufferedUarteTx<'d, U> { /// Panics if `rx_buffer.len()` is odd. pub fn new_with_cts( uarte: Peri<'d, U>, - _irq: impl interrupt::typelevel::Binding> + 'd, txd: Peri<'d, impl GpioPin>, cts: Peri<'d, impl GpioPin>, + _irq: impl interrupt::typelevel::Binding> + 'd, config: Config, tx_buffer: &'d mut [u8], ) -> Self { @@ -588,9 +588,9 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarteRx<'d, U, T> { ppi_ch1: Peri<'d, impl ConfigurableChannel>, ppi_ch2: Peri<'d, impl ConfigurableChannel>, ppi_group: Peri<'d, impl Group>, - _irq: impl interrupt::typelevel::Binding> + 'd, rxd: Peri<'d, impl GpioPin>, rts: Peri<'d, impl GpioPin>, + _irq: impl interrupt::typelevel::Binding> + 'd, config: Config, rx_buffer: &'d mut [u8], ) -> Self { diff --git a/embassy-nrf/src/uarte.rs b/embassy-nrf/src/uarte.rs index b44edfe84..f377df49e 100644 --- a/embassy-nrf/src/uarte.rs +++ b/embassy-nrf/src/uarte.rs @@ -155,9 +155,9 @@ impl<'d, T: Instance> Uarte<'d, T> { /// Create a new UARTE without hardware flow control pub fn new( uarte: Peri<'d, T>, - _irq: impl interrupt::typelevel::Binding> + 'd, rxd: Peri<'d, impl GpioPin>, txd: Peri<'d, impl GpioPin>, + _irq: impl interrupt::typelevel::Binding> + 'd, config: Config, ) -> Self { Self::new_inner(uarte, rxd.into(), txd.into(), None, None, config) @@ -166,11 +166,11 @@ impl<'d, T: Instance> Uarte<'d, T> { /// Create a new UARTE with hardware flow control (RTS/CTS) pub fn new_with_rtscts( uarte: Peri<'d, T>, - _irq: impl interrupt::typelevel::Binding> + 'd, rxd: Peri<'d, impl GpioPin>, txd: Peri<'d, impl GpioPin>, cts: Peri<'d, impl GpioPin>, rts: Peri<'d, impl GpioPin>, + _irq: impl interrupt::typelevel::Binding> + 'd, config: Config, ) -> Self { Self::new_inner( diff --git a/embassy-rp/CHANGELOG.md b/embassy-rp/CHANGELOG.md index 8ad3b0b76..7ac0a47cb 100644 --- a/embassy-rp/CHANGELOG.md +++ b/embassy-rp/CHANGELOG.md @@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - rp235x: add ImageDef features. ([#3890](https://github.com/embassy-rs/embassy/pull/3890)) - doc: Fix "the the" ([#3903](https://github.com/embassy-rs/embassy/pull/3903)) - pio: Add access to DMA engine byte swapping ([#3935](https://github.com/embassy-rs/embassy/pull/3935)) +- Modify BufferedUart initialization to take pins before interrupts ([#3983](https://github.com/embassy-rs/embassy/pull/3983)) ## 0.3.1 - 2025-02-06 diff --git a/embassy-rp/src/uart/buffered.rs b/embassy-rp/src/uart/buffered.rs index 5b5159d22..da18138b5 100644 --- a/embassy-rp/src/uart/buffered.rs +++ b/embassy-rp/src/uart/buffered.rs @@ -91,9 +91,9 @@ impl<'d, T: Instance> BufferedUart<'d, T> { /// Create a buffered UART instance. pub fn new( _uart: Peri<'d, T>, - irq: impl Binding>, tx: Peri<'d, impl TxPin>, rx: Peri<'d, impl RxPin>, + irq: impl Binding>, tx_buffer: &'d mut [u8], rx_buffer: &'d mut [u8], config: Config, @@ -110,11 +110,11 @@ impl<'d, T: Instance> BufferedUart<'d, T> { /// Create a buffered UART instance with flow control. pub fn new_with_rtscts( _uart: Peri<'d, T>, - irq: impl Binding>, tx: Peri<'d, impl TxPin>, rx: Peri<'d, impl RxPin>, rts: Peri<'d, impl RtsPin>, cts: Peri<'d, impl CtsPin>, + irq: impl Binding>, tx_buffer: &'d mut [u8], rx_buffer: &'d mut [u8], config: Config, diff --git a/embassy-stm32/CHANGELOG.md b/embassy-stm32/CHANGELOG.md index 10b0739fb..c50ab5294 100644 --- a/embassy-stm32/CHANGELOG.md +++ b/embassy-stm32/CHANGELOG.md @@ -5,6 +5,9 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## Unreleased +- Modify BufferedUart initialization to take pins before interrupts ([#3983](https://github.com/embassy-rs/embassy/pull/3983)) + ## 0.2.0 - 2025-01-10 Starting 2025 strong with a release packed with new, exciting good stuff! 🚀 @@ -272,4 +275,4 @@ Misc: ## 0.1.0 - 2024-01-12 -First release. \ No newline at end of file +First release. diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs index b1640b6dc..8a33a152c 100644 --- a/embassy-stm32/src/usart/buffered.rs +++ b/embassy-stm32/src/usart/buffered.rs @@ -208,11 +208,11 @@ impl<'d> BufferedUart<'d> { /// Create a new bidirectional buffered UART driver pub fn new( peri: Peri<'d, T>, - _irq: impl interrupt::typelevel::Binding> + 'd, rx: Peri<'d, impl RxPin>, tx: Peri<'d, impl TxPin>, tx_buffer: &'d mut [u8], rx_buffer: &'d mut [u8], + _irq: impl interrupt::typelevel::Binding> + 'd, config: Config, ) -> Result { Self::new_inner( @@ -231,11 +231,11 @@ impl<'d> BufferedUart<'d> { /// Create a new bidirectional buffered UART driver with request-to-send and clear-to-send pins pub fn new_with_rtscts( peri: Peri<'d, T>, - _irq: impl interrupt::typelevel::Binding> + 'd, rx: Peri<'d, impl RxPin>, tx: Peri<'d, impl TxPin>, rts: Peri<'d, impl RtsPin>, cts: Peri<'d, impl CtsPin>, + _irq: impl interrupt::typelevel::Binding> + 'd, tx_buffer: &'d mut [u8], rx_buffer: &'d mut [u8], config: Config, @@ -256,10 +256,10 @@ impl<'d> BufferedUart<'d> { /// Create a new bidirectional buffered UART driver with only the RTS pin as the DE pin pub fn new_with_rts_as_de( peri: Peri<'d, T>, - _irq: impl interrupt::typelevel::Binding> + 'd, rx: Peri<'d, impl RxPin>, tx: Peri<'d, impl TxPin>, rts: Peri<'d, impl RtsPin>, + _irq: impl interrupt::typelevel::Binding> + 'd, tx_buffer: &'d mut [u8], rx_buffer: &'d mut [u8], config: Config, @@ -280,10 +280,10 @@ impl<'d> BufferedUart<'d> { /// Create a new bidirectional buffered UART driver with only the request-to-send pin pub fn new_with_rts( peri: Peri<'d, T>, - _irq: impl interrupt::typelevel::Binding> + 'd, rx: Peri<'d, impl RxPin>, tx: Peri<'d, impl TxPin>, rts: Peri<'d, impl RtsPin>, + _irq: impl interrupt::typelevel::Binding> + 'd, tx_buffer: &'d mut [u8], rx_buffer: &'d mut [u8], config: Config, @@ -305,10 +305,10 @@ impl<'d> BufferedUart<'d> { #[cfg(not(any(usart_v1, usart_v2)))] pub fn new_with_de( peri: Peri<'d, T>, - _irq: impl interrupt::typelevel::Binding> + 'd, rx: Peri<'d, impl RxPin>, tx: Peri<'d, impl TxPin>, de: Peri<'d, impl DePin>, + _irq: impl interrupt::typelevel::Binding> + 'd, tx_buffer: &'d mut [u8], rx_buffer: &'d mut [u8], config: Config, diff --git a/examples/nrf52840/src/bin/buffered_uart.rs b/examples/nrf52840/src/bin/buffered_uart.rs index 77d017964..f0a066818 100644 --- a/examples/nrf52840/src/bin/buffered_uart.rs +++ b/examples/nrf52840/src/bin/buffered_uart.rs @@ -28,9 +28,9 @@ async fn main(_spawner: Spawner) { p.PPI_CH0, p.PPI_CH1, p.PPI_GROUP0, - Irqs, p.P0_08, p.P0_06, + Irqs, config, &mut rx_buffer, &mut tx_buffer, diff --git a/examples/nrf52840/src/bin/uart.rs b/examples/nrf52840/src/bin/uart.rs index 23154672f..f9f8d74ab 100644 --- a/examples/nrf52840/src/bin/uart.rs +++ b/examples/nrf52840/src/bin/uart.rs @@ -17,7 +17,7 @@ async fn main(_spawner: Spawner) { config.parity = uarte::Parity::EXCLUDED; config.baudrate = uarte::Baudrate::BAUD115200; - let mut uart = uarte::Uarte::new(p.UARTE0, Irqs, p.P0_08, p.P0_06, config); + let mut uart = uarte::Uarte::new(p.UARTE0, p.P0_08, p.P0_06, Irqs, config); info!("uarte initialized!"); diff --git a/examples/nrf52840/src/bin/uart_idle.rs b/examples/nrf52840/src/bin/uart_idle.rs index a42e84fa4..00e3ae904 100644 --- a/examples/nrf52840/src/bin/uart_idle.rs +++ b/examples/nrf52840/src/bin/uart_idle.rs @@ -18,7 +18,7 @@ async fn main(_spawner: Spawner) { config.parity = uarte::Parity::EXCLUDED; config.baudrate = uarte::Baudrate::BAUD115200; - let uart = uarte::Uarte::new(p.UARTE0, Irqs, p.P0_08, p.P0_06, config); + let uart = uarte::Uarte::new(p.UARTE0, p.P0_08, p.P0_06, Irqs, config); let (mut tx, mut rx) = uart.split_with_idle(p.TIMER0, p.PPI_CH0, p.PPI_CH1); info!("uarte initialized!"); diff --git a/examples/nrf52840/src/bin/uart_split.rs b/examples/nrf52840/src/bin/uart_split.rs index 94af4be86..46be8f636 100644 --- a/examples/nrf52840/src/bin/uart_split.rs +++ b/examples/nrf52840/src/bin/uart_split.rs @@ -23,7 +23,7 @@ async fn main(spawner: Spawner) { config.parity = uarte::Parity::EXCLUDED; config.baudrate = uarte::Baudrate::BAUD115200; - let uart = uarte::Uarte::new(p.UARTE0, Irqs, p.P0_08, p.P0_06, config); + let uart = uarte::Uarte::new(p.UARTE0, p.P0_08, p.P0_06, Irqs, config); let (mut tx, rx) = uart.split(); info!("uarte initialized!"); diff --git a/examples/nrf5340/src/bin/uart.rs b/examples/nrf5340/src/bin/uart.rs index 7b41d7463..7e8b8d418 100644 --- a/examples/nrf5340/src/bin/uart.rs +++ b/examples/nrf5340/src/bin/uart.rs @@ -18,7 +18,7 @@ async fn main(_spawner: Spawner) { config.parity = uarte::Parity::EXCLUDED; config.baudrate = uarte::Baudrate::BAUD115200; - let mut uart = uarte::Uarte::new(p.SERIAL0, Irqs, p.P1_00, p.P1_01, config); + let mut uart = uarte::Uarte::new(p.SERIAL0, p.P1_00, p.P1_01, Irqs, config); info!("uarte initialized!"); diff --git a/examples/nrf9151/ns/src/bin/uart.rs b/examples/nrf9151/ns/src/bin/uart.rs index 234ff35f2..6fd377978 100644 --- a/examples/nrf9151/ns/src/bin/uart.rs +++ b/examples/nrf9151/ns/src/bin/uart.rs @@ -17,7 +17,7 @@ async fn main(_spawner: Spawner) { config.parity = uarte::Parity::EXCLUDED; config.baudrate = uarte::Baudrate::BAUD115200; - let mut uart = uarte::Uarte::new(p.SERIAL0, Irqs, p.P0_26, p.P0_27, config); + let mut uart = uarte::Uarte::new(p.SERIAL0, p.P0_26, p.P0_27, Irqs, config); info!("uarte initialized!"); diff --git a/examples/nrf9160/src/bin/modem_tcp_client.rs b/examples/nrf9160/src/bin/modem_tcp_client.rs index 2ba964b1f..a36b14626 100644 --- a/examples/nrf9160/src/bin/modem_tcp_client.rs +++ b/examples/nrf9160/src/bin/modem_tcp_client.rs @@ -127,8 +127,8 @@ async fn main(spawner: Spawner) { let uart = BufferedUarteTx::new( //let trace_uart = BufferedUarteTx::new( unsafe { peripherals::SERIAL0::steal() }, - Irqs, unsafe { peripherals::P0_01::steal() }, + Irqs, //unsafe { peripherals::P0_14::steal() }, config, unsafe { &mut *addr_of_mut!(TRACE_BUF) }, diff --git a/examples/rp/src/bin/uart_buffered_split.rs b/examples/rp/src/bin/uart_buffered_split.rs index 468d2b61a..da7e94139 100644 --- a/examples/rp/src/bin/uart_buffered_split.rs +++ b/examples/rp/src/bin/uart_buffered_split.rs @@ -30,7 +30,7 @@ async fn main(spawner: Spawner) { let tx_buf = &mut TX_BUF.init([0; 16])[..]; static RX_BUF: StaticCell<[u8; 16]> = StaticCell::new(); let rx_buf = &mut RX_BUF.init([0; 16])[..]; - let uart = BufferedUart::new(uart, Irqs, tx_pin, rx_pin, tx_buf, rx_buf, Config::default()); + let uart = BufferedUart::new(uart, tx_pin, rx_pin, Irqs, tx_buf, rx_buf, Config::default()); let (mut tx, rx) = uart.split(); unwrap!(spawner.spawn(reader(rx))); diff --git a/examples/rp235x/src/bin/uart_buffered_split.rs b/examples/rp235x/src/bin/uart_buffered_split.rs index 468d2b61a..da7e94139 100644 --- a/examples/rp235x/src/bin/uart_buffered_split.rs +++ b/examples/rp235x/src/bin/uart_buffered_split.rs @@ -30,7 +30,7 @@ async fn main(spawner: Spawner) { let tx_buf = &mut TX_BUF.init([0; 16])[..]; static RX_BUF: StaticCell<[u8; 16]> = StaticCell::new(); let rx_buf = &mut RX_BUF.init([0; 16])[..]; - let uart = BufferedUart::new(uart, Irqs, tx_pin, rx_pin, tx_buf, rx_buf, Config::default()); + let uart = BufferedUart::new(uart, tx_pin, rx_pin, Irqs, tx_buf, rx_buf, Config::default()); let (mut tx, rx) = uart.split(); unwrap!(spawner.spawn(reader(rx))); diff --git a/examples/stm32f4/src/bin/usart_buffered.rs b/examples/stm32f4/src/bin/usart_buffered.rs index c99807f11..3b6cdad8d 100644 --- a/examples/stm32f4/src/bin/usart_buffered.rs +++ b/examples/stm32f4/src/bin/usart_buffered.rs @@ -21,7 +21,7 @@ async fn main(_spawner: Spawner) { let mut tx_buf = [0u8; 32]; let mut rx_buf = [0u8; 32]; - let mut buf_usart = BufferedUart::new(p.USART3, Irqs, p.PD9, p.PD8, &mut tx_buf, &mut rx_buf, config).unwrap(); + let mut buf_usart = BufferedUart::new(p.USART3, p.PD9, p.PD8, &mut tx_buf, &mut rx_buf, Irqs, config).unwrap(); loop { let buf = buf_usart.fill_buf().await.unwrap(); diff --git a/examples/stm32g0/src/bin/usart_buffered.rs b/examples/stm32g0/src/bin/usart_buffered.rs index c097a0c5a..6d9ec8cb4 100644 --- a/examples/stm32g0/src/bin/usart_buffered.rs +++ b/examples/stm32g0/src/bin/usart_buffered.rs @@ -21,7 +21,7 @@ async fn main(_spawner: Spawner) { config.baudrate = 115200; let mut tx_buf = [0u8; 256]; let mut rx_buf = [0u8; 256]; - let mut usart = BufferedUart::new(p.USART1, Irqs, p.PB7, p.PB6, &mut tx_buf, &mut rx_buf, config).unwrap(); + let mut usart = BufferedUart::new(p.USART1, p.PB7, p.PB6, &mut tx_buf, &mut rx_buf, Irqs, config).unwrap(); usart.write_all(b"Hello Embassy World!\r\n").await.unwrap(); info!("wrote Hello, starting echo"); diff --git a/examples/stm32l0/src/bin/usart_irq.rs b/examples/stm32l0/src/bin/usart_irq.rs index 2c96a8bc2..a51ddbcbb 100644 --- a/examples/stm32l0/src/bin/usart_irq.rs +++ b/examples/stm32l0/src/bin/usart_irq.rs @@ -21,7 +21,7 @@ async fn main(_spawner: Spawner) { config.baudrate = 9600; let mut tx_buf = [0u8; 256]; let mut rx_buf = [0u8; 256]; - let mut usart = BufferedUart::new(p.USART2, Irqs, p.PA3, p.PA2, &mut tx_buf, &mut rx_buf, config).unwrap(); + let mut usart = BufferedUart::new(p.USART2, p.PA3, p.PA2, &mut tx_buf, &mut rx_buf, Irqs, config).unwrap(); usart.write_all(b"Hello Embassy World!\r\n").await.unwrap(); info!("wrote Hello, starting echo"); diff --git a/tests/nrf/src/bin/buffered_uart.rs b/tests/nrf/src/bin/buffered_uart.rs index 2eecafb95..8c4827464 100644 --- a/tests/nrf/src/bin/buffered_uart.rs +++ b/tests/nrf/src/bin/buffered_uart.rs @@ -30,9 +30,9 @@ async fn main(_spawner: Spawner) { p.PPI_CH0.reborrow(), p.PPI_CH1.reborrow(), p.PPI_GROUP0.reborrow(), - irqs!(UART0_BUFFERED), peri!(p, PIN_A).reborrow(), peri!(p, PIN_B).reborrow(), + irqs!(UART0_BUFFERED), config.clone(), &mut rx_buffer, &mut tx_buffer, diff --git a/tests/nrf/src/bin/buffered_uart_full.rs b/tests/nrf/src/bin/buffered_uart_full.rs index 09353bbe8..e0f41b891 100644 --- a/tests/nrf/src/bin/buffered_uart_full.rs +++ b/tests/nrf/src/bin/buffered_uart_full.rs @@ -28,9 +28,9 @@ async fn main(_spawner: Spawner) { p.PPI_CH0, p.PPI_CH1, p.PPI_GROUP0, - irqs!(UART0_BUFFERED), peri!(p, PIN_A), peri!(p, PIN_B), + irqs!(UART0_BUFFERED), config.clone(), &mut rx_buffer, &mut tx_buffer, diff --git a/tests/nrf/src/bin/buffered_uart_halves.rs b/tests/nrf/src/bin/buffered_uart_halves.rs index adfba509d..e6debd76e 100644 --- a/tests/nrf/src/bin/buffered_uart_halves.rs +++ b/tests/nrf/src/bin/buffered_uart_halves.rs @@ -28,8 +28,8 @@ async fn main(_spawner: Spawner) { let mut tx = BufferedUarteTx::new( peri!(p, UART1).reborrow(), - irqs!(UART1_BUFFERED), peri!(p, PIN_A).reborrow(), + irqs!(UART1_BUFFERED), config.clone(), &mut tx_buffer, ); diff --git a/tests/nrf/src/bin/uart_split.rs b/tests/nrf/src/bin/uart_split.rs index f24903297..8fe710068 100644 --- a/tests/nrf/src/bin/uart_split.rs +++ b/tests/nrf/src/bin/uart_split.rs @@ -22,9 +22,9 @@ async fn main(_spawner: Spawner) { let uarte = Uarte::new( peri!(p, UART0).reborrow(), - irqs!(UART0), peri!(p, PIN_A).reborrow(), peri!(p, PIN_B).reborrow(), + irqs!(UART0), config.clone(), ); let (mut tx, mut rx) = uarte.split(); diff --git a/tests/rp/src/bin/uart_buffered.rs b/tests/rp/src/bin/uart_buffered.rs index b270a60ce..d5f655e9b 100644 --- a/tests/rp/src/bin/uart_buffered.rs +++ b/tests/rp/src/bin/uart_buffered.rs @@ -75,9 +75,9 @@ async fn main(_spawner: Spawner) { let rx_buf = &mut [0u8; 16]; let mut uart = BufferedUart::new( uart.reborrow(), - Irqs, tx.reborrow(), rx.reborrow(), + Irqs, tx_buf, rx_buf, config, @@ -103,9 +103,9 @@ async fn main(_spawner: Spawner) { let rx_buf = &mut [0u8; 16]; let mut uart = BufferedUart::new( uart.reborrow(), - Irqs, tx.reborrow(), rx.reborrow(), + Irqs, tx_buf, rx_buf, config, @@ -146,9 +146,9 @@ async fn main(_spawner: Spawner) { let rx_buf = &mut [0u8; 16]; let mut uart = BufferedUart::new( uart.reborrow(), - Irqs, tx.reborrow(), rx.reborrow(), + Irqs, tx_buf, rx_buf, config, From ac4f4ee8074411ce36bde44ea947fb78939a23c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=85ke=20Amcoff?= Date: Sat, 5 Apr 2025 18:36:04 +0200 Subject: [PATCH 0927/1217] disable critical-section/std for arch-std in embassy-executor --- embassy-executor/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-executor/Cargo.toml b/embassy-executor/Cargo.toml index 79d899c61..0a2dfaa6a 100644 --- a/embassy-executor/Cargo.toml +++ b/embassy-executor/Cargo.toml @@ -70,7 +70,7 @@ turbowakers = [] #! ### Architecture _arch = [] # some arch was picked ## std -arch-std = ["_arch", "critical-section/std"] +arch-std = ["_arch"] ## Cortex-M arch-cortex-m = ["_arch", "dep:cortex-m"] ## RISC-V 32 From 4fec76da2829acf636ab08f70aae452e5315590f Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sun, 6 Apr 2025 22:17:26 +0200 Subject: [PATCH 0928/1217] stm32/timer: update OPM to Peri API. --- embassy-stm32/src/timer/one_pulse.rs | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/embassy-stm32/src/timer/one_pulse.rs b/embassy-stm32/src/timer/one_pulse.rs index 43ba3dedf..933165ef9 100644 --- a/embassy-stm32/src/timer/one_pulse.rs +++ b/embassy-stm32/src/timer/one_pulse.rs @@ -17,7 +17,7 @@ use crate::gpio::{AfType, AnyPin, Pull}; use crate::interrupt::typelevel::{Binding, Interrupt}; use crate::pac::timer::vals::Etp; use crate::time::Hertz; -use crate::{into_ref, Peripheral, PeripheralRef}; +use crate::Peri; /// External input marker type. pub enum Ext {} @@ -44,7 +44,7 @@ impl From for Etp { /// /// This wraps a pin to make it usable as a timer trigger. pub struct TriggerPin<'d, T, C> { - _pin: PeripheralRef<'d, AnyPin>, + _pin: Peri<'d, AnyPin>, phantom: PhantomData<(T, C)>, } @@ -52,11 +52,10 @@ macro_rules! channel_impl { ($new_chx:ident, $channel:ident, $pin_trait:ident) => { impl<'d, T: GeneralInstance4Channel> TriggerPin<'d, T, $channel> { #[doc = concat!("Create a new ", stringify!($channel), " trigger pin instance.")] - pub fn $new_chx(pin: impl Peripheral

> + 'd, pull: Pull) -> Self { - into_ref!(pin); + pub fn $new_chx(pin: Peri<'d, impl $pin_trait>, pull: Pull) -> Self { pin.set_as_af(pin.af_num(), AfType::input(pull)); TriggerPin { - _pin: pin.map_into(), + _pin: pin.into(), phantom: PhantomData, } } @@ -81,7 +80,7 @@ impl<'d, T: GeneralInstance4Channel> OnePulse<'d, T> { /// The pulse is triggered by a channel 1 input pin on both rising and /// falling edges. Channel 1 will unusable as an output. pub fn new_ch1_edge_detect( - tim: impl Peripheral

+ 'd, + tim: Peri<'d, T>, _pin: TriggerPin<'d, T, Ch1>, _irq: impl Binding> + 'd, freq: Hertz, @@ -105,7 +104,7 @@ impl<'d, T: GeneralInstance4Channel> OnePulse<'d, T> { /// The pulse is triggered by a channel 1 input pin. Channel 1 will unusable /// as an output. pub fn new_ch1( - tim: impl Peripheral

+ 'd, + tim: Peri<'d, T>, _pin: TriggerPin<'d, T, Ch1>, _irq: impl Binding> + 'd, freq: Hertz, @@ -131,7 +130,7 @@ impl<'d, T: GeneralInstance4Channel> OnePulse<'d, T> { /// The pulse is triggered by a channel 2 input pin. Channel 2 will unusable /// as an output. pub fn new_ch2( - tim: impl Peripheral

+ 'd, + tim: Peri<'d, T>, _pin: TriggerPin<'d, T, Ch1>, _irq: impl Binding> + 'd, freq: Hertz, @@ -156,7 +155,7 @@ impl<'d, T: GeneralInstance4Channel> OnePulse<'d, T> { /// /// The pulse is triggered by a external trigger input pin. pub fn new_ext( - tim: impl Peripheral

+ 'd, + tim: Peri<'d, T>, _pin: TriggerPin<'d, T, Ext>, _irq: impl Binding> + 'd, freq: Hertz, From c04b4339919a5b6fd18763554096f84778df79c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Sun, 6 Apr 2025 22:11:21 +0200 Subject: [PATCH 0929/1217] embassy-sync, executor/wasm: don't select critical-section impl for std --- embassy-executor/Cargo.toml | 2 +- embassy-sync/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-executor/Cargo.toml b/embassy-executor/Cargo.toml index 0a2dfaa6a..8d7cf715f 100644 --- a/embassy-executor/Cargo.toml +++ b/embassy-executor/Cargo.toml @@ -76,7 +76,7 @@ arch-cortex-m = ["_arch", "dep:cortex-m"] ## RISC-V 32 arch-riscv32 = ["_arch"] ## WASM -arch-wasm = ["_arch", "dep:wasm-bindgen", "dep:js-sys", "critical-section/std"] +arch-wasm = ["_arch", "dep:wasm-bindgen", "dep:js-sys"] ## AVR arch-avr = ["_arch", "dep:portable-atomic", "dep:avr-device"] ## spin (architecture agnostic; never sleeps) diff --git a/embassy-sync/Cargo.toml b/embassy-sync/Cargo.toml index 4430f1956..92ee38ed9 100644 --- a/embassy-sync/Cargo.toml +++ b/embassy-sync/Cargo.toml @@ -20,7 +20,7 @@ src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-sync/ target = "thumbv7em-none-eabi" [features] -std = ["critical-section/std"] +std = [] turbowakers = [] [dependencies] From b0ba604ba5ab1ba866df71b7e11099a3b1ceee3f Mon Sep 17 00:00:00 2001 From: Badr Bouslikhin Date: Fri, 7 Mar 2025 18:00:52 +0100 Subject: [PATCH 0930/1217] fix(stm32): handle half-duplex in ringbuffered read --- embassy-stm32/src/usart/mod.rs | 1 - embassy-stm32/src/usart/ringbuffered.rs | 10 ++++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index 5b7f8dc26..10e3ea88b 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -711,7 +711,6 @@ impl<'d> UartRx<'d, Async> { // make sure USART state is restored to neutral state when this future is dropped let on_drop = OnDrop::new(move || { - // defmt::trace!("Clear all USART interrupts and DMA Read Request"); // clear all interrupts and DMA Rx Request r.cr1().modify(|w| { // disable RXNE interrupt diff --git a/embassy-stm32/src/usart/ringbuffered.rs b/embassy-stm32/src/usart/ringbuffered.rs index 8e42d5917..eaa9424c5 100644 --- a/embassy-stm32/src/usart/ringbuffered.rs +++ b/embassy-stm32/src/usart/ringbuffered.rs @@ -150,6 +150,16 @@ impl<'d> RingBufferedUartRx<'d> { pub async fn read(&mut self, buf: &mut [u8]) -> Result { self.start_dma_or_check_errors()?; + // In half-duplex mode, we need to disable the Transmitter and enable the Receiver + // since they can't operate simultaneously on the shared line + let r = self.info.regs; + if r.cr3().read().hdsel() && r.cr1().read().te() { + r.cr1().modify(|reg| { + reg.set_re(true); + reg.set_te(false); + }); + } + loop { match self.ring_buf.read(buf) { Ok((0, _)) => {} From f7ddac3e0d5ed7b43f75223a8f662a4bf872d687 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sun, 6 Apr 2025 23:49:07 +0200 Subject: [PATCH 0931/1217] Remove flaky test. --- ci.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ci.sh b/ci.sh index 5b63c507b..e2d3db546 100755 --- a/ci.sh +++ b/ci.sh @@ -328,8 +328,9 @@ rm out/tests/stm32wb55rg/wpan_ble # unstable, I think it's running out of RAM? rm out/tests/stm32f207zg/eth -# temporarily disabled, hard faults for unknown reasons +# temporarily disabled, flaky. rm out/tests/stm32f207zg/usart_rx_ringbuffered +rm out/tests/stm32l152re/usart_rx_ringbuffered # doesn't work, gives "noise error", no idea why. usart_dma does pass. rm out/tests/stm32u5a5zj/usart From c6e16c9e4e64aefff5d40935587433f4e9718fb5 Mon Sep 17 00:00:00 2001 From: David Brown Date: Fri, 28 Feb 2025 09:00:53 -0700 Subject: [PATCH 0932/1217] embassy-rp: uart: Increase RX FIFO watermark Change the UART RX FIFO depth from 1/8 to 7/8. This should allow for buffered receipt of uart data with a lower IRQ load. The PL011 fifo is pretty smart about the fifo, it has an automatic timeout (which triggers an interrupt) of about 4 characters worth of time, so setting this threshold doesn't affect the behavior of receipt of a partially filled fifo. This should not have any affect on the DMA mode, as the DMA will generally drain the fifo as data becomes available. The constraint for the fifo threshold should be determined by expected interrupt latency. The IRQ needs to be able to drain the fifo before it fills. As such, the proper threshold depends on system design and data rate. At full speed (7.8 Mbaud), the remaining 8 characters will come in in about 10us, which is probably insufficient. But, the time is quite adequate at lower speeds. --- embassy-rp/src/uart/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-rp/src/uart/mod.rs b/embassy-rp/src/uart/mod.rs index 90c7655be..7ce074a3f 100644 --- a/embassy-rp/src/uart/mod.rs +++ b/embassy-rp/src/uart/mod.rs @@ -913,7 +913,7 @@ impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> { }); r.uartifls().write(|w| { - w.set_rxiflsel(0b000); + w.set_rxiflsel(0b100); w.set_txiflsel(0b000); }); From 1074cc7eaf406647a887fbc1fbe521ae1e8850bc Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 7 Apr 2025 01:04:50 +0200 Subject: [PATCH 0933/1217] stm32/adc: enable interrupt for stm32f1 Co-Authored-By: Tnze --- embassy-stm32/src/adc/f1.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/embassy-stm32/src/adc/f1.rs b/embassy-stm32/src/adc/f1.rs index fa6255c23..3cdc9d8fb 100644 --- a/embassy-stm32/src/adc/f1.rs +++ b/embassy-stm32/src/adc/f1.rs @@ -4,8 +4,10 @@ use core::task::Poll; use super::blocking_delay_us; use crate::adc::{Adc, AdcChannel, Instance, SampleTime}; +use crate::interrupt::typelevel::Interrupt; +use crate::interrupt::{self}; use crate::time::Hertz; -use crate::{interrupt, rcc, Peri}; +use crate::{rcc, Peri}; pub const VDDA_CALIB_MV: u32 = 3300; pub const ADC_MAX: u32 = (1 << 12) - 1; @@ -20,12 +22,9 @@ pub struct InterruptHandler { impl interrupt::typelevel::Handler for InterruptHandler { unsafe fn on_interrupt() { if T::regs().sr().read().eoc() { - T::regs().cr1().modify(|w| w.set_eocie(false)); - } else { - return; + T::regs().cr1().modify(|w| w.set_eocie(false)); // End of Convert interrupt disable + T::state().waker.wake(); } - - T::state().waker.wake(); } } @@ -69,6 +68,9 @@ impl<'d, T: Instance> Adc<'d, T> { // One cycle after calibration blocking_delay_us((1_000_000 * 1) / Self::freq().0 + 1); + T::Interrupt::unpend(); + unsafe { T::Interrupt::enable() }; + Self { adc, sample_time: SampleTime::from_bits(0), From ef8d168df6fa1d8020d7490e4469d196a35077ce Mon Sep 17 00:00:00 2001 From: outfoxxed Date: Fri, 4 Apr 2025 01:33:51 -0700 Subject: [PATCH 0934/1217] executor: add executor selection to #[embassy_executor::main] --- embassy-executor-macros/src/lib.rs | 24 +++++++++++ embassy-executor-macros/src/macros/main.rs | 48 +++++++++++++++++++--- embassy-executor/src/lib.rs | 2 + 3 files changed, 69 insertions(+), 5 deletions(-) diff --git a/embassy-executor-macros/src/lib.rs b/embassy-executor-macros/src/lib.rs index 5f2182f10..8e737db6a 100644 --- a/embassy-executor-macros/src/lib.rs +++ b/embassy-executor-macros/src/lib.rs @@ -173,3 +173,27 @@ pub fn main_std(args: TokenStream, item: TokenStream) -> TokenStream { pub fn main_wasm(args: TokenStream, item: TokenStream) -> TokenStream { main::run(args.into(), item.into(), &main::ARCH_WASM).into() } + +/// Creates a new `executor` instance and declares an application entry point for an unspecified architecture, spawning the corresponding function body as an async task. +/// +/// The following restrictions apply: +/// +/// * The function must accept exactly 1 parameter, an `embassy_executor::Spawner` handle that it can use to spawn additional tasks. +/// * The function must be declared `async`. +/// * The function must not use generics. +/// * Only a single `main` task may be declared. +/// +/// A user-defined entry macro and executor type must be provided via the `entry` and `executor` arguments of the `main` macro. +/// +/// ## Examples +/// Spawning a task: +/// ``` rust +/// #[embassy_executor::main(entry = "your_hal::entry", executor = "your_hal::Executor")] +/// async fn main(_s: embassy_executor::Spawner) { +/// // Function body +/// } +/// ``` +#[proc_macro_attribute] +pub fn main_unspecified(args: TokenStream, item: TokenStream) -> TokenStream { + main::run(args.into(), item.into(), &main::ARCH_UNSPECIFIED).into() +} diff --git a/embassy-executor-macros/src/macros/main.rs b/embassy-executor-macros/src/macros/main.rs index 24f61f30b..95722b19b 100644 --- a/embassy-executor-macros/src/macros/main.rs +++ b/embassy-executor-macros/src/macros/main.rs @@ -16,42 +16,57 @@ enum Flavor { pub(crate) struct Arch { default_entry: Option<&'static str>, flavor: Flavor, + executor_required: bool, } pub static ARCH_AVR: Arch = Arch { default_entry: Some("avr_device::entry"), flavor: Flavor::Standard, + executor_required: false, }; pub static ARCH_RISCV: Arch = Arch { default_entry: Some("riscv_rt::entry"), flavor: Flavor::Standard, + executor_required: false, }; pub static ARCH_CORTEX_M: Arch = Arch { default_entry: Some("cortex_m_rt::entry"), flavor: Flavor::Standard, + executor_required: false, }; pub static ARCH_SPIN: Arch = Arch { default_entry: None, flavor: Flavor::Standard, + executor_required: false, }; pub static ARCH_STD: Arch = Arch { default_entry: None, flavor: Flavor::Standard, + executor_required: false, }; pub static ARCH_WASM: Arch = Arch { default_entry: Some("wasm_bindgen::prelude::wasm_bindgen(start)"), flavor: Flavor::Wasm, + executor_required: false, +}; + +pub static ARCH_UNSPECIFIED: Arch = Arch { + default_entry: None, + flavor: Flavor::Standard, + executor_required: true, }; #[derive(Debug, FromMeta, Default)] struct Args { #[darling(default)] entry: Option, + #[darling(default)] + executor: Option, } pub fn run(args: TokenStream, item: TokenStream, arch: &Arch) -> TokenStream { @@ -112,9 +127,10 @@ pub fn run(args: TokenStream, item: TokenStream, arch: &Arch) -> TokenStream { error(&mut errors, &f.sig, "main function must have 1 argument: the spawner."); } - let entry = match args.entry.as_deref().or(arch.default_entry) { - None => TokenStream::new(), - Some(x) => match TokenStream::from_str(x) { + let entry = match (args.entry.as_deref(), arch.default_entry.as_deref()) { + (None, None) => TokenStream::new(), + (Some(x), _) | (None, Some(x)) if x == "" => TokenStream::new(), + (Some(x), _) | (None, Some(x)) => match TokenStream::from_str(x) { Ok(x) => quote!(#[#x]), Err(e) => { error(&mut errors, &f.sig, e); @@ -123,6 +139,28 @@ pub fn run(args: TokenStream, item: TokenStream, arch: &Arch) -> TokenStream { }, }; + let executor = match (args.executor.as_deref(), arch.executor_required) { + (None, true) => { + error( + &mut errors, + &f.sig, + "\ +No architecture selected for embassy-executor. Make sure you've enabled one of the `arch-*` features in your Cargo.toml. + +Alternatively, if you would like to use a custom executor implementation, specify it with the `executor` argument. +For example: `#[embassy_executor::main(entry = ..., executor = \"some_crate::Executor\")]", + ); + "" + } + (Some(x), _) => x, + (None, _) => "::embassy_executor::Executor", + }; + + let executor = TokenStream::from_str(executor).unwrap_or_else(|e| { + error(&mut errors, &f.sig, e); + TokenStream::new() + }); + let f_body = f.body; let out = &f.sig.output; @@ -134,7 +172,7 @@ pub fn run(args: TokenStream, item: TokenStream, arch: &Arch) -> TokenStream { ::core::mem::transmute(t) } - let mut executor = ::embassy_executor::Executor::new(); + let mut executor = #executor::new(); let executor = unsafe { __make_static(&mut executor) }; executor.run(|spawner| { spawner.must_spawn(__embassy_main(spawner)); @@ -144,7 +182,7 @@ pub fn run(args: TokenStream, item: TokenStream, arch: &Arch) -> TokenStream { Flavor::Wasm => ( quote!(Result<(), wasm_bindgen::JsValue>), quote! { - let executor = ::std::boxed::Box::leak(::std::boxed::Box::new(::embassy_executor::Executor::new())); + let executor = ::std::boxed::Box::leak(::std::boxed::Box::new(#executor::new())); executor.start(|spawner| { spawner.must_spawn(__embassy_main(spawner)); diff --git a/embassy-executor/src/lib.rs b/embassy-executor/src/lib.rs index d6bd63665..d6fd3d651 100644 --- a/embassy-executor/src/lib.rs +++ b/embassy-executor/src/lib.rs @@ -44,6 +44,8 @@ mod arch; #[cfg(feature = "_arch")] #[allow(unused_imports)] // don't warn if the module is empty. pub use arch::*; +#[cfg(not(feature = "_arch"))] +pub use embassy_executor_macros::main_unspecified as main; pub mod raw; From 1e23b8114bb1f4b9e092bc50b3cfe4bd2f7ebdb6 Mon Sep 17 00:00:00 2001 From: i509VCB Date: Sun, 6 Apr 2025 21:13:49 -0500 Subject: [PATCH 0935/1217] mspm0: add uart tests This also fixes a bug in the uart clock calculation where it could select an oversampling faster than what the hardware is providing. --- ci.sh | 4 ++ embassy-mspm0/src/uart.rs | 32 +++++++++++-- tests/mspm0/.cargo/config.toml | 8 ++++ tests/mspm0/Cargo.toml | 58 ++++++++++++++++++++++++ tests/mspm0/build.rs | 24 ++++++++++ tests/mspm0/memory_g3507.x | 6 +++ tests/mspm0/src/bin/uart.rs | 83 ++++++++++++++++++++++++++++++++++ 7 files changed, 212 insertions(+), 3 deletions(-) create mode 100644 tests/mspm0/.cargo/config.toml create mode 100644 tests/mspm0/Cargo.toml create mode 100644 tests/mspm0/build.rs create mode 100644 tests/mspm0/memory_g3507.x create mode 100644 tests/mspm0/src/bin/uart.rs diff --git a/ci.sh b/ci.sh index e2d3db546..97916ebf1 100755 --- a/ci.sh +++ b/ci.sh @@ -308,6 +308,7 @@ cargo batch \ --- build --release --manifest-path tests/nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52840 --artifact-dir out/tests/nrf52840-dk \ --- build --release --manifest-path tests/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features nrf5340 --artifact-dir out/tests/nrf5340-dk \ --- build --release --manifest-path tests/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features nrf9160 --artifact-dir out/tests/nrf9160-dk \ + --- build --release --manifest-path tests/mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0g3507 --artifact-dir out/tests/mspm0g3507 \ --- build --release --manifest-path tests/riscv32/Cargo.toml --target riscv32imac-unknown-none-elf \ $BUILD_EXTRA @@ -322,6 +323,9 @@ rm -rf out/tests/stm32f103c8 rm -rf out/tests/nrf52840-dk rm -rf out/tests/nrf52833-dk +# disabled because these boards are not on the shelf +rm -rf out/tests/mspm0g3507 + rm out/tests/stm32wb55rg/wpan_mac rm out/tests/stm32wb55rg/wpan_ble diff --git a/embassy-mspm0/src/uart.rs b/embassy-mspm0/src/uart.rs index 45094a000..bc1d2e343 100644 --- a/embassy-mspm0/src/uart.rs +++ b/embassy-mspm0/src/uart.rs @@ -869,7 +869,7 @@ fn set_baudrate_inner(regs: Regs, clock: u32, baudrate: u32) -> Result<(), Confi // maximum speed is limited to UARTclk/16." // // Based on these requirements, prioritize higher oversampling first to increase tolerance to clock - // deviation. If no valid BRD valud can be found satisifying the highest sample rate, then reduce + // deviation. If no valid BRD value can be found satisifying the highest sample rate, then reduce // sample rate until valid parameters are found. const OVS: [(u8, vals::Hse); 3] = [(16, vals::Hse::OVS16), (8, vals::Hse::OVS8), (3, vals::Hse::OVS3)]; @@ -882,21 +882,47 @@ fn set_baudrate_inner(regs: Regs, clock: u32, baudrate: u32) -> Result<(), Confi }; let mut found = None; - for &(oversampling, hse_value) in &OVS { - if matches!(hse_value, vals::Hse::OVS3) && !x3_invalid { + 'outer: for &(oversampling, hse_value) in &OVS { + if matches!(hse_value, vals::Hse::OVS3) && x3_invalid { + continue; + } + + // Verify that the selected oversampling does not require a clock faster than what the hardware + // is provided. + let Some(min_clock) = baudrate.checked_mul(oversampling as u32) else { + trace!( + "{}x oversampling would cause overflow for clock: {} Hz", + oversampling, + clock + ); + continue; + }; + + if min_clock > clock { + trace!("{} oversampling is too high for clock: {} Hz", oversampling, clock); continue; } for &(div, div_value) in &DIVS { + trace!( + "Trying div: {}, oversampling {} for {} baud", + div, + oversampling, + baudrate + ); + let Some((ibrd, fbrd)) = calculate_brd(clock, div, baudrate, oversampling) else { + trace!("Calculating BRD overflowed: trying another divider"); continue; }; if ibrd < MIN_IBRD || fbrd > MAX_FBRD { + trace!("BRD was invalid: trying another divider"); continue; } found = Some((hse_value, div_value, ibrd, fbrd)); + break 'outer; } } diff --git a/tests/mspm0/.cargo/config.toml b/tests/mspm0/.cargo/config.toml new file mode 100644 index 000000000..825bf3ae9 --- /dev/null +++ b/tests/mspm0/.cargo/config.toml @@ -0,0 +1,8 @@ +[target.'cfg(all(target_arch = "arm", target_os = "none"))'] +runner = "teleprobe local run --chip MSPM0G3507 --protocol swd --elf" + +[build] +target = "thumbv6m-none-eabi" + +[env] +DEFMT_LOG = "trace,embassy_hal_internal=debug" diff --git a/tests/mspm0/Cargo.toml b/tests/mspm0/Cargo.toml new file mode 100644 index 000000000..0566807d7 --- /dev/null +++ b/tests/mspm0/Cargo.toml @@ -0,0 +1,58 @@ +[package] +edition = "2021" +name = "embassy-mspm0-tests" +version = "0.1.0" +license = "MIT OR Apache-2.0" + +[features] +mspm0g3507 = [ "embassy-mspm0/mspm0g350x" ] + +[dependencies] +teleprobe-meta = "1.1" + +embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = [ "defmt" ] } +embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = [ "arch-cortex-m", "executor-thread", "defmt" ] } +embassy-time = { version = "0.4.0", path = "../../embassy-time", features = [ "defmt" ] } +embassy-mspm0 = { version = "0.1.0", path = "../../embassy-mspm0", features = [ "rt", "defmt", "unstable-pac", "time-driver-any" ] } +embassy-embedded-hal = { version = "0.3.0", path = "../../embassy-embedded-hal/"} + +defmt = "1.0.1" +defmt-rtt = "1.0.0" + +cortex-m = { version = "0.7.6", features = [ "inline-asm", "critical-section-single-core" ]} +cortex-m-rt = "0.7.0" +embedded-hal = { package = "embedded-hal", version = "1.0" } +embedded-hal-async = { version = "1.0" } +panic-probe = { version = "0.3.0", features = ["print-defmt"] } +static_cell = "2" +portable-atomic = { version = "1.5", features = ["critical-section"] } + +[profile.dev] +debug = 2 +debug-assertions = true +opt-level = 's' +overflow-checks = true + +[profile.release] +codegen-units = 1 +debug = 2 +debug-assertions = false +incremental = false +lto = "fat" +opt-level = 's' +overflow-checks = false + +# do not optimize proc-macro crates = faster builds from scratch +[profile.dev.build-override] +codegen-units = 8 +debug = false +debug-assertions = false +opt-level = 0 +overflow-checks = false + +[profile.release.build-override] +codegen-units = 8 +debug = false +debug-assertions = false +opt-level = 0 +overflow-checks = false diff --git a/tests/mspm0/build.rs b/tests/mspm0/build.rs new file mode 100644 index 000000000..57b592abf --- /dev/null +++ b/tests/mspm0/build.rs @@ -0,0 +1,24 @@ +use std::error::Error; +use std::path::PathBuf; +use std::{env, fs}; + +fn main() -> Result<(), Box> { + let out = PathBuf::from(env::var("OUT_DIR").unwrap()); + + #[cfg(feature = "mspm0g3507")] + let memory_x = include_bytes!("memory_g3507.x"); + + fs::write(out.join("memory.x"), memory_x).unwrap(); + + println!("cargo:rustc-link-search={}", out.display()); + println!("cargo:rerun-if-changed=link_ram.x"); + // copy main linker script. + fs::write(out.join("link_ram.x"), include_bytes!("../link_ram_cortex_m.x")).unwrap(); + + println!("cargo:rustc-link-arg-bins=--nmagic"); + println!("cargo:rustc-link-arg-bins=-Tlink_ram.x"); + println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); + println!("cargo:rustc-link-arg-bins=-Tteleprobe.x"); + + Ok(()) +} diff --git a/tests/mspm0/memory_g3507.x b/tests/mspm0/memory_g3507.x new file mode 100644 index 000000000..37e381fbd --- /dev/null +++ b/tests/mspm0/memory_g3507.x @@ -0,0 +1,6 @@ +MEMORY +{ + FLASH : ORIGIN = 0x00000000, LENGTH = 128K + /* Select non-parity range of SRAM due to SRAM_ERR_01 errata in SLAZ758 */ + RAM : ORIGIN = 0x20200000, LENGTH = 32K +} diff --git a/tests/mspm0/src/bin/uart.rs b/tests/mspm0/src/bin/uart.rs new file mode 100644 index 000000000..458129d44 --- /dev/null +++ b/tests/mspm0/src/bin/uart.rs @@ -0,0 +1,83 @@ +#![no_std] +#![no_main] + +#[cfg(feature = "mspm0g3507")] +teleprobe_meta::target!(b"lp-mspm0g3507"); + +use defmt::{assert_eq, unwrap, *}; +use embassy_executor::Spawner; +use embassy_mspm0::mode::Blocking; +use embassy_mspm0::uart::{ClockSel, Config, Error, Uart}; +use {defmt_rtt as _, panic_probe as _}; + +fn read(uart: &mut Uart<'_, Blocking>) -> Result<[u8; N], Error> { + let mut buf = [255; N]; + uart.blocking_read(&mut buf)?; + Ok(buf) +} + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_mspm0::init(Default::default()); + info!("Hello World!"); + + // TODO: Allow creating a looped-back UART (so pins are not needed). + // Do not select default UART since the virtual COM port is attached to UART0. + #[cfg(feature = "mspm0g3507")] + let (mut tx, mut rx, mut uart) = (p.PA8, p.PA9, p.UART1); + + const MFCLK_BUAD_RATES: &[u32] = &[1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200]; + + for &rate in MFCLK_BUAD_RATES { + info!("{} baud using MFCLK", rate); + + let mut config = Config::default(); + // MSPM0 hardware supports a loopback mode to allow self test. + config.loop_back_enable = true; + config.baudrate = rate; + + let mut uart = unwrap!(Uart::new_blocking( + uart.reborrow(), + rx.reborrow(), + tx.reborrow(), + config + )); + + // We can't send too many bytes, they have to fit in the FIFO. + // This is because we aren't sending+receiving at the same time. + + let data = [0xC0, 0xDE]; + unwrap!(uart.blocking_write(&data)); + assert_eq!(unwrap!(read(&mut uart)), data); + } + + // 9600 is the maximum possible value for 32.768 kHz. + const LFCLK_BAUD_RATES: &[u32] = &[1200, 2400, 4800, 9600]; + + for &rate in LFCLK_BAUD_RATES { + info!("{} baud using LFCLK", rate); + + let mut config = Config::default(); + // MSPM0 hardware supports a loopback mode to allow self test. + config.loop_back_enable = true; + config.baudrate = rate; + config.clock_source = ClockSel::LfClk; + + let mut uart = expect!(Uart::new_blocking( + uart.reborrow(), + rx.reborrow(), + tx.reborrow(), + config, + )); + + // We can't send too many bytes, they have to fit in the FIFO. + // This is because we aren't sending+receiving at the same time. + + let data = [0xC0, 0xDE]; + unwrap!(uart.blocking_write(&data)); + assert_eq!(unwrap!(read(&mut uart)), data); + } + + info!("Test OK"); + cortex_m::asm::bkpt(); +} From 72f72ee15b42338c60271a82152895130d5865ab Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Mon, 7 Apr 2025 10:13:40 +0200 Subject: [PATCH 0936/1217] chore: update cyw43 bt-hci version The new version contains some fixes to hci serialization. --- cyw43/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cyw43/Cargo.toml b/cyw43/Cargo.toml index 34a51338c..88d1fe506 100644 --- a/cyw43/Cargo.toml +++ b/cyw43/Cargo.toml @@ -36,7 +36,7 @@ heapless = "0.8.0" # Bluetooth deps embedded-io-async = { version = "0.6.0", optional = true } -bt-hci = { version = "0.2.0", optional = true } +bt-hci = { version = "0.3.0", optional = true } [package.metadata.embassy_docs] src_base = "https://github.com/embassy-rs/embassy/blob/cyw43-v$VERSION/cyw43/src/" From 05a6f7a7957d891c20f00f428a36abb0da1c921a Mon Sep 17 00:00:00 2001 From: Sebastian Quilitz Date: Thu, 27 Mar 2025 16:50:56 +0000 Subject: [PATCH 0937/1217] embassy-rp: Implementation of a SpinlockMutex --- embassy-rp/src/lib.rs | 1 + embassy-rp/src/spinlock_mutex.rs | 93 ++++++++++++++++++++++++++++++++ 2 files changed, 94 insertions(+) create mode 100644 embassy-rp/src/spinlock_mutex.rs diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs index 01d26b8e9..f549446bc 100644 --- a/embassy-rp/src/lib.rs +++ b/embassy-rp/src/lib.rs @@ -42,6 +42,7 @@ pub mod rom_data; pub mod rtc; pub mod spi; mod spinlock; +pub mod spinlock_mutex; #[cfg(feature = "time-driver")] pub mod time_driver; #[cfg(feature = "_rp235x")] diff --git a/embassy-rp/src/spinlock_mutex.rs b/embassy-rp/src/spinlock_mutex.rs new file mode 100644 index 000000000..85174cf86 --- /dev/null +++ b/embassy-rp/src/spinlock_mutex.rs @@ -0,0 +1,93 @@ +//! Mutex implementation utilizing an hardware spinlock + +use core::marker::PhantomData; +use core::sync::atomic::Ordering; + +use embassy_sync::blocking_mutex::raw::RawMutex; + +use crate::spinlock::{Spinlock, SpinlockValid}; + +/// A mutex that allows borrowing data across executors and interrupts by utilizing an hardware spinlock +/// +/// # Safety +/// +/// This mutex is safe to share between different executors and interrupts. +pub struct SpinlockRawMutex { + _phantom: PhantomData<()>, +} +unsafe impl Send for SpinlockRawMutex {} +unsafe impl Sync for SpinlockRawMutex {} + +impl SpinlockRawMutex { + /// Create a new `SpinlockRawMutex`. + pub const fn new() -> Self { + Self { _phantom: PhantomData } + } +} + +unsafe impl RawMutex for SpinlockRawMutex +where + Spinlock: SpinlockValid, +{ + const INIT: Self = Self::new(); + + fn lock(&self, f: impl FnOnce() -> R) -> R { + // Store the initial interrupt state in stack variable + let interrupts_active = cortex_m::register::primask::read().is_active(); + + // Spin until we get the lock + loop { + // Need to disable interrupts to ensure that we will not deadlock + // if an interrupt or higher prio locks the spinlock after we acquire the lock + cortex_m::interrupt::disable(); + // Ensure the compiler doesn't re-order accesses and violate safety here + core::sync::atomic::compiler_fence(Ordering::SeqCst); + if let Some(lock) = Spinlock::::try_claim() { + // We just acquired the lock. + // 1. Forget it, so we don't immediately unlock + core::mem::forget(lock); + break; + } + // We didn't get the lock, enable interrupts if they were enabled before we started + if interrupts_active { + // safety: interrupts are only enabled, if they had been enabled before + unsafe { + cortex_m::interrupt::enable(); + } + } + } + + let retval = f(); + + // Ensure the compiler doesn't re-order accesses and violate safety here + core::sync::atomic::compiler_fence(Ordering::SeqCst); + // Release the spinlock to allow others to lock mutex again + // safety: this point is only reached a spinlock was acquired before + unsafe { + Spinlock::::release(); + } + + // Re-enable interrupts if they were enabled before the mutex was locked + if interrupts_active { + // safety: interrupts are only enabled, if they had been enabled before + unsafe { + cortex_m::interrupt::enable(); + } + } + + retval + } +} + +pub mod blocking_mutex { + //! Mutex implementation utilizing an hardware spinlock + use embassy_sync::blocking_mutex::Mutex; + + use crate::spinlock_mutex::SpinlockRawMutex; + /// A mutex that allows borrowing data across executors and interrupts by utilizing an hardware spinlock. + /// + /// # Safety + /// + /// This mutex is safe to share between different executors and interrupts. + pub type SpinlockMutex = Mutex, T>; +} From 313328c09a52ba6f8f30105a3a9f98a76a5aef69 Mon Sep 17 00:00:00 2001 From: Sebastian Quilitz Date: Fri, 28 Mar 2025 22:54:13 +0100 Subject: [PATCH 0938/1217] embassy-rp: add multicore test for SpinlockRawMutex --- ci.sh | 1 + tests/rp/src/bin/spinlock_mutex_multicore.rs | 54 ++++++++++++++++++++ 2 files changed, 55 insertions(+) create mode 100644 tests/rp/src/bin/spinlock_mutex_multicore.rs diff --git a/ci.sh b/ci.sh index 5b63c507b..39dd76b74 100755 --- a/ci.sh +++ b/ci.sh @@ -338,6 +338,7 @@ rm out/tests/stm32u5a5zj/usart # As of 2025-02-17 these tests work when run from flash rm out/tests/pimoroni-pico-plus-2/multicore rm out/tests/pimoroni-pico-plus-2/gpio_multicore +rm out/tests/pimoroni-pico-plus-2/spinlock_mutex_multicore # Doesn't work when run from ram on the 2350 rm out/tests/pimoroni-pico-plus-2/flash # This test passes locally but fails on the HIL, no idea why diff --git a/tests/rp/src/bin/spinlock_mutex_multicore.rs b/tests/rp/src/bin/spinlock_mutex_multicore.rs new file mode 100644 index 000000000..ebcf1ca32 --- /dev/null +++ b/tests/rp/src/bin/spinlock_mutex_multicore.rs @@ -0,0 +1,54 @@ +#![no_std] +#![no_main] +#[cfg(feature = "rp2040")] +teleprobe_meta::target!(b"rpi-pico"); +#[cfg(feature = "rp235xb")] +teleprobe_meta::target!(b"pimoroni-pico-plus-2"); + +use defmt::{info, unwrap}; +use embassy_executor::Executor; +use embassy_rp::multicore::{spawn_core1, Stack}; +use embassy_rp::spinlock_mutex::SpinlockRawMutex; +use embassy_sync::channel::Channel; +use static_cell::StaticCell; +use {defmt_rtt as _, panic_probe as _}; + +static mut CORE1_STACK: Stack<1024> = Stack::new(); +static EXECUTOR0: StaticCell = StaticCell::new(); +static EXECUTOR1: StaticCell = StaticCell::new(); +static CHANNEL0: Channel, bool, 1> = Channel::new(); +static CHANNEL1: Channel, bool, 1> = Channel::new(); + +#[cortex_m_rt::entry] +fn main() -> ! { + let p = embassy_rp::init(Default::default()); + spawn_core1( + p.CORE1, + unsafe { &mut *core::ptr::addr_of_mut!(CORE1_STACK) }, + move || { + let executor1 = EXECUTOR1.init(Executor::new()); + executor1.run(|spawner| unwrap!(spawner.spawn(core1_task()))); + }, + ); + let executor0 = EXECUTOR0.init(Executor::new()); + executor0.run(|spawner| unwrap!(spawner.spawn(core0_task()))); +} + +#[embassy_executor::task] +async fn core0_task() { + info!("CORE0 is running"); + let ping = true; + CHANNEL0.send(ping).await; + let pong = CHANNEL1.receive().await; + assert_eq!(ping, pong); + + info!("Test OK"); + cortex_m::asm::bkpt(); +} + +#[embassy_executor::task] +async fn core1_task() { + info!("CORE1 is running"); + let ping = CHANNEL0.receive().await; + CHANNEL1.send(ping).await; +} From 3cb178e78e737fd83e78d04233e7e13f668f6c61 Mon Sep 17 00:00:00 2001 From: Steven Friedman Date: Tue, 8 Apr 2025 09:17:54 -0400 Subject: [PATCH 0939/1217] Frequency display is now consistent --- embassy-stm32/src/adc/c0.rs | 2 +- embassy-stm32/src/adc/g4.rs | 2 +- embassy-stm32/src/adc/u5_adc4.rs | 2 +- embassy-stm32/src/adc/v4.rs | 2 +- embassy-stm32/src/rcc/h.rs | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/embassy-stm32/src/adc/c0.rs b/embassy-stm32/src/adc/c0.rs index a9c1d8faf..a9f0da07e 100644 --- a/embassy-stm32/src/adc/c0.rs +++ b/embassy-stm32/src/adc/c0.rs @@ -163,7 +163,7 @@ impl<'d, T: Instance> Adc<'d, T> { T::common_regs().ccr().modify(|w| w.set_presc(prescaler.presc())); let frequency = Hertz(T::frequency().0 / prescaler.divisor()); - debug!("ADC frequency set to {} Hz", frequency.0); + debug!("ADC frequency set to {} Hz", frequency); if frequency > MAX_ADC_CLK_FREQ { panic!("Maximal allowed frequency for the ADC is {} MHz and it varies with different packages, refer to ST docs for more information.", MAX_ADC_CLK_FREQ.0 / 1_000_000 ); diff --git a/embassy-stm32/src/adc/g4.rs b/embassy-stm32/src/adc/g4.rs index 6b9182ad6..8d13c85be 100644 --- a/embassy-stm32/src/adc/g4.rs +++ b/embassy-stm32/src/adc/g4.rs @@ -143,7 +143,7 @@ impl<'d, T: Instance> Adc<'d, T> { T::common_regs().ccr().modify(|w| w.set_presc(prescaler.presc())); let frequency = Hertz(T::frequency().0 / prescaler.divisor()); - info!("ADC frequency set to {} Hz", frequency.0); + info!("ADC frequency set to {} Hz", frequency); if frequency > MAX_ADC_CLK_FREQ { panic!("Maximal allowed frequency for the ADC is {} MHz and it varies with different packages, refer to ST docs for more information.", MAX_ADC_CLK_FREQ.0 / 1_000_000 ); diff --git a/embassy-stm32/src/adc/u5_adc4.rs b/embassy-stm32/src/adc/u5_adc4.rs index a5cfbfdcf..eee500ef5 100644 --- a/embassy-stm32/src/adc/u5_adc4.rs +++ b/embassy-stm32/src/adc/u5_adc4.rs @@ -193,7 +193,7 @@ impl<'d, T: Instance> Adc4<'d, T> { T::regs().ccr().modify(|w| w.set_presc(prescaler.presc())); let frequency = Hertz(T::frequency().0 / prescaler.divisor()); - info!("ADC4 frequency set to {} Hz", frequency.0); + info!("ADC4 frequency set to {} Hz", frequency); if frequency > MAX_ADC_CLK_FREQ { panic!("Maximal allowed frequency for ADC4 is {} MHz and it varies with different packages, refer to ST docs for more information.", MAX_ADC_CLK_FREQ.0 / 1_000_000 ); diff --git a/embassy-stm32/src/adc/v4.rs b/embassy-stm32/src/adc/v4.rs index 5910eef30..9bc8c9712 100644 --- a/embassy-stm32/src/adc/v4.rs +++ b/embassy-stm32/src/adc/v4.rs @@ -166,7 +166,7 @@ impl<'d, T: Instance> Adc<'d, T> { T::common_regs().ccr().modify(|w| w.set_presc(prescaler.presc())); let frequency = Hertz(T::frequency().0 / prescaler.divisor()); - info!("ADC frequency set to {} Hz", frequency.0); + info!("ADC frequency set to {} Hz", frequency); if frequency > MAX_ADC_CLK_FREQ { panic!("Maximal allowed frequency for the ADC is {} MHz and it varies with different packages, refer to ST docs for more information.", MAX_ADC_CLK_FREQ.0 / 1_000_000 ); diff --git a/embassy-stm32/src/rcc/h.rs b/embassy-stm32/src/rcc/h.rs index d80fbeb1e..39af84ad3 100644 --- a/embassy-stm32/src/rcc/h.rs +++ b/embassy-stm32/src/rcc/h.rs @@ -792,7 +792,7 @@ fn init_pll(num: usize, config: Option, input: &PllInput) -> PllOutput { } else if wide_allowed && VCO_WIDE_RANGE.contains(&vco_clk) { Pllvcosel::WIDE_VCO } else { - panic!("pll vco_clk out of range: {} hz", vco_clk.0) + panic!("pll vco_clk out of range: {} hz", vco_clk) }; let p = config.divp.map(|div| { From bbf2a641dd6760777d862d8de49217c632b30156 Mon Sep 17 00:00:00 2001 From: Steven Friedman Date: Tue, 8 Apr 2025 09:36:35 -0400 Subject: [PATCH 0940/1217] remove Hz from log --- embassy-stm32/src/adc/c0.rs | 2 +- embassy-stm32/src/adc/g4.rs | 2 +- embassy-stm32/src/adc/u5_adc4.rs | 2 +- embassy-stm32/src/adc/v4.rs | 2 +- embassy-stm32/src/rcc/h.rs | 4 ++-- embassy-stm32/src/rcc/u5.rs | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/embassy-stm32/src/adc/c0.rs b/embassy-stm32/src/adc/c0.rs index a9f0da07e..936ad7413 100644 --- a/embassy-stm32/src/adc/c0.rs +++ b/embassy-stm32/src/adc/c0.rs @@ -163,7 +163,7 @@ impl<'d, T: Instance> Adc<'d, T> { T::common_regs().ccr().modify(|w| w.set_presc(prescaler.presc())); let frequency = Hertz(T::frequency().0 / prescaler.divisor()); - debug!("ADC frequency set to {} Hz", frequency); + debug!("ADC frequency set to {}", frequency); if frequency > MAX_ADC_CLK_FREQ { panic!("Maximal allowed frequency for the ADC is {} MHz and it varies with different packages, refer to ST docs for more information.", MAX_ADC_CLK_FREQ.0 / 1_000_000 ); diff --git a/embassy-stm32/src/adc/g4.rs b/embassy-stm32/src/adc/g4.rs index 8d13c85be..91be53607 100644 --- a/embassy-stm32/src/adc/g4.rs +++ b/embassy-stm32/src/adc/g4.rs @@ -143,7 +143,7 @@ impl<'d, T: Instance> Adc<'d, T> { T::common_regs().ccr().modify(|w| w.set_presc(prescaler.presc())); let frequency = Hertz(T::frequency().0 / prescaler.divisor()); - info!("ADC frequency set to {} Hz", frequency); + info!("ADC frequency set to {}", frequency); if frequency > MAX_ADC_CLK_FREQ { panic!("Maximal allowed frequency for the ADC is {} MHz and it varies with different packages, refer to ST docs for more information.", MAX_ADC_CLK_FREQ.0 / 1_000_000 ); diff --git a/embassy-stm32/src/adc/u5_adc4.rs b/embassy-stm32/src/adc/u5_adc4.rs index eee500ef5..1dd664366 100644 --- a/embassy-stm32/src/adc/u5_adc4.rs +++ b/embassy-stm32/src/adc/u5_adc4.rs @@ -193,7 +193,7 @@ impl<'d, T: Instance> Adc4<'d, T> { T::regs().ccr().modify(|w| w.set_presc(prescaler.presc())); let frequency = Hertz(T::frequency().0 / prescaler.divisor()); - info!("ADC4 frequency set to {} Hz", frequency); + info!("ADC4 frequency set to {}", frequency); if frequency > MAX_ADC_CLK_FREQ { panic!("Maximal allowed frequency for ADC4 is {} MHz and it varies with different packages, refer to ST docs for more information.", MAX_ADC_CLK_FREQ.0 / 1_000_000 ); diff --git a/embassy-stm32/src/adc/v4.rs b/embassy-stm32/src/adc/v4.rs index 9bc8c9712..4d2e0f0df 100644 --- a/embassy-stm32/src/adc/v4.rs +++ b/embassy-stm32/src/adc/v4.rs @@ -166,7 +166,7 @@ impl<'d, T: Instance> Adc<'d, T> { T::common_regs().ccr().modify(|w| w.set_presc(prescaler.presc())); let frequency = Hertz(T::frequency().0 / prescaler.divisor()); - info!("ADC frequency set to {} Hz", frequency); + info!("ADC frequency set to {}", frequency); if frequency > MAX_ADC_CLK_FREQ { panic!("Maximal allowed frequency for the ADC is {} MHz and it varies with different packages, refer to ST docs for more information.", MAX_ADC_CLK_FREQ.0 / 1_000_000 ); diff --git a/embassy-stm32/src/rcc/h.rs b/embassy-stm32/src/rcc/h.rs index 39af84ad3..33d698861 100644 --- a/embassy-stm32/src/rcc/h.rs +++ b/embassy-stm32/src/rcc/h.rs @@ -575,7 +575,7 @@ pub(crate) unsafe fn init(config: Config) { Hertz(24_000_000) => Usbrefcksel::MHZ24, Hertz(26_000_000) => Usbrefcksel::MHZ26, Hertz(32_000_000) => Usbrefcksel::MHZ32, - _ => panic!("cannot select USBPHYC reference clock with source frequency of {} Hz, must be one of 16, 19.2, 20, 24, 26, 32 MHz", clk_val), + _ => panic!("cannot select USBPHYC reference clock with source frequency of {}, must be one of 16, 19.2, 20, 24, 26, 32 MHz", clk_val), }, None => Usbrefcksel::MHZ24, }; @@ -792,7 +792,7 @@ fn init_pll(num: usize, config: Option, input: &PllInput) -> PllOutput { } else if wide_allowed && VCO_WIDE_RANGE.contains(&vco_clk) { Pllvcosel::WIDE_VCO } else { - panic!("pll vco_clk out of range: {} hz", vco_clk) + panic!("pll vco_clk out of range: {}", vco_clk) }; let p = config.divp.map(|div| { diff --git a/embassy-stm32/src/rcc/u5.rs b/embassy-stm32/src/rcc/u5.rs index dc77dc540..d15eb53f8 100644 --- a/embassy-stm32/src/rcc/u5.rs +++ b/embassy-stm32/src/rcc/u5.rs @@ -315,7 +315,7 @@ pub(crate) unsafe fn init(config: Config) { Hertz(24_000_000) => Usbrefcksel::MHZ24, Hertz(26_000_000) => Usbrefcksel::MHZ26, Hertz(32_000_000) => Usbrefcksel::MHZ32, - _ => panic!("cannot select OTG_HS reference clock with source frequency of {} Hz, must be one of 16, 19.2, 20, 24, 26, 32 MHz", clk_val), + _ => panic!("cannot select OTG_HS reference clock with source frequency of {}, must be one of 16, 19.2, 20, 24, 26, 32 MHz", clk_val), }, None => Usbrefcksel::MHZ24, }; From 4239a43810f55f2e35b313c5bb9cc59ad432fcc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Tue, 8 Apr 2025 16:21:41 +0200 Subject: [PATCH 0941/1217] Hand-roll defmt::Format for Hertz --- embassy-stm32/src/time.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/embassy-stm32/src/time.rs b/embassy-stm32/src/time.rs index 71fe668a9..532877f70 100644 --- a/embassy-stm32/src/time.rs +++ b/embassy-stm32/src/time.rs @@ -5,7 +5,6 @@ use core::ops::{Div, Mul}; /// Hertz #[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Copy, Debug)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct Hertz(pub u32); impl Display for Hertz { @@ -14,6 +13,13 @@ impl Display for Hertz { } } +#[cfg(feature = "defmt")] +impl defmt::Format for Hertz { + fn format(&self, f: defmt::Formatter) { + defmt::write!(f, "{=u32} Hz", self.0) + } +} + impl Hertz { /// Create a `Hertz` from the given hertz. pub const fn hz(hertz: u32) -> Self { From b5e6d22117e0a11ae717dc7ec904ca25db56cd29 Mon Sep 17 00:00:00 2001 From: lonesometraveler Date: Tue, 8 Apr 2025 15:49:27 -0400 Subject: [PATCH 0942/1217] Update Cargo.toml --- examples/boot/application/rp/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/boot/application/rp/Cargo.toml b/examples/boot/application/rp/Cargo.toml index fa4a7d44f..3c0d207d1 100644 --- a/examples/boot/application/rp/Cargo.toml +++ b/examples/boot/application/rp/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.6.2", path = "../../../../embassy-sync" } -embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "arch-cortex-m", "executor-thread"] } +embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [] } embassy-rp = { version = "0.4.0", path = "../../../../embassy-rp", features = ["time-driver", "rp2040"] } embassy-boot-rp = { version = "0.5.0", path = "../../../../embassy-boot-rp", features = [] } From 1a4b1a9476cf4fa6d962379c1deabbb4bf046b84 Mon Sep 17 00:00:00 2001 From: Phil-hacker Date: Tue, 8 Apr 2025 22:07:36 +0200 Subject: [PATCH 0943/1217] update `avr_device` --- embassy-executor/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-executor/Cargo.toml b/embassy-executor/Cargo.toml index 8d7cf715f..0f69d3c8a 100644 --- a/embassy-executor/Cargo.toml +++ b/embassy-executor/Cargo.toml @@ -50,7 +50,7 @@ wasm-bindgen = { version = "0.2.82", optional = true } js-sys = { version = "0.3", optional = true } # arch-avr dependencies -avr-device = { version = "0.5.3", optional = true } +avr-device = { version = "0.7.0", optional = true } [dev-dependencies] critical-section = { version = "1.1", features = ["std"] } From 66a02a4f8dceaa7c7e4f30df64b1011943f68423 Mon Sep 17 00:00:00 2001 From: Phil-hacker Date: Tue, 8 Apr 2025 22:10:17 +0200 Subject: [PATCH 0944/1217] fix the avr executor --- embassy-executor/src/raw/mod.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs index 56faa911d..d14fe9281 100644 --- a/embassy-executor/src/raw/mod.rs +++ b/embassy-executor/src/raw/mod.rs @@ -28,9 +28,11 @@ use core::marker::PhantomData; use core::mem; use core::pin::Pin; use core::ptr::NonNull; -use core::sync::atomic::{AtomicPtr, Ordering}; +use core::sync::atomic::Ordering; use core::task::{Context, Poll}; +use portable_atomic::AtomicPtr; + use self::run_queue::{RunQueue, RunQueueItem}; use self::state::State; use self::util::{SyncUnsafeCell, UninitCell}; From ce40a39a874bbf34d0438afce189bf2fca5bb1e9 Mon Sep 17 00:00:00 2001 From: Phil-hacker Date: Tue, 8 Apr 2025 22:15:05 +0200 Subject: [PATCH 0945/1217] fix compilation on anything not using the feature `arch-avr` --- embassy-executor/src/raw/mod.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs index d14fe9281..41dade75e 100644 --- a/embassy-executor/src/raw/mod.rs +++ b/embassy-executor/src/raw/mod.rs @@ -29,8 +29,10 @@ use core::mem; use core::pin::Pin; use core::ptr::NonNull; use core::sync::atomic::Ordering; +#[cfg(not(feature = "arch-avr"))] +use core::sync::atomic::AtomicPtr; use core::task::{Context, Poll}; - +#[cfg(feature = "arch-avr")] use portable_atomic::AtomicPtr; use self::run_queue::{RunQueue, RunQueueItem}; From 3a85ecebef61017069da9f1e1d48d20c3889b76b Mon Sep 17 00:00:00 2001 From: Phil-hacker Date: Tue, 8 Apr 2025 22:15:53 +0200 Subject: [PATCH 0946/1217] fix rustfmt --- embassy-executor/src/raw/mod.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs index 41dade75e..88d839e07 100644 --- a/embassy-executor/src/raw/mod.rs +++ b/embassy-executor/src/raw/mod.rs @@ -28,10 +28,11 @@ use core::marker::PhantomData; use core::mem; use core::pin::Pin; use core::ptr::NonNull; -use core::sync::atomic::Ordering; #[cfg(not(feature = "arch-avr"))] use core::sync::atomic::AtomicPtr; +use core::sync::atomic::Ordering; use core::task::{Context, Poll}; + #[cfg(feature = "arch-avr")] use portable_atomic::AtomicPtr; From aa9a16e569dfb56ce2b689733975f4d854af0b00 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 3 Apr 2025 08:47:25 -0700 Subject: [PATCH 0947/1217] Add embassy-imxrt Adds initial support for MIMXRT600 series MCUs from NXP. Subsequent PRs will add more drivers. --- ci.sh | 2 + docs/pages/imxrt.adoc | 13 + docs/pages/system.adoc | 1 + embassy-imxrt/Cargo.toml | 84 ++ embassy-imxrt/README.md | 59 + embassy-imxrt/src/chips/mimxrt633s.rs | 389 ++++++ embassy-imxrt/src/chips/mimxrt685s.rs | 388 ++++++ embassy-imxrt/src/clocks.rs | 1687 +++++++++++++++++++++++++ embassy-imxrt/src/fmt.rs | 257 ++++ embassy-imxrt/src/gpio.rs | 1060 ++++++++++++++++ embassy-imxrt/src/iopctl.rs | 717 +++++++++++ embassy-imxrt/src/lib.rs | 130 ++ examples/mimxrt6/.cargo/config.toml | 17 + examples/mimxrt6/.gitignore | 14 + examples/mimxrt6/Cargo.toml | 60 + examples/mimxrt6/README.md | 18 + examples/mimxrt6/build.rs | 45 + examples/mimxrt6/memory.x | 34 + examples/mimxrt6/src/bin/blinky.rs | 29 + examples/mimxrt6/src/bin/hello.rs | 17 + examples/mimxrt6/src/lib.rs | 20 + 21 files changed, 5041 insertions(+) create mode 100644 docs/pages/imxrt.adoc create mode 100644 embassy-imxrt/Cargo.toml create mode 100644 embassy-imxrt/README.md create mode 100644 embassy-imxrt/src/chips/mimxrt633s.rs create mode 100644 embassy-imxrt/src/chips/mimxrt685s.rs create mode 100644 embassy-imxrt/src/clocks.rs create mode 100644 embassy-imxrt/src/fmt.rs create mode 100644 embassy-imxrt/src/gpio.rs create mode 100644 embassy-imxrt/src/iopctl.rs create mode 100644 embassy-imxrt/src/lib.rs create mode 100644 examples/mimxrt6/.cargo/config.toml create mode 100644 examples/mimxrt6/.gitignore create mode 100644 examples/mimxrt6/Cargo.toml create mode 100644 examples/mimxrt6/README.md create mode 100644 examples/mimxrt6/build.rs create mode 100644 examples/mimxrt6/memory.x create mode 100644 examples/mimxrt6/src/bin/blinky.rs create mode 100644 examples/mimxrt6/src/bin/hello.rs create mode 100644 examples/mimxrt6/src/lib.rs diff --git a/ci.sh b/ci.sh index 810a9ab42..f08c38b7c 100755 --- a/ci.sh +++ b/ci.sh @@ -53,6 +53,8 @@ cargo batch \ --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,proto-ipv6,medium-ip \ --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,proto-ipv6,medium-ip,medium-ethernet \ --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,proto-ipv6,medium-ip,medium-ethernet,medium-ieee802154 \ + --- build --release --manifest-path embassy-imxrt/Cargo.toml --target thumbv8m.main-none-eabihf --features mimxrt633s,defmt,unstable-pac \ + --- build --release --manifest-path embassy-imxrt/Cargo.toml --target thumbv8m.main-none-eabihf --features mimxrt685s,defmt,unstable-pac \ --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv6m-none-eabi --features nrf51,gpiote,time,time-driver-rtc1 \ --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52805,gpiote,time,time-driver-rtc1 \ --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52810,gpiote,time,time-driver-rtc1 \ diff --git a/docs/pages/imxrt.adoc b/docs/pages/imxrt.adoc new file mode 100644 index 000000000..adf5218e8 --- /dev/null +++ b/docs/pages/imxrt.adoc @@ -0,0 +1,13 @@ += Embassy iMXRT HAL + +The link: link:https://github.com/embassy-rs/embassy/tree/main/embassy-imxrt[Embassy iMXRT HAL] is based on the following PACs (Peripheral Access Crate): + +* link:https://github.com/OpenDevicePartnership/mimxrt685s-pac[mimxrt685s-pac] +* link:https://github.com/OpenDevicePartnership/mimxrt633s-pac[mimxrt633s-pac] + +== Peripherals + +The following peripherals have a HAL implementation at present + +* GPIO + diff --git a/docs/pages/system.adoc b/docs/pages/system.adoc index 985f92b18..09241a8df 100644 --- a/docs/pages/system.adoc +++ b/docs/pages/system.adoc @@ -6,6 +6,7 @@ include::runtime.adoc[leveloffset = 2] include::bootloader.adoc[leveloffset = 2] include::time_keeping.adoc[leveloffset = 2] include::hal.adoc[leveloffset = 2] +include::imxrt.adoc[leveloffset = 2] include::nrf.adoc[leveloffset = 2] include::stm32.adoc[leveloffset = 2] include::sharing_peripherals.adoc[leveloffset = 2] diff --git a/embassy-imxrt/Cargo.toml b/embassy-imxrt/Cargo.toml new file mode 100644 index 000000000..38087bf77 --- /dev/null +++ b/embassy-imxrt/Cargo.toml @@ -0,0 +1,84 @@ +[package] +name = "embassy-imxrt" +version = "0.1.0" +edition = "2021" +license = "MIT" +description = "Embassy Hardware Abstraction Layer (HAL) for the IMXRT microcontroller" +keywords = ["embedded", "async", "imxrt", "rt600", "embedded-hal"] +categories = ["embedded", "hardware-support", "no-std", "asynchronous"] +repository = "https://github.com/embassy-rs/embassy" +documentation = "https://docs.embassy.dev/embassy-imxrt" + +[package.metadata.embassy_docs] +src_base = "https://github.com/embassy-rs/embassy/blob/embassy-imxrt-v$VERSION/embassy-imxrt/src/" +src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-imxrt/src/" +features = ["defmt", "unstable-pac"] +flavors = [ + { regex_feature = "mimxrt6.*", target = "thumbv8m.main-none-eabihf" } +] + +[package.metadata.docs.rs] +features = ["mimxrt685s", "defmt", "unstable-pac"] +rustdoc-args = ["--cfg", "docsrs"] + +[features] +default = ["rt"] + +## Cortex-M runtime (enabled by default) +rt = [ + "mimxrt685s-pac?/rt", + "mimxrt633s-pac?/rt", +] + +## Enable defmt +defmt = ["dep:defmt", "embassy-hal-internal/defmt", "embassy-sync/defmt", "mimxrt685s-pac?/defmt", "mimxrt633s-pac?/defmt"] + +## Reexport the PAC for the currently enabled chip at `embassy_imxrt::pac` (unstable) +unstable-pac = [] + +# Features starting with `_` are for internal use only. They're not intended +# to be enabled by other crates, and are not covered by semver guarantees. + +_mimxrt685s = [] +_mimxrt633s = ["_espi"] + +# Peripherals +_espi = [] + +#! ### Chip selection features +## MIMXRT685S +mimxrt685s = ["mimxrt685s-pac", "_mimxrt685s"] +## MIMXRT633S +mimxrt633s = ["mimxrt633s-pac", "_mimxrt633s"] + +[dependencies] +embassy-sync = { version = "0.6.2", path = "../embassy-sync" } +embassy-hal-internal = { version = "0.2.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-3"] } +embassy-embedded-hal = { version = "0.3.0", path = "../embassy-embedded-hal", default-features = false } +embassy-futures = { version = "0.1.1", path = "../embassy-futures" } + +defmt = { version = "1.0", optional = true } +log = { version = "0.4.14", optional = true } +nb = "1.0.0" +cfg-if = "1.0.0" +cortex-m-rt = ">=0.7.3,<0.8" +cortex-m = "0.7.6" +critical-section = "1.1" +embedded-io = { version = "0.6.1" } +embedded-io-async = { version = "0.6.1" } +rand_core = "0.6.4" +fixed = "1.23.1" + +embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = [ + "unproven", +] } +embedded-hal-1 = { package = "embedded-hal", version = "1.0" } +embedded-hal-async = { version = "1.0" } +embedded-hal-nb = { version = "1.0" } + +document-features = "0.2.7" +paste = "1.0" + +# PACs +mimxrt685s-pac = { version = "0.4.0", optional = true, features = ["rt", "critical-section"] } +mimxrt633s-pac = { version = "0.4.0", optional = true, features = ["rt", "critical-section"] } diff --git a/embassy-imxrt/README.md b/embassy-imxrt/README.md new file mode 100644 index 000000000..cfdfb8ce2 --- /dev/null +++ b/embassy-imxrt/README.md @@ -0,0 +1,59 @@ +# Embassy iMXRT HAL + +## Introduction + +HALs implement safe, idiomatic Rust APIs to use the hardware capabilities, so +raw register manipulation is not needed. + +The Embassy iMXRT HAL targets the NXP iMXRT Family of MCUs. The HAL implements +both blocking and async APIs for many peripherals. The benefit of using the +async APIs is that the HAL takes care of waiting for peripherals to complete +operations in low power mode and handling of interrupts, so that applications +can focus on business logic. + +NOTE: The Embassy HALs can be used both for non-async and async operations. For +async, you can choose which runtime you want to use. + +For a complete list of available peripherals and features, see the +[embassy-imxrt documentation](https://docs.embassy.dev/embassy-imxrt). + +## Hardware support + +The `embassy-imxrt` HAL currently supports two main variants of the iMXRT +family: + +* MIMXRT685S + ([examples](https://github.com/OpenDevicePartnership/embassy-imxrt/tree/main/examples/rt685s-evk)) +* MIMXRT633s + ([examples](https://github.com/OpenDevicePartnership/embassy-imxrt/tree/main/examples/rt633)) + +Several peripherals are supported and tested on both supported chip variants. To +check what's available, make sure to the MCU you're targetting in the top menu +in the [documentation](https://docs.embassy.dev/embassy-imxrt). + +## TrustZone support + +TrustZone support is yet to be implemented. + +## Time driver + +If the `time-driver` feature is enabled, the HAL uses the RTC peripheral as a +global time driver for [embassy-time](https://crates.io/crates/embassy-time), +with a tick rate of 32768 Hz. + +## Embedded-hal + +The `embassy-imxrt` HAL implements the traits from +[embedded-hal](https://crates.io/crates/embedded-hal) (v0.2 and 1.0) and +[embedded-hal-async](https://crates.io/crates/embedded-hal-async), as well as +[embedded-io](https://crates.io/crates/embedded-io) and +[embedded-io-async](https://crates.io/crates/embedded-io-async). + +## Interoperability + +This crate can run on any executor. + +Optionally, some features requiring +[`embassy-time`](https://crates.io/crates/embassy-time) can be activated with +the `time` feature. If you enable it, you must link an `embassy-time` driver in +your project. diff --git a/embassy-imxrt/src/chips/mimxrt633s.rs b/embassy-imxrt/src/chips/mimxrt633s.rs new file mode 100644 index 000000000..30072132a --- /dev/null +++ b/embassy-imxrt/src/chips/mimxrt633s.rs @@ -0,0 +1,389 @@ +pub use mimxrt633s_pac as pac; + +#[allow(clippy::missing_safety_doc)] +pub mod interrupts { + embassy_hal_internal::interrupt_mod!( + ACMP, + ADC0, + CASPER, + CTIMER0, + CTIMER1, + CTIMER2, + CTIMER3, + CTIMER4, + DMA0, + DMA1, + DMIC0, + ESPI, + FLEXCOMM0, + FLEXCOMM1, + FLEXCOMM14, + FLEXCOMM15, + FLEXCOMM2, + FLEXCOMM3, + FLEXCOMM4, + FLEXCOMM5, + FLEXCOMM6, + FLEXCOMM7, + FLEXSPI, + GPIO_INTA, + GPIO_INTB, + HASHCRYPT, + HWVAD0, + HYPERVISOR, + I3C0, + MRT0, + MU_A, + OS_EVENT, + PIN_INT0, + PIN_INT1, + PIN_INT2, + PIN_INT3, + PIN_INT4, + PIN_INT5, + PIN_INT6, + PIN_INT7, + PMC_PMIC, + POWERQUAD, + PUF, + RNG, + RTC, + SCT0, + SECUREVIOLATION, + SGPIO_INTA, + SGPIO_INTB, + USB, + USBPHY_DCD, + USB_WAKEUP, + USDHC0, + USDHC1, + UTICK0, + WDT0, + WDT1, + ); +} + +embassy_hal_internal::peripherals!( + ACMP, + ADC0, + CASPER, + CRC, + CTIMER0_COUNT_CHANNEL0, + CTIMER0_COUNT_CHANNEL1, + CTIMER0_COUNT_CHANNEL2, + CTIMER0_COUNT_CHANNEL3, + CTIMER0_CAPTURE_CHANNEL0, + CTIMER0_CAPTURE_CHANNEL1, + CTIMER0_CAPTURE_CHANNEL2, + CTIMER0_CAPTURE_CHANNEL3, + CTIMER1_COUNT_CHANNEL0, + CTIMER1_COUNT_CHANNEL1, + CTIMER1_COUNT_CHANNEL2, + CTIMER1_COUNT_CHANNEL3, + CTIMER1_CAPTURE_CHANNEL0, + CTIMER1_CAPTURE_CHANNEL1, + CTIMER1_CAPTURE_CHANNEL2, + CTIMER1_CAPTURE_CHANNEL3, + CTIMER2_COUNT_CHANNEL0, + CTIMER2_COUNT_CHANNEL1, + CTIMER2_COUNT_CHANNEL2, + CTIMER2_COUNT_CHANNEL3, + CTIMER2_CAPTURE_CHANNEL0, + CTIMER2_CAPTURE_CHANNEL1, + CTIMER2_CAPTURE_CHANNEL2, + CTIMER2_CAPTURE_CHANNEL3, + CTIMER3_COUNT_CHANNEL0, + CTIMER3_COUNT_CHANNEL1, + CTIMER3_COUNT_CHANNEL2, + CTIMER3_COUNT_CHANNEL3, + CTIMER3_CAPTURE_CHANNEL0, + CTIMER3_CAPTURE_CHANNEL1, + CTIMER3_CAPTURE_CHANNEL2, + CTIMER3_CAPTURE_CHANNEL3, + CTIMER4_COUNT_CHANNEL0, + CTIMER4_COUNT_CHANNEL1, + CTIMER4_COUNT_CHANNEL2, + CTIMER4_COUNT_CHANNEL3, + CTIMER4_CAPTURE_CHANNEL0, + CTIMER4_CAPTURE_CHANNEL1, + CTIMER4_CAPTURE_CHANNEL2, + CTIMER4_CAPTURE_CHANNEL3, + DMA0, + DMA0_CH0, + DMA0_CH1, + DMA0_CH2, + DMA0_CH3, + DMA0_CH4, + DMA0_CH5, + DMA0_CH6, + DMA0_CH7, + DMA0_CH8, + DMA0_CH9, + DMA0_CH10, + DMA0_CH11, + DMA0_CH12, + DMA0_CH13, + DMA0_CH14, + DMA0_CH15, + DMA0_CH16, + DMA0_CH17, + DMA0_CH18, + DMA0_CH19, + DMA0_CH20, + DMA0_CH21, + DMA0_CH22, + DMA0_CH23, + DMA0_CH24, + DMA0_CH25, + DMA0_CH26, + DMA0_CH27, + DMA0_CH28, + DMA0_CH29, + DMA0_CH30, + DMA0_CH31, + DMA0_CH32, + DMA1, + DMA1_CH0, + DMA1_CH1, + DMA1_CH2, + DMA1_CH3, + DMA1_CH4, + DMA1_CH5, + DMA1_CH6, + DMA1_CH7, + DMA1_CH8, + DMA1_CH9, + DMA1_CH10, + DMA1_CH11, + DMA1_CH12, + DMA1_CH13, + DMA1_CH14, + DMA1_CH15, + DMA1_CH16, + DMA1_CH17, + DMA1_CH18, + DMA1_CH19, + DMA1_CH20, + DMA1_CH21, + DMA1_CH22, + DMA1_CH23, + DMA1_CH24, + DMA1_CH25, + DMA1_CH26, + DMA1_CH27, + DMA1_CH28, + DMA1_CH29, + DMA1_CH30, + DMA1_CH31, + DMA1_CH32, + DMIC0, + DSPWAKE, + ESPI, + FLEXCOMM0, + FLEXCOMM1, + FLEXCOMM14, + FLEXCOMM15, + FLEXCOMM2, + FLEXCOMM3, + FLEXCOMM4, + FLEXCOMM5, + FLEXCOMM6, + FLEXCOMM7, + FLEXSPI, + FREQME, + GPIO_INTA, + GPIO_INTB, + HASHCRYPT, + HSGPIO0, + HSGPIO1, + HSGPIO2, + HSGPIO3, + HSGPIO4, + HSGPIO5, + HSGPIO6, + HSGPIO7, + HWVAD0, + HYPERVISOR, + I3C0, + MRT0, + MU_A, + OS_EVENT, + PIN_INT0, + PIN_INT1, + PIN_INT2, + PIN_INT3, + PIN_INT4, + PIN_INT5, + PIN_INT6, + PIN_INT7, + PIO0_0, + PIO0_1, + PIO0_10, + PIO0_11, + PIO0_12, + PIO0_13, + PIO0_14, + PIO0_15, + PIO0_16, + PIO0_17, + PIO0_18, + PIO0_19, + PIO0_2, + PIO0_20, + PIO0_21, + PIO0_22, + PIO0_23, + PIO0_24, + PIO0_25, + PIO0_26, + PIO0_27, + PIO0_28, + PIO0_29, + PIO0_3, + PIO0_30, + PIO0_31, + PIO0_4, + PIO0_5, + PIO0_6, + PIO0_7, + PIO0_8, + PIO0_9, + PIO1_0, + PIO1_1, + PIO1_10, + PIO1_11, + PIO1_12, + PIO1_13, + PIO1_14, + PIO1_15, + PIO1_16, + PIO1_17, + PIO1_18, + PIO1_19, + PIO1_2, + PIO1_20, + PIO1_21, + PIO1_22, + PIO1_23, + PIO1_24, + PIO1_25, + PIO1_26, + PIO1_27, + PIO1_28, + PIO1_29, + PIO1_3, + PIO1_30, + PIO1_31, + PIO1_4, + PIO1_5, + PIO1_6, + PIO1_7, + PIO1_8, + PIO1_9, + PIO2_0, + PIO2_1, + PIO2_10, + PIO2_11, + PIO2_12, + PIO2_13, + PIO2_14, + PIO2_15, + PIO2_16, + PIO2_17, + PIO2_18, + PIO2_19, + PIO2_2, + PIO2_20, + PIO2_21, + PIO2_22, + PIO2_23, + PIO2_24, + PIO2_25, + PIO2_26, + PIO2_27, + PIO2_28, + PIO2_29, + PIO2_3, + PIO2_30, + PIO2_31, + PIO2_4, + PIO2_5, + PIO2_6, + PIO2_7, + PIO2_8, + PIO2_9, + PIO3_0, + PIO3_1, + PIO3_10, + PIO3_11, + PIO3_12, + PIO3_13, + PIO3_14, + PIO3_15, + PIO3_16, + PIO3_17, + PIO3_18, + PIO3_19, + PIO3_2, + PIO3_20, + PIO3_21, + PIO3_22, + PIO3_23, + PIO3_24, + PIO3_25, + PIO3_26, + PIO3_27, + PIO3_28, + PIO3_29, + PIO3_3, + PIO3_30, + PIO3_31, + PIO3_4, + PIO3_5, + PIO3_6, + PIO3_7, + PIO3_8, + PIO3_9, + PIO4_0, + PIO4_1, + PIO4_10, + PIO4_2, + PIO4_3, + PIO4_4, + PIO4_5, + PIO4_6, + PIO4_7, + PIO4_8, + PIO4_9, + PIO7_24, + PIO7_25, + PIO7_26, + PIO7_27, + PIO7_28, + PIO7_29, + PIO7_30, + PIO7_31, + PIOFC15_SCL, + PIOFC15_SDA, + PMC_PMIC, + PIMCTL, + POWERQUAD, + PUF, + RNG, + RTC, + SCT0, + SECGPIO, + SECUREVIOLATION, + SEMA42, + SGPIO_INTA, + SGPIO_INTB, + USBHSD, + USBHSH, + USBPHY, + USB_WAKEUP, + USDHC0, + USDHC1, + UTICK0, + WDT0, + WDT1, +); diff --git a/embassy-imxrt/src/chips/mimxrt685s.rs b/embassy-imxrt/src/chips/mimxrt685s.rs new file mode 100644 index 000000000..746861e35 --- /dev/null +++ b/embassy-imxrt/src/chips/mimxrt685s.rs @@ -0,0 +1,388 @@ +pub use mimxrt685s_pac as pac; + +#[allow(clippy::missing_safety_doc)] +pub mod interrupts { + embassy_hal_internal::interrupt_mod!( + ACMP, + ADC0, + CASPER, + CTIMER0, + CTIMER1, + CTIMER2, + CTIMER3, + CTIMER4, + DMA0, + DMA1, + DMIC0, + DSPWAKE, + FLEXCOMM0, + FLEXCOMM1, + FLEXCOMM14, + FLEXCOMM15, + FLEXCOMM2, + FLEXCOMM3, + FLEXCOMM4, + FLEXCOMM5, + FLEXCOMM6, + FLEXCOMM7, + FLEXSPI, + GPIO_INTA, + GPIO_INTB, + HASHCRYPT, + HWVAD0, + HYPERVISOR, + I3C0, + MRT0, + MU_A, + OS_EVENT, + PIN_INT0, + PIN_INT1, + PIN_INT2, + PIN_INT3, + PIN_INT4, + PIN_INT5, + PIN_INT6, + PIN_INT7, + PMC_PMIC, + POWERQUAD, + PUF, + RNG, + RTC, + SCT0, + SECUREVIOLATION, + SGPIO_INTA, + SGPIO_INTB, + USB, + USBPHY_DCD, + USB_WAKEUP, + USDHC0, + USDHC1, + UTICK0, + WDT0, + WDT1, + ); +} + +embassy_hal_internal::peripherals!( + ACMP, + ADC0, + CASPER, + CRC, + CTIMER0_COUNT_CHANNEL0, + CTIMER0_COUNT_CHANNEL1, + CTIMER0_COUNT_CHANNEL2, + CTIMER0_COUNT_CHANNEL3, + CTIMER0_CAPTURE_CHANNEL0, + CTIMER0_CAPTURE_CHANNEL1, + CTIMER0_CAPTURE_CHANNEL2, + CTIMER0_CAPTURE_CHANNEL3, + CTIMER1_COUNT_CHANNEL0, + CTIMER1_COUNT_CHANNEL1, + CTIMER1_COUNT_CHANNEL2, + CTIMER1_COUNT_CHANNEL3, + CTIMER1_CAPTURE_CHANNEL0, + CTIMER1_CAPTURE_CHANNEL1, + CTIMER1_CAPTURE_CHANNEL2, + CTIMER1_CAPTURE_CHANNEL3, + CTIMER2_COUNT_CHANNEL0, + CTIMER2_COUNT_CHANNEL1, + CTIMER2_COUNT_CHANNEL2, + CTIMER2_COUNT_CHANNEL3, + CTIMER2_CAPTURE_CHANNEL0, + CTIMER2_CAPTURE_CHANNEL1, + CTIMER2_CAPTURE_CHANNEL2, + CTIMER2_CAPTURE_CHANNEL3, + CTIMER3_COUNT_CHANNEL0, + CTIMER3_COUNT_CHANNEL1, + CTIMER3_COUNT_CHANNEL2, + CTIMER3_COUNT_CHANNEL3, + CTIMER3_CAPTURE_CHANNEL0, + CTIMER3_CAPTURE_CHANNEL1, + CTIMER3_CAPTURE_CHANNEL2, + CTIMER3_CAPTURE_CHANNEL3, + CTIMER4_COUNT_CHANNEL0, + CTIMER4_COUNT_CHANNEL1, + CTIMER4_COUNT_CHANNEL2, + CTIMER4_COUNT_CHANNEL3, + CTIMER4_CAPTURE_CHANNEL0, + CTIMER4_CAPTURE_CHANNEL1, + CTIMER4_CAPTURE_CHANNEL2, + CTIMER4_CAPTURE_CHANNEL3, + DMA0, + DMA0_CH0, + DMA0_CH1, + DMA0_CH2, + DMA0_CH3, + DMA0_CH4, + DMA0_CH5, + DMA0_CH6, + DMA0_CH7, + DMA0_CH8, + DMA0_CH9, + DMA0_CH10, + DMA0_CH11, + DMA0_CH12, + DMA0_CH13, + DMA0_CH14, + DMA0_CH15, + DMA0_CH16, + DMA0_CH17, + DMA0_CH18, + DMA0_CH19, + DMA0_CH20, + DMA0_CH21, + DMA0_CH22, + DMA0_CH23, + DMA0_CH24, + DMA0_CH25, + DMA0_CH26, + DMA0_CH27, + DMA0_CH28, + DMA0_CH29, + DMA0_CH30, + DMA0_CH31, + DMA0_CH32, + DMA1, + DMA1_CH0, + DMA1_CH1, + DMA1_CH2, + DMA1_CH3, + DMA1_CH4, + DMA1_CH5, + DMA1_CH6, + DMA1_CH7, + DMA1_CH8, + DMA1_CH9, + DMA1_CH10, + DMA1_CH11, + DMA1_CH12, + DMA1_CH13, + DMA1_CH14, + DMA1_CH15, + DMA1_CH16, + DMA1_CH17, + DMA1_CH18, + DMA1_CH19, + DMA1_CH20, + DMA1_CH21, + DMA1_CH22, + DMA1_CH23, + DMA1_CH24, + DMA1_CH25, + DMA1_CH26, + DMA1_CH27, + DMA1_CH28, + DMA1_CH29, + DMA1_CH30, + DMA1_CH31, + DMA1_CH32, + DMIC0, + DSPWAKE, + FLEXCOMM0, + FLEXCOMM1, + FLEXCOMM14, + FLEXCOMM15, + FLEXCOMM2, + FLEXCOMM3, + FLEXCOMM4, + FLEXCOMM5, + FLEXCOMM6, + FLEXCOMM7, + FLEXSPI, + FREQME, + GPIO_INTA, + GPIO_INTB, + HASHCRYPT, + HSGPIO0, + HSGPIO1, + HSGPIO2, + HSGPIO3, + HSGPIO4, + HSGPIO5, + HSGPIO6, + HSGPIO7, + HWVAD0, + HYPERVISOR, + I3C0, + MRT0, + MU_A, + OS_EVENT, + PIN_INT0, + PIN_INT1, + PIN_INT2, + PIN_INT3, + PIN_INT4, + PIN_INT5, + PIN_INT6, + PIN_INT7, + PIO0_0, + PIO0_1, + PIO0_10, + PIO0_11, + PIO0_12, + PIO0_13, + PIO0_14, + PIO0_15, + PIO0_16, + PIO0_17, + PIO0_18, + PIO0_19, + PIO0_2, + PIO0_20, + PIO0_21, + PIO0_22, + PIO0_23, + PIO0_24, + PIO0_25, + PIO0_26, + PIO0_27, + PIO0_28, + PIO0_29, + PIO0_3, + PIO0_30, + PIO0_31, + PIO0_4, + PIO0_5, + PIO0_6, + PIO0_7, + PIO0_8, + PIO0_9, + PIO1_0, + PIO1_1, + PIO1_10, + PIO1_11, + PIO1_12, + PIO1_13, + PIO1_14, + PIO1_15, + PIO1_16, + PIO1_17, + PIO1_18, + PIO1_19, + PIO1_2, + PIO1_20, + PIO1_21, + PIO1_22, + PIO1_23, + PIO1_24, + PIO1_25, + PIO1_26, + PIO1_27, + PIO1_28, + PIO1_29, + PIO1_3, + PIO1_30, + PIO1_31, + PIO1_4, + PIO1_5, + PIO1_6, + PIO1_7, + PIO1_8, + PIO1_9, + PIO2_0, + PIO2_1, + PIO2_10, + PIO2_11, + PIO2_12, + PIO2_13, + PIO2_14, + PIO2_15, + PIO2_16, + PIO2_17, + PIO2_18, + PIO2_19, + PIO2_2, + PIO2_20, + PIO2_21, + PIO2_22, + PIO2_23, + PIO2_24, + PIO2_25, + PIO2_26, + PIO2_27, + PIO2_28, + PIO2_29, + PIO2_3, + PIO2_30, + PIO2_31, + PIO2_4, + PIO2_5, + PIO2_6, + PIO2_7, + PIO2_8, + PIO2_9, + PIO3_0, + PIO3_1, + PIO3_10, + PIO3_11, + PIO3_12, + PIO3_13, + PIO3_14, + PIO3_15, + PIO3_16, + PIO3_17, + PIO3_18, + PIO3_19, + PIO3_2, + PIO3_20, + PIO3_21, + PIO3_22, + PIO3_23, + PIO3_24, + PIO3_25, + PIO3_26, + PIO3_27, + PIO3_28, + PIO3_29, + PIO3_3, + PIO3_30, + PIO3_31, + PIO3_4, + PIO3_5, + PIO3_6, + PIO3_7, + PIO3_8, + PIO3_9, + PIO4_0, + PIO4_1, + PIO4_10, + PIO4_2, + PIO4_3, + PIO4_4, + PIO4_5, + PIO4_6, + PIO4_7, + PIO4_8, + PIO4_9, + PIO7_24, + PIO7_25, + PIO7_26, + PIO7_27, + PIO7_28, + PIO7_29, + PIO7_30, + PIO7_31, + PIOFC15_SCL, + PIOFC15_SDA, + PMC_PMIC, + PIMCTL, + POWERQUAD, + PUF, + RNG, + RTC, + SCT0, + SECGPIO, + SECUREVIOLATION, + SEMA42, + SGPIO_INTA, + SGPIO_INTB, + USBHSD, + USBHSH, + USBPHY, + USB_WAKEUP, + USDHC0, + USDHC1, + UTICK0, + WDT0, + WDT1, +); diff --git a/embassy-imxrt/src/clocks.rs b/embassy-imxrt/src/clocks.rs new file mode 100644 index 000000000..1d36fb142 --- /dev/null +++ b/embassy-imxrt/src/clocks.rs @@ -0,0 +1,1687 @@ +//! Clock configuration for the `RT6xx` +use core::sync::atomic::{AtomicU32, AtomicU8, Ordering}; + +#[cfg(feature = "defmt")] +use defmt; +use paste::paste; + +use crate::pac; + +/// Clock configuration; +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum Clocks { + /// Low power oscillator + Lposc, + /// System Frequency Resonance Oscillator (SFRO) + Sfro, + /// Real Time Clock + Rtc, + /// Feed-forward Ring Oscillator + Ffro, // This includes that div2 and div4 variations + /// External Clock Input + ClkIn, + /// AHB Clock + Hclk, + /// Main Clock + MainClk, + /// Main PLL Clock + MainPllClk, // also has aux0,aux1,dsp, and audio pll's downstream + /// System Clock + SysClk, + /// System Oscillator + SysOscClk, + /// ADC Clock + Adc, +} + +/// Clock configuration. +pub struct ClockConfig { + /// low-power oscillator config + pub lposc: LposcConfig, + /// 16Mhz internal oscillator config + pub sfro: SfroConfig, + /// Real Time Clock config + pub rtc: RtcClkConfig, + /// 48/60 Mhz internal oscillator config + pub ffro: FfroConfig, + // pub pll: Option, //potentially covered in main pll clk + /// External Clock-In config + pub clk_in: ClkInConfig, + /// AHB bus clock config + pub hclk: HclkConfig, + /// Main Clock config + pub main_clk: MainClkConfig, + /// Main Pll clock config + pub main_pll_clk: MainPllClkConfig, + /// Software concept to be used with systick, doesn't map to a register + pub sys_clk: SysClkConfig, + /// System Oscillator Config + pub sys_osc: SysOscConfig, + // todo: move ADC here +} + +impl ClockConfig { + /// Clock configuration derived from external crystal. + #[must_use] + pub fn crystal() -> Self { + const CORE_CPU_FREQ: u32 = 500_000_000; + const PLL_CLK_FREQ: u32 = 528_000_000; + const SYS_CLK_FREQ: u32 = CORE_CPU_FREQ / 2; + Self { + lposc: LposcConfig { + state: State::Enabled, + freq: AtomicU32::new(Into::into(LposcFreq::Lp1m)), + }, + sfro: SfroConfig { state: State::Enabled }, + rtc: RtcClkConfig { + state: State::Enabled, + wake_alarm_state: State::Disabled, + sub_second_state: State::Disabled, + freq: AtomicU32::new(Into::into(RtcFreq::Default1Hz)), + rtc_int: RtcInterrupts::None, + }, + ffro: FfroConfig { + state: State::Enabled, + freq: AtomicU32::new(Into::into(FfroFreq::Ffro48m)), + }, + //pll: Some(PllConfig {}),//includes aux0 and aux1 pll + clk_in: ClkInConfig { + state: State::Disabled, + // This is an externally sourced clock + // Don't give it an initial frequency + freq: Some(AtomicU32::new(0)), + }, + hclk: HclkConfig { state: State::Disabled }, + main_clk: MainClkConfig { + state: State::Enabled, + //FFRO divided by 4 is reset values of Main Clk Sel A, Sel B + src: MainClkSrc::FFRO, + div_int: AtomicU32::new(4), + freq: AtomicU32::new(CORE_CPU_FREQ), + }, + main_pll_clk: MainPllClkConfig { + state: State::Enabled, + src: MainPllClkSrc::SFRO, + freq: AtomicU32::new(PLL_CLK_FREQ), + mult: AtomicU8::new(16), + pfd0: 19, // + pfd1: 0, // future field + pfd2: 19, // 0x13 + pfd3: 0, // future field + aux0_div: 0, + aux1_div: 0, + }, + sys_clk: SysClkConfig { + sysclkfreq: AtomicU32::new(SYS_CLK_FREQ), + }, + sys_osc: SysOscConfig { state: State::Enabled }, + //adc: Some(AdcConfig {}), // TODO: add config + } + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +/// Clock state enum +pub enum State { + /// Clock is enabled + Enabled, + /// Clock is disabled + Disabled, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +/// Low Power Oscillator valid frequencies +pub enum LposcFreq { + /// 1 `MHz` oscillator + Lp1m, + /// 32kHz oscillator + Lp32k, +} + +impl From for u32 { + fn from(value: LposcFreq) -> Self { + match value { + LposcFreq::Lp1m => 1_000_000, + LposcFreq::Lp32k => 32_768, + } + } +} + +impl TryFrom for LposcFreq { + type Error = ClockError; + fn try_from(value: u32) -> Result { + match value { + 1_000_000 => Ok(LposcFreq::Lp1m), + 32_768 => Ok(LposcFreq::Lp32k), + _ => Err(ClockError::InvalidFrequency), + } + } +} + +/// Low power oscillator config +pub struct LposcConfig { + state: State, + // low power osc + freq: AtomicU32, +} + +const SFRO_FREQ: u32 = 16_000_000; +/// SFRO config +pub struct SfroConfig { + state: State, +} + +/// Valid RTC frequencies +pub enum RtcFreq { + /// "Alarm" aka 1Hz clock + Default1Hz, + /// "Wake" aka 1kHz clock + HighResolution1khz, + /// 32kHz clock + SubSecond32kHz, +} + +impl From for u32 { + fn from(value: RtcFreq) -> Self { + match value { + RtcFreq::Default1Hz => 1, + RtcFreq::HighResolution1khz => 1_000, + RtcFreq::SubSecond32kHz => 32_768, + } + } +} + +impl TryFrom for RtcFreq { + type Error = ClockError; + fn try_from(value: u32) -> Result { + match value { + 1 => Ok(RtcFreq::Default1Hz), + 1_000 => Ok(RtcFreq::HighResolution1khz), + 32_768 => Ok(RtcFreq::SubSecond32kHz), + _ => Err(ClockError::InvalidFrequency), + } + } +} + +/// RTC Interrupt options +pub enum RtcInterrupts { + /// No interrupts are set + None, + /// 1Hz RTC clock aka Alarm interrupt set + Alarm, + /// 1kHz RTC clock aka Wake interrupt set + Wake, +} + +impl From for u8 { + fn from(value: RtcInterrupts) -> Self { + match value { + RtcInterrupts::None => 0b00, + RtcInterrupts::Alarm => 0b01, + RtcInterrupts::Wake => 0b10, + } + } +} +/// RTC clock config. +pub struct RtcClkConfig { + /// 1 Hz Clock state + pub state: State, + /// 1kHz Clock state + pub wake_alarm_state: State, + /// 32kHz Clock state + pub sub_second_state: State, + /// RTC clock source. + pub freq: AtomicU32, + /// RTC Interrupt + pub rtc_int: RtcInterrupts, +} + +/// Valid FFRO Frequencies +pub enum FfroFreq { + /// 48 Mhz Internal Oscillator + Ffro48m, + /// 60 `MHz` Internal Oscillator + Ffro60m, +} + +/// FFRO Clock Config +pub struct FfroConfig { + /// FFRO Clock state + state: State, + /// FFRO Frequency + freq: AtomicU32, +} + +impl From for u32 { + fn from(value: FfroFreq) -> Self { + match value { + FfroFreq::Ffro48m => 48_000_000, + FfroFreq::Ffro60m => 60_000_000, + } + } +} + +impl TryFrom for FfroFreq { + type Error = ClockError; + fn try_from(value: u32) -> Result { + match value { + 48_000_000 => Ok(FfroFreq::Ffro48m), + 60_000_000 => Ok(FfroFreq::Ffro60m), + _ => Err(ClockError::InvalidFrequency), + } + } +} + +/// PLL clock source +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum MainPllClkSrc { + /// SFRO + SFRO, + /// External Clock + ClkIn, + /// FFRO + FFRO, +} + +/// Transform from Source Clock enum to Clocks +impl From for Clocks { + fn from(value: MainPllClkSrc) -> Self { + match value { + MainPllClkSrc::SFRO => Clocks::Sfro, + MainPllClkSrc::ClkIn => Clocks::ClkIn, + MainPllClkSrc::FFRO => Clocks::Ffro, + } + } +} + +impl TryFrom for MainPllClkSrc { + type Error = ClockError; + fn try_from(value: Clocks) -> Result { + match value { + Clocks::Sfro => Ok(MainPllClkSrc::SFRO), + Clocks::Ffro => Ok(MainPllClkSrc::FFRO), + Clocks::ClkIn => Ok(MainPllClkSrc::ClkIn), + _ => Err(ClockError::ClockNotSupported), + } + } +} + +/// PLL configuration. +pub struct MainPllClkConfig { + /// Clock active state + pub state: State, + /// Main clock source. + pub src: MainPllClkSrc, + /// Main clock frequency + pub freq: AtomicU32, + //TODO: numerator and denominator not used but present in register + /// Multiplication factor. + pub mult: AtomicU8, + // the following are actually 6-bits not 8 + /// Fractional divider 0, main pll clock + pub pfd0: u8, + /// Fractional divider 1 + pub pfd1: u8, + /// Fractional divider 2 + pub pfd2: u8, + /// Fractional divider 3 + pub pfd3: u8, + // Aux dividers + /// aux divider 0 + pub aux0_div: u8, + /// aux divider 1 + pub aux1_div: u8, +} +/// External input clock config +pub struct ClkInConfig { + /// External clock input state + state: State, + /// External clock input rate + freq: Option, +} + +/// AHB clock config +pub struct HclkConfig { + /// divider to turn main clk into hclk for AHB bus + pub state: State, +} + +/// Main clock source. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum MainClkSrc { + /// FFRO divided by 4 + FFROdiv4, // probably don't need since it'll be covered by div_int + /// External Clock + ClkIn, + /// Low Power Oscillator + Lposc, + /// FFRO + FFRO, + /// SFRO + SFRO, + /// Main PLL Clock + PllMain, + /// RTC 32kHz oscillator. + RTC32k, +} + +impl From for Clocks { + fn from(value: MainClkSrc) -> Self { + match value { + MainClkSrc::ClkIn => Clocks::ClkIn, + MainClkSrc::Lposc => Clocks::Lposc, + MainClkSrc::FFRO => Clocks::Ffro, + MainClkSrc::SFRO => Clocks::Sfro, + MainClkSrc::PllMain => Clocks::MainPllClk, + MainClkSrc::RTC32k => Clocks::Rtc, + MainClkSrc::FFROdiv4 => Clocks::Ffro, + } + } +} + +impl TryFrom for MainClkSrc { + type Error = ClockError; + fn try_from(value: Clocks) -> Result { + match value { + Clocks::ClkIn => Ok(MainClkSrc::ClkIn), + Clocks::Lposc => Ok(MainClkSrc::Lposc), + Clocks::Sfro => Ok(MainClkSrc::SFRO), + Clocks::MainPllClk => Ok(MainClkSrc::PllMain), + Clocks::Rtc => Ok(MainClkSrc::RTC32k), + Clocks::Ffro => Ok(MainClkSrc::FFRO), + _ => Err(ClockError::ClockNotSupported), + } + } +} + +/// Main clock config. +pub struct MainClkConfig { + /// Main clock state + pub state: State, + /// Main clock source. + pub src: MainClkSrc, + /// Main clock divider. + pub div_int: AtomicU32, + /// Clock Frequency + pub freq: AtomicU32, +} + +/// System Core Clock config, SW concept for systick +pub struct SysClkConfig { + /// keeps track of the system core clock frequency + /// future use with systick + pub sysclkfreq: AtomicU32, +} + +/// System Oscillator Config +pub struct SysOscConfig { + /// Clock State + pub state: State, +} +const SYS_OSC_DEFAULT_FREQ: u32 = 24_000_000; + +/// Clock Errors +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum ClockError { + /// Error due to attempting to change a clock with the wrong config block + ClockMismatch, + /// Error due to attempting to modify a clock that's not yet been enabled + ClockNotEnabled, + /// Error due to attempting to set a clock source that's not a supported option + ClockNotSupported, + /// Error due to attempting to set a clock to an invalid frequency + InvalidFrequency, + /// Error due to attempting to modify a clock output with an invalid divider + InvalidDiv, + /// Error due to attempting to modify a clock output with an invalid multiplier + InvalidMult, +} + +/// Trait to configure one of the clocks +pub trait ConfigurableClock { + /// Reset the clock, will enable it + fn disable(&self) -> Result<(), ClockError>; + /// Enable the clock + fn enable_and_reset(&self) -> Result<(), ClockError>; + /// Return the clock rate (Hz) + fn get_clock_rate(&self) -> Result; + /// Set the desired clock rate (Hz) + fn set_clock_rate(&mut self, div: u8, mult: u8, freq: u32) -> Result<(), ClockError>; + /// Returns whether this clock is enabled + fn is_enabled(&self) -> bool; +} + +impl LposcConfig { + /// Initializes low-power oscillator. + fn init_lposc() { + // Enable low power oscillator + // SAFETY: unsafe needed to take pointer to Sysctl0, only happens once during init + let sysctl0 = unsafe { crate::pac::Sysctl0::steal() }; + sysctl0.pdruncfg0_clr().write(|w| w.lposc_pd().clr_pdruncfg0()); + + // Wait for low-power oscillator to be ready (typically 64 us) + // Busy loop seems better here than trying to shoe-in an async delay + // SAFETY: unsafe needed to take pointer to Clkctl0, needed to validate HW is ready + let clkctl0 = unsafe { crate::pac::Clkctl0::steal() }; + while clkctl0.lposcctl0().read().clkrdy().bit_is_clear() {} + } +} +impl ConfigurableClock for LposcConfig { + fn enable_and_reset(&self) -> Result<(), ClockError> { + LposcConfig::init_lposc(); + Ok(()) + } + fn disable(&self) -> Result<(), ClockError> { + // SAFETY: unsafe needed to take pointer to Sysctl0, needed to power down the LPOSC HW + let sysctl0 = unsafe { crate::pac::Sysctl0::steal() }; + sysctl0.pdruncfg0_set().write(|w| w.lposc_pd().set_pdruncfg0()); + // Wait until LPOSC disabled + while !sysctl0.pdruncfg0().read().lposc_pd().is_power_down() {} + Ok(()) + } + fn get_clock_rate(&self) -> Result { + Ok(self.freq.load(Ordering::Relaxed)) + } + fn set_clock_rate(&mut self, _div: u8, _mult: u8, freq: u32) -> Result<(), ClockError> { + if let Ok(r) = >::try_into(freq) { + match r { + LposcFreq::Lp1m => { + self.freq + .store(LposcFreq::Lp1m as u32, core::sync::atomic::Ordering::Relaxed); + Ok(()) + } + LposcFreq::Lp32k => { + self.freq + .store(LposcFreq::Lp1m as u32, core::sync::atomic::Ordering::Relaxed); + Ok(()) + } + } + } else { + error!("failed to convert desired clock rate, {:#}, to LPOSC Freq", freq); + Err(ClockError::InvalidFrequency) + } + } + fn is_enabled(&self) -> bool { + self.state == State::Enabled + } +} + +impl FfroConfig { + /// Necessary register writes to initialize the FFRO clock + pub fn init_ffro_clk() { + // SAFETY: unsafe needed to take pointer to Sysctl0, only to power up FFRO + let sysctl0 = unsafe { crate::pac::Sysctl0::steal() }; + + /* Power on FFRO (48/60MHz) */ + sysctl0.pdruncfg0_clr().write(|w| w.ffro_pd().clr_pdruncfg0()); + + // SAFETY: unsafe needed to take pointer to Clkctl0, only to set proper ffro update mode + let clkctl0 = unsafe { crate::pac::Clkctl0::steal() }; + + clkctl0.ffroctl1().write(|w| w.update().normal_mode()); + + // No FFRO enable/disable control in CLKCTL. + // Delay enough for FFRO to be stable in case it was just powered on + delay_loop_clocks(50, 12_000_000); + } +} + +impl ConfigurableClock for FfroConfig { + fn enable_and_reset(&self) -> Result<(), ClockError> { + // SAFETY: should be called once + FfroConfig::init_ffro_clk(); + // default is 48 MHz + Ok(()) + } + fn disable(&self) -> Result<(), ClockError> { + // SAFETY: unsafe needed to take pointer to Sysctl0, only to power down FFRO + let sysctl0 = unsafe { crate::pac::Sysctl0::steal() }; + sysctl0.pdruncfg0_set().write(|w| w.ffro_pd().set_pdruncfg0()); + delay_loop_clocks(30, 12_000_000); + // Wait until FFRO disabled + while !sysctl0.pdruncfg0().read().ffro_pd().is_power_down() {} + Ok(()) + } + fn get_clock_rate(&self) -> Result { + trace!("getting ffro clock rate"); + Ok(self.freq.load(Ordering::Relaxed)) + } + fn set_clock_rate(&mut self, _div: u8, _mult: u8, freq: u32) -> Result<(), ClockError> { + if let Ok(r) = >::try_into(freq) { + match r { + FfroFreq::Ffro48m => { + // SAFETY: unsafe needed to take pointer to Clkctl0, needed to set the right HW frequency + let clkctl0 = unsafe { crate::pac::Clkctl0::steal() }; + clkctl0.ffroctl1().write(|w| w.update().update_safe_mode()); + clkctl0.ffroctl0().write(|w| w.trim_range().ffro_48mhz()); + clkctl0.ffroctl1().write(|w| w.update().normal_mode()); + + self.freq + .store(FfroFreq::Ffro48m as u32, core::sync::atomic::Ordering::Relaxed); + Ok(()) + } + FfroFreq::Ffro60m => { + // SAFETY: unsafe needed to take pointer to Clkctl0, needed to set the right HW frequency + let clkctl0 = unsafe { crate::pac::Clkctl0::steal() }; + clkctl0.ffroctl1().write(|w| w.update().update_safe_mode()); + clkctl0.ffroctl0().write(|w| w.trim_range().ffro_60mhz()); + clkctl0.ffroctl1().write(|w| w.update().normal_mode()); + + self.freq + .store(FfroFreq::Ffro60m as u32, core::sync::atomic::Ordering::Relaxed); + Ok(()) + } + } + } else { + error!("failed to convert desired clock rate, {:#}, to FFRO Freq", freq); + Err(ClockError::InvalidFrequency) + } + } + fn is_enabled(&self) -> bool { + self.state == State::Enabled + } +} + +impl ConfigurableClock for SfroConfig { + fn enable_and_reset(&self) -> Result<(), ClockError> { + // SAFETY: unsafe needed to take pointer to Sysctl0, only to power up SFRO + let sysctl0 = unsafe { crate::pac::Sysctl0::steal() }; + sysctl0.pdruncfg0_clr().write(|w| w.sfro_pd().clr_pdruncfg0()); + // wait until ready + while !sysctl0.pdruncfg0().read().sfro_pd().is_enabled() {} + Ok(()) + } + fn disable(&self) -> Result<(), ClockError> { + // SAFETY: unsafe needed to take pointer to Sysctl0, only to power down SFRO + let sysctl0 = unsafe { crate::pac::Sysctl0::steal() }; + sysctl0.pdruncfg0_set().write(|w| w.sfro_pd().set_pdruncfg0()); + delay_loop_clocks(30, 12_000_000); + // Wait until SFRO disabled + while !sysctl0.pdruncfg0().read().sfro_pd().is_power_down() {} + Ok(()) + } + fn get_clock_rate(&self) -> Result { + if self.state == State::Enabled { + Ok(SFRO_FREQ) + } else { + Err(ClockError::ClockNotEnabled) + } + } + fn set_clock_rate(&mut self, _div: u8, _mult: u8, freq: u32) -> Result<(), ClockError> { + if self.state == State::Enabled { + if freq == SFRO_FREQ { + trace!("Sfro frequency is already set at 16MHz"); + Ok(()) + } else { + Err(ClockError::InvalidFrequency) + } + } else { + Err(ClockError::ClockNotEnabled) + } + } + fn is_enabled(&self) -> bool { + self.state == State::Enabled + } +} + +/// A Clock with multiple options for clock source +pub trait MultiSourceClock { + /// Returns which clock is being used as the clock source and its rate + fn get_clock_source_and_rate(&self, clock: &Clocks) -> Result<(Clocks, u32), ClockError>; + /// Sets a specific clock source and its associated rate + fn set_clock_source_and_rate( + &mut self, + clock_src_config: &mut impl ConfigurableClock, + clock_src: &Clocks, + rate: u32, + ) -> Result<(), ClockError>; +} + +impl MultiSourceClock for MainPllClkConfig { + fn get_clock_source_and_rate(&self, clock: &Clocks) -> Result<(Clocks, u32), ClockError> { + match clock { + Clocks::MainPllClk => { + let converted_clock = Clocks::from(self.src); + Ok((converted_clock, self.freq.load(Ordering::Relaxed))) + } + _ => Err(ClockError::ClockMismatch), + } + } + fn set_clock_source_and_rate( + &mut self, + clock_src_config: &mut impl ConfigurableClock, + clock_src: &Clocks, + rate: u32, + ) -> Result<(), ClockError> { + if let Ok(c) = >::try_into(*clock_src) { + match c { + MainPllClkSrc::ClkIn => { + self.src = MainPllClkSrc::ClkIn; + // div mult and rate don't matter since this is an external clock + self.set_clock_rate(1, 1, rate) + } + MainPllClkSrc::FFRO => { + // FFRO Clock is divided by 2 + let r = clock_src_config.get_clock_rate()?; + let base_rate = r / 2; + let m = MainPllClkConfig::calc_mult(rate, base_rate)?; + + self.src = MainPllClkSrc::FFRO; + self.set_clock_rate(2, m, rate) + } + MainPllClkSrc::SFRO => { + if !clock_src_config.is_enabled() { + error!("Can't set SFRO as source for MainPll as it's not enabled"); + return Err(ClockError::ClockNotEnabled); + } + // check if desired frequency is a valid multiple of 16m SFRO clock + let m = MainPllClkConfig::calc_mult(rate, SFRO_FREQ)?; + self.src = MainPllClkSrc::SFRO; + self.set_clock_rate(1, m, rate) + } + } + } else { + Err(ClockError::ClockNotSupported) + } + } +} + +impl ConfigurableClock for MainPllClkConfig { + fn enable_and_reset(&self) -> Result<(), ClockError> { + MainPllClkConfig::init_syspll(); + + MainPllClkConfig::init_syspll_pfd0(self.pfd0); + + MainPllClkConfig::init_syspll_pfd2(self.pfd2); + Ok(()) + } + fn disable(&self) -> Result<(), ClockError> { + if self.is_enabled() { + error!("Attempting to reset the Main Pll Clock, should be resetting its source"); + Err(ClockError::ClockNotSupported) + } else { + Err(ClockError::ClockNotEnabled) + } + } + fn get_clock_rate(&self) -> Result { + if self.is_enabled() { + let (_c, rate) = self.get_clock_source_and_rate(&Clocks::MainPllClk)?; + Ok(rate) + } else { + Err(ClockError::ClockNotEnabled) + } + } + fn set_clock_rate(&mut self, div: u8, mult: u8, freq: u32) -> Result<(), ClockError> { + if self.is_enabled() { + trace!("attempting to set main pll clock rate"); + // SAFETY: unsafe needed to take pointers to Sysctl0 and Clkctl0 + let clkctl0 = unsafe { crate::pac::Clkctl0::steal() }; + let sysctl0 = unsafe { crate::pac::Sysctl0::steal() }; + + // Power down pll before changes + sysctl0 + .pdruncfg0_set() + .write(|w| w.syspllldo_pd().set_pdruncfg0().syspllana_pd().set_pdruncfg0()); + + let desired_freq: u64 = self.freq.load(Ordering::Relaxed).into(); + + match self.src { + c if c == MainPllClkSrc::ClkIn || c == MainPllClkSrc::FFRO || c == MainPllClkSrc::SFRO => { + let mut base_rate; + match c { + MainPllClkSrc::ClkIn => { + clkctl0.syspll0clksel().write(|w| w.sel().sysxtal_clk()); + let r = self.get_clock_rate()?; + base_rate = r; + } + MainPllClkSrc::FFRO => { + trace!("found FFRO as source, wait a bit"); + delay_loop_clocks(1000, desired_freq); + match clkctl0.ffroctl0().read().trim_range().is_ffro_48mhz() { + true => base_rate = Into::into(FfroFreq::Ffro48m), + false => base_rate = Into::into(FfroFreq::Ffro60m), + } + trace!("found ffro rate to be: {:#}", base_rate); + if div == 2 { + trace!("dividing FFRO rate by 2"); + clkctl0.syspll0clksel().write(|w| w.sel().ffro_div_2()); + delay_loop_clocks(150, desired_freq); + base_rate /= 2; + } else { + return Err(ClockError::InvalidDiv); + } + } + MainPllClkSrc::SFRO => { + base_rate = SFRO_FREQ; + clkctl0.syspll0clksel().write(|w| w.sel().sfro_clk()); + } + }; + base_rate *= u32::from(mult); + trace!("calculated base rate at: {:#}", base_rate); + if base_rate != freq { + // make sure to power syspll back up before returning the error + error!("invalid frequency found, powering syspll back up before returning error. Check div and mult"); + // Clear System PLL reset + clkctl0.syspll0ctl0().write(|w| w.reset().normal()); + // Power up SYSPLL + sysctl0 + .pdruncfg0_clr() + .write(|w| w.syspllana_pd().clr_pdruncfg0().syspllldo_pd().clr_pdruncfg0()); + return Err(ClockError::InvalidFrequency); + } + trace!("setting default num and denom"); + // SAFETY: unsafe needed to write the bits for the num and demon fields + clkctl0.syspll0num().write(|w| unsafe { w.num().bits(0b0) }); + clkctl0.syspll0denom().write(|w| unsafe { w.denom().bits(0b1) }); + delay_loop_clocks(30, desired_freq); + self.mult.store(mult, Ordering::Relaxed); + trace!("setting self.mult as: {:#}", mult); + match mult { + 16 => { + clkctl0.syspll0ctl0().modify(|_r, w| w.mult().div_16()); + } + 17 => { + clkctl0.syspll0ctl0().modify(|_r, w| w.mult().div_17()); + } + 20 => { + clkctl0.syspll0ctl0().modify(|_r, w| w.mult().div_20()); + } + 22 => { + clkctl0.syspll0ctl0().modify(|_r, w| w.mult().div_22()); + } + 27 => { + clkctl0.syspll0ctl0().modify(|_r, w| w.mult().div_27()); + } + 33 => { + clkctl0.syspll0ctl0().modify(|_r, w| w.mult().div_33()); + } + _ => return Err(ClockError::InvalidMult), + } + trace!("clear syspll reset"); + // Clear System PLL reset + clkctl0.syspll0ctl0().modify(|_r, w| w.reset().normal()); + // Power up SYSPLL + sysctl0 + .pdruncfg0_clr() + .write(|w| w.syspllana_pd().clr_pdruncfg0().syspllldo_pd().clr_pdruncfg0()); + + // Set System PLL HOLDRINGOFF_ENA + clkctl0.syspll0ctl0().modify(|_, w| w.holdringoff_ena().enable()); + delay_loop_clocks(75, desired_freq); + + // Clear System PLL HOLDRINGOFF_ENA + clkctl0.syspll0ctl0().modify(|_, w| w.holdringoff_ena().dsiable()); + delay_loop_clocks(15, desired_freq); + + trace!("setting new PFD0 bits"); + // gate the output and clear bits. + // SAFETY: unsafe needed to write the bits for pfd0 + clkctl0 + .syspll0pfd() + .modify(|_, w| unsafe { w.pfd0_clkgate().gated().pfd0().bits(0x0) }); + // set pfd bits and un-gate the clock output + // output is multiplied by syspll * 18/pfd0_bits + // SAFETY: unsafe needed to write the bits for pfd0 + clkctl0 + .syspll0pfd() + .modify(|_r, w| unsafe { w.pfd0_clkgate().not_gated().pfd0().bits(0x12) }); + // wait for ready bit to be set + delay_loop_clocks(50, desired_freq); + trace!("waiting for mainpll clock to be ready"); + while clkctl0.syspll0pfd().read().pfd0_clkrdy().bit_is_clear() {} + // clear by writing a 1 + clkctl0.syspll0pfd().modify(|_, w| w.pfd0_clkrdy().set_bit()); + + Ok(()) + } + _ => Err(ClockError::ClockNotSupported), + } + } else { + Err(ClockError::ClockNotEnabled) + } + } + fn is_enabled(&self) -> bool { + self.state == State::Enabled + } +} + +impl MainPllClkConfig { + /// Calculate the mult value of a desired frequency, return error if invalid + pub(self) fn calc_mult(rate: u32, base_freq: u32) -> Result { + trace!("calculating mult for {:#} / {:#}", rate, base_freq); + const VALIDMULTS: [u8; 6] = [16, 17, 20, 22, 27, 33]; + if rate > base_freq && rate % base_freq == 0 { + let mult = (rate / base_freq) as u8; + trace!("verifying that calculated mult {:#} is a valid one", mult); + if VALIDMULTS.into_iter().any(|i| i == mult) { + Ok(mult) + } else { + Err(ClockError::InvalidFrequency) + } + } else { + Err(ClockError::InvalidFrequency) + } + } + pub(self) fn init_syspll() { + // SAFETY: unsafe needed to take pointers to Sysctl0 and Clkctl0 + let clkctl0 = unsafe { crate::pac::Clkctl0::steal() }; + let sysctl0 = unsafe { crate::pac::Sysctl0::steal() }; + + // Power down SYSPLL before change fractional settings + sysctl0 + .pdruncfg0_set() + .write(|w| w.syspllldo_pd().set_pdruncfg0().syspllana_pd().set_pdruncfg0()); + + clkctl0.syspll0clksel().write(|w| w.sel().ffro_div_2()); + // SAFETY: unsafe needed to write the bits for both num and denom + clkctl0.syspll0num().write(|w| unsafe { w.num().bits(0x0) }); + clkctl0.syspll0denom().write(|w| unsafe { w.denom().bits(0x1) }); + + // kCLOCK_SysPllMult22 + clkctl0.syspll0ctl0().modify(|_, w| w.mult().div_22()); + + // Clear System PLL reset + clkctl0.syspll0ctl0().modify(|_, w| w.reset().normal()); + + // Power up SYSPLL + sysctl0 + .pdruncfg0_clr() + .write(|w| w.syspllldo_pd().clr_pdruncfg0().syspllana_pd().clr_pdruncfg0()); + delay_loop_clocks((150 & 0xFFFF) / 2, 12_000_000); + + // Set System PLL HOLDRINGOFF_ENA + clkctl0.syspll0ctl0().modify(|_, w| w.holdringoff_ena().enable()); + delay_loop_clocks((150 & 0xFFFF) / 2, 12_000_000); + + // Clear System PLL HOLDRINGOFF_ENA + clkctl0.syspll0ctl0().modify(|_, w| w.holdringoff_ena().dsiable()); + delay_loop_clocks((15 & 0xFFFF) / 2, 12_000_000); + } + /// enables default settings for pfd2 bits + pub(self) fn init_syspll_pfd2(config_bits: u8) { + // SAFETY: unsafe needed to take pointer to Clkctl0 and write specific bits + // needed to change the output of pfd0 + unsafe { + let clkctl0 = crate::pac::Clkctl0::steal(); + + // Disable the clock output first. + // SAFETY: unsafe needed to write the bits for pfd2 + clkctl0 + .syspll0pfd() + .modify(|_, w| w.pfd2_clkgate().gated().pfd2().bits(0x0)); + + // Set the new value and enable output. + // SAFETY: unsafe needed to write the bits for pfd2 + clkctl0 + .syspll0pfd() + .modify(|_, w| w.pfd2_clkgate().not_gated().pfd2().bits(config_bits)); + + // Wait for output becomes stable. + while clkctl0.syspll0pfd().read().pfd2_clkrdy().bit_is_clear() {} + + // Clear ready status flag. + clkctl0.syspll0pfd().modify(|_, w| w.pfd2_clkrdy().clear_bit()); + } + } + /// Enables default settings for pfd0 + pub(self) fn init_syspll_pfd0(config_bits: u8) { + // SAFETY: unsafe needed to take pointer to Clkctl0 and write specific bits + // needed to change the output of pfd0 + unsafe { + let clkctl0 = crate::pac::Clkctl0::steal(); + // Disable the clock output first + clkctl0 + .syspll0pfd() + .modify(|_, w| w.pfd0_clkgate().gated().pfd0().bits(0x0)); + + // Set the new value and enable output + clkctl0 + .syspll0pfd() + .modify(|_, w| w.pfd0_clkgate().not_gated().pfd0().bits(config_bits)); + + // Wait for output becomes stable + while clkctl0.syspll0pfd().read().pfd0_clkrdy().bit_is_clear() {} + + // Clear ready status flag + clkctl0.syspll0pfd().modify(|_, w| w.pfd0_clkrdy().clear_bit()); + } + } +} + +impl MainClkConfig { + fn init_main_clk() { + // SAFETY:: unsafe needed to take pointers to Clkctl0 and Clkctl1 + // used to set the right HW frequency + let clkctl0 = unsafe { crate::pac::Clkctl0::steal() }; + let clkctl1 = unsafe { crate::pac::Clkctl1::steal() }; + + clkctl0.mainclkselb().write(|w| w.sel().main_pll_clk()); + + // Set PFC0DIV divider to value 2, Subtract 1 since 0-> 1, 1-> 2, etc... + clkctl0.pfcdiv(0).modify(|_, w| w.reset().set_bit()); + // SAFETY: unsafe needed to write the bits for pfcdiv + clkctl0 + .pfcdiv(0) + .write(|w| unsafe { w.div().bits(2 - 1).halt().clear_bit() }); + while clkctl0.pfcdiv(0).read().reqflag().bit_is_set() {} + + // Set FRGPLLCLKDIV divider to value 12, Subtract 1 since 0-> 1, 1-> 2, etc... + clkctl1.frgpllclkdiv().modify(|_, w| w.reset().set_bit()); + // SAFETY: unsafe needed to write the bits for frgpllclkdiv + clkctl1 + .frgpllclkdiv() + .write(|w| unsafe { w.div().bits(12 - 1).halt().clear_bit() }); + while clkctl1.frgpllclkdiv().read().reqflag().bit_is_set() {} + } +} +impl MultiSourceClock for MainClkConfig { + fn get_clock_source_and_rate(&self, clock: &Clocks) -> Result<(Clocks, u32), ClockError> { + match clock { + Clocks::MainClk => { + let div: u32 = if self.src == MainClkSrc::FFROdiv4 { 4 } else { 1 }; + let converted_clock = Clocks::from(self.src); + match ConfigurableClock::get_clock_rate(self) { + Ok(_rate) => { + // SAFETY: unsafe needed to take pointer to Clkctl0 + // needed to calculate the clock rate from the bits written in the registers + let clkctl0 = unsafe { crate::pac::Clkctl0::steal() }; + if self.src == MainClkSrc::PllMain && clkctl0.syspll0ctl0().read().bypass().is_programmed_clk() + { + let mut temp; + temp = self.freq.load(Ordering::Relaxed) + * u32::from(clkctl0.syspll0ctl0().read().mult().bits()); + temp = (u64::from(temp) * 18 / u64::from(clkctl0.syspll0pfd().read().pfd0().bits())) as u32; + return Ok((converted_clock, temp)); + } + Ok((converted_clock, self.freq.load(Ordering::Relaxed) / div)) + } + Err(clk_err) => Err(clk_err), + } + } + _ => Err(ClockError::ClockMismatch), + } + } + fn set_clock_source_and_rate( + &mut self, + clock_src_config: &mut impl ConfigurableClock, + clock_src: &Clocks, + rate: u32, + ) -> Result<(), ClockError> { + if !clock_src_config.is_enabled() { + return Err(ClockError::ClockNotEnabled); + } + if let Ok(c) = >::try_into(*clock_src) { + // SAFETY: unsafe needed to take pointer to Clkctl0 + // needed to change the clock source + let clkctl0 = unsafe { crate::pac::Clkctl0::steal() }; + match c { + MainClkSrc::ClkIn => { + self.src = MainClkSrc::ClkIn; + + clkctl0.mainclksela().write(|w| w.sel().sysxtal_clk()); + clkctl0.mainclkselb().write(|w| w.sel().main_1st_clk()); + Ok(()) + } + // the following will yield the same result as if compared to FFROdiv4 + MainClkSrc::FFRO | MainClkSrc::FFROdiv4 => match rate { + div4 if div4 == (FfroFreq::Ffro60m as u32) / 4 || div4 == (FfroFreq::Ffro48m as u32) / 4 => { + self.src = MainClkSrc::FFROdiv4; + self.freq.store(div4, Ordering::Relaxed); + + clkctl0.mainclksela().write(|w| w.sel().ffro_div_4()); + clkctl0.mainclkselb().write(|w| w.sel().main_1st_clk()); + Ok(()) + } + div1 if div1 == FfroFreq::Ffro60m as u32 || div1 == FfroFreq::Ffro48m as u32 => { + self.src = MainClkSrc::FFRO; + self.freq.store(div1, Ordering::Relaxed); + + clkctl0.mainclksela().write(|w| w.sel().ffro_clk()); + clkctl0.mainclkselb().write(|w| w.sel().main_1st_clk()); + Ok(()) + } + _ => Err(ClockError::InvalidFrequency), + }, + MainClkSrc::Lposc => { + if let Ok(r) = >::try_into(rate) { + match r { + LposcFreq::Lp1m => { + self.src = MainClkSrc::Lposc; + self.freq.store(rate, Ordering::Relaxed); + + clkctl0.mainclksela().write(|w| w.sel().lposc()); + clkctl0.mainclkselb().write(|w| w.sel().main_1st_clk()); + Ok(()) + } + LposcFreq::Lp32k => Err(ClockError::InvalidFrequency), + } + } else { + Err(ClockError::InvalidFrequency) + } + } + MainClkSrc::SFRO => { + if rate == SFRO_FREQ { + self.src = MainClkSrc::SFRO; + self.freq.store(rate, Ordering::Relaxed); + clkctl0.mainclkselb().write(|w| w.sel().sfro_clk()); + Ok(()) + } else { + Err(ClockError::InvalidFrequency) + } + } + MainClkSrc::PllMain => { + let r = rate; + // From Section 4.6.1.1 Pll Limitations of the RT6xx User manual + let pll_max = 572_000_000; + let pll_min = 80_000_000; + if pll_min <= r && r <= pll_max { + clkctl0.mainclkselb().write(|w| w.sel().main_pll_clk()); + self.src = MainClkSrc::PllMain; + self.freq.store(r, Ordering::Relaxed); + Ok(()) + } else { + Err(ClockError::InvalidFrequency) + } + } + MainClkSrc::RTC32k => { + if rate == RtcFreq::SubSecond32kHz as u32 { + self.src = MainClkSrc::RTC32k; + self.freq.store(rate, Ordering::Relaxed); + clkctl0.mainclkselb().write(|w| w.sel().rtc_32k_clk()); + Ok(()) + } else { + Err(ClockError::InvalidFrequency) + } + } + } + } else { + Err(ClockError::ClockNotSupported) + } + } +} + +impl ConfigurableClock for MainClkConfig { + fn enable_and_reset(&self) -> Result<(), ClockError> { + MainClkConfig::init_main_clk(); + Ok(()) + } + fn disable(&self) -> Result<(), ClockError> { + error!("Attempting to reset the main clock, should NOT happen during runtime"); + Err(ClockError::ClockNotSupported) + } + fn get_clock_rate(&self) -> Result { + let (_c, rate) = MainClkConfig::get_clock_source_and_rate(self, &Clocks::MainClk)?; + Ok(rate) + } + fn set_clock_rate(&mut self, _div: u8, _mult: u8, _freq: u32) -> Result<(), ClockError> { + error!("The multi-source set_clock_rate_and_source method should be used instead of set_clock_rate"); + Err(ClockError::ClockNotSupported) + } + fn is_enabled(&self) -> bool { + self.state == State::Enabled + } +} + +impl ConfigurableClock for ClkInConfig { + fn enable_and_reset(&self) -> Result<(), ClockError> { + // External Input, no hw writes needed + Ok(()) + } + fn disable(&self) -> Result<(), ClockError> { + error!("Attempting to reset a clock input"); + Err(ClockError::ClockNotSupported) + } + fn get_clock_rate(&self) -> Result { + if self.freq.is_some() { + Ok(self.freq.as_ref().unwrap().load(Ordering::Relaxed)) + } else { + Err(ClockError::ClockNotEnabled) + } + } + fn set_clock_rate(&mut self, _div: u8, _mult: u8, freq: u32) -> Result<(), ClockError> { + trace!("Setting value of clk in config, this won't change the clock itself"); + self.freq.as_ref().unwrap().store(freq, Ordering::Relaxed); + Ok(()) + } + fn is_enabled(&self) -> bool { + self.state == State::Enabled + } +} + +impl RtcClkConfig { + /// Register writes to initialize the RTC Clock + fn init_rtc_clk() { + // SAFETY: unsafe needed to take pointer to Clkctl0, Clkctl1, and RTC + // needed to enable the RTC HW + let cc0 = unsafe { pac::Clkctl0::steal() }; + let cc1 = unsafe { pac::Clkctl1::steal() }; + let r = unsafe { pac::Rtc::steal() }; + // Enable the RTC peripheral clock + cc1.pscctl2_set().write(|w| w.rtc_lite_clk_set().set_clock()); + // Make sure the reset bit is cleared amd RTC OSC is powered up + r.ctrl().modify(|_, w| w.swreset().not_in_reset().rtc_osc_pd().enable()); + + // set initial match value, note that with a 15 bit count-down timer this would + // typically be 0x8000, but we are "doing some clever things" in time-driver.rs, + // read more about it in the comments there + // SAFETY: unsafe needed to write the bits + r.wake().write(|w| unsafe { w.bits(0xA) }); + + // Enable 32K OSC + cc0.osc32khzctl0().write(|w| w.ena32khz().enabled()); + + // enable rtc clk + r.ctrl().modify(|_, w| w.rtc_en().enable()); + } +} + +impl ConfigurableClock for RtcClkConfig { + fn enable_and_reset(&self) -> Result<(), ClockError> { + // should only be called once if previously disabled + RtcClkConfig::init_rtc_clk(); + Ok(()) + } + fn disable(&self) -> Result<(), ClockError> { + error!("Resetting the RTC clock, this should NOT happen during runtime"); + Err(ClockError::ClockNotSupported) + } + fn set_clock_rate(&mut self, _div: u8, _mult: u8, freq: u32) -> Result<(), ClockError> { + if let Ok(r) = >::try_into(freq) { + // SAFETY: unsafe needed to take pointer to RTC + // needed to enable the HW for the different RTC frequencies, powered down by default + let rtc = unsafe { crate::pac::Rtc::steal() }; + match r { + RtcFreq::Default1Hz => { + if rtc.ctrl().read().rtc_en().is_enable() { + trace!("Attempting to enable an already enabled clock, RTC 1Hz"); + } else { + rtc.ctrl().modify(|_r, w| w.rtc_en().enable()); + } + Ok(()) + } + RtcFreq::HighResolution1khz => { + if rtc.ctrl().read().rtc1khz_en().is_enable() { + trace!("Attempting to enable an already enabled clock, RTC 1Hz"); + } else { + rtc.ctrl().modify(|_r, w| w.rtc1khz_en().enable()); + } + Ok(()) + } + RtcFreq::SubSecond32kHz => { + if rtc.ctrl().read().rtc_subsec_ena().is_enable() { + trace!("Attempting to enable an already enabled clock, RTC 1Hz"); + } else { + rtc.ctrl().modify(|_r, w| w.rtc_subsec_ena().enable()); + } + Ok(()) + } + } + } else { + Err(ClockError::InvalidFrequency) + } + } + // unlike the others, since this provides multiple clocks, return the fastest one + fn get_clock_rate(&self) -> Result { + if self.sub_second_state == State::Enabled { + Ok(RtcFreq::SubSecond32kHz as u32) + } else if self.wake_alarm_state == State::Enabled { + Ok(RtcFreq::HighResolution1khz as u32) + } else if self.state == State::Enabled { + Ok(RtcFreq::Default1Hz as u32) + } else { + Err(ClockError::ClockNotEnabled) + } + } + fn is_enabled(&self) -> bool { + self.state == State::Enabled + } +} + +impl SysClkConfig { + /// Updates the system core clock frequency, SW concept used for systick + fn update_sys_core_clock(&self) { + trace!( + "System core clock has been updated to {:?}, this involves no HW reg writes", + self.sysclkfreq.load(Ordering::Relaxed) + ); + } +} + +impl ConfigurableClock for SysOscConfig { + fn enable_and_reset(&self) -> Result<(), ClockError> { + if self.state == State::Enabled { + trace!("SysOsc was already enabled"); + return Ok(()); + } + + // SAFETY: unsafe needed to take pointers to Sysctl0 and Clkctl0, needed to modify clock HW + let clkctl0 = unsafe { crate::pac::Clkctl0::steal() }; + let sysctl0 = unsafe { crate::pac::Sysctl0::steal() }; + + // Let CPU run on ffro for safe switching + clkctl0.mainclksela().write(|w| w.sel().ffro_clk()); + clkctl0.mainclksela().write(|w| w.sel().ffro_div_4()); + + // Power on SYSXTAL + sysctl0.pdruncfg0_clr().write(|w| w.sysxtal_pd().clr_pdruncfg0()); + + // Enable system OSC + clkctl0 + .sysoscctl0() + .write(|w| w.lp_enable().lp().bypass_enable().normal_mode()); + + delay_loop_clocks(260, SYS_OSC_DEFAULT_FREQ.into()); + Ok(()) + } + fn disable(&self) -> Result<(), ClockError> { + // SAFETY: unsafe needed to take pointers to Sysctl0 and Clkctl0, needed to modify clock HW + let clkctl0 = unsafe { crate::pac::Clkctl0::steal() }; + let sysctl0 = unsafe { crate::pac::Sysctl0::steal() }; + + // Let CPU run on ffro for safe switching + clkctl0.mainclksela().write(|w| w.sel().ffro_clk()); + clkctl0.mainclksela().write(|w| w.sel().ffro_div_4()); + + // Power on SYSXTAL + sysctl0.pdruncfg0_set().write(|w| w.sysxtal_pd().set_pdruncfg0()); + Ok(()) + } + fn get_clock_rate(&self) -> Result { + if self.state == State::Enabled { + Ok(SYS_OSC_DEFAULT_FREQ) + } else { + Err(ClockError::ClockNotEnabled) + } + } + fn is_enabled(&self) -> bool { + self.state == State::Enabled + } + fn set_clock_rate(&mut self, _div: u8, _mult: u8, _freq: u32) -> Result<(), ClockError> { + Err(ClockError::ClockNotSupported) + } +} + +/// Method to delay for a certain number of microseconds given a clock rate +pub fn delay_loop_clocks(usec: u64, freq_mhz: u64) { + let mut ticks = usec * freq_mhz / 1_000_000 / 4; + if ticks > u64::from(u32::MAX) { + ticks = u64::from(u32::MAX); + } + // won't panic since we check value above + cortex_m::asm::delay(ticks as u32); +} + +/// Configure the pad voltage pmc registers for all 3 vddio ranges +fn set_pad_voltage_range() { + // SAFETY: unsafe needed to take pointer to PNC as well as to write specific bits + unsafe { + let pmc = crate::pac::Pmc::steal(); + // Set up IO voltages + // all 3 ranges need to be 1.71-1.98V which is 01 + pmc.padvrange().write(|w| { + w.vddio_0range() + .bits(0b01) + .vddio_1range() + .bits(0b01) + .vddio_2range() + .bits(0b01) + }); + } +} + +/// Initialize AHB clock +fn init_syscpuahb_clk() { + // SAFETY: unsafe needed to take pointer to Clkctl0 + let clkctl0 = unsafe { crate::pac::Clkctl0::steal() }; + // SAFETY: unsafe needed to write the bits + // Set syscpuahbclkdiv to value 2, Subtract 1 since 0-> 1, 1-> 2, etc... + clkctl0.syscpuahbclkdiv().write(|w| unsafe { w.div().bits(2 - 1) }); + + while clkctl0.syscpuahbclkdiv().read().reqflag().bit_is_set() {} +} + +/// `ClockOut` config +pub struct ClockOutConfig { + src: ClkOutSrc, + div: u8, +} + +/// `ClockOut` sources +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +/// `ClockOut` sources +pub enum ClkOutSrc { + /// No Source, reduce power consumption + None, + /// SFRO clock + Sfro, + /// External input clock + ClkIn, + /// Low-power oscillator + Lposc, + /// FFRO clock + Ffro, + /// Main clock + MainClk, + /// Main DSP clock + DspMainClk, + /// Main Pll clock + MainPllClk, + /// `SysPll` Aux0 clock + Aux0PllClk, + /// `SysPll` DSP clock + DspPllClk, + /// `SysPll` Aux1 clock + Aux1PllClk, + /// Audio Pll clock + AudioPllClk, + /// 32 `KHz` RTC + RTC32k, +} + +/// Initialize the `ClkOutConfig` +impl ClockOutConfig { + /// Default configuration for Clock out + #[must_use] + pub fn default_config() -> Self { + Self { + src: ClkOutSrc::None, + div: 0, + } + } + + /// Enable the Clock Out output + pub fn enable_and_reset(&mut self) -> Result<(), ClockError> { + self.set_clkout_source_and_div(self.src, self.div)?; + Ok(()) + } + + /// Disable Clock Out output and select None as the source to conserve power + pub fn disable(&mut self) -> Result<(), ClockError> { + self.set_clkout_source_and_div(ClkOutSrc::None, 0)?; + Ok(()) + } + + /// Set the source of the Clock Out pin + fn set_clkout_source(&mut self, src: ClkOutSrc) -> Result<(), ClockError> { + // SAFETY: unsafe needed to take pointers to Clkctl1, needed to set source in HW + let cc1 = unsafe { pac::Clkctl1::steal() }; + match src { + ClkOutSrc::None => { + cc1.clkoutsel0().write(|w| w.sel().none()); + cc1.clkoutsel1().write(|w| w.sel().none()); + } + ClkOutSrc::Sfro => { + cc1.clkoutsel0().write(|w| w.sel().sfro_clk()); + cc1.clkoutsel1().write(|w| w.sel().clkoutsel0_output()); + } + ClkOutSrc::ClkIn => { + cc1.clkoutsel0().write(|w| w.sel().xtalin_clk()); + cc1.clkoutsel1().write(|w| w.sel().clkoutsel0_output()); + } + ClkOutSrc::Lposc => { + cc1.clkoutsel0().write(|w| w.sel().lposc()); + cc1.clkoutsel1().write(|w| w.sel().clkoutsel0_output()); + } + ClkOutSrc::Ffro => { + cc1.clkoutsel0().write(|w| w.sel().ffro_clk()); + cc1.clkoutsel1().write(|w| w.sel().clkoutsel0_output()); + } + ClkOutSrc::MainClk => { + cc1.clkoutsel0().write(|w| w.sel().main_clk()); + cc1.clkoutsel1().write(|w| w.sel().clkoutsel0_output()); + } + ClkOutSrc::DspMainClk => { + cc1.clkoutsel0().write(|w| w.sel().dsp_main_clk()); + cc1.clkoutsel1().write(|w| w.sel().clkoutsel0_output()); + } + ClkOutSrc::MainPllClk => { + cc1.clkoutsel0().write(|w| w.sel().none()); + cc1.clkoutsel1().write(|w| w.sel().main_pll_clk()); + } + ClkOutSrc::Aux0PllClk => { + cc1.clkoutsel0().write(|w| w.sel().none()); + cc1.clkoutsel1().write(|w| w.sel().syspll0_aux0_pll_clk()); + } + ClkOutSrc::DspPllClk => { + cc1.clkoutsel0().write(|w| w.sel().none()); + cc1.clkoutsel1().write(|w| w.sel().dsp_pll_clk()); + } + ClkOutSrc::AudioPllClk => { + cc1.clkoutsel0().write(|w| w.sel().none()); + cc1.clkoutsel1().write(|w| w.sel().audio_pll_clk()); + } + ClkOutSrc::Aux1PllClk => { + cc1.clkoutsel0().write(|w| w.sel().none()); + cc1.clkoutsel1().write(|w| w.sel().syspll0_aux1_pll_clk()); + } + ClkOutSrc::RTC32k => { + cc1.clkoutsel0().write(|w| w.sel().none()); + cc1.clkoutsel1().write(|w| w.sel().rtc_clk_32khz()); + } + } + self.src = src; + Ok(()) + } + /// set the clock out divider + /// note that 1 will be added to div when mapping to the divider + /// so bits(0) -> divide by 1 + /// ... + /// bits(255)-> divide by 256 + pub fn set_clkout_divider(&self, div: u8) -> Result<(), ClockError> { + // don't wait for clock to be ready if there's no source + if self.src != ClkOutSrc::None { + let cc1 = unsafe { pac::Clkctl1::steal() }; + + cc1.clkoutdiv() + .modify(|_, w| unsafe { w.div().bits(div).halt().clear_bit() }); + while cc1.clkoutdiv().read().reqflag().bit_is_set() {} + } + Ok(()) + } + /// set the source and divider for the clockout pin + pub fn set_clkout_source_and_div(&mut self, src: ClkOutSrc, div: u8) -> Result<(), ClockError> { + self.set_clkout_source(src)?; + + self.set_clkout_divider(div)?; + + Ok(()) + } +} + +/// Using the config, enables all desired clocks to desired clock rates +fn init_clock_hw(config: ClockConfig) -> Result<(), ClockError> { + if let Err(e) = config.rtc.enable_and_reset() { + error!("couldn't Power on OSC for RTC, result: {:?}", e); + return Err(e); + } + + if let Err(e) = config.lposc.enable_and_reset() { + error!("couldn't Power on LPOSC, result: {:?}", e); + return Err(e); + } + + if let Err(e) = config.ffro.enable_and_reset() { + error!("couldn't Power on FFRO, result: {:?}", e); + return Err(e); + } + + if let Err(e) = config.sfro.enable_and_reset() { + error!("couldn't Power on SFRO, result: {:?}", e); + return Err(e); + } + + if let Err(e) = config.sys_osc.enable_and_reset() { + error!("Couldn't enable sys oscillator {:?}", e); + return Err(e); + } + + if let Err(e) = config.main_pll_clk.enable_and_reset() { + error!("Couldn't enable main pll clock {:?}", e); + return Err(e); + } + + // Move FLEXSPI clock source from main clock to FFRO to avoid instruction/data fetch issue in XIP when + // updating PLL and main clock. + // SAFETY: unsafe needed to take pointers to Clkctl0 + let cc0 = unsafe { pac::Clkctl0::steal() }; + cc0.flexspifclksel().write(|w| w.sel().ffro_clk()); + + // Move ESPI clock source to FFRO + #[cfg(feature = "_espi")] + { + cc0.espiclksel().write(|w| w.sel().use_48_60m()); + } + + init_syscpuahb_clk(); + + if let Err(e) = config.main_clk.enable_and_reset() { + error!("Couldn't enable main clock {:?}", e); + return Err(e); + } + + config.sys_clk.update_sys_core_clock(); + Ok(()) +} + +/// SAFETY: must be called exactly once at bootup +pub(crate) unsafe fn init(config: ClockConfig) -> Result<(), ClockError> { + init_clock_hw(config)?; + + // set VDDIO ranges 0-2 + set_pad_voltage_range(); + Ok(()) +} + +///Trait to expose perph clocks +trait SealedSysconPeripheral { + fn enable_and_reset_perph_clock(); + fn disable_perph_clock(); +} + +/// Clock and Reset control for peripherals +#[allow(private_bounds)] +pub trait SysconPeripheral: SealedSysconPeripheral + 'static {} +/// Enables and resets peripheral `T`. +/// +/// # Safety +/// +/// Peripheral must not be in use. +pub fn enable_and_reset() { + T::enable_and_reset_perph_clock(); +} + +/// Disables peripheral `T`. +/// +/// # Safety +/// +/// Peripheral must not be in use. +pub fn disable() { + T::disable_perph_clock(); +} +macro_rules! impl_perph_clk { + ($peripheral:ident, $clkctl:ident, $clkreg:ident, $rstctl:ident, $rstreg:ident, $bit:expr) => { + impl SealedSysconPeripheral for crate::peripherals::$peripheral { + fn enable_and_reset_perph_clock() { + // SAFETY: unsafe needed to take pointers to Rstctl1 and Clkctl1 + let cc1 = unsafe { pac::$clkctl::steal() }; + let rc1 = unsafe { pac::$rstctl::steal() }; + + paste! { + // SAFETY: unsafe due to the use of bits() + cc1.[<$clkreg _set>]().write(|w| unsafe { w.bits(1 << $bit) }); + + // SAFETY: unsafe due to the use of bits() + rc1.[<$rstreg _clr>]().write(|w| unsafe { w.bits(1 << $bit) }); + } + } + + fn disable_perph_clock() { + // SAFETY: unsafe needed to take pointers to Rstctl1 and Clkctl1 + let cc1 = unsafe { pac::$clkctl::steal() }; + let rc1 = unsafe { pac::$rstctl::steal() }; + + paste! { + // SAFETY: unsafe due to the use of bits() + rc1.[<$rstreg _set>]().write(|w| unsafe { w.bits(1 << $bit) }); + + // SAFETY: unsafe due to the use of bits() + cc1.[<$clkreg _clr>]().write(|w| unsafe { w.bits(1 << $bit) }); + } + } + } + + impl SysconPeripheral for crate::peripherals::$peripheral {} + }; +} + +// These should enabled once the relevant peripherals are implemented. +// impl_perph_clk!(GPIOINTCTL, Clkctl1, pscctl2, Rstctl1, prstctl2, 30); +// impl_perph_clk!(OTP, Clkctl0, pscctl0, Rstctl0, prstctl0, 17); + +// impl_perph_clk!(ROM_CTL_128KB, Clkctl0, pscctl0, Rstctl0, prstctl0, 2); +// impl_perph_clk!(USBHS_SRAM, Clkctl0, pscctl0, Rstctl0, prstctl0, 23); + +impl_perph_clk!(PIMCTL, Clkctl1, pscctl2, Rstctl1, prstctl2, 31); +impl_perph_clk!(ACMP, Clkctl0, pscctl1, Rstctl0, prstctl1, 15); +impl_perph_clk!(ADC0, Clkctl0, pscctl1, Rstctl0, prstctl1, 16); +impl_perph_clk!(CASPER, Clkctl0, pscctl0, Rstctl0, prstctl0, 9); +impl_perph_clk!(CRC, Clkctl1, pscctl1, Rstctl1, prstctl1, 16); +impl_perph_clk!(CTIMER0_COUNT_CHANNEL0, Clkctl1, pscctl2, Rstctl1, prstctl2, 0); +impl_perph_clk!(CTIMER1_COUNT_CHANNEL0, Clkctl1, pscctl2, Rstctl1, prstctl2, 1); +impl_perph_clk!(CTIMER2_COUNT_CHANNEL0, Clkctl1, pscctl2, Rstctl1, prstctl2, 2); +impl_perph_clk!(CTIMER3_COUNT_CHANNEL0, Clkctl1, pscctl2, Rstctl1, prstctl2, 3); +impl_perph_clk!(CTIMER4_COUNT_CHANNEL0, Clkctl1, pscctl2, Rstctl1, prstctl2, 4); +impl_perph_clk!(DMA0, Clkctl1, pscctl1, Rstctl1, prstctl1, 23); +impl_perph_clk!(DMA1, Clkctl1, pscctl1, Rstctl1, prstctl1, 24); +impl_perph_clk!(DMIC0, Clkctl1, pscctl0, Rstctl1, prstctl0, 24); + +#[cfg(feature = "_espi")] +impl_perph_clk!(ESPI, Clkctl0, pscctl1, Rstctl0, prstctl1, 7); + +impl_perph_clk!(FLEXCOMM0, Clkctl1, pscctl0, Rstctl1, prstctl0, 8); +impl_perph_clk!(FLEXCOMM1, Clkctl1, pscctl0, Rstctl1, prstctl0, 9); +impl_perph_clk!(FLEXCOMM14, Clkctl1, pscctl0, Rstctl1, prstctl0, 22); +impl_perph_clk!(FLEXCOMM15, Clkctl1, pscctl0, Rstctl1, prstctl0, 23); +impl_perph_clk!(FLEXCOMM2, Clkctl1, pscctl0, Rstctl1, prstctl0, 10); +impl_perph_clk!(FLEXCOMM3, Clkctl1, pscctl0, Rstctl1, prstctl0, 11); +impl_perph_clk!(FLEXCOMM4, Clkctl1, pscctl0, Rstctl1, prstctl0, 12); +impl_perph_clk!(FLEXCOMM5, Clkctl1, pscctl0, Rstctl1, prstctl0, 13); +impl_perph_clk!(FLEXCOMM6, Clkctl1, pscctl0, Rstctl1, prstctl0, 14); +impl_perph_clk!(FLEXCOMM7, Clkctl1, pscctl0, Rstctl1, prstctl0, 15); +impl_perph_clk!(FLEXSPI, Clkctl0, pscctl0, Rstctl0, prstctl0, 16); +impl_perph_clk!(FREQME, Clkctl1, pscctl1, Rstctl1, prstctl1, 31); +impl_perph_clk!(HASHCRYPT, Clkctl0, pscctl0, Rstctl0, prstctl0, 10); +impl_perph_clk!(HSGPIO0, Clkctl1, pscctl1, Rstctl1, prstctl1, 0); +impl_perph_clk!(HSGPIO1, Clkctl1, pscctl1, Rstctl1, prstctl1, 1); +impl_perph_clk!(HSGPIO2, Clkctl1, pscctl1, Rstctl1, prstctl1, 2); +impl_perph_clk!(HSGPIO3, Clkctl1, pscctl1, Rstctl1, prstctl1, 3); +impl_perph_clk!(HSGPIO4, Clkctl1, pscctl1, Rstctl1, prstctl1, 4); +impl_perph_clk!(HSGPIO5, Clkctl1, pscctl1, Rstctl1, prstctl1, 5); +impl_perph_clk!(HSGPIO6, Clkctl1, pscctl1, Rstctl1, prstctl1, 6); +impl_perph_clk!(HSGPIO7, Clkctl1, pscctl1, Rstctl1, prstctl1, 7); +impl_perph_clk!(I3C0, Clkctl1, pscctl2, Rstctl1, prstctl2, 16); +impl_perph_clk!(MRT0, Clkctl1, pscctl2, Rstctl1, prstctl2, 8); +impl_perph_clk!(MU_A, Clkctl1, pscctl1, Rstctl1, prstctl1, 28); +impl_perph_clk!(OS_EVENT, Clkctl1, pscctl0, Rstctl1, prstctl0, 27); +impl_perph_clk!(POWERQUAD, Clkctl0, pscctl0, Rstctl0, prstctl0, 8); +impl_perph_clk!(PUF, Clkctl0, pscctl0, Rstctl0, prstctl0, 11); +impl_perph_clk!(RNG, Clkctl0, pscctl0, Rstctl0, prstctl0, 12); +impl_perph_clk!(RTC, Clkctl1, pscctl2, Rstctl1, prstctl2, 7); +impl_perph_clk!(SCT0, Clkctl0, pscctl0, Rstctl0, prstctl0, 24); +impl_perph_clk!(SECGPIO, Clkctl0, pscctl1, Rstctl0, prstctl1, 24); +impl_perph_clk!(SEMA42, Clkctl1, pscctl1, Rstctl1, prstctl1, 29); +impl_perph_clk!(USBHSD, Clkctl0, pscctl0, Rstctl0, prstctl0, 21); +impl_perph_clk!(USBHSH, Clkctl0, pscctl0, Rstctl0, prstctl0, 22); +impl_perph_clk!(USBPHY, Clkctl0, pscctl0, Rstctl0, prstctl0, 20); +impl_perph_clk!(USDHC0, Clkctl0, pscctl1, Rstctl0, prstctl1, 2); +impl_perph_clk!(USDHC1, Clkctl0, pscctl1, Rstctl0, prstctl1, 3); +impl_perph_clk!(UTICK0, Clkctl0, pscctl2, Rstctl0, prstctl2, 0); +impl_perph_clk!(WDT0, Clkctl0, pscctl2, Rstctl0, prstctl2, 1); +impl_perph_clk!(WDT1, Clkctl1, pscctl2, Rstctl1, prstctl2, 10); diff --git a/embassy-imxrt/src/fmt.rs b/embassy-imxrt/src/fmt.rs new file mode 100644 index 000000000..c65273340 --- /dev/null +++ b/embassy-imxrt/src/fmt.rs @@ -0,0 +1,257 @@ +#![macro_use] +#![allow(unused)] + +use core::fmt::{Debug, Display, LowerHex}; + +#[collapse_debuginfo(yes)] +macro_rules! assert { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::assert!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::assert!($($x)*); + } + }; +} + +#[collapse_debuginfo(yes)] +macro_rules! assert_eq { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::assert_eq!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::assert_eq!($($x)*); + } + }; +} + +#[collapse_debuginfo(yes)] +macro_rules! assert_ne { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::assert_ne!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::assert_ne!($($x)*); + } + }; +} + +#[collapse_debuginfo(yes)] +macro_rules! debug_assert { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::debug_assert!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::debug_assert!($($x)*); + } + }; +} + +#[collapse_debuginfo(yes)] +macro_rules! debug_assert_eq { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::debug_assert_eq!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::debug_assert_eq!($($x)*); + } + }; +} + +#[collapse_debuginfo(yes)] +macro_rules! debug_assert_ne { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::debug_assert_ne!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::debug_assert_ne!($($x)*); + } + }; +} + +#[collapse_debuginfo(yes)] +macro_rules! todo { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::todo!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::todo!($($x)*); + } + }; +} + +#[collapse_debuginfo(yes)] +macro_rules! unreachable { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::unreachable!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::unreachable!($($x)*); + } + }; +} + +#[collapse_debuginfo(yes)] +macro_rules! panic { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::panic!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::panic!($($x)*); + } + }; +} + +#[collapse_debuginfo(yes)] +macro_rules! trace { + ($s:literal $(, $x:expr)* $(,)?) => { + { + #[cfg(feature = "defmt")] + ::defmt::trace!($s $(, $x)*); + #[cfg(not(feature = "defmt"))] + let _ = ($( & $x ),*); + } + }; +} + +#[collapse_debuginfo(yes)] +macro_rules! debug { + ($s:literal $(, $x:expr)* $(,)?) => { + { + #[cfg(feature = "defmt")] + ::defmt::debug!($s $(, $x)*); + #[cfg(not(feature = "defmt"))] + let _ = ($( & $x ),*); + } + }; +} + +#[collapse_debuginfo(yes)] +macro_rules! info { + ($s:literal $(, $x:expr)* $(,)?) => { + { + #[cfg(feature = "defmt")] + ::defmt::info!($s $(, $x)*); + #[cfg(not(feature = "defmt"))] + let _ = ($( & $x ),*); + } + }; +} + +#[collapse_debuginfo(yes)] +macro_rules! warn { + ($s:literal $(, $x:expr)* $(,)?) => { + { + #[cfg(feature = "defmt")] + ::defmt::warn!($s $(, $x)*); + #[cfg(not(feature = "defmt"))] + let _ = ($( & $x ),*); + } + }; +} + +#[collapse_debuginfo(yes)] +macro_rules! error { + ($s:literal $(, $x:expr)* $(,)?) => { + { + #[cfg(feature = "defmt")] + ::defmt::error!($s $(, $x)*); + #[cfg(not(feature = "defmt"))] + let _ = ($( & $x ),*); + } + }; +} + +#[cfg(feature = "defmt")] +#[collapse_debuginfo(yes)] +macro_rules! unwrap { + ($($x:tt)*) => { + ::defmt::unwrap!($($x)*) + }; +} + +#[cfg(not(feature = "defmt"))] +#[collapse_debuginfo(yes)] +macro_rules! unwrap { + ($arg:expr) => { + match $crate::fmt::Try::into_result($arg) { + ::core::result::Result::Ok(t) => t, + ::core::result::Result::Err(e) => { + ::core::panic!("unwrap of `{}` failed: {:?}", ::core::stringify!($arg), e); + } + } + }; + ($arg:expr, $($msg:expr),+ $(,)? ) => { + match $crate::fmt::Try::into_result($arg) { + ::core::result::Result::Ok(t) => t, + ::core::result::Result::Err(e) => { + ::core::panic!("unwrap of `{}` failed: {}: {:?}", ::core::stringify!($arg), ::core::format_args!($($msg,)*), e); + } + } + } +} + +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub struct NoneError; + +pub trait Try { + type Ok; + type Error; + fn into_result(self) -> Result; +} + +impl Try for Option { + type Ok = T; + type Error = NoneError; + + #[inline] + fn into_result(self) -> Result { + self.ok_or(NoneError) + } +} + +impl Try for Result { + type Ok = T; + type Error = E; + + #[inline] + fn into_result(self) -> Self { + self + } +} + +pub(crate) struct Bytes<'a>(pub &'a [u8]); + +impl Debug for Bytes<'_> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +impl Display for Bytes<'_> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +impl LowerHex for Bytes<'_> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +#[cfg(feature = "defmt")] +impl defmt::Format for Bytes<'_> { + fn format(&self, fmt: defmt::Formatter) { + defmt::write!(fmt, "{:02x}", self.0) + } +} diff --git a/embassy-imxrt/src/gpio.rs b/embassy-imxrt/src/gpio.rs new file mode 100644 index 000000000..6883c4ee0 --- /dev/null +++ b/embassy-imxrt/src/gpio.rs @@ -0,0 +1,1060 @@ +//! GPIO + +use core::convert::Infallible; +use core::future::Future; +use core::marker::PhantomData; +use core::pin::Pin as FuturePin; +use core::task::{Context, Poll}; + +use embassy_hal_internal::interrupt::InterruptExt; +use embassy_sync::waitqueue::AtomicWaker; + +use crate::clocks::enable_and_reset; +use crate::iopctl::IopctlPin; +pub use crate::iopctl::{AnyPin, DriveMode, DriveStrength, Function, Inverter, Pull, SlewRate}; +use crate::sealed::Sealed; +use crate::{interrupt, peripherals, Peri, PeripheralType}; + +// This should be unique per IMXRT package +const PORT_COUNT: usize = 8; + +/// Digital input or output level. +#[derive(Debug, Eq, PartialEq, Copy, Clone)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum Level { + /// Logic Low + Low, + /// Logic High + High, +} + +impl From for Level { + fn from(val: bool) -> Self { + match val { + true => Self::High, + false => Self::Low, + } + } +} + +impl From for bool { + fn from(level: Level) -> bool { + match level { + Level::Low => false, + Level::High => true, + } + } +} + +/// Interrupt trigger levels. +#[derive(Debug, Eq, PartialEq, Copy, Clone)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum InterruptType { + /// Trigger on level. + Level, + /// Trigger on edge. + Edge, +} + +#[cfg(feature = "rt")] +#[interrupt] +#[allow(non_snake_case)] +fn GPIO_INTA() { + irq_handler(&GPIO_WAKERS); +} + +#[cfg(feature = "rt")] +struct BitIter(u32); + +#[cfg(feature = "rt")] +impl Iterator for BitIter { + type Item = u32; + + fn next(&mut self) -> Option { + match self.0.trailing_zeros() { + 32 => None, + b => { + self.0 &= !(1 << b); + Some(b) + } + } + } +} + +#[cfg(feature = "rt")] +fn irq_handler(port_wakers: &[Option<&PortWaker>]) { + let reg = unsafe { crate::pac::Gpio::steal() }; + + for (port, port_waker) in port_wakers.iter().enumerate() { + let Some(port_waker) = port_waker else { + continue; + }; + + let stat = reg.intstata(port).read().bits(); + for pin in BitIter(stat) { + // Clear the interrupt from this pin + reg.intstata(port).write(|w| unsafe { w.status().bits(1 << pin) }); + // Disable interrupt from this pin + reg.intena(port) + .modify(|r, w| unsafe { w.int_en().bits(r.int_en().bits() & !(1 << pin)) }); + + let Some(waker) = port_waker.get_waker(pin as usize) else { + continue; + }; + + waker.wake(); + } + } +} + +/// Initialization Logic +/// Note: GPIO port clocks are initialized in the clocks module. +pub(crate) fn init() { + // Enable GPIO clocks + enable_and_reset::(); + enable_and_reset::(); + enable_and_reset::(); + enable_and_reset::(); + enable_and_reset::(); + enable_and_reset::(); + enable_and_reset::(); + enable_and_reset::(); + + // Enable INTA + interrupt::GPIO_INTA.unpend(); + + // SAFETY: + // + // At this point, all GPIO interrupts are masked. No interrupts + // will trigger until a pin is configured as Input, which can only + // happen after initialization of the HAL + unsafe { interrupt::GPIO_INTA.enable() }; +} + +/// Input Sense mode. +pub trait Sense: Sealed {} + +/// Sense Enabled Flex pin. +/// +/// This is a true flex pin as the input buffer is enabled. +/// It can sense its own level when even when configured as an output pin. +pub enum SenseEnabled {} +impl Sealed for SenseEnabled {} +impl Sense for SenseEnabled {} + +/// Sense Enabled Flex pin. +/// +/// This is **not** a true flex pin as the input buffer is disabled. +/// It cannot be turned into an input and it cannot see its own state, but it consumes less power. +/// Consider using a sense enabled flex pin if you need to read the pin's state or turn this into an input, +/// however note that **power consumption may be increased**. +pub enum SenseDisabled {} +impl Sealed for SenseDisabled {} +impl Sense for SenseDisabled {} + +/// Flex pin. +/// +/// This pin can be either an input or output pin. The output level register bit will +/// remain set while not in output mode, so the pin's level will be 'remembered' when it is not in +/// output mode. +pub struct Flex<'d, S: Sense> { + pin: Peri<'d, AnyPin>, + _sense_mode: PhantomData, +} + +impl Flex<'_, S> { + /// Converts pin to output pin + /// + /// The pin level will be whatever was set before (or low by default). If you want it to begin + /// at a specific level, call `set_high`/`set_low` on the pin first. + pub fn set_as_output(&mut self, mode: DriveMode, strength: DriveStrength, slew_rate: SlewRate) { + self.pin + .set_pull(Pull::None) + .set_drive_mode(mode) + .set_drive_strength(strength) + .set_slew_rate(slew_rate); + + self.pin.block().dirset(self.pin.port()).write(|w| + // SAFETY: Writing a 0 to bits in this register has no effect, + // however PAC has it marked unsafe due to using the bits() method. + // There is not currently a "safe" method for setting a single-bit. + unsafe { w.dirsetp().bits(1 << self.pin.pin()) }); + } + + /// Set high + pub fn set_high(&mut self) { + self.pin.block().set(self.pin.port()).write(|w| + // SAFETY: Writing a 0 to bits in this register has no effect, + // however PAC has it marked unsafe due to using the bits() method. + // There is not currently a "safe" method for setting a single-bit. + unsafe { w.setp().bits(1 << self.pin.pin()) }); + } + + /// Set low + pub fn set_low(&mut self) { + self.pin.block().clr(self.pin.port()).write(|w| + // SAFETY: Writing a 0 to bits in this register has no effect, + // however PAC has it marked unsafe due to using the bits() method. + // There is not currently a "safe" method for setting a single-bit. + unsafe { w.clrp().bits(1 << self.pin.pin()) }); + } + + /// Set level + pub fn set_level(&mut self, level: Level) { + match level { + Level::High => self.set_high(), + Level::Low => self.set_low(), + } + } + + /// Is the output level high? + #[must_use] + pub fn is_set_high(&self) -> bool { + !self.is_set_low() + } + + /// Is the output level low? + #[must_use] + pub fn is_set_low(&self) -> bool { + (self.pin.block().set(self.pin.port()).read().setp().bits() & (1 << self.pin.pin())) == 0 + } + + /// Toggle + pub fn toggle(&mut self) { + self.pin.block().not(self.pin.port()).write(|w| + // SAFETY: Writing a 0 to bits in this register has no effect, + // however PAC has it marked unsafe due to using the bits() method. + // There is not currently a "safe" method for setting a single-bit. + unsafe { w.notp().bits(1 << self.pin.pin()) }); + } +} + +impl Drop for Flex<'_, S> { + #[inline] + fn drop(&mut self) { + critical_section::with(|_| { + self.pin.reset(); + }); + } +} + +impl<'d> Flex<'d, SenseEnabled> { + /// New flex pin. + pub fn new_with_sense(pin: Peri<'d, impl GpioPin>) -> Self { + pin.set_function(Function::F0) + .disable_analog_multiplex() + .enable_input_buffer(); + + Self { + pin: pin.into(), + _sense_mode: PhantomData::, + } + } + + /// Converts pin to input pin + pub fn set_as_input(&mut self, pull: Pull, inverter: Inverter) { + self.pin.set_pull(pull).set_input_inverter(inverter); + + self.pin.block().dirclr(self.pin.port()).write(|w| + // SAFETY: Writing a 0 to bits in this register has no effect, + // however PAC has it marked unsafe due to using the bits() method. + // There is not currently a "safe" method for setting a single-bit. + unsafe { w.dirclrp().bits(1 << self.pin.pin()) }); + } + + /// Converts pin to special function pin + /// # Safety + /// Unsafe to require justifying change from default to a special function + /// + pub unsafe fn set_as_special_function(&mut self, func: Function) { + self.pin.set_function(func); + } + + /// Is high? + #[must_use] + pub fn is_high(&self) -> bool { + !self.is_low() + } + + /// Is low? + #[must_use] + pub fn is_low(&self) -> bool { + self.pin.block().b(self.pin.port()).b_(self.pin.pin()).read() == 0 + } + + /// Current level + #[must_use] + pub fn get_level(&self) -> Level { + self.is_high().into() + } + + /// Wait until the pin is high. If it is already high, return immediately. + #[inline] + pub async fn wait_for_high(&mut self) { + InputFuture::new(self.pin.reborrow(), InterruptType::Level, Level::High).await; + } + + /// Wait until the pin is low. If it is already low, return immediately. + #[inline] + pub async fn wait_for_low(&mut self) { + InputFuture::new(self.pin.reborrow(), InterruptType::Level, Level::Low).await; + } + + /// Wait for the pin to undergo a transition from low to high. + #[inline] + pub async fn wait_for_rising_edge(&mut self) { + InputFuture::new(self.pin.reborrow(), InterruptType::Edge, Level::High).await; + } + + /// Wait for the pin to undergo a transition from high to low. + #[inline] + pub async fn wait_for_falling_edge(&mut self) { + InputFuture::new(self.pin.reborrow(), InterruptType::Edge, Level::Low).await; + } + + /// Wait for the pin to undergo any transition, i.e low to high OR high to low. + #[inline] + pub async fn wait_for_any_edge(&mut self) { + if self.is_high() { + InputFuture::new(self.pin.reborrow(), InterruptType::Edge, Level::Low).await; + } else { + InputFuture::new(self.pin.reborrow(), InterruptType::Edge, Level::High).await; + } + } + + /// Return a new Flex pin instance with level sensing disabled. + /// + /// Consumes less power than a flex pin with sensing enabled. + #[must_use] + pub fn disable_sensing(self) -> Flex<'d, SenseDisabled> { + // Cloning the pin is ok since we consume self immediately + let new_pin = unsafe { self.pin.clone_unchecked() }; + drop(self); + Flex::::new(new_pin) + } +} + +impl<'d> Flex<'d, SenseDisabled> { + /// New flex pin. + pub fn new(pin: Peri<'d, impl GpioPin>) -> Self { + pin.set_function(Function::F0) + .disable_analog_multiplex() + .disable_input_buffer(); + + Self { + pin: pin.into(), + _sense_mode: PhantomData::, + } + } + + /// Return a new Flex pin instance with level sensing enabled. + #[must_use] + pub fn enable_sensing(self) -> Flex<'d, SenseEnabled> { + // Cloning the pin is ok since we consume self immediately + let new_pin = unsafe { self.pin.clone_unchecked() }; + drop(self); + Flex::new_with_sense(new_pin) + } +} + +/// Input pin +pub struct Input<'d> { + // When Input is dropped, Flex's drop() will make sure the pin is reset to its default state. + pin: Flex<'d, SenseEnabled>, +} + +impl<'d> Input<'d> { + /// New input pin + pub fn new(pin: Peri<'d, impl GpioPin>, pull: Pull, inverter: Inverter) -> Self { + let mut pin = Flex::new_with_sense(pin); + pin.set_as_input(pull, inverter); + Self { pin } + } + + /// Is high? + #[must_use] + pub fn is_high(&self) -> bool { + self.pin.is_high() + } + + /// Is low? + #[must_use] + pub fn is_low(&self) -> bool { + self.pin.is_low() + } + + /// Input level + #[must_use] + pub fn get_level(&self) -> Level { + self.pin.get_level() + } + + /// Wait until the pin is high. If it is already high, return immediately. + #[inline] + pub async fn wait_for_high(&mut self) { + self.pin.wait_for_high().await; + } + + /// Wait until the pin is low. If it is already low, return immediately. + #[inline] + pub async fn wait_for_low(&mut self) { + self.pin.wait_for_low().await; + } + + /// Wait for the pin to undergo a transition from low to high. + #[inline] + pub async fn wait_for_rising_edge(&mut self) { + self.pin.wait_for_rising_edge().await; + } + + /// Wait for the pin to undergo a transition from high to low. + #[inline] + pub async fn wait_for_falling_edge(&mut self) { + self.pin.wait_for_falling_edge().await; + } + + /// Wait for the pin to undergo any transition, i.e low to high OR high to low. + #[inline] + pub async fn wait_for_any_edge(&mut self) { + self.pin.wait_for_any_edge().await; + } +} + +#[must_use = "futures do nothing unless you `.await` or poll them"] +struct InputFuture<'d> { + pin: Peri<'d, AnyPin>, +} + +impl<'d> InputFuture<'d> { + fn new(pin: Peri<'d, impl GpioPin>, int_type: InterruptType, level: Level) -> Self { + critical_section::with(|_| { + // Clear any existing pending interrupt on this pin + pin.block() + .intstata(pin.port()) + .write(|w| unsafe { w.status().bits(1 << pin.pin()) }); + + /* Pin interrupt configuration */ + pin.block().intedg(pin.port()).modify(|r, w| match int_type { + InterruptType::Edge => unsafe { w.bits(r.bits() | (1 << pin.pin())) }, + InterruptType::Level => unsafe { w.bits(r.bits() & !(1 << pin.pin())) }, + }); + + pin.block().intpol(pin.port()).modify(|r, w| match level { + Level::High => unsafe { w.bits(r.bits() & !(1 << pin.pin())) }, + Level::Low => unsafe { w.bits(r.bits() | (1 << pin.pin())) }, + }); + + // Enable pin interrupt on GPIO INT A + pin.block() + .intena(pin.port()) + .modify(|r, w| unsafe { w.int_en().bits(r.int_en().bits() | (1 << pin.pin())) }); + }); + + Self { pin: pin.into() } + } +} + +impl Future for InputFuture<'_> { + type Output = (); + + fn poll(self: FuturePin<&mut Self>, cx: &mut Context<'_>) -> Poll { + // We need to register/re-register the waker for each poll because any + // calls to wake will deregister the waker. + if self.pin.port() >= GPIO_WAKERS.len() { + panic!("Invalid GPIO port index {}", self.pin.port()); + } + + let port_waker = GPIO_WAKERS[self.pin.port()]; + if port_waker.is_none() { + panic!("Waker not present for GPIO port {}", self.pin.port()); + } + + let waker = port_waker.unwrap().get_waker(self.pin.pin()); + if waker.is_none() { + panic!( + "Waker not present for GPIO pin {}, port {}", + self.pin.pin(), + self.pin.port() + ); + } + waker.unwrap().register(cx.waker()); + + // Double check that the pin interrut has been disabled by IRQ handler + if self.pin.block().intena(self.pin.port()).read().bits() & (1 << self.pin.pin()) == 0 { + Poll::Ready(()) + } else { + Poll::Pending + } + } +} + +/// Output pin +/// Cannot be set as an input and cannot read its own pin state! +/// Consider using a Flex pin if you want that functionality, at the cost of higher power consumption. +pub struct Output<'d> { + // When Output is dropped, Flex's drop() will make sure the pin is reset to its default state. + pin: Flex<'d, SenseDisabled>, +} + +impl<'d> Output<'d> { + /// New output pin + pub fn new( + pin: Peri<'d, impl GpioPin>, + initial_output: Level, + mode: DriveMode, + strength: DriveStrength, + slew_rate: SlewRate, + ) -> Self { + let mut pin = Flex::new(pin); + pin.set_level(initial_output); + pin.set_as_output(mode, strength, slew_rate); + + Self { pin } + } + + /// Set high + pub fn set_high(&mut self) { + self.pin.set_high(); + } + + /// Set low + pub fn set_low(&mut self) { + self.pin.set_low(); + } + + /// Toggle + pub fn toggle(&mut self) { + self.pin.toggle(); + } + + /// Set level + pub fn set_level(&mut self, level: Level) { + self.pin.set_level(level); + } + + /// Is set high? + #[must_use] + pub fn is_set_high(&self) -> bool { + self.pin.is_set_high() + } + + /// Is set low? + #[must_use] + pub fn is_set_low(&self) -> bool { + self.pin.is_set_low() + } +} + +trait SealedPin: IopctlPin { + fn pin_port(&self) -> usize; + + fn port(&self) -> usize { + self.pin_port() / 32 + } + + fn pin(&self) -> usize { + self.pin_port() % 32 + } + + fn block(&self) -> crate::pac::Gpio { + // SAFETY: Assuming GPIO pin specific registers are only accessed through this HAL, + // this is safe because the HAL ensures ownership or exclusive mutable references + // to pins. + unsafe { crate::pac::Gpio::steal() } + } +} + +/// GPIO pin trait. +#[allow(private_bounds)] +pub trait GpioPin: SealedPin + Sized + PeripheralType + Into + 'static { + /// Type-erase the pin. + fn degrade(self) -> AnyPin { + // SAFETY: This is only called within the GpioPin trait, which is only + // implemented within this module on valid pin peripherals and thus + // has been verified to be correct. + unsafe { AnyPin::steal(self.port() as u8, self.pin() as u8) } + } +} + +impl SealedPin for AnyPin { + fn pin_port(&self) -> usize { + self.pin_port() + } +} +impl GpioPin for AnyPin {} + +macro_rules! impl_pin { + ($pin_periph:ident, $pin_port:expr, $pin_no:expr) => { + impl SealedPin for crate::peripherals::$pin_periph { + fn pin_port(&self) -> usize { + $pin_port * 32 + $pin_no + } + } + impl GpioPin for crate::peripherals::$pin_periph {} + impl From for AnyPin { + fn from(value: crate::peripherals::$pin_periph) -> Self { + value.degrade() + } + } + }; +} + +/// Container for pin wakers +struct PortWaker { + offset: usize, + wakers: &'static [AtomicWaker], +} + +impl PortWaker { + fn get_waker(&self, pin: usize) -> Option<&AtomicWaker> { + self.wakers.get(pin - self.offset) + } +} + +macro_rules! define_port_waker { + ($name:ident, $start:expr, $end:expr) => { + mod $name { + static PIN_WAKERS: [super::AtomicWaker; $end - $start + 1] = + [const { super::AtomicWaker::new() }; $end - $start + 1]; + pub static WAKER: super::PortWaker = super::PortWaker { + offset: $start, + wakers: &PIN_WAKERS, + }; + } + }; +} + +// GPIO port 0 +define_port_waker!(port0_waker, 0, 31); +impl_pin!(PIO0_0, 0, 0); +impl_pin!(PIO0_1, 0, 1); +impl_pin!(PIO0_2, 0, 2); +impl_pin!(PIO0_3, 0, 3); +impl_pin!(PIO0_4, 0, 4); +impl_pin!(PIO0_5, 0, 5); +impl_pin!(PIO0_6, 0, 6); +impl_pin!(PIO0_7, 0, 7); +impl_pin!(PIO0_8, 0, 8); +impl_pin!(PIO0_9, 0, 9); +impl_pin!(PIO0_10, 0, 10); +impl_pin!(PIO0_11, 0, 11); +impl_pin!(PIO0_12, 0, 12); +impl_pin!(PIO0_13, 0, 13); +impl_pin!(PIO0_14, 0, 14); +impl_pin!(PIO0_15, 0, 15); +impl_pin!(PIO0_16, 0, 16); +impl_pin!(PIO0_17, 0, 17); +impl_pin!(PIO0_18, 0, 18); +impl_pin!(PIO0_19, 0, 19); +impl_pin!(PIO0_20, 0, 20); +impl_pin!(PIO0_21, 0, 21); +impl_pin!(PIO0_22, 0, 22); +impl_pin!(PIO0_23, 0, 23); +impl_pin!(PIO0_24, 0, 24); +impl_pin!(PIO0_25, 0, 25); +impl_pin!(PIO0_26, 0, 26); +impl_pin!(PIO0_27, 0, 27); +impl_pin!(PIO0_28, 0, 28); +impl_pin!(PIO0_29, 0, 29); +impl_pin!(PIO0_30, 0, 30); +impl_pin!(PIO0_31, 0, 31); + +// GPIO port 1 +define_port_waker!(port1_waker, 0, 31); +impl_pin!(PIO1_0, 1, 0); +impl_pin!(PIO1_1, 1, 1); +impl_pin!(PIO1_2, 1, 2); +impl_pin!(PIO1_3, 1, 3); +impl_pin!(PIO1_4, 1, 4); +impl_pin!(PIO1_5, 1, 5); +impl_pin!(PIO1_6, 1, 6); +impl_pin!(PIO1_7, 1, 7); +impl_pin!(PIO1_8, 1, 8); +impl_pin!(PIO1_9, 1, 9); +impl_pin!(PIO1_10, 1, 10); +impl_pin!(PIO1_11, 1, 11); +impl_pin!(PIO1_12, 1, 12); +impl_pin!(PIO1_13, 1, 13); +impl_pin!(PIO1_14, 1, 14); +impl_pin!(PIO1_15, 1, 15); +impl_pin!(PIO1_16, 1, 16); +impl_pin!(PIO1_17, 1, 17); +impl_pin!(PIO1_18, 1, 18); +impl_pin!(PIO1_19, 1, 19); +impl_pin!(PIO1_20, 1, 20); +impl_pin!(PIO1_21, 1, 21); +impl_pin!(PIO1_22, 1, 22); +impl_pin!(PIO1_23, 1, 23); +impl_pin!(PIO1_24, 1, 24); +impl_pin!(PIO1_25, 1, 25); +impl_pin!(PIO1_26, 1, 26); +impl_pin!(PIO1_27, 1, 27); +impl_pin!(PIO1_28, 1, 28); +impl_pin!(PIO1_29, 1, 29); +impl_pin!(PIO1_30, 1, 30); +impl_pin!(PIO1_31, 1, 31); + +// GPIO port 2 +define_port_waker!(port2_waker, 0, 31); +impl_pin!(PIO2_0, 2, 0); +impl_pin!(PIO2_1, 2, 1); +impl_pin!(PIO2_2, 2, 2); +impl_pin!(PIO2_3, 2, 3); +impl_pin!(PIO2_4, 2, 4); +impl_pin!(PIO2_5, 2, 5); +impl_pin!(PIO2_6, 2, 6); +impl_pin!(PIO2_7, 2, 7); +impl_pin!(PIO2_8, 2, 8); +impl_pin!(PIO2_9, 2, 9); +impl_pin!(PIO2_10, 2, 10); +impl_pin!(PIO2_11, 2, 11); +impl_pin!(PIO2_12, 2, 12); +impl_pin!(PIO2_13, 2, 13); +impl_pin!(PIO2_14, 2, 14); +impl_pin!(PIO2_15, 2, 15); +impl_pin!(PIO2_16, 2, 16); +impl_pin!(PIO2_17, 2, 17); +impl_pin!(PIO2_18, 2, 18); +impl_pin!(PIO2_19, 2, 19); +impl_pin!(PIO2_20, 2, 20); +impl_pin!(PIO2_21, 2, 21); +impl_pin!(PIO2_22, 2, 22); +impl_pin!(PIO2_23, 2, 23); +impl_pin!(PIO2_24, 2, 24); +impl_pin!(PIO2_25, 2, 25); +impl_pin!(PIO2_26, 2, 26); +impl_pin!(PIO2_27, 2, 27); +impl_pin!(PIO2_28, 2, 28); +impl_pin!(PIO2_29, 2, 29); +impl_pin!(PIO2_30, 2, 30); +impl_pin!(PIO2_31, 2, 31); + +// GPIO port 3 +define_port_waker!(port3_waker, 0, 31); +impl_pin!(PIO3_0, 3, 0); +impl_pin!(PIO3_1, 3, 1); +impl_pin!(PIO3_2, 3, 2); +impl_pin!(PIO3_3, 3, 3); +impl_pin!(PIO3_4, 3, 4); +impl_pin!(PIO3_5, 3, 5); +impl_pin!(PIO3_6, 3, 6); +impl_pin!(PIO3_7, 3, 7); +impl_pin!(PIO3_8, 3, 8); +impl_pin!(PIO3_9, 3, 9); +impl_pin!(PIO3_10, 3, 10); +impl_pin!(PIO3_11, 3, 11); +impl_pin!(PIO3_12, 3, 12); +impl_pin!(PIO3_13, 3, 13); +impl_pin!(PIO3_14, 3, 14); +impl_pin!(PIO3_15, 3, 15); +impl_pin!(PIO3_16, 3, 16); +impl_pin!(PIO3_17, 3, 17); +impl_pin!(PIO3_18, 3, 18); +impl_pin!(PIO3_19, 3, 19); +impl_pin!(PIO3_20, 3, 20); +impl_pin!(PIO3_21, 3, 21); +impl_pin!(PIO3_22, 3, 22); +impl_pin!(PIO3_23, 3, 23); +impl_pin!(PIO3_24, 3, 24); +impl_pin!(PIO3_25, 3, 25); +impl_pin!(PIO3_26, 3, 26); +impl_pin!(PIO3_27, 3, 27); +impl_pin!(PIO3_28, 3, 28); +impl_pin!(PIO3_29, 3, 29); +impl_pin!(PIO3_30, 3, 30); +impl_pin!(PIO3_31, 3, 31); + +// GPIO port 4 +define_port_waker!(port4_waker, 0, 10); +impl_pin!(PIO4_0, 4, 0); +impl_pin!(PIO4_1, 4, 1); +impl_pin!(PIO4_2, 4, 2); +impl_pin!(PIO4_3, 4, 3); +impl_pin!(PIO4_4, 4, 4); +impl_pin!(PIO4_5, 4, 5); +impl_pin!(PIO4_6, 4, 6); +impl_pin!(PIO4_7, 4, 7); +impl_pin!(PIO4_8, 4, 8); +impl_pin!(PIO4_9, 4, 9); +impl_pin!(PIO4_10, 4, 10); + +// GPIO port 7 +define_port_waker!(port7_waker, 24, 31); +impl_pin!(PIO7_24, 7, 24); +impl_pin!(PIO7_25, 7, 25); +impl_pin!(PIO7_26, 7, 26); +impl_pin!(PIO7_27, 7, 27); +impl_pin!(PIO7_28, 7, 28); +impl_pin!(PIO7_29, 7, 29); +impl_pin!(PIO7_30, 7, 30); +impl_pin!(PIO7_31, 7, 31); + +static GPIO_WAKERS: [Option<&PortWaker>; PORT_COUNT] = [ + Some(&port0_waker::WAKER), + Some(&port1_waker::WAKER), + Some(&port2_waker::WAKER), + Some(&port3_waker::WAKER), + Some(&port4_waker::WAKER), + None, + None, + Some(&port7_waker::WAKER), +]; + +impl embedded_hal_02::digital::v2::InputPin for Flex<'_, SenseEnabled> { + type Error = Infallible; + + #[inline] + fn is_high(&self) -> Result { + Ok(self.is_high()) + } + + #[inline] + fn is_low(&self) -> Result { + Ok(self.is_low()) + } +} + +impl embedded_hal_02::digital::v2::OutputPin for Flex<'_, S> { + type Error = Infallible; + + #[inline] + fn set_high(&mut self) -> Result<(), Self::Error> { + self.set_high(); + Ok(()) + } + + #[inline] + fn set_low(&mut self) -> Result<(), Self::Error> { + self.set_low(); + Ok(()) + } +} + +impl embedded_hal_02::digital::v2::StatefulOutputPin for Flex<'_, SenseEnabled> { + #[inline] + fn is_set_high(&self) -> Result { + Ok(self.is_set_high()) + } + + #[inline] + fn is_set_low(&self) -> Result { + Ok(self.is_set_low()) + } +} + +impl embedded_hal_02::digital::v2::ToggleableOutputPin for Flex<'_, S> { + type Error = Infallible; + + #[inline] + fn toggle(&mut self) -> Result<(), Self::Error> { + self.toggle(); + Ok(()) + } +} + +impl embedded_hal_02::digital::v2::InputPin for Input<'_> { + type Error = Infallible; + + #[inline] + fn is_high(&self) -> Result { + Ok(self.is_high()) + } + + #[inline] + fn is_low(&self) -> Result { + Ok(self.is_low()) + } +} + +impl embedded_hal_02::digital::v2::OutputPin for Output<'_> { + type Error = Infallible; + + #[inline] + fn set_high(&mut self) -> Result<(), Self::Error> { + self.set_high(); + Ok(()) + } + + #[inline] + fn set_low(&mut self) -> Result<(), Self::Error> { + self.set_low(); + Ok(()) + } +} + +impl embedded_hal_02::digital::v2::StatefulOutputPin for Output<'_> { + #[inline] + fn is_set_high(&self) -> Result { + Ok(self.is_set_high()) + } + + #[inline] + fn is_set_low(&self) -> Result { + Ok(self.is_set_low()) + } +} + +impl embedded_hal_02::digital::v2::ToggleableOutputPin for Output<'_> { + type Error = Infallible; + + #[inline] + fn toggle(&mut self) -> Result<(), Self::Error> { + self.toggle(); + Ok(()) + } +} + +impl embedded_hal_1::digital::ErrorType for Flex<'_, S> { + type Error = Infallible; +} + +impl embedded_hal_1::digital::InputPin for Flex<'_, SenseEnabled> { + #[inline] + fn is_high(&mut self) -> Result { + // Dereference of self is used here and a few other places to + // access the correct method (since different types/traits + // share method names) + Ok((*self).is_high()) + } + + #[inline] + fn is_low(&mut self) -> Result { + Ok((*self).is_low()) + } +} + +impl embedded_hal_1::digital::OutputPin for Flex<'_, S> { + #[inline] + fn set_high(&mut self) -> Result<(), Self::Error> { + self.set_high(); + Ok(()) + } + + #[inline] + fn set_low(&mut self) -> Result<(), Self::Error> { + self.set_low(); + Ok(()) + } +} + +impl embedded_hal_1::digital::StatefulOutputPin for Flex<'_, SenseEnabled> { + #[inline] + fn is_set_high(&mut self) -> Result { + Ok((*self).is_set_high()) + } + + #[inline] + fn is_set_low(&mut self) -> Result { + Ok((*self).is_set_low()) + } +} + +impl<'d> embedded_hal_async::digital::Wait for Flex<'d, SenseEnabled> { + #[inline] + async fn wait_for_high(&mut self) -> Result<(), Self::Error> { + self.wait_for_high().await; + Ok(()) + } + + #[inline] + async fn wait_for_low(&mut self) -> Result<(), Self::Error> { + self.wait_for_low().await; + Ok(()) + } + + #[inline] + async fn wait_for_rising_edge(&mut self) -> Result<(), Self::Error> { + self.wait_for_rising_edge().await; + Ok(()) + } + + #[inline] + async fn wait_for_falling_edge(&mut self) -> Result<(), Self::Error> { + self.wait_for_falling_edge().await; + Ok(()) + } + + #[inline] + async fn wait_for_any_edge(&mut self) -> Result<(), Self::Error> { + self.wait_for_any_edge().await; + Ok(()) + } +} + +impl embedded_hal_1::digital::ErrorType for Input<'_> { + type Error = Infallible; +} + +impl embedded_hal_1::digital::InputPin for Input<'_> { + #[inline] + fn is_high(&mut self) -> Result { + Ok((*self).is_high()) + } + + #[inline] + fn is_low(&mut self) -> Result { + Ok((*self).is_low()) + } +} + +impl<'d> embedded_hal_async::digital::Wait for Input<'d> { + #[inline] + async fn wait_for_high(&mut self) -> Result<(), Self::Error> { + self.wait_for_high().await; + Ok(()) + } + + #[inline] + async fn wait_for_low(&mut self) -> Result<(), Self::Error> { + self.wait_for_low().await; + Ok(()) + } + + #[inline] + async fn wait_for_rising_edge(&mut self) -> Result<(), Self::Error> { + self.wait_for_rising_edge().await; + Ok(()) + } + + #[inline] + async fn wait_for_falling_edge(&mut self) -> Result<(), Self::Error> { + self.wait_for_falling_edge().await; + Ok(()) + } + + #[inline] + async fn wait_for_any_edge(&mut self) -> Result<(), Self::Error> { + self.wait_for_any_edge().await; + Ok(()) + } +} + +impl embedded_hal_1::digital::ErrorType for Output<'_> { + type Error = Infallible; +} + +impl embedded_hal_1::digital::OutputPin for Output<'_> { + #[inline] + fn set_high(&mut self) -> Result<(), Self::Error> { + self.set_high(); + Ok(()) + } + + #[inline] + fn set_low(&mut self) -> Result<(), Self::Error> { + self.set_low(); + Ok(()) + } +} + +impl embedded_hal_1::digital::StatefulOutputPin for Output<'_> { + #[inline] + fn is_set_high(&mut self) -> Result { + Ok((*self).is_set_high()) + } + + #[inline] + fn is_set_low(&mut self) -> Result { + Ok((*self).is_set_low()) + } +} diff --git a/embassy-imxrt/src/iopctl.rs b/embassy-imxrt/src/iopctl.rs new file mode 100644 index 000000000..a3b8b14d6 --- /dev/null +++ b/embassy-imxrt/src/iopctl.rs @@ -0,0 +1,717 @@ +//! IO Pad Controller (IOPCTL) +//! +//! Also known as IO Pin Configuration (IOCON) + +use crate::pac::{iopctl, Iopctl}; + +// A generic pin of any type. +// +// The actual pin type used here is arbitrary, +// as all PioM_N types provide the same methods. +// +// Merely need some pin type to cast a raw pointer +// to in order to access the provided methods. +#[allow(non_camel_case_types)] +type PioM_N = iopctl::Pio0_0; + +/// Pin function number. +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum Function { + /// Function 0 + F0, + /// Function 1 + F1, + /// Function 2 + F2, + /// Function 3 + F3, + /// Function 4 + F4, + /// Function 5 + F5, + /// Function 6 + F6, + /// Function 7 + F7, + /// Function 8 + F8, +} + +/// Internal pull-up/down resistors on a pin. +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum Pull { + /// No pull-up or pull-down resistor selected + None, + /// Pull-up resistor + Up, + /// Pull-down resistor + Down, +} + +/// Pin slew rate. +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum SlewRate { + /// Standard slew rate + Standard, + /// Slow slew rate + Slow, +} + +/// Output drive strength of a pin. +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum DriveStrength { + /// Normal + Normal, + /// Full + Full, +} + +/// Output drive mode of a pin. +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum DriveMode { + /// Push-Pull + PushPull, + /// Pseudo Open-Drain + OpenDrain, +} + +/// Input inverter of a pin. +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum Inverter { + /// No inverter + Disabled, + /// Enable input inverter on the input port. A low signal will be + /// seen as a high signal by the pin. + Enabled, +} + +trait SealedPin {} +trait ToAnyPin: SealedPin { + #[inline] + fn to_raw(port: u8, pin: u8) -> AnyPin { + // SAFETY: This is safe since this is only called from within the module, + // where the port and pin numbers have been verified to be correct. + unsafe { AnyPin::steal(port, pin) } + } +} + +trait ToFC15Pin: SealedPin { + #[inline] + fn to_raw(pin: u8) -> FC15Pin { + // SAFETY: This is safe since this is only called from within the module, + // where the port and pin numbers have been verified to be correct. + unsafe { FC15Pin::steal(pin) } + } +} + +/// A pin that can be configured via iopctl. +#[allow(private_bounds)] +pub trait IopctlPin: SealedPin { + /// Sets the function number of a pin. + /// + /// This number corresponds to a specific function that the pin supports. + /// + /// Typically, function 0 corresponds to GPIO while other numbers correspond to a special function. + /// + /// See Section 7.5.3 in reference manual for list of pins and their supported functions. + fn set_function(&self, function: Function) -> &Self; + + /// Enables either a pull-up or pull-down resistor on a pin. + /// + /// Setting this to [`Pull::None`] will disable the resistor. + fn set_pull(&self, pull: Pull) -> &Self; + + /// Enables the input buffer of a pin. + /// + /// This must be enabled for any pin acting as an input, + /// and some peripheral pins acting as output may need this enabled as well. + /// + /// If there is any doubt, it is best to enable the input buffer. + /// + /// See Section 7.4.2.3 of reference manual. + fn enable_input_buffer(&self) -> &Self; + + /// Disables the input buffer of a pin. + fn disable_input_buffer(&self) -> &Self; + + /// Sets the slew rate of a pin. + /// + /// This controls the speed at which a pin can toggle, + /// which is voltage and load dependent. + fn set_slew_rate(&self, slew_rate: SlewRate) -> &Self; + + /// Sets the output drive strength of a pin. + /// + /// A drive strength of [`DriveStrength::Full`] has twice the + /// high and low drive capability of the [`DriveStrength::Normal`] setting. + fn set_drive_strength(&self, strength: DriveStrength) -> &Self; + + /// Enables the analog multiplexer of a pin. + /// + /// This must be called to allow analog functionalities of a pin. + /// + /// To protect the analog input, [`IopctlPin::set_function`] should be + /// called with [`Function::F0`] to disable digital functions. + /// + /// Additionally, [`IopctlPin::disable_input_buffer`] and [`IopctlPin::set_pull`] + /// with [`Pull::None`] should be called. + fn enable_analog_multiplex(&self) -> &Self; + + /// Disables the analog multiplexer of a pin. + fn disable_analog_multiplex(&self) -> &Self; + + /// Sets the ouput drive mode of a pin. + /// + /// A pin configured as [`DriveMode::OpenDrain`] actually operates in + /// a "pseudo" open-drain mode which is somewhat different than true open-drain. + /// + /// See Section 7.4.2.7 of reference manual. + fn set_drive_mode(&self, mode: DriveMode) -> &Self; + + /// Sets the input inverter of an input pin. + /// + /// Setting this to [`Inverter::Enabled`] will invert + /// the input signal. + fn set_input_inverter(&self, inverter: Inverter) -> &Self; + + /// Returns a pin to its reset state. + fn reset(&self) -> &Self; +} + +/// Represents a pin peripheral created at run-time from given port and pin numbers. +pub struct AnyPin { + pin_port: u8, + reg: &'static PioM_N, +} + +impl AnyPin { + /// Creates a pin from raw port and pin numbers which can then be configured. + /// + /// This should ONLY be called when there is no other choice + /// (e.g. from a type-erased GPIO pin). + /// + /// Otherwise, pin peripherals should be configured directly. + /// + /// # Safety + /// + /// The caller MUST ensure valid port and pin numbers are provided, + /// and that multiple instances of [`AnyPin`] with the same port + /// and pin combination are not being used simultaneously. + /// + /// Failure to uphold these requirements will result in undefined behavior. + /// + /// See Table 297 in reference manual for a list of valid + /// pin and port number combinations. + #[must_use] + pub unsafe fn steal(port: u8, pin: u8) -> Self { + // Calculates the offset from the beginning of the IOPCTL register block + // address to the register address representing the pin. + // + // See Table 297 in reference manual for how this offset is calculated. + let offset = ((port as usize) << 7) + ((pin as usize) << 2); + + // SAFETY: This is safe assuming the caller of this function satisfies the safety requirements above. + let reg = unsafe { &*Iopctl::ptr().byte_offset(offset as isize).cast() }; + Self { + pin_port: port * 32 + pin, + reg, + } + } + + /// Returns the pin's port and pin combination. + #[must_use] + pub fn pin_port(&self) -> usize { + self.pin_port as usize + } +} + +/// Represents a FC15 pin peripheral created at run-time from given pin number. +pub struct FC15Pin { + reg: &'static PioM_N, +} + +impl FC15Pin { + /// Creates an FC15 pin from raw pin number which can then be configured. + /// + /// This should ONLY be called when there is no other choice + /// (e.g. from a type-erased GPIO pin). + /// + /// Otherwise, pin peripherals should be configured directly. + /// + /// # Safety + /// + /// The caller MUST ensure valid port and pin numbers are provided, + /// and that multiple instances of [`AnyPin`] with the same port + /// and pin combination are not being used simultaneously. + /// + /// Failure to uphold these requirements will result in undefined behavior. + /// + /// See Table 297 in reference manual for a list of valid + /// pin and port number combinations. + #[must_use] + pub unsafe fn steal(pin: u8) -> Self { + // Table 297: FC15_I2C_SCL offset = 0x400, FC15_I2C_SCL offset = 0x404 + let iopctl = unsafe { crate::pac::Iopctl::steal() }; + + let reg = if pin == 0 { + &*iopctl.fc15_i2c_scl().as_ptr().cast() + } else { + &*iopctl.fc15_i2c_sda().as_ptr().cast() + }; + + Self { reg } + } +} + +// This allows AnyPin/FC15Pin to be used in HAL constructors that require types +// which impl Peripheral. Used primarily by GPIO HAL to convert type-erased +// GPIO pins back into an Output or Input pin specifically. +embassy_hal_internal::impl_peripheral!(AnyPin); + +impl SealedPin for AnyPin {} + +embassy_hal_internal::impl_peripheral!(FC15Pin); + +impl SealedPin for FC15Pin {} + +macro_rules! impl_iopctlpin { + ($pintype:ident) => { + impl IopctlPin for $pintype { + fn set_function(&self, function: Function) -> &Self { + critical_section::with(|_| match function { + Function::F0 => { + self.reg.modify(|_, w| w.fsel().function_0()); + } + Function::F1 => { + self.reg.modify(|_, w| w.fsel().function_1()); + } + Function::F2 => { + self.reg.modify(|_, w| w.fsel().function_2()); + } + Function::F3 => { + self.reg.modify(|_, w| w.fsel().function_3()); + } + Function::F4 => { + self.reg.modify(|_, w| w.fsel().function_4()); + } + Function::F5 => { + self.reg.modify(|_, w| w.fsel().function_5()); + } + Function::F6 => { + self.reg.modify(|_, w| w.fsel().function_6()); + } + Function::F7 => { + self.reg.modify(|_, w| w.fsel().function_7()); + } + Function::F8 => { + self.reg.modify(|_, w| w.fsel().function_8()); + } + }); + self + } + + fn set_pull(&self, pull: Pull) -> &Self { + critical_section::with(|_| { + match pull { + Pull::None => { + self.reg.modify(|_, w| w.pupdena().disabled()); + } + Pull::Up => { + self.reg.modify(|_, w| w.pupdena().enabled().pupdsel().pull_up()); + } + Pull::Down => { + self.reg + .modify(|_, w| w.pupdena().enabled().pupdsel().pull_down()); + } + } + self + }) + } + + fn enable_input_buffer(&self) -> &Self { + critical_section::with(|_| self.reg.modify(|_, w| w.ibena().enabled())); + self + } + + fn disable_input_buffer(&self) -> &Self { + critical_section::with(|_| self.reg.modify(|_, w| w.ibena().disabled())); + self + } + + fn set_slew_rate(&self, slew_rate: SlewRate) -> &Self { + critical_section::with(|_| match slew_rate { + SlewRate::Standard => { + self.reg.modify(|_, w| w.slewrate().normal()); + } + SlewRate::Slow => { + self.reg.modify(|_, w| w.slewrate().slow()); + } + }); + self + } + + fn set_drive_strength(&self, strength: DriveStrength) -> &Self { + critical_section::with(|_| match strength { + DriveStrength::Normal => { + self.reg.modify(|_, w| w.fulldrive().normal_drive()); + } + DriveStrength::Full => { + self.reg.modify(|_, w| w.fulldrive().full_drive()); + } + }); + self + } + + fn enable_analog_multiplex(&self) -> &Self { + critical_section::with(|_| self.reg.modify(|_, w| w.amena().enabled())); + self + } + + fn disable_analog_multiplex(&self) -> &Self { + critical_section::with(|_| self.reg.modify(|_, w| w.amena().disabled())); + self + } + + fn set_drive_mode(&self, mode: DriveMode) -> &Self { + critical_section::with(|_| match mode { + DriveMode::PushPull => { + self.reg.modify(|_, w| w.odena().disabled()); + } + DriveMode::OpenDrain => { + self.reg.modify(|_, w| w.odena().enabled()); + } + }); + self + } + + fn set_input_inverter(&self, inverter: Inverter) -> &Self { + critical_section::with(|_| match inverter { + Inverter::Disabled => { + self.reg.modify(|_, w| w.iiena().disabled()); + } + Inverter::Enabled => { + self.reg.modify(|_, w| w.iiena().enabled()); + } + }); + self + } + + fn reset(&self) -> &Self { + self.reg.reset(); + self + } + } + }; +} + +impl_iopctlpin!(AnyPin); +impl_iopctlpin!(FC15Pin); + +macro_rules! impl_FC15pin { + ($pin_periph:ident, $pin_no:expr) => { + impl SealedPin for crate::peripherals::$pin_periph {} + impl ToFC15Pin for crate::peripherals::$pin_periph {} + impl IopctlPin for crate::peripherals::$pin_periph { + #[inline] + fn set_function(&self, _function: Function) -> &Self { + //No function configuration for FC15 pin + self + } + + #[inline] + fn set_pull(&self, pull: Pull) -> &Self { + Self::to_raw($pin_no).set_pull(pull); + self + } + + #[inline] + fn enable_input_buffer(&self) -> &Self { + Self::to_raw($pin_no).enable_input_buffer(); + self + } + + #[inline] + fn disable_input_buffer(&self) -> &Self { + Self::to_raw($pin_no).disable_input_buffer(); + self + } + + #[inline] + fn set_slew_rate(&self, slew_rate: SlewRate) -> &Self { + Self::to_raw($pin_no).set_slew_rate(slew_rate); + self + } + + #[inline] + fn set_drive_strength(&self, strength: DriveStrength) -> &Self { + Self::to_raw($pin_no).set_drive_strength(strength); + self + } + + #[inline] + fn enable_analog_multiplex(&self) -> &Self { + Self::to_raw($pin_no).enable_analog_multiplex(); + self + } + + #[inline] + fn disable_analog_multiplex(&self) -> &Self { + Self::to_raw($pin_no).disable_analog_multiplex(); + self + } + + #[inline] + fn set_drive_mode(&self, mode: DriveMode) -> &Self { + Self::to_raw($pin_no).set_drive_mode(mode); + self + } + + #[inline] + fn set_input_inverter(&self, inverter: Inverter) -> &Self { + Self::to_raw($pin_no).set_input_inverter(inverter); + self + } + + #[inline] + fn reset(&self) -> &Self { + Self::to_raw($pin_no).reset(); + self + } + } + }; +} + +macro_rules! impl_pin { + ($pin_periph:ident, $pin_port:expr, $pin_no:expr) => { + impl SealedPin for crate::peripherals::$pin_periph {} + impl ToAnyPin for crate::peripherals::$pin_periph {} + impl IopctlPin for crate::peripherals::$pin_periph { + #[inline] + fn set_function(&self, function: Function) -> &Self { + Self::to_raw($pin_port, $pin_no).set_function(function); + self + } + + #[inline] + fn set_pull(&self, pull: Pull) -> &Self { + Self::to_raw($pin_port, $pin_no).set_pull(pull); + self + } + + #[inline] + fn enable_input_buffer(&self) -> &Self { + Self::to_raw($pin_port, $pin_no).enable_input_buffer(); + self + } + + #[inline] + fn disable_input_buffer(&self) -> &Self { + Self::to_raw($pin_port, $pin_no).disable_input_buffer(); + self + } + + #[inline] + fn set_slew_rate(&self, slew_rate: SlewRate) -> &Self { + Self::to_raw($pin_port, $pin_no).set_slew_rate(slew_rate); + self + } + + #[inline] + fn set_drive_strength(&self, strength: DriveStrength) -> &Self { + Self::to_raw($pin_port, $pin_no).set_drive_strength(strength); + self + } + + #[inline] + fn enable_analog_multiplex(&self) -> &Self { + Self::to_raw($pin_port, $pin_no).enable_analog_multiplex(); + self + } + + #[inline] + fn disable_analog_multiplex(&self) -> &Self { + Self::to_raw($pin_port, $pin_no).disable_analog_multiplex(); + self + } + + #[inline] + fn set_drive_mode(&self, mode: DriveMode) -> &Self { + Self::to_raw($pin_port, $pin_no).set_drive_mode(mode); + self + } + + #[inline] + fn set_input_inverter(&self, inverter: Inverter) -> &Self { + Self::to_raw($pin_port, $pin_no).set_input_inverter(inverter); + self + } + + #[inline] + fn reset(&self) -> &Self { + Self::to_raw($pin_port, $pin_no).reset(); + self + } + } + }; +} + +impl_pin!(PIO0_0, 0, 0); +impl_pin!(PIO0_1, 0, 1); +impl_pin!(PIO0_2, 0, 2); +impl_pin!(PIO0_3, 0, 3); +impl_pin!(PIO0_4, 0, 4); +impl_pin!(PIO0_5, 0, 5); +impl_pin!(PIO0_6, 0, 6); +impl_pin!(PIO0_7, 0, 7); +impl_pin!(PIO0_8, 0, 8); +impl_pin!(PIO0_9, 0, 9); +impl_pin!(PIO0_10, 0, 10); +impl_pin!(PIO0_11, 0, 11); +impl_pin!(PIO0_12, 0, 12); +impl_pin!(PIO0_13, 0, 13); +impl_pin!(PIO0_14, 0, 14); +impl_pin!(PIO0_15, 0, 15); +impl_pin!(PIO0_16, 0, 16); +impl_pin!(PIO0_17, 0, 17); +impl_pin!(PIO0_18, 0, 18); +impl_pin!(PIO0_19, 0, 19); +impl_pin!(PIO0_20, 0, 20); +impl_pin!(PIO0_21, 0, 21); +impl_pin!(PIO0_22, 0, 22); +impl_pin!(PIO0_23, 0, 23); +impl_pin!(PIO0_24, 0, 24); +impl_pin!(PIO0_25, 0, 25); +impl_pin!(PIO0_26, 0, 26); +impl_pin!(PIO0_27, 0, 27); +impl_pin!(PIO0_28, 0, 28); +impl_pin!(PIO0_29, 0, 29); +impl_pin!(PIO0_30, 0, 30); +impl_pin!(PIO0_31, 0, 31); +impl_pin!(PIO1_0, 1, 0); +impl_pin!(PIO1_1, 1, 1); +impl_pin!(PIO1_2, 1, 2); +impl_pin!(PIO1_3, 1, 3); +impl_pin!(PIO1_4, 1, 4); +impl_pin!(PIO1_5, 1, 5); +impl_pin!(PIO1_6, 1, 6); +impl_pin!(PIO1_7, 1, 7); +impl_pin!(PIO1_8, 1, 8); +impl_pin!(PIO1_9, 1, 9); +impl_pin!(PIO1_10, 1, 10); +impl_pin!(PIO1_11, 1, 11); +impl_pin!(PIO1_12, 1, 12); +impl_pin!(PIO1_13, 1, 13); +impl_pin!(PIO1_14, 1, 14); +impl_pin!(PIO1_15, 1, 15); +impl_pin!(PIO1_16, 1, 16); +impl_pin!(PIO1_17, 1, 17); +impl_pin!(PIO1_18, 1, 18); +impl_pin!(PIO1_19, 1, 19); +impl_pin!(PIO1_20, 1, 20); +impl_pin!(PIO1_21, 1, 21); +impl_pin!(PIO1_22, 1, 22); +impl_pin!(PIO1_23, 1, 23); +impl_pin!(PIO1_24, 1, 24); +impl_pin!(PIO1_25, 1, 25); +impl_pin!(PIO1_26, 1, 26); +impl_pin!(PIO1_27, 1, 27); +impl_pin!(PIO1_28, 1, 28); +impl_pin!(PIO1_29, 1, 29); +impl_pin!(PIO1_30, 1, 30); +impl_pin!(PIO1_31, 1, 31); +impl_pin!(PIO2_0, 2, 0); +impl_pin!(PIO2_1, 2, 1); +impl_pin!(PIO2_2, 2, 2); +impl_pin!(PIO2_3, 2, 3); +impl_pin!(PIO2_4, 2, 4); +impl_pin!(PIO2_5, 2, 5); +impl_pin!(PIO2_6, 2, 6); +impl_pin!(PIO2_7, 2, 7); +impl_pin!(PIO2_8, 2, 8); +impl_pin!(PIO2_9, 2, 9); +impl_pin!(PIO2_10, 2, 10); +impl_pin!(PIO2_11, 2, 11); +impl_pin!(PIO2_12, 2, 12); +impl_pin!(PIO2_13, 2, 13); +impl_pin!(PIO2_14, 2, 14); +impl_pin!(PIO2_15, 2, 15); +impl_pin!(PIO2_16, 2, 16); +impl_pin!(PIO2_17, 2, 17); +impl_pin!(PIO2_18, 2, 18); +impl_pin!(PIO2_19, 2, 19); +impl_pin!(PIO2_20, 2, 20); +impl_pin!(PIO2_21, 2, 21); +impl_pin!(PIO2_22, 2, 22); +impl_pin!(PIO2_23, 2, 23); +impl_pin!(PIO2_24, 2, 24); + +// Note: These have have reset values of 0x41 to support SWD by default +impl_pin!(PIO2_25, 2, 25); +impl_pin!(PIO2_26, 2, 26); + +impl_pin!(PIO2_27, 2, 27); +impl_pin!(PIO2_28, 2, 28); +impl_pin!(PIO2_29, 2, 29); +impl_pin!(PIO2_30, 2, 30); +impl_pin!(PIO2_31, 2, 31); +impl_pin!(PIO3_0, 3, 0); +impl_pin!(PIO3_1, 3, 1); +impl_pin!(PIO3_2, 3, 2); +impl_pin!(PIO3_3, 3, 3); +impl_pin!(PIO3_4, 3, 4); +impl_pin!(PIO3_5, 3, 5); +impl_pin!(PIO3_6, 3, 6); +impl_pin!(PIO3_7, 3, 7); +impl_pin!(PIO3_8, 3, 8); +impl_pin!(PIO3_9, 3, 9); +impl_pin!(PIO3_10, 3, 10); +impl_pin!(PIO3_11, 3, 11); +impl_pin!(PIO3_12, 3, 12); +impl_pin!(PIO3_13, 3, 13); +impl_pin!(PIO3_14, 3, 14); +impl_pin!(PIO3_15, 3, 15); +impl_pin!(PIO3_16, 3, 16); +impl_pin!(PIO3_17, 3, 17); +impl_pin!(PIO3_18, 3, 18); +impl_pin!(PIO3_19, 3, 19); +impl_pin!(PIO3_20, 3, 20); +impl_pin!(PIO3_21, 3, 21); +impl_pin!(PIO3_22, 3, 22); +impl_pin!(PIO3_23, 3, 23); +impl_pin!(PIO3_24, 3, 24); +impl_pin!(PIO3_25, 3, 25); +impl_pin!(PIO3_26, 3, 26); +impl_pin!(PIO3_27, 3, 27); +impl_pin!(PIO3_28, 3, 28); +impl_pin!(PIO3_29, 3, 29); +impl_pin!(PIO3_30, 3, 30); +impl_pin!(PIO3_31, 3, 31); +impl_pin!(PIO4_0, 4, 0); +impl_pin!(PIO4_1, 4, 1); +impl_pin!(PIO4_2, 4, 2); +impl_pin!(PIO4_3, 4, 3); +impl_pin!(PIO4_4, 4, 4); +impl_pin!(PIO4_5, 4, 5); +impl_pin!(PIO4_6, 4, 6); +impl_pin!(PIO4_7, 4, 7); +impl_pin!(PIO4_8, 4, 8); +impl_pin!(PIO4_9, 4, 9); +impl_pin!(PIO4_10, 4, 10); +impl_pin!(PIO7_24, 7, 24); +impl_pin!(PIO7_25, 7, 25); +impl_pin!(PIO7_26, 7, 26); +impl_pin!(PIO7_27, 7, 27); +impl_pin!(PIO7_28, 7, 28); +impl_pin!(PIO7_29, 7, 29); +impl_pin!(PIO7_30, 7, 30); +impl_pin!(PIO7_31, 7, 31); + +// FC15 pins +impl_FC15pin!(PIOFC15_SCL, 0); +impl_FC15pin!(PIOFC15_SDA, 1); diff --git a/embassy-imxrt/src/lib.rs b/embassy-imxrt/src/lib.rs new file mode 100644 index 000000000..d56d993c3 --- /dev/null +++ b/embassy-imxrt/src/lib.rs @@ -0,0 +1,130 @@ +#![no_std] +#![allow(async_fn_in_trait)] +#![doc = include_str!("../README.md")] +#![warn(missing_docs)] + +//! ## Feature flags +#![doc = document_features::document_features!(feature_label = r#"{feature}"#)] + +#[cfg(not(any(feature = "mimxrt633s", feature = "mimxrt685s",)))] +compile_error!( + "No chip feature activated. You must activate exactly one of the following features: + mimxrt633s, + mimxrt685s, + " +); + +// This mod MUST go first, so that the others see its macros. +pub(crate) mod fmt; + +pub mod clocks; +pub mod gpio; +pub mod iopctl; + +// This mod MUST go last, so that it sees all the `impl_foo!' macros +#[cfg_attr(feature = "mimxrt633s", path = "chips/mimxrt633s.rs")] +#[cfg_attr(feature = "mimxrt685s", path = "chips/mimxrt685s.rs")] +mod chip; + +// Reexports +pub use chip::interrupts::*; +#[cfg(feature = "unstable-pac")] +pub use chip::pac; +#[cfg(not(feature = "unstable-pac"))] +pub(crate) use chip::pac; +pub use chip::{peripherals, Peripherals}; +pub use embassy_hal_internal::{Peri, PeripheralType}; + +#[cfg(feature = "rt")] +pub use crate::pac::NVIC_PRIO_BITS; + +/// Macro to bind interrupts to handlers. +/// +/// This defines the right interrupt handlers, and creates a unit struct (like `struct Irqs;`) +/// and implements the right \[`Binding`\]s for it. You can pass this struct to drivers to +/// prove at compile-time that the right interrupts have been bound. +/// +/// Example of how to bind one interrupt: +/// +/// ```rust,ignore +/// use embassy_imxrt::{bind_interrupts, flexspi, peripherals}; +/// +/// bind_interrupts!(struct Irqs { +/// FLEXSPI_IRQ => flexspi::InterruptHandler; +/// }); +/// ``` +/// +// developer note: this macro can't be in `embassy-hal-internal` due to the use of `$crate`. +#[macro_export] +macro_rules! bind_interrupts { + ($vis:vis struct $name:ident { $($irq:ident => $($handler:ty),*;)* }) => { + #[derive(Copy, Clone)] + $vis struct $name; + + $( + #[allow(non_snake_case)] + #[no_mangle] + unsafe extern "C" fn $irq() { + $( + <$handler as $crate::interrupt::typelevel::Handler<$crate::interrupt::typelevel::$irq>>::on_interrupt(); + )* + } + + $( + unsafe impl $crate::interrupt::typelevel::Binding<$crate::interrupt::typelevel::$irq, $handler> for $name {} + )* + )* + }; +} + +/// HAL configuration for iMX RT600. +pub mod config { + use crate::clocks::ClockConfig; + + /// HAL configuration passed when initializing. + #[non_exhaustive] + pub struct Config { + /// Clock configuration. + pub clocks: ClockConfig, + } + + impl Default for Config { + fn default() -> Self { + Self { + clocks: ClockConfig::crystal(), + } + } + } + + impl Config { + /// Create a new configuration with the provided clock config. + pub fn new(clocks: ClockConfig) -> Self { + Self { clocks } + } + } +} + +/// Initialize the `embassy-imxrt` HAL with the provided configuration. +/// +/// This returns the peripheral singletons that can be used for creating drivers. +/// +/// This should only be called once at startup, otherwise it panics. +pub fn init(config: config::Config) -> Peripherals { + // Do this first, so that it panics if user is calling `init` a second time + // before doing anything important. + let peripherals = Peripherals::take(); + + unsafe { + if let Err(e) = clocks::init(config.clocks) { + error!("unable to initialize Clocks for reason: {:?}", e); + // Panic here? + } + gpio::init(); + } + + peripherals +} + +pub(crate) mod sealed { + pub trait Sealed {} +} diff --git a/examples/mimxrt6/.cargo/config.toml b/examples/mimxrt6/.cargo/config.toml new file mode 100644 index 000000000..db42be81d --- /dev/null +++ b/examples/mimxrt6/.cargo/config.toml @@ -0,0 +1,17 @@ +[target.thumbv8m.main-none-eabihf] +runner = 'probe-rs run --chip MIMXRT685SFVKB' + +rustflags = [ + "-C", "linker=flip-link", + "-C", "link-arg=-Tlink.x", + "-C", "link-arg=-Tdefmt.x", + # This is needed if your flash or ram addresses are not aligned to 0x10000 in memory.x + # See https://github.com/rust-embedded/cortex-m-quickstart/pull/95 + "-C", "link-arg=--nmagic", +] + +[build] +target = "thumbv8m.main-none-eabihf" # Cortex-M33 + +[env] +DEFMT_LOG = "trace" diff --git a/examples/mimxrt6/.gitignore b/examples/mimxrt6/.gitignore new file mode 100644 index 000000000..418e01907 --- /dev/null +++ b/examples/mimxrt6/.gitignore @@ -0,0 +1,14 @@ +# Generated by Cargo +# will have compiled files and executables +/debug +/target + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html +Cargo.lock + +# These are backup files generated by rustfmt +**/*.rs.bk + +# MSVC Windows builds of rustc generate these, which store debugging information +*.pdb diff --git a/examples/mimxrt6/Cargo.toml b/examples/mimxrt6/Cargo.toml new file mode 100644 index 000000000..894ce174c --- /dev/null +++ b/examples/mimxrt6/Cargo.toml @@ -0,0 +1,60 @@ +[package] +name = "embassy-imxrt-examples" +version = "0.1.0" +edition = "2021" +license = "MIT or Apache-2.0" + +[dependencies] +cortex-m = { version = "0.7.7", features = ["inline-asm", "critical-section-single-core"] } +cortex-m-rt = "0.7.3" +defmt = "1.0" +defmt-rtt = "1.0" + +embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } +embassy-futures = { version = "0.1.1", path = "../../embassy-futures" } +embassy-imxrt = { version = "0.1.0", path = "../../embassy-imxrt", features = ["defmt", "mimxrt685s", "unstable-pac"] } +embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } +embedded-hal-1 = { package = "embedded-hal", version = "1.0" } +embedded-hal-async = "1.0.0" + +mimxrt600-fcb = "0.1.0" +panic-probe = { version = "0.3", features = ["print-defmt"] } +rand = { version = "0.8.5", default-features = false } + +# cargo build/run +[profile.dev] +codegen-units = 1 +debug = 2 +debug-assertions = true # <- +incremental = false +opt-level = 3 # <- +overflow-checks = true # <- + +# cargo test +[profile.test] +codegen-units = 1 +debug = 2 +debug-assertions = true # <- +incremental = false +opt-level = 3 # <- +overflow-checks = true # <- + +# cargo build/run --release +[profile.release] +codegen-units = 1 +debug = 2 +debug-assertions = false # <- +incremental = false +lto = 'fat' +opt-level = 3 # <- +overflow-checks = false # <- + +# cargo test --release +[profile.bench] +codegen-units = 1 +debug = 2 +debug-assertions = false # <- +incremental = false +lto = 'fat' +opt-level = 3 # <- +overflow-checks = false # <- diff --git a/examples/mimxrt6/README.md b/examples/mimxrt6/README.md new file mode 100644 index 000000000..6d5031cf9 --- /dev/null +++ b/examples/mimxrt6/README.md @@ -0,0 +1,18 @@ +# embassy-imxrt-examples + +## Introduction + +These examples illustrates how to use the embassy-imxrt HAL. + +## Adding Examples +Add uniquely named example to `src/bin` like `adc.rs` + +## Build +`cd` to examples folder +`cargo build --bin ` for example, `cargo build --bin adc` + +## Run +Assuming RT685 is powered and connected to Jlink debug probe and the latest probe-rs is installed via + `$ cargo install probe-rs-tools --git https://github.com/probe-rs/probe-rs --locked` +`cd` to examples folder +`cargo run --bin ` for example, `cargo run --bin adc` \ No newline at end of file diff --git a/examples/mimxrt6/build.rs b/examples/mimxrt6/build.rs new file mode 100644 index 000000000..9c0ed3213 --- /dev/null +++ b/examples/mimxrt6/build.rs @@ -0,0 +1,45 @@ +use std::env; +use std::fs::File; +use std::io::Write; +use std::path::PathBuf; + +fn main() { + // Put `memory.x` in our output directory and ensure it's + // on the linker search path. + let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); + File::create(out.join("memory.x")) + .unwrap() + .write_all(include_bytes!("memory.x")) + .unwrap(); + println!("cargo:rustc-link-search={}", out.display()); + + // By default, Cargo will re-run a build script whenever + // any file in the project changes. By specifying `memory.x` + // here, we ensure the build script is only re-run when + // `memory.x` is changed. + println!("cargo:rerun-if-changed=memory.x"); + + // Inject crate version into the .biv section. + File::create(out.join("biv.rs")) + .unwrap() + .write_all( + format!( + r##" +#[link_section = ".biv"] +#[used] +static BOOT_IMAGE_VERSION: u32 = 0x{:02x}{:02x}{:02x}00; +"##, + env!("CARGO_PKG_VERSION_MAJOR") + .parse::() + .expect("should have major version"), + env!("CARGO_PKG_VERSION_MINOR") + .parse::() + .expect("should have minor version"), + env!("CARGO_PKG_VERSION_PATCH") + .parse::() + .expect("should have patch version"), + ) + .as_bytes(), + ) + .unwrap(); +} diff --git a/examples/mimxrt6/memory.x b/examples/mimxrt6/memory.x new file mode 100644 index 000000000..5ea82fd71 --- /dev/null +++ b/examples/mimxrt6/memory.x @@ -0,0 +1,34 @@ +MEMORY { + OTFAD : ORIGIN = 0x08000000, LENGTH = 256 + FCB : ORIGIN = 0x08000400, LENGTH = 512 + BIV : ORIGIN = 0x08000600, LENGTH = 4 + KEYSTORE : ORIGIN = 0x08000800, LENGTH = 2K + FLASH : ORIGIN = 0x08001000, LENGTH = 1M + RAM : ORIGIN = 0x20080000, LENGTH = 1536K +} + +SECTIONS { + .otfad : { + . = ALIGN(4); + KEEP(* (.otfad)) + . = ALIGN(4); + } > OTFAD + + .fcb : { + . = ALIGN(4); + KEEP(* (.fcb)) + . = ALIGN(4); + } > FCB + + .biv : { + . = ALIGN(4); + KEEP(* (.biv)) + . = ALIGN(4); + } > BIV + + .keystore : { + . = ALIGN(4); + KEEP(* (.keystore)) + . = ALIGN(4); + } > KEYSTORE +} diff --git a/examples/mimxrt6/src/bin/blinky.rs b/examples/mimxrt6/src/bin/blinky.rs new file mode 100644 index 000000000..e40e71e6f --- /dev/null +++ b/examples/mimxrt6/src/bin/blinky.rs @@ -0,0 +1,29 @@ +#![no_std] +#![no_main] + +extern crate embassy_imxrt_examples; + +use defmt::info; +use embassy_executor::Spawner; +use embassy_imxrt::gpio; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_imxrt::init(Default::default()); + + info!("Initializing GPIO"); + + let mut led = gpio::Output::new( + p.PIO0_26, + gpio::Level::Low, + gpio::DriveMode::PushPull, + gpio::DriveStrength::Normal, + gpio::SlewRate::Standard, + ); + + loop { + info!("Toggling LED"); + led.toggle(); + cortex_m::asm::delay(5_000_000); + } +} diff --git a/examples/mimxrt6/src/bin/hello.rs b/examples/mimxrt6/src/bin/hello.rs new file mode 100644 index 000000000..c640241ce --- /dev/null +++ b/examples/mimxrt6/src/bin/hello.rs @@ -0,0 +1,17 @@ +#![no_std] +#![no_main] + +extern crate embassy_imxrt_examples; + +use defmt::info; +use embassy_executor::Spawner; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) -> ! { + let _p = embassy_imxrt::init(Default::default()); + loop { + info!("Hello"); + cortex_m::asm::delay(5_000_000); + } +} diff --git a/examples/mimxrt6/src/lib.rs b/examples/mimxrt6/src/lib.rs new file mode 100644 index 000000000..da6e14427 --- /dev/null +++ b/examples/mimxrt6/src/lib.rs @@ -0,0 +1,20 @@ +#![no_std] + +use mimxrt600_fcb::FlexSPIFlashConfigurationBlock; +use {defmt_rtt as _, panic_probe as _}; + +// auto-generated version information from Cargo.toml +include!(concat!(env!("OUT_DIR"), "/biv.rs")); + +#[link_section = ".otfad"] +#[used] +static OTFAD: [u8; 256] = [0; 256]; + +#[rustfmt::skip] +#[link_section = ".fcb"] +#[used] +static FCB: FlexSPIFlashConfigurationBlock = FlexSPIFlashConfigurationBlock::build(); + +#[link_section = ".keystore"] +#[used] +static KEYSTORE: [u8; 2048] = [0; 2048]; From a78707b779e10e6ed9ee5228de425836c97b3373 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 9 Apr 2025 13:15:02 -0700 Subject: [PATCH 0948/1217] Add Embassy iMXRT RTC Time Driver --- ci.sh | 4 +- embassy-imxrt/Cargo.toml | 15 +- embassy-imxrt/src/lib.rs | 19 ++- embassy-imxrt/src/rtc.rs | 254 +++++++++++++++++++++++++++++ examples/mimxrt6/Cargo.toml | 3 +- examples/mimxrt6/src/bin/blinky.rs | 3 +- 6 files changed, 291 insertions(+), 7 deletions(-) create mode 100644 embassy-imxrt/src/rtc.rs diff --git a/ci.sh b/ci.sh index f08c38b7c..edc9bd617 100755 --- a/ci.sh +++ b/ci.sh @@ -53,8 +53,8 @@ cargo batch \ --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,proto-ipv6,medium-ip \ --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,proto-ipv6,medium-ip,medium-ethernet \ --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,proto-ipv6,medium-ip,medium-ethernet,medium-ieee802154 \ - --- build --release --manifest-path embassy-imxrt/Cargo.toml --target thumbv8m.main-none-eabihf --features mimxrt633s,defmt,unstable-pac \ - --- build --release --manifest-path embassy-imxrt/Cargo.toml --target thumbv8m.main-none-eabihf --features mimxrt685s,defmt,unstable-pac \ + --- build --release --manifest-path embassy-imxrt/Cargo.toml --target thumbv8m.main-none-eabihf --features mimxrt633s,defmt,unstable-pac,time,time-driver-rtc \ + --- build --release --manifest-path embassy-imxrt/Cargo.toml --target thumbv8m.main-none-eabihf --features mimxrt685s,defmt,unstable-pac,time,time-driver-rtc \ --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv6m-none-eabi --features nrf51,gpiote,time,time-driver-rtc1 \ --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52805,gpiote,time,time-driver-rtc1 \ --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52810,gpiote,time,time-driver-rtc1 \ diff --git a/embassy-imxrt/Cargo.toml b/embassy-imxrt/Cargo.toml index 38087bf77..d58de6353 100644 --- a/embassy-imxrt/Cargo.toml +++ b/embassy-imxrt/Cargo.toml @@ -12,13 +12,13 @@ documentation = "https://docs.embassy.dev/embassy-imxrt" [package.metadata.embassy_docs] src_base = "https://github.com/embassy-rs/embassy/blob/embassy-imxrt-v$VERSION/embassy-imxrt/src/" src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-imxrt/src/" -features = ["defmt", "unstable-pac"] +features = ["defmt", "unstable-pac", "time", "time-driver"] flavors = [ { regex_feature = "mimxrt6.*", target = "thumbv8m.main-none-eabihf" } ] [package.metadata.docs.rs] -features = ["mimxrt685s", "defmt", "unstable-pac"] +features = ["mimxrt685s", "defmt", "unstable-pac", "time", "time-driver"] rustdoc-args = ["--cfg", "docsrs"] [features] @@ -33,6 +33,14 @@ rt = [ ## Enable defmt defmt = ["dep:defmt", "embassy-hal-internal/defmt", "embassy-sync/defmt", "mimxrt685s-pac?/defmt", "mimxrt633s-pac?/defmt"] +## Enable features requiring `embassy-time` +time = ["dep:embassy-time", "embassy-embedded-hal/time"] + +## Enable custom embassy time-driver implementation, using 32KHz RTC +time-driver-rtc = ["_time-driver"] + +_time-driver = ["dep:embassy-time-driver", "embassy-time-driver?/tick-hz-1_000", "dep:embassy-time-queue-utils", "embassy-embedded-hal/time"] + ## Reexport the PAC for the currently enabled chip at `embassy_imxrt::pac` (unstable) unstable-pac = [] @@ -53,6 +61,9 @@ mimxrt633s = ["mimxrt633s-pac", "_mimxrt633s"] [dependencies] embassy-sync = { version = "0.6.2", path = "../embassy-sync" } +embassy-time-driver = { version = "0.2", path = "../embassy-time-driver", optional = true } +embassy-time-queue-utils = { version = "0.1", path = "../embassy-time-queue-utils", optional = true } +embassy-time = { version = "0.4", path = "../embassy-time", optional = true } embassy-hal-internal = { version = "0.2.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-3"] } embassy-embedded-hal = { version = "0.3.0", path = "../embassy-embedded-hal", default-features = false } embassy-futures = { version = "0.1.1", path = "../embassy-futures" } diff --git a/embassy-imxrt/src/lib.rs b/embassy-imxrt/src/lib.rs index d56d993c3..5fbf3244b 100644 --- a/embassy-imxrt/src/lib.rs +++ b/embassy-imxrt/src/lib.rs @@ -21,6 +21,9 @@ pub mod clocks; pub mod gpio; pub mod iopctl; +#[cfg(feature = "_time-driver")] +pub mod rtc; + // This mod MUST go last, so that it sees all the `impl_foo!' macros #[cfg_attr(feature = "mimxrt633s", path = "chips/mimxrt633s.rs")] #[cfg_attr(feature = "mimxrt685s", path = "chips/mimxrt685s.rs")] @@ -86,12 +89,18 @@ pub mod config { pub struct Config { /// Clock configuration. pub clocks: ClockConfig, + + /// RTC Time driver interrupt priority. + #[cfg(feature = "_time-driver")] + pub time_interrupt_priority: crate::interrupt::Priority, } impl Default for Config { fn default() -> Self { Self { clocks: ClockConfig::crystal(), + #[cfg(feature = "_time-driver")] + time_interrupt_priority: crate::interrupt::Priority::P0, } } } @@ -99,7 +108,11 @@ pub mod config { impl Config { /// Create a new configuration with the provided clock config. pub fn new(clocks: ClockConfig) -> Self { - Self { clocks } + Self { + clocks, + #[cfg(feature = "_time-driver")] + time_interrupt_priority: crate::interrupt::Priority::P0, + } } } } @@ -122,6 +135,10 @@ pub fn init(config: config::Config) -> Peripherals { gpio::init(); } + // init RTC time driver + #[cfg(feature = "_time-driver")] + rtc::init(config.time_interrupt_priority); + peripherals } diff --git a/embassy-imxrt/src/rtc.rs b/embassy-imxrt/src/rtc.rs new file mode 100644 index 000000000..56a8f7397 --- /dev/null +++ b/embassy-imxrt/src/rtc.rs @@ -0,0 +1,254 @@ +//! RTC Time Driver. +use core::cell::{Cell, RefCell}; +use core::sync::atomic::{compiler_fence, AtomicU32, Ordering}; + +use critical_section::CriticalSection; +use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; +use embassy_sync::blocking_mutex::Mutex; +use embassy_time_driver::Driver; +use embassy_time_queue_utils::Queue; + +use crate::interrupt::InterruptExt; +use crate::{interrupt, pac}; + +fn rtc() -> &'static pac::rtc::RegisterBlock { + unsafe { &*pac::Rtc::ptr() } +} + +/// Calculate the timestamp from the period count and the tick count. +/// +/// To get `now()`, `period` is read first, then `counter` is read. If the counter value matches +/// the expected range for the `period` parity, we're done. If it doesn't, this means that +/// a new period start has raced us between reading `period` and `counter`, so we assume the `counter` value +/// corresponds to the next period. +/// +/// the 1kHz RTC counter is 16 bits and RTC doesn't have separate compare channels, +/// so using a 32 bit GPREG0-2 as counter, compare, and int_en +/// `period` is a 32bit integer, gpreg 'counter' is 31 bits plus the parity bit for overflow detection +fn calc_now(period: u32, counter: u32) -> u64 { + ((period as u64) << 31) + ((counter ^ ((period & 1) << 31)) as u64) +} + +struct AlarmState { + timestamp: Cell, +} + +unsafe impl Send for AlarmState {} + +impl AlarmState { + const fn new() -> Self { + Self { + timestamp: Cell::new(u64::MAX), + } + } +} + +struct Rtc { + /// Number of 2^31 periods elapsed since boot. + period: AtomicU32, + /// Timestamp at which to fire alarm. u64::MAX if no alarm is scheduled. + alarms: Mutex, + queue: Mutex>, +} + +embassy_time_driver::time_driver_impl!(static DRIVER: Rtc = Rtc { + period: AtomicU32::new(0), + alarms: Mutex::const_new(CriticalSectionRawMutex::new(), AlarmState::new()), + queue: Mutex::new(RefCell::new(Queue::new())), +}); + +impl Rtc { + /// Access the GPREG0 register to use it as a 31-bit counter. + #[inline] + fn counter_reg(&self) -> &pac::rtc::Gpreg { + rtc().gpreg(0) + } + + /// Access the GPREG1 register to use it as a compare register for triggering alarms. + #[inline] + fn compare_reg(&self) -> &pac::rtc::Gpreg { + rtc().gpreg(1) + } + + /// Access the GPREG2 register to use it to enable or disable interrupts (int_en). + #[inline] + fn int_en_reg(&self) -> &pac::rtc::Gpreg { + rtc().gpreg(2) + } + + fn init(&'static self, irq_prio: crate::interrupt::Priority) { + let r = rtc(); + // enable RTC int (1kHz since subsecond doesn't generate an int) + r.ctrl().modify(|_r, w| w.rtc1khz_en().set_bit()); + // TODO: low power support. line above is leaving out write to .wakedpd_en().set_bit()) + // which enables wake from deep power down + + // safety: Writing to the gregs is always considered unsafe, gpreg1 is used + // as a compare register for triggering an alarm so to avoid unnecessary triggers + // after initialization, this is set to 0x:FFFF_FFFF + self.compare_reg().write(|w| unsafe { w.gpdata().bits(u32::MAX) }); + // safety: writing a value to the 1kHz RTC wake counter is always considered unsafe. + // The following loads 10 into the count-down timer. + r.wake().write(|w| unsafe { w.bits(0xA) }); + interrupt::RTC.set_priority(irq_prio); + unsafe { interrupt::RTC.enable() }; + } + + #[cfg(feature = "rt")] + fn on_interrupt(&self) { + let r = rtc(); + // This interrupt fires every 10 ticks of the 1kHz RTC high res clk and adds + // 10 to the 31 bit counter gpreg0. The 32nd bit is used for parity detection + // This is done to avoid needing to calculate # of ticks spent on interrupt + // handlers to recalibrate the clock between interrupts + // + // TODO: this is admittedly not great for power that we're generating this + // many interrupts, will probably get updated in future iterations. + if r.ctrl().read().wake1khz().bit_is_set() { + r.ctrl().modify(|_r, w| w.wake1khz().set_bit()); + // safety: writing a value to the 1kHz RTC wake counter is always considered unsafe. + // The following reloads 10 into the count-down timer after it triggers an int. + // The countdown begins anew after the write so time can continue to be measured. + r.wake().write(|w| unsafe { w.bits(0xA) }); + if (self.counter_reg().read().bits() + 0xA) > 0x8000_0000 { + // if we're going to "overflow", increase the period + self.next_period(); + let rollover_diff = 0x8000_0000 - (self.counter_reg().read().bits() + 0xA); + // safety: writing to gpregs is always considered unsafe. In order to + // not "lose" time when incrementing the period, gpreg0, the extended + // counter, is restarted at the # of ticks it would overflow by + self.counter_reg().write(|w| unsafe { w.bits(rollover_diff) }); + } else { + self.counter_reg().modify(|r, w| unsafe { w.bits(r.bits() + 0xA) }); + } + } + + critical_section::with(|cs| { + // gpreg2 as an "int_en" set by next_period(). This is + // 1 when the timestamp for the alarm deadline expires + // before the counter register overflows again. + if self.int_en_reg().read().gpdata().bits() == 1 { + // gpreg0 is our extended counter register, check if + // our counter is larger than the compare value + if self.counter_reg().read().bits() > self.compare_reg().read().bits() { + self.trigger_alarm(cs); + } + } + }) + } + + #[cfg(feature = "rt")] + fn next_period(&self) { + critical_section::with(|cs| { + let period = self + .period + .fetch_update(Ordering::Relaxed, Ordering::Relaxed, |p| Some(p + 1)) + .unwrap_or_else(|p| { + trace!("Unable to increment period. Time is now inaccurate"); + // TODO: additional error handling beyond logging + + p + }); + let t = (period as u64) << 31; + + let alarm = &self.alarms.borrow(cs); + let at = alarm.timestamp.get(); + if at < t + 0xc000_0000 { + // safety: writing to gpregs is always unsafe, gpreg2 is an alarm + // enable. If the alarm must trigger within the next period, then + // just enable it. `set_alarm` has already set the correct CC val. + self.int_en_reg().write(|w| unsafe { w.gpdata().bits(1) }); + } + }) + } + + #[must_use] + fn set_alarm(&self, cs: CriticalSection, timestamp: u64) -> bool { + let alarm = self.alarms.borrow(cs); + alarm.timestamp.set(timestamp); + + let t = self.now(); + if timestamp <= t { + // safety: Writing to the gpregs is always unsafe, gpreg2 is + // always just used as the alarm enable for the timer driver. + // If alarm timestamp has passed the alarm will not fire. + // Disarm the alarm and return `false` to indicate that. + self.int_en_reg().write(|w| unsafe { w.gpdata().bits(0) }); + + alarm.timestamp.set(u64::MAX); + + return false; + } + + // If it hasn't triggered yet, setup it by writing to the compare field + // An alarm can be delayed, but this is allowed by the Alarm trait contract. + // What's not allowed is triggering alarms *before* their scheduled time, + let safe_timestamp = timestamp.max(t + 10); //t+3 was done for nrf chip, choosing 10 + + // safety: writing to the gregs is always unsafe. When a new alarm is set, + // the compare register, gpreg1, is set to the last 31 bits of the timestamp + // as the 32nd and final bit is used for the parity check in `next_period` + // `period` will be used for the upper bits in a timestamp comparison. + self.compare_reg() + .modify(|_r, w| unsafe { w.bits(safe_timestamp as u32 & 0x7FFF_FFFF) }); + + // The following checks that the difference in timestamp is less than the overflow period + let diff = timestamp - t; + if diff < 0xc000_0000 { + // this is 0b11 << (30). NRF chip used 23 bit periods and checked against 0b11<<22 + + // safety: writing to the gpregs is always unsafe. If the alarm + // must trigger within the next period, set the "int enable" + self.int_en_reg().write(|w| unsafe { w.gpdata().bits(1) }); + } else { + // safety: writing to the gpregs is always unsafe. If alarm must trigger + // some time after the current period, too far in the future, don't setup + // the alarm enable, gpreg2, yet. It will be setup later by `next_period`. + self.int_en_reg().write(|w| unsafe { w.gpdata().bits(0) }); + } + + true + } + + #[cfg(feature = "rt")] + fn trigger_alarm(&self, cs: CriticalSection) { + let mut next = self.queue.borrow(cs).borrow_mut().next_expiration(self.now()); + while !self.set_alarm(cs, next) { + next = self.queue.borrow(cs).borrow_mut().next_expiration(self.now()); + } + } +} + +impl Driver for Rtc { + fn now(&self) -> u64 { + // `period` MUST be read before `counter`, see comment at the top for details. + let period = self.period.load(Ordering::Acquire); + compiler_fence(Ordering::Acquire); + let counter = self.counter_reg().read().bits(); + calc_now(period, counter) + } + + fn schedule_wake(&self, at: u64, waker: &core::task::Waker) { + critical_section::with(|cs| { + let mut queue = self.queue.borrow(cs).borrow_mut(); + + if queue.schedule_wake(at, waker) { + let mut next = queue.next_expiration(self.now()); + while !self.set_alarm(cs, next) { + next = queue.next_expiration(self.now()); + } + } + }) + } +} + +#[cfg(feature = "rt")] +#[allow(non_snake_case)] +#[interrupt] +fn RTC() { + DRIVER.on_interrupt() +} + +pub(crate) fn init(irq_prio: crate::interrupt::Priority) { + DRIVER.init(irq_prio) +} diff --git a/examples/mimxrt6/Cargo.toml b/examples/mimxrt6/Cargo.toml index 894ce174c..0e4a1ee36 100644 --- a/examples/mimxrt6/Cargo.toml +++ b/examples/mimxrt6/Cargo.toml @@ -12,7 +12,8 @@ defmt-rtt = "1.0" embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-futures = { version = "0.1.1", path = "../../embassy-futures" } -embassy-imxrt = { version = "0.1.0", path = "../../embassy-imxrt", features = ["defmt", "mimxrt685s", "unstable-pac"] } +embassy-imxrt = { version = "0.1.0", path = "../../embassy-imxrt", features = ["defmt", "mimxrt685s", "unstable-pac", "time", "time-driver-rtc"] } +embassy-time = { version = "0.4", path = "../../embassy-time" } embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } embedded-hal-1 = { package = "embedded-hal", version = "1.0" } embedded-hal-async = "1.0.0" diff --git a/examples/mimxrt6/src/bin/blinky.rs b/examples/mimxrt6/src/bin/blinky.rs index e40e71e6f..de079d505 100644 --- a/examples/mimxrt6/src/bin/blinky.rs +++ b/examples/mimxrt6/src/bin/blinky.rs @@ -6,6 +6,7 @@ extern crate embassy_imxrt_examples; use defmt::info; use embassy_executor::Spawner; use embassy_imxrt::gpio; +use embassy_time::Timer; #[embassy_executor::main] async fn main(_spawner: Spawner) { @@ -24,6 +25,6 @@ async fn main(_spawner: Spawner) { loop { info!("Toggling LED"); led.toggle(); - cortex_m::asm::delay(5_000_000); + Timer::after_secs(1).await; } } From b4bbc00a0060ae1edb6178d12c9d0b9cd5a7031a Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 10 Apr 2025 10:15:44 -0700 Subject: [PATCH 0949/1217] Convert tabs into spaces Indent everything with spaces instead of TABS. Based on PR by James Munns on the original "out-of-tree" copy of embassy-imxrt: https://github.com/OpenDevicePartnership/embassy-imxrt/pull/387 --- examples/mimxrt6/memory.x | 52 +++++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/examples/mimxrt6/memory.x b/examples/mimxrt6/memory.x index 5ea82fd71..6c4410f57 100644 --- a/examples/mimxrt6/memory.x +++ b/examples/mimxrt6/memory.x @@ -1,34 +1,34 @@ MEMORY { - OTFAD : ORIGIN = 0x08000000, LENGTH = 256 - FCB : ORIGIN = 0x08000400, LENGTH = 512 - BIV : ORIGIN = 0x08000600, LENGTH = 4 - KEYSTORE : ORIGIN = 0x08000800, LENGTH = 2K - FLASH : ORIGIN = 0x08001000, LENGTH = 1M - RAM : ORIGIN = 0x20080000, LENGTH = 1536K + OTFAD : ORIGIN = 0x08000000, LENGTH = 256 + FCB : ORIGIN = 0x08000400, LENGTH = 512 + BIV : ORIGIN = 0x08000600, LENGTH = 4 + KEYSTORE : ORIGIN = 0x08000800, LENGTH = 2K + FLASH : ORIGIN = 0x08001000, LENGTH = 1M + RAM : ORIGIN = 0x20080000, LENGTH = 1536K } SECTIONS { - .otfad : { - . = ALIGN(4); - KEEP(* (.otfad)) - . = ALIGN(4); - } > OTFAD + .otfad : { + . = ALIGN(4); + KEEP(* (.otfad)) + . = ALIGN(4); + } > OTFAD - .fcb : { - . = ALIGN(4); - KEEP(* (.fcb)) - . = ALIGN(4); - } > FCB + .fcb : { + . = ALIGN(4); + KEEP(* (.fcb)) + . = ALIGN(4); + } > FCB - .biv : { - . = ALIGN(4); - KEEP(* (.biv)) - . = ALIGN(4); - } > BIV + .biv : { + . = ALIGN(4); + KEEP(* (.biv)) + . = ALIGN(4); + } > BIV - .keystore : { - . = ALIGN(4); - KEEP(* (.keystore)) - . = ALIGN(4); - } > KEYSTORE + .keystore : { + . = ALIGN(4); + KEEP(* (.keystore)) + . = ALIGN(4); + } > KEYSTORE } From 05606d03804b431d014fa7cde23c2058b1ad2648 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 10 Apr 2025 10:16:49 -0700 Subject: [PATCH 0950/1217] Update minimum FCB version to latest released Version 0.2+ allows for the user to provide custom FCB for their platform. By default, FCB should work on MIMXRT685s EVK, by NXP. Based on PR by James Munns on the original "out-of-tree" copy of embassy-imxrt: https://github.com/OpenDevicePartnership/embassy-imxrt/pull/387 --- examples/mimxrt6/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/mimxrt6/Cargo.toml b/examples/mimxrt6/Cargo.toml index 0e4a1ee36..8fc510c47 100644 --- a/examples/mimxrt6/Cargo.toml +++ b/examples/mimxrt6/Cargo.toml @@ -18,7 +18,7 @@ embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["de embedded-hal-1 = { package = "embedded-hal", version = "1.0" } embedded-hal-async = "1.0.0" -mimxrt600-fcb = "0.1.0" +mimxrt600-fcb = "0.2.2" panic-probe = { version = "0.3", features = ["print-defmt"] } rand = { version = "0.8.5", default-features = false } From 8fb0186f878f28727203d021a5a5ce21a9c06e82 Mon Sep 17 00:00:00 2001 From: RichardWGNR <171420035+RichardWGNR@users.noreply.github.com> Date: Fri, 11 Apr 2025 00:36:00 +0500 Subject: [PATCH 0951/1217] Fix #4062 --- embassy-stm32/src/can/fd/config.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/embassy-stm32/src/can/fd/config.rs b/embassy-stm32/src/can/fd/config.rs index 68161ca50..c6a66b469 100644 --- a/embassy-stm32/src/can/fd/config.rs +++ b/embassy-stm32/src/can/fd/config.rs @@ -328,11 +328,15 @@ pub struct FdCanConfig { /// /// Automatic retransmission is enabled by default. pub automatic_retransmit: bool, - /// Enabled or disables the pausing between transmissions + /// The transmit pause feature is intended for use in CAN systems where the CAN message + /// identifiers are permanently specified to specific values and cannot easily be changed. /// - /// This feature looses up burst transmissions coming from a single node and it protects against - /// "babbling idiot" scenarios where the application program erroneously requests too many - /// transmissions. + /// These message identifiers can have a higher CAN arbitration priority than other defined + /// messages, while in a specific application their relative arbitration priority must be inverse. + /// + /// This may lead to a case where one ECU sends a burst of CAN messages that cause + /// another ECU CAN messages to be delayed because that other messages have a lower + /// CAN arbitration priority. pub transmit_pause: bool, /// Enabled or disables the pausing between transmissions /// From e4739113b7c31a2949b4ebab7ac0ff2d44c39d6a Mon Sep 17 00:00:00 2001 From: Mick Chanthaseth Date: Thu, 10 Apr 2025 14:02:39 -0700 Subject: [PATCH 0952/1217] added qspi example for stm32h742 --- examples/stm32h742/.cargo/config.toml | 9 + examples/stm32h742/Cargo.toml | 66 ++++++ examples/stm32h742/build.rs | 5 + examples/stm32h742/src/bin/qspi.rs | 300 ++++++++++++++++++++++++++ 4 files changed, 380 insertions(+) create mode 100644 examples/stm32h742/.cargo/config.toml create mode 100644 examples/stm32h742/Cargo.toml create mode 100644 examples/stm32h742/build.rs create mode 100644 examples/stm32h742/src/bin/qspi.rs diff --git a/examples/stm32h742/.cargo/config.toml b/examples/stm32h742/.cargo/config.toml new file mode 100644 index 000000000..f30a52a79 --- /dev/null +++ b/examples/stm32h742/.cargo/config.toml @@ -0,0 +1,9 @@ +[target.'cfg(all(target_arch = "arm", target_os = "none"))'] +# replace STM32H742VITx with your chip as listed in `probe-rs chip list` +runner = "probe-rs run --chip STM32H742VITx" + +[build] +target = "thumbv7em-none-eabihf" + +[env] +DEFMT_LOG = "trace" diff --git a/examples/stm32h742/Cargo.toml b/examples/stm32h742/Cargo.toml new file mode 100644 index 000000000..e2e0094b8 --- /dev/null +++ b/examples/stm32h742/Cargo.toml @@ -0,0 +1,66 @@ +[package] +edition = "2021" +name = "embassy-stm32f7-examples" +version = "0.1.0" +license = "MIT OR Apache-2.0" + +[dependencies] +# Change stm32f777zi to your chip name, if necessary. +embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [ + "defmt", + "stm32h742vi", + "memory-x", + "unstable-pac", + "time-driver-any", + "exti", +] } +embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = [ + "defmt", +] } +embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = [ + "arch-cortex-m", + "executor-thread", + "defmt", +] } +embassy-time = { version = "0.4.0", path = "../../embassy-time", features = [ + "defmt", + "defmt-timestamp-uptime", + "tick-hz-32_768", +] } +embassy-net = { version = "0.7.0", path = "../../embassy-net", features = [ + "defmt", + "tcp", + "dhcpv4", + "medium-ethernet", +] } +embedded-io-async = { version = "0.6.1" } +embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = [ + "defmt", +] } +embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } + +defmt = "0.3" +defmt-rtt = "0.4" + +cortex-m = { version = "0.7.6", features = [ + "inline-asm", + "critical-section-single-core", +] } +cortex-m-rt = "0.7.0" +embedded-hal = "0.2.6" +panic-probe = { version = "0.3", features = ["print-defmt"] } +heapless = { version = "0.8", default-features = false } +nb = "1.0.0" +rand_core = "0.6.3" +critical-section = "1.1" +embedded-storage = "0.3.1" +static_cell = "2" +sha2 = { version = "0.10.8", default-features = false } +hmac = "0.12.1" +aes-gcm = { version = "0.10.3", default-features = false, features = [ + "aes", + "heapless", +] } + +[profile.release] +debug = 2 diff --git a/examples/stm32h742/build.rs b/examples/stm32h742/build.rs new file mode 100644 index 000000000..8cd32d7ed --- /dev/null +++ b/examples/stm32h742/build.rs @@ -0,0 +1,5 @@ +fn main() { + println!("cargo:rustc-link-arg-bins=--nmagic"); + println!("cargo:rustc-link-arg-bins=-Tlink.x"); + println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); +} diff --git a/examples/stm32h742/src/bin/qspi.rs b/examples/stm32h742/src/bin/qspi.rs new file mode 100644 index 000000000..707bb9922 --- /dev/null +++ b/examples/stm32h742/src/bin/qspi.rs @@ -0,0 +1,300 @@ +#![no_std] +#![no_main] +#![allow(dead_code)] // Allow dead code as not all commands are used in the example + +use defmt::info; +use embassy_executor::Spawner; +use embassy_stm32::mode::Blocking; +use embassy_stm32::qspi::enums::{ + AddressSize, ChipSelectHighTime, FIFOThresholdLevel, MemorySize, *, +}; +use embassy_stm32::qspi::{Config as QspiCfg, Instance, Qspi, TransferConfig}; +use embassy_stm32::Config as StmCfg; +use {defmt_rtt as _, panic_probe as _}; + +const MEMORY_PAGE_SIZE: usize = 256; + +const CMD_READ: u8 = 0x03; +const CMD_HS_READ: u8 = 0x0B; +const CMD_QUAD_READ: u8 = 0x6B; + +const CMD_WRITE_PG: u8 = 0xF2; +const CMD_QUAD_WRITE_PG: u8 = 0x32; + +const CMD_READ_ID: u8 = 0x9F; +const CMD_READ_UUID: u8 = 0x4B; + +const CMD_ENABLE_RESET: u8 = 0x66; +const CMD_RESET: u8 = 0x99; + +const CMD_WRITE_ENABLE: u8 = 0x06; +const CMD_WRITE_DISABLE: u8 = 0x04; + +const CMD_CHIP_ERASE: u8 = 0xC7; +const CMD_SECTOR_ERASE: u8 = 0x20; +const CMD_BLOCK_ERASE_32K: u8 = 0x52; +const CMD_BLOCK_ERASE_64K: u8 = 0xD8; + +const CMD_READ_SR: u8 = 0x05; +const CMD_READ_CR: u8 = 0x35; + +const CMD_WRITE_SR: u8 = 0x01; +const CMD_WRITE_CR: u8 = 0x31; +const MEMORY_ADDR: u32 = 0x00000001u32; + +/// Implementation of access to flash chip. +/// Chip commands are hardcoded as it depends on used chip. +/// This implementation is using chip GD25Q64C from Giga Device +pub struct FlashMemory { + qspi: Qspi<'static, I, Blocking>, +} + +impl FlashMemory { + pub fn new(qspi: Qspi<'static, I, Blocking>) -> Self { + let mut memory = Self { qspi }; + + memory.reset_memory(); + memory.enable_quad(); + + memory + } + + fn enable_quad(&mut self) { + let cr = self.read_cr(); + self.write_cr(cr | 0x02); + } + + fn exec_command(&mut self, cmd: u8) { + let transaction = TransferConfig { + iwidth: QspiWidth::SING, + awidth: QspiWidth::NONE, + dwidth: QspiWidth::NONE, + instruction: cmd, + address: None, + dummy: DummyCycles::_0, + }; + self.qspi.blocking_command(transaction); + } + + pub fn reset_memory(&mut self) { + self.exec_command(CMD_ENABLE_RESET); + self.exec_command(CMD_RESET); + self.wait_write_finish(); + } + + pub fn enable_write(&mut self) { + self.exec_command(CMD_WRITE_ENABLE); + } + + pub fn read_id(&mut self) -> [u8; 3] { + let mut buffer = [0; 3]; + let transaction: TransferConfig = TransferConfig { + iwidth: QspiWidth::SING, + awidth: QspiWidth::NONE, + dwidth: QspiWidth::SING, + instruction: CMD_READ_ID, + address: None, + dummy: DummyCycles::_0, + }; + self.qspi.blocking_read(&mut buffer, transaction); + buffer + } + + pub fn read_uuid(&mut self) -> [u8; 16] { + let mut buffer = [0; 16]; + let transaction: TransferConfig = TransferConfig { + iwidth: QspiWidth::SING, + awidth: QspiWidth::SING, + dwidth: QspiWidth::SING, + instruction: CMD_READ_UUID, + address: Some(0), + dummy: DummyCycles::_8, + }; + self.qspi.blocking_read(&mut buffer, transaction); + buffer + } + + pub fn read_memory(&mut self, addr: u32, buffer: &mut [u8]) { + let transaction = TransferConfig { + iwidth: QspiWidth::SING, + awidth: QspiWidth::SING, + dwidth: QspiWidth::QUAD, + instruction: CMD_QUAD_READ, + address: Some(addr), + dummy: DummyCycles::_8, + }; + self.qspi.blocking_read(buffer, transaction); + } + + fn wait_write_finish(&mut self) { + while (self.read_sr() & 0x01) != 0 {} + } + + fn perform_erase(&mut self, addr: u32, cmd: u8) { + let transaction = TransferConfig { + iwidth: QspiWidth::SING, + awidth: QspiWidth::SING, + dwidth: QspiWidth::NONE, + instruction: cmd, + address: Some(addr), + dummy: DummyCycles::_0, + }; + self.enable_write(); + self.qspi.blocking_command(transaction); + self.wait_write_finish(); + } + + pub fn erase_sector(&mut self, addr: u32) { + self.perform_erase(addr, CMD_SECTOR_ERASE); + } + + pub fn erase_block_32k(&mut self, addr: u32) { + self.perform_erase(addr, CMD_BLOCK_ERASE_32K); + } + + pub fn erase_block_64k(&mut self, addr: u32) { + self.perform_erase(addr, CMD_BLOCK_ERASE_64K); + } + + pub fn erase_chip(&mut self) { + self.exec_command(CMD_CHIP_ERASE); + } + + fn write_page(&mut self, addr: u32, buffer: &[u8], len: usize) { + assert!( + (len as u32 + (addr & 0x000000ff)) <= MEMORY_PAGE_SIZE as u32, + "write_page(): page write length exceeds page boundary (len = {}, addr = {:X}", + len, + addr + ); + + let transaction = TransferConfig { + iwidth: QspiWidth::SING, + awidth: QspiWidth::SING, + dwidth: QspiWidth::QUAD, + instruction: CMD_QUAD_WRITE_PG, + address: Some(addr), + dummy: DummyCycles::_0, + }; + self.enable_write(); + self.qspi.blocking_write(buffer, transaction); + self.wait_write_finish(); + } + + pub fn write_memory(&mut self, addr: u32, buffer: &[u8]) { + let mut left = buffer.len(); + let mut place = addr; + let mut chunk_start = 0; + + while left > 0 { + let max_chunk_size = MEMORY_PAGE_SIZE - (place & 0x000000ff) as usize; + let chunk_size = if left >= max_chunk_size { + max_chunk_size + } else { + left + }; + let chunk = &buffer[chunk_start..(chunk_start + chunk_size)]; + self.write_page(place, chunk, chunk_size); + place += chunk_size as u32; + left -= chunk_size; + chunk_start += chunk_size; + } + } + + fn read_register(&mut self, cmd: u8) -> u8 { + let mut buffer = [0; 1]; + let transaction: TransferConfig = TransferConfig { + iwidth: QspiWidth::SING, + awidth: QspiWidth::NONE, + dwidth: QspiWidth::SING, + instruction: cmd, + address: None, + dummy: DummyCycles::_0, + }; + self.qspi.blocking_read(&mut buffer, transaction); + buffer[0] + } + + fn write_register(&mut self, cmd: u8, value: u8) { + let buffer = [value; 1]; + let transaction: TransferConfig = TransferConfig { + iwidth: QspiWidth::SING, + awidth: QspiWidth::NONE, + dwidth: QspiWidth::SING, + instruction: cmd, + address: None, + dummy: DummyCycles::_0, + }; + self.qspi.blocking_write(&buffer, transaction); + } + + pub fn read_sr(&mut self) -> u8 { + self.read_register(CMD_READ_SR) + } + + pub fn read_cr(&mut self) -> u8 { + self.read_register(CMD_READ_CR) + } + + pub fn write_sr(&mut self, value: u8) { + self.write_register(CMD_WRITE_SR, value); + } + + pub fn write_cr(&mut self, value: u8) { + self.write_register(CMD_WRITE_CR, value); + } +} + +#[embassy_executor::main] +async fn main(_spawner: Spawner) -> ! { + let mut config = StmCfg::default(); + { + use embassy_stm32::rcc::*; + config.rcc.hsi = Some(HSIPrescaler::DIV1); + config.rcc.csi = true; + config.rcc.hsi48 = Some(Default::default()); // needed for RNG + config.rcc.pll1 = Some(Pll { + source: PllSource::HSI, + prediv: PllPreDiv::DIV4, + mul: PllMul::MUL50, + divp: Some(PllDiv::DIV2), + divq: None, + divr: None, + }); + config.rcc.sys = Sysclk::PLL1_P; // 400 Mhz + config.rcc.ahb_pre = AHBPrescaler::DIV2; // 200 Mhz + config.rcc.apb1_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.apb2_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.voltage_scale = VoltageScale::Scale1; + } + let p = embassy_stm32::init(config); + info!("Embassy initialized"); + + let config = QspiCfg { + memory_size: MemorySize::_8MiB, + address_size: AddressSize::_24bit, + prescaler: 16, + cs_high_time: ChipSelectHighTime::_1Cycle, + fifo_threshold: FIFOThresholdLevel::_16Bytes, + }; + let driver = Qspi::new_blocking_bank1( + p.QUADSPI, p.PD11, p.PD12, p.PE2, p.PD13, p.PB2, p.PB10, config, + ); + let mut flash = FlashMemory::new(driver); + let flash_id = flash.read_id(); + info!("FLASH ID: {:?}", flash_id); + let mut wr_buf = [0u8; 256]; + for i in 0..256 { + wr_buf[i] = i as u8; + } + let mut rd_buf = [0u8; 256]; + flash.erase_sector(MEMORY_ADDR); + flash.write_memory(MEMORY_ADDR, &wr_buf); + flash.read_memory(MEMORY_ADDR, &mut rd_buf); + info!("WRITE BUF: {:?}", wr_buf); + info!("READ BUF: {:?}", rd_buf); + info!("End of Program, proceed to empty endless loop"); + loop {} +} From 5bc4de236c6740b5afa4f95bbab1991ac31df06a Mon Sep 17 00:00:00 2001 From: Mick Chanthaseth Date: Thu, 10 Apr 2025 14:09:53 -0700 Subject: [PATCH 0953/1217] fixed fmt --- examples/stm32h742/src/bin/qspi.rs | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/examples/stm32h742/src/bin/qspi.rs b/examples/stm32h742/src/bin/qspi.rs index 707bb9922..aee07f3f2 100644 --- a/examples/stm32h742/src/bin/qspi.rs +++ b/examples/stm32h742/src/bin/qspi.rs @@ -5,9 +5,7 @@ use defmt::info; use embassy_executor::Spawner; use embassy_stm32::mode::Blocking; -use embassy_stm32::qspi::enums::{ - AddressSize, ChipSelectHighTime, FIFOThresholdLevel, MemorySize, *, -}; +use embassy_stm32::qspi::enums::{AddressSize, ChipSelectHighTime, FIFOThresholdLevel, MemorySize, *}; use embassy_stm32::qspi::{Config as QspiCfg, Instance, Qspi, TransferConfig}; use embassy_stm32::Config as StmCfg; use {defmt_rtt as _, panic_probe as _}; @@ -188,11 +186,7 @@ impl FlashMemory { while left > 0 { let max_chunk_size = MEMORY_PAGE_SIZE - (place & 0x000000ff) as usize; - let chunk_size = if left >= max_chunk_size { - max_chunk_size - } else { - left - }; + let chunk_size = if left >= max_chunk_size { max_chunk_size } else { left }; let chunk = &buffer[chunk_start..(chunk_start + chunk_size)]; self.write_page(place, chunk, chunk_size); place += chunk_size as u32; @@ -279,9 +273,7 @@ async fn main(_spawner: Spawner) -> ! { cs_high_time: ChipSelectHighTime::_1Cycle, fifo_threshold: FIFOThresholdLevel::_16Bytes, }; - let driver = Qspi::new_blocking_bank1( - p.QUADSPI, p.PD11, p.PD12, p.PE2, p.PD13, p.PB2, p.PB10, config, - ); + let driver = Qspi::new_blocking_bank1(p.QUADSPI, p.PD11, p.PD12, p.PE2, p.PD13, p.PB2, p.PB10, config); let mut flash = FlashMemory::new(driver); let flash_id = flash.read_id(); info!("FLASH ID: {:?}", flash_id); From 4d903a713eb1db05a8465c74e6c6cd71fefc5d4e Mon Sep 17 00:00:00 2001 From: RichardWGNR <171420035+RichardWGNR@users.noreply.github.com> Date: Fri, 11 Apr 2025 04:27:03 +0500 Subject: [PATCH 0954/1217] Capability to modify CAN frame data without copying. #4075 --- embassy-stm32/src/can/frame.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/embassy-stm32/src/can/frame.rs b/embassy-stm32/src/can/frame.rs index d2d1f7aa6..f1bc81ec3 100644 --- a/embassy-stm32/src/can/frame.rs +++ b/embassy-stm32/src/can/frame.rs @@ -128,6 +128,11 @@ impl ClassicData { pub fn raw(&self) -> &[u8] { &self.bytes } + + /// Raw mutable read access to data. + pub fn raw_mut(&mut self) -> &mut [u8] { + &mut self.bytes + } /// Checks if the length can be encoded in FDCAN DLC field. pub const fn is_valid_len(len: usize) -> bool { @@ -208,6 +213,11 @@ impl Frame { pub fn data(&self) -> &[u8] { &self.data.raw() } + + /// Get mutable reference to data + pub fn data_mut(&mut self) -> &mut [u8] { + self.data.raw_mut() + } /// Get priority of frame pub fn priority(&self) -> u32 { @@ -313,6 +323,11 @@ impl FdData { pub fn raw(&self) -> &[u8] { &self.bytes } + + /// Raw mutable read access to data. + pub fn raw_mut(&mut self) -> &mut [u8] { + &mut self.bytes + } /// Checks if the length can be encoded in FDCAN DLC field. pub const fn is_valid_len(len: usize) -> bool { @@ -392,6 +407,11 @@ impl FdFrame { pub fn data(&self) -> &[u8] { &self.data.raw() } + + /// Get mutable reference to data + pub fn data_mut(&mut self) -> &mut [u8] { + self.data.raw_mut() + } } impl embedded_can::Frame for FdFrame { From aae3f7fb70600851240501c9eced2cbc248ca700 Mon Sep 17 00:00:00 2001 From: RichardWGNR <171420035+RichardWGNR@users.noreply.github.com> Date: Fri, 11 Apr 2025 04:31:32 +0500 Subject: [PATCH 0955/1217] Fix rustfmt #4075 --- embassy-stm32/src/can/frame.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/embassy-stm32/src/can/frame.rs b/embassy-stm32/src/can/frame.rs index f1bc81ec3..f621b8bd5 100644 --- a/embassy-stm32/src/can/frame.rs +++ b/embassy-stm32/src/can/frame.rs @@ -128,7 +128,7 @@ impl ClassicData { pub fn raw(&self) -> &[u8] { &self.bytes } - + /// Raw mutable read access to data. pub fn raw_mut(&mut self) -> &mut [u8] { &mut self.bytes @@ -213,7 +213,7 @@ impl Frame { pub fn data(&self) -> &[u8] { &self.data.raw() } - + /// Get mutable reference to data pub fn data_mut(&mut self) -> &mut [u8] { self.data.raw_mut() @@ -323,7 +323,7 @@ impl FdData { pub fn raw(&self) -> &[u8] { &self.bytes } - + /// Raw mutable read access to data. pub fn raw_mut(&mut self) -> &mut [u8] { &mut self.bytes @@ -407,7 +407,7 @@ impl FdFrame { pub fn data(&self) -> &[u8] { &self.data.raw() } - + /// Get mutable reference to data pub fn data_mut(&mut self) -> &mut [u8] { self.data.raw_mut() From 608fe44a43a527beef946c4e087008f549e3f3e5 Mon Sep 17 00:00:00 2001 From: JuliDi <20155974+JuliDi@users.noreply.github.com> Date: Fri, 11 Apr 2025 13:57:41 +0200 Subject: [PATCH 0956/1217] remove incompatible device classes and protocol from RP webusb example --- examples/rp/src/bin/usb_webusb.rs | 6 ------ examples/rp235x/src/bin/usb_webusb.rs | 6 ------ 2 files changed, 12 deletions(-) diff --git a/examples/rp/src/bin/usb_webusb.rs b/examples/rp/src/bin/usb_webusb.rs index e73938ac9..a5dc94d5b 100644 --- a/examples/rp/src/bin/usb_webusb.rs +++ b/examples/rp/src/bin/usb_webusb.rs @@ -51,12 +51,6 @@ async fn main(_spawner: Spawner) { config.max_power = 100; config.max_packet_size_0 = 64; - // Required for windows compatibility. - // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help - config.device_class = 0xff; - config.device_sub_class = 0x00; - config.device_protocol = 0x00; - // Create embassy-usb DeviceBuilder using the driver and config. // It needs some buffers for building the descriptors. let mut config_descriptor = [0; 256]; diff --git a/examples/rp235x/src/bin/usb_webusb.rs b/examples/rp235x/src/bin/usb_webusb.rs index e73938ac9..a5dc94d5b 100644 --- a/examples/rp235x/src/bin/usb_webusb.rs +++ b/examples/rp235x/src/bin/usb_webusb.rs @@ -51,12 +51,6 @@ async fn main(_spawner: Spawner) { config.max_power = 100; config.max_packet_size_0 = 64; - // Required for windows compatibility. - // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help - config.device_class = 0xff; - config.device_sub_class = 0x00; - config.device_protocol = 0x00; - // Create embassy-usb DeviceBuilder using the driver and config. // It needs some buffers for building the descriptors. let mut config_descriptor = [0; 256]; From e3cec4a246a0e3cbaae60c91f946f608f6637f63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anton=20P=C3=B6hl?= Date: Thu, 13 Mar 2025 10:52:41 +0100 Subject: [PATCH 0957/1217] Stm32 usart: make pin modes of cts, tx, rts and de configurable --- embassy-stm32/src/usart/buffered.rs | 28 ++++----- embassy-stm32/src/usart/mod.rs | 90 ++++++++++++++++++++++------- 2 files changed, 84 insertions(+), 34 deletions(-) diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs index b1640b6dc..2dfb99dbc 100644 --- a/embassy-stm32/src/usart/buffered.rs +++ b/embassy-stm32/src/usart/buffered.rs @@ -16,7 +16,7 @@ use super::{ sr, tdr, Config, ConfigError, CtsPin, Duplex, Error, HalfDuplexConfig, HalfDuplexReadback, Info, Instance, Regs, RtsPin, RxPin, TxPin, }; -use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed}; +use crate::gpio::{AfType, AnyPin, Pull, SealedPin as _}; use crate::interrupt::{self, InterruptExt}; use crate::time::Hertz; @@ -217,8 +217,8 @@ impl<'d> BufferedUart<'d> { ) -> Result { Self::new_inner( peri, - new_pin!(rx, AfType::input(config.rx_pull)), - new_pin!(tx, AfType::output(OutputType::PushPull, Speed::Medium)), + new_pin!(rx, config.rx_af()), + new_pin!(tx, config.tx_af()), None, None, None, @@ -242,10 +242,10 @@ impl<'d> BufferedUart<'d> { ) -> Result { Self::new_inner( peri, - new_pin!(rx, AfType::input(Pull::None)), - new_pin!(tx, AfType::output(OutputType::PushPull, Speed::Medium)), - new_pin!(rts, AfType::output(OutputType::PushPull, Speed::Medium)), - new_pin!(cts, AfType::input(Pull::None)), + new_pin!(rx, config.rx_af()), + new_pin!(tx, config.tx_af()), + new_pin!(rts, config.rts_config.af_type()), + new_pin!(cts, AfType::input(config.cts_pull)), None, tx_buffer, rx_buffer, @@ -266,8 +266,8 @@ impl<'d> BufferedUart<'d> { ) -> Result { Self::new_inner( peri, - new_pin!(rx, AfType::input(Pull::None)), - new_pin!(tx, AfType::output(OutputType::PushPull, Speed::Medium)), + new_pin!(rx, config.rx_af()), + new_pin!(tx, config.tx_af()), None, None, new_pin!(rts, AfType::input(Pull::None)), // RTS mapped used as DE @@ -290,8 +290,8 @@ impl<'d> BufferedUart<'d> { ) -> Result { Self::new_inner( peri, - new_pin!(rx, AfType::input(Pull::None)), - new_pin!(tx, AfType::output(OutputType::PushPull, Speed::Medium)), + new_pin!(rx, config.rx_af()), + new_pin!(tx, config.tx_af()), new_pin!(rts, AfType::input(Pull::None)), None, // no CTS None, // no DE @@ -315,11 +315,11 @@ impl<'d> BufferedUart<'d> { ) -> Result { Self::new_inner( peri, - new_pin!(rx, AfType::input(config.rx_pull)), - new_pin!(tx, AfType::output(OutputType::PushPull, Speed::Medium)), + new_pin!(rx, config.rx_af()), + new_pin!(tx, config.tx_af()), None, None, - new_pin!(de, AfType::output(OutputType::PushPull, Speed::Medium)), + new_pin!(de, config.de_config.af_type()), tx_buffer, rx_buffer, config, diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index 675e90c7f..80a391d41 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -136,6 +136,40 @@ pub enum HalfDuplexReadback { Readback, } +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +/// Half duplex IO mode +pub enum OutputConfig { + /// Push pull allows for faster baudrates, no internal pullup + PushPull, + #[cfg(not(gpio_v1))] + /// Push pull with internal pull up resistor + PushPullPullUp, + #[cfg(not(gpio_v1))] + /// Push pull with internal pull down resistor + PushPullPullDown, + /// Open drain output using external pull down resistor + OpenDrainExternal, + #[cfg(not(gpio_v1))] + /// Open drain output using internal pull up resistor + OpenDrainInternal, +} + +impl OutputConfig { + const fn af_type(self) -> AfType { + match self { + OutputConfig::PushPull => AfType::output(OutputType::PushPull, Speed::Medium), + #[cfg(not(gpio_v1))] + OutputConfig::PushPullPullUp => AfType::output_pull(OutputType::OpenDrain, Speed::Medium, Pull::Up), + #[cfg(not(gpio_v1))] + OutputConfig::PushPullPullDown => AfType::output_pull(OutputType::OpenDrain, Speed::Medium, Pull::Down), + OutputConfig::OpenDrainExternal => AfType::output(OutputType::OpenDrain, Speed::Medium), + #[cfg(not(gpio_v1))] + OutputConfig::OpenDrainInternal => AfType::output_pull(OutputType::OpenDrain, Speed::Medium, Pull::Up), + } + } +} + #[derive(Clone, Copy, PartialEq, Eq, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] /// Duplex mode @@ -208,6 +242,18 @@ pub struct Config { /// Set the pull configuration for the RX pin. pub rx_pull: Pull, + /// Set the pull configuration for the CTS pin. + pub cts_pull: Pull, + + /// Set the pin configuration for the TX pin. + pub tx_config: OutputConfig, + + /// Set the pin configuration for the RTS pin. + pub rts_config: OutputConfig, + + /// Set the pin configuration for the DE pin. + pub de_config: OutputConfig, + // private: set by new_half_duplex, not by the user. duplex: Duplex, } @@ -218,13 +264,13 @@ impl Config { if self.swap_rx_tx { return AfType::input(self.rx_pull); }; - AfType::output(OutputType::PushPull, Speed::Medium) + self.tx_config.af_type() } fn rx_af(&self) -> AfType { #[cfg(any(usart_v3, usart_v4))] if self.swap_rx_tx { - return AfType::output(OutputType::PushPull, Speed::Medium); + return self.tx_config.af_type(); }; AfType::input(self.rx_pull) } @@ -248,6 +294,10 @@ impl Default for Config { #[cfg(any(usart_v3, usart_v4))] invert_rx: false, rx_pull: Pull::None, + cts_pull: Pull::None, + tx_config: OutputConfig::PushPull, + rts_config: OutputConfig::PushPull, + de_config: OutputConfig::PushPull, duplex: Duplex::Full, } } @@ -426,7 +476,7 @@ impl<'d> UartTx<'d, Async> { ) -> Result { Self::new_inner( peri, - new_pin!(tx, AfType::output(OutputType::PushPull, Speed::Medium)), + new_pin!(tx, config.tx_af()), None, new_dma!(tx_dma), config, @@ -443,8 +493,8 @@ impl<'d> UartTx<'d, Async> { ) -> Result { Self::new_inner( peri, - new_pin!(tx, AfType::output(OutputType::PushPull, Speed::Medium)), - new_pin!(cts, AfType::input(Pull::None)), + new_pin!(tx, config.tx_af()), + new_pin!(cts, AfType::input(config.cts_pull)), new_dma!(tx_dma), config, ) @@ -484,7 +534,7 @@ impl<'d> UartTx<'d, Blocking> { ) -> Result { Self::new_inner( peri, - new_pin!(tx, AfType::output(OutputType::PushPull, Speed::Medium)), + new_pin!(tx, config.tx_af()), None, None, config, @@ -500,8 +550,8 @@ impl<'d> UartTx<'d, Blocking> { ) -> Result { Self::new_inner( peri, - new_pin!(tx, AfType::output(OutputType::PushPull, Speed::Medium)), - new_pin!(cts, AfType::input(config.rx_pull)), + new_pin!(tx, config.tx_af()), + new_pin!(cts, AfType::input(config.cts_pull)), None, config, ) @@ -658,7 +708,7 @@ impl<'d> UartRx<'d, Async> { ) -> Result { Self::new_inner( peri, - new_pin!(rx, AfType::input(config.rx_pull)), + new_pin!(rx, config.rx_af()), None, new_dma!(rx_dma), config, @@ -676,8 +726,8 @@ impl<'d> UartRx<'d, Async> { ) -> Result { Self::new_inner( peri, - new_pin!(rx, AfType::input(config.rx_pull)), - new_pin!(rts, AfType::output(OutputType::PushPull, Speed::Medium)), + new_pin!(rx, config.rx_af()), + new_pin!(rts, config.rts_config.af_type()), new_dma!(rx_dma), config, ) @@ -912,7 +962,7 @@ impl<'d> UartRx<'d, Blocking> { rx: Peri<'d, impl RxPin>, config: Config, ) -> Result { - Self::new_inner(peri, new_pin!(rx, AfType::input(config.rx_pull)), None, None, config) + Self::new_inner(peri, new_pin!(rx, config.rx_af()), None, None, config) } /// Create a new rx-only UART with a request-to-send pin @@ -924,8 +974,8 @@ impl<'d> UartRx<'d, Blocking> { ) -> Result { Self::new_inner( peri, - new_pin!(rx, AfType::input(config.rx_pull)), - new_pin!(rts, AfType::output(OutputType::PushPull, Speed::Medium)), + new_pin!(rx, config.rx_af()), + new_pin!(rts, config.rts_config.af_type()), None, config, ) @@ -1141,8 +1191,8 @@ impl<'d> Uart<'d, Async> { peri, new_pin!(rx, config.rx_af()), new_pin!(tx, config.tx_af()), - new_pin!(rts, AfType::output(OutputType::PushPull, Speed::Medium)), - new_pin!(cts, AfType::input(Pull::None)), + new_pin!(rts, config.rts_config.af_type()), + new_pin!(cts, AfType::input(config.cts_pull)), None, new_dma!(tx_dma), new_dma!(rx_dma), @@ -1168,7 +1218,7 @@ impl<'d> Uart<'d, Async> { new_pin!(tx, config.tx_af()), None, None, - new_pin!(de, AfType::output(OutputType::PushPull, Speed::Medium)), + new_pin!(de, config.de_config.af_type()), new_dma!(tx_dma), new_dma!(rx_dma), config, @@ -1308,8 +1358,8 @@ impl<'d> Uart<'d, Blocking> { peri, new_pin!(rx, config.rx_af()), new_pin!(tx, config.tx_af()), - new_pin!(rts, AfType::output(OutputType::PushPull, Speed::Medium)), - new_pin!(cts, AfType::input(Pull::None)), + new_pin!(rts, config.rts_config.af_type()), + new_pin!(cts, AfType::input(config.cts_pull)), None, None, None, @@ -1332,7 +1382,7 @@ impl<'d> Uart<'d, Blocking> { new_pin!(tx, config.tx_af()), None, None, - new_pin!(de, AfType::output(OutputType::PushPull, Speed::Medium)), + new_pin!(de, config.de_config.af_type()), None, None, config, From a544726be4ef66574419e95ee508f2062e9a3da2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anton=20P=C3=B6hl?= Date: Thu, 13 Mar 2025 11:05:10 +0100 Subject: [PATCH 0958/1217] Stm32 usart: remove HalfDuplexConfig The pin parameters of usart::Config are used instead. --- embassy-stm32/src/usart/buffered.rs | 8 ++--- embassy-stm32/src/usart/mod.rs | 38 +++------------------ examples/stm32g0/src/bin/onewire_ds18b20.rs | 13 ++++--- 3 files changed, 16 insertions(+), 43 deletions(-) diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs index 2dfb99dbc..57551ff56 100644 --- a/embassy-stm32/src/usart/buffered.rs +++ b/embassy-stm32/src/usart/buffered.rs @@ -13,7 +13,7 @@ use embassy_sync::waitqueue::AtomicWaker; use super::DePin; use super::{ clear_interrupt_flags, configure, half_duplex_set_rx_tx_before_write, rdr, reconfigure, send_break, set_baudrate, - sr, tdr, Config, ConfigError, CtsPin, Duplex, Error, HalfDuplexConfig, HalfDuplexReadback, Info, Instance, Regs, + sr, tdr, Config, ConfigError, CtsPin, Duplex, Error, HalfDuplexReadback, Info, Instance, Regs, RtsPin, RxPin, TxPin, }; use crate::gpio::{AfType, AnyPin, Pull, SealedPin as _}; @@ -346,7 +346,6 @@ impl<'d> BufferedUart<'d> { rx_buffer: &'d mut [u8], mut config: Config, readback: HalfDuplexReadback, - half_duplex: HalfDuplexConfig, ) -> Result { #[cfg(not(any(usart_v1, usart_v2)))] { @@ -357,7 +356,7 @@ impl<'d> BufferedUart<'d> { Self::new_inner( peri, None, - new_pin!(tx, half_duplex.af_type()), + new_pin!(tx, config.tx_af()), None, None, None, @@ -386,14 +385,13 @@ impl<'d> BufferedUart<'d> { rx_buffer: &'d mut [u8], mut config: Config, readback: HalfDuplexReadback, - half_duplex: HalfDuplexConfig, ) -> Result { config.swap_rx_tx = true; config.duplex = Duplex::Half(readback); Self::new_inner( peri, - new_pin!(rx, half_duplex.af_type()), + new_pin!(rx, config.rx_af()), None, None, None, diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index 80a391d41..a6bafc5a7 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -14,7 +14,7 @@ use embassy_sync::waitqueue::AtomicWaker; use futures_util::future::{select, Either}; use crate::dma::ChannelAndRequest; -use crate::gpio::{self, AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed}; +use crate::gpio::{AfType, AnyPin, OutputType, Pull, SealedPin as _, Speed}; use crate::interrupt::typelevel::Interrupt as _; use crate::interrupt::{self, Interrupt, InterruptExt}; use crate::mode::{Async, Blocking, Mode}; @@ -303,30 +303,6 @@ impl Default for Config { } } -#[derive(Clone, Copy, PartialEq, Eq, Debug)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -/// Half duplex IO mode -pub enum HalfDuplexConfig { - /// Push pull allows for faster baudrates, may require series resistor - PushPull, - /// Open drain output using external pull up resistor - OpenDrainExternal, - #[cfg(not(gpio_v1))] - /// Open drain output using internal pull up resistor - OpenDrainInternal, -} - -impl HalfDuplexConfig { - fn af_type(self) -> gpio::AfType { - match self { - HalfDuplexConfig::PushPull => AfType::output(OutputType::PushPull, Speed::Medium), - HalfDuplexConfig::OpenDrainExternal => AfType::output(OutputType::OpenDrain, Speed::Medium), - #[cfg(not(gpio_v1))] - HalfDuplexConfig::OpenDrainInternal => AfType::output_pull(OutputType::OpenDrain, Speed::Medium, Pull::Up), - } - } -} - /// Serial error #[derive(Debug, Eq, PartialEq, Copy, Clone)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -1245,7 +1221,6 @@ impl<'d> Uart<'d, Async> { rx_dma: Peri<'d, impl RxDma>, mut config: Config, readback: HalfDuplexReadback, - half_duplex: HalfDuplexConfig, ) -> Result { #[cfg(not(any(usart_v1, usart_v2)))] { @@ -1256,7 +1231,7 @@ impl<'d> Uart<'d, Async> { Self::new_inner( peri, None, - new_pin!(tx, half_duplex.af_type()), + new_pin!(tx, config.tx_af()), None, None, None, @@ -1285,7 +1260,6 @@ impl<'d> Uart<'d, Async> { rx_dma: Peri<'d, impl RxDma>, mut config: Config, readback: HalfDuplexReadback, - half_duplex: HalfDuplexConfig, ) -> Result { config.swap_rx_tx = true; config.duplex = Duplex::Half(readback); @@ -1294,7 +1268,7 @@ impl<'d> Uart<'d, Async> { peri, None, None, - new_pin!(rx, half_duplex.af_type()), + new_pin!(rx, config.rx_af()), None, None, new_dma!(tx_dma), @@ -1405,7 +1379,6 @@ impl<'d> Uart<'d, Blocking> { tx: Peri<'d, impl TxPin>, mut config: Config, readback: HalfDuplexReadback, - half_duplex: HalfDuplexConfig, ) -> Result { #[cfg(not(any(usart_v1, usart_v2)))] { @@ -1416,7 +1389,7 @@ impl<'d> Uart<'d, Blocking> { Self::new_inner( peri, None, - new_pin!(tx, half_duplex.af_type()), + new_pin!(tx, config.tx_af()), None, None, None, @@ -1442,7 +1415,6 @@ impl<'d> Uart<'d, Blocking> { rx: Peri<'d, impl RxPin>, mut config: Config, readback: HalfDuplexReadback, - half_duplex: HalfDuplexConfig, ) -> Result { config.swap_rx_tx = true; config.duplex = Duplex::Half(readback); @@ -1451,7 +1423,7 @@ impl<'d> Uart<'d, Blocking> { peri, None, None, - new_pin!(rx, half_duplex.af_type()), + new_pin!(rx, config.rx_af()), None, None, None, diff --git a/examples/stm32g0/src/bin/onewire_ds18b20.rs b/examples/stm32g0/src/bin/onewire_ds18b20.rs index f85cc4ff8..75519bbf2 100644 --- a/examples/stm32g0/src/bin/onewire_ds18b20.rs +++ b/examples/stm32g0/src/bin/onewire_ds18b20.rs @@ -8,7 +8,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::mode::Async; use embassy_stm32::usart::{ - BufferedUartRx, BufferedUartTx, Config, ConfigError, HalfDuplexConfig, RingBufferedUartRx, UartTx, + BufferedUartRx, BufferedUartTx, Config, ConfigError, OutputConfig, RingBufferedUartRx, UartTx, }; use embassy_stm32::{bind_interrupts, peripherals, usart}; use embassy_time::{Duration, Timer}; @@ -21,16 +21,18 @@ fn create_onewire(p: embassy_stm32::Peripherals) -> OneWire usart::InterruptHandler; }); + let mut config = Config::default(); + config.tx_config = OutputConfig::OpenDrainExternal; + let usart = Uart::new_half_duplex( p.USART1, p.PA9, Irqs, p.DMA1_CH1, p.DMA1_CH2, - Config::default(), + config, // Enable readback so we can read sensor pulling data low while transmission is in progress usart::HalfDuplexReadback::Readback, - HalfDuplexConfig::OpenDrainExternal, ) .unwrap(); @@ -50,6 +52,8 @@ fn create_onewire(p: embassy_stm32::Peripherals) -> OneWire OneWire Date: Thu, 13 Mar 2025 11:33:11 +0100 Subject: [PATCH 0959/1217] Format --- embassy-stm32/src/usart/buffered.rs | 4 ++-- embassy-stm32/src/usart/mod.rs | 24 +++--------------------- 2 files changed, 5 insertions(+), 23 deletions(-) diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs index 57551ff56..19dab75a0 100644 --- a/embassy-stm32/src/usart/buffered.rs +++ b/embassy-stm32/src/usart/buffered.rs @@ -13,8 +13,8 @@ use embassy_sync::waitqueue::AtomicWaker; use super::DePin; use super::{ clear_interrupt_flags, configure, half_duplex_set_rx_tx_before_write, rdr, reconfigure, send_break, set_baudrate, - sr, tdr, Config, ConfigError, CtsPin, Duplex, Error, HalfDuplexReadback, Info, Instance, Regs, - RtsPin, RxPin, TxPin, + sr, tdr, Config, ConfigError, CtsPin, Duplex, Error, HalfDuplexReadback, Info, Instance, Regs, RtsPin, RxPin, + TxPin, }; use crate::gpio::{AfType, AnyPin, Pull, SealedPin as _}; use crate::interrupt::{self, InterruptExt}; diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index a6bafc5a7..6c5d3422b 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -450,13 +450,7 @@ impl<'d> UartTx<'d, Async> { tx_dma: Peri<'d, impl TxDma>, config: Config, ) -> Result { - Self::new_inner( - peri, - new_pin!(tx, config.tx_af()), - None, - new_dma!(tx_dma), - config, - ) + Self::new_inner(peri, new_pin!(tx, config.tx_af()), None, new_dma!(tx_dma), config) } /// Create a new tx-only UART with a clear-to-send pin @@ -508,13 +502,7 @@ impl<'d> UartTx<'d, Blocking> { tx: Peri<'d, impl TxPin>, config: Config, ) -> Result { - Self::new_inner( - peri, - new_pin!(tx, config.tx_af()), - None, - None, - config, - ) + Self::new_inner(peri, new_pin!(tx, config.tx_af()), None, None, config) } /// Create a new blocking tx-only UART with a clear-to-send pin @@ -682,13 +670,7 @@ impl<'d> UartRx<'d, Async> { rx_dma: Peri<'d, impl RxDma>, config: Config, ) -> Result { - Self::new_inner( - peri, - new_pin!(rx, config.rx_af()), - None, - new_dma!(rx_dma), - config, - ) + Self::new_inner(peri, new_pin!(rx, config.rx_af()), None, new_dma!(rx_dma), config) } /// Create a new rx-only UART with a request-to-send pin From 181a324b4d6ea79a570f020941f0419fbb4530fc Mon Sep 17 00:00:00 2001 From: Alix ANNERAUD Date: Sat, 12 Apr 2025 12:26:48 +0200 Subject: [PATCH 0960/1217] Refactor RwLock implementation by removing unused map methods and cleaning up code for improved readability --- embassy-sync/src/rwlock.rs | 238 +------------------------------------ 1 file changed, 1 insertion(+), 237 deletions(-) diff --git a/embassy-sync/src/rwlock.rs b/embassy-sync/src/rwlock.rs index 25c575925..deeadd167 100644 --- a/embassy-sync/src/rwlock.rs +++ b/embassy-sync/src/rwlock.rs @@ -2,10 +2,10 @@ //! //! This module provides a read-write lock that can be used to synchronize data between asynchronous tasks. use core::cell::{RefCell, UnsafeCell}; +use core::fmt; use core::future::{poll_fn, Future}; use core::ops::{Deref, DerefMut}; use core::task::Poll; -use core::{fmt, mem}; use crate::blocking_mutex::raw::RawMutex; use crate::blocking_mutex::Mutex as BlockingMutex; @@ -221,27 +221,6 @@ where rwlock: &'a RwLock, } -impl<'a, M, T> RwLockReadGuard<'a, M, T> -where - M: RawMutex, - T: ?Sized, -{ - /// Map the contents of the `RwLockReadGuard` to a different type. - /// - /// This is useful for calling methods on the contents of the `RwLockReadGuard` without - /// moving out of the guard. - pub fn map(this: Self, fun: impl FnOnce(&T) -> &U) -> MappedRwLockReadGuard<'a, M, U> { - let rwlock = this.rwlock; - let value = fun(unsafe { &mut *this.rwlock.inner.get() }); - - mem::forget(this); - MappedRwLockReadGuard { - state: &rwlock.state, - value, - } - } -} - impl<'a, M, T> Drop for RwLockReadGuard<'a, M, T> where M: RawMutex, @@ -307,25 +286,6 @@ where rwlock: &'a RwLock, } -impl<'a, R, T> RwLockWriteGuard<'a, R, T> -where - R: RawMutex, - T: ?Sized, -{ - /// Returns a locked view over a portion of the locked data. - pub fn map(this: Self, fun: impl FnOnce(&mut T) -> &mut U) -> MappedRwLockWriteGuard<'a, R, U> { - let rwlock = this.rwlock; - let value = fun(unsafe { &mut *this.rwlock.inner.get() }); - // Dont run the `drop` method for RwLockWriteGuard. The ownership of the underlying - // locked state is being moved to the returned MappedRwLockWriteGuard. - mem::forget(this); - MappedRwLockWriteGuard { - state: &rwlock.state, - value, - } - } -} - impl<'a, R, T> Drop for RwLockWriteGuard<'a, R, T> where R: RawMutex, @@ -385,202 +345,6 @@ where } } -/// A handle to a held `RwLock` that has had a function applied to it via [`RwLockReadGuard::map`] or -/// [`MappedRwLockReadGuard::map`]. -/// -/// This can be used to hold a subfield of the protected data. -#[clippy::has_significant_drop] -pub struct MappedRwLockReadGuard<'a, M, T> -where - M: RawMutex, - T: ?Sized, -{ - state: &'a BlockingMutex>, - value: *const T, -} - -impl<'a, M, T> MappedRwLockReadGuard<'a, M, T> -where - M: RawMutex, - T: ?Sized, -{ - /// Returns a locked view over a portion of the locked data. - pub fn map(this: Self, fun: impl FnOnce(&T) -> &U) -> MappedRwLockReadGuard<'a, M, U> { - let rwlock = this.state; - let value = fun(unsafe { &*this.value }); - // Dont run the `drop` method for RwLockReadGuard. The ownership of the underlying - // locked state is being moved to the returned MappedRwLockReadGuard. - mem::forget(this); - MappedRwLockReadGuard { state: rwlock, value } - } -} - -impl<'a, M, T> Deref for MappedRwLockReadGuard<'a, M, T> -where - M: RawMutex, - T: ?Sized, -{ - type Target = T; - fn deref(&self) -> &Self::Target { - // Safety: the MappedRwLockReadGuard represents shared access to the contents - // of the read-write lock, so it's OK to get it. - unsafe { &*self.value } - } -} - -impl<'a, M, T> Drop for MappedRwLockReadGuard<'a, M, T> -where - M: RawMutex, - T: ?Sized, -{ - fn drop(&mut self) { - self.state.lock(|s| { - let mut s = unwrap!(s.try_borrow_mut()); - s.readers -= 1; - if s.readers == 0 { - s.waker.wake(); - } - }) - } -} - -unsafe impl<'a, M, T> Send for MappedRwLockReadGuard<'a, M, T> -where - M: RawMutex, - T: ?Sized, -{ -} - -unsafe impl<'a, M, T> Sync for MappedRwLockReadGuard<'a, M, T> -where - M: RawMutex, - T: ?Sized, -{ -} - -impl<'a, M, T> fmt::Debug for MappedRwLockReadGuard<'a, M, T> -where - M: RawMutex, - T: ?Sized + fmt::Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Debug::fmt(&**self, f) - } -} - -impl<'a, M, T> fmt::Display for MappedRwLockReadGuard<'a, M, T> -where - M: RawMutex, - T: ?Sized + fmt::Display, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(&**self, f) - } -} - -/// A handle to a held `RwLock` that has had a function applied to it via [`RwLockWriteGuard::map`] or -/// [`MappedRwLockWriteGuard::map`]. -/// -/// This can be used to hold a subfield of the protected data. -#[clippy::has_significant_drop] -pub struct MappedRwLockWriteGuard<'a, M, T> -where - M: RawMutex, - T: ?Sized, -{ - state: &'a BlockingMutex>, - value: *mut T, -} - -impl<'a, M, T> MappedRwLockWriteGuard<'a, M, T> -where - M: RawMutex, - T: ?Sized, -{ - /// Returns a locked view over a portion of the locked data. - pub fn map(this: Self, fun: impl FnOnce(&mut T) -> &mut U) -> MappedRwLockWriteGuard<'a, M, U> { - let rwlock = this.state; - let value = fun(unsafe { &mut *this.value }); - // Dont run the `drop` method for RwLockWriteGuard. The ownership of the underlying - // locked state is being moved to the returned MappedRwLockWriteGuard. - mem::forget(this); - MappedRwLockWriteGuard { state: rwlock, value } - } -} - -impl<'a, M, T> Deref for MappedRwLockWriteGuard<'a, M, T> -where - M: RawMutex, - T: ?Sized, -{ - type Target = T; - fn deref(&self) -> &Self::Target { - // Safety: the MappedRwLockWriteGuard represents exclusive access to the contents - // of the read-write lock, so it's OK to get it. - unsafe { &*self.value } - } -} - -impl<'a, M, T> DerefMut for MappedRwLockWriteGuard<'a, M, T> -where - M: RawMutex, - T: ?Sized, -{ - fn deref_mut(&mut self) -> &mut Self::Target { - // Safety: the MappedRwLockWriteGuard represents exclusive access to the contents - // of the read-write lock, so it's OK to get it. - unsafe { &mut *self.value } - } -} - -impl<'a, M, T> Drop for MappedRwLockWriteGuard<'a, M, T> -where - M: RawMutex, - T: ?Sized, -{ - fn drop(&mut self) { - self.state.lock(|s| { - let mut s = unwrap!(s.try_borrow_mut()); - s.writer = false; - s.waker.wake(); - }) - } -} - -unsafe impl<'a, M, T> Send for MappedRwLockWriteGuard<'a, M, T> -where - M: RawMutex, - T: ?Sized, -{ -} - -unsafe impl<'a, M, T> Sync for MappedRwLockWriteGuard<'a, M, T> -where - M: RawMutex, - T: ?Sized, -{ -} - -impl<'a, M, T> fmt::Debug for MappedRwLockWriteGuard<'a, M, T> -where - M: RawMutex, - T: ?Sized + fmt::Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Debug::fmt(&**self, f) - } -} - -impl<'a, M, T> fmt::Display for MappedRwLockWriteGuard<'a, M, T> -where - M: RawMutex, - T: ?Sized + fmt::Display, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(&**self, f) - } -} - #[cfg(test)] mod tests { use crate::blocking_mutex::raw::NoopRawMutex; From de064068995e6f9041d8c4f8e5bd78aabf80fd27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anton=20P=C3=B6hl?= Date: Sat, 12 Apr 2025 20:56:00 +0200 Subject: [PATCH 0961/1217] Stm32 usart: Remove meaningless pin configurations --- embassy-stm32/src/usart/mod.rs | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index 6c5d3422b..49f536799 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -142,12 +142,6 @@ pub enum HalfDuplexReadback { pub enum OutputConfig { /// Push pull allows for faster baudrates, no internal pullup PushPull, - #[cfg(not(gpio_v1))] - /// Push pull with internal pull up resistor - PushPullPullUp, - #[cfg(not(gpio_v1))] - /// Push pull with internal pull down resistor - PushPullPullDown, /// Open drain output using external pull down resistor OpenDrainExternal, #[cfg(not(gpio_v1))] @@ -159,10 +153,6 @@ impl OutputConfig { const fn af_type(self) -> AfType { match self { OutputConfig::PushPull => AfType::output(OutputType::PushPull, Speed::Medium), - #[cfg(not(gpio_v1))] - OutputConfig::PushPullPullUp => AfType::output_pull(OutputType::OpenDrain, Speed::Medium, Pull::Up), - #[cfg(not(gpio_v1))] - OutputConfig::PushPullPullDown => AfType::output_pull(OutputType::OpenDrain, Speed::Medium, Pull::Down), OutputConfig::OpenDrainExternal => AfType::output(OutputType::OpenDrain, Speed::Medium), #[cfg(not(gpio_v1))] OutputConfig::OpenDrainInternal => AfType::output_pull(OutputType::OpenDrain, Speed::Medium, Pull::Up), From 88b57529603d361412d479855360009abf5d2f90 Mon Sep 17 00:00:00 2001 From: Mark Murphy Date: Sat, 12 Apr 2025 21:02:51 -0400 Subject: [PATCH 0962/1217] Update blinky_wifi example name The RP pico w 2 blinky example is currently called `blinky_wifi` --- examples/rp235x/src/bin/blinky.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/rp235x/src/bin/blinky.rs b/examples/rp235x/src/bin/blinky.rs index 2d962baca..a36029f92 100644 --- a/examples/rp235x/src/bin/blinky.rs +++ b/examples/rp235x/src/bin/blinky.rs @@ -1,6 +1,6 @@ //! This example test the RP Pico on board LED. //! -//! It does not work with the RP Pico W board. See wifi_blinky.rs. +//! It does not work with the RP Pico W board. See `blinky_wifi.rs`. #![no_std] #![no_main] From db83d7275e63ba2a277f50138a6bd38baedf6937 Mon Sep 17 00:00:00 2001 From: iliana etaoin Date: Sun, 13 Apr 2025 00:26:43 -0700 Subject: [PATCH 0963/1217] cyw43: make State::new a const fn --- cyw43/src/events.rs | 25 ++++++++++++++++++++----- cyw43/src/ioctl.rs | 8 ++++---- cyw43/src/lib.rs | 2 +- 3 files changed, 25 insertions(+), 10 deletions(-) diff --git a/cyw43/src/events.rs b/cyw43/src/events.rs index 44bfa98e9..2a78b38c3 100644 --- a/cyw43/src/events.rs +++ b/cyw43/src/events.rs @@ -296,10 +296,10 @@ pub struct Events { } impl Events { - pub fn new() -> Self { + pub const fn new() -> Self { Self { queue: EventQueue::new(), - mask: SharedEventMask::default(), + mask: SharedEventMask::new(), } } } @@ -333,7 +333,6 @@ impl Message { } } -#[derive(Default)] struct EventMask { mask: [u32; Self::WORD_COUNT], } @@ -341,6 +340,12 @@ struct EventMask { impl EventMask { const WORD_COUNT: usize = ((Event::LAST as u32 + (u32::BITS - 1)) / u32::BITS) as usize; + const fn new() -> Self { + Self { + mask: [0; Self::WORD_COUNT], + } + } + fn enable(&mut self, event: Event) { let n = event as u32; let word = n / u32::BITS; @@ -366,13 +371,17 @@ impl EventMask { } } -#[derive(Default)] - pub struct SharedEventMask { mask: RefCell, } impl SharedEventMask { + pub const fn new() -> Self { + Self { + mask: RefCell::new(EventMask::new()), + } + } + pub fn enable(&self, events: &[Event]) { let mut mask = self.mask.borrow_mut(); for event in events { @@ -398,3 +407,9 @@ impl SharedEventMask { mask.is_enabled(event) } } + +impl Default for SharedEventMask { + fn default() -> Self { + Self::new() + } +} diff --git a/cyw43/src/ioctl.rs b/cyw43/src/ioctl.rs index af8bb695b..35135e296 100644 --- a/cyw43/src/ioctl.rs +++ b/cyw43/src/ioctl.rs @@ -33,8 +33,8 @@ struct Wakers { runner: WakerRegistration, } -impl Default for Wakers { - fn default() -> Self { +impl Wakers { + const fn new() -> Self { Self { control: WakerRegistration::new(), runner: WakerRegistration::new(), @@ -48,10 +48,10 @@ pub struct IoctlState { } impl IoctlState { - pub fn new() -> Self { + pub const fn new() -> Self { Self { state: Cell::new(IoctlStateInner::Done { resp_len: 0 }), - wakers: Default::default(), + wakers: RefCell::new(Wakers::new()), } } diff --git a/cyw43/src/lib.rs b/cyw43/src/lib.rs index aab13d8b8..16b436e66 100644 --- a/cyw43/src/lib.rs +++ b/cyw43/src/lib.rs @@ -124,7 +124,7 @@ struct NetState { impl State { /// Create new driver state holder. - pub fn new() -> Self { + pub const fn new() -> Self { Self { ioctl_state: IoctlState::new(), net: NetState { From 6719e1305921c08fcfba7e8f48e315ef8b676c6e Mon Sep 17 00:00:00 2001 From: 1-rafael-1 Date: Sun, 13 Apr 2025 22:23:07 +0200 Subject: [PATCH 0964/1217] update documentation and examples to mention RP235x --- docs/pages/faq.adoc | 2 +- docs/pages/hal.adoc | 2 +- docs/pages/overview.adoc | 2 +- embassy-rp/Cargo.toml | 4 ++-- embassy-rp/README.md | 2 +- examples/rp235x/src/bin/adc.rs | 4 ++-- examples/rp235x/src/bin/adc_dma.rs | 2 +- examples/rp235x/src/bin/blinky_wifi.rs | 4 ++-- examples/rp235x/src/bin/blinky_wifi_pico_plus_2.rs | 4 ++-- examples/rp235x/src/bin/gpio_async.rs | 2 +- examples/rp235x/src/bin/multicore.rs | 2 +- examples/rp235x/src/bin/pio_async.rs | 2 +- examples/rp235x/src/bin/pio_dma.rs | 2 +- examples/rp235x/src/bin/pio_hd44780.rs | 4 ++-- examples/rp235x/src/bin/pio_i2s.rs | 2 +- examples/rp235x/src/bin/pio_pwm.rs | 2 +- examples/rp235x/src/bin/pio_rotary_encoder.rs | 2 +- examples/rp235x/src/bin/pio_servo.rs | 2 +- examples/rp235x/src/bin/pio_stepper.rs | 2 +- examples/rp235x/src/bin/pio_uart.rs | 4 ++-- examples/rp235x/src/bin/pio_ws2812.rs | 2 +- examples/rp235x/src/bin/spi.rs | 2 +- examples/rp235x/src/bin/spi_async.rs | 2 +- examples/rp235x/src/bin/spi_display.rs | 2 +- examples/rp235x/src/bin/spi_sdmmc.rs | 2 +- examples/rp235x/src/bin/uart.rs | 2 +- examples/rp235x/src/bin/uart_buffered_split.rs | 2 +- examples/rp235x/src/bin/uart_unidir.rs | 2 +- examples/rp235x/src/bin/usb_webusb.rs | 2 +- examples/rp235x/src/bin/watchdog.rs | 2 +- examples/rp235x/src/bin/zerocopy.rs | 2 +- 31 files changed, 37 insertions(+), 37 deletions(-) diff --git a/docs/pages/faq.adoc b/docs/pages/faq.adoc index 88e0c3330..3b5eafa99 100644 --- a/docs/pages/faq.adoc +++ b/docs/pages/faq.adoc @@ -4,7 +4,7 @@ These are a list of unsorted, commonly asked questions and answers. Please feel free to add items to link:https://github.com/embassy-rs/embassy/edit/main/docs/pages/faq.adoc[this page], especially if someone in the chat answered a question for you! -== How to deploy to RP2040 without a debugging probe. +== How to deploy to RP2040 or RP235x without a debugging probe. Install link:https://github.com/JoNil/elf2uf2-rs[elf2uf2-rs] for converting the generated elf binary into a uf2 file. diff --git a/docs/pages/hal.adoc b/docs/pages/hal.adoc index 3c6839792..3bbe94e02 100644 --- a/docs/pages/hal.adoc +++ b/docs/pages/hal.adoc @@ -4,7 +4,7 @@ Embassy provides HALs for several microcontroller families: * `embassy-nrf` for the nRF microcontrollers from Nordic Semiconductor * `embassy-stm32` for STM32 microcontrollers from ST Microelectronics -* `embassy-rp` for the Raspberry Pi RP2040 microcontrollers +* `embassy-rp` for the Raspberry Pi RP2040 and RP235x microcontrollers These HALs implement async/await functionality for most peripherals while also implementing the async traits in `embedded-hal` and `embedded-hal-async`. You can also use these HALs with another executor. diff --git a/docs/pages/overview.adoc b/docs/pages/overview.adoc index b169c686e..acd757795 100644 --- a/docs/pages/overview.adoc +++ b/docs/pages/overview.adoc @@ -28,7 +28,7 @@ The Embassy project maintains HALs for select hardware, but you can still use HA * link:https://docs.embassy.dev/embassy-stm32/[embassy-stm32], for all STM32 microcontroller families. * link:https://docs.embassy.dev/embassy-nrf/[embassy-nrf], for the Nordic Semiconductor nRF52, nRF53, nRF91 series. -* link:https://docs.embassy.dev/embassy-rp/[embassy-rp], for the Raspberry Pi RP2040 microcontroller. +* link:https://docs.embassy.dev/embassy-rp/[embassy-rp], for the Raspberry Pi RP2040 as well as RP235x microcontroller. * link:https://docs.embassy.dev/embassy-mspm0/[embassy-mspm0], for the Texas Instruments MSPM0 microcontrollers. * link:https://github.com/esp-rs[esp-rs], for the Espressif Systems ESP32 series of chips. * link:https://github.com/ch32-rs/ch32-hal[ch32-hal], for the WCH 32-bit RISC-V(CH32V) series of chips. diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index 4e5ef2813..b440591cf 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml @@ -3,8 +3,8 @@ name = "embassy-rp" version = "0.4.0" edition = "2021" license = "MIT OR Apache-2.0" -description = "Embassy Hardware Abstraction Layer (HAL) for the Raspberry Pi RP2040 microcontroller" -keywords = ["embedded", "async", "raspberry-pi", "rp2040", "embedded-hal"] +description = "Embassy Hardware Abstraction Layer (HAL) for the Raspberry Pi RP2040 or RP235x microcontroller" +keywords = ["embedded", "async", "rp235x", "rp2040", "embedded-hal"] categories = ["embedded", "hardware-support", "no-std", "asynchronous"] repository = "https://github.com/embassy-rs/embassy" documentation = "https://docs.embassy.dev/embassy-rp" diff --git a/embassy-rp/README.md b/embassy-rp/README.md index 16b189344..8e16184b8 100644 --- a/embassy-rp/README.md +++ b/embassy-rp/README.md @@ -2,7 +2,7 @@ HALs implement safe, idiomatic Rust APIs to use the hardware capabilities, so raw register manipulation is not needed. -The embassy-rp HAL targets the Raspberry Pi RP2040 microcontroller. The HAL implements both blocking and async APIs +The embassy-rp HAL targets the Raspberry Pi RP2040 as well as RP235x microcontroller. The HAL implements both blocking and async APIs for many peripherals. The benefit of using the async APIs is that the HAL takes care of waiting for peripherals to complete operations in low power mode and handling interrupts, so that applications can focus on more important matters. diff --git a/examples/rp235x/src/bin/adc.rs b/examples/rp235x/src/bin/adc.rs index b7324f755..b2a83e376 100644 --- a/examples/rp235x/src/bin/adc.rs +++ b/examples/rp235x/src/bin/adc.rs @@ -40,8 +40,8 @@ async fn main(_spawner: Spawner) { } fn convert_to_celsius(raw_temp: u16) -> f32 { - // According to chapter 4.9.5. Temperature Sensor in RP2040 datasheet - let temp = 27.0 - (raw_temp as f32 * 3.3 / 4096.0 - 0.706) / 0.001721; + // According to chapter 12.4.6 Temperature Sensor in RP235x datasheet + let temp = 27.0 - (raw_temp as f32 * 3.3 / 4096.0 - ..0.706) / 0.0..01721; let sign = if temp < 0.0 { -1.0 } else { 1.0 }; let rounded_temp_x10: i16 = ((temp * 10.0) + 0.5 * sign) as i16; (rounded_temp_x10 as f32) / 10.0 diff --git a/examples/rp235x/src/bin/adc_dma.rs b/examples/rp235x/src/bin/adc_dma.rs index b42c13fde..4003cc078 100644 --- a/examples/rp235x/src/bin/adc_dma.rs +++ b/examples/rp235x/src/bin/adc_dma.rs @@ -1,4 +1,4 @@ -//! This example shows how to use the RP2040 ADC with DMA, both single- and multichannel reads. +//! This example shows how to use the RP235x ADC with DMA, both single- and multichannel reads. //! For multichannel, the samples are interleaved in the buffer: //! `[ch1, ch2, ch3, ch4, ch1, ch2, ch3, ch4, ...]` #![no_std] diff --git a/examples/rp235x/src/bin/blinky_wifi.rs b/examples/rp235x/src/bin/blinky_wifi.rs index 7aeb38f1e..ef029867a 100644 --- a/examples/rp235x/src/bin/blinky_wifi.rs +++ b/examples/rp235x/src/bin/blinky_wifi.rs @@ -47,8 +47,8 @@ async fn main(spawner: Spawner) { // To make flashing faster for development, you may want to flash the firmwares independently // at hardcoded addresses, instead of baking them into the program with `include_bytes!`: - // probe-rs download ../../cyw43-firmware/43439A0.bin --binary-format bin --chip RP2040 --base-address 0x10100000 - // probe-rs download ../../cyw43-firmware/43439A0_clm.bin --binary-format bin --chip RP2040 --base-address 0x10140000 + // probe-rs download ../../cyw43-firmware/43439A0.bin --binary-format bin --chip RP235x --base-address 0x10100000 + // probe-rs download ../../cyw43-firmware/43439A0_clm.bin --binary-format bin --chip RP235x --base-address 0x10140000 //let fw = unsafe { core::slice::from_raw_parts(0x10100000 as *const u8, 230321) }; //let clm = unsafe { core::slice::from_raw_parts(0x10140000 as *const u8, 4752) }; diff --git a/examples/rp235x/src/bin/blinky_wifi_pico_plus_2.rs b/examples/rp235x/src/bin/blinky_wifi_pico_plus_2.rs index d49d2e34f..2a919a1ea 100644 --- a/examples/rp235x/src/bin/blinky_wifi_pico_plus_2.rs +++ b/examples/rp235x/src/bin/blinky_wifi_pico_plus_2.rs @@ -46,8 +46,8 @@ async fn main(spawner: Spawner) { // To make flashing faster for development, you may want to flash the firmwares independently // at hardcoded addresses, instead of baking them into the program with `include_bytes!`: - // probe-rs download ../../cyw43-firmware/43439A0.bin --binary-format bin --chip RP2040 --base-address 0x10100000 - // probe-rs download ../../cyw43-firmware/43439A0_clm.bin --binary-format bin --chip RP2040 --base-address 0x10140000 + // probe-rs download ../../cyw43-firmware/43439A0.bin --binary-format bin --chip RP235x --base-address 0x10100000 + // probe-rs download ../../cyw43-firmware/43439A0_clm.bin --binary-format bin --chip RP235x --base-address 0x10140000 //let fw = unsafe { core::slice::from_raw_parts(0x10100000 as *const u8, 230321) }; //let clm = unsafe { core::slice::from_raw_parts(0x10140000 as *const u8, 4752) }; diff --git a/examples/rp235x/src/bin/gpio_async.rs b/examples/rp235x/src/bin/gpio_async.rs index b79fb2a15..3be8569bc 100644 --- a/examples/rp235x/src/bin/gpio_async.rs +++ b/examples/rp235x/src/bin/gpio_async.rs @@ -1,4 +1,4 @@ -//! This example shows how async gpio can be used with a RP2040. +//! This example shows how async gpio can be used with a RP235x. //! //! The LED on the RP Pico W board is connected differently. See wifi_blinky.rs. diff --git a/examples/rp235x/src/bin/multicore.rs b/examples/rp235x/src/bin/multicore.rs index 7cb546c91..f02dc3876 100644 --- a/examples/rp235x/src/bin/multicore.rs +++ b/examples/rp235x/src/bin/multicore.rs @@ -1,4 +1,4 @@ -//! This example shows how to send messages between the two cores in the RP2040 chip. +//! This example shows how to send messages between the two cores in the RP235x chip. //! //! The LED on the RP Pico W board is connected differently. See wifi_blinky.rs. diff --git a/examples/rp235x/src/bin/pio_async.rs b/examples/rp235x/src/bin/pio_async.rs index baf567b58..a519b8a50 100644 --- a/examples/rp235x/src/bin/pio_async.rs +++ b/examples/rp235x/src/bin/pio_async.rs @@ -1,4 +1,4 @@ -//! This example shows powerful PIO module in the RP2040 chip. +//! This example shows powerful PIO module in the RP235x chip. #![no_std] #![no_main] diff --git a/examples/rp235x/src/bin/pio_dma.rs b/examples/rp235x/src/bin/pio_dma.rs index 64d603ba4..17332a238 100644 --- a/examples/rp235x/src/bin/pio_dma.rs +++ b/examples/rp235x/src/bin/pio_dma.rs @@ -1,4 +1,4 @@ -//! This example shows powerful PIO module in the RP2040 chip. +//! This example shows powerful PIO module in the RP235x chip. #![no_std] #![no_main] diff --git a/examples/rp235x/src/bin/pio_hd44780.rs b/examples/rp235x/src/bin/pio_hd44780.rs index 164e6f8d3..06d989505 100644 --- a/examples/rp235x/src/bin/pio_hd44780.rs +++ b/examples/rp235x/src/bin/pio_hd44780.rs @@ -1,4 +1,4 @@ -//! This example shows powerful PIO module in the RP2040 chip to communicate with a HD44780 display. +//! This example shows powerful PIO module in the RP235x chip to communicate with a HD44780 display. //! See (https://www.sparkfun.com/datasheets/LCD/HD44780.pdf) #![no_std] @@ -30,7 +30,7 @@ async fn main(_spawner: Spawner) { // db6 = PIN5 // db7 = PIN6 // additionally a pwm signal for a bias voltage charge pump is provided on pin 15, - // allowing direct connection of the display to the RP2040 without level shifters. + // allowing direct connection of the display to the RP235x without level shifters. let p = embassy_rp::init(Default::default()); let _pwm = Pwm::new_output_b(p.PWM_SLICE7, p.PIN_15, { diff --git a/examples/rp235x/src/bin/pio_i2s.rs b/examples/rp235x/src/bin/pio_i2s.rs index ae937a4ed..5a4bcfcac 100644 --- a/examples/rp235x/src/bin/pio_i2s.rs +++ b/examples/rp235x/src/bin/pio_i2s.rs @@ -1,5 +1,5 @@ //! This example shows generating audio and sending it to a connected i2s DAC using the PIO -//! module of the RP2040. +//! module of the RP235x. //! //! Connect the i2s DAC as follows: //! bclk : GPIO 18 diff --git a/examples/rp235x/src/bin/pio_pwm.rs b/examples/rp235x/src/bin/pio_pwm.rs index 7eabb2289..5712b5b91 100644 --- a/examples/rp235x/src/bin/pio_pwm.rs +++ b/examples/rp235x/src/bin/pio_pwm.rs @@ -1,4 +1,4 @@ -//! This example shows how to create a pwm using the PIO module in the RP2040 chip. +//! This example shows how to create a pwm using the PIO module in the RP235x chip. #![no_std] #![no_main] diff --git a/examples/rp235x/src/bin/pio_rotary_encoder.rs b/examples/rp235x/src/bin/pio_rotary_encoder.rs index 2750f61ae..e820d316d 100644 --- a/examples/rp235x/src/bin/pio_rotary_encoder.rs +++ b/examples/rp235x/src/bin/pio_rotary_encoder.rs @@ -1,4 +1,4 @@ -//! This example shows how to use the PIO module in the RP2040 to read a quadrature rotary encoder. +//! This example shows how to use the PIO module in the RP235x to read a quadrature rotary encoder. #![no_std] #![no_main] diff --git a/examples/rp235x/src/bin/pio_servo.rs b/examples/rp235x/src/bin/pio_servo.rs index c52ee7492..086b02f03 100644 --- a/examples/rp235x/src/bin/pio_servo.rs +++ b/examples/rp235x/src/bin/pio_servo.rs @@ -1,4 +1,4 @@ -//! This example shows how to create a pwm using the PIO module in the RP2040 chip. +//! This example shows how to create a pwm using the PIO module in the RP235x chip. #![no_std] #![no_main] diff --git a/examples/rp235x/src/bin/pio_stepper.rs b/examples/rp235x/src/bin/pio_stepper.rs index 3862c248b..931adbeda 100644 --- a/examples/rp235x/src/bin/pio_stepper.rs +++ b/examples/rp235x/src/bin/pio_stepper.rs @@ -1,4 +1,4 @@ -//! This example shows how to use the PIO module in the RP2040 to implement a stepper motor driver +//! This example shows how to use the PIO module in the RP235x to implement a stepper motor driver //! for a 5-wire stepper such as the 28BYJ-48. You can halt an ongoing rotation by dropping the future. #![no_std] diff --git a/examples/rp235x/src/bin/pio_uart.rs b/examples/rp235x/src/bin/pio_uart.rs index 9712984f9..d92e33feb 100644 --- a/examples/rp235x/src/bin/pio_uart.rs +++ b/examples/rp235x/src/bin/pio_uart.rs @@ -1,10 +1,10 @@ -//! This example shows how to use the PIO module in the RP2040 chip to implement a duplex UART. +//! This example shows how to use the PIO module in the RP235x chip to implement a duplex UART. //! The PIO module is a very powerful peripheral that can be used to implement many different //! protocols. It is a very flexible state machine that can be programmed to do almost anything. //! //! This example opens up a USB device that implements a CDC ACM serial port. It then uses the //! PIO module to implement a UART that is connected to the USB serial port. This allows you to -//! communicate with a device connected to the RP2040 over USB serial. +//! communicate with a device connected to the RP235x over USB serial. #![no_std] #![no_main] diff --git a/examples/rp235x/src/bin/pio_ws2812.rs b/examples/rp235x/src/bin/pio_ws2812.rs index d1fcfc471..42694c527 100644 --- a/examples/rp235x/src/bin/pio_ws2812.rs +++ b/examples/rp235x/src/bin/pio_ws2812.rs @@ -1,4 +1,4 @@ -//! This example shows powerful PIO module in the RP2040 chip to communicate with WS2812 LED modules. +//! This example shows powerful PIO module in the RP235x chip to communicate with WS2812 LED modules. //! See (https://www.sparkfun.com/categories/tags/ws2812) #![no_std] diff --git a/examples/rp235x/src/bin/spi.rs b/examples/rp235x/src/bin/spi.rs index 4cc4f5210..308f05c01 100644 --- a/examples/rp235x/src/bin/spi.rs +++ b/examples/rp235x/src/bin/spi.rs @@ -1,4 +1,4 @@ -//! This example shows how to use SPI (Serial Peripheral Interface) in the RP2040 chip. +//! This example shows how to use SPI (Serial Peripheral Interface) in the RP235x chip. //! //! Example for resistive touch sensor in Waveshare Pico-ResTouch diff --git a/examples/rp235x/src/bin/spi_async.rs b/examples/rp235x/src/bin/spi_async.rs index 266584efc..62bedc68a 100644 --- a/examples/rp235x/src/bin/spi_async.rs +++ b/examples/rp235x/src/bin/spi_async.rs @@ -1,4 +1,4 @@ -//! This example shows how to use SPI (Serial Peripheral Interface) in the RP2040 chip. +//! This example shows how to use SPI (Serial Peripheral Interface) in the RP235x chip. //! No specific hardware is specified in this example. If you connect pin 11 and 12 you should get the same data back. #![no_std] diff --git a/examples/rp235x/src/bin/spi_display.rs b/examples/rp235x/src/bin/spi_display.rs index 9c524ab25..9967abefd 100644 --- a/examples/rp235x/src/bin/spi_display.rs +++ b/examples/rp235x/src/bin/spi_display.rs @@ -95,7 +95,7 @@ async fn main(_spawner: Spawner) { let style = MonoTextStyle::new(&FONT_10X20, Rgb565::GREEN); Text::new( - "Hello embedded_graphics \n + embassy + RP2040!", + "Hello embedded_graphics \n + embassy + RP235x!", Point::new(20, 200), style, ) diff --git a/examples/rp235x/src/bin/spi_sdmmc.rs b/examples/rp235x/src/bin/spi_sdmmc.rs index 9808b6a5d..e14a62c31 100644 --- a/examples/rp235x/src/bin/spi_sdmmc.rs +++ b/examples/rp235x/src/bin/spi_sdmmc.rs @@ -1,4 +1,4 @@ -//! This example shows how to use `embedded-sdmmc` with the RP2040 chip, over SPI. +//! This example shows how to use `embedded-sdmmc` with the RP235x chip, over SPI. //! //! The example will attempt to read a file `MY_FILE.TXT` from the root directory //! of the SD card and print its contents. diff --git a/examples/rp235x/src/bin/uart.rs b/examples/rp235x/src/bin/uart.rs index a59f537bf..ed912b959 100644 --- a/examples/rp235x/src/bin/uart.rs +++ b/examples/rp235x/src/bin/uart.rs @@ -1,4 +1,4 @@ -//! This example shows how to use UART (Universal asynchronous receiver-transmitter) in the RP2040 chip. +//! This example shows how to use UART (Universal asynchronous receiver-transmitter) in the RP235x chip. //! //! No specific hardware is specified in this example. Only output on pin 0 is tested. //! The Raspberry Pi Debug Probe (https://www.raspberrypi.com/products/debug-probe/) could be used diff --git a/examples/rp235x/src/bin/uart_buffered_split.rs b/examples/rp235x/src/bin/uart_buffered_split.rs index da7e94139..f707c4b5e 100644 --- a/examples/rp235x/src/bin/uart_buffered_split.rs +++ b/examples/rp235x/src/bin/uart_buffered_split.rs @@ -1,4 +1,4 @@ -//! This example shows how to use UART (Universal asynchronous receiver-transmitter) in the RP2040 chip. +//! This example shows how to use UART (Universal asynchronous receiver-transmitter) in the RP235x chip. //! //! No specific hardware is specified in this example. If you connect pin 0 and 1 you should get the same data back. //! The Raspberry Pi Debug Probe (https://www.raspberrypi.com/products/debug-probe/) could be used diff --git a/examples/rp235x/src/bin/uart_unidir.rs b/examples/rp235x/src/bin/uart_unidir.rs index a45f40756..4e98f9e1e 100644 --- a/examples/rp235x/src/bin/uart_unidir.rs +++ b/examples/rp235x/src/bin/uart_unidir.rs @@ -1,4 +1,4 @@ -//! This example shows how to use UART (Universal asynchronous receiver-transmitter) in the RP2040 chip. +//! This example shows how to use UART (Universal asynchronous receiver-transmitter) in the RP235x chip. //! //! Test TX-only and RX-only on two different UARTs. You need to connect GPIO0 to GPIO5 for //! this to work diff --git a/examples/rp235x/src/bin/usb_webusb.rs b/examples/rp235x/src/bin/usb_webusb.rs index a5dc94d5b..75d28c853 100644 --- a/examples/rp235x/src/bin/usb_webusb.rs +++ b/examples/rp235x/src/bin/usb_webusb.rs @@ -1,4 +1,4 @@ -//! This example shows how to use USB (Universal Serial Bus) in the RP2040 chip. +//! This example shows how to use USB (Universal Serial Bus) in the RP235x chip. //! //! This creates a WebUSB capable device that echoes data back to the host. //! diff --git a/examples/rp235x/src/bin/watchdog.rs b/examples/rp235x/src/bin/watchdog.rs index b9d4ef22f..a54ec493a 100644 --- a/examples/rp235x/src/bin/watchdog.rs +++ b/examples/rp235x/src/bin/watchdog.rs @@ -1,4 +1,4 @@ -//! This example shows how to use Watchdog in the RP2040 chip. +//! This example shows how to use Watchdog in the RP235x chip. //! //! It does not work with the RP Pico W board. See wifi_blinky.rs or connect external LED and resistor. diff --git a/examples/rp235x/src/bin/zerocopy.rs b/examples/rp235x/src/bin/zerocopy.rs index d1fb0eb00..086c86cac 100644 --- a/examples/rp235x/src/bin/zerocopy.rs +++ b/examples/rp235x/src/bin/zerocopy.rs @@ -1,6 +1,6 @@ //! This example shows how to use `zerocopy_channel` from `embassy_sync` for //! sending large values between two tasks without copying. -//! The example also shows how to use the RP2040 ADC with DMA. +//! The example also shows how to use the RP235x ADC with DMA. #![no_std] #![no_main] From 642740b8cbff7099e452337c8fcb6fd78eb0567e Mon Sep 17 00:00:00 2001 From: 1-rafael-1 Date: Sun, 13 Apr 2025 22:33:10 +0200 Subject: [PATCH 0965/1217] update WiFi credentials to placeholders --- examples/rp/src/bin/wifi_tcp_server.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/rp/src/bin/wifi_tcp_server.rs b/examples/rp/src/bin/wifi_tcp_server.rs index 14dbf4552..7e3c663fe 100644 --- a/examples/rp/src/bin/wifi_tcp_server.rs +++ b/examples/rp/src/bin/wifi_tcp_server.rs @@ -28,8 +28,8 @@ bind_interrupts!(struct Irqs { PIO0_IRQ_0 => InterruptHandler; }); -const WIFI_NETWORK: &str = "LadronDeWifi"; -const WIFI_PASSWORD: &str = "MBfcaedHmyRFE4kaQ1O5SsY8"; +const WIFI_NETWORK: &str = "ssid"; // change to your network SSID +const WIFI_PASSWORD: &str = "pwd"; // change to your network password #[embassy_executor::task] async fn cyw43_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>) -> ! { From bed6dde744d6e2f2e8af42dfc3a39d80d29d1ad2 Mon Sep 17 00:00:00 2001 From: rafael Date: Mon, 14 Apr 2025 09:23:32 +0200 Subject: [PATCH 0966/1217] Update adc.rs --- examples/rp235x/src/bin/adc.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/rp235x/src/bin/adc.rs b/examples/rp235x/src/bin/adc.rs index b2a83e376..0a462bebd 100644 --- a/examples/rp235x/src/bin/adc.rs +++ b/examples/rp235x/src/bin/adc.rs @@ -1,4 +1,4 @@ -//! This example test the ADC (Analog to Digital Conversion) of the RP2350A pins 26, 27 and 28. +o//! This example test the ADC (Analog to Digital Conversion) of the RP2350A pins 26, 27 and 28. //! It also reads the temperature sensor in the chip. #![no_std] @@ -41,7 +41,7 @@ async fn main(_spawner: Spawner) { fn convert_to_celsius(raw_temp: u16) -> f32 { // According to chapter 12.4.6 Temperature Sensor in RP235x datasheet - let temp = 27.0 - (raw_temp as f32 * 3.3 / 4096.0 - ..0.706) / 0.0..01721; + let temp = 27.0 - (raw_temp as f32 * 3.3 / 4096.0 - 0.706) / 0.001721; let sign = if temp < 0.0 { -1.0 } else { 1.0 }; let rounded_temp_x10: i16 = ((temp * 10.0) + 0.5 * sign) as i16; (rounded_temp_x10 as f32) / 10.0 From 4e90c535d24b4c575c2fc63556738ebc24ddab5f Mon Sep 17 00:00:00 2001 From: rafael Date: Mon, 14 Apr 2025 09:26:53 +0200 Subject: [PATCH 0967/1217] Update adc.rs --- examples/rp235x/src/bin/adc.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/rp235x/src/bin/adc.rs b/examples/rp235x/src/bin/adc.rs index 0a462bebd..5c4135268 100644 --- a/examples/rp235x/src/bin/adc.rs +++ b/examples/rp235x/src/bin/adc.rs @@ -1,4 +1,4 @@ -o//! This example test the ADC (Analog to Digital Conversion) of the RP2350A pins 26, 27 and 28. +//! This example test the ADC (Analog to Digital Conversion) of the RP2350A pins 26, 27 and 28. //! It also reads the temperature sensor in the chip. #![no_std] From bbfebf968e31815a78ba9f19e7a6b2e26bad7456 Mon Sep 17 00:00:00 2001 From: Ivan Li Date: Mon, 14 Apr 2025 17:52:36 +0800 Subject: [PATCH 0968/1217] feat(embassy-stm32/opamp): Add some stm32g4 opamp usage Signed-off-by: Ivan Li --- embassy-stm32/build.rs | 12 + embassy-stm32/src/opamp.rs | 357 ++++++++++++++++++++++++++-- examples/stm32f334/src/bin/opamp.rs | 4 +- 3 files changed, 346 insertions(+), 27 deletions(-) diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index d965d8732..19851ee66 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -1338,6 +1338,18 @@ fn main() { g.extend(quote! { impl_opamp_vp_pin!( #peri, #pin_name, #ch); }) + } else if pin.signal.starts_with("VINM") { + // Impl NonInvertingPin for the VINM* signals ( VINM0, VINM1, etc) + // STM32G4 + let peri = format_ident!("{}", p.name); + let pin_name = format_ident!("{}", pin.pin); + let ch: Result = pin.signal.strip_prefix("VINM").unwrap().parse(); + + if let Ok(ch) = ch { + g.extend(quote! { + impl_opamp_vn_pin!( #peri, #pin_name, #ch); + }) + } } else if pin.signal == "VOUT" { // Impl OutputPin for the VOUT pin let peri = format_ident!("{}", p.name); diff --git a/embassy-stm32/src/opamp.rs b/embassy-stm32/src/opamp.rs index a81493c1b..82de4a89b 100644 --- a/embassy-stm32/src/opamp.rs +++ b/embassy-stm32/src/opamp.rs @@ -6,15 +6,33 @@ use embassy_hal_internal::PeripheralType; use crate::pac::opamp::vals::*; use crate::Peri; +/// Performs a busy-wait delay for a specified number of microseconds. +#[cfg(opamp_g4)] +fn blocking_delay_ms(ms: u32) { + #[cfg(feature = "time")] + embassy_time::block_for(embassy_time::Duration::from_millis(ms as u64)); + #[cfg(not(feature = "time"))] + cortex_m::asm::delay(unsafe { crate::rcc::get_freqs() }.sys.to_hertz().unwrap().0 / 1_000 * ms); +} + /// Gain #[allow(missing_docs)] #[derive(Clone, Copy)] pub enum OpAmpGain { - Mul1, Mul2, Mul4, Mul8, Mul16, + #[cfg(opamp_g4)] + Mul32, + #[cfg(opamp_g4)] + Mul64, +} + +#[cfg(opamp_g4)] +enum OpAmpDifferentialPair { + P, + N, } /// Speed @@ -82,24 +100,18 @@ impl<'d, T: Instance> OpAmp<'d, T> { &mut self, in_pin: Peri<'_, impl NonInvertingPin + crate::gpio::Pin>, out_pin: Peri<'_, impl OutputPin + crate::gpio::Pin>, - gain: OpAmpGain, ) -> OpAmpOutput<'_, T> { in_pin.set_as_analog(); out_pin.set_as_analog(); - // PGA_GAIN value may have different meaning in different MCU serials, use with caution. - let (vm_sel, pga_gain) = match gain { - OpAmpGain::Mul1 => (0b11, 0b00), - OpAmpGain::Mul2 => (0b10, 0b00), - OpAmpGain::Mul4 => (0b10, 0b01), - OpAmpGain::Mul8 => (0b10, 0b10), - OpAmpGain::Mul16 => (0b10, 0b11), - }; + #[cfg(opamp_g4)] + let vm_sel = VmSel::OUTPUT; + #[cfg(not(opamp_g4))] + let vm_sel = VmSel::from_bits(0b11); T::regs().csr().modify(|w| { w.set_vp_sel(VpSel::from_bits(in_pin.channel())); - w.set_vm_sel(VmSel::from_bits(vm_sel)); - w.set_pga_gain(PgaGain::from_bits(pga_gain)); + w.set_vm_sel(vm_sel); #[cfg(opamp_g4)] w.set_opaintoen(Opaintoen::OUTPUT_PIN); w.set_opampen(true); @@ -107,6 +119,60 @@ impl<'d, T: Instance> OpAmp<'d, T> { OpAmpOutput { _inner: self } } + + /// Configure the OpAmp as a PGA for the provided input pin, + /// outputting to the provided output pin, and enable the opamp. + /// + /// The input pin is configured for analogue mode but not consumed, + /// so it may subsequently be used for ADC or comparator inputs. + /// + /// The output pin is held within the returned [`OpAmpOutput`] struct, + /// preventing it being used elsewhere. The `OpAmpOutput` can then be + /// directly used as an ADC input. The opamp will be disabled when the + /// [`OpAmpOutput`] is dropped. + pub fn pga_ext( + &mut self, + in_pin: Peri<'_, impl NonInvertingPin + crate::gpio::Pin>, + out_pin: Peri<'_, impl OutputPin + crate::gpio::Pin>, + gain: OpAmpGain, + ) -> OpAmpOutput<'_, T> { + in_pin.set_as_analog(); + out_pin.set_as_analog(); + + #[cfg(opamp_g4)] + let vm_sel = VmSel::PGA; + #[cfg(not(opamp_g4))] + let vm_sel = VmSel::from_bits(0b10); + + #[cfg(opamp_g4)] + let pga_gain = match gain { + OpAmpGain::Mul2 => PgaGain::GAIN2, + OpAmpGain::Mul4 => PgaGain::GAIN4, + OpAmpGain::Mul8 => PgaGain::GAIN8, + OpAmpGain::Mul16 => PgaGain::GAIN16, + OpAmpGain::Mul32 => PgaGain::GAIN32, + OpAmpGain::Mul64 => PgaGain::GAIN64, + }; + #[cfg(not(opamp_g4))] + let pga_gain = PgaGain::from_bits(match gain { + OpAmpGain::Mul2 => 0b00, + OpAmpGain::Mul4 => 0b01, + OpAmpGain::Mul8 => 0b10, + OpAmpGain::Mul16 => 0b11, + }); + + T::regs().csr().modify(|w| { + w.set_vp_sel(VpSel::from_bits(in_pin.channel())); + w.set_vm_sel(vm_sel); + w.set_pga_gain(pga_gain); + #[cfg(opamp_g4)] + w.set_opaintoen(Opaintoen::OUTPUT_PIN); + w.set_opampen(true); + }); + + OpAmpOutput { _inner: self } + } + /// Configure the OpAmp as a buffer for the DAC it is connected to, /// outputting to the provided output pin, and enable the opamp. /// @@ -142,30 +208,259 @@ impl<'d, T: Instance> OpAmp<'d, T> { pub fn buffer_int( &mut self, pin: Peri<'_, impl NonInvertingPin + crate::gpio::Pin>, - gain: OpAmpGain, ) -> OpAmpInternalOutput<'_, T> { pin.set_as_analog(); - // PGA_GAIN value may have different meaning in different MCU serials, use with caution. - let (vm_sel, pga_gain) = match gain { - OpAmpGain::Mul1 => (0b11, 0b00), - OpAmpGain::Mul2 => (0b10, 0b00), - OpAmpGain::Mul4 => (0b10, 0b01), - OpAmpGain::Mul8 => (0b10, 0b10), - OpAmpGain::Mul16 => (0b10, 0b11), - }; - T::regs().csr().modify(|w| { - use crate::pac::opamp::vals::*; w.set_vp_sel(VpSel::from_bits(pin.channel())); - w.set_vm_sel(VmSel::from_bits(vm_sel)); - w.set_pga_gain(PgaGain::from_bits(pga_gain)); + w.set_vm_sel(VmSel::OUTPUT); + #[cfg(opamp_g4)] w.set_opaintoen(Opaintoen::ADCCHANNEL); w.set_opampen(true); }); OpAmpInternalOutput { _inner: self } } + + /// Configure the OpAmp as a PGA for the provided input pin, + /// with the output only used internally, and enable the opamp. + /// + /// The input pin is configured for analogue mode but not consumed, + /// so it may be subsequently used for ADC or comparator inputs. + /// + /// The returned `OpAmpInternalOutput` struct may be used as an ADC input. + /// The opamp output will be disabled when it is dropped. + #[cfg(opamp_g4)] + pub fn pga_int( + &mut self, + pin: Peri<'_, impl NonInvertingPin + crate::gpio::Pin>, + gain: OpAmpGain, + ) -> OpAmpInternalOutput<'_, T> { + pin.set_as_analog(); + + let pga_gain = match gain { + OpAmpGain::Mul2 => PgaGain::GAIN2, + OpAmpGain::Mul4 => PgaGain::GAIN4, + OpAmpGain::Mul8 => PgaGain::GAIN8, + OpAmpGain::Mul16 => PgaGain::GAIN16, + OpAmpGain::Mul32 => PgaGain::GAIN32, + OpAmpGain::Mul64 => PgaGain::GAIN64, + }; + + T::regs().csr().modify(|w| { + w.set_vp_sel(VpSel::from_bits(pin.channel())); + w.set_vm_sel(VmSel::OUTPUT); + w.set_pga_gain(pga_gain); + w.set_opaintoen(Opaintoen::ADCCHANNEL); + w.set_opampen(true); + }); + + OpAmpInternalOutput { _inner: self } + } + + /// Configure the OpAmp as a standalone DAC with the inverting input + /// connected to the provided pin, and the output is connected + /// internally to an ADC channel. + /// + /// The input pin is configured for analogue mode but not consumed, + /// so it may be subsequently used for ADC or comparator inputs. + /// + /// The returned `OpAmpInternalOutput` struct may be used as an ADC + /// input. The opamp output will be disabled when it is dropped. + #[cfg(opamp_g4)] + pub fn standalone_dac_int( + &mut self, + m_pin: Peri<'_, impl InvertingPin + crate::gpio::Pin>, + ) -> OpAmpInternalOutput<'_, T> { + m_pin.set_as_analog(); + + T::regs().csr().modify(|w| { + use crate::pac::opamp::vals::*; + w.set_vp_sel(VpSel::DAC3_CH1); // Actually DAC3_CHx + w.set_vm_sel(VmSel::from_bits(m_pin.channel())); + w.set_opaintoen(Opaintoen::ADCCHANNEL); + w.set_opampen(true); + }); + + OpAmpInternalOutput { _inner: self } + } + + /// Configure the OpAmp as a standalone DAC with the inverting input + /// connected to the provided pin, and the output connected to the + /// provided pin. + /// + /// The input pin is configured for analogue mode but not consumed, + /// so it may be subsequently used for ADC or comparator inputs. + /// + /// The output pin is held within the returned [`OpAmpOutput`] struct, + /// preventing it being used elsewhere. The opamp will be disabled when + /// the [`OpAmpOutput`] is dropped. + #[cfg(opamp_g4)] + pub fn standalone_dac_ext( + &mut self, + m_pin: Peri<'_, impl InvertingPin + crate::gpio::Pin>, + out_pin: Peri<'_, impl OutputPin + crate::gpio::Pin>, + ) -> OpAmpOutput<'_, T> { + m_pin.set_as_analog(); + out_pin.set_as_analog(); + + T::regs().csr().modify(|w| { + use crate::pac::opamp::vals::*; + w.set_vp_sel(VpSel::DAC3_CH1); // Actually DAC3_CHx + w.set_vm_sel(VmSel::from_bits(m_pin.channel())); + w.set_opaintoen(Opaintoen::OUTPUT_PIN); + w.set_opampen(true); + }); + + OpAmpOutput { _inner: self } + } + + /// Configure the OpAmp in standalone mode with the non-inverting input + /// connected to the provided `p_pin`, the inverting input connected to + /// the `m_pin`, and output to the provided `out_pin`. + /// + /// The input pins are configured for analogue mode but not consumed, + /// allowing their subsequent use for ADC or comparator inputs. + /// + /// The output pin is held within the returned [`OpAmpOutput`] struct, + /// preventing it being used elsewhere. The opamp will be disabled when + /// the [`OpAmpOutput`] is dropped. + #[cfg(opamp_g4)] + pub fn standalone_ext( + &mut self, + p_pin: Peri<'d, impl NonInvertingPin + crate::gpio::Pin>, + m_pin: Peri<'d, impl InvertingPin + crate::gpio::Pin>, + out_pin: Peri<'d, impl OutputPin + crate::gpio::Pin>, + ) -> OpAmpOutput<'_, T> { + p_pin.set_as_analog(); + m_pin.set_as_analog(); + out_pin.set_as_analog(); + + T::regs().csr().modify(|w| { + use crate::pac::opamp::vals::*; + w.set_vp_sel(VpSel::from_bits(p_pin.channel())); + w.set_vm_sel(VmSel::from_bits(m_pin.channel())); + w.set_opaintoen(Opaintoen::OUTPUT_PIN); + w.set_opampen(true); + }); + + OpAmpOutput { _inner: self } + } + + /// Configure the OpAmp in standalone mode with the non-inverting input + /// connected to the provided `p_pin`, the inverting input connected to + /// the `m_pin`, and output is connected to the DAC. + /// + /// The input pins are configured for analogue mode but not consumed, + /// allowing their subsequent use for ADC or comparator inputs. + /// + /// The returned `OpAmpOutput` struct may be used as an ADC + /// input. The opamp output will be disabled when it is dropped. + #[cfg(opamp_g4)] + pub fn standalone_int( + &mut self, + p_pin: Peri<'d, impl NonInvertingPin + crate::gpio::Pin>, + m_pin: Peri<'d, impl InvertingPin + crate::gpio::Pin>, + ) -> OpAmpOutput<'_, T> { + p_pin.set_as_analog(); + m_pin.set_as_analog(); + + T::regs().csr().modify(|w| { + use crate::pac::opamp::vals::*; + w.set_vp_sel(VpSel::from_bits(p_pin.channel())); + w.set_vm_sel(VmSel::from_bits(m_pin.channel())); + w.set_opaintoen(Opaintoen::ADCCHANNEL); + w.set_opampen(true); + }); + + OpAmpOutput { _inner: self } + } + + /// Calibrates the operational amplifier. + /// + /// This function enables the opamp and sets the user trim mode for calibration. + /// Depending on the speed mode of the opamp, it calibrates the differential pair inputs. + /// For normal speed, both the P and N differential pairs are calibrated, + /// while for high-speed mode, only the P differential pair is calibrated. + /// + /// Calibrating a differential pair requires waiting 12ms in the worst case (binary method). + #[cfg(opamp_g4)] + pub fn calibrate(&mut self) { + T::regs().csr().modify(|w| { + w.set_opampen(true); + w.set_calon(true); + w.set_usertrim(Usertrim::USER); + }); + + match T::regs().csr().read().opahsm() { + Opahsm::NORMAL => { + self.calibrate_differential_pair(OpAmpDifferentialPair::P); + self.calibrate_differential_pair(OpAmpDifferentialPair::N); + } + Opahsm::HIGH_SPEED => { + self.calibrate_differential_pair(OpAmpDifferentialPair::P); + } + } + + T::regs().csr().modify(|w| { + w.set_calon(false); + w.set_opampen(false); + }); + } + + /// Calibrate differential pair. + /// + /// The calibration is done by trying different offset values and + /// measuring the outcal bit. + /// + /// The calibration range is from 0 to 31. + /// + /// The result is stored in the OPAMP_CSR register. + #[cfg(opamp_g4)] + fn calibrate_differential_pair(&mut self, pair: OpAmpDifferentialPair) { + let mut low = 0; + let mut high = 31; + + let calsel = match pair { + OpAmpDifferentialPair::P => Calsel::PERCENT10, + OpAmpDifferentialPair::N => Calsel::PERCENT90, + }; + + T::regs().csr().modify(|w| { + w.set_calsel(calsel); + }); + + while low <= high { + let mid = (low + high) / 2; + + T::regs().csr().modify(|w| match pair { + OpAmpDifferentialPair::P => { + defmt::info!("p calibration. offset: {}", mid); + w.set_trimoffsetp(mid); + } + OpAmpDifferentialPair::N => { + defmt::info!("n calibration. offset: {}", mid); + w.set_trimoffsetn(mid); + } + }); + + // The closer the trimming value is to the optimum trimming value, the longer it takes to stabilize + // (with a maximum stabilization time remaining below 2 ms in any case) -- RM0440 25.3.7 + blocking_delay_ms(2); + + if T::regs().csr().read().outcal() == Outcal::LOW { + if mid == 0 { + break; + } + high = mid - 1; + } else { + if mid == 31 { + break; + } + low = mid + 1; + } + } + } } impl<'d, T: Instance> Drop for OpAmpOutput<'d, T> { @@ -338,6 +633,18 @@ macro_rules! impl_opamp_vp_pin { }; } +#[allow(unused_macros)] +macro_rules! impl_opamp_vn_pin { + ($inst:ident, $pin:ident, $ch:expr) => { + impl crate::opamp::InvertingPin for crate::peripherals::$pin {} + impl crate::opamp::SealedInvertingPin for crate::peripherals::$pin { + fn channel(&self) -> u8 { + $ch + } + } + }; +} + #[allow(unused_macros)] macro_rules! impl_opamp_vout_pin { ($inst:ident, $pin:ident) => { diff --git a/examples/stm32f334/src/bin/opamp.rs b/examples/stm32f334/src/bin/opamp.rs index b30445ead..c344935d7 100644 --- a/examples/stm32f334/src/bin/opamp.rs +++ b/examples/stm32f334/src/bin/opamp.rs @@ -4,7 +4,7 @@ use defmt::info; use embassy_executor::Spawner; use embassy_stm32::adc::{Adc, SampleTime}; -use embassy_stm32::opamp::{OpAmp, OpAmpGain}; +use embassy_stm32::opamp::OpAmp; use embassy_stm32::peripherals::ADC2; use embassy_stm32::time::mhz; use embassy_stm32::{adc, bind_interrupts, Config}; @@ -48,7 +48,7 @@ async fn main(_spawner: Spawner) -> ! { let mut vrefint = adc.enable_vref(); let mut temperature = adc.enable_temperature(); - let mut buffer = opamp.buffer_ext(p.PA7.reborrow(), p.PA6.reborrow(), OpAmpGain::Mul1); + let mut buffer = opamp.buffer_ext(p.PA7.reborrow(), p.PA6.reborrow()); loop { let vref = adc.read(&mut vrefint).await; From 04dd1d9e775af75f8a122d9f00c17444b7a183a5 Mon Sep 17 00:00:00 2001 From: Dion Dokter Date: Mon, 14 Apr 2025 14:57:28 +0200 Subject: [PATCH 0969/1217] Add the ADC5 to the DMA codegen for the STM32g4x3 and g4x4 --- embassy-stm32/build.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index d965d8732..bb1f1c047 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -1412,6 +1412,13 @@ fn main() { signals.insert(("adc", "ADC4"), quote!(crate::adc::RxDma)); } + if chip_name.starts_with("stm32g4") { + let line_number = chip_name.chars().skip(8).next().unwrap(); + if line_number == '3' || line_number == '4' { + signals.insert(("adc", "ADC5"), quote!(crate::adc::RxDma)); + } + } + for p in METADATA.peripherals { if let Some(regs) = &p.registers { // FIXME: stm32u5a crash on Cordic driver From dbd7ce4d385e26f78b139c0d9e135d70501c939f Mon Sep 17 00:00:00 2001 From: 1-rafael-1 Date: Mon, 14 Apr 2025 22:41:28 +0200 Subject: [PATCH 0970/1217] Enable input mode for PWM pins on RP235x and disable it on drop --- embassy-rp/src/pwm.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/embassy-rp/src/pwm.rs b/embassy-rp/src/pwm.rs index f631402a2..6dfb90fef 100644 --- a/embassy-rp/src/pwm.rs +++ b/embassy-rp/src/pwm.rs @@ -157,6 +157,11 @@ impl<'d> Pwm<'d> { pin.pad_ctrl().modify(|w| { #[cfg(feature = "_rp235x")] w.set_iso(false); + #[cfg(feature = "_rp235x")] + if divmode != Divmode::DIV { + // Is in input mode and so must enable input mode for the pin + w.set_ie(true); + } w.set_pue(b_pull == Pull::Up); w.set_pde(b_pull == Pull::Down); }); @@ -462,6 +467,11 @@ impl<'d> Drop for Pwm<'d> { } if let Some(pin) = &self.pin_b { pin.gpio().ctrl().write(|w| w.set_funcsel(31)); + #[cfg(feature = "_rp235x")] + // Disable input mode. Only pin_b can be input, so not needed for pin_a + pin.pad_ctrl().modify(|w| { + w.set_ie(false); + }); } } } From d9f708ca6dff653ca7ab6c24b5e9e437ea922ce4 Mon Sep 17 00:00:00 2001 From: Andreas Galauner Date: Tue, 15 Apr 2025 04:05:52 +0200 Subject: [PATCH 0971/1217] Implement MII for STM32 V1 ethernet peripheral --- embassy-stm32/src/eth/v1/mod.rs | 131 ++++++++++++++++++++++++++++---- 1 file changed, 116 insertions(+), 15 deletions(-) diff --git a/embassy-stm32/src/eth/v1/mod.rs b/embassy-stm32/src/eth/v1/mod.rs index 640191d69..01e321bce 100644 --- a/embassy-stm32/src/eth/v1/mod.rs +++ b/embassy-stm32/src/eth/v1/mod.rs @@ -51,12 +51,18 @@ pub struct Ethernet<'d, T: Instance, P: Phy> { pub(crate) tx: TDesRing<'d>, pub(crate) rx: RDesRing<'d>, - pins: [Peri<'d, AnyPin>; 9], + pins: Pins<'d>, pub(crate) phy: P, pub(crate) station_management: EthernetStationManagement, pub(crate) mac_addr: [u8; 6], } +/// Pins of ethernet driver. +enum Pins<'d> { + Rmii([Peri<'d, AnyPin>; 9]), + Mii([Peri<'d, AnyPin>; 14]), +} + #[cfg(eth_v1a)] macro_rules! config_in_pins { ($($pin:ident),*) => { @@ -96,7 +102,7 @@ impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> { pub fn new( queue: &'d mut PacketQueue, peri: Peri<'d, T>, - _irq: impl interrupt::typelevel::Binding + 'd, + irq: impl interrupt::typelevel::Binding + 'd, ref_clk: Peri<'d, impl RefClkPin>, mdio: Peri<'d, impl MDIOPin>, mdc: Peri<'d, impl MDCPin>, @@ -146,6 +152,29 @@ impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> { #[cfg(any(eth_v1b, eth_v1c))] config_pins!(ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en); + let pins = Pins::Rmii([ + ref_clk.into(), + mdio.into(), + mdc.into(), + crs.into(), + rx_d0.into(), + rx_d1.into(), + tx_d0.into(), + tx_d1.into(), + tx_en.into(), + ]); + + Self::new_inner(queue, peri, irq, pins, phy, mac_addr) + } + + fn new_inner( + queue: &'d mut PacketQueue, + peri: Peri<'d, T>, + _irq: impl interrupt::typelevel::Binding + 'd, + pins: Pins<'d>, + phy: P, + mac_addr: [u8; 6], + ) -> Self { let dma = T::regs().ethernet_dma(); let mac = T::regs().ethernet_mac(); @@ -210,18 +239,6 @@ impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> { } }; - let pins = [ - ref_clk.into(), - mdio.into(), - mdc.into(), - crs.into(), - rx_d0.into(), - rx_d1.into(), - tx_d0.into(), - tx_d1.into(), - tx_en.into(), - ]; - let mut this = Self { _peri: peri, pins, @@ -267,6 +284,87 @@ impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> { this } + + /// Create a new MII ethernet driver using 14 pins. + pub fn new_mii( + queue: &'d mut PacketQueue, + peri: Peri<'d, T>, + irq: impl interrupt::typelevel::Binding + 'd, + rx_clk: Peri<'d, impl RXClkPin>, + tx_clk: Peri<'d, impl TXClkPin>, + mdio: Peri<'d, impl MDIOPin>, + mdc: Peri<'d, impl MDCPin>, + rxdv: Peri<'d, impl RXDVPin>, + rx_d0: Peri<'d, impl RXD0Pin>, + rx_d1: Peri<'d, impl RXD1Pin>, + rx_d2: Peri<'d, impl RXD2Pin>, + rx_d3: Peri<'d, impl RXD3Pin>, + tx_d0: Peri<'d, impl TXD0Pin>, + tx_d1: Peri<'d, impl TXD1Pin>, + tx_d2: Peri<'d, impl TXD2Pin>, + tx_d3: Peri<'d, impl TXD3Pin>, + tx_en: Peri<'d, impl TXEnPin>, + phy: P, + mac_addr: [u8; 6], + ) -> Self { + // TODO: Handle optional signals like CRS, MII_COL, RX_ER? + + // Enable the necessary Clocks + #[cfg(eth_v1a)] + critical_section::with(|_| { + RCC.apb2enr().modify(|w| w.set_afioen(true)); + + // Select MII (Media Independent Interface) + // Must be done prior to enabling peripheral clock + AFIO.mapr().modify(|w| w.set_mii_rmii_sel(false)); + + RCC.ahbenr().modify(|w| { + w.set_ethen(true); + w.set_ethtxen(true); + w.set_ethrxen(true); + }); + }); + + #[cfg(any(eth_v1b, eth_v1c))] + critical_section::with(|_| { + RCC.ahb1enr().modify(|w| { + w.set_ethen(true); + w.set_ethtxen(true); + w.set_ethrxen(true); + }); + + // MII (Media Independent Interface) + SYSCFG.pmc().modify(|w| w.set_mii_rmii_sel(false)); + }); + + #[cfg(eth_v1a)] + { + config_in_pins!(rx_clk, tx_clk, rx_d0, rx_d1, rx_d2, rx_d3, rxdv); + config_af_pins!(mdio, mdc, tx_d0, tx_d1, tx_d2, tx_d3, tx_en); + } + + #[cfg(any(eth_v1b, eth_v1c))] + config_pins!(rx_clk, tx_clk, mdio, mdc, rxdv, rx_d0, rx_d1, rx_d2, rx_d3, tx_d0, tx_d1, tx_d2, tx_d3, tx_en); + + let pins = Pins::Mii([ + rx_clk.into(), + tx_clk.into(), + mdio.into(), + mdc.into(), + rxdv.into(), + rx_d0.into(), + rx_d1.into(), + rx_d2.into(), + rx_d3.into(), + tx_d0.into(), + tx_d1.into(), + tx_d2.into(), + tx_d3.into(), + tx_en.into(), + ]); + + Self::new_inner(queue, peri, irq, pins, phy, mac_addr) + } } /// Ethernet station management interface. @@ -322,7 +420,10 @@ impl<'d, T: Instance, P: Phy> Drop for Ethernet<'d, T, P> { dma.dmaomr().modify(|w| w.set_sr(DmaomrSr::STOPPED)); critical_section::with(|_| { - for pin in self.pins.iter_mut() { + for pin in match self.pins { + Pins::Rmii(ref mut pins) => pins.iter_mut(), + Pins::Mii(ref mut pins) => pins.iter_mut(), + } { pin.set_as_disconnected(); } }) From a606a1a45a32117b170e3a5d59f51fc6f123e084 Mon Sep 17 00:00:00 2001 From: Wez Furlong Date: Mon, 14 Apr 2025 19:22:33 -0700 Subject: [PATCH 0972/1217] embassy-rp: impl rand_core::CryptoRng for Trng Per discussion in https://github.com/embassy-rs/embassy/pull/3338/files#r2040704590 the Trng implementation satisfies the requirements for CryptoRng, so it is reasonable to implement this marker trait. --- embassy-rp/src/trng.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/embassy-rp/src/trng.rs b/embassy-rp/src/trng.rs index 44b1bb996..611fee83b 100644 --- a/embassy-rp/src/trng.rs +++ b/embassy-rp/src/trng.rs @@ -368,6 +368,9 @@ impl<'d, T: Instance> rand_core::RngCore for Trng<'d, T> { Ok(()) } } + +impl<'d, T: Instance> rand_core::CryptoRng for Trng<'d, T> {} + /// TRNG interrupt handler. pub struct InterruptHandler { _trng: PhantomData, From 6a6e4216522508450f51748f210a0db7277d4eee Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Tue, 15 Apr 2025 17:43:18 +0800 Subject: [PATCH 0973/1217] rp: i2c-slave example: fix twice-swapped sda/scl sda and scl were swapped twice. The code worked, but would be confusing trying to interface with pins externally. --- examples/rp/src/bin/i2c_slave.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/rp/src/bin/i2c_slave.rs b/examples/rp/src/bin/i2c_slave.rs index 9fffb4646..08f31001b 100644 --- a/examples/rp/src/bin/i2c_slave.rs +++ b/examples/rp/src/bin/i2c_slave.rs @@ -99,19 +99,19 @@ async fn main(spawner: Spawner) { let p = embassy_rp::init(Default::default()); info!("Hello World!"); - let d_sda = p.PIN_3; - let d_scl = p.PIN_2; + let d_sda = p.PIN_2; + let d_scl = p.PIN_3; let mut config = i2c_slave::Config::default(); config.addr = DEV_ADDR as u16; - let device = i2c_slave::I2cSlave::new(p.I2C1, d_sda, d_scl, Irqs, config); + let device = i2c_slave::I2cSlave::new(p.I2C1, d_scl, d_sda, Irqs, config); unwrap!(spawner.spawn(device_task(device))); - let c_sda = p.PIN_1; - let c_scl = p.PIN_0; + let c_sda = p.PIN_0; + let c_scl = p.PIN_1; let mut config = i2c::Config::default(); config.frequency = 1_000_000; - let controller = i2c::I2c::new_async(p.I2C0, c_sda, c_scl, Irqs, config); + let controller = i2c::I2c::new_async(p.I2C0, c_scl, c_sda, Irqs, config); unwrap!(spawner.spawn(controller_task(controller))); } From af755a57adbe211e1746790d1b8ba4ee644ef7fc Mon Sep 17 00:00:00 2001 From: ckrenslehner Date: Tue, 15 Apr 2025 17:29:43 +0200 Subject: [PATCH 0974/1217] fix: stm32wb55 low power feature did not compile --- ci.sh | 1 + embassy-stm32/src/rtc/low_power.rs | 10 +++++++++- embassy-stm32/src/rtc/v2.rs | 5 ++++- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/ci.sh b/ci.sh index edc9bd617..82fda4422 100755 --- a/ci.sh +++ b/ci.sh @@ -168,6 +168,7 @@ cargo batch \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32u5f9zj,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32u5g9nj,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wb35ce,defmt,exti,time-driver-any,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wb55rg,defmt,exti,time-driver-any,low-power,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32u031r8,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32u073mb,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32u083rc,defmt,exti,time-driver-any,time \ diff --git a/embassy-stm32/src/rtc/low_power.rs b/embassy-stm32/src/rtc/low_power.rs index cf7c4bb28..cd075f3de 100644 --- a/embassy-stm32/src/rtc/low_power.rs +++ b/embassy-stm32/src/rtc/low_power.rs @@ -231,7 +231,15 @@ impl Rtc { { use crate::pac::EXTI; EXTI.rtsr(0).modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true)); - EXTI.imr(0).modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true)); + + #[cfg(not(stm32wb))] + { + EXTI.imr(0).modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true)); + } + #[cfg(stm32wb)] + { + EXTI.cpu(0).imr(0).modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true)); + } } #[cfg(stm32u5)] { diff --git a/embassy-stm32/src/rtc/v2.rs b/embassy-stm32/src/rtc/v2.rs index b7d25635b..28380a3c0 100644 --- a/embassy-stm32/src/rtc/v2.rs +++ b/embassy-stm32/src/rtc/v2.rs @@ -137,7 +137,10 @@ impl SealedInstance for crate::peripherals::RTC { #[cfg(all(feature = "low-power", stm32l0))] const EXTI_WAKEUP_LINE: usize = 20; - #[cfg(all(feature = "low-power", any(stm32f4, stm32l4)))] + #[cfg(all(feature = "low-power", stm32wb))] + const EXTI_WAKEUP_LINE: usize = 19; + + #[cfg(all(feature = "low-power", any(stm32f4, stm32l4, stm32wb)))] type WakeupInterrupt = crate::interrupt::typelevel::RTC_WKUP; #[cfg(all(feature = "low-power", stm32l0))] From 94c208b52a55337658baa894c699c428fc67a449 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anton=20P=C3=B6hl?= Date: Sun, 13 Apr 2025 20:26:26 +0200 Subject: [PATCH 0975/1217] Stm32 usart: better names for open drain pin modes --- embassy-stm32/src/usart/mod.rs | 12 ++++++------ examples/stm32g0/src/bin/onewire_ds18b20.rs | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index 49f536799..48f9a84fa 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -142,20 +142,20 @@ pub enum HalfDuplexReadback { pub enum OutputConfig { /// Push pull allows for faster baudrates, no internal pullup PushPull, - /// Open drain output using external pull down resistor - OpenDrainExternal, + /// Open drain output (external pull up needed) + OpenDrain, #[cfg(not(gpio_v1))] - /// Open drain output using internal pull up resistor - OpenDrainInternal, + /// Open drain output with internal pull up resistor + OpenDrainPullUp, } impl OutputConfig { const fn af_type(self) -> AfType { match self { OutputConfig::PushPull => AfType::output(OutputType::PushPull, Speed::Medium), - OutputConfig::OpenDrainExternal => AfType::output(OutputType::OpenDrain, Speed::Medium), + OutputConfig::OpenDrain => AfType::output(OutputType::OpenDrain, Speed::Medium), #[cfg(not(gpio_v1))] - OutputConfig::OpenDrainInternal => AfType::output_pull(OutputType::OpenDrain, Speed::Medium, Pull::Up), + OutputConfig::OpenDrainPullUp => AfType::output_pull(OutputType::OpenDrain, Speed::Medium, Pull::Up), } } } diff --git a/examples/stm32g0/src/bin/onewire_ds18b20.rs b/examples/stm32g0/src/bin/onewire_ds18b20.rs index 75519bbf2..62f8711a6 100644 --- a/examples/stm32g0/src/bin/onewire_ds18b20.rs +++ b/examples/stm32g0/src/bin/onewire_ds18b20.rs @@ -22,7 +22,7 @@ fn create_onewire(p: embassy_stm32::Peripherals) -> OneWire OneWire Date: Wed, 16 Apr 2025 21:40:30 +0200 Subject: [PATCH 0976/1217] Fix link in faq.adoc Looks like a link was using markdown instead of asciidoc. --- docs/pages/faq.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/pages/faq.adoc b/docs/pages/faq.adoc index 3b5eafa99..a535e89f8 100644 --- a/docs/pages/faq.adoc +++ b/docs/pages/faq.adoc @@ -212,7 +212,7 @@ _stack_start = ORIGIN(RAM) + LENGTH(RAM); Please refer to the STM32 documentation for the specific values suitable for your board and setup. The STM32 Cube examples often contain a linker script `.ld` file. Look for the `MEMORY` section and try to determine the FLASH and RAM sizes and section start. -If you find a case where the memory.x is wrong, please report it on [this Github issue](https://github.com/embassy-rs/stm32-data/issues/301) so other users are not caught by surprise. +If you find a case where the memory.x is wrong, please report it on link:https://github.com/embassy-rs/stm32-data/issues/301[this Github issue] so other users are not caught by surprise. == The USB examples are not working on my board, is there anything else I need to configure? From e410e65b830f5486a9d15b87039817aa4668e06f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Thu, 17 Apr 2025 18:05:03 +0200 Subject: [PATCH 0977/1217] Add CMSIS-DAP driver --- embassy-usb/src/class/cmsis_dap_v2.rs | 101 ++++++++++++++++++++++++++ embassy-usb/src/class/mod.rs | 1 + 2 files changed, 102 insertions(+) create mode 100644 embassy-usb/src/class/cmsis_dap_v2.rs diff --git a/embassy-usb/src/class/cmsis_dap_v2.rs b/embassy-usb/src/class/cmsis_dap_v2.rs new file mode 100644 index 000000000..41f6be5dd --- /dev/null +++ b/embassy-usb/src/class/cmsis_dap_v2.rs @@ -0,0 +1,101 @@ +//! CMSIS-DAP V2 class implementation. + +use core::mem::MaybeUninit; + +use crate::driver::{Driver, Endpoint, EndpointError, EndpointIn, EndpointOut}; +use crate::types::StringIndex; +use crate::{msos, Builder, Handler}; + +/// State for the CMSIS-DAP v2 USB class. +pub struct State { + control: MaybeUninit, +} + +struct Control { + iface_string: StringIndex, +} + +impl Handler for Control { + fn get_string(&mut self, index: StringIndex, _lang_id: u16) -> Option<&str> { + if index == self.iface_string { + Some("CMSIS-DAP v2 Interface") + } else { + warn!("unknown string index requested"); + None + } + } +} + +impl State { + /// Create a new `State`. + pub const fn new() -> Self { + Self { + control: MaybeUninit::uninit(), + } + } +} + +/// USB device class for CMSIS-DAP v2 probes. +pub struct CmsisDapV2Class<'d, D: Driver<'d>> { + read_ep: D::EndpointOut, + write_ep: D::EndpointIn, + max_packet_size: u16, +} + +impl<'d, D: Driver<'d>> CmsisDapV2Class<'d, D> { + /// Creates a new CmsisDapV2Class with the provided UsbBus and `max_packet_size` in bytes. For + /// full-speed devices, `max_packet_size` has to be 64. + pub fn new(builder: &mut Builder<'d, D>, state: &'d mut State, max_packet_size: u16) -> Self { + // DAP - Custom Class 0 + let iface_string = builder.string(); + let mut function = builder.function(0xFF, 0, 0); + function.msos_feature(msos::CompatibleIdFeatureDescriptor::new("WINUSB", "")); + function.msos_feature(msos::RegistryPropertyFeatureDescriptor::new( + "DeviceInterfaceGUIDs", + // CMSIS-DAP standard GUID, from https://arm-software.github.io/CMSIS_5/DAP/html/group__DAP__ConfigUSB__gr.html + msos::PropertyData::RegMultiSz(&["{CDB3B5AD-293B-4663-AA36-1AAE46463776}"]), + )); + let mut interface = function.interface(); + let mut alt = interface.alt_setting(0xFF, 0, 0, Some(iface_string)); + let read_ep = alt.endpoint_bulk_out(max_packet_size); + let write_ep = alt.endpoint_bulk_in(max_packet_size); + drop(function); + + builder.handler(state.control.write(Control { iface_string })); + + CmsisDapV2Class { + read_ep, + write_ep, + max_packet_size, + } + } + + /// Waits for the USB host to enable this interface + pub async fn wait_connection(&mut self) { + self.read_ep.wait_enabled().await; + } + + /// Write data to the host. + pub async fn write_packet(&mut self, data: &[u8]) -> Result<(), EndpointError> { + for chunk in data.chunks(self.max_packet_size as usize) { + self.write_ep.write(chunk).await?; + } + if data.len() % self.max_packet_size as usize == 0 { + self.write_ep.write(&[]).await?; + } + Ok(()) + } + + /// Read data from the host. + pub async fn read_packet(&mut self, data: &mut [u8]) -> Result { + let mut n = 0; + + loop { + let i = self.read_ep.read(&mut data[n..]).await?; + n += i; + if i < self.max_packet_size as usize { + return Ok(n); + } + } + } +} diff --git a/embassy-usb/src/class/mod.rs b/embassy-usb/src/class/mod.rs index 4bd89eb66..c01707971 100644 --- a/embassy-usb/src/class/mod.rs +++ b/embassy-usb/src/class/mod.rs @@ -1,6 +1,7 @@ //! Implementations of well-known USB classes. pub mod cdc_acm; pub mod cdc_ncm; +pub mod cmsis_dap_v2; pub mod hid; pub mod midi; pub mod uac1; From b0eacf0eecbef48ac526da6bce250189e4999ce5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Thu, 17 Apr 2025 22:29:15 +0200 Subject: [PATCH 0978/1217] Add optional trace endpoint --- embassy-usb/src/class/cmsis_dap_v2.rs | 29 ++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/embassy-usb/src/class/cmsis_dap_v2.rs b/embassy-usb/src/class/cmsis_dap_v2.rs index 41f6be5dd..a94e3ddb7 100644 --- a/embassy-usb/src/class/cmsis_dap_v2.rs +++ b/embassy-usb/src/class/cmsis_dap_v2.rs @@ -39,13 +39,17 @@ impl State { pub struct CmsisDapV2Class<'d, D: Driver<'d>> { read_ep: D::EndpointOut, write_ep: D::EndpointIn, + trace_ep: Option, max_packet_size: u16, } impl<'d, D: Driver<'d>> CmsisDapV2Class<'d, D> { /// Creates a new CmsisDapV2Class with the provided UsbBus and `max_packet_size` in bytes. For /// full-speed devices, `max_packet_size` has to be 64. - pub fn new(builder: &mut Builder<'d, D>, state: &'d mut State, max_packet_size: u16) -> Self { + /// + /// The `trace` parameter enables the trace output endpoint. This is optional and can be + /// disabled if the probe does not support trace output. + pub fn new(builder: &mut Builder<'d, D>, state: &'d mut State, max_packet_size: u16, trace: bool) -> Self { // DAP - Custom Class 0 let iface_string = builder.string(); let mut function = builder.function(0xFF, 0, 0); @@ -59,6 +63,11 @@ impl<'d, D: Driver<'d>> CmsisDapV2Class<'d, D> { let mut alt = interface.alt_setting(0xFF, 0, 0, Some(iface_string)); let read_ep = alt.endpoint_bulk_out(max_packet_size); let write_ep = alt.endpoint_bulk_in(max_packet_size); + let trace_ep = if trace { + Some(alt.endpoint_bulk_in(max_packet_size)) + } else { + None + }; drop(function); builder.handler(state.control.write(Control { iface_string })); @@ -66,6 +75,7 @@ impl<'d, D: Driver<'d>> CmsisDapV2Class<'d, D> { CmsisDapV2Class { read_ep, write_ep, + trace_ep, max_packet_size, } } @@ -86,6 +96,23 @@ impl<'d, D: Driver<'d>> CmsisDapV2Class<'d, D> { Ok(()) } + /// Write data to the host via the trace output endpoint. + /// + /// Returns `EndpointError::Disabled` if the trace output endpoint is not enabled. + pub async fn write_trace(&mut self, data: &[u8]) -> Result<(), EndpointError> { + let Some(ep) = self.trace_ep.as_mut() else { + return Err(EndpointError::Disabled); + }; + + for chunk in data.chunks(self.max_packet_size as usize) { + ep.write(chunk).await?; + } + if data.len() % self.max_packet_size as usize == 0 { + ep.write(&[]).await?; + } + Ok(()) + } + /// Read data from the host. pub async fn read_packet(&mut self, data: &mut [u8]) -> Result { let mut n = 0; From 69d2ce4eab278b839678fb41e2be65618c639145 Mon Sep 17 00:00:00 2001 From: Josep Angel Oltra Date: Thu, 17 Apr 2025 22:57:13 +0200 Subject: [PATCH 0979/1217] Added USB core_id 0x1000 for STM32 --- embassy-stm32/src/usb/otg.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/src/usb/otg.rs b/embassy-stm32/src/usb/otg.rs index 51429b8cc..2aca3d929 100644 --- a/embassy-stm32/src/usb/otg.rs +++ b/embassy-stm32/src/usb/otg.rs @@ -335,7 +335,7 @@ impl<'d, T: Instance> Bus<'d, T> { // Configuring Vbus sense and SOF output match core_id { - 0x0000_1200 | 0x0000_1100 => self.inner.config_v1(), + 0x0000_1200 | 0x0000_1100 | 0x0000_1000 => self.inner.config_v1(), 0x0000_2000 | 0x0000_2100 | 0x0000_2300 | 0x0000_3000 | 0x0000_3100 => self.inner.config_v2v3(), 0x0000_5000 => self.inner.config_v5(), _ => unimplemented!("Unknown USB core id {:X}", core_id), From 27e4d70377542e089f26e556f1f9cf05a98ecdae Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Fri, 18 Apr 2025 12:53:43 +0200 Subject: [PATCH 0980/1217] RIP stm32l073rz --- ci.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/ci.sh b/ci.sh index 82fda4422..11c2be186 100755 --- a/ci.sh +++ b/ci.sh @@ -323,6 +323,7 @@ DEFMT_RTT_BUFFER_SIZE="72" cargo batch \ # temporarily disabled, these boards are dead. rm -rf out/tests/stm32f103c8 +rm -rf out/tests/stm32l073rz rm -rf out/tests/nrf52840-dk rm -rf out/tests/nrf52833-dk From eb83d049c7fe1919b435878012de5da886e9fc62 Mon Sep 17 00:00:00 2001 From: Oliver <18360865+ost-ing@users.noreply.github.com> Date: Tue, 4 Feb 2025 12:15:22 +1100 Subject: [PATCH 0981/1217] stm32/sdmmc: add support for multiple block reads and writes. --- embassy-stm32/src/sdmmc/mod.rs | 192 ++++++++++++++++++++++++++++++--- tests/stm32/src/bin/sdmmc.rs | 20 +++- 2 files changed, 195 insertions(+), 17 deletions(-) diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs index 63868e5ae..6a02aae70 100644 --- a/embassy-stm32/src/sdmmc/mod.rs +++ b/embassy-stm32/src/sdmmc/mod.rs @@ -151,6 +151,8 @@ pub enum Error { BadClock, /// Signaling switch failed. SignalingSwitchFailed, + /// Underrun error + Underrun, /// ST bit error. #[cfg(sdmmc_v1)] StBitErr, @@ -1025,6 +1027,9 @@ impl<'d, T: Instance> Sdmmc<'d, T> { if status.dtimeout() { return Poll::Ready(Err(Error::Timeout)); } + if status.txunderr() { + return Poll::Ready(Err(Error::Underrun)); + } #[cfg(sdmmc_v1)] if status.stbiterr() { return Poll::Ready(Err(Error::StBitErr)); @@ -1080,6 +1085,73 @@ impl<'d, T: Instance> Sdmmc<'d, T> { res } + /// Read multiple data blocks. + #[inline] + pub async fn read_blocks(&mut self, block_idx: u32, blocks: &mut [DataBlock]) -> Result<(), Error> { + let card_capacity = self.card()?.get_capacity(); + + // NOTE(unsafe) reinterpret buffer as &mut [u32] + let buffer = unsafe { + let ptr = blocks.as_mut_ptr() as *mut u32; + let len = blocks.len() * 128; + core::slice::from_raw_parts_mut(ptr, len) + }; + + // Always read 1 block of 512 bytes + // SDSC cards are byte addressed hence the blockaddress is in multiples of 512 bytes + let address = match card_capacity { + CardCapacity::StandardCapacity => block_idx * 512, + _ => block_idx, + }; + Self::cmd(common_cmd::set_block_length(512), false)?; // CMD16 + + let regs = T::regs(); + let on_drop = OnDrop::new(|| Self::on_drop()); + + let transfer = Self::prepare_datapath_read( + &self.config, + #[cfg(sdmmc_v1)] + &mut self.dma, + buffer, + 512 * blocks.len() as u32, + 9, + ); + InterruptHandler::::data_interrupts(true); + + Self::cmd(common_cmd::read_multiple_blocks(address), true)?; + + let res = poll_fn(|cx| { + T::state().register(cx.waker()); + let status = regs.star().read(); + + if status.dcrcfail() { + return Poll::Ready(Err(Error::Crc)); + } + if status.dtimeout() { + return Poll::Ready(Err(Error::Timeout)); + } + #[cfg(sdmmc_v1)] + if status.stbiterr() { + return Poll::Ready(Err(Error::StBitErr)); + } + if status.dataend() { + return Poll::Ready(Ok(())); + } + Poll::Pending + }) + .await; + + Self::cmd(common_cmd::stop_transmission(), false)?; // CMD12 + Self::clear_interrupt_flags(); + + if res.is_ok() { + on_drop.defuse(); + Self::stop_datapath(); + drop(transfer); + } + res + } + /// Write a data block. pub async fn write_block(&mut self, block_idx: u32, buffer: &DataBlock) -> Result<(), Error> { let card = self.card.as_mut().ok_or(Error::NoCard)?; @@ -1088,7 +1160,7 @@ impl<'d, T: Instance> Sdmmc<'d, T> { let buffer = unsafe { &*((&buffer.0) as *const [u8; 512] as *const [u32; 128]) }; // Always read 1 block of 512 bytes - // SDSC cards are byte addressed hence the blockaddress is in multiples of 512 bytes + // cards are byte addressed hence the blockaddress is in multiples of 512 bytes let address = match card.get_capacity() { CardCapacity::StandardCapacity => block_idx * 512, _ => block_idx, @@ -1136,6 +1208,94 @@ impl<'d, T: Instance> Sdmmc<'d, T> { } } + /// Write multiple data blocks. + pub async fn write_blocks(&mut self, block_idx: u32, blocks: &[DataBlock]) -> Result<(), Error> { + let card = self.card.as_mut().ok_or(Error::NoCard)?; + + // NOTE(unsafe) reinterpret buffer as &[u32] + let buffer = unsafe { + let ptr = blocks.as_ptr() as *const u32; + let len = blocks.len() * 128; + core::slice::from_raw_parts(ptr, len) + }; + + // Always read 1 block of 512 bytes + // SDSC cards are byte addressed hence the blockaddress is in multiples of 512 bytes + let address = match card.get_capacity() { + CardCapacity::StandardCapacity => block_idx * 512, + _ => block_idx, + }; + + Self::cmd(common_cmd::set_block_length(512), false)?; // CMD16 + + let block_count = blocks.len(); + + let regs = T::regs(); + let on_drop = OnDrop::new(|| Self::on_drop()); + + #[cfg(sdmmc_v1)] + Self::cmd(common_cmd::write_multiple_blocks(address), true)?; // CMD25 + + // Setup write command + let transfer = self.prepare_datapath_write(buffer, 512 * block_count as u32, 9); + InterruptHandler::::data_interrupts(true); + + #[cfg(sdmmc_v2)] + Self::cmd(common_cmd::write_multiple_blocks(address), true)?; // CMD25 + + let res = poll_fn(|cx| { + T::state().register(cx.waker()); + + let status = regs.star().read(); + + if status.dcrcfail() { + return Poll::Ready(Err(Error::Crc)); + } + if status.dtimeout() { + return Poll::Ready(Err(Error::Timeout)); + } + if status.txunderr() { + return Poll::Ready(Err(Error::Underrun)); + } + #[cfg(sdmmc_v1)] + if status.stbiterr() { + return Poll::Ready(Err(Error::StBitErr)); + } + if status.dataend() { + return Poll::Ready(Ok(())); + } + + Poll::Pending + }) + .await; + + Self::cmd(common_cmd::stop_transmission(), false)?; // CMD12 + Self::clear_interrupt_flags(); + + match res { + Ok(_) => { + on_drop.defuse(); + Self::stop_datapath(); + drop(transfer); + + // TODO: Make this configurable + let mut timeout: u32 = 0x00FF_FFFF; + + // Try to read card status (ACMD13) + while timeout > 0 { + match self.read_sd_status().await { + Ok(_) => return Ok(()), + Err(Error::Timeout) => (), // Try again + Err(e) => return Err(e), + } + timeout -= 1; + } + Err(Error::SoftwareTimeout) + } + Err(e) => Err(e), + } + } + /// Get a reference to the initialized card /// /// # Errors @@ -1699,33 +1859,35 @@ impl<'d, T: Instance> block_device_driver::BlockDevice<512> for Sdmmc<'d, T> { async fn read( &mut self, - mut block_address: u32, + block_address: u32, buf: &mut [aligned::Aligned], ) -> Result<(), Self::Error> { - // FIXME/TODO because of missing read_blocks multiple we have to do this one block at a time - for block in buf.iter_mut() { - // safety aligned by block device - let block = unsafe { &mut *(block as *mut _ as *mut crate::sdmmc::DataBlock) }; + // TODO: I think block_address needs to be adjusted by the partition start offset + if buf.len() == 1 { + let block = unsafe { &mut *(&mut buf[0] as *mut _ as *mut crate::sdmmc::DataBlock) }; self.read_block(block_address, block).await?; - block_address += 1; + } else { + let blocks: &mut [DataBlock] = + unsafe { core::slice::from_raw_parts_mut(buf.as_mut_ptr() as *mut DataBlock, buf.len()) }; + self.read_blocks(block_address, blocks).await?; } - Ok(()) } async fn write( &mut self, - mut block_address: u32, + block_address: u32, buf: &[aligned::Aligned], ) -> Result<(), Self::Error> { - // FIXME/TODO because of missing read_blocks multiple we have to do this one block at a time - for block in buf.iter() { - // safety aligned by block device - let block = unsafe { &*(block as *const _ as *const crate::sdmmc::DataBlock) }; + // TODO: I think block_address needs to be adjusted by the partition start offset + if buf.len() == 1 { + let block = unsafe { &*(&buf[0] as *const _ as *const crate::sdmmc::DataBlock) }; self.write_block(block_address, block).await?; - block_address += 1; + } else { + let blocks: &[DataBlock] = + unsafe { core::slice::from_raw_parts(buf.as_ptr() as *const DataBlock, buf.len()) }; + self.write_blocks(block_address, blocks).await?; } - Ok(()) } diff --git a/tests/stm32/src/bin/sdmmc.rs b/tests/stm32/src/bin/sdmmc.rs index c1ed45588..34a53a725 100644 --- a/tests/stm32/src/bin/sdmmc.rs +++ b/tests/stm32/src/bin/sdmmc.rs @@ -34,8 +34,10 @@ async fn main(_spawner: Spawner) { pattern1[i] = i as u8; pattern2[i] = !i as u8; } + let patterns = [pattern1.clone(), pattern2.clone()]; let mut block = DataBlock([0u8; 512]); + let mut blocks = [DataBlock([0u8; 512]), DataBlock([0u8; 512])]; // ======== Try 4bit. ============== info!("initializing in 4-bit mode..."); @@ -84,6 +86,13 @@ async fn main(_spawner: Spawner) { s.read_block(block_idx, &mut block).await.unwrap(); assert_eq!(block, pattern2); + info!("writing blocks [pattern1, pattern2]..."); + s.write_blocks(block_idx, &patterns).await.unwrap(); + + info!("reading blocks..."); + s.read_blocks(block_idx, &mut blocks).await.unwrap(); + assert_eq!(&blocks, &patterns); + drop(s); // ======== Try 1bit. ============== @@ -116,9 +125,9 @@ async fn main(_spawner: Spawner) { info!("Card: {:#?}", Debug2Format(card)); info!("Clock: {}", s.clock()); - info!("reading pattern2 written in 4bit mode..."); + info!("reading pattern1 written in 4bit mode..."); s.read_block(block_idx, &mut block).await.unwrap(); - assert_eq!(block, pattern2); + assert_eq!(block, pattern1); info!("writing pattern1..."); s.write_block(block_idx, &pattern1).await.unwrap(); @@ -134,6 +143,13 @@ async fn main(_spawner: Spawner) { s.read_block(block_idx, &mut block).await.unwrap(); assert_eq!(block, pattern2); + info!("writing blocks [pattern1, pattern2]..."); + s.write_blocks(block_idx, &patterns).await.unwrap(); + + info!("reading blocks..."); + s.read_blocks(block_idx, &mut blocks).await.unwrap(); + assert_eq!(&blocks, &patterns); + drop(s); info!("Test OK"); From 97172c36b76d07fd45d96eff34be7913f0063f03 Mon Sep 17 00:00:00 2001 From: Adam Greig Date: Fri, 18 Apr 2025 14:41:56 +0100 Subject: [PATCH 0982/1217] STM32: Fix G4 build without defmt feature --- embassy-stm32/src/opamp.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/opamp.rs b/embassy-stm32/src/opamp.rs index 82de4a89b..28ae2a3eb 100644 --- a/embassy-stm32/src/opamp.rs +++ b/embassy-stm32/src/opamp.rs @@ -435,11 +435,13 @@ impl<'d, T: Instance> OpAmp<'d, T> { T::regs().csr().modify(|w| match pair { OpAmpDifferentialPair::P => { - defmt::info!("p calibration. offset: {}", mid); + #[cfg(feature = "defmt")] + defmt::debug!("opamp p calibration. offset: {}", mid); w.set_trimoffsetp(mid); } OpAmpDifferentialPair::N => { - defmt::info!("n calibration. offset: {}", mid); + #[cfg(feature = "defmt")] + defmt::debug!("opamp n calibration. offset: {}", mid); w.set_trimoffsetn(mid); } }); From dc3b83f9c83ac9316c0e623af1726fe975557ad3 Mon Sep 17 00:00:00 2001 From: Adam Greig Date: Fri, 18 Apr 2025 14:42:16 +0100 Subject: [PATCH 0983/1217] STM32: Change CAN data() to return slice with correct length --- embassy-stm32/src/can/fd/peripheral.rs | 2 +- embassy-stm32/src/can/frame.rs | 18 ++++++++---------- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/embassy-stm32/src/can/fd/peripheral.rs b/embassy-stm32/src/can/fd/peripheral.rs index 39c4112ad..014f31c87 100644 --- a/embassy-stm32/src/can/fd/peripheral.rs +++ b/embassy-stm32/src/can/fd/peripheral.rs @@ -190,7 +190,7 @@ impl Registers { DataLength::Fdcan(len) => len, DataLength::Classic(len) => len, }; - if len as usize > ClassicData::MAX_DATA_LEN { + if len as usize > 8 { return None; } diff --git a/embassy-stm32/src/can/frame.rs b/embassy-stm32/src/can/frame.rs index f621b8bd5..a1d773f2c 100644 --- a/embassy-stm32/src/can/frame.rs +++ b/embassy-stm32/src/can/frame.rs @@ -104,15 +104,13 @@ pub trait CanHeader: Sized { #[derive(Debug, Copy, Clone)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct ClassicData { - pub(crate) bytes: [u8; Self::MAX_DATA_LEN], + pub(crate) bytes: [u8; 8], } impl ClassicData { - pub(crate) const MAX_DATA_LEN: usize = 8; /// Creates a data payload from a raw byte slice. /// - /// Returns `None` if `data` is more than 64 bytes (which is the maximum) or - /// cannot be represented with an FDCAN DLC. + /// Returns `FrameCreateError` if `data` is more than 8 bytes (which is the maximum). pub fn new(data: &[u8]) -> Result { if data.len() > 8 { return Err(FrameCreateError::InvalidDataLength); @@ -211,12 +209,12 @@ impl Frame { /// Get reference to data pub fn data(&self) -> &[u8] { - &self.data.raw() + &self.data.raw()[..self.can_header.len as usize] } /// Get mutable reference to data pub fn data_mut(&mut self) -> &mut [u8] { - self.data.raw_mut() + &mut self.data.raw_mut()[..self.can_header.len as usize] } /// Get priority of frame @@ -260,7 +258,7 @@ impl embedded_can::Frame for Frame { self.can_header.len as usize } fn data(&self) -> &[u8] { - &self.data.raw() + &self.data() } } @@ -405,12 +403,12 @@ impl FdFrame { /// Get reference to data pub fn data(&self) -> &[u8] { - &self.data.raw() + &self.data.raw()[..self.can_header.len as usize] } /// Get mutable reference to data pub fn data_mut(&mut self) -> &mut [u8] { - self.data.raw_mut() + &mut self.data.raw_mut()[..self.can_header.len as usize] } } @@ -448,7 +446,7 @@ impl embedded_can::Frame for FdFrame { self.can_header.len as usize } fn data(&self) -> &[u8] { - &self.data.raw() + &self.data() } } From 17d3adac4b9f1fe4458faba8fa467d13cf1ceac1 Mon Sep 17 00:00:00 2001 From: Adam Greig Date: Fri, 18 Apr 2025 17:19:21 +0100 Subject: [PATCH 0984/1217] STM32: Fix CAN transmit on bxcan targets --- embassy-stm32/src/can/bxcan/registers.rs | 4 ++-- embassy-stm32/src/can/fd/peripheral.rs | 2 +- embassy-stm32/src/can/frame.rs | 5 +++++ 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/embassy-stm32/src/can/bxcan/registers.rs b/embassy-stm32/src/can/bxcan/registers.rs index c5467dfe8..c295b0f50 100644 --- a/embassy-stm32/src/can/bxcan/registers.rs +++ b/embassy-stm32/src/can/bxcan/registers.rs @@ -299,9 +299,9 @@ impl Registers { mb.tdtr().write(|w| w.set_dlc(frame.header().len() as u8)); mb.tdlr() - .write(|w| w.0 = u32::from_ne_bytes(unwrap!(frame.data()[0..4].try_into()))); + .write(|w| w.0 = u32::from_ne_bytes(unwrap!(frame.raw_data()[0..4].try_into()))); mb.tdhr() - .write(|w| w.0 = u32::from_ne_bytes(unwrap!(frame.data()[4..8].try_into()))); + .write(|w| w.0 = u32::from_ne_bytes(unwrap!(frame.raw_data()[4..8].try_into()))); let id: IdReg = frame.id().into(); mb.tir().write(|w| { w.0 = id.0; diff --git a/embassy-stm32/src/can/fd/peripheral.rs b/embassy-stm32/src/can/fd/peripheral.rs index 014f31c87..4873ee444 100644 --- a/embassy-stm32/src/can/fd/peripheral.rs +++ b/embassy-stm32/src/can/fd/peripheral.rs @@ -75,7 +75,7 @@ impl Registers { let mailbox = self.tx_buffer_element(bufidx); mailbox.reset(); put_tx_header(mailbox, header); - put_tx_data(mailbox, &buffer[..header.len() as usize]); + put_tx_data(mailbox, buffer); // Set as ready to transmit self.regs.txbar().modify(|w| w.set_ar(bufidx, true)); diff --git a/embassy-stm32/src/can/frame.rs b/embassy-stm32/src/can/frame.rs index a1d773f2c..a4d5a9752 100644 --- a/embassy-stm32/src/can/frame.rs +++ b/embassy-stm32/src/can/frame.rs @@ -212,6 +212,11 @@ impl Frame { &self.data.raw()[..self.can_header.len as usize] } + /// Get reference to underlying 8-byte raw data buffer + pub(crate) fn raw_data(&self) -> &[u8] { + self.data.raw() + } + /// Get mutable reference to data pub fn data_mut(&mut self) -> &mut [u8] { &mut self.data.raw_mut()[..self.can_header.len as usize] From 11241c579aeda5051c2cbfcc7d3264437decb230 Mon Sep 17 00:00:00 2001 From: Anton Lazarev Date: Wed, 2 Apr 2025 22:40:32 -0700 Subject: [PATCH 0985/1217] derive `Clone` for `hash::Context` The HASH accelerator can be used for HMAC if a key is provided. One significant use case of HMAC is as a PRF for the PBKDF2 algorithm, but this requires that the hashing state can be recursively "branched" multiple times. --- embassy-stm32/src/hash/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/embassy-stm32/src/hash/mod.rs b/embassy-stm32/src/hash/mod.rs index 1258e8923..e62151bb5 100644 --- a/embassy-stm32/src/hash/mod.rs +++ b/embassy-stm32/src/hash/mod.rs @@ -101,6 +101,7 @@ pub enum DataType { /// Stores the state of the HASH peripheral for suspending/resuming /// digest calculation. +#[derive(Clone)] pub struct Context<'c> { first_word_sent: bool, key_sent: bool, From 7512c5f14ed90b264fa7b617bba8be6fc5ae53b4 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Fri, 18 Apr 2025 20:32:15 +0200 Subject: [PATCH 0986/1217] stm32: update metapac, cleanup clocks a bit. --- embassy-stm32/Cargo.toml | 4 +- embassy-stm32/build.rs | 81 ++++++++++++++++++++++++----------- embassy-stm32/src/rcc/f013.rs | 6 --- embassy-stm32/src/rcc/f247.rs | 1 - embassy-stm32/src/rcc/g0.rs | 2 - embassy-stm32/src/rcc/g4.rs | 2 + embassy-stm32/src/rcc/h.rs | 5 +-- embassy-stm32/src/rcc/l.rs | 2 +- embassy-stm32/src/rcc/u5.rs | 4 -- 9 files changed, 63 insertions(+), 44 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index d15ac4823..82bc76883 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -73,7 +73,7 @@ rand_core = "0.6.3" sdio-host = "0.9.0" critical-section = "1.1" #stm32-metapac = { version = "16" } -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-a7a30c9d54e7415709c463a537501691784672db" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-380f03cb71f43a242adc45e83607a380ffe0447b" } vcell = "0.1.3" nb = "1.0.0" @@ -102,7 +102,7 @@ proc-macro2 = "1.0.36" quote = "1.0.15" #stm32-metapac = { version = "16", default-features = false, features = ["metadata"]} -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-a7a30c9d54e7415709c463a537501691784672db", default-features = false, features = ["metadata"] } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-380f03cb71f43a242adc45e83607a380ffe0447b", default-features = false, features = ["metadata"] } [features] default = ["rt"] diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index d982d9010..f9f03c51b 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -489,9 +489,39 @@ fn main() { } impl<'a> ClockGen<'a> { + fn parse_mul_div(name: &str) -> (&str, Frac) { + if name == "hse_div_rtcpre" { + return (name, Frac { num: 1, denom: 1 }); + } + + if let Some(i) = name.find("_div_") { + let n = &name[..i]; + let val: u32 = name[i + 5..].parse().unwrap(); + (n, Frac { num: 1, denom: val }) + } else if let Some(i) = name.find("_mul_") { + let n = &name[..i]; + let val: u32 = name[i + 5..].parse().unwrap(); + (n, Frac { num: val, denom: 1 }) + } else { + (name, Frac { num: 1, denom: 1 }) + } + } + fn gen_clock(&mut self, peripheral: &str, name: &str) -> TokenStream { - let clock_name = format_ident!("{}", name.to_ascii_lowercase()); - self.clock_names.insert(name.to_ascii_lowercase()); + let name = name.to_ascii_lowercase(); + let (name, frac) = Self::parse_mul_div(&name); + let clock_name = format_ident!("{}", name); + self.clock_names.insert(name.to_string()); + + let mut muldiv = quote!(); + if frac.num != 1 { + let val = frac.num; + muldiv.extend(quote!(* #val)); + } + if frac.denom != 1 { + let val = frac.denom; + muldiv.extend(quote!(/ #val)); + } quote!(unsafe { unwrap!( crate::rcc::get_freqs().#clock_name.to_hertz(), @@ -500,6 +530,7 @@ fn main() { #peripheral, #name ) + #muldiv }) } @@ -1503,29 +1534,6 @@ fn main() { } } - #[derive(Copy, Clone, Debug)] - struct Frac { - num: u32, - denom: u32, - } - - impl Frac { - fn simplify(self) -> Self { - let d = gcd(self.num, self.denom); - Self { - num: self.num / d, - denom: self.denom / d, - } - } - } - - fn gcd(a: u32, b: u32) -> u32 { - if b == 0 { - return a; - } - gcd(b, a % b) - } - fn parse_num(n: &str) -> Result { for prefix in ["DIV", "MUL"] { if let Some(n) = n.strip_prefix(prefix) { @@ -2136,3 +2144,26 @@ fn mem_filter(chip: &str, region: &str) -> bool { true } + +#[derive(Copy, Clone, Debug)] +struct Frac { + num: u32, + denom: u32, +} + +impl Frac { + fn simplify(self) -> Self { + let d = gcd(self.num, self.denom); + Self { + num: self.num / d, + denom: self.denom / d, + } + } +} + +fn gcd(a: u32, b: u32) -> u32 { + if b == 0 { + return a; + } + gcd(b, a % b) +} diff --git a/embassy-stm32/src/rcc/f013.rs b/embassy-stm32/src/rcc/f013.rs index 13b0ae38e..cfa223d1f 100644 --- a/embassy-stm32/src/rcc/f013.rs +++ b/embassy-stm32/src/rcc/f013.rs @@ -289,9 +289,6 @@ pub(crate) unsafe fn init(config: Config) { out_freq }); - #[cfg(stm32f3)] - let pll_mul_2 = pll.map(|pll| pll * 2u32); - #[cfg(any(rcc_f1, rcc_f1cl, stm32f3, stm32f107))] let usb = match pll { Some(Hertz(72_000_000)) => Some(crate::pac::rcc::vals::Usbpre::DIV1_5), @@ -483,9 +480,6 @@ pub(crate) unsafe fn init(config: Config) { hsi: hsi, hse: hse, pll1_p: pll, - #[cfg(stm32f3)] - pll1_p_mul_2: pll_mul_2, - hsi_div_244: hsi.map(|h| h / 244u32), sys: Some(sys), pclk1: Some(pclk1), pclk2: Some(pclk2), diff --git a/embassy-stm32/src/rcc/f247.rs b/embassy-stm32/src/rcc/f247.rs index 8ce9d5f5b..ee67f1cc0 100644 --- a/embassy-stm32/src/rcc/f247.rs +++ b/embassy-stm32/src/rcc/f247.rs @@ -316,7 +316,6 @@ pub(crate) unsafe fn init(config: Config) { #[cfg(dsihost)] dsi_phy: None, // DSI PLL clock not supported, don't call `RccPeripheral::frequency()` in the drivers - hsi_div488: hsi.map(|hsi| hsi/488u32), hsi_hse: None, afif: None, ); diff --git a/embassy-stm32/src/rcc/g0.rs b/embassy-stm32/src/rcc/g0.rs index 2dbf62a9f..e391b1210 100644 --- a/embassy-stm32/src/rcc/g0.rs +++ b/embassy-stm32/src/rcc/g0.rs @@ -309,8 +309,6 @@ pub(crate) unsafe fn init(config: Config) { #[cfg(crs)] hsi48: hsi48, rtc: rtc, - hsi_div_8: hsi.map(|h| h / 8u32), - hsi_div_488: hsi.map(|h| h / 488u32), // TODO lsi: None, diff --git a/embassy-stm32/src/rcc/g4.rs b/embassy-stm32/src/rcc/g4.rs index 6b34aa306..d7d5c7388 100644 --- a/embassy-stm32/src/rcc/g4.rs +++ b/embassy-stm32/src/rcc/g4.rs @@ -320,6 +320,8 @@ pub(crate) unsafe fn init(config: Config) { hse: hse, hsi48: hsi48, rtc: rtc, + lsi: None, + lse: None, ); } diff --git a/embassy-stm32/src/rcc/h.rs b/embassy-stm32/src/rcc/h.rs index 33d698861..eaba8cefb 100644 --- a/embassy-stm32/src/rcc/h.rs +++ b/embassy-stm32/src/rcc/h.rs @@ -687,7 +687,6 @@ pub(crate) unsafe fn init(config: Config) { hsi: hsi, hsi48: hsi48, csi: csi, - csi_div_122: csi.map(|c| c / 122u32), hse: hse, lse: None, @@ -726,9 +725,9 @@ pub(crate) unsafe fn init(config: Config) { #[cfg(stm32h7rs)] clk48mohci: None, // TODO #[cfg(stm32h7rs)] - hse_div_2: hse.map(|clk| clk / 2u32), - #[cfg(stm32h7rs)] usb: Some(Hertz(48_000_000)), + #[cfg(stm32h5)] + hse_div_rtcpre: None, // TODO ); } diff --git a/embassy-stm32/src/rcc/l.rs b/embassy-stm32/src/rcc/l.rs index 8223a657b..863942f1a 100644 --- a/embassy-stm32/src/rcc/l.rs +++ b/embassy-stm32/src/rcc/l.rs @@ -396,7 +396,7 @@ pub(crate) unsafe fn init(config: Config) { hsi48: hsi48, #[cfg(any(stm32l0, stm32l1))] - pll1_vco_div_2: pll.vco.map(|c| c/2u32), + pll1_vco: pll.vco, #[cfg(not(any(stm32l0, stm32l1)))] pll1_p: pll.p, diff --git a/embassy-stm32/src/rcc/u5.rs b/embassy-stm32/src/rcc/u5.rs index d15eb53f8..93a327be7 100644 --- a/embassy-stm32/src/rcc/u5.rs +++ b/embassy-stm32/src/rcc/u5.rs @@ -345,10 +345,8 @@ pub(crate) unsafe fn init(config: Config) { lse: lse, lsi: lsi, hse: hse, - hse_div_2: hse.map(|clk| clk / 2u32), hsi: hsi, pll1_p: pll1.p, - pll1_p_div_2: pll1.p.map(|clk| clk / 2u32), pll1_q: pll1.q, pll1_r: pll1.r, pll2_p: pll2.p, @@ -363,9 +361,7 @@ pub(crate) unsafe fn init(config: Config) { // TODO audioclk: None, - hsi48_div_2: None, shsi: None, - shsi_div_2: None, ); } From 77d355e0ecb3f5eab4a563981552fdb69175c8c5 Mon Sep 17 00:00:00 2001 From: Alex Moon Date: Fri, 18 Apr 2025 15:08:18 -0400 Subject: [PATCH 0987/1217] Make the nrf Twim RAM buffer a instance variable instead of stack allocated --- embassy-nrf/src/twim.rs | 165 +++------------------ examples/nrf52840/src/bin/twim.rs | 4 +- examples/nrf52840/src/bin/twim_lowpower.rs | 2 + 3 files changed, 28 insertions(+), 143 deletions(-) diff --git a/embassy-nrf/src/twim.rs b/embassy-nrf/src/twim.rs index 083b54b99..95b24c616 100644 --- a/embassy-nrf/src/twim.rs +++ b/embassy-nrf/src/twim.rs @@ -4,7 +4,6 @@ use core::future::{poll_fn, Future}; use core::marker::PhantomData; -use core::mem::MaybeUninit; use core::sync::atomic::compiler_fence; use core::sync::atomic::Ordering::SeqCst; use core::task::Poll; @@ -17,7 +16,7 @@ use embassy_time::{Duration, Instant}; use embedded_hal_1::i2c::Operation; pub use pac::twim::vals::Frequency; -use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE}; +use crate::chip::EASY_DMA_SIZE; use crate::gpio::Pin as GpioPin; use crate::interrupt::typelevel::Interrupt; use crate::pac::gpio::vals as gpiovals; @@ -75,8 +74,8 @@ pub enum Error { Transmit, /// Data reception failed. Receive, - /// The buffer is not in data RAM. It's most likely in flash, and nRF's DMA cannot access flash. - BufferNotInRAM, + /// The buffer is not in data RAM and is larger than the RAM buffer. It's most likely in flash, and nRF's DMA cannot access flash. + RAMBufferTooSmall, /// Didn't receive an ACK bit after the address byte. Address might be wrong, or the i2c device chip might not be connected properly. AddressNack, /// Didn't receive an ACK bit after a data byte. @@ -115,6 +114,7 @@ impl interrupt::typelevel::Handler for InterruptHandl /// TWI driver. pub struct Twim<'d, T: Instance> { _p: Peri<'d, T>, + tx_ram_buffer: &'d mut [u8], } impl<'d, T: Instance> Twim<'d, T> { @@ -125,6 +125,7 @@ impl<'d, T: Instance> Twim<'d, T> { sda: Peri<'d, impl GpioPin>, scl: Peri<'d, impl GpioPin>, config: Config, + tx_ram_buffer: &'d mut [u8], ) -> Self { let r = T::regs(); @@ -159,7 +160,10 @@ impl<'d, T: Instance> Twim<'d, T> { // Enable TWIM instance. r.enable().write(|w| w.set_enable(vals::Enable::ENABLED)); - let mut twim = Self { _p: twim }; + let mut twim = Self { + _p: twim, + tx_ram_buffer, + }; // Apply runtime peripheral configuration Self::set_config(&mut twim, &config).unwrap(); @@ -174,21 +178,17 @@ impl<'d, T: Instance> Twim<'d, T> { } /// Set TX buffer, checking that it is in RAM and has suitable length. - unsafe fn set_tx_buffer( - &mut self, - buffer: &[u8], - ram_buffer: Option<&mut [MaybeUninit; FORCE_COPY_BUFFER_SIZE]>, - ) -> Result<(), Error> { + unsafe fn set_tx_buffer(&mut self, buffer: &[u8]) -> Result<(), Error> { let buffer = if slice_in_ram(buffer) { buffer } else { - let ram_buffer = ram_buffer.ok_or(Error::BufferNotInRAM)?; + if buffer.len() > self.tx_ram_buffer.len() { + return Err(Error::RAMBufferTooSmall); + } trace!("Copying TWIM tx buffer into RAM for DMA"); - let ram_buffer = &mut ram_buffer[..buffer.len()]; - // Inline implementation of the nightly API MaybeUninit::copy_from_slice(ram_buffer, buffer) - let uninit_src: &[MaybeUninit] = unsafe { core::mem::transmute(buffer) }; - ram_buffer.copy_from_slice(uninit_src); - unsafe { &*(ram_buffer as *const [MaybeUninit] as *const [u8]) } + let ram_buffer = &mut self.tx_ram_buffer[..buffer.len()]; + ram_buffer.copy_from_slice(buffer); + &*ram_buffer }; if buffer.len() > EASY_DMA_SIZE { @@ -358,7 +358,6 @@ impl<'d, T: Instance> Twim<'d, T> { &mut self, address: u8, operations: &mut [Operation<'_>], - tx_ram_buffer: Option<&mut [MaybeUninit; FORCE_COPY_BUFFER_SIZE]>, last_op: Option<&Operation<'_>>, inten: bool, ) -> Result { @@ -397,7 +396,7 @@ impl<'d, T: Instance> Twim<'d, T> { // Set up DMA buffers. unsafe { - self.set_tx_buffer(wr_buffer, tx_ram_buffer)?; + self.set_tx_buffer(wr_buffer)?; self.set_rx_buffer(rd_buffer)?; } @@ -450,7 +449,7 @@ impl<'d, T: Instance> Twim<'d, T> { { // Set up DMA buffers. unsafe { - self.set_tx_buffer(wr_buffer, tx_ram_buffer)?; + self.set_tx_buffer(wr_buffer)?; self.set_rx_buffer(rd_buffer)?; } @@ -472,7 +471,7 @@ impl<'d, T: Instance> Twim<'d, T> { // Set up DMA buffers. unsafe { - self.set_tx_buffer(buffer, tx_ram_buffer)?; + self.set_tx_buffer(buffer)?; } // Start write operation. @@ -539,28 +538,9 @@ impl<'d, T: Instance> Twim<'d, T> { /// An `Operation::Write` following an `Operation::Read` must have a /// non-empty buffer. pub fn blocking_transaction(&mut self, address: u8, mut operations: &mut [Operation<'_>]) -> Result<(), Error> { - let mut tx_ram_buffer = [MaybeUninit::uninit(); FORCE_COPY_BUFFER_SIZE]; let mut last_op = None; while !operations.is_empty() { - let ops = self.setup_operations(address, operations, Some(&mut tx_ram_buffer), last_op, false)?; - let (in_progress, rest) = operations.split_at_mut(ops); - self.blocking_wait(); - self.check_operations(in_progress)?; - last_op = in_progress.last(); - operations = rest; - } - Ok(()) - } - - /// Same as [`blocking_transaction`](Twim::blocking_transaction) but will fail instead of copying data into RAM. Consult the module level documentation to learn more. - pub fn blocking_transaction_from_ram( - &mut self, - address: u8, - mut operations: &mut [Operation<'_>], - ) -> Result<(), Error> { - let mut last_op = None; - while !operations.is_empty() { - let ops = self.setup_operations(address, operations, None, last_op, false)?; + let ops = self.setup_operations(address, operations, last_op, false)?; let (in_progress, rest) = operations.split_at_mut(ops); self.blocking_wait(); self.check_operations(in_progress)?; @@ -580,30 +560,9 @@ impl<'d, T: Instance> Twim<'d, T> { mut operations: &mut [Operation<'_>], timeout: Duration, ) -> Result<(), Error> { - let mut tx_ram_buffer = [MaybeUninit::uninit(); FORCE_COPY_BUFFER_SIZE]; let mut last_op = None; while !operations.is_empty() { - let ops = self.setup_operations(address, operations, Some(&mut tx_ram_buffer), last_op, false)?; - let (in_progress, rest) = operations.split_at_mut(ops); - self.blocking_wait_timeout(timeout)?; - self.check_operations(in_progress)?; - last_op = in_progress.last(); - operations = rest; - } - Ok(()) - } - - /// Same as [`blocking_transaction_timeout`](Twim::blocking_transaction_timeout) but will fail instead of copying data into RAM. Consult the module level documentation to learn more. - #[cfg(feature = "time")] - pub fn blocking_transaction_from_ram_timeout( - &mut self, - address: u8, - mut operations: &mut [Operation<'_>], - timeout: Duration, - ) -> Result<(), Error> { - let mut last_op = None; - while !operations.is_empty() { - let ops = self.setup_operations(address, operations, None, last_op, false)?; + let ops = self.setup_operations(address, operations, last_op, false)?; let (in_progress, rest) = operations.split_at_mut(ops); self.blocking_wait_timeout(timeout)?; self.check_operations(in_progress)?; @@ -624,28 +583,9 @@ impl<'d, T: Instance> Twim<'d, T> { /// An `Operation::Write` following an `Operation::Read` must have a /// non-empty buffer. pub async fn transaction(&mut self, address: u8, mut operations: &mut [Operation<'_>]) -> Result<(), Error> { - let mut tx_ram_buffer = [MaybeUninit::uninit(); FORCE_COPY_BUFFER_SIZE]; let mut last_op = None; while !operations.is_empty() { - let ops = self.setup_operations(address, operations, Some(&mut tx_ram_buffer), last_op, true)?; - let (in_progress, rest) = operations.split_at_mut(ops); - self.async_wait().await?; - self.check_operations(in_progress)?; - last_op = in_progress.last(); - operations = rest; - } - Ok(()) - } - - /// Same as [`transaction`](Twim::transaction) but will fail instead of copying data into RAM. Consult the module level documentation to learn more. - pub async fn transaction_from_ram( - &mut self, - address: u8, - mut operations: &mut [Operation<'_>], - ) -> Result<(), Error> { - let mut last_op = None; - while !operations.is_empty() { - let ops = self.setup_operations(address, operations, None, last_op, true)?; + let ops = self.setup_operations(address, operations, last_op, true)?; let (in_progress, rest) = operations.split_at_mut(ops); self.async_wait().await?; self.check_operations(in_progress)?; @@ -665,11 +605,6 @@ impl<'d, T: Instance> Twim<'d, T> { self.blocking_transaction(address, &mut [Operation::Write(buffer)]) } - /// Same as [`blocking_write`](Twim::blocking_write) but will fail instead of copying data into RAM. Consult the module level documentation to learn more. - pub fn blocking_write_from_ram(&mut self, address: u8, buffer: &[u8]) -> Result<(), Error> { - self.blocking_transaction_from_ram(address, &mut [Operation::Write(buffer)]) - } - /// Read from an I2C slave. /// /// The buffer must have a length of at most 255 bytes on the nRF52832 @@ -687,16 +622,6 @@ impl<'d, T: Instance> Twim<'d, T> { self.blocking_transaction(address, &mut [Operation::Write(wr_buffer), Operation::Read(rd_buffer)]) } - /// Same as [`blocking_write_read`](Twim::blocking_write_read) but will fail instead of copying data into RAM. Consult the module level documentation to learn more. - pub fn blocking_write_read_from_ram( - &mut self, - address: u8, - wr_buffer: &[u8], - rd_buffer: &mut [u8], - ) -> Result<(), Error> { - self.blocking_transaction_from_ram(address, &mut [Operation::Write(wr_buffer), Operation::Read(rd_buffer)]) - } - // =========================================== /// Write to an I2C slave with timeout. @@ -707,17 +632,6 @@ impl<'d, T: Instance> Twim<'d, T> { self.blocking_transaction_timeout(address, &mut [Operation::Write(buffer)], timeout) } - /// Same as [`blocking_write`](Twim::blocking_write) but will fail instead of copying data into RAM. Consult the module level documentation to learn more. - #[cfg(feature = "time")] - pub fn blocking_write_from_ram_timeout( - &mut self, - address: u8, - buffer: &[u8], - timeout: Duration, - ) -> Result<(), Error> { - self.blocking_transaction_from_ram_timeout(address, &mut [Operation::Write(buffer)], timeout) - } - /// Read from an I2C slave. /// /// The buffer must have a length of at most 255 bytes on the nRF52832 @@ -747,22 +661,6 @@ impl<'d, T: Instance> Twim<'d, T> { ) } - /// Same as [`blocking_write_read`](Twim::blocking_write_read) but will fail instead of copying data into RAM. Consult the module level documentation to learn more. - #[cfg(feature = "time")] - pub fn blocking_write_read_from_ram_timeout( - &mut self, - address: u8, - wr_buffer: &[u8], - rd_buffer: &mut [u8], - timeout: Duration, - ) -> Result<(), Error> { - self.blocking_transaction_from_ram_timeout( - address, - &mut [Operation::Write(wr_buffer), Operation::Read(rd_buffer)], - timeout, - ) - } - // =========================================== /// Read from an I2C slave. @@ -781,12 +679,6 @@ impl<'d, T: Instance> Twim<'d, T> { self.transaction(address, &mut [Operation::Write(buffer)]).await } - /// Same as [`write`](Twim::write) but will fail instead of copying data into RAM. Consult the module level documentation to learn more. - pub async fn write_from_ram(&mut self, address: u8, buffer: &[u8]) -> Result<(), Error> { - self.transaction_from_ram(address, &mut [Operation::Write(buffer)]) - .await - } - /// Write data to an I2C slave, then read data from the slave without /// triggering a stop condition between the two. /// @@ -796,17 +688,6 @@ impl<'d, T: Instance> Twim<'d, T> { self.transaction(address, &mut [Operation::Write(wr_buffer), Operation::Read(rd_buffer)]) .await } - - /// Same as [`write_read`](Twim::write_read) but will fail instead of copying data into RAM. Consult the module level documentation to learn more. - pub async fn write_read_from_ram( - &mut self, - address: u8, - wr_buffer: &[u8], - rd_buffer: &mut [u8], - ) -> Result<(), Error> { - self.transaction_from_ram(address, &mut [Operation::Write(wr_buffer), Operation::Read(rd_buffer)]) - .await - } } impl<'a, T: Instance> Drop for Twim<'a, T> { @@ -904,7 +785,7 @@ impl embedded_hal_1::i2c::Error for Error { Self::RxBufferTooLong => embedded_hal_1::i2c::ErrorKind::Other, Self::Transmit => embedded_hal_1::i2c::ErrorKind::Other, Self::Receive => embedded_hal_1::i2c::ErrorKind::Other, - Self::BufferNotInRAM => embedded_hal_1::i2c::ErrorKind::Other, + Self::RAMBufferTooSmall => embedded_hal_1::i2c::ErrorKind::Other, Self::AddressNack => { embedded_hal_1::i2c::ErrorKind::NoAcknowledge(embedded_hal_1::i2c::NoAcknowledgeSource::Address) } diff --git a/examples/nrf52840/src/bin/twim.rs b/examples/nrf52840/src/bin/twim.rs index ceaafd784..e30a3855d 100644 --- a/examples/nrf52840/src/bin/twim.rs +++ b/examples/nrf52840/src/bin/twim.rs @@ -9,6 +9,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_nrf::twim::{self, Twim}; use embassy_nrf::{bind_interrupts, peripherals}; +use static_cell::ConstStaticCell; use {defmt_rtt as _, panic_probe as _}; const ADDRESS: u8 = 0x50; @@ -22,7 +23,8 @@ async fn main(_spawner: Spawner) { let p = embassy_nrf::init(Default::default()); info!("Initializing TWI..."); let config = twim::Config::default(); - let mut twi = Twim::new(p.TWISPI0, Irqs, p.P0_03, p.P0_04, config); + static RAM_BUFFER: ConstStaticCell<[u8; 16]> = ConstStaticCell::new([0; 16]); + let mut twi = Twim::new(p.TWISPI0, Irqs, p.P0_03, p.P0_04, config, RAM_BUFFER.take()); info!("Reading..."); diff --git a/examples/nrf52840/src/bin/twim_lowpower.rs b/examples/nrf52840/src/bin/twim_lowpower.rs index 8a6f958eb..f7380e20d 100644 --- a/examples/nrf52840/src/bin/twim_lowpower.rs +++ b/examples/nrf52840/src/bin/twim_lowpower.rs @@ -30,6 +30,7 @@ async fn main(_p: Spawner) { loop { info!("Initializing TWI..."); let config = twim::Config::default(); + let mut ram_buffer = [0u8; 16]; // Create the TWIM instance with borrowed singletons, so they're not consumed. let mut twi = Twim::new( @@ -38,6 +39,7 @@ async fn main(_p: Spawner) { p.P0_03.reborrow(), p.P0_04.reborrow(), config, + &mut ram_buffer, ); info!("Reading..."); From 54ef354d21f7a90b0ccddbe6d1a037b35baa6006 Mon Sep 17 00:00:00 2001 From: 1-rafael-1 Date: Fri, 18 Apr 2025 23:06:20 +0200 Subject: [PATCH 0988/1217] pwm: enable pull-down resistors for pins in Drop implementation --- embassy-rp/src/pwm.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/embassy-rp/src/pwm.rs b/embassy-rp/src/pwm.rs index 6dfb90fef..1e1ccc4c6 100644 --- a/embassy-rp/src/pwm.rs +++ b/embassy-rp/src/pwm.rs @@ -464,6 +464,10 @@ impl<'d> Drop for Pwm<'d> { pac::PWM.ch(self.slice).csr().write_clear(|w| w.set_en(false)); if let Some(pin) = &self.pin_a { pin.gpio().ctrl().write(|w| w.set_funcsel(31)); + // Enable pin PULL-DOWN + pin.pad_ctrl().modify(|w| { + w.set_pde(true); + }); } if let Some(pin) = &self.pin_b { pin.gpio().ctrl().write(|w| w.set_funcsel(31)); @@ -472,6 +476,10 @@ impl<'d> Drop for Pwm<'d> { pin.pad_ctrl().modify(|w| { w.set_ie(false); }); + // Enable pin PULL-DOWN + pin.pad_ctrl().modify(|w| { + w.set_pde(true); + }); } } } From f535acfca09b916554fa63550f9e12f18cbca25d Mon Sep 17 00:00:00 2001 From: Matthew Tran <0e4ef622@gmail.com> Date: Sun, 20 Apr 2025 20:14:13 -0500 Subject: [PATCH 0989/1217] nrf53: add WDT support --- ci.sh | 1 + embassy-boot-nrf/src/lib.rs | 3 +- embassy-nrf/Cargo.toml | 5 +- embassy-nrf/src/chips/nrf51.rs | 2 + embassy-nrf/src/chips/nrf52805.rs | 2 + embassy-nrf/src/chips/nrf52810.rs | 2 + embassy-nrf/src/chips/nrf52811.rs | 2 + embassy-nrf/src/chips/nrf52820.rs | 2 + embassy-nrf/src/chips/nrf52832.rs | 2 + embassy-nrf/src/chips/nrf52833.rs | 2 + embassy-nrf/src/chips/nrf52840.rs | 2 + embassy-nrf/src/chips/nrf5340_app.rs | 6 +- embassy-nrf/src/chips/nrf5340_net.rs | 2 + embassy-nrf/src/chips/nrf9120.rs | 2 + embassy-nrf/src/chips/nrf9160.rs | 2 + embassy-nrf/src/lib.rs | 1 - embassy-nrf/src/wdt.rs | 110 ++++++++++++++++++--------- 17 files changed, 106 insertions(+), 42 deletions(-) diff --git a/ci.sh b/ci.sh index 11c2be186..e27ada508 100755 --- a/ci.sh +++ b/ci.sh @@ -188,6 +188,7 @@ cargo batch \ --- build --release --manifest-path cyw43-pio/Cargo.toml --target thumbv6m-none-eabi --features 'embassy-rp/rp2040' \ --- build --release --manifest-path cyw43-pio/Cargo.toml --target thumbv6m-none-eabi --features 'embassy-rp/rp2040' \ --- build --release --manifest-path embassy-boot-nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840 \ + --- build --release --manifest-path embassy-boot-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf5340-app-s \ --- build --release --manifest-path embassy-boot-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9160-ns \ --- build --release --manifest-path embassy-boot-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9120-ns \ --- build --release --manifest-path embassy-boot-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9151-ns \ diff --git a/embassy-boot-nrf/src/lib.rs b/embassy-boot-nrf/src/lib.rs index 46c1994e2..f1c9da080 100644 --- a/embassy-boot-nrf/src/lib.rs +++ b/embassy-boot-nrf/src/lib.rs @@ -8,7 +8,6 @@ pub use embassy_boot::{ FirmwareUpdater, FirmwareUpdaterConfig, }; use embassy_nrf::nvmc::PAGE_SIZE; -use embassy_nrf::peripherals::WDT; use embassy_nrf::{wdt, Peri}; use embedded_storage::nor_flash::{ErrorType, NorFlash, ReadNorFlash}; @@ -113,7 +112,7 @@ pub struct WatchdogFlash { impl WatchdogFlash { /// Start a new watchdog with a given flash and WDT peripheral and a timeout - pub fn start(flash: FLASH, wdt: Peri<'static, WDT>, config: wdt::Config) -> Self { + pub fn start(flash: FLASH, wdt: Peri<'static, impl wdt::Instance>, config: wdt::Config) -> Self { let (_wdt, [wdt]) = match wdt::Watchdog::try_new(wdt, config) { Ok(x) => x, Err(_) => { diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml index 405115dd7..6ca099599 100644 --- a/embassy-nrf/Cargo.toml +++ b/embassy-nrf/Cargo.toml @@ -109,7 +109,7 @@ nrf9161-ns = ["nrf9120-ns"] # Features starting with `_` are for internal use only. They're not intended # to be enabled by other crates, and are not covered by semver guarantees. -_nrf5340-app = ["_nrf5340", "nrf-pac/nrf5340-app"] +_nrf5340-app = ["_nrf5340", "_multi_wdt", "nrf-pac/nrf5340-app"] _nrf5340-net = ["_nrf5340", "nrf-pac/nrf5340-net"] _nrf5340 = ["_gpio-p1", "_dppi"] _nrf54l15-app = ["_nrf54l15", "nrf-pac/nrf54l15-app"] @@ -136,6 +136,9 @@ _gpio-p2 = [] # Errata workarounds _nrf52832_anomaly_109 = [] +# watchdog timer +_multi_wdt = [] + [dependencies] embassy-time-driver = { version = "0.2", path = "../embassy-time-driver", optional = true } embassy-time-queue-utils = { version = "0.1", path = "../embassy-time-queue-utils", optional = true } diff --git a/embassy-nrf/src/chips/nrf51.rs b/embassy-nrf/src/chips/nrf51.rs index a0365a6ee..fd13ae5c4 100644 --- a/embassy-nrf/src/chips/nrf51.rs +++ b/embassy-nrf/src/chips/nrf51.rs @@ -145,6 +145,8 @@ impl_pin!(P0_31, 0, 31); impl_radio!(RADIO, RADIO, RADIO); +impl_wdt!(WDT, WDT, WDT, 0); + embassy_hal_internal::interrupt_mod!( CLOCK_POWER, RADIO, diff --git a/embassy-nrf/src/chips/nrf52805.rs b/embassy-nrf/src/chips/nrf52805.rs index a9cbccec4..7e72df8fc 100644 --- a/embassy-nrf/src/chips/nrf52805.rs +++ b/embassy-nrf/src/chips/nrf52805.rs @@ -221,6 +221,8 @@ impl_radio!(RADIO, RADIO, RADIO); impl_egu!(EGU0, EGU0, EGU0_SWI0); impl_egu!(EGU1, EGU1, EGU1_SWI1); +impl_wdt!(WDT, WDT, WDT, 0); + embassy_hal_internal::interrupt_mod!( CLOCK_POWER, RADIO, diff --git a/embassy-nrf/src/chips/nrf52810.rs b/embassy-nrf/src/chips/nrf52810.rs index ca31c35e1..e388e44e8 100644 --- a/embassy-nrf/src/chips/nrf52810.rs +++ b/embassy-nrf/src/chips/nrf52810.rs @@ -247,6 +247,8 @@ impl_radio!(RADIO, RADIO, RADIO); impl_egu!(EGU0, EGU0, EGU0_SWI0); impl_egu!(EGU1, EGU1, EGU1_SWI1); +impl_wdt!(WDT, WDT, WDT, 0); + embassy_hal_internal::interrupt_mod!( CLOCK_POWER, RADIO, diff --git a/embassy-nrf/src/chips/nrf52811.rs b/embassy-nrf/src/chips/nrf52811.rs index caf3fdcf8..96b8df30b 100644 --- a/embassy-nrf/src/chips/nrf52811.rs +++ b/embassy-nrf/src/chips/nrf52811.rs @@ -249,6 +249,8 @@ impl_radio!(RADIO, RADIO, RADIO); impl_egu!(EGU0, EGU0, EGU0_SWI0); impl_egu!(EGU1, EGU1, EGU1_SWI1); +impl_wdt!(WDT, WDT, WDT, 0); + embassy_hal_internal::interrupt_mod!( CLOCK_POWER, RADIO, diff --git a/embassy-nrf/src/chips/nrf52820.rs b/embassy-nrf/src/chips/nrf52820.rs index 39573e4a5..ad461b153 100644 --- a/embassy-nrf/src/chips/nrf52820.rs +++ b/embassy-nrf/src/chips/nrf52820.rs @@ -244,6 +244,8 @@ impl_egu!(EGU3, EGU3, EGU3_SWI3); impl_egu!(EGU4, EGU4, EGU4_SWI4); impl_egu!(EGU5, EGU5, EGU5_SWI5); +impl_wdt!(WDT, WDT, WDT, 0); + embassy_hal_internal::interrupt_mod!( CLOCK_POWER, RADIO, diff --git a/embassy-nrf/src/chips/nrf52832.rs b/embassy-nrf/src/chips/nrf52832.rs index 2d9346229..cf2abf23a 100644 --- a/embassy-nrf/src/chips/nrf52832.rs +++ b/embassy-nrf/src/chips/nrf52832.rs @@ -287,6 +287,8 @@ impl_egu!(EGU3, EGU3, EGU3_SWI3); impl_egu!(EGU4, EGU4, EGU4_SWI4); impl_egu!(EGU5, EGU5, EGU5_SWI5); +impl_wdt!(WDT, WDT, WDT, 0); + embassy_hal_internal::interrupt_mod!( CLOCK_POWER, RADIO, diff --git a/embassy-nrf/src/chips/nrf52833.rs b/embassy-nrf/src/chips/nrf52833.rs index 4e4915c32..e46eb1d2b 100644 --- a/embassy-nrf/src/chips/nrf52833.rs +++ b/embassy-nrf/src/chips/nrf52833.rs @@ -329,6 +329,8 @@ impl_egu!(EGU3, EGU3, EGU3_SWI3); impl_egu!(EGU4, EGU4, EGU4_SWI4); impl_egu!(EGU5, EGU5, EGU5_SWI5); +impl_wdt!(WDT, WDT, WDT, 0); + embassy_hal_internal::interrupt_mod!( CLOCK_POWER, RADIO, diff --git a/embassy-nrf/src/chips/nrf52840.rs b/embassy-nrf/src/chips/nrf52840.rs index 70a56971b..88747843d 100644 --- a/embassy-nrf/src/chips/nrf52840.rs +++ b/embassy-nrf/src/chips/nrf52840.rs @@ -334,6 +334,8 @@ impl_egu!(EGU3, EGU3, EGU3_SWI3); impl_egu!(EGU4, EGU4, EGU4_SWI4); impl_egu!(EGU5, EGU5, EGU5_SWI5); +impl_wdt!(WDT, WDT, WDT, 0); + embassy_hal_internal::interrupt_mod!( CLOCK_POWER, RADIO, diff --git a/embassy-nrf/src/chips/nrf5340_app.rs b/embassy-nrf/src/chips/nrf5340_app.rs index 86274bf48..0103fa7ae 100644 --- a/embassy-nrf/src/chips/nrf5340_app.rs +++ b/embassy-nrf/src/chips/nrf5340_app.rs @@ -171,7 +171,8 @@ embassy_hal_internal::peripherals! { RTC1, // WDT - WDT, + WDT0, + WDT1, // NVMC NVMC, @@ -473,6 +474,9 @@ impl_egu!(EGU3, EGU3, EGU3); impl_egu!(EGU4, EGU4, EGU4); impl_egu!(EGU5, EGU5, EGU5); +impl_wdt!(WDT0, WDT0, WDT0, 0); +impl_wdt!(WDT1, WDT1, WDT1, 1); + embassy_hal_internal::interrupt_mod!( FPU, CACHE, diff --git a/embassy-nrf/src/chips/nrf5340_net.rs b/embassy-nrf/src/chips/nrf5340_net.rs index 6c6ac3fbb..22d33d080 100644 --- a/embassy-nrf/src/chips/nrf5340_net.rs +++ b/embassy-nrf/src/chips/nrf5340_net.rs @@ -299,6 +299,8 @@ impl_radio!(RADIO, RADIO, RADIO); impl_egu!(EGU0, EGU0, EGU0); +impl_wdt!(WDT, WDT, WDT, 0); + embassy_hal_internal::interrupt_mod!( CLOCK_POWER, RADIO, diff --git a/embassy-nrf/src/chips/nrf9120.rs b/embassy-nrf/src/chips/nrf9120.rs index b02b8c6d8..e8ddbf86f 100644 --- a/embassy-nrf/src/chips/nrf9120.rs +++ b/embassy-nrf/src/chips/nrf9120.rs @@ -342,6 +342,8 @@ impl_egu!(EGU3, EGU3, EGU3); impl_egu!(EGU4, EGU4, EGU4); impl_egu!(EGU5, EGU5, EGU5); +impl_wdt!(WDT, WDT, WDT, 0); + embassy_hal_internal::interrupt_mod!( SPU, CLOCK_POWER, diff --git a/embassy-nrf/src/chips/nrf9160.rs b/embassy-nrf/src/chips/nrf9160.rs index b0981e3b5..5d04a72e5 100644 --- a/embassy-nrf/src/chips/nrf9160.rs +++ b/embassy-nrf/src/chips/nrf9160.rs @@ -342,6 +342,8 @@ impl_egu!(EGU3, EGU3, EGU3); impl_egu!(EGU4, EGU4, EGU4); impl_egu!(EGU5, EGU5, EGU5); +impl_wdt!(WDT, WDT, WDT, 0); + embassy_hal_internal::interrupt_mod!( SPU, CLOCK_POWER, diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index d2ff054f4..07ba2f6d4 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs @@ -169,7 +169,6 @@ pub mod uarte; ))] pub mod usb; #[cfg(not(feature = "_nrf54l"))] // TODO -#[cfg(not(feature = "_nrf5340"))] pub mod wdt; // This mod MUST go last, so that it sees all the `impl_foo!` macros diff --git a/embassy-nrf/src/wdt.rs b/embassy-nrf/src/wdt.rs index 11cfa398e..baaf1c801 100644 --- a/embassy-nrf/src/wdt.rs +++ b/embassy-nrf/src/wdt.rs @@ -3,11 +3,15 @@ //! This HAL implements a basic watchdog timer with 1..=8 handles. //! Once the watchdog has been started, it cannot be stopped. -use core::marker::PhantomData; +#![macro_use] + +use core::hint::unreachable_unchecked; + +use embassy_hal_internal::PeripheralType; use crate::pac::wdt::vals; pub use crate::pac::wdt::vals::{Halt as HaltConfig, Sleep as SleepConfig}; -use crate::{peripherals, Peri}; +use crate::{interrupt, pac, peripherals, Peri}; const MIN_TICKS: u32 = 15; @@ -30,12 +34,12 @@ pub struct Config { impl Config { /// Create a config structure from the current configuration of the WDT /// peripheral. - pub fn try_new(_wdt: &peripherals::WDT) -> Option { - let r = crate::pac::WDT; + pub fn try_new(_wdt: &Peri<'_, T>) -> Option { + let r = T::REGS; - #[cfg(not(feature = "_nrf91"))] + #[cfg(not(any(feature = "_nrf91", feature = "_nrf5340")))] let runstatus = r.runstatus().read().runstatus(); - #[cfg(feature = "_nrf91")] + #[cfg(any(feature = "_nrf91", feature = "_nrf5340"))] let runstatus = r.runstatus().read().runstatuswdt(); if runstatus { @@ -62,11 +66,11 @@ impl Default for Config { } /// Watchdog driver. -pub struct Watchdog { - _wdt: Peri<'static, peripherals::WDT>, +pub struct Watchdog { + _wdt: Peri<'static, T>, } -impl Watchdog { +impl Watchdog { /// Try to create a new watchdog driver. /// /// This function will return an error if the watchdog is already active @@ -76,19 +80,19 @@ impl Watchdog { /// `N` must be between 1 and 8, inclusive. #[inline] pub fn try_new( - wdt: Peri<'static, peripherals::WDT>, + wdt: Peri<'static, T>, config: Config, - ) -> Result<(Self, [WatchdogHandle; N]), Peri<'static, peripherals::WDT>> { + ) -> Result<(Self, [WatchdogHandle; N]), Peri<'static, T>> { assert!(N >= 1 && N <= 8); - let r = crate::pac::WDT; + let r = T::REGS; let crv = config.timeout_ticks.max(MIN_TICKS); let rren = crate::pac::wdt::regs::Rren((1u32 << N) - 1); - #[cfg(not(feature = "_nrf91"))] + #[cfg(not(any(feature = "_nrf91", feature = "_nrf5340")))] let runstatus = r.runstatus().read().runstatus(); - #[cfg(feature = "_nrf91")] + #[cfg(any(feature = "_nrf91", feature = "_nrf5340"))] let runstatus = r.runstatus().read().runstatuswdt(); if runstatus { @@ -114,17 +118,9 @@ impl Watchdog { let this = Self { _wdt: wdt }; - let mut handles = [const { - WatchdogHandle { - _wdt: PhantomData, - index: 0, - } - }; N]; + let mut handles = [const { WatchdogHandle { index: 0 } }; N]; for i in 0..N { - handles[i] = WatchdogHandle { - _wdt: PhantomData, - index: i as u8, - }; + handles[i] = unsafe { WatchdogHandle::steal(T::INDEX, i as u8) }; handles[i].pet(); } @@ -139,7 +135,7 @@ impl Watchdog { /// interrupt has been enabled. #[inline(always)] pub fn enable_interrupt(&mut self) { - crate::pac::WDT.intenset().write(|w| w.set_timeout(true)); + T::REGS.intenset().write(|w| w.set_timeout(true)); } /// Disable the watchdog interrupt. @@ -147,7 +143,7 @@ impl Watchdog { /// NOTE: This has no effect on the reset caused by the Watchdog. #[inline(always)] pub fn disable_interrupt(&mut self) { - crate::pac::WDT.intenclr().write(|w| w.set_timeout(true)); + T::REGS.intenclr().write(|w| w.set_timeout(true)); } /// Is the watchdog still awaiting pets from any handle? @@ -156,7 +152,7 @@ impl Watchdog { /// handles to prevent a reset this time period. #[inline(always)] pub fn awaiting_pets(&self) -> bool { - let r = crate::pac::WDT; + let r = T::REGS; let enabled = r.rren().read().0; let status = r.reqstatus().read().0; (status & enabled) == 0 @@ -165,11 +161,26 @@ impl Watchdog { /// Watchdog handle. pub struct WatchdogHandle { - _wdt: PhantomData>, index: u8, } impl WatchdogHandle { + fn regs(&self) -> pac::wdt::Wdt { + match self.index / 8 { + #[cfg(not(feature = "_multi_wdt"))] + peripherals::WDT::INDEX => peripherals::WDT::REGS, + #[cfg(feature = "_multi_wdt")] + peripherals::WDT0::INDEX => peripherals::WDT0::REGS, + #[cfg(feature = "_multi_wdt")] + peripherals::WDT1::INDEX => peripherals::WDT1::REGS, + _ => unsafe { unreachable_unchecked() }, + } + } + + fn rr_index(&self) -> usize { + usize::from(self.index % 8) + } + /// Pet the watchdog. /// /// This function pets the given watchdog handle. @@ -178,25 +189,50 @@ impl WatchdogHandle { /// prevent a reset from occurring. #[inline] pub fn pet(&mut self) { - let r = crate::pac::WDT; - r.rr(self.index as usize).write(|w| w.set_rr(vals::Rr::RELOAD)); + let r = self.regs(); + r.rr(self.rr_index()).write(|w| w.set_rr(vals::Rr::RELOAD)); } /// Has this handle been pet within the current window? pub fn is_pet(&self) -> bool { - let r = crate::pac::WDT; - !r.reqstatus().read().rr(self.index as usize) + let r = self.regs(); + !r.reqstatus().read().rr(self.rr_index()) } /// Steal a watchdog handle by index. /// /// # Safety - /// Watchdog must be initialized and `index` must be between `0` and `N-1` - /// where `N` is the handle count when initializing. - pub unsafe fn steal(index: u8) -> Self { + /// Watchdog must be initialized, `instance_index` must be the index + /// [`Instance::INDEX`], and `index` must be between `0` and `N-1` where `N` + /// is the handle count when initializing. + pub unsafe fn steal(instance_index: u8, index: u8) -> Self { Self { - _wdt: PhantomData, - index, + index: instance_index * 8 + index, } } } + +pub(crate) trait SealedInstance { + const REGS: pac::wdt::Wdt; +} + +/// WDT instance. +#[allow(private_bounds)] +pub trait Instance: SealedInstance + PeripheralType + 'static + Send { + /// Interrupt for this peripheral. + type Interrupt: interrupt::typelevel::Interrupt; + /// Index of the watchdog instance. + const INDEX: u8; +} + +macro_rules! impl_wdt { + ($type:ident, $pac_type:ident, $irq:ident, $index:literal) => { + impl crate::wdt::SealedInstance for peripherals::$type { + const REGS: pac::wdt::Wdt = pac::$pac_type; + } + impl crate::wdt::Instance for peripherals::$type { + type Interrupt = crate::interrupt::typelevel::$irq; + const INDEX: u8 = $index; + } + }; +} From c00e3f94f0ecccfc8afce3fb9bd19b05d3f8889b Mon Sep 17 00:00:00 2001 From: Matthew Tran <0e4ef622@gmail.com> Date: Mon, 21 Apr 2025 10:43:02 -0500 Subject: [PATCH 0990/1217] nrf: make wdt INDEX private --- embassy-nrf/src/wdt.rs | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/embassy-nrf/src/wdt.rs b/embassy-nrf/src/wdt.rs index baaf1c801..308071726 100644 --- a/embassy-nrf/src/wdt.rs +++ b/embassy-nrf/src/wdt.rs @@ -120,7 +120,7 @@ impl Watchdog { let mut handles = [const { WatchdogHandle { index: 0 } }; N]; for i in 0..N { - handles[i] = unsafe { WatchdogHandle::steal(T::INDEX, i as u8) }; + handles[i] = unsafe { WatchdogHandle::steal::(i as u8) }; handles[i].pet(); } @@ -202,18 +202,18 @@ impl WatchdogHandle { /// Steal a watchdog handle by index. /// /// # Safety - /// Watchdog must be initialized, `instance_index` must be the index - /// [`Instance::INDEX`], and `index` must be between `0` and `N-1` where `N` - /// is the handle count when initializing. - pub unsafe fn steal(instance_index: u8, index: u8) -> Self { + /// Watchdog must be initialized and `index` must be between `0` and `N-1` + /// where `N` is the handle count when initializing. + pub unsafe fn steal(index: u8) -> Self { Self { - index: instance_index * 8 + index, + index: T::INDEX * 8 + index, } } } pub(crate) trait SealedInstance { const REGS: pac::wdt::Wdt; + const INDEX: u8; } /// WDT instance. @@ -221,18 +221,16 @@ pub(crate) trait SealedInstance { pub trait Instance: SealedInstance + PeripheralType + 'static + Send { /// Interrupt for this peripheral. type Interrupt: interrupt::typelevel::Interrupt; - /// Index of the watchdog instance. - const INDEX: u8; } macro_rules! impl_wdt { ($type:ident, $pac_type:ident, $irq:ident, $index:literal) => { impl crate::wdt::SealedInstance for peripherals::$type { const REGS: pac::wdt::Wdt = pac::$pac_type; + const INDEX: u8 = $index; } impl crate::wdt::Instance for peripherals::$type { type Interrupt = crate::interrupt::typelevel::$irq; - const INDEX: u8 = $index; } }; } From 3c9661cebc0f093d8d9a194adca2d1c815ebfd2e Mon Sep 17 00:00:00 2001 From: Gerhard de Clercq <11624490+Gerharddc@users.noreply.github.com> Date: Tue, 22 Apr 2025 12:20:21 +0200 Subject: [PATCH 0991/1217] [embassy-usb-dfu] Add generic DFU marking interface This commit adds an interface that allows users to customise how the bootloader is informed that DFU mode is needed on the next boot. --- embassy-usb-dfu/src/application.rs | 36 +++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/embassy-usb-dfu/src/application.rs b/embassy-usb-dfu/src/application.rs index f0d7626f6..e93c241ad 100644 --- a/embassy-usb-dfu/src/application.rs +++ b/embassy-usb-dfu/src/application.rs @@ -13,9 +13,25 @@ use crate::consts::{ }; use crate::Reset; +/// Generic interface for a system that can signal to the bootloader that USB DFU mode is needed on the next boot. +/// +/// By default this trait is implemented for `BlockingFirmwareState<'d, STATE>` but you could also implement this generic +/// interface yourself instead in more complex situations. This could for instance be when you cannot hand ownership of a +/// `BlockingFirmwareState` instance over directly to the DFU `Control` instance and need to use a more complex mechanism. +pub trait DfuMarker { + /// Signal to the bootloader that DFU mode should be used on the next boot. + fn mark_dfu(&mut self); +} + +impl<'d, STATE: NorFlash> DfuMarker for BlockingFirmwareState<'d, STATE> { + fn mark_dfu(&mut self) { + self.mark_dfu().expect("Failed to mark DFU mode in bootloader") + } +} + /// Internal state for the DFU class -pub struct Control<'d, STATE: NorFlash, RST: Reset> { - firmware_state: BlockingFirmwareState<'d, STATE>, +pub struct Control { + dfu_marker: MARK, attrs: DfuAttributes, state: State, timeout: Option, @@ -23,11 +39,11 @@ pub struct Control<'d, STATE: NorFlash, RST: Reset> { _rst: PhantomData, } -impl<'d, STATE: NorFlash, RST: Reset> Control<'d, STATE, RST> { +impl Control { /// Create a new DFU instance to expose a DFU interface. - pub fn new(firmware_state: BlockingFirmwareState<'d, STATE>, attrs: DfuAttributes) -> Self { + pub fn new(dfu_marker: MARK, attrs: DfuAttributes) -> Self { Control { - firmware_state, + dfu_marker, attrs, state: State::AppIdle, detach_start: None, @@ -37,7 +53,7 @@ impl<'d, STATE: NorFlash, RST: Reset> Control<'d, STATE, RST> { } } -impl<'d, STATE: NorFlash, RST: Reset> Handler for Control<'d, STATE, RST> { +impl Handler for Control { fn reset(&mut self) { if let Some(start) = self.detach_start { let delta = Instant::now() - start; @@ -48,9 +64,7 @@ impl<'d, STATE: NorFlash, RST: Reset> Handler for Control<'d, STATE, RST> { timeout.as_millis() ); if delta < timeout { - self.firmware_state - .mark_dfu() - .expect("Failed to mark DFU mode in bootloader"); + self.dfu_marker.mark_dfu(); RST::sys_reset() } } @@ -109,9 +123,9 @@ impl<'d, STATE: NorFlash, RST: Reset> Handler for Control<'d, STATE, RST> { /// it should expose a DFU device, and a software reset will be issued. /// /// To apply USB DFU updates, the bootloader must be capable of recognizing the DFU magic and exposing a device to handle the full DFU transaction with the host. -pub fn usb_dfu<'d, D: Driver<'d>, STATE: NorFlash, RST: Reset>( +pub fn usb_dfu<'d, D: Driver<'d>, MARK: DfuMarker, RST: Reset>( builder: &mut Builder<'d, D>, - handler: &'d mut Control<'d, STATE, RST>, + handler: &'d mut Control, timeout: Duration, ) { let mut func = builder.function(0x00, 0x00, 0x00); From d8631f96d95b42cdf963b7a836f966570981d884 Mon Sep 17 00:00:00 2001 From: Sebastian Gabrielli Date: Tue, 22 Apr 2025 12:47:33 +0200 Subject: [PATCH 0992/1217] Disable SPI before changing config, then re-enable SPI on STM32 Fixes #2259 --- embassy-stm32/src/spi/mod.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs index 6578aa1aa..9e2ba093a 100644 --- a/embassy-stm32/src/spi/mod.rs +++ b/embassy-stm32/src/spi/mod.rs @@ -284,6 +284,10 @@ impl<'d, M: PeriMode> Spi<'d, M> { #[cfg(any(spi_v3, spi_v4, spi_v5))] { + self.info.regs.cr1().modify(|w| { + w.set_spe(false); + }); + self.info.regs.cfg2().modify(|w| { w.set_cpha(cpha); w.set_cpol(cpol); @@ -292,6 +296,10 @@ impl<'d, M: PeriMode> Spi<'d, M> { self.info.regs.cfg1().modify(|w| { w.set_mbr(br); }); + + self.info.regs.cr1().modify(|w| { + w.set_spe(true); + }); } Ok(()) } From 0b8f43b714ab8ae951740a9e45c04d7a855c2067 Mon Sep 17 00:00:00 2001 From: Alex Moon Date: Wed, 23 Apr 2025 13:15:17 -0400 Subject: [PATCH 0993/1217] Manually implement the future for `with_timeout` --- embassy-time/src/timer.rs | 61 +++++++++++++++++++++++++++------------ 1 file changed, 42 insertions(+), 19 deletions(-) diff --git a/embassy-time/src/timer.rs b/embassy-time/src/timer.rs index 34e5762d2..d1162eadd 100644 --- a/embassy-time/src/timer.rs +++ b/embassy-time/src/timer.rs @@ -1,8 +1,7 @@ use core::future::{poll_fn, Future}; -use core::pin::{pin, Pin}; +use core::pin::Pin; use core::task::{Context, Poll}; -use futures_util::future::{select, Either}; use futures_util::stream::FusedStream; use futures_util::Stream; @@ -17,11 +16,10 @@ pub struct TimeoutError; /// /// If the future completes before the timeout, its output is returned. Otherwise, on timeout, /// work on the future is stopped (`poll` is no longer called), the future is dropped and `Err(TimeoutError)` is returned. -pub async fn with_timeout(timeout: Duration, fut: F) -> Result { - let timeout_fut = Timer::after(timeout); - match select(pin!(fut), timeout_fut).await { - Either::Left((r, _)) => Ok(r), - Either::Right(_) => Err(TimeoutError), +pub fn with_timeout(timeout: Duration, fut: F) -> TimeoutFuture { + TimeoutFuture { + timer: Timer::after(timeout), + fut, } } @@ -29,16 +27,15 @@ pub async fn with_timeout(timeout: Duration, fut: F) -> Result(at: Instant, fut: F) -> Result { - let timeout_fut = Timer::at(at); - match select(pin!(fut), timeout_fut).await { - Either::Left((r, _)) => Ok(r), - Either::Right(_) => Err(TimeoutError), +pub fn with_deadline(at: Instant, fut: F) -> TimeoutFuture { + TimeoutFuture { + timer: Timer::at(at), + fut, } } /// Provides functions to run a given future with a timeout or a deadline. -pub trait WithTimeout { +pub trait WithTimeout: Sized { /// Output type of the future. type Output; @@ -46,24 +43,50 @@ pub trait WithTimeout { /// /// If the future completes before the timeout, its output is returned. Otherwise, on timeout, /// work on the future is stopped (`poll` is no longer called), the future is dropped and `Err(TimeoutError)` is returned. - async fn with_timeout(self, timeout: Duration) -> Result; + fn with_timeout(self, timeout: Duration) -> TimeoutFuture; /// Runs a given future with a deadline time. /// /// If the future completes before the deadline, its output is returned. Otherwise, on timeout, /// work on the future is stopped (`poll` is no longer called), the future is dropped and `Err(TimeoutError)` is returned. - async fn with_deadline(self, at: Instant) -> Result; + fn with_deadline(self, at: Instant) -> TimeoutFuture; } impl WithTimeout for F { type Output = F::Output; - async fn with_timeout(self, timeout: Duration) -> Result { - with_timeout(timeout, self).await + fn with_timeout(self, timeout: Duration) -> TimeoutFuture { + with_timeout(timeout, self) } - async fn with_deadline(self, at: Instant) -> Result { - with_deadline(at, self).await + fn with_deadline(self, at: Instant) -> TimeoutFuture { + with_deadline(at, self) + } +} + +/// Future for the [`with_timeout`] and [`with_deadline`] functions. +#[must_use = "futures do nothing unless you `.await` or poll them"] +pub struct TimeoutFuture { + timer: Timer, + fut: F, +} + +impl Unpin for TimeoutFuture {} + +impl Future for TimeoutFuture { + type Output = Result; + + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + let this = unsafe { self.get_unchecked_mut() }; + let fut = unsafe { Pin::new_unchecked(&mut this.fut) }; + let timer = unsafe { Pin::new_unchecked(&mut this.timer) }; + if let Poll::Ready(x) = fut.poll(cx) { + return Poll::Ready(Ok(x)); + } + if let Poll::Ready(_) = timer.poll(cx) { + return Poll::Ready(Err(TimeoutError)); + } + Poll::Pending } } From 8cf8fb324ce9063890d8912cccd02bc79fbffd1d Mon Sep 17 00:00:00 2001 From: Michael Medin Date: Thu, 24 Apr 2025 07:15:11 +0200 Subject: [PATCH 0994/1217] Add function to allow re-init rcc config for stm32 --- embassy-stm32/src/lib.rs | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 226293a9d..0cc6886d9 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -616,3 +616,31 @@ fn init_hw(config: Config) -> Peripherals { p }) } + + +/// Re-initialize the `embassy-stm32` clock configuration with the provided configuration. +/// +/// This is useful when you need to alter the CPU clock after configuring peripherals. +/// For instance, configure an external clock via spi or i2c. +/// +/// Please not this only re-configures the rcc and the time driver (not GPIO, EXTI, etc). +/// +/// This should only be called after `init`. +#[cfg(not(feature = "_dual-core"))] +pub fn reinitialize_rcc(config: Config) { + critical_section::with(|cs| { + unsafe { + rcc::init(config.rcc); + + // must be after rcc init + #[cfg(feature = "_time-driver")] + time_driver::init(cs); + + #[cfg(feature = "low-power")] + { + crate::rcc::REFCOUNT_STOP2 = 0; + crate::rcc::REFCOUNT_STOP1 = 0; + } + } + }) +} From f67f11534f9617279b9ff83a693aad5f7ceb4d4f Mon Sep 17 00:00:00 2001 From: Michael Medin Date: Thu, 24 Apr 2025 07:25:21 +0200 Subject: [PATCH 0995/1217] Fixed formatting --- embassy-stm32/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 0cc6886d9..cccffd4fe 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -617,7 +617,6 @@ fn init_hw(config: Config) -> Peripherals { }) } - /// Re-initialize the `embassy-stm32` clock configuration with the provided configuration. /// /// This is useful when you need to alter the CPU clock after configuring peripherals. From 6842ced7cb858f7735bc9376db9d39386dadec58 Mon Sep 17 00:00:00 2001 From: Michael Medin Date: Thu, 24 Apr 2025 10:17:04 +0200 Subject: [PATCH 0996/1217] Fixed for cs not always used --- embassy-stm32/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index cccffd4fe..1ad30d522 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -627,13 +627,13 @@ fn init_hw(config: Config) -> Peripherals { /// This should only be called after `init`. #[cfg(not(feature = "_dual-core"))] pub fn reinitialize_rcc(config: Config) { - critical_section::with(|cs| { + critical_section::with(|_cs| { unsafe { rcc::init(config.rcc); // must be after rcc init #[cfg(feature = "_time-driver")] - time_driver::init(cs); + time_driver::init(_cs); #[cfg(feature = "low-power")] { From b2c32a947ea724facb75f81978dfb5d3ca331ddb Mon Sep 17 00:00:00 2001 From: Michael Medin Date: Thu, 24 Apr 2025 10:54:35 +0200 Subject: [PATCH 0997/1217] Updated based on feedback --- embassy-stm32/src/lib.rs | 48 ++++++++++++++++++---------------------- 1 file changed, 21 insertions(+), 27 deletions(-) diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 1ad30d522..af7ef9fe0 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -222,6 +222,7 @@ pub(crate) use stm32_metapac as pac; use crate::interrupt::Priority; #[cfg(feature = "rt")] pub use crate::pac::NVIC_PRIO_BITS; +use critical_section::CriticalSection; /// `embassy-stm32` global configuration. #[non_exhaustive] @@ -600,17 +601,7 @@ fn init_hw(config: Config) -> Peripherals { #[cfg(feature = "exti")] exti::init(cs); - rcc::init(config.rcc); - - // must be after rcc init - #[cfg(feature = "_time-driver")] - time_driver::init(cs); - - #[cfg(feature = "low-power")] - { - crate::rcc::REFCOUNT_STOP2 = 0; - crate::rcc::REFCOUNT_STOP1 = 0; - } + init_rcc(cs, config.rcc); } p @@ -626,20 +617,23 @@ fn init_hw(config: Config) -> Peripherals { /// /// This should only be called after `init`. #[cfg(not(feature = "_dual-core"))] -pub fn reinitialize_rcc(config: Config) { - critical_section::with(|_cs| { - unsafe { - rcc::init(config.rcc); - - // must be after rcc init - #[cfg(feature = "_time-driver")] - time_driver::init(_cs); - - #[cfg(feature = "low-power")] - { - crate::rcc::REFCOUNT_STOP2 = 0; - crate::rcc::REFCOUNT_STOP1 = 0; - } - } - }) +pub fn reinit(config: rcc::Config) { + critical_section::with(|cs| init_rcc(cs, config)) +} + +#[cfg(not(feature = "_dual-core"))] +fn init_rcc(_cs: CriticalSection, config: rcc::Config) { + unsafe { + rcc::init(config); + + // must be after rcc init + #[cfg(feature = "_time-driver")] + time_driver::init(_cs); + + #[cfg(feature = "low-power")] + { + crate::rcc::REFCOUNT_STOP2 = 0; + crate::rcc::REFCOUNT_STOP1 = 0; + } + } } From 8661b019e609f50bd78067cc49c65a4babfead00 Mon Sep 17 00:00:00 2001 From: Michael Medin Date: Thu, 24 Apr 2025 10:57:02 +0200 Subject: [PATCH 0998/1217] Fixed formatting --- embassy-stm32/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index af7ef9fe0..b0bc7ffbb 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -213,6 +213,7 @@ macro_rules! bind_interrupts { // Reexports pub use _generated::{peripherals, Peripherals}; +use critical_section::CriticalSection; pub use embassy_hal_internal::{Peri, PeripheralType}; #[cfg(feature = "unstable-pac")] pub use stm32_metapac as pac; @@ -222,7 +223,6 @@ pub(crate) use stm32_metapac as pac; use crate::interrupt::Priority; #[cfg(feature = "rt")] pub use crate::pac::NVIC_PRIO_BITS; -use critical_section::CriticalSection; /// `embassy-stm32` global configuration. #[non_exhaustive] From b0519d11fb0842267e0cdd36da9b84cdb0ebb23a Mon Sep 17 00:00:00 2001 From: Michael Medin Date: Thu, 24 Apr 2025 11:01:46 +0200 Subject: [PATCH 0999/1217] Possible fix for unused CS and feature selections --- embassy-stm32/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index b0bc7ffbb..466634edf 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -213,6 +213,7 @@ macro_rules! bind_interrupts { // Reexports pub use _generated::{peripherals, Peripherals}; +#[cfg(not(feature = "_dual-core"))] use critical_section::CriticalSection; pub use embassy_hal_internal::{Peri, PeripheralType}; #[cfg(feature = "unstable-pac")] From 584066e209141ce92d882ceb6e7525c980833689 Mon Sep 17 00:00:00 2001 From: Michael Medin Date: Thu, 24 Apr 2025 11:07:15 +0200 Subject: [PATCH 1000/1217] updated cs gates for dual core --- embassy-stm32/src/lib.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 466634edf..444d14f28 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -213,7 +213,6 @@ macro_rules! bind_interrupts { // Reexports pub use _generated::{peripherals, Peripherals}; -#[cfg(not(feature = "_dual-core"))] use critical_section::CriticalSection; pub use embassy_hal_internal::{Peri, PeripheralType}; #[cfg(feature = "unstable-pac")] @@ -622,7 +621,6 @@ pub fn reinit(config: rcc::Config) { critical_section::with(|cs| init_rcc(cs, config)) } -#[cfg(not(feature = "_dual-core"))] fn init_rcc(_cs: CriticalSection, config: rcc::Config) { unsafe { rcc::init(config); From 7259f20fe211f2833ffb4aa1b44e6ddd60145853 Mon Sep 17 00:00:00 2001 From: Dion Dokter Date: Thu, 24 Apr 2025 11:23:11 +0200 Subject: [PATCH 1001/1217] Add configurable bank support in build script --- embassy-stm32/Cargo.toml | 9 ++++-- embassy-stm32/build.rs | 67 ++++++++++++++++++++++++++++++---------- 2 files changed, 58 insertions(+), 18 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 82bc76883..afef5d72f 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -73,7 +73,8 @@ rand_core = "0.6.3" sdio-host = "0.9.0" critical-section = "1.1" #stm32-metapac = { version = "16" } -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-380f03cb71f43a242adc45e83607a380ffe0447b" } +# stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-380f03cb71f43a242adc45e83607a380ffe0447b" } +stm32-metapac = { path = "R:/stm32-data/build/stm32-metapac" } vcell = "0.1.3" nb = "1.0.0" @@ -102,7 +103,8 @@ proc-macro2 = "1.0.36" quote = "1.0.15" #stm32-metapac = { version = "16", default-features = false, features = ["metadata"]} -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-380f03cb71f43a242adc45e83607a380ffe0447b", default-features = false, features = ["metadata"] } +# stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-380f03cb71f43a242adc45e83607a380ffe0447b", default-features = false, features = ["metadata"] } +stm32-metapac = { path = "R:/stm32-data/build/stm32-metapac", default-features = false, features = ["metadata"] } [features] default = ["rt"] @@ -197,6 +199,9 @@ split-pc2 = ["_split-pins-enabled"] ## Split PC3 split-pc3 = ["_split-pins-enabled"] +dual-bank = [] +single-bank = [] + ## internal use only _split-pins-enabled = [] diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index f9f03c51b..2a3213c0c 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -49,6 +49,48 @@ fn main() { } } + // ======== + // Select the memory variant to use + let memory = { + let single_bank_selected = env::var("CARGO_FEATURE_SINGLE_BANK").is_ok(); + let dual_bank_selected = env::var("CARGO_FEATURE_DUAL_BANK").is_ok(); + + let single_bank_memory = METADATA.memory.iter().find(|mem| { + mem.iter() + .filter(|region| region.kind == MemoryRegionKind::Flash) + .count() + == 1 + }); + + let dual_bank_memory = METADATA.memory.iter().find(|mem| { + mem.iter() + .filter(|region| region.kind == MemoryRegionKind::Flash) + .count() + == 2 + }); + + cfgs.set( + "bank_setup_configurable", + single_bank_memory.is_some() && dual_bank_memory.is_some(), + ); + + match (single_bank_selected, dual_bank_selected) { + (true, true) => panic!("Both 'single-bank' and 'dual-bank' features enabled"), + (true, false) => { + single_bank_memory.expect("The 'single-bank' feature is not supported on this dual bank chip") + } + (false, true) => { + dual_bank_memory.expect("The 'dual-bank' feature is not supported on this single bank chip") + } + (false, false) => { + if METADATA.memory.len() != 1 { + panic!("Chip supports single and dual bank configuration. No Cargo feature to select one is enabled. Use the 'single-bank' or 'dual-bank' feature to make your selection") + } + METADATA.memory[0] + } + } + }; + // ======== // Generate singletons @@ -290,8 +332,7 @@ fn main() { // ======== // Generate FLASH regions let mut flash_regions = TokenStream::new(); - let flash_memory_regions: Vec<_> = METADATA - .memory + let flash_memory_regions: Vec<_> = memory .iter() .filter(|x| x.kind == MemoryRegionKind::Flash && x.settings.is_some()) .collect(); @@ -1616,8 +1657,7 @@ fn main() { let mut pins_table: Vec> = Vec::new(); let mut adc_table: Vec> = Vec::new(); - for m in METADATA - .memory + for m in memory .iter() .filter(|m| m.kind == MemoryRegionKind::Flash && m.settings.is_some()) { @@ -1855,8 +1895,7 @@ fn main() { // ======== // Generate flash constants - let flash_regions: Vec<&MemoryRegion> = METADATA - .memory + let flash_regions: Vec<&MemoryRegion> = memory .iter() .filter(|x| x.kind == MemoryRegionKind::Flash && x.name.starts_with("BANK_")) .collect(); @@ -1981,7 +2020,7 @@ fn main() { println!("cargo:rerun-if-changed=build.rs"); if cfg!(feature = "memory-x") { - gen_memory_x(out_dir); + gen_memory_x(memory, out_dir); println!("cargo:rustc-link-search={}", out_dir.display()); } } @@ -2070,11 +2109,11 @@ fn rustfmt(path: impl AsRef) { } } -fn gen_memory_x(out_dir: &Path) { +fn gen_memory_x(memory: &[MemoryRegion], out_dir: &Path) { let mut memory_x = String::new(); - let flash = get_memory_range(MemoryRegionKind::Flash); - let ram = get_memory_range(MemoryRegionKind::Ram); + let flash = get_memory_range(memory, MemoryRegionKind::Flash); + let ram = get_memory_range(memory, MemoryRegionKind::Ram); write!(memory_x, "MEMORY\n{{\n").unwrap(); writeln!( @@ -2098,12 +2137,8 @@ fn gen_memory_x(out_dir: &Path) { std::fs::write(out_dir.join("memory.x"), memory_x.as_bytes()).unwrap(); } -fn get_memory_range(kind: MemoryRegionKind) -> (u32, u32, String) { - let mut mems: Vec<_> = METADATA - .memory - .iter() - .filter(|m| m.kind == kind && m.size != 0) - .collect(); +fn get_memory_range(memory: &[MemoryRegion], kind: MemoryRegionKind) -> (u32, u32, String) { + let mut mems: Vec<_> = memory.iter().filter(|m| m.kind == kind && m.size != 0).collect(); mems.sort_by_key(|m| m.address); let mut start = u32::MAX; From 19351c374ad42eb720194f8921375773a9b9c0a9 Mon Sep 17 00:00:00 2001 From: Dion Dokter Date: Thu, 24 Apr 2025 11:40:15 +0200 Subject: [PATCH 1002/1217] Check the bank setup when required --- embassy-stm32/src/flash/common.rs | 4 ++++ embassy-stm32/src/flash/g.rs | 10 ++++++++++ 2 files changed, 14 insertions(+) diff --git a/embassy-stm32/src/flash/common.rs b/embassy-stm32/src/flash/common.rs index 1376ca4b4..93d734b20 100644 --- a/embassy-stm32/src/flash/common.rs +++ b/embassy-stm32/src/flash/common.rs @@ -20,6 +20,10 @@ pub struct Flash<'d, MODE = Async> { impl<'d> Flash<'d, Blocking> { /// Create a new flash driver, usable in blocking mode. pub fn new_blocking(p: Peri<'d, FLASH>) -> Self { + #[cfg(bank_setup_configurable)] + // Check if the configuration matches the embassy setup + super::check_bank_setup(); + Self { inner: p, _mode: PhantomData, diff --git a/embassy-stm32/src/flash/g.rs b/embassy-stm32/src/flash/g.rs index 83663743c..f55c5e6a7 100644 --- a/embassy-stm32/src/flash/g.rs +++ b/embassy-stm32/src/flash/g.rs @@ -109,3 +109,13 @@ fn wait_busy() { fn wait_busy() { while pac::FLASH.sr().read().bsy() {} } + +#[cfg(bank_setup_configurable)] +pub(crate) fn check_bank_setup() { + if cfg!(feature = "single-bank") && pac::FLASH.optr().read().dbank() { + panic!("Embassy is configured as single-bank, but the hardware is running in dual-bank mode. Change the hardware by changing the dbank value in the user option bytes or configure embassy to use dual-bank config"); + } + if cfg!(feature = "dual-bank") && !pac::FLASH.optr().read().dbank() { + panic!("Embassy is configured as dual-bank, but the hardware is running in single-bank mode. Change the hardware by changing the dbank value in the user option bytes or configure embassy to use single-bank config"); + } +} From a41c83d1824a42bd68bb4d2f01500d06d25b0118 Mon Sep 17 00:00:00 2001 From: Dion Dokter Date: Thu, 24 Apr 2025 11:56:17 +0200 Subject: [PATCH 1003/1217] Add to changelog --- embassy-stm32/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/embassy-stm32/CHANGELOG.md b/embassy-stm32/CHANGELOG.md index c50ab5294..7b7d559e2 100644 --- a/embassy-stm32/CHANGELOG.md +++ b/embassy-stm32/CHANGELOG.md @@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased - Modify BufferedUart initialization to take pins before interrupts ([#3983](https://github.com/embassy-rs/embassy/pull/3983)) +- Added a 'single-bank' and a 'dual-bank' feature so chips with configurable flash bank setups can be supported in embassy. The G4 series now supports this. ([#4125](https://github.com/embassy-rs/embassy/pull/4125)) ## 0.2.0 - 2025-01-10 From 97c605f61afad8748da989eba59264abb78e70d6 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 24 Apr 2025 20:37:36 +0200 Subject: [PATCH 1004/1217] tests/stm32: stm32l0 is alive. --- ci.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/ci.sh b/ci.sh index e27ada508..5a438f0b1 100755 --- a/ci.sh +++ b/ci.sh @@ -324,7 +324,6 @@ DEFMT_RTT_BUFFER_SIZE="72" cargo batch \ # temporarily disabled, these boards are dead. rm -rf out/tests/stm32f103c8 -rm -rf out/tests/stm32l073rz rm -rf out/tests/nrf52840-dk rm -rf out/tests/nrf52833-dk From b32ff0c8f790379074c38d0409a3bf7709023f8b Mon Sep 17 00:00:00 2001 From: Thomas Giesel Date: Thu, 24 Apr 2025 22:15:41 +0200 Subject: [PATCH 1005/1217] Update opamp code to current stm32-metapac Some trivial enums have been removed from the OpAmp API in stm32-metapac, this commit updates the HAL accordingly. --- embassy-stm32/Cargo.toml | 4 ++-- embassy-stm32/src/opamp.rs | 49 ++++++++++++++------------------------ 2 files changed, 20 insertions(+), 33 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 82bc76883..a1dc75dba 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -73,7 +73,7 @@ rand_core = "0.6.3" sdio-host = "0.9.0" critical-section = "1.1" #stm32-metapac = { version = "16" } -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-380f03cb71f43a242adc45e83607a380ffe0447b" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-9385c0824aff194913a2eab3c957791d0de06771" } vcell = "0.1.3" nb = "1.0.0" @@ -102,7 +102,7 @@ proc-macro2 = "1.0.36" quote = "1.0.15" #stm32-metapac = { version = "16", default-features = false, features = ["metadata"]} -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-380f03cb71f43a242adc45e83607a380ffe0447b", default-features = false, features = ["metadata"] } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-9385c0824aff194913a2eab3c957791d0de06771", default-features = false, features = ["metadata"] } [features] default = ["rt"] diff --git a/embassy-stm32/src/opamp.rs b/embassy-stm32/src/opamp.rs index 82de4a89b..a76389495 100644 --- a/embassy-stm32/src/opamp.rs +++ b/embassy-stm32/src/opamp.rs @@ -37,22 +37,12 @@ enum OpAmpDifferentialPair { /// Speed #[allow(missing_docs)] -#[derive(Clone, Copy)] +#[derive(Clone, Copy, PartialEq)] pub enum OpAmpSpeed { Normal, HighSpeed, } -#[cfg(opamp_g4)] -impl From for crate::pac::opamp::vals::Opahsm { - fn from(v: OpAmpSpeed) -> Self { - match v { - OpAmpSpeed::Normal => crate::pac::opamp::vals::Opahsm::NORMAL, - OpAmpSpeed::HighSpeed => crate::pac::opamp::vals::Opahsm::HIGH_SPEED, - } - } -} - /// OpAmp external outputs, wired to a GPIO pad. /// /// This struct can also be used as an ADC input. @@ -80,7 +70,7 @@ impl<'d, T: Instance> OpAmp<'d, T> { pub fn new(opamp: Peri<'d, T>, #[cfg(opamp_g4)] speed: OpAmpSpeed) -> Self { #[cfg(opamp_g4)] T::regs().csr().modify(|w| { - w.set_opahsm(speed.into()); + w.set_opahsm(speed == OpAmpSpeed::HighSpeed); }); Self { _inner: opamp } @@ -113,7 +103,7 @@ impl<'d, T: Instance> OpAmp<'d, T> { w.set_vp_sel(VpSel::from_bits(in_pin.channel())); w.set_vm_sel(vm_sel); #[cfg(opamp_g4)] - w.set_opaintoen(Opaintoen::OUTPUT_PIN); + w.set_opaintoen(false); w.set_opampen(true); }); @@ -166,7 +156,7 @@ impl<'d, T: Instance> OpAmp<'d, T> { w.set_vm_sel(vm_sel); w.set_pga_gain(pga_gain); #[cfg(opamp_g4)] - w.set_opaintoen(Opaintoen::OUTPUT_PIN); + w.set_opaintoen(false); w.set_opampen(true); }); @@ -189,7 +179,7 @@ impl<'d, T: Instance> OpAmp<'d, T> { w.set_vm_sel(VmSel::OUTPUT); w.set_vp_sel(VpSel::DAC3_CH1); - w.set_opaintoen(Opaintoen::OUTPUT_PIN); + w.set_opaintoen(false); w.set_opampen(true); }); @@ -215,7 +205,7 @@ impl<'d, T: Instance> OpAmp<'d, T> { w.set_vp_sel(VpSel::from_bits(pin.channel())); w.set_vm_sel(VmSel::OUTPUT); #[cfg(opamp_g4)] - w.set_opaintoen(Opaintoen::ADCCHANNEL); + w.set_opaintoen(true); w.set_opampen(true); }); @@ -251,7 +241,7 @@ impl<'d, T: Instance> OpAmp<'d, T> { w.set_vp_sel(VpSel::from_bits(pin.channel())); w.set_vm_sel(VmSel::OUTPUT); w.set_pga_gain(pga_gain); - w.set_opaintoen(Opaintoen::ADCCHANNEL); + w.set_opaintoen(true); w.set_opampen(true); }); @@ -278,7 +268,7 @@ impl<'d, T: Instance> OpAmp<'d, T> { use crate::pac::opamp::vals::*; w.set_vp_sel(VpSel::DAC3_CH1); // Actually DAC3_CHx w.set_vm_sel(VmSel::from_bits(m_pin.channel())); - w.set_opaintoen(Opaintoen::ADCCHANNEL); + w.set_opaintoen(true); w.set_opampen(true); }); @@ -308,7 +298,7 @@ impl<'d, T: Instance> OpAmp<'d, T> { use crate::pac::opamp::vals::*; w.set_vp_sel(VpSel::DAC3_CH1); // Actually DAC3_CHx w.set_vm_sel(VmSel::from_bits(m_pin.channel())); - w.set_opaintoen(Opaintoen::OUTPUT_PIN); + w.set_opaintoen(false); w.set_opampen(true); }); @@ -340,7 +330,7 @@ impl<'d, T: Instance> OpAmp<'d, T> { use crate::pac::opamp::vals::*; w.set_vp_sel(VpSel::from_bits(p_pin.channel())); w.set_vm_sel(VmSel::from_bits(m_pin.channel())); - w.set_opaintoen(Opaintoen::OUTPUT_PIN); + w.set_opaintoen(false); w.set_opampen(true); }); @@ -369,7 +359,7 @@ impl<'d, T: Instance> OpAmp<'d, T> { use crate::pac::opamp::vals::*; w.set_vp_sel(VpSel::from_bits(p_pin.channel())); w.set_vm_sel(VmSel::from_bits(m_pin.channel())); - w.set_opaintoen(Opaintoen::ADCCHANNEL); + w.set_opaintoen(true); w.set_opampen(true); }); @@ -389,17 +379,14 @@ impl<'d, T: Instance> OpAmp<'d, T> { T::regs().csr().modify(|w| { w.set_opampen(true); w.set_calon(true); - w.set_usertrim(Usertrim::USER); + w.set_usertrim(true); }); - match T::regs().csr().read().opahsm() { - Opahsm::NORMAL => { - self.calibrate_differential_pair(OpAmpDifferentialPair::P); - self.calibrate_differential_pair(OpAmpDifferentialPair::N); - } - Opahsm::HIGH_SPEED => { - self.calibrate_differential_pair(OpAmpDifferentialPair::P); - } + if T::regs().csr().read().opahsm() { + self.calibrate_differential_pair(OpAmpDifferentialPair::P); + } else { + self.calibrate_differential_pair(OpAmpDifferentialPair::P); + self.calibrate_differential_pair(OpAmpDifferentialPair::N); } T::regs().csr().modify(|w| { @@ -448,7 +435,7 @@ impl<'d, T: Instance> OpAmp<'d, T> { // (with a maximum stabilization time remaining below 2 ms in any case) -- RM0440 25.3.7 blocking_delay_ms(2); - if T::regs().csr().read().outcal() == Outcal::LOW { + if !T::regs().csr().read().calout() { if mid == 0 { break; } From 18eea73d198b4cc1bed3e034c912518ce47888cc Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Fri, 25 Apr 2025 00:09:13 +0200 Subject: [PATCH 1006/1217] stm32/adc: add h7rs support. --- embassy-stm32/src/adc/mod.rs | 4 +++- embassy-stm32/src/adc/v3.rs | 20 ++++++++++---------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index 321db7431..f46e87f38 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs @@ -11,7 +11,7 @@ #[cfg_attr(adc_v1, path = "v1.rs")] #[cfg_attr(adc_l0, path = "v1.rs")] #[cfg_attr(adc_v2, path = "v2.rs")] -#[cfg_attr(any(adc_v3, adc_g0, adc_h5, adc_u0), path = "v3.rs")] +#[cfg_attr(any(adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0), path = "v3.rs")] #[cfg_attr(any(adc_v4, adc_u5), path = "v4.rs")] #[cfg_attr(adc_g4, path = "g4.rs")] #[cfg_attr(adc_c0, path = "c0.rs")] @@ -108,6 +108,7 @@ pub(crate) fn blocking_delay_us(us: u32) { adc_g0, adc_u0, adc_h5, + adc_h7rs, adc_u5, adc_c0 )))] @@ -129,6 +130,7 @@ pub trait Instance: SealedInstance + crate::PeripheralType { adc_g0, adc_u0, adc_h5, + adc_h7rs, adc_u5, adc_c0 ))] diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs index 2de12d1d6..1c5ad16e9 100644 --- a/embassy-stm32/src/adc/v3.rs +++ b/embassy-stm32/src/adc/v3.rs @@ -19,7 +19,7 @@ impl SealedAdcChannel for VrefInt { cfg_if! { if #[cfg(adc_g0)] { let val = 13; - } else if #[cfg(adc_h5)] { + } else if #[cfg(any(adc_h5, adc_h7rs))] { let val = 17; } else if #[cfg(adc_u0)] { let val = 12; @@ -38,7 +38,7 @@ impl SealedAdcChannel for Temperature { cfg_if! { if #[cfg(adc_g0)] { let val = 12; - } else if #[cfg(adc_h5)] { + } else if #[cfg(any(adc_h5, adc_h7rs))] { let val = 16; } else if #[cfg(adc_u0)] { let val = 11; @@ -57,9 +57,9 @@ impl SealedAdcChannel for Vbat { cfg_if! { if #[cfg(adc_g0)] { let val = 14; - } else if #[cfg(adc_h5)] { + } else if #[cfg(any(adc_h5, adc_h7rs))] { let val = 2; - } else if #[cfg(adc_h5)] { + } else if #[cfg(any(adc_h5, adc_h7rs))] { let val = 13; } else { let val = 18; @@ -70,7 +70,7 @@ impl SealedAdcChannel for Vbat { } cfg_if! { - if #[cfg(adc_h5)] { + if #[cfg(any(adc_h5, adc_h7rs))] { pub struct VddCore; impl AdcChannel for VddCore {} impl super::SealedAdcChannel for VddCore { @@ -171,7 +171,7 @@ impl<'d, T: Instance> Adc<'d, T> { T::regs().ccr().modify(|reg| { reg.set_tsen(true); }); - } else if #[cfg(adc_h5)] { + } else if #[cfg(any(adc_h5, adc_h7rs))] { T::common_regs().ccr().modify(|reg| { reg.set_tsen(true); }); @@ -191,7 +191,7 @@ impl<'d, T: Instance> Adc<'d, T> { T::regs().ccr().modify(|reg| { reg.set_vbaten(true); }); - } else if #[cfg(adc_h5)] { + } else if #[cfg(any(adc_h5, adc_h7rs))] { T::common_regs().ccr().modify(|reg| { reg.set_vbaten(true); }); @@ -414,7 +414,7 @@ impl<'d, T: Instance> Adc<'d, T> { fn configure_channel(channel: &mut impl AdcChannel, sample_time: SampleTime) { // RM0492, RM0481, etc. // "This option bit must be set to 1 when ADCx_INP0 or ADCx_INN1 channel is selected." - #[cfg(adc_h5)] + #[cfg(any(adc_h5, adc_h7rs))] if channel.channel() == 0 { T::regs().or().modify(|reg| reg.set_op0(true)); } @@ -447,7 +447,7 @@ impl<'d, T: Instance> Adc<'d, T> { // RM0492, RM0481, etc. // "This option bit must be set to 1 when ADCx_INP0 or ADCx_INN1 channel is selected." - #[cfg(adc_h5)] + #[cfg(any(adc_h5, adc_h7rs))] if channel.channel() == 0 { T::regs().or().modify(|reg| reg.set_op0(false)); } @@ -475,7 +475,7 @@ impl<'d, T: Instance> Adc<'d, T> { if #[cfg(any(adc_g0, adc_u0))] { // On G0 and U6 all channels use the same sampling time. T::regs().smpr().modify(|reg| reg.set_smp1(sample_time.into())); - } else if #[cfg(adc_h5)] { + } else if #[cfg(any(adc_h5, adc_h7rs))] { match _ch { 0..=9 => T::regs().smpr1().modify(|w| w.set_smp(_ch as usize % 10, sample_time.into())), _ => T::regs().smpr2().modify(|w| w.set_smp(_ch as usize % 10, sample_time.into())), From 29bcddaa10276df2bce1acd80f51ddcec251af50 Mon Sep 17 00:00:00 2001 From: Marc <35759328+marcemmers@users.noreply.github.com> Date: Thu, 24 Apr 2025 23:32:07 +0200 Subject: [PATCH 1007/1217] Refactor Onewire PIO implementation --- embassy-rp/src/pio_programs/onewire.rs | 317 ++++++++++++++++++++----- 1 file changed, 255 insertions(+), 62 deletions(-) diff --git a/embassy-rp/src/pio_programs/onewire.rs b/embassy-rp/src/pio_programs/onewire.rs index 00783aab0..9f2ed5695 100644 --- a/embassy-rp/src/pio_programs/onewire.rs +++ b/embassy-rp/src/pio_programs/onewire.rs @@ -1,11 +1,18 @@ //! OneWire pio driver -use crate::pio::{Common, Config, Instance, LoadedProgram, PioPin, ShiftConfig, ShiftDirection, StateMachine}; +use crate::clocks::clk_sys_freq; +use crate::gpio::Level; +use crate::pio::{ + Common, Config, Direction, Instance, LoadedProgram, PioPin, ShiftConfig, ShiftDirection, StateMachine, +}; use crate::Peri; -/// This struct represents an onewire driver program +/// This struct represents a onewire driver program pub struct PioOneWireProgram<'a, PIO: Instance> { prg: LoadedProgram<'a, PIO>, + reset_addr: u8, + next_bit_addr: u8, + search_addr: u8, } impl<'a, PIO: Instance> PioOneWireProgram<'a, PIO> { @@ -13,56 +20,86 @@ impl<'a, PIO: Instance> PioOneWireProgram<'a, PIO> { pub fn new(common: &mut Common<'a, PIO>) -> Self { let prg = pio::pio_asm!( r#" - .wrap_target - again: - pull block - mov x, osr - jmp !x, read - write: - set pindirs, 1 - set pins, 0 - loop1: - jmp x--,loop1 - set pindirs, 0 [31] - wait 1 pin 0 [31] - pull block - mov x, osr - bytes1: - pull block - set y, 7 - set pindirs, 1 - bit1: - set pins, 0 [1] - out pins,1 [31] - set pins, 1 [20] - jmp y--,bit1 - jmp x--,bytes1 - set pindirs, 0 [31] - jmp again - read: - pull block - mov x, osr - bytes2: - set y, 7 - bit2: - set pindirs, 1 - set pins, 0 [1] - set pindirs, 0 [5] - in pins,1 [10] - jmp y--,bit2 - jmp x--,bytes2 - .wrap - "#, - ); - let prg = common.load_program(&prg.program); + ; We need to use the pins direction to simulate open drain output + ; This results in all the side-set values being swapped from the actual pin value + .side_set 1 pindirs - Self { prg } + ; Set the origin to 0 so we can correctly use jmp instructions externally + .origin 0 + + ; Tick rate is 1 tick per 6us, so all delays should be calculated back to that + ; All the instructions have a calculated delay in [], -1 for the instruction + ; The delay also be 0 which will take 6us for the instruction itself + .define CLK 6 + + ; Write the reset block after trigger + public reset: + set x, 4 side 0 [(60 / CLK) - 1] ; idle before reset + reset_inner: ; Repeat the following 5 times, so 5*96us = 480us in total + nop side 1 [(90 / CLK) - 1] + jmp x--, reset_inner side 1 [( 6 / CLK) - 1] + ; Fallthrough + + ; Check for presence of one or more devices. + ; This samples 32 times with an interval of 12us after a 18us delay. + ; If any bit is zero in the end value, there is a detection + ; This whole function takes 480us + set x, 31 side 0 [(24 / CLK) - 1] ; Loop 32 times -> 32*12us = 384us + presence_check: + in pins, 1 side 0 [( 6 / CLK) - 1] ; poll pin and push to isr + jmp x--, presence_check side 0 [( 6 / CLK) - 1] + jmp next_bit side 0 [(72 / CLK) - 1] + + ; The low pulse was already done, we only need to delay and poll the bit in case we are reading + write_1: + nop side 0 [( 6 / CLK) - 1] ; Delay before sampling the input pin + in pins, 1 side 0 [(54 / CLK) - 1] ; This writes the state of the pin into the ISR + ; Fallthrough + + ; This is the entry point when reading and writing data + public next_bit: + .wrap_target + out x, 1 side 0 [(18 / CLK) - 1] ; Stalls if no data available in TX FIFO and OSR + jmp x--, write_1 side 1 [(12 / CLK) - 1] ; Do the always low part of a bit, jump to write_1 if we want to write a 1 bit + in null, 1 side 1 [(60 / CLK) - 1] ; Do the remainder of the low part of a 0 bit + ; This writes 0 into the ISR so that the shift count stays in sync + .wrap + + public search: + set x, 1 side 0 [(78 / CLK) - 1] ; Set x to 1 for the inner loop + search_inner: + ; Read 2 bits + nop side 1 [(12 / CLK) - 1] ; Do the always low part of a bit + nop side 0 [( 6 / CLK) - 1] ; Delay before sampling the input pin + in pins, 1 side 0 [(54 / CLK) - 1] ; This writes the state of the pin into the ISR + jmp x--, search_inner side 0 [(18 / CLK) - 1] + ; Fallthrough + + ; Write output + out x, 1 side 0 [( 6 / CLK) - 1] ; Stalls if no data available in TX FIFO and OSR + jmp x--, search side 1 [(12 / CLK) - 1] ; Do the always low part of a bit, jump to search to write a 1 bit + ; Fallthrough + + set x, 1 side 1 [(60 / CLK) - 1] ; Set x to 1 for the inner loop, write the remainder of the low part of a 0 bit + jmp search_inner side 0 [(18 / CLK) - 1] + "# + ); + + Self { + prg: common.load_program(&prg.program), + reset_addr: prg.public_defines.reset as u8, + next_bit_addr: prg.public_defines.next_bit as u8, + search_addr: prg.public_defines.search as u8, + } } } - /// Pio backed OneWire driver pub struct PioOneWire<'d, PIO: Instance, const SM: usize> { sm: StateMachine<'d, PIO, SM>, + cfg: Config<'d, PIO>, + reset_addr: u8, + search_addr: u8, + next_bit_addr: u8, } impl<'d, PIO: Instance, const SM: usize> PioOneWire<'d, PIO, SM> { @@ -74,37 +111,193 @@ impl<'d, PIO: Instance, const SM: usize> PioOneWire<'d, PIO, SM> { program: &PioOneWireProgram<'d, PIO>, ) -> Self { let pin = common.make_pio_pin(pin); + + sm.set_pin_dirs(Direction::In, &[&pin]); + sm.set_pins(Level::Low, &[&pin]); + let mut cfg = Config::default(); - cfg.use_program(&program.prg, &[]); - cfg.set_out_pins(&[&pin]); + cfg.use_program(&program.prg, &[&pin]); cfg.set_in_pins(&[&pin]); - cfg.set_set_pins(&[&pin]); - cfg.shift_in = ShiftConfig { + + let byte_shift = ShiftConfig { auto_fill: true, direction: ShiftDirection::Right, threshold: 8, }; - cfg.clock_divider = 255_u8.into(); + cfg.shift_in = byte_shift; + cfg.shift_out = byte_shift; + + let divider = (clk_sys_freq() / 1000000) as u16 * 6; + cfg.clock_divider = divider.into(); + sm.set_config(&cfg); + sm.clear_fifos(); + sm.restart(); + unsafe { + sm.exec_jmp(program.next_bit_addr); + } sm.set_enable(true); - Self { sm } + + Self { + sm, + cfg, + reset_addr: program.reset_addr, + search_addr: program.search_addr, + next_bit_addr: program.next_bit_addr, + } + } + + pub async fn reset(&mut self) -> bool { + // The state machine immediately starts running when jumping to this address + unsafe { + self.sm.exec_jmp(self.reset_addr); + } + + let rx = self.sm.rx(); + let mut found = false; + for _ in 0..4 { + if rx.wait_pull().await != 0 { + found = true; + } + } + + found } /// Write bytes over the wire - pub async fn write_bytes(&mut self, bytes: &[u8]) { - self.sm.tx().wait_push(250).await; - self.sm.tx().wait_push(bytes.len() as u32 - 1).await; - for b in bytes { - self.sm.tx().wait_push(*b as u32).await; + pub async fn write_bytes(&mut self, data: &[u8]) { + let (rx, tx) = self.sm.rx_tx(); + for b in data { + tx.wait_push(*b as u32).await; + + // Empty the buffer that is always filled + let _ = rx.wait_pull().await; } } /// Read bytes from the wire - pub async fn read_bytes(&mut self, bytes: &mut [u8]) { - self.sm.tx().wait_push(0).await; - self.sm.tx().wait_push(bytes.len() as u32 - 1).await; - for b in bytes.iter_mut() { - *b = (self.sm.rx().wait_pull().await >> 24) as u8; + pub async fn read_bytes(&mut self, data: &mut [u8]) { + let (rx, tx) = self.sm.rx_tx(); + for b in data { + // Write all 1's so that we can read what the device responds + tx.wait_push(0xff).await; + + *b = (rx.wait_pull().await >> 24) as u8; } } + + async fn search(&mut self, state: &mut PioOneWireSearch) -> Option { + let _ = self.reset().await; + self.write_bytes(&[0xF0]).await; + + let shift_cfg = self.prepare_search(); + + let (rx, tx) = self.sm.rx_tx(); + + let mut value = 0u64; + let mut last_zero = 0; + + for bit in 0..64 { + let push = match rx.wait_pull().await { + 0b00 => { + let write_value = if bit < state.last_discrepancy { + (state.last_rom & (1 << bit)) != 0 + } else { + bit == state.last_discrepancy + }; + + if write_value { + 1 + } else { + last_zero = bit; + 0 + } + } + 0b01 => 0, + 0b10 => 1, + _ => { + self.restore_after_search(&shift_cfg); + state.finished = true; + return None; + } + }; + value >>= 1; + if push == 1 { + value |= 1 << 63; + } + tx.wait_push(push).await; + } + + self.restore_after_search(&shift_cfg); + + state.last_discrepancy = last_zero; + state.finished = last_zero == 0; + state.last_rom = value; + Some(value) + } + + fn prepare_search(&mut self) -> ShiftConfig { + let shift_cfg = self.cfg.shift_in; + self.cfg.shift_in = ShiftConfig { + auto_fill: true, + direction: ShiftDirection::Left, + threshold: 2, + }; + self.cfg.shift_out = ShiftConfig { + auto_fill: true, + direction: ShiftDirection::Right, + threshold: 1, + }; + + self.sm.set_enable(false); + self.sm.set_config(&self.cfg); + + unsafe { + self.sm.exec_jmp(self.search_addr); + } + self.sm.set_enable(true); + shift_cfg + } + + fn restore_after_search(&mut self, cfg: &ShiftConfig) { + self.cfg.shift_in = *cfg; + self.cfg.shift_out = *cfg; + + self.sm.set_enable(false); + self.sm.set_config(&self.cfg); + unsafe { + self.sm.exec_jmp(self.next_bit_addr); + } + self.sm.clear_fifos(); + self.sm.restart(); + self.sm.set_enable(true); + } +} + +pub struct PioOneWireSearch { + last_rom: u64, + last_discrepancy: u8, + finished: bool, +} + +impl PioOneWireSearch { + pub fn new() -> Self { + Self { + last_rom: 0, + last_discrepancy: 0, + finished: false, + } + } + + pub async fn next(&mut self, pio: &mut PioOneWire<'_, PIO, SM>) -> Option { + if self.finished { + None + } else { + pio.search(self).await + } + } + + pub fn is_finished(&self) -> bool { + self.finished + } } From 2a4b380cb715fface63a438185502f2a96d58d80 Mon Sep 17 00:00:00 2001 From: Marc <35759328+marcemmers@users.noreply.github.com> Date: Fri, 25 Apr 2025 00:40:32 +0200 Subject: [PATCH 1008/1217] Search can use the normal write/read instructions --- embassy-rp/src/pio_programs/onewire.rs | 129 ++++++++++++------------- 1 file changed, 62 insertions(+), 67 deletions(-) diff --git a/embassy-rp/src/pio_programs/onewire.rs b/embassy-rp/src/pio_programs/onewire.rs index 9f2ed5695..82fd98b96 100644 --- a/embassy-rp/src/pio_programs/onewire.rs +++ b/embassy-rp/src/pio_programs/onewire.rs @@ -12,7 +12,6 @@ pub struct PioOneWireProgram<'a, PIO: Instance> { prg: LoadedProgram<'a, PIO>, reset_addr: u8, next_bit_addr: u8, - search_addr: u8, } impl<'a, PIO: Instance> PioOneWireProgram<'a, PIO> { @@ -53,35 +52,17 @@ impl<'a, PIO: Instance> PioOneWireProgram<'a, PIO> { ; The low pulse was already done, we only need to delay and poll the bit in case we are reading write_1: nop side 0 [( 6 / CLK) - 1] ; Delay before sampling the input pin - in pins, 1 side 0 [(54 / CLK) - 1] ; This writes the state of the pin into the ISR + in pins, 1 side 0 [(48 / CLK) - 1] ; This writes the state of the pin into the ISR ; Fallthrough ; This is the entry point when reading and writing data public next_bit: .wrap_target - out x, 1 side 0 [(18 / CLK) - 1] ; Stalls if no data available in TX FIFO and OSR - jmp x--, write_1 side 1 [(12 / CLK) - 1] ; Do the always low part of a bit, jump to write_1 if we want to write a 1 bit - in null, 1 side 1 [(60 / CLK) - 1] ; Do the remainder of the low part of a 0 bit + out x, 1 side 0 [(12 / CLK) - 1] ; Stalls if no data available in TX FIFO and OSR + jmp x--, write_1 side 1 [( 6 / CLK) - 1] ; Do the always low part of a bit, jump to write_1 if we want to write a 1 bit + in null, 1 side 1 [(54 / CLK) - 1] ; Do the remainder of the low part of a 0 bit ; This writes 0 into the ISR so that the shift count stays in sync .wrap - - public search: - set x, 1 side 0 [(78 / CLK) - 1] ; Set x to 1 for the inner loop - search_inner: - ; Read 2 bits - nop side 1 [(12 / CLK) - 1] ; Do the always low part of a bit - nop side 0 [( 6 / CLK) - 1] ; Delay before sampling the input pin - in pins, 1 side 0 [(54 / CLK) - 1] ; This writes the state of the pin into the ISR - jmp x--, search_inner side 0 [(18 / CLK) - 1] - ; Fallthrough - - ; Write output - out x, 1 side 0 [( 6 / CLK) - 1] ; Stalls if no data available in TX FIFO and OSR - jmp x--, search side 1 [(12 / CLK) - 1] ; Do the always low part of a bit, jump to search to write a 1 bit - ; Fallthrough - - set x, 1 side 1 [(60 / CLK) - 1] ; Set x to 1 for the inner loop, write the remainder of the low part of a 0 bit - jmp search_inner side 0 [(18 / CLK) - 1] "# ); @@ -89,7 +70,6 @@ impl<'a, PIO: Instance> PioOneWireProgram<'a, PIO> { prg: common.load_program(&prg.program), reset_addr: prg.public_defines.reset as u8, next_bit_addr: prg.public_defines.next_bit as u8, - search_addr: prg.public_defines.search as u8, } } } @@ -98,7 +78,6 @@ pub struct PioOneWire<'d, PIO: Instance, const SM: usize> { sm: StateMachine<'d, PIO, SM>, cfg: Config<'d, PIO>, reset_addr: u8, - search_addr: u8, next_bit_addr: u8, } @@ -119,13 +98,16 @@ impl<'d, PIO: Instance, const SM: usize> PioOneWire<'d, PIO, SM> { cfg.use_program(&program.prg, &[&pin]); cfg.set_in_pins(&[&pin]); - let byte_shift = ShiftConfig { + cfg.shift_in = ShiftConfig { + auto_fill: true, + direction: ShiftDirection::Right, + threshold: 8, + }; + cfg.shift_out = ShiftConfig { auto_fill: true, direction: ShiftDirection::Right, threshold: 8, }; - cfg.shift_in = byte_shift; - cfg.shift_out = byte_shift; let divider = (clk_sys_freq() / 1000000) as u16 * 6; cfg.clock_divider = divider.into(); @@ -142,11 +124,11 @@ impl<'d, PIO: Instance, const SM: usize> PioOneWire<'d, PIO, SM> { sm, cfg, reset_addr: program.reset_addr, - search_addr: program.search_addr, next_bit_addr: program.next_bit_addr, } } + /// Perform an initialization sequence, will return true if a presence pulse was detected from a device pub async fn reset(&mut self) -> bool { // The state machine immediately starts running when jumping to this address unsafe { @@ -164,18 +146,18 @@ impl<'d, PIO: Instance, const SM: usize> PioOneWire<'d, PIO, SM> { found } - /// Write bytes over the wire + /// Write bytes to the onewire bus pub async fn write_bytes(&mut self, data: &[u8]) { let (rx, tx) = self.sm.rx_tx(); for b in data { tx.wait_push(*b as u32).await; - // Empty the buffer that is always filled + // Empty the buffer that is being filled with every write let _ = rx.wait_pull().await; } } - /// Read bytes from the wire + /// Read bytes from the onewire bus pub async fn read_bytes(&mut self, data: &mut [u8]) { let (rx, tx) = self.sm.rx_tx(); for b in data { @@ -187,19 +169,29 @@ impl<'d, PIO: Instance, const SM: usize> PioOneWire<'d, PIO, SM> { } async fn search(&mut self, state: &mut PioOneWireSearch) -> Option { - let _ = self.reset().await; - self.write_bytes(&[0xF0]).await; + if !self.reset().await { + // No device present, no use in searching + state.finished = true; + return None; + } + self.write_bytes(&[0xF0]).await; // 0xF0 is the search rom command - let shift_cfg = self.prepare_search(); + self.prepare_search(); let (rx, tx) = self.sm.rx_tx(); - let mut value = 0u64; + let mut value = 0; let mut last_zero = 0; for bit in 0..64 { - let push = match rx.wait_pull().await { - 0b00 => { + // Write 2 dummy bits to read a bit and its complement + tx.wait_push(0x1).await; + tx.wait_push(0x1).await; + let in1 = rx.wait_pull().await; + let in2 = rx.wait_pull().await; + let push = match (in1, in2) { + (0, 0) => { + // If both are 0, it means we have devices with 0 and 1 bits in this position let write_value = if bit < state.last_discrepancy { (state.last_rom & (1 << bit)) != 0 } else { @@ -213,10 +205,11 @@ impl<'d, PIO: Instance, const SM: usize> PioOneWire<'d, PIO, SM> { 0 } } - 0b01 => 0, - 0b10 => 1, + (0, 1) => 0, // Only devices with a 0 bit in this position + (1, 0) => 1, // Only devices with a 1 bit in this position _ => { - self.restore_after_search(&shift_cfg); + // If both are 1, it means there is no device active and there is no point in continuing + self.restore_after_search(); state.finished = true; return None; } @@ -226,9 +219,10 @@ impl<'d, PIO: Instance, const SM: usize> PioOneWire<'d, PIO, SM> { value |= 1 << 63; } tx.wait_push(push).await; + let _ = rx.wait_pull().await; // Discard the result of the write action } - self.restore_after_search(&shift_cfg); + self.restore_after_search(); state.last_discrepancy = last_zero; state.finished = last_zero == 0; @@ -236,44 +230,42 @@ impl<'d, PIO: Instance, const SM: usize> PioOneWire<'d, PIO, SM> { Some(value) } - fn prepare_search(&mut self) -> ShiftConfig { - let shift_cfg = self.cfg.shift_in; - self.cfg.shift_in = ShiftConfig { - auto_fill: true, - direction: ShiftDirection::Left, - threshold: 2, - }; - self.cfg.shift_out = ShiftConfig { - auto_fill: true, - direction: ShiftDirection::Right, - threshold: 1, - }; + fn prepare_search(&mut self) { + self.cfg.shift_in.threshold = 1; + self.cfg.shift_in.direction = ShiftDirection::Left; + self.cfg.shift_out.threshold = 1; self.sm.set_enable(false); self.sm.set_config(&self.cfg); - unsafe { - self.sm.exec_jmp(self.search_addr); - } - self.sm.set_enable(true); - shift_cfg - } - - fn restore_after_search(&mut self, cfg: &ShiftConfig) { - self.cfg.shift_in = *cfg; - self.cfg.shift_out = *cfg; - - self.sm.set_enable(false); - self.sm.set_config(&self.cfg); + // set_config jumps to the wrong address so jump to the right one here unsafe { self.sm.exec_jmp(self.next_bit_addr); } + self.sm.set_enable(true); + } + + fn restore_after_search(&mut self) { + self.cfg.shift_in.threshold = 8; + self.cfg.shift_in.direction = ShiftDirection::Right; + self.cfg.shift_out.threshold = 8; + + self.sm.set_enable(false); + self.sm.set_config(&self.cfg); + + // Clear the state in case we aborted prematurely with some bits still in the shift registers self.sm.clear_fifos(); self.sm.restart(); + + // set_config jumps to the wrong address so jump to the right one here + unsafe { + self.sm.exec_jmp(self.next_bit_addr); + } self.sm.set_enable(true); } } +/// Onewire search state pub struct PioOneWireSearch { last_rom: u64, last_discrepancy: u8, @@ -281,6 +273,7 @@ pub struct PioOneWireSearch { } impl PioOneWireSearch { + /// Create a new Onewire search state pub fn new() -> Self { Self { last_rom: 0, @@ -289,6 +282,7 @@ impl PioOneWireSearch { } } + /// Search for the next address on the bus pub async fn next(&mut self, pio: &mut PioOneWire<'_, PIO, SM>) -> Option { if self.finished { None @@ -297,6 +291,7 @@ impl PioOneWireSearch { } } + /// Is finished when all devices have been found pub fn is_finished(&self) -> bool { self.finished } From cd27a8a06b0160d654ebed7b89ca473041710235 Mon Sep 17 00:00:00 2001 From: Marc <35759328+marcemmers@users.noreply.github.com> Date: Fri, 25 Apr 2025 00:43:46 +0200 Subject: [PATCH 1009/1217] Updated the pio onewire example --- examples/rp/src/bin/pio_onewire.rs | 104 +++++++++++++++-------------- 1 file changed, 54 insertions(+), 50 deletions(-) diff --git a/examples/rp/src/bin/pio_onewire.rs b/examples/rp/src/bin/pio_onewire.rs index 991510851..379e2b8f9 100644 --- a/examples/rp/src/bin/pio_onewire.rs +++ b/examples/rp/src/bin/pio_onewire.rs @@ -1,4 +1,4 @@ -//! This example shows how you can use PIO to read a `DS18B20` one-wire temperature sensor. +//! This example shows how you can use PIO to read one or more `DS18B20` one-wire temperature sensors. #![no_std] #![no_main] @@ -6,9 +6,10 @@ use defmt::*; use embassy_executor::Spawner; use embassy_rp::bind_interrupts; use embassy_rp::peripherals::PIO0; -use embassy_rp::pio::{self, InterruptHandler, Pio}; -use embassy_rp::pio_programs::onewire::{PioOneWire, PioOneWireProgram}; +use embassy_rp::pio::{InterruptHandler, Pio}; +use embassy_rp::pio_programs::onewire::{PioOneWire, PioOneWireProgram, PioOneWireSearch}; use embassy_time::Timer; +use heapless::Vec; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { @@ -21,63 +22,66 @@ async fn main(_spawner: Spawner) { let mut pio = Pio::new(p.PIO0, Irqs); let prg = PioOneWireProgram::new(&mut pio.common); - let onewire = PioOneWire::new(&mut pio.common, pio.sm0, p.PIN_2, &prg); + let mut onewire = PioOneWire::new(&mut pio.common, pio.sm0, p.PIN_2, &prg); - let mut sensor = Ds18b20::new(onewire); + info!("Starting onewire search"); + + let mut devices = Vec::::new(); + let mut search = PioOneWireSearch::new(); + for _ in 0..10 { + if !search.is_finished() { + if let Some(address) = search.next(&mut onewire).await { + if crc8(&address.to_le_bytes()) == 0 { + info!("Found addres: {:x}", address); + let _ = devices.push(address); + } else { + warn!("Found invalid address: {:x}", address); + } + } + } + } + + info!("Search done, found {} devices", devices.len()); loop { - sensor.start().await; // Start a new measurement + onewire.reset().await; + // Skip rom and trigger conversion, we can trigger all devices on the bus immediately + onewire.write_bytes(&[0xCC, 0x44]).await; + Timer::after_secs(1).await; // Allow 1s for the measurement to finish - match sensor.temperature().await { - Ok(temp) => info!("temp = {:?} deg C", temp), - _ => error!("sensor error"), + + // Read all devices one by one + for device in &devices { + onewire.reset().await; + onewire.write_bytes(&[0x55]).await; // Match rom + onewire.write_bytes(&device.to_le_bytes()).await; + onewire.write_bytes(&[0xBE]).await; // Read scratchpad + + let mut data = [0; 9]; + onewire.read_bytes(&mut data).await; + if crc8(&data) == 0 { + let temp = ((data[1] as u32) << 8 | data[0] as u32) as f32 / 16.; + info!("Read device {:x}: {} deg C", device, temp); + } else { + warn!("Reading device {:x} failed", device); + } } Timer::after_secs(1).await; } } -/// DS18B20 temperature sensor driver -pub struct Ds18b20<'d, PIO: pio::Instance, const SM: usize> { - wire: PioOneWire<'d, PIO, SM>, -} - -impl<'d, PIO: pio::Instance, const SM: usize> Ds18b20<'d, PIO, SM> { - pub fn new(wire: PioOneWire<'d, PIO, SM>) -> Self { - Self { wire } - } - - /// Calculate CRC8 of the data - fn crc8(data: &[u8]) -> u8 { - let mut temp; - let mut data_byte; - let mut crc = 0; - for b in data { - data_byte = *b; - for _ in 0..8 { - temp = (crc ^ data_byte) & 0x01; - crc >>= 1; - if temp != 0 { - crc ^= 0x8C; - } - data_byte >>= 1; +fn crc8(data: &[u8]) -> u8 { + let mut crc = 0; + for b in data { + let mut data_byte = *b; + for _ in 0..8 { + let temp = (crc ^ data_byte) & 0x01; + crc >>= 1; + if temp != 0 { + crc ^= 0x8C; } - } - crc - } - - /// Start a new measurement. Allow at least 1000ms before getting `temperature`. - pub async fn start(&mut self) { - self.wire.write_bytes(&[0xCC, 0x44]).await; - } - - /// Read the temperature. Ensure >1000ms has passed since `start` before calling this. - pub async fn temperature(&mut self) -> Result { - self.wire.write_bytes(&[0xCC, 0xBE]).await; - let mut data = [0; 9]; - self.wire.read_bytes(&mut data).await; - match Self::crc8(&data) == 0 { - true => Ok(((data[1] as u32) << 8 | data[0] as u32) as f32 / 16.), - false => Err(()), + data_byte >>= 1; } } + crc } From 5d8b0e0327955039d58542ee2036744e155561e6 Mon Sep 17 00:00:00 2001 From: Marc <35759328+marcemmers@users.noreply.github.com> Date: Fri, 25 Apr 2025 00:55:03 +0200 Subject: [PATCH 1010/1217] Some small improvements --- embassy-rp/src/pio_programs/onewire.rs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/embassy-rp/src/pio_programs/onewire.rs b/embassy-rp/src/pio_programs/onewire.rs index 82fd98b96..287ddab41 100644 --- a/embassy-rp/src/pio_programs/onewire.rs +++ b/embassy-rp/src/pio_programs/onewire.rs @@ -27,8 +27,9 @@ impl<'a, PIO: Instance> PioOneWireProgram<'a, PIO> { .origin 0 ; Tick rate is 1 tick per 6us, so all delays should be calculated back to that - ; All the instructions have a calculated delay in [], -1 for the instruction - ; The delay also be 0 which will take 6us for the instruction itself + ; All the instructions have a calculated delay XX in us as [(XX / CLK) - 1]. + ; The - 1 is for the instruction which also takes one clock cyle. + ; The delay can be 0 which will result in just 6us for the instruction itself .define CLK 6 ; Write the reset block after trigger @@ -98,16 +99,13 @@ impl<'d, PIO: Instance, const SM: usize> PioOneWire<'d, PIO, SM> { cfg.use_program(&program.prg, &[&pin]); cfg.set_in_pins(&[&pin]); - cfg.shift_in = ShiftConfig { - auto_fill: true, - direction: ShiftDirection::Right, - threshold: 8, - }; - cfg.shift_out = ShiftConfig { + let shift_cfg = ShiftConfig { auto_fill: true, direction: ShiftDirection::Right, threshold: 8, }; + cfg.shift_in = shift_cfg; + cfg.shift_out = shift_cfg; let divider = (clk_sys_freq() / 1000000) as u16 * 6; cfg.clock_divider = divider.into(); From f5ab597a07995259c950357acf8b4f8aad89ecfb Mon Sep 17 00:00:00 2001 From: Dion Dokter Date: Fri, 25 Apr 2025 10:53:17 +0200 Subject: [PATCH 1011/1217] Logging: Make some things less chatty --- embassy-stm32/src/adc/g4.rs | 2 +- embassy-usb/src/builder.rs | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/embassy-stm32/src/adc/g4.rs b/embassy-stm32/src/adc/g4.rs index 91be53607..8ed102c1b 100644 --- a/embassy-stm32/src/adc/g4.rs +++ b/embassy-stm32/src/adc/g4.rs @@ -143,7 +143,7 @@ impl<'d, T: Instance> Adc<'d, T> { T::common_regs().ccr().modify(|w| w.set_presc(prescaler.presc())); let frequency = Hertz(T::frequency().0 / prescaler.divisor()); - info!("ADC frequency set to {}", frequency); + trace!("ADC frequency set to {}", frequency); if frequency > MAX_ADC_CLK_FREQ { panic!("Maximal allowed frequency for the ADC is {} MHz and it varies with different packages, refer to ST docs for more information.", MAX_ADC_CLK_FREQ.0 / 1_000_000 ); diff --git a/embassy-usb/src/builder.rs b/embassy-usb/src/builder.rs index 9a21b9a3b..6c4b3f9a4 100644 --- a/embassy-usb/src/builder.rs +++ b/embassy-usb/src/builder.rs @@ -218,10 +218,10 @@ impl<'d, D: Driver<'d>> Builder<'d, D> { self.bos_descriptor.end_bos(); // Log the number of allocator bytes actually used in descriptor buffers - info!("USB: config_descriptor used: {}", self.config_descriptor.position()); - info!("USB: bos_descriptor used: {}", self.bos_descriptor.writer.position()); - info!("USB: msos_descriptor used: {}", msos_descriptor.len()); - info!("USB: control_buf size: {}", self.control_buf.len()); + trace!("USB: config_descriptor used: {}", self.config_descriptor.position()); + trace!("USB: bos_descriptor used: {}", self.bos_descriptor.writer.position()); + trace!("USB: msos_descriptor used: {}", msos_descriptor.len()); + trace!("USB: control_buf size: {}", self.control_buf.len()); UsbDevice::build( self.driver, From d1555f4d5fed9001bc743d6e13ec5be93896d599 Mon Sep 17 00:00:00 2001 From: Ekaterina Savelyeva Date: Fri, 25 Apr 2025 13:05:48 +0400 Subject: [PATCH 1012/1217] Dead-time computation in complementary PWM fixed (missing DTG msbs added) --- embassy-stm32/src/timer/complementary_pwm.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/embassy-stm32/src/timer/complementary_pwm.rs b/embassy-stm32/src/timer/complementary_pwm.rs index f543bafab..869e3df3b 100644 --- a/embassy-stm32/src/timer/complementary_pwm.rs +++ b/embassy-stm32/src/timer/complementary_pwm.rs @@ -240,11 +240,11 @@ fn compute_dead_time_value(value: u16) -> (Ckd, u8) { let (these_bits, result) = if target < 128 { (target as u8, target) } else if target < 255 { - (64 + (target / 2) as u8, (target - target % 2)) + ((64 + (target / 2) as u8) | 128, (target - target % 2)) } else if target < 508 { - (32 + (target / 8) as u8, (target - target % 8)) + ((32 + (target / 8) as u8) | 192, (target - target % 8)) } else if target < 1008 { - (32 + (target / 16) as u8, (target - target % 16)) + ((32 + (target / 16) as u8) | 224, (target - target % 16)) } else { (u8::MAX, 1008) }; From edc585a8ef0242604890df3f89d0abe766782c8d Mon Sep 17 00:00:00 2001 From: Ekaterina Savelyeva Date: Fri, 25 Apr 2025 13:36:38 +0400 Subject: [PATCH 1013/1217] Test for dead-time computation corrected --- embassy-stm32/src/timer/complementary_pwm.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/src/timer/complementary_pwm.rs b/embassy-stm32/src/timer/complementary_pwm.rs index 869e3df3b..8eec6c0c7 100644 --- a/embassy-stm32/src/timer/complementary_pwm.rs +++ b/embassy-stm32/src/timer/complementary_pwm.rs @@ -300,7 +300,7 @@ mod tests { TestRun { value: 400, ckd: Ckd::DIV1, - bits: 32 + (400u16 / 8) as u8, + bits: 210, }, TestRun { value: 600, From 8b123b4e0d585e142408980fa1d18fd1f91d738d Mon Sep 17 00:00:00 2001 From: Thomas Giesel Date: Sat, 26 Apr 2025 19:10:59 +0200 Subject: [PATCH 1014/1217] Fix set_ovsr typo, ramp up to latest stm32-data-generated This is an adaption to https://github.com/embassy-rs/stm32-data/pull/597 --- embassy-stm32/Cargo.toml | 4 ++-- embassy-stm32/src/adc/v4.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index a1dc75dba..54badc8f2 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -73,7 +73,7 @@ rand_core = "0.6.3" sdio-host = "0.9.0" critical-section = "1.1" #stm32-metapac = { version = "16" } -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-9385c0824aff194913a2eab3c957791d0de06771" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-a821bf5dd8d283c1e8de88fc7699235777a07e78" } vcell = "0.1.3" nb = "1.0.0" @@ -102,7 +102,7 @@ proc-macro2 = "1.0.36" quote = "1.0.15" #stm32-metapac = { version = "16", default-features = false, features = ["metadata"]} -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-9385c0824aff194913a2eab3c957791d0de06771", default-features = false, features = ["metadata"] } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-a821bf5dd8d283c1e8de88fc7699235777a07e78", default-features = false, features = ["metadata"] } [features] default = ["rt"] diff --git a/embassy-stm32/src/adc/v4.rs b/embassy-stm32/src/adc/v4.rs index 4d2e0f0df..e455b275c 100644 --- a/embassy-stm32/src/adc/v4.rs +++ b/embassy-stm32/src/adc/v4.rs @@ -305,7 +305,7 @@ impl<'d, T: Instance> Adc<'d, T> { T::regs().cfgr2().modify(|reg| { reg.set_rovse(enable); - reg.set_osvr(samples); + reg.set_ovsr(samples); reg.set_ovss(right_shift); }) } From c2173591aa77ab7aa0a1b3d921883667fb9881f4 Mon Sep 17 00:00:00 2001 From: ckrenslehner Date: Sat, 26 Apr 2025 20:07:30 +0200 Subject: [PATCH 1015/1217] docs: extend the waker documentation --- embassy-sync/README.md | 2 +- embassy-sync/src/waitqueue/atomic_waker.rs | 3 +++ embassy-sync/src/waitqueue/atomic_waker_turbo.rs | 3 +++ embassy-sync/src/waitqueue/multi_waker.rs | 2 ++ embassy-sync/src/waitqueue/waker_registration.rs | 4 ++++ 5 files changed, 13 insertions(+), 1 deletion(-) diff --git a/embassy-sync/README.md b/embassy-sync/README.md index 6871bcabc..91c59884f 100644 --- a/embassy-sync/README.md +++ b/embassy-sync/README.md @@ -12,7 +12,7 @@ Synchronization primitives and data structures with async support: - [`Mutex`](mutex::Mutex) - Mutex for synchronizing state between asynchronous tasks. - [`Pipe`](pipe::Pipe) - Byte stream implementing `embedded_io` traits. - [`WakerRegistration`](waitqueue::WakerRegistration) - Utility to register and wake a `Waker`. -- [`AtomicWaker`](waitqueue::AtomicWaker) - A variant of `WakerRegistration` accessible using a non-mut API. +- [`AtomicWaker`](waitqueue::AtomicWaker) - Utility to register and wake a `Waker` from interrupt context. - [`MultiWakerRegistration`](waitqueue::MultiWakerRegistration) - Utility registering and waking multiple `Waker`'s. - [`LazyLock`](lazy_lock::LazyLock) - A value which is initialized on the first access diff --git a/embassy-sync/src/waitqueue/atomic_waker.rs b/embassy-sync/src/waitqueue/atomic_waker.rs index 231902c5a..5a9910e7f 100644 --- a/embassy-sync/src/waitqueue/atomic_waker.rs +++ b/embassy-sync/src/waitqueue/atomic_waker.rs @@ -5,6 +5,9 @@ use crate::blocking_mutex::raw::{CriticalSectionRawMutex, RawMutex}; use crate::blocking_mutex::Mutex; /// Utility struct to register and wake a waker. +/// If a waker is registered, registering another waker will replace the previous one without waking it. +/// Intended to wake a task from an interrupt. Therefore, it is generally not expected, +/// that multiple tasks register try to register a waker simultaneously. pub struct GenericAtomicWaker { waker: Mutex>>, } diff --git a/embassy-sync/src/waitqueue/atomic_waker_turbo.rs b/embassy-sync/src/waitqueue/atomic_waker_turbo.rs index 5c6a96ec8..c06b83056 100644 --- a/embassy-sync/src/waitqueue/atomic_waker_turbo.rs +++ b/embassy-sync/src/waitqueue/atomic_waker_turbo.rs @@ -4,6 +4,9 @@ use core::sync::atomic::{AtomicPtr, Ordering}; use core::task::Waker; /// Utility struct to register and wake a waker. +/// If a waker is registered, registering another waker will replace the previous one without waking it. +/// The intended use case is to wake tasks from interrupts. Therefore, it is generally not expected, +/// that multiple tasks register try to register a waker simultaneously. pub struct AtomicWaker { waker: AtomicPtr<()>, } diff --git a/embassy-sync/src/waitqueue/multi_waker.rs b/embassy-sync/src/waitqueue/multi_waker.rs index 0e520bf40..0384d6bed 100644 --- a/embassy-sync/src/waitqueue/multi_waker.rs +++ b/embassy-sync/src/waitqueue/multi_waker.rs @@ -3,6 +3,8 @@ use core::task::Waker; use heapless::Vec; /// Utility struct to register and wake multiple wakers. +/// Queue of wakers with a maximum length of `N`. +/// Intended for waking multiple tasks. pub struct MultiWakerRegistration { wakers: Vec, } diff --git a/embassy-sync/src/waitqueue/waker_registration.rs b/embassy-sync/src/waitqueue/waker_registration.rs index 9b666e7c4..7f24f8fb6 100644 --- a/embassy-sync/src/waitqueue/waker_registration.rs +++ b/embassy-sync/src/waitqueue/waker_registration.rs @@ -2,6 +2,10 @@ use core::mem; use core::task::Waker; /// Utility struct to register and wake a waker. +/// If a waker is registered, registering another waker will replace the previous one. +/// The previous waker will be woken in this case, giving it a chance to reregister itself. +/// Although it is possible to wake multiple tasks this way, +/// this will cause them to wake each other in a loop registering themselves. #[derive(Debug, Default)] pub struct WakerRegistration { waker: Option, From 4ce3bdb3703e5120c7936b5e3762744ae4461e75 Mon Sep 17 00:00:00 2001 From: 1-rafael-1 Date: Sat, 26 Apr 2025 21:54:40 +0200 Subject: [PATCH 1016/1217] Add core voltage scaling options and PLL parameter finder for RP2040 --- embassy-rp/src/clocks.rs | 242 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 228 insertions(+), 14 deletions(-) diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs index 67aa5e540..ba7b139a6 100644 --- a/embassy-rp/src/clocks.rs +++ b/embassy-rp/src/clocks.rs @@ -69,6 +69,48 @@ pub enum PeriClkSrc { // Gpin1 = ClkPeriCtrlAuxsrc::CLKSRC_GPIN1 as _ , } +/// Core voltage scaling options for RP2040. +/// See RP2040 Datasheet, Table 18. +#[cfg(feature = "rp2040")] +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[repr(u8)] +pub enum VoltageScale { + /// 0.85V + V0_85 = 0b1000, + /// 0.90V + V0_90 = 0b1001, + /// 0.95V + V0_95 = 0b1010, + /// 1.00V + V1_00 = 0b1011, + /// 1.05V + V1_05 = 0b1100, + /// 1.10V (Default) + V1_10 = 0b1101, + /// 1.15V + V1_15 = 0b1110, + /// 1.20V + V1_20 = 0b1111, +} + +#[cfg(feature = "rp2040")] +impl VoltageScale { + /// Get the recommended Brown-Out Detection (BOD) setting for this voltage. + /// See RP2040 Datasheet, Table 19. + fn recommended_bod(self) -> u8 { + match self { + VoltageScale::V0_85 => 0b1000, // BOD recommends VSEL + 1 + VoltageScale::V0_90 => 0b1001, + VoltageScale::V0_95 => 0b1010, + VoltageScale::V1_00 => 0b1011, + VoltageScale::V1_05 => 0b1100, + VoltageScale::V1_10 => 0b1101, // Default + VoltageScale::V1_15 => 0b1110, + VoltageScale::V1_20 => 0b1111, + } + } +} + /// CLock configuration. #[non_exhaustive] pub struct ClockConfig { @@ -89,6 +131,9 @@ pub struct ClockConfig { /// RTC clock configuration. #[cfg(feature = "rp2040")] pub rtc_clk: Option, + /// Core voltage scaling (RP2040 only). Defaults to 1.10V if None. + #[cfg(feature = "rp2040")] + pub voltage_scale: Option, // gpin0: Option<(u32, Gpin<'static, AnyPin>)>, // gpin1: Option<(u32, Gpin<'static, AnyPin>)>, } @@ -152,6 +197,93 @@ impl ClockConfig { div_frac: 0, phase: 0, }), + #[cfg(feature = "rp2040")] + voltage_scale: None, // Use hardware default (1.10V) + // gpin0: None, + // gpin1: None, + } + } + + /// Clock configuration derived from external crystal, targeting a specific SYS clock frequency for RP2040. + /// + /// This function calculates the required PLL settings and core voltage based on the target frequency. + /// + /// # Arguments + /// + /// * `crystal_hz`: The frequency of the external crystal (e.g., 12_000_000 for 12MHz). + /// * `sys_freq_hz`: The target system clock frequency. + /// + /// # Panics + /// + /// Panics if the requested frequency is impossible to achieve with the given crystal, + /// or if the required voltage for the frequency is not supported or known. + /// + /// # Safety Notes (RP2040) + /// + /// * Frequencies > 133MHz require increased core voltage. + /// * This function automatically selects `VoltageScale::V1_15` for frequencies > 133MHz and <= 200MHz. + /// * Frequencies > 200MHz might require `VoltageScale::V1_20` or higher and are considered overclocking beyond datasheet recommendations. + /// This function will select `VoltageScale::V1_20` for frequencies > 200MHz, use with caution. + /// * Ensure your hardware supports the selected voltage and frequency. + #[cfg(feature = "rp2040")] + pub fn crystal_freq(crystal_hz: u32, sys_freq_hz: u32) -> Self { + // Determine required voltage based on target frequency + let voltage_scale = match sys_freq_hz { + 0..=133_000_000 => VoltageScale::V1_10, // Default voltage is sufficient + 133_000_001..=200_000_000 => VoltageScale::V1_15, // Requires 1.15V + _ => VoltageScale::V1_20, // Frequencies > 200MHz require at least 1.20V (Overclocking) + }; + + // Find suitable PLL parameters + let pll_params = find_pll_params(crystal_hz, sys_freq_hz) + .expect("Could not find valid PLL parameters for the requested frequency"); + + Self { + rosc: Some(RoscConfig { + hz: 6_500_000, + range: RoscRange::Medium, + drive_strength: [0; 8], + div: 16, + }), + xosc: Some(XoscConfig { + hz: crystal_hz, + sys_pll: Some(pll_params), + // Keep USB PLL at 48MHz for compatibility + usb_pll: Some(PllConfig { + refdiv: 1, + fbdiv: 120, + post_div1: 6, + post_div2: 5, + }), + delay_multiplier: 128, + }), + ref_clk: RefClkConfig { + src: RefClkSrc::Xosc, + div: 1, + }, + sys_clk: SysClkConfig { + src: SysClkSrc::PllSys, + div_int: 1, + div_frac: 0, + }, + peri_clk_src: Some(PeriClkSrc::Sys), + usb_clk: Some(UsbClkConfig { + src: UsbClkSrc::PllUsb, + div: 1, + phase: 0, + }), + adc_clk: Some(AdcClkConfig { + src: AdcClkSrc::PllUsb, + div: 1, + phase: 0, + }), + rtc_clk: Some(RtcClkConfig { + src: RtcClkSrc::PllUsb, + div_int: 1024, + div_frac: 0, + phase: 0, + }), + voltage_scale: Some(voltage_scale), // gpin0: None, // gpin1: None, } @@ -192,8 +324,10 @@ impl ClockConfig { div_frac: 171, phase: 0, }), - // gpin0: None, - // gpin1: None, + #[cfg(feature = "rp2040")] + voltage_scale: None, // Use hardware default (1.10V) + // gpin0: None, + // gpin1: None, } } @@ -405,6 +539,72 @@ pub struct RtcClkConfig { pub phase: u8, } +/// Find valid PLL parameters (refdiv, fbdiv, post_div1, post_div2) for a target output frequency +/// based on the input frequency. +/// +/// See RP2040 Datasheet section 2.16.3. Reference Clock (ref) and 2.18.3. PLL +#[cfg(feature = "rp2040")] +fn find_pll_params(input_hz: u32, target_hz: u32) -> Option { + // Constraints from datasheet: + // REFDIV: 1..=63 + // FBDIV: 16..=320 + // POSTDIV1: 1..=7 + // POSTDIV2: 1..=7 (must be <= POSTDIV1) + // VCO frequency (input_hz / refdiv * fbdiv): 400MHz ..= 1600MHz + + for refdiv in 1..=63 { + let ref_clk = input_hz / refdiv; + // Reference clock must be >= 5MHz (implied by VCO min / FBDIV max) + if ref_clk < 5_000_000 { + continue; + } + + for fbdiv in (16..=320).rev() { + // Iterate high fbdiv first for better VCO stability + let vco_freq = ref_clk * fbdiv; + if !(400_000_000..=1_600_000_000).contains(&vco_freq) { + continue; + } + + // We want vco_freq / (post_div1 * post_div2) = target_hz + // So, post_div1 * post_div2 = vco_freq / target_hz + let target_post_div_product = vco_freq as f64 / target_hz as f64; + if target_post_div_product < 1.0 || target_post_div_product > 49.0 { + // 7*7 = 49 + continue; + } + // Manual rounding: floor(x + 0.5) + let target_post_div_product_int = (target_post_div_product + 0.5) as u32; + if target_post_div_product_int == 0 { + continue; + } + + // Check if the rounded product gives the target frequency + if vco_freq / target_post_div_product_int != target_hz { + continue; + } + + for post_div1 in (1..=7).rev() { + // Iterate high post_div1 first + if target_post_div_product_int % post_div1 == 0 { + let post_div2 = target_post_div_product_int / post_div1; + if (1..=7).contains(&post_div2) && post_div2 <= post_div1 { + // Found a valid combination + return Some(PllConfig { + refdiv: refdiv as u8, // Cast u32 to u8 (safe: 1..=63) + fbdiv: fbdiv as u16, // Cast u32 to u16 (safe: 16..=320) + post_div1: post_div1 as u8, + post_div2: post_div2 as u8, + }); + } + } + } + } + } + + None // No valid parameters found +} + /// safety: must be called exactly once at bootup pub(crate) unsafe fn init(config: ClockConfig) { // Reset everything except: @@ -447,23 +647,14 @@ pub(crate) unsafe fn init(config: ClockConfig) { reset::reset(peris); reset::unreset_wait(peris); - // let gpin0_freq = config.gpin0.map_or(0, |p| { - // core::mem::forget(p.1); - // p.0 - // }); - // CLOCKS.gpin0.store(gpin0_freq, Ordering::Relaxed); - // let gpin1_freq = config.gpin1.map_or(0, |p| { - // core::mem::forget(p.1); - // p.0 - // }); - // CLOCKS.gpin1.store(gpin1_freq, Ordering::Relaxed); - + // Configure ROSC first if present let rosc_freq = match config.rosc { Some(config) => configure_rosc(config), None => 0, }; CLOCKS.rosc.store(rosc_freq, Ordering::Relaxed); + // Configure XOSC and PLLs if present let (xosc_freq, pll_sys_freq, pll_usb_freq) = match config.xosc { Some(config) => { // start XOSC @@ -488,6 +679,7 @@ pub(crate) unsafe fn init(config: ClockConfig) { CLOCKS.pll_sys.store(pll_sys_freq, Ordering::Relaxed); CLOCKS.pll_usb.store(pll_usb_freq, Ordering::Relaxed); + // Configure REF clock source and divider let (ref_src, ref_aux, clk_ref_freq) = { use {ClkRefCtrlAuxsrc as Aux, ClkRefCtrlSrc as Src}; let div = config.ref_clk.div as u32; @@ -514,7 +706,7 @@ pub(crate) unsafe fn init(config: ClockConfig) { w.set_int(config.ref_clk.div); }); - // Configure tick generation on the 2040. + // Configure tick generation using REF clock #[cfg(feature = "rp2040")] pac::WATCHDOG.tick().write(|w| { w.set_cycles((clk_ref_freq / 1_000_000) as u16); @@ -532,6 +724,28 @@ pub(crate) unsafe fn init(config: ClockConfig) { pac::TICKS.watchdog_ctrl().write(|w| w.set_enable(true)); } + // Set Core Voltage (RP2040 only) BEFORE switching SYS clock to high speed PLL + #[cfg(feature = "rp2040")] + if let Some(voltage) = config.voltage_scale { + let vreg = pac::VREG_AND_CHIP_RESET; + let current_vsel = vreg.vreg().read().vsel(); + let target_vsel = voltage as u8; + + if target_vsel != current_vsel { + // Set voltage and recommended BOD level + vreg.bod().write(|w| w.set_vsel(voltage.recommended_bod())); + vreg.vreg().write(|w| w.set_vsel(target_vsel)); + + // Wait 10us for regulator to settle. Delay calculation uses REF clock + // as it's guaranteed to be stable here, before SYS potentially switches. + // 10 us = 1/100_000 s. cycles = freq * time. + let delay_cycles = clk_ref_freq / 100_000; + // delay(N) waits N+1 cycles. + cortex_m::asm::delay(delay_cycles.saturating_sub(1)); + } + } + + // Configure SYS clock source and divider let (sys_src, sys_aux, clk_sys_freq) = { use {ClkSysCtrlAuxsrc as Aux, ClkSysCtrlSrc as Src}; let (src, aux, freq) = match config.sys_clk.src { From 713d6291d569cf44ce3a53bc93ddd7d569fb93ed Mon Sep 17 00:00:00 2001 From: 1-rafael-1 Date: Sat, 26 Apr 2025 21:54:48 +0200 Subject: [PATCH 1017/1217] Scale clock dividers in HD44780, rotary encoder, and stepper driver based on system clock frequency --- embassy-rp/src/pio_programs/hd44780.rs | 15 +++++++++++++-- embassy-rp/src/pio_programs/rotary_encoder.rs | 8 +++++++- embassy-rp/src/pio_programs/stepper.rs | 5 +++-- 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/embassy-rp/src/pio_programs/hd44780.rs b/embassy-rp/src/pio_programs/hd44780.rs index 5846a8027..3aa54495f 100644 --- a/embassy-rp/src/pio_programs/hd44780.rs +++ b/embassy-rp/src/pio_programs/hd44780.rs @@ -1,5 +1,6 @@ //! [HD44780 display driver](https://www.sparkfun.com/datasheets/LCD/HD44780.pdf) +use crate::clocks::clk_sys_freq; use crate::dma::{AnyChannel, Channel}; use crate::pio::{ Common, Config, Direction, FifoJoin, Instance, Irq, LoadedProgram, PioPin, ShiftConfig, ShiftDirection, @@ -134,7 +135,12 @@ impl<'l, P: Instance, const S: usize> PioHD44780<'l, P, S> { let mut cfg = Config::default(); cfg.use_program(&word_prg.prg, &[&e]); - cfg.clock_divider = 125u8.into(); + + // Scale the divider based on system clock frequency + // Original: 125 at 125 MHz (1 MHz PIO clock) + let word_divider = (clk_sys_freq() / 1_000_000) as u8; // Target 1 MHz PIO clock + cfg.clock_divider = word_divider.into(); + cfg.set_out_pins(&[&db4, &db5, &db6, &db7]); cfg.shift_out = ShiftConfig { auto_fill: true, @@ -160,7 +166,12 @@ impl<'l, P: Instance, const S: usize> PioHD44780<'l, P, S> { let mut cfg = Config::default(); cfg.use_program(&seq_prg.prg, &[&e]); - cfg.clock_divider = 8u8.into(); // ~64ns/insn + + // Original: 8 at 125 MHz (~15.6 MHz PIO clock) + // Comment says ~64ns/insn which is 1/(15.6 MHz) = ~64ns + let seq_divider = (clk_sys_freq() / 15_600_000) as u8; // Target ~15.6 MHz PIO clock (~64ns/insn) + cfg.clock_divider = seq_divider.into(); + cfg.set_jmp_pin(&db7); cfg.set_set_pins(&[&rs, &rw]); cfg.set_out_pins(&[&db4, &db5, &db6, &db7]); diff --git a/embassy-rp/src/pio_programs/rotary_encoder.rs b/embassy-rp/src/pio_programs/rotary_encoder.rs index e520da8a3..7bd463bb8 100644 --- a/embassy-rp/src/pio_programs/rotary_encoder.rs +++ b/embassy-rp/src/pio_programs/rotary_encoder.rs @@ -2,6 +2,7 @@ use fixed::traits::ToFixed; +use crate::clocks::clk_sys_freq; use crate::gpio::Pull; use crate::pio::{ Common, Config, Direction as PioDirection, FifoJoin, Instance, LoadedProgram, PioPin, ShiftDirection, StateMachine, @@ -48,7 +49,12 @@ impl<'d, T: Instance, const SM: usize> PioEncoder<'d, T, SM> { cfg.set_in_pins(&[&pin_a, &pin_b]); cfg.fifo_join = FifoJoin::RxOnly; cfg.shift_in.direction = ShiftDirection::Left; - cfg.clock_divider = 10_000.to_fixed(); + + // Original: 10_000 at 125 MHz (12.5 KHz PIO clock) + // Scale divider to maintain same PIO clock frequency at different system clocks + let divider = (clk_sys_freq() as f32 / 12_500.0).to_fixed(); + cfg.clock_divider = divider; + cfg.use_program(&program.prg, &[]); sm.set_config(&cfg); sm.set_enable(true); diff --git a/embassy-rp/src/pio_programs/stepper.rs b/embassy-rp/src/pio_programs/stepper.rs index 495191659..6878c32f5 100644 --- a/embassy-rp/src/pio_programs/stepper.rs +++ b/embassy-rp/src/pio_programs/stepper.rs @@ -6,6 +6,7 @@ use fixed::traits::ToFixed; use fixed::types::extra::U8; use fixed::FixedU32; +use crate::clocks::clk_sys_freq; use crate::pio::{Common, Config, Direction, Instance, Irq, LoadedProgram, PioPin, StateMachine}; use crate::Peri; @@ -64,7 +65,7 @@ impl<'d, T: Instance, const SM: usize> PioStepper<'d, T, SM> { sm.set_pin_dirs(Direction::Out, &[&pin0, &pin1, &pin2, &pin3]); let mut cfg = Config::default(); cfg.set_out_pins(&[&pin0, &pin1, &pin2, &pin3]); - cfg.clock_divider = (125_000_000 / (100 * 136)).to_fixed(); + cfg.clock_divider = (clk_sys_freq() / (100 * 136)).to_fixed(); cfg.use_program(&program.prg, &[]); sm.set_config(&cfg); sm.set_enable(true); @@ -73,7 +74,7 @@ impl<'d, T: Instance, const SM: usize> PioStepper<'d, T, SM> { /// Set pulse frequency pub fn set_frequency(&mut self, freq: u32) { - let clock_divider: FixedU32 = (125_000_000 / (freq * 136)).to_fixed(); + let clock_divider: FixedU32 = (clk_sys_freq() / (freq * 136)).to_fixed(); assert!(clock_divider <= 65536, "clkdiv must be <= 65536"); assert!(clock_divider >= 1, "clkdiv must be >= 1"); self.sm.set_clock_divider(clock_divider); From 45b7127d614ddc65181249e70d94422500865ecd Mon Sep 17 00:00:00 2001 From: 1-rafael-1 Date: Sat, 26 Apr 2025 21:55:16 +0200 Subject: [PATCH 1018/1217] fmt --- embassy-rp/src/pio_programs/rotary_encoder.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-rp/src/pio_programs/rotary_encoder.rs b/embassy-rp/src/pio_programs/rotary_encoder.rs index 7bd463bb8..71567a602 100644 --- a/embassy-rp/src/pio_programs/rotary_encoder.rs +++ b/embassy-rp/src/pio_programs/rotary_encoder.rs @@ -49,12 +49,12 @@ impl<'d, T: Instance, const SM: usize> PioEncoder<'d, T, SM> { cfg.set_in_pins(&[&pin_a, &pin_b]); cfg.fifo_join = FifoJoin::RxOnly; cfg.shift_in.direction = ShiftDirection::Left; - + // Original: 10_000 at 125 MHz (12.5 KHz PIO clock) // Scale divider to maintain same PIO clock frequency at different system clocks let divider = (clk_sys_freq() as f32 / 12_500.0).to_fixed(); cfg.clock_divider = divider; - + cfg.use_program(&program.prg, &[]); sm.set_config(&cfg); sm.set_enable(true); From b0594d16f238f803a0192810833ae2b0c3941ec3 Mon Sep 17 00:00:00 2001 From: 1-rafael-1 Date: Sat, 26 Apr 2025 22:55:24 +0200 Subject: [PATCH 1019/1217] Add overclock example for RP2040 with 200 MHz clock configuration --- examples/rp/src/bin/overclock.rs | 60 ++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 examples/rp/src/bin/overclock.rs diff --git a/examples/rp/src/bin/overclock.rs b/examples/rp/src/bin/overclock.rs new file mode 100644 index 000000000..429fff1ac --- /dev/null +++ b/examples/rp/src/bin/overclock.rs @@ -0,0 +1,60 @@ +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_rp::clocks::{clk_sys_freq, ClockConfig}; +use embassy_rp::config::Config; +use embassy_rp::gpio::{Level, Output}; +use embassy_time::{Duration, Instant, Timer}; +use {defmt_rtt as _, panic_probe as _}; + +const COUNT_TO: i32 = 1_000_000; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) -> ! { + // Set up for clock frequency of 200 MHz + // We will need a clock config in the HAL config that supports this frequency + // The RP2040 can run at 200 MHz with a 12 MHz crystal + let config = Config::new(ClockConfig::crystal_freq(12_000_000, 200_000_000)); + + // Initialize the peripherals + let p = embassy_rp::init(config); + + // Show CPU frequency for verification + let sys_freq = clk_sys_freq(); + info!("System clock frequency: {} Hz", sys_freq); + + // LED to indicate the system is running + let mut led = Output::new(p.PIN_25, Level::Low); + + loop { + // Reset the counter at the start of measurement period + let mut counter = 0; + + // Turn LED on while counting + led.set_high(); + + let start = Instant::now(); + + // Count to COUNT_TO + // This is a busy loop that will take some time to complete + while counter < COUNT_TO { + counter += 1; + } + + let elapsed = start - Instant::now(); + + // Report the elapsed time + led.set_low(); + info!( + "At {}Mhz: Elapsed time to count to {}: {}ms", + sys_freq / 1_000_000, + COUNT_TO, + elapsed.as_millis() + ); + + // Wait 2 seconds before starting the next measurement + Timer::after(Duration::from_secs(2)).await; + } +} From eaec6c81651aaf59212a8def080bbd279192f357 Mon Sep 17 00:00:00 2001 From: Corey Schuhen Date: Fri, 18 Apr 2025 14:41:56 +0100 Subject: [PATCH 1020/1217] Make raw_data public. --- embassy-stm32/src/can/frame.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/can/frame.rs b/embassy-stm32/src/can/frame.rs index a4d5a9752..0fbab053b 100644 --- a/embassy-stm32/src/can/frame.rs +++ b/embassy-stm32/src/can/frame.rs @@ -212,8 +212,8 @@ impl Frame { &self.data.raw()[..self.can_header.len as usize] } - /// Get reference to underlying 8-byte raw data buffer - pub(crate) fn raw_data(&self) -> &[u8] { + /// Get reference to underlying 8-byte raw data buffer, some bytes on the tail might be undefined. + pub fn raw_data(&self) -> &[u8] { self.data.raw() } From cdef573f529c49d27a1daace3fc0c7a5d38b05de Mon Sep 17 00:00:00 2001 From: Luke Rindels Date: Sun, 27 Apr 2025 13:19:14 -0700 Subject: [PATCH 1021/1217] Enable rp235x trng self-tests by default Gracefully handle rp235x trng self-test errors and resets --- embassy-rp/src/trng.rs | 104 ++++++++++++++++++++++++++--------------- 1 file changed, 67 insertions(+), 37 deletions(-) diff --git a/embassy-rp/src/trng.rs b/embassy-rp/src/trng.rs index 611fee83b..a8a0172be 100644 --- a/embassy-rp/src/trng.rs +++ b/embassy-rp/src/trng.rs @@ -78,6 +78,9 @@ impl From for u8 { /// failed entropy checks. /// For acceptable results with an average generation time of about 2 milliseconds, use ROSC chain length settings of 0 or /// 1 and sample count settings of 20-25. +/// Larger sample count settings (e.g. 100) provide proportionately slower average generation times. These settings +/// significantly reduce, but do not eliminate NIST test failures and entropy check failures. Results occasionally take an +/// especially long time to generate. /// /// --- /// @@ -108,9 +111,10 @@ pub struct Config { impl Default for Config { fn default() -> Self { Config { - disable_autocorrelation_test: true, - disable_crngt_test: true, - disable_von_neumann_balancer: true, + // WARNING: Disabling these tests increases likelihood of poor rng results. + disable_autocorrelation_test: false, + disable_crngt_test: false, + disable_von_neumann_balancer: false, sample_count: 25, inverter_chain_length: InverterChainLength::One, } @@ -148,6 +152,7 @@ impl Default for Config { /// ``` pub struct Trng<'d, T: Instance> { phantom: PhantomData<&'d mut T>, + config: Config, } /// 12.12.1. Overview @@ -159,28 +164,12 @@ const TRNG_BLOCK_SIZE_BYTES: usize = TRNG_BLOCK_SIZE_BITS / 8; impl<'d, T: Instance> Trng<'d, T> { /// Create a new TRNG driver. pub fn new(_trng: Peri<'d, T>, _irq: impl Binding> + 'd, config: Config) -> Self { - let regs = T::regs(); - - regs.rng_imr().write(|w| w.set_ehr_valid_int_mask(false)); - - let trng_config_register = regs.trng_config(); - trng_config_register.write(|w| { - w.set_rnd_src_sel(config.inverter_chain_length.clone().into()); - }); - - let sample_count_register = regs.sample_cnt1(); - sample_count_register.write(|w| { - *w = config.sample_count; - }); - - let debug_control_register = regs.trng_debug_control(); - debug_control_register.write(|w| { - w.set_auto_correlate_bypass(config.disable_autocorrelation_test); - w.set_trng_crngt_bypass(config.disable_crngt_test); - w.set_vnc_bypass(config.disable_von_neumann_balancer) - }); - - Trng { phantom: PhantomData } + let trng = Trng { + phantom: PhantomData, + config: config, + }; + trng.initialize_rng(); + trng } fn start_rng(&self) { @@ -198,6 +187,29 @@ impl<'d, T: Instance> Trng<'d, T> { reset_bits_counter_register.write(|w| w.set_rst_bits_counter(true)); } + fn initialize_rng(&self) { + let regs = T::regs(); + + regs.rng_imr().write(|w| w.set_ehr_valid_int_mask(false)); + + let trng_config_register = regs.trng_config(); + trng_config_register.write(|w| { + w.set_rnd_src_sel(self.config.inverter_chain_length.clone().into()); + }); + + let sample_count_register = regs.sample_cnt1(); + sample_count_register.write(|w| { + *w = self.config.sample_count; + }); + + let debug_control_register = regs.trng_debug_control(); + debug_control_register.write(|w| { + w.set_auto_correlate_bypass(self.config.disable_autocorrelation_test); + w.set_trng_crngt_bypass(self.config.disable_crngt_test); + w.set_vnc_bypass(self.config.disable_von_neumann_balancer); + }); + } + fn enable_irq(&self) { unsafe { T::Interrupt::enable() } } @@ -218,6 +230,10 @@ impl<'d, T: Instance> Trng<'d, T> { if trng_valid_register.read().ehr_valid().not() { if regs.rng_isr().read().autocorr_err() { regs.trng_sw_reset().write(|w| w.set_trng_sw_reset(true)); + // Fixed delay is required after TRNG soft reset. This read is sufficient. + regs.trng_sw_reset().read(); + self.initialize_rng(); + self.start_rng(); } else { panic!("RNG not busy, but ehr is not valid!") } @@ -279,8 +295,11 @@ impl<'d, T: Instance> Trng<'d, T> { if trng_busy_register.read().trng_busy() { Poll::Pending } else { + // If woken up and EHR is *not* valid, assume the trng has been reset and reinitialize, restart. if trng_valid_register.read().ehr_valid().not() { - panic!("RNG not busy, but ehr is not valid!") + self.initialize_rng(); + self.start_rng(); + return Poll::Pending; } self.read_ehr_registers_into_array(&mut buffer); let remaining = destination_length - bytes_transferred; @@ -380,25 +399,36 @@ impl interrupt::typelevel::Handler for InterruptHandl unsafe fn on_interrupt() { let regs = T::regs(); let isr = regs.rng_isr().read(); - // Clear ehr bit - regs.rng_icr().write(|w| { - w.set_ehr_valid(true); - }); if isr.ehr_valid() { + regs.rng_icr().write(|w| { + w.set_ehr_valid(true); + }); T::waker().wake(); - } else { + } else if isr.crngt_err() { + warn!("TRNG CRNGT error! Increase sample count to reduce likelihood"); + regs.rng_icr().write(|w| { + w.set_crngt_err(true); + }); + } else if isr.vn_err() { + warn!("TRNG Von-Neumann balancer error! Increase sample count to reduce likelihood"); + regs.rng_icr().write(|w| { + w.set_vn_err(true); + }); + } else if isr.autocorr_err() { // 12.12.5. List of Registers // ... // TRNG: RNG_ISR Register // ... // AUTOCORR_ERR: 1 indicates Autocorrelation test failed four times in a row. // When set, RNG ceases functioning until next reset - if isr.autocorr_err() { - warn!("TRNG Autocorrect error! Resetting TRNG"); - regs.trng_sw_reset().write(|w| { - w.set_trng_sw_reset(true); - }); - } + warn!("TRNG Autocorrect error! Resetting TRNG. Increase sample count to reduce likelihood"); + regs.trng_sw_reset().write(|w| { + w.set_trng_sw_reset(true); + }); + // Fixed delay is required after TRNG soft reset, this read is sufficient. + regs.trng_sw_reset().read(); + // Wake up to reinitialize and restart the TRNG. + T::waker().wake(); } } } From 74cb84eb4e4be75859deb6fa4896efae5345eacb Mon Sep 17 00:00:00 2001 From: Michael Medin Date: Mon, 28 Apr 2025 09:14:56 +0200 Subject: [PATCH 1022/1217] Moved functions to rcc module (this is a bit awkward as we now have two init functions in rcc: `rcc::init`and `rcc::init_rcc`) --- embassy-stm32/src/lib.rs | 32 +------------------------------- embassy-stm32/src/rcc/mod.rs | 30 ++++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 31 deletions(-) diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 444d14f28..3e84d3386 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -213,7 +213,6 @@ macro_rules! bind_interrupts { // Reexports pub use _generated::{peripherals, Peripherals}; -use critical_section::CriticalSection; pub use embassy_hal_internal::{Peri, PeripheralType}; #[cfg(feature = "unstable-pac")] pub use stm32_metapac as pac; @@ -601,38 +600,9 @@ fn init_hw(config: Config) -> Peripherals { #[cfg(feature = "exti")] exti::init(cs); - init_rcc(cs, config.rcc); + rcc::init_rcc(cs, config.rcc); } p }) } - -/// Re-initialize the `embassy-stm32` clock configuration with the provided configuration. -/// -/// This is useful when you need to alter the CPU clock after configuring peripherals. -/// For instance, configure an external clock via spi or i2c. -/// -/// Please not this only re-configures the rcc and the time driver (not GPIO, EXTI, etc). -/// -/// This should only be called after `init`. -#[cfg(not(feature = "_dual-core"))] -pub fn reinit(config: rcc::Config) { - critical_section::with(|cs| init_rcc(cs, config)) -} - -fn init_rcc(_cs: CriticalSection, config: rcc::Config) { - unsafe { - rcc::init(config); - - // must be after rcc init - #[cfg(feature = "_time-driver")] - time_driver::init(_cs); - - #[cfg(feature = "low-power")] - { - crate::rcc::REFCOUNT_STOP2 = 0; - crate::rcc::REFCOUNT_STOP1 = 0; - } - } -} diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index 4f43d3748..cf88cfad6 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs @@ -34,6 +34,7 @@ pub use _version::*; use stm32_metapac::RCC; pub use crate::_generated::{mux, Clocks}; +use crate::rcc; use crate::time::Hertz; #[cfg(feature = "low-power")] @@ -369,3 +370,32 @@ pub fn enable_and_reset() { pub fn disable() { T::RCC_INFO.disable(); } + +/// Re-initialize the `embassy-stm32` clock configuration with the provided configuration. +/// +/// This is useful when you need to alter the CPU clock after configuring peripherals. +/// For instance, configure an external clock via spi or i2c. +/// +/// Please not this only re-configures the rcc and the time driver (not GPIO, EXTI, etc). +/// +/// This should only be called after `init`. +#[cfg(not(feature = "_dual-core"))] +pub fn reinit(config: Config) { + critical_section::with(|cs| init_rcc(cs, config)) +} + +fn init_rcc(_cs: CriticalSection, config: Config) { + unsafe { + init(config); + + // must be after rcc init + #[cfg(feature = "_time-driver")] + crate::time_driver::init(_cs); + + #[cfg(feature = "low-power")] + { + REFCOUNT_STOP2 = 0; + REFCOUNT_STOP1 = 0; + } + } +} From 1d578f5a7e1fe2b676f36b1960a93af899418c91 Mon Sep 17 00:00:00 2001 From: Michael Medin Date: Mon, 28 Apr 2025 09:21:21 +0200 Subject: [PATCH 1023/1217] function needs to be pub(crate) --- embassy-stm32/src/rcc/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index cf88cfad6..22bec6d1a 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs @@ -384,7 +384,7 @@ pub fn reinit(config: Config) { critical_section::with(|cs| init_rcc(cs, config)) } -fn init_rcc(_cs: CriticalSection, config: Config) { +pub(crate) fn init_rcc(_cs: CriticalSection, config: Config) { unsafe { init(config); From a94cc79b9b5e01f7b207947a1dfa30432e508a9c Mon Sep 17 00:00:00 2001 From: Michael Medin Date: Mon, 28 Apr 2025 18:52:03 +0200 Subject: [PATCH 1024/1217] removed unused import --- embassy-stm32/src/rcc/mod.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index 22bec6d1a..3c00d5dfb 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs @@ -34,7 +34,6 @@ pub use _version::*; use stm32_metapac::RCC; pub use crate::_generated::{mux, Clocks}; -use crate::rcc; use crate::time::Hertz; #[cfg(feature = "low-power")] From 3a6dc910ffc66d4a30b89f299432b383271a719f Mon Sep 17 00:00:00 2001 From: 1-rafael-1 Date: Mon, 28 Apr 2025 22:54:15 +0200 Subject: [PATCH 1025/1217] first working draft --- embassy-rp/src/clocks.rs | 666 +++++++++++++++++++++++-------- examples/rp/src/bin/overclock.rs | 26 +- 2 files changed, 509 insertions(+), 183 deletions(-) diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs index ba7b139a6..b74e90f5e 100644 --- a/embassy-rp/src/clocks.rs +++ b/embassy-rp/src/clocks.rs @@ -70,43 +70,51 @@ pub enum PeriClkSrc { } /// Core voltage scaling options for RP2040. -/// See RP2040 Datasheet, Table 18. +/// See RP2040 Datasheet, Table 189, VREG Register. #[cfg(feature = "rp2040")] #[derive(Clone, Copy, Debug, PartialEq, Eq)] #[repr(u8)] pub enum VoltageScale { /// 0.85V - V0_85 = 0b1000, + V0_85 = 0b0110, /// 0.90V - V0_90 = 0b1001, + V0_90 = 0b0111, /// 0.95V - V0_95 = 0b1010, + V0_95 = 0b1000, /// 1.00V - V1_00 = 0b1011, + V1_00 = 0b1001, /// 1.05V - V1_05 = 0b1100, + V1_05 = 0b1010, /// 1.10V (Default) - V1_10 = 0b1101, + V1_10 = 0b1011, /// 1.15V - V1_15 = 0b1110, + V1_15 = 0b1100, /// 1.20V - V1_20 = 0b1111, + V1_20 = 0b1101, + /// 1.25V + V1_25 = 0b1110, + /// 1.30V + V1_30 = 0b1111, } #[cfg(feature = "rp2040")] impl VoltageScale { /// Get the recommended Brown-Out Detection (BOD) setting for this voltage. - /// See RP2040 Datasheet, Table 19. + /// Sets the BOD threshold to approximately 90% of the core voltage. + /// See RP2040 Datasheet, Table 190, BOD Register fn recommended_bod(self) -> u8 { match self { - VoltageScale::V0_85 => 0b1000, // BOD recommends VSEL + 1 - VoltageScale::V0_90 => 0b1001, - VoltageScale::V0_95 => 0b1010, - VoltageScale::V1_00 => 0b1011, - VoltageScale::V1_05 => 0b1100, - VoltageScale::V1_10 => 0b1101, // Default - VoltageScale::V1_15 => 0b1110, - VoltageScale::V1_20 => 0b1111, + // ~90% of voltage setting based on Table 190 values + VoltageScale::V0_85 => 0b0111, // 0.774V (~91% of 0.85V) + VoltageScale::V0_90 => 0b1000, // 0.817V (~91% of 0.90V) + VoltageScale::V0_95 => 0b1001, // 0.860V (~91% of 0.95V) + VoltageScale::V1_00 => 0b1010, // 0.903V (~90% of 1.00V) + VoltageScale::V1_05 => 0b1011, // 0.946V (~90% of 1.05V) + VoltageScale::V1_10 => 0b1100, // 0.989V (~90% of 1.10V) + VoltageScale::V1_15 => 0b1101, // 1.032V (~90% of 1.15V) + VoltageScale::V1_20 => 0b1110, // 1.075V (~90% of 1.20V) + VoltageScale::V1_25 => 0b1111, // 1.118V (~89% of 1.25V) + VoltageScale::V1_30 => 0b1111, // 1.118V (~86% of 1.30V) - using max available threshold } } } @@ -134,6 +142,9 @@ pub struct ClockConfig { /// Core voltage scaling (RP2040 only). Defaults to 1.10V if None. #[cfg(feature = "rp2040")] pub voltage_scale: Option, + /// Voltage stabilization delay in microseconds. + #[cfg(feature = "rp2040")] + pub voltage_stabilization_delay_us: Option, // gpin0: Option<(u32, Gpin<'static, AnyPin>)>, // gpin1: Option<(u32, Gpin<'static, AnyPin>)>, } @@ -199,8 +210,10 @@ impl ClockConfig { }), #[cfg(feature = "rp2040")] voltage_scale: None, // Use hardware default (1.10V) - // gpin0: None, - // gpin1: None, + #[cfg(feature = "rp2040")] + voltage_stabilization_delay_us: None, + // gpin0: None, + // gpin1: None, } } @@ -235,8 +248,16 @@ impl ClockConfig { }; // Find suitable PLL parameters - let pll_params = find_pll_params(crystal_hz, sys_freq_hz) - .expect("Could not find valid PLL parameters for the requested frequency"); + let pll_params = match find_pll_params(crystal_hz, sys_freq_hz) { + Some(params) => params, + None => { + // If we can't find valid parameters for the requested frequency, + // fall back to safe defaults (125 MHz for RP2040) + let safe_freq = 125_000_000; // Safe default frequency + find_pll_params(crystal_hz, safe_freq) + .expect("Could not find valid PLL parameters even for safe default frequency") + } + }; Self { rosc: Some(RoscConfig { @@ -284,6 +305,8 @@ impl ClockConfig { phase: 0, }), voltage_scale: Some(voltage_scale), + #[cfg(feature = "rp2040")] + voltage_stabilization_delay_us: None, // gpin0: None, // gpin1: None, } @@ -326,11 +349,128 @@ impl ClockConfig { }), #[cfg(feature = "rp2040")] voltage_scale: None, // Use hardware default (1.10V) - // gpin0: None, - // gpin1: None, + #[cfg(feature = "rp2040")] + voltage_stabilization_delay_us: None, + // gpin0: None, + // gpin1: None, } } + /// Configure the system clock to a specific frequency in MHz. + /// + /// This is a more user-friendly way to configure the system clock, similar to + /// the Pico SDK's approach. It automatically handles voltage scaling based on the + /// requested frequency and uses the standard 12MHz crystal found on most RP2040 boards. + /// + /// # Arguments + /// + /// * `sys_freq_mhz` - The target system clock frequency in MHz + /// + /// # Safety Notes + /// + /// * Frequencies > 133MHz require increased core voltage and are considered overclocking. + /// * Frequencies > 250MHz are extreme overclocking and may not be stable on all chips. + /// + /// # Example + /// + /// ``` + /// // Configure for standard 125MHz clock + /// let config = ClockConfig::with_speed_mhz(125); + /// + /// // Overclock to 200MHz (requires higher voltage) + /// let config = ClockConfig::with_speed_mhz(200); + /// ``` + #[cfg(feature = "rp2040")] + pub fn with_speed_mhz(sys_freq_mhz: u32) -> Self { + // For 125MHz, use exactly the same config as the default to avoid any differences + if sys_freq_mhz == 125 { + return Self::crystal(12_000_000); + } + + // For other frequencies, provide appropriate voltage scaling and PLL configuration + // Standard crystal on Raspberry Pi Pico boards is 12MHz + const DEFAULT_CRYSTAL_HZ: u32 = 12_000_000; + + let sys_freq_hz = sys_freq_mhz * 1_000_000; + let mut config = Self::crystal_freq(DEFAULT_CRYSTAL_HZ, sys_freq_hz); + + // For frequencies above 200MHz, ensure we're using the highest voltage + if sys_freq_mhz > 200 { + config.voltage_scale = Some(VoltageScale::V1_20); + } + + config + } + + /// Configure the system clock to a specific frequency in Hz, using a custom crystal frequency. + /// + /// This more flexible version allows specifying both the crystal frequency and target + /// system frequency for boards with non-standard crystals. + /// + /// # Arguments + /// + /// * `crystal_hz` - The frequency of the external crystal in Hz + /// * `sys_freq_hz` - The target system clock frequency in Hz + /// + /// # Safety Notes + /// + /// * Frequencies > 133MHz require increased core voltage and are considered overclocking. + /// * Frequencies > 250MHz are extreme overclocking and may not be stable on all chips. + /// + /// # Example + /// + /// ``` + /// // Use a non-standard 16MHz crystal to achieve 250MHz + /// let config = ClockConfig::with_custom_crystal(16_000_000, 250_000_000); + /// ``` + #[cfg(feature = "rp2040")] + pub fn with_custom_crystal(crystal_hz: u32, sys_freq_hz: u32) -> Self { + Self::crystal_freq(crystal_hz, sys_freq_hz) + } + + #[cfg(feature = "rp2040")] + pub fn with_speed_mhz_test_voltage(sys_freq_mhz: u32, voltage: Option) -> Self { + // Create a config with the requested frequency + let sys_freq_hz = sys_freq_mhz * 1_000_000; + let mut config = Self::crystal_freq(12_000_000, sys_freq_hz); + + // Override the voltage setting + config.voltage_scale = voltage; + + // For debugging + // println!("Debug: Setting freq to {}MHz with voltage {:?}", sys_freq_mhz, voltage); + + config + } + + /// Similar to `with_speed_mhz_test_voltage` but with an extended voltage stabilization delay. + /// + /// This function is useful for testing voltage stability issues where the default delay + /// may not be sufficient for the voltage regulator to fully stabilize. + /// + /// # Arguments + /// + /// * `sys_freq_mhz` - The target system clock frequency in MHz + /// * `voltage` - The desired voltage scale setting + /// * `stabilization_delay_us` - Voltage stabilization delay in microseconds (default: 500μs) + #[cfg(feature = "rp2040")] + pub fn with_speed_mhz_test_voltage_extended_delay( + sys_freq_mhz: u32, + voltage: Option, + stabilization_delay_us: Option, + ) -> Self { + // Create a config with the requested frequency + let sys_freq_hz = sys_freq_mhz * 1_000_000; + let mut config = Self::crystal_freq(12_000_000, sys_freq_hz); + + // Override the voltage setting + config.voltage_scale = voltage; + + // Add a custom voltage stabilization delay + config.voltage_stabilization_delay_us = stabilization_delay_us; + + config + } // pub fn bind_gpin(&mut self, gpin: Gpin<'static, P>, hz: u32) { // match P::NR { // 0 => self.gpin0 = Some((hz, gpin.into())), @@ -385,6 +525,7 @@ pub struct XoscConfig { } /// PLL configuration. +#[derive(Clone, Copy, Debug)] pub struct PllConfig { /// Reference divisor. pub refdiv: u8, @@ -542,67 +683,124 @@ pub struct RtcClkConfig { /// Find valid PLL parameters (refdiv, fbdiv, post_div1, post_div2) for a target output frequency /// based on the input frequency. /// +/// Similar to the Pico SDK's parameter selection approach, prioritizing stability. /// See RP2040 Datasheet section 2.16.3. Reference Clock (ref) and 2.18.3. PLL #[cfg(feature = "rp2040")] fn find_pll_params(input_hz: u32, target_hz: u32) -> Option { + // Fixed reference divider for system PLL + const PLL_SYS_REFDIV: u8 = 1; + // Constraints from datasheet: // REFDIV: 1..=63 // FBDIV: 16..=320 // POSTDIV1: 1..=7 // POSTDIV2: 1..=7 (must be <= POSTDIV1) - // VCO frequency (input_hz / refdiv * fbdiv): 400MHz ..= 1600MHz + // VCO frequency (input_hz / refdiv * fbdiv): 750MHz ..= 1800MHz - for refdiv in 1..=63 { - let ref_clk = input_hz / refdiv; - // Reference clock must be >= 5MHz (implied by VCO min / FBDIV max) - if ref_clk < 5_000_000 { + // Calculate reference frequency + let reference_freq = input_hz / PLL_SYS_REFDIV as u32; + + // Start from highest fbdiv for better stability (like SDK does) + for fbdiv in (16..=320).rev() { + let vco_freq = reference_freq * fbdiv; + + // Check VCO frequency is within valid range + if vco_freq < 750_000_000 || vco_freq > 1_800_000_000 { continue; } - for fbdiv in (16..=320).rev() { - // Iterate high fbdiv first for better VCO stability - let vco_freq = ref_clk * fbdiv; - if !(400_000_000..=1_600_000_000).contains(&vco_freq) { - continue; - } + // Try all possible postdiv combinations starting from larger values + // (more conservative/stable approach) + for post_div1 in (1..=7).rev() { + for post_div2 in (1..=post_div1).rev() { + let out_freq = vco_freq / (post_div1 * post_div2) as u32; - // We want vco_freq / (post_div1 * post_div2) = target_hz - // So, post_div1 * post_div2 = vco_freq / target_hz - let target_post_div_product = vco_freq as f64 / target_hz as f64; - if target_post_div_product < 1.0 || target_post_div_product > 49.0 { - // 7*7 = 49 - continue; - } - // Manual rounding: floor(x + 0.5) - let target_post_div_product_int = (target_post_div_product + 0.5) as u32; - if target_post_div_product_int == 0 { - continue; - } - - // Check if the rounded product gives the target frequency - if vco_freq / target_post_div_product_int != target_hz { - continue; - } - - for post_div1 in (1..=7).rev() { - // Iterate high post_div1 first - if target_post_div_product_int % post_div1 == 0 { - let post_div2 = target_post_div_product_int / post_div1; - if (1..=7).contains(&post_div2) && post_div2 <= post_div1 { - // Found a valid combination - return Some(PllConfig { - refdiv: refdiv as u8, // Cast u32 to u8 (safe: 1..=63) - fbdiv: fbdiv as u16, // Cast u32 to u16 (safe: 16..=320) - post_div1: post_div1 as u8, - post_div2: post_div2 as u8, - }); - } + // Check if we get the exact target frequency without remainder + if out_freq == target_hz && (vco_freq % (post_div1 * post_div2) as u32 == 0) { + return Some(PllConfig { + refdiv: PLL_SYS_REFDIV, + fbdiv: fbdiv as u16, + post_div1: post_div1 as u8, + post_div2: post_div2 as u8, + }); } } } } - None // No valid parameters found + // If we couldn't find an exact match, find the closest match + let mut best_config = None; + let mut min_diff = u32::MAX; + + for fbdiv in (16..=320).rev() { + let vco_freq = reference_freq * fbdiv; + + if vco_freq < 750_000_000 || vco_freq > 1_800_000_000 { + continue; + } + + for post_div1 in (1..=7).rev() { + for post_div2 in (1..=post_div1).rev() { + let out_freq = vco_freq / (post_div1 * post_div2) as u32; + let diff = if out_freq > target_hz { + out_freq - target_hz + } else { + target_hz - out_freq + }; + + // If this is closer to the target, save it + if diff < min_diff { + min_diff = diff; + best_config = Some(PllConfig { + refdiv: PLL_SYS_REFDIV, + fbdiv: fbdiv as u16, + post_div1: post_div1 as u8, + post_div2: post_div2 as u8, + }); + } + } + } + } + + // Return the closest match if we found one + best_config +} + +#[cfg(feature = "rp2040")] +pub fn compare_pll_params() { + // Parameters from default configuration + let default_params = PllConfig { + refdiv: 1, + fbdiv: 125, + post_div1: 6, + post_div2: 2, + }; + + // Calculate parameters using our find_pll_params function + let crystal_hz = 12_000_000; + let target_hz = 125_000_000; + let calculated_params = find_pll_params(crystal_hz, target_hz).expect("Failed to find PLL parameters"); + + // Check if they're identical + let params_match = default_params.refdiv == calculated_params.refdiv + && default_params.fbdiv == calculated_params.fbdiv + && default_params.post_div1 == calculated_params.post_div1 + && default_params.post_div2 == calculated_params.post_div2; + + // Here we'd normally print results, but without a console we'll just + // use this for debugging in our IDE + let _default_output_freq = crystal_hz / default_params.refdiv as u32 * default_params.fbdiv as u32 + / (default_params.post_div1 * default_params.post_div2) as u32; + + let _calculated_output_freq = crystal_hz / calculated_params.refdiv as u32 * calculated_params.fbdiv as u32 + / (calculated_params.post_div1 * calculated_params.post_div2) as u32; + + // Parameters: default vs calculated + // refdiv: 1 vs {calculated_params.refdiv} + // fbdiv: 125 vs {calculated_params.fbdiv} + // post_div1: 6 vs {calculated_params.post_div1} + // post_div2: 2 vs {calculated_params.post_div2} + // params_match: {params_match} } /// safety: must be called exactly once at bootup @@ -640,12 +838,42 @@ pub(crate) unsafe fn init(config: ClockConfig) { #[cfg(feature = "_rp235x")] while c.clk_ref_selected().read() != pac::clocks::regs::ClkRefSelected(1) {} - // Reset the PLLs - let mut peris = reset::Peripherals(0); - peris.set_pll_sys(true); - peris.set_pll_usb(true); - reset::reset(peris); - reset::unreset_wait(peris); + // Set Core Voltage (RP2040 only) BEFORE doing anything with PLLs + // This is critical for overclocking - must be done before PLL setup + #[cfg(feature = "rp2040")] + if let Some(voltage) = config.voltage_scale { + let vreg = pac::VREG_AND_CHIP_RESET; + let current_vsel = vreg.vreg().read().vsel(); + let target_vsel = voltage as u8; + + if target_vsel != current_vsel { + // IMPORTANT: Use modify() instead of write() to preserve the HIZ and EN bits + // This is critical - otherwise we might disable the regulator when changing voltage + vreg.vreg().modify(|w| w.set_vsel(target_vsel)); + + // For higher voltage settings (overclocking), we need a longer stabilization time + // Default to 1000 µs (1ms) like the SDK, but allow user override + let settling_time_us = config.voltage_stabilization_delay_us.unwrap_or_else(|| { + match voltage { + VoltageScale::V1_15 => 1000, // 1ms for 1.15V (matches SDK default) + VoltageScale::V1_20 | VoltageScale::V1_25 | VoltageScale::V1_30 => 2000, // 2ms for higher voltages + _ => 500, // 500 µs for standard voltages + } + }); + + // We need a clock that's guaranteed to be running at this point + // Use ROSC which should be configured by now + let rosc_freq_rough = 6_000_000; // Rough ROSC frequency estimate + let cycles_per_us = rosc_freq_rough / 1_000_000; + let delay_cycles = settling_time_us * cycles_per_us; + + // Wait for voltage to stabilize + cortex_m::asm::delay(delay_cycles); + + // Only NOW set the BOD level after voltage has stabilized + vreg.bod().write(|w| w.set_vsel(voltage.recommended_bod())); + } + } // Configure ROSC first if present let rosc_freq = match config.rosc { @@ -654,59 +882,91 @@ pub(crate) unsafe fn init(config: ClockConfig) { }; CLOCKS.rosc.store(rosc_freq, Ordering::Relaxed); - // Configure XOSC and PLLs if present - let (xosc_freq, pll_sys_freq, pll_usb_freq) = match config.xosc { + // Configure XOSC - we'll need this for our temporary stable clock + let xosc_freq = match &config.xosc { Some(config) => { - // start XOSC - // datasheet mentions support for clock inputs into XIN, but doesn't go into - // how this is achieved. pico-sdk doesn't support this at all. start_xosc(config.hz, config.delay_multiplier); - - let pll_sys_freq = match config.sys_pll { - Some(sys_pll_config) => configure_pll(pac::PLL_SYS, config.hz, sys_pll_config), - None => 0, - }; - let pll_usb_freq = match config.usb_pll { - Some(usb_pll_config) => configure_pll(pac::PLL_USB, config.hz, usb_pll_config), - None => 0, - }; - - (config.hz, pll_sys_freq, pll_usb_freq) + config.hz } - None => (0, 0, 0), + None => 0, }; CLOCKS.xosc.store(xosc_freq, Ordering::Relaxed); - CLOCKS.pll_sys.store(pll_sys_freq, Ordering::Relaxed); - CLOCKS.pll_usb.store(pll_usb_freq, Ordering::Relaxed); - // Configure REF clock source and divider - let (ref_src, ref_aux, clk_ref_freq) = { - use {ClkRefCtrlAuxsrc as Aux, ClkRefCtrlSrc as Src}; - let div = config.ref_clk.div as u32; - assert!(div >= 1 && div <= 4); - match config.ref_clk.src { - RefClkSrc::Xosc => (Src::XOSC_CLKSRC, Aux::CLKSRC_PLL_USB, xosc_freq / div), - RefClkSrc::Rosc => (Src::ROSC_CLKSRC_PH, Aux::CLKSRC_PLL_USB, rosc_freq / div), - RefClkSrc::PllUsb => (Src::CLKSRC_CLK_REF_AUX, Aux::CLKSRC_PLL_USB, pll_usb_freq / div), - // RefClkSrc::Gpin0 => (Src::CLKSRC_CLK_REF_AUX, Aux::CLKSRC_GPIN0, gpin0_freq / div), - // RefClkSrc::Gpin1 => (Src::CLKSRC_CLK_REF_AUX, Aux::CLKSRC_GPIN1, gpin1_freq / div), - } + // SETUP TEMPORARY STABLE CLOCKS FIRST + // Configure USB PLL for our stable temporary clock + // This follows the SDK's approach of using USB PLL as a stable intermediate clock + let usb_pll_freq = match &config.xosc { + Some(config) => match &config.usb_pll { + Some(usb_pll_config) => { + // Reset USB PLL + let mut peris = reset::Peripherals(0); + peris.set_pll_usb(true); + reset::reset(peris); + reset::unreset_wait(peris); + + // Configure the USB PLL - this should give us 48MHz + let usb_pll_freq = configure_pll(pac::PLL_USB, xosc_freq, *usb_pll_config); + CLOCKS.pll_usb.store(usb_pll_freq, Ordering::Relaxed); + usb_pll_freq + } + None => 0, + }, + None => 0, }; - assert!(clk_ref_freq != 0); - CLOCKS.reference.store(clk_ref_freq, Ordering::Relaxed); + + // Configure REF clock to use XOSC c.clk_ref_ctrl().write(|w| { - w.set_src(ref_src); - w.set_auxsrc(ref_aux); + w.set_src(ClkRefCtrlSrc::XOSC_CLKSRC); }); #[cfg(feature = "rp2040")] - while c.clk_ref_selected().read() != (1 << ref_src as u32) {} + while c.clk_ref_selected().read() != (1 << ClkRefCtrlSrc::XOSC_CLKSRC as u32) {} #[cfg(feature = "_rp235x")] - while c.clk_ref_selected().read() != pac::clocks::regs::ClkRefSelected(1 << ref_src as u32) {} - c.clk_ref_div().write(|w| { - w.set_int(config.ref_clk.div); + while c.clk_ref_selected().read() != pac::clocks::regs::ClkRefSelected(1 << ClkRefCtrlSrc::XOSC_CLKSRC as u32) {} + + // First switch the system clock to a stable source (USB PLL at 48MHz) + // This follows the Pico SDK's approach to ensure stability during reconfiguration + c.clk_sys_ctrl().write(|w| { + w.set_auxsrc(ClkSysCtrlAuxsrc::CLKSRC_PLL_USB); + w.set_src(ClkSysCtrlSrc::CLKSRC_CLK_SYS_AUX); }); + #[cfg(feature = "rp2040")] + while c.clk_sys_selected().read() != (1 << ClkSysCtrlSrc::CLKSRC_CLK_SYS_AUX as u32) {} + #[cfg(feature = "_rp235x")] + while c.clk_sys_selected().read() + != pac::clocks::regs::ClkSysSelected(1 << ClkSysCtrlSrc::CLKSRC_CLK_SYS_AUX as u32) + {} + + // Short delay after switching to USB PLL to ensure stability + cortex_m::asm::delay(100); + + // NOW CONFIGURE THE SYSTEM PLL (safely, since we're running from the USB PLL) + let pll_sys_freq = match &config.xosc { + Some(config) => match &config.sys_pll { + Some(sys_pll_config) => { + // Reset SYS PLL + let mut peris = reset::Peripherals(0); + peris.set_pll_sys(true); + reset::reset(peris); + reset::unreset_wait(peris); + + // Configure the SYS PLL + let pll_sys_freq = configure_pll(pac::PLL_SYS, xosc_freq, *sys_pll_config); + + // Ensure PLL is locked and stable + cortex_m::asm::delay(100); + + CLOCKS.pll_sys.store(pll_sys_freq, Ordering::Relaxed); + pll_sys_freq + } + None => 0, + }, + None => 0, + }; + // Configure tick generation using REF clock + let clk_ref_freq = xosc_freq; // REF clock is now XOSC + CLOCKS.reference.store(clk_ref_freq, Ordering::Relaxed); #[cfg(feature = "rp2040")] pac::WATCHDOG.tick().write(|w| { w.set_cycles((clk_ref_freq / 1_000_000) as u16); @@ -724,34 +984,14 @@ pub(crate) unsafe fn init(config: ClockConfig) { pac::TICKS.watchdog_ctrl().write(|w| w.set_enable(true)); } - // Set Core Voltage (RP2040 only) BEFORE switching SYS clock to high speed PLL - #[cfg(feature = "rp2040")] - if let Some(voltage) = config.voltage_scale { - let vreg = pac::VREG_AND_CHIP_RESET; - let current_vsel = vreg.vreg().read().vsel(); - let target_vsel = voltage as u8; - - if target_vsel != current_vsel { - // Set voltage and recommended BOD level - vreg.bod().write(|w| w.set_vsel(voltage.recommended_bod())); - vreg.vreg().write(|w| w.set_vsel(target_vsel)); - - // Wait 10us for regulator to settle. Delay calculation uses REF clock - // as it's guaranteed to be stable here, before SYS potentially switches. - // 10 us = 1/100_000 s. cycles = freq * time. - let delay_cycles = clk_ref_freq / 100_000; - // delay(N) waits N+1 cycles. - cortex_m::asm::delay(delay_cycles.saturating_sub(1)); - } - } - - // Configure SYS clock source and divider + // NOW SWITCH THE SYSTEM CLOCK TO THE CONFIGURED SOURCE + // The SYS PLL is now stable and we can safely switch to it let (sys_src, sys_aux, clk_sys_freq) = { use {ClkSysCtrlAuxsrc as Aux, ClkSysCtrlSrc as Src}; let (src, aux, freq) = match config.sys_clk.src { SysClkSrc::Ref => (Src::CLK_REF, Aux::CLKSRC_PLL_SYS, clk_ref_freq), SysClkSrc::PllSys => (Src::CLKSRC_CLK_SYS_AUX, Aux::CLKSRC_PLL_SYS, pll_sys_freq), - SysClkSrc::PllUsb => (Src::CLKSRC_CLK_SYS_AUX, Aux::CLKSRC_PLL_USB, pll_usb_freq), + SysClkSrc::PllUsb => (Src::CLKSRC_CLK_SYS_AUX, Aux::CLKSRC_PLL_USB, usb_pll_freq), SysClkSrc::Rosc => (Src::CLKSRC_CLK_SYS_AUX, Aux::ROSC_CLKSRC, rosc_freq), SysClkSrc::Xosc => (Src::CLKSRC_CLK_SYS_AUX, Aux::XOSC_CLKSRC, xosc_freq), // SysClkSrc::Gpin0 => (Src::CLKSRC_CLK_SYS_AUX, Aux::CLKSRC_GPIN0, gpin0_freq), @@ -762,28 +1002,48 @@ pub(crate) unsafe fn init(config: ClockConfig) { }; assert!(clk_sys_freq != 0); CLOCKS.sys.store(clk_sys_freq, Ordering::Relaxed); - if sys_src != ClkSysCtrlSrc::CLK_REF { - c.clk_sys_ctrl().write(|w| w.set_src(ClkSysCtrlSrc::CLK_REF)); - #[cfg(feature = "rp2040")] - while c.clk_sys_selected().read() != (1 << ClkSysCtrlSrc::CLK_REF as u32) {} - #[cfg(feature = "_rp235x")] - while c.clk_sys_selected().read() != pac::clocks::regs::ClkSysSelected(1 << ClkSysCtrlSrc::CLK_REF as u32) {} + + // Set the divider before changing the source if it's increasing + if config.sys_clk.div_int > 1 || config.sys_clk.div_frac > 0 { + c.clk_sys_div().write(|w| { + w.set_int(config.sys_clk.div_int); + w.set_frac(config.sys_clk.div_frac); + }); } + + // Configure aux source first if needed + if sys_src == ClkSysCtrlSrc::CLKSRC_CLK_SYS_AUX { + c.clk_sys_ctrl().modify(|w| { + w.set_auxsrc(sys_aux); + }); + } + + // Now set the source c.clk_sys_ctrl().write(|w| { - w.set_auxsrc(sys_aux); + if sys_src == ClkSysCtrlSrc::CLKSRC_CLK_SYS_AUX { + w.set_auxsrc(sys_aux); + } w.set_src(sys_src); }); + // Wait for the clock to be selected #[cfg(feature = "rp2040")] while c.clk_sys_selected().read() != (1 << sys_src as u32) {} #[cfg(feature = "_rp235x")] while c.clk_sys_selected().read() != pac::clocks::regs::ClkSysSelected(1 << sys_src as u32) {} - c.clk_sys_div().write(|w| { - w.set_int(config.sys_clk.div_int); - w.set_frac(config.sys_clk.div_frac); - }); + // Short delay after final clock switch to ensure stability + cortex_m::asm::delay(100); + // Set the divider after changing the source if it's decreasing + if config.sys_clk.div_int == 1 && config.sys_clk.div_frac == 0 { + c.clk_sys_div().write(|w| { + w.set_int(config.sys_clk.div_int); + w.set_frac(config.sys_clk.div_frac); + }); + } + + // CONFIGURE PERIPHERAL CLOCK let mut peris = reset::ALL_PERIPHERALS; if let Some(src) = config.peri_clk_src { @@ -794,7 +1054,7 @@ pub(crate) unsafe fn init(config: ClockConfig) { let peri_freq = match src { PeriClkSrc::Sys => clk_sys_freq, PeriClkSrc::PllSys => pll_sys_freq, - PeriClkSrc::PllUsb => pll_usb_freq, + PeriClkSrc::PllUsb => usb_pll_freq, PeriClkSrc::Rosc => rosc_freq, PeriClkSrc::Xosc => xosc_freq, // PeriClkSrc::Gpin0 => gpin0_freq, @@ -810,6 +1070,7 @@ pub(crate) unsafe fn init(config: ClockConfig) { CLOCKS.peri.store(0, Ordering::Relaxed); } + // CONFIGURE USB CLOCK if let Some(conf) = config.usb_clk { c.clk_usb_div().write(|w| w.set_int(conf.div)); c.clk_usb_ctrl().write(|w| { @@ -818,7 +1079,7 @@ pub(crate) unsafe fn init(config: ClockConfig) { w.set_auxsrc(ClkUsbCtrlAuxsrc::from_bits(conf.src as _)); }); let usb_freq = match conf.src { - UsbClkSrc::PllUsb => pll_usb_freq, + UsbClkSrc::PllUsb => usb_pll_freq, UsbClkSrc::PllSys => pll_sys_freq, UsbClkSrc::Rosc => rosc_freq, UsbClkSrc::Xosc => xosc_freq, @@ -833,6 +1094,7 @@ pub(crate) unsafe fn init(config: ClockConfig) { CLOCKS.usb.store(0, Ordering::Relaxed); } + // CONFIGURE ADC CLOCK if let Some(conf) = config.adc_clk { c.clk_adc_div().write(|w| w.set_int(conf.div)); c.clk_adc_ctrl().write(|w| { @@ -841,7 +1103,7 @@ pub(crate) unsafe fn init(config: ClockConfig) { w.set_auxsrc(ClkAdcCtrlAuxsrc::from_bits(conf.src as _)); }); let adc_in_freq = match conf.src { - AdcClkSrc::PllUsb => pll_usb_freq, + AdcClkSrc::PllUsb => usb_pll_freq, AdcClkSrc::PllSys => pll_sys_freq, AdcClkSrc::Rosc => rosc_freq, AdcClkSrc::Xosc => xosc_freq, @@ -856,7 +1118,7 @@ pub(crate) unsafe fn init(config: ClockConfig) { CLOCKS.adc.store(0, Ordering::Relaxed); } - // rp2040 specific clocks + // CONFIGURE RTC CLOCK #[cfg(feature = "rp2040")] if let Some(conf) = config.rtc_clk { c.clk_rtc_div().write(|w| { @@ -869,7 +1131,7 @@ pub(crate) unsafe fn init(config: ClockConfig) { w.set_auxsrc(ClkRtcCtrlAuxsrc::from_bits(conf.src as _)); }); let rtc_in_freq = match conf.src { - RtcClkSrc::PllUsb => pll_usb_freq, + RtcClkSrc::PllUsb => usb_pll_freq, RtcClkSrc::PllSys => pll_sys_freq, RtcClkSrc::Rosc => rosc_freq, RtcClkSrc::Xosc => xosc_freq, @@ -999,43 +1261,101 @@ fn start_xosc(crystal_hz: u32, delay_multiplier: u32) { #[inline(always)] fn configure_pll(p: pac::pll::Pll, input_freq: u32, config: PllConfig) -> u32 { + // Calculate reference frequency let ref_freq = input_freq / config.refdiv as u32; - assert!(config.fbdiv >= 16 && config.fbdiv <= 320); - assert!(config.post_div1 >= 1 && config.post_div1 <= 7); - assert!(config.post_div2 >= 1 && config.post_div2 <= 7); - assert!(config.refdiv >= 1 && config.refdiv <= 63); - assert!(ref_freq >= 5_000_000 && ref_freq <= 800_000_000); + + // Validate PLL parameters + assert!( + config.fbdiv >= 16 && config.fbdiv <= 320, + "fbdiv must be between 16 and 320" + ); + assert!( + config.post_div1 >= 1 && config.post_div1 <= 7, + "post_div1 must be between 1 and 7" + ); + assert!( + config.post_div2 >= 1 && config.post_div2 <= 7, + "post_div2 must be between 1 and 7" + ); + assert!(config.post_div2 <= config.post_div1, "post_div2 must be <= post_div1"); + assert!( + config.refdiv >= 1 && config.refdiv <= 63, + "refdiv must be between 1 and 63" + ); + assert!( + ref_freq >= 5_000_000 && ref_freq <= 800_000_000, + "ref_freq must be between 5MHz and 800MHz" + ); + + // Calculate VCO frequency let vco_freq = ref_freq.saturating_mul(config.fbdiv as u32); - assert!(vco_freq >= 750_000_000 && vco_freq <= 1_800_000_000); + assert!( + vco_freq >= 750_000_000 && vco_freq <= 1_800_000_000, + "VCO frequency must be between 750MHz and 1800MHz" + ); - // Load VCO-related dividers before starting VCO - p.cs().write(|w| w.set_refdiv(config.refdiv as _)); - p.fbdiv_int().write(|w| w.set_fbdiv_int(config.fbdiv)); + // We follow the SDK's approach to PLL configuration which is: + // 1. Power down PLL + // 2. Configure the reference divider + // 3. Configure the feedback divider + // 4. Power up PLL and VCO + // 5. Wait for PLL to lock + // 6. Configure post-dividers + // 7. Enable post-divider output - // Turn on PLL - let pwr = p.pwr().write(|w| { - w.set_dsmpd(true); // "nothing is achieved by setting this low" - w.set_pd(false); - w.set_vcopd(false); - w.set_postdivpd(true); + // 1. Power down PLL before configuration + p.pwr().write(|w| { + w.set_pd(true); // Power down the PLL + w.set_vcopd(true); // Power down the VCO + w.set_postdivpd(true); // Power down the post divider + w.set_dsmpd(true); // Disable fractional mode *w }); - // Wait for PLL to lock - while !p.cs().read().lock() {} + // Short delay after powering down + cortex_m::asm::delay(10); - // Set post-dividers + // 2. Configure reference divider first + p.cs().write(|w| w.set_refdiv(config.refdiv as _)); + + // 3. Configure feedback divider + p.fbdiv_int().write(|w| w.set_fbdiv_int(config.fbdiv)); + + // 4. Power up PLL and VCO, but keep post divider powered down during initial lock + p.pwr().write(|w| { + w.set_pd(false); // Power up the PLL + w.set_vcopd(false); // Power up the VCO + w.set_postdivpd(true); // Keep post divider powered down during initial lock + w.set_dsmpd(true); // Disable fractional mode (simpler configuration) + *w + }); + + // 5. Wait for PLL to lock with a timeout + let mut timeout = 1_000_000; // Reasonable timeout value + while !p.cs().read().lock() { + timeout -= 1; + if timeout == 0 { + // PLL failed to lock, return 0 to indicate failure + return 0; + } + } + + // 6. Configure post dividers after PLL is locked p.prim().write(|w| { w.set_postdiv1(config.post_div1); w.set_postdiv2(config.post_div2); }); - // Turn on post divider - p.pwr().write(|w| { - *w = pwr; - w.set_postdivpd(false); + // 7. Enable the post divider output + p.pwr().modify(|w| { + w.set_postdivpd(false); // Power up post divider + *w }); + // Final delay to ensure everything is stable + cortex_m::asm::delay(100); + + // Calculate and return actual output frequency vco_freq / ((config.post_div1 * config.post_div2) as u32) } diff --git a/examples/rp/src/bin/overclock.rs b/examples/rp/src/bin/overclock.rs index 429fff1ac..db6c8f448 100644 --- a/examples/rp/src/bin/overclock.rs +++ b/examples/rp/src/bin/overclock.rs @@ -3,22 +3,18 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_rp::clocks::{clk_sys_freq, ClockConfig}; +use embassy_rp::clocks::{clk_sys_freq, ClockConfig, VoltageScale}; use embassy_rp::config::Config; use embassy_rp::gpio::{Level, Output}; use embassy_time::{Duration, Instant, Timer}; use {defmt_rtt as _, panic_probe as _}; -const COUNT_TO: i32 = 1_000_000; +const COUNT_TO: i64 = 10_000_000; #[embassy_executor::main] async fn main(_spawner: Spawner) -> ! { // Set up for clock frequency of 200 MHz - // We will need a clock config in the HAL config that supports this frequency - // The RP2040 can run at 200 MHz with a 12 MHz crystal - let config = Config::new(ClockConfig::crystal_freq(12_000_000, 200_000_000)); - - // Initialize the peripherals + let config = Config::new(ClockConfig::with_speed_mhz(200)); let p = embassy_rp::init(config); // Show CPU frequency for verification @@ -37,20 +33,19 @@ async fn main(_spawner: Spawner) -> ! { let start = Instant::now(); - // Count to COUNT_TO // This is a busy loop that will take some time to complete while counter < COUNT_TO { counter += 1; } - let elapsed = start - Instant::now(); + let elapsed = Instant::now() - start; // Report the elapsed time led.set_low(); info!( "At {}Mhz: Elapsed time to count to {}: {}ms", sys_freq / 1_000_000, - COUNT_TO, + counter, elapsed.as_millis() ); @@ -58,3 +53,14 @@ async fn main(_spawner: Spawner) -> ! { Timer::after(Duration::from_secs(2)).await; } } + +// let config = Config::new(ClockConfig::with_speed_mhz_test_voltage(125, Some(VoltageScale::V1_10))); +// let config = Config::default(); +// let config = Config::new(ClockConfig::with_speed_mhz_test_voltage_extended_delay( +// 200, // Standard 125MHz clock +// Some(VoltageScale::V1_15), // 1.15V voltage +// Some(1000), // 1000μs (1ms) stabilization delay - significantly longer than default +// )); +// Initialize the peripherals + +// let p = embassy_rp::init(Default::default()); //testing the bog standard From b967aaf7cc90e1e8810f24968ba137141b0c35ec Mon Sep 17 00:00:00 2001 From: Dion Dokter Date: Tue, 29 Apr 2025 16:34:12 +0200 Subject: [PATCH 1026/1217] Add support for g0 --- embassy-stm32/src/flash/g.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/embassy-stm32/src/flash/g.rs b/embassy-stm32/src/flash/g.rs index f55c5e6a7..70e472dcf 100644 --- a/embassy-stm32/src/flash/g.rs +++ b/embassy-stm32/src/flash/g.rs @@ -110,7 +110,7 @@ fn wait_busy() { while pac::FLASH.sr().read().bsy() {} } -#[cfg(bank_setup_configurable)] +#[cfg(all(bank_setup_configurable, any(flash_g4c2, flash_g4c3, flash_g4c4)))] pub(crate) fn check_bank_setup() { if cfg!(feature = "single-bank") && pac::FLASH.optr().read().dbank() { panic!("Embassy is configured as single-bank, but the hardware is running in dual-bank mode. Change the hardware by changing the dbank value in the user option bytes or configure embassy to use dual-bank config"); @@ -119,3 +119,13 @@ pub(crate) fn check_bank_setup() { panic!("Embassy is configured as dual-bank, but the hardware is running in single-bank mode. Change the hardware by changing the dbank value in the user option bytes or configure embassy to use single-bank config"); } } + +#[cfg(all(bank_setup_configurable, flash_g0x1))] +pub(crate) fn check_bank_setup() { + if cfg!(feature = "single-bank") && pac::FLASH.optr().read().dual_bank() { + panic!("Embassy is configured as single-bank, but the hardware is running in dual-bank mode. Change the hardware by changing the dual_bank value in the user option bytes or configure embassy to use dual-bank config"); + } + if cfg!(feature = "dual-bank") && !pac::FLASH.optr().read().dual_bank() { + panic!("Embassy is configured as dual-bank, but the hardware is running in single-bank mode. Change the hardware by changing the dual_bank value in the user option bytes or configure embassy to use single-bank config"); + } +} From 1c2208718863dc0ed23449393c0213c8f9194519 Mon Sep 17 00:00:00 2001 From: Dion Dokter Date: Tue, 29 Apr 2025 16:37:27 +0200 Subject: [PATCH 1027/1217] Add support for L5 --- embassy-stm32/src/flash/l.rs | 10 ++++++++++ examples/stm32l5/Cargo.toml | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/embassy-stm32/src/flash/l.rs b/embassy-stm32/src/flash/l.rs index ea00bf499..bc6f8c873 100644 --- a/embassy-stm32/src/flash/l.rs +++ b/embassy-stm32/src/flash/l.rs @@ -238,3 +238,13 @@ unsafe fn wait_ready_blocking() -> Result<(), Error> { } } } + +#[cfg(all(bank_setup_configurable, flash_l5))] +pub(crate) fn check_bank_setup() { + if cfg!(feature = "single-bank") && pac::FLASH.optr().read().dbank() { + panic!("Embassy is configured as single-bank, but the hardware is running in dual-bank mode. Change the hardware by changing the dbank value in the user option bytes or configure embassy to use dual-bank config"); + } + if cfg!(feature = "dual-bank") && !pac::FLASH.optr().read().dbank() { + panic!("Embassy is configured as dual-bank, but the hardware is running in single-bank mode. Change the hardware by changing the dbank value in the user option bytes or configure embassy to use single-bank config"); + } +} diff --git a/examples/stm32l5/Cargo.toml b/examples/stm32l5/Cargo.toml index fbf68c890..4c372a554 100644 --- a/examples/stm32l5/Cargo.toml +++ b/examples/stm32l5/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32l552ze to your chip name, if necessary. -embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32l552ze", "time-driver-any", "exti", "memory-x", "low-power"] } +embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32l552ze", "time-driver-any", "exti", "memory-x", "low-power", "dual-bank"] } embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } From 5691c61ef9a128c84f5f5962ed736a3a757371c1 Mon Sep 17 00:00:00 2001 From: Dion Dokter Date: Tue, 29 Apr 2025 16:55:11 +0200 Subject: [PATCH 1028/1217] Add F4 support --- embassy-stm32/build.rs | 12 ++++-------- embassy-stm32/src/flash/f4.rs | 10 ++++++++++ 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 2a3213c0c..946aa0399 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -56,17 +56,13 @@ fn main() { let dual_bank_selected = env::var("CARGO_FEATURE_DUAL_BANK").is_ok(); let single_bank_memory = METADATA.memory.iter().find(|mem| { - mem.iter() - .filter(|region| region.kind == MemoryRegionKind::Flash) - .count() - == 1 + mem.iter().any(|region| region.name.contains("BANK_1")) + && !mem.iter().any(|region| region.name.contains("BANK_2")) }); let dual_bank_memory = METADATA.memory.iter().find(|mem| { - mem.iter() - .filter(|region| region.kind == MemoryRegionKind::Flash) - .count() - == 2 + mem.iter().any(|region| region.name.contains("BANK_1")) + && mem.iter().any(|region| region.name.contains("BANK_2")) }); cfgs.set( diff --git a/embassy-stm32/src/flash/f4.rs b/embassy-stm32/src/flash/f4.rs index 687eabaeb..ba3067556 100644 --- a/embassy-stm32/src/flash/f4.rs +++ b/embassy-stm32/src/flash/f4.rs @@ -555,3 +555,13 @@ mod tests { assert_sector(0x17, FlashBank::Bank2, 7, 0x080E_0000, LARGE_SECTOR_SIZE, 0x080F_FFFF); } } + +#[cfg(all(bank_setup_configurable))] +pub(crate) fn check_bank_setup() { + if cfg!(feature = "single-bank") && pac::FLASH.optcr().read().db1m() { + panic!("Embassy is configured as single-bank, but the hardware is running in dual-bank mode. Change the hardware by changing the db1m value in the user option bytes or configure embassy to use dual-bank config"); + } + if cfg!(feature = "dual-bank") && !pac::FLASH.optcr().read().db1m() { + panic!("Embassy is configured as dual-bank, but the hardware is running in single-bank mode. Change the hardware by changing the db1m value in the user option bytes or configure embassy to use single-bank config"); + } +} From a1081f29bfa0bc0940b55d7d249d9cb76c2d2e23 Mon Sep 17 00:00:00 2001 From: Dion Dokter Date: Tue, 29 Apr 2025 16:59:04 +0200 Subject: [PATCH 1029/1217] Add f7 support --- embassy-stm32/src/flash/f7.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/embassy-stm32/src/flash/f7.rs b/embassy-stm32/src/flash/f7.rs index 09ebe9db9..043382590 100644 --- a/embassy-stm32/src/flash/f7.rs +++ b/embassy-stm32/src/flash/f7.rs @@ -169,3 +169,13 @@ mod tests { assert_sector(7, 0x080C_0000, LARGE_SECTOR_SIZE, 0x080F_FFFF); } } + +#[cfg(all(bank_setup_configurable))] +pub(crate) fn check_bank_setup() { + if cfg!(feature = "single-bank") && !pac::FLASH.optcr().read().n_dbank() { + panic!("Embassy is configured as single-bank, but the hardware is running in dual-bank mode. Change the hardware by changing the ndbank value in the user option bytes or configure embassy to use dual-bank config"); + } + if cfg!(feature = "dual-bank") && pac::FLASH.optcr().read().n_dbank() { + panic!("Embassy is configured as dual-bank, but the hardware is running in single-bank mode. Change the hardware by changing the ndbank value in the user option bytes or configure embassy to use single-bank config"); + } +} From 34a4dddfe79e55057c2ce87ee60b1c6b93c5ac76 Mon Sep 17 00:00:00 2001 From: Dion Dokter Date: Tue, 29 Apr 2025 17:05:07 +0200 Subject: [PATCH 1030/1217] Add L4+ support --- embassy-stm32/src/flash/l.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/embassy-stm32/src/flash/l.rs b/embassy-stm32/src/flash/l.rs index bc6f8c873..3b62fa2ee 100644 --- a/embassy-stm32/src/flash/l.rs +++ b/embassy-stm32/src/flash/l.rs @@ -248,3 +248,13 @@ pub(crate) fn check_bank_setup() { panic!("Embassy is configured as dual-bank, but the hardware is running in single-bank mode. Change the hardware by changing the dbank value in the user option bytes or configure embassy to use single-bank config"); } } + +#[cfg(all(bank_setup_configurable, flash_l4))] +pub(crate) fn check_bank_setup() { + if cfg!(feature = "single-bank") && pac::FLASH.optr().read().dualbank() { + panic!("Embassy is configured as single-bank, but the hardware is running in dual-bank mode. Change the hardware by changing the dualbank value in the user option bytes or configure embassy to use dual-bank config"); + } + if cfg!(feature = "dual-bank") && !pac::FLASH.optr().read().dualbank() { + panic!("Embassy is configured as dual-bank, but the hardware is running in single-bank mode. Change the hardware by changing the dualbank value in the user option bytes or configure embassy to use single-bank config"); + } +} From c84d8e36323ccc7b12782ae2f7644e49b1074978 Mon Sep 17 00:00:00 2001 From: Dion Dokter Date: Tue, 29 Apr 2025 17:07:02 +0200 Subject: [PATCH 1031/1217] Update changelog --- embassy-stm32/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/CHANGELOG.md b/embassy-stm32/CHANGELOG.md index 7b7d559e2..b6781905e 100644 --- a/embassy-stm32/CHANGELOG.md +++ b/embassy-stm32/CHANGELOG.md @@ -7,7 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased - Modify BufferedUart initialization to take pins before interrupts ([#3983](https://github.com/embassy-rs/embassy/pull/3983)) -- Added a 'single-bank' and a 'dual-bank' feature so chips with configurable flash bank setups can be supported in embassy. The G4 series now supports this. ([#4125](https://github.com/embassy-rs/embassy/pull/4125)) +- Added a 'single-bank' and a 'dual-bank' feature so chips with configurable flash bank setups are be supported in embassy ([#4125](https://github.com/embassy-rs/embassy/pull/4125)) ## 0.2.0 - 2025-01-10 From fb7504c2930a3f177a33f1dcc736da0d548d6e97 Mon Sep 17 00:00:00 2001 From: Alex Moon Date: Tue, 29 Apr 2025 11:07:58 -0400 Subject: [PATCH 1032/1217] Add docs --- embassy-nrf/src/twim.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/embassy-nrf/src/twim.rs b/embassy-nrf/src/twim.rs index 95b24c616..3d5e841d1 100644 --- a/embassy-nrf/src/twim.rs +++ b/embassy-nrf/src/twim.rs @@ -119,6 +119,12 @@ pub struct Twim<'d, T: Instance> { impl<'d, T: Instance> Twim<'d, T> { /// Create a new TWI driver. + /// + /// `tx_ram_buffer` is required if any write operations will be performed with data that is not in RAM. + /// Usually this is static data that the compiler locates in flash instead of RAM. The `tx_ram_buffer` + /// needs to be at least as large as the largest write operation that will be executed with a buffer + /// that is not in RAM. If all write operations will be performed from RAM, an empty buffer (`&[]`) may + /// be used. pub fn new( twim: Peri<'d, T>, _irq: impl interrupt::typelevel::Binding> + 'd, From ae59d0acf4f7c7be028b1246aaa8033015985154 Mon Sep 17 00:00:00 2001 From: Dion Dokter Date: Tue, 29 Apr 2025 17:13:43 +0200 Subject: [PATCH 1033/1217] Use generated metapac instead of local one --- embassy-stm32/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index afef5d72f..5ed5c3519 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -74,7 +74,7 @@ sdio-host = "0.9.0" critical-section = "1.1" #stm32-metapac = { version = "16" } # stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-380f03cb71f43a242adc45e83607a380ffe0447b" } -stm32-metapac = { path = "R:/stm32-data/build/stm32-metapac" } +stm32-metapac = { git="https://ci.embassy.dev/jobs/039aa6808ef1/artifacts/generated.git" } vcell = "0.1.3" nb = "1.0.0" @@ -104,7 +104,7 @@ quote = "1.0.15" #stm32-metapac = { version = "16", default-features = false, features = ["metadata"]} # stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-380f03cb71f43a242adc45e83607a380ffe0447b", default-features = false, features = ["metadata"] } -stm32-metapac = { path = "R:/stm32-data/build/stm32-metapac", default-features = false, features = ["metadata"] } +stm32-metapac = { git="https://ci.embassy.dev/jobs/039aa6808ef1/artifacts/generated.git", default-features = false, features = ["metadata"] } [features] default = ["rt"] From 77e8bc9b28d6988b2703029679f290b351fc54a0 Mon Sep 17 00:00:00 2001 From: 1-rafael-1 Date: Tue, 29 Apr 2025 22:49:05 +0200 Subject: [PATCH 1034/1217] refactoring to have higher and lower level api --- embassy-rp/sdk examples | 1 + embassy-rp/src/clocks.rs | 546 +++++++++++++++++++------------ examples/rp/src/bin/overclock.rs | 13 +- 3 files changed, 352 insertions(+), 208 deletions(-) create mode 160000 embassy-rp/sdk examples diff --git a/embassy-rp/sdk examples b/embassy-rp/sdk examples new file mode 160000 index 000000000..ee68c78d0 --- /dev/null +++ b/embassy-rp/sdk examples @@ -0,0 +1 @@ +Subproject commit ee68c78d0afae2b69c03ae1a72bf5cc267a2d94c diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs index b74e90f5e..1f5c27df1 100644 --- a/embassy-rp/src/clocks.rs +++ b/embassy-rp/src/clocks.rs @@ -1,4 +1,78 @@ -//! Clock configuration for the RP2040 +//! # Clock configuration for the RP2040 and RP235x microcontrollers. +//! +//! # Clock Configuration API +//! +//! This module provides both high-level convenience functions and low-level manual +//! configuration options for the RP2040 clock system. +//! +//! ## High-Level Convenience Functions +//! +//! For most users, these functions provide an easy way to configure clocks: +//! +//! - `ClockConfig::crystal(12_000_000)` - Default configuration with 12MHz crystal giving 125MHz system clock +//! - `ClockConfig::at_sys_frequency_mhz(200)` - Set system clock to a specific frequency with automatic voltage scaling +//! - `ClockConfig::with_external_crystal(16_000_000)` - Configure with a non-standard crystal frequency +//! +//! ## Manual Configuration +//! +//! For advanced users who need precise control: +//! +//! ```rust,ignore +//! // Start with default configuration and customize it +//! let mut config = ClockConfig::default(); +//! +//! // Set custom PLL parameters +//! config.xosc = Some(XoscConfig { +//! hz: 12_000_000, +//! sys_pll: Some(PllConfig { +//! refdiv: 1, +//! fbdiv: 200, +//! post_div1: 6, +//! post_div2: 2, +//! }), +//! // ... other fields +//! }); +//! +//! // Set voltage for overclocking +//! config.voltage_scale = Some(VoltageScale::V1_15); +//! ``` +//! +//! ## Voltage Scaling for Overclocking (RP2040 only) +//! +//! When overclocking beyond 133MHz, higher core voltages are needed: +//! +//! - Up to 133MHz: `VoltageScale::V1_10` (default) +//! - 133-200MHz: `VoltageScale::V1_15` +//! - Above 200MHz: `VoltageScale::V1_20` or higher +//! +//! The `at_sys_frequency_mhz()` function automatically sets appropriate voltages. +//! +//! ## Examples +//! +//! ### Standard 125MHz configuration +//! ```rust,ignore +//! let config = ClockConfig::crystal(12_000_000); +//! ``` +//! +//! Or using the default configuration: +//! ```rust,ignore +//! let config = ClockConfig::default(); +//! ``` +//! +//! ### Overclock to 200MHz +//! ```rust,ignore +//! let config = ClockConfig::at_sys_frequency_mhz(200); +//! ``` +//! +//! ### Manual configuration for advanced scenarios +//! ```rust,ignore +//! use embassy_rp::clocks::{ClockConfig, XoscConfig, PllConfig, VoltageScale}; +//! +//! // Start with defaults and customize +//! let mut config = ClockConfig::default(); +//! config.voltage_scale = Some(VoltageScale::V1_15); +//! // Set other parameters as needed... +//! ``` #[cfg(feature = "rp2040")] use core::arch::asm; @@ -18,6 +92,7 @@ use crate::{pac, reset, Peri}; // gpin is not usually safe to use during the boot init() call, so it won't // be very useful until we have runtime clock reconfiguration. once this // happens we can resurrect the commented-out gpin bits. + struct Clocks { xosc: AtomicU32, sys: AtomicU32, @@ -70,30 +145,58 @@ pub enum PeriClkSrc { } /// Core voltage scaling options for RP2040. -/// See RP2040 Datasheet, Table 189, VREG Register. +/// +/// The RP2040 voltage regulator can be configured for different output voltages. +/// Higher voltages allow for higher clock frequencies but increase power consumption. +/// +/// # Typical Use Cases +/// +/// - `V0_85` to `V1_05`: Power saving for lower frequencies (below 100MHz) +/// - `V1_10`: Default voltage, safe for standard 125MHz operation +/// - `V1_15`: Required for frequencies above 133MHz (e.g., 200MHz overclocking) +/// - `V1_20`: For more extreme overclocking (200MHz+) +/// - `V1_25` and `V1_30`: Highest voltage settings, use with caution +/// +/// # Overclocking Notes +/// +/// When overclocking: +/// - Frequencies up to 133MHz are typically stable at default voltage (`V1_10`) +/// - Frequencies from 133MHz to 200MHz generally require `V1_15` +/// - Frequencies above 200MHz typically require `V1_20` or higher +/// +/// # Power Consumption +/// +/// Higher voltages increase power consumption and heat generation. In battery-powered +/// applications, consider using lower voltages when maximum performance is not required. +/// +/// # Safety +/// +/// Increased voltage can reduce the lifespan of the chip if used for extended periods, +/// especially at `V1_25` and `V1_30`. These higher voltages should be used with +/// consideration of thermal management. #[cfg(feature = "rp2040")] #[derive(Clone, Copy, Debug, PartialEq, Eq)] #[repr(u8)] pub enum VoltageScale { - /// 0.85V + /// 0.85V - Lowest power consumption, suitable for low frequencies V0_85 = 0b0110, - /// 0.90V + /// 0.90V - Low power consumption V0_90 = 0b0111, - /// 0.95V + /// 0.95V - Low power consumption V0_95 = 0b1000, - /// 1.00V + /// 1.00V - Medium power consumption V1_00 = 0b1001, - /// 1.05V + /// 1.05V - Medium power consumption V1_05 = 0b1010, - /// 1.10V (Default) + /// 1.10V (Default) - Standard voltage for 125MHz operation V1_10 = 0b1011, - /// 1.15V + /// 1.15V - Required for frequencies above 133MHz V1_15 = 0b1100, - /// 1.20V + /// 1.20V - For higher overclocking (200MHz+) V1_20 = 0b1101, - /// 1.25V + /// 1.25V - High voltage, use with caution V1_25 = 0b1110, - /// 1.30V + /// 1.30V - Maximum voltage, use with extreme caution V1_30 = 0b1111, } @@ -143,14 +246,57 @@ pub struct ClockConfig { #[cfg(feature = "rp2040")] pub voltage_scale: Option, /// Voltage stabilization delay in microseconds. + /// If not set, appropriate defaults will be used based on voltage level. #[cfg(feature = "rp2040")] pub voltage_stabilization_delay_us: Option, // gpin0: Option<(u32, Gpin<'static, AnyPin>)>, // gpin1: Option<(u32, Gpin<'static, AnyPin>)>, } +impl Default for ClockConfig { + /// Creates a minimal default configuration with safe values. + /// + /// This configuration uses the ring oscillator (ROSC) as the clock source + /// and sets minimal defaults that guarantee a working system. It's intended + /// as a starting point for manual configuration. + /// + /// Most users should use one of the more specific configuration functions: + /// - `ClockConfig::crystal()` - Standard configuration with external crystal + /// - `ClockConfig::rosc()` - Configuration using only the internal oscillator + /// - `ClockConfig::at_sys_frequency_mhz()` - Configuration for a specific system frequency + fn default() -> Self { + Self { + rosc: None, + xosc: None, + ref_clk: RefClkConfig { + src: RefClkSrc::Rosc, + div: 1, + }, + sys_clk: SysClkConfig { + src: SysClkSrc::Rosc, + div_int: 1, + div_frac: 0, + }, + peri_clk_src: None, + usb_clk: None, + adc_clk: None, + #[cfg(feature = "rp2040")] + rtc_clk: None, + #[cfg(feature = "rp2040")] + voltage_scale: None, + #[cfg(feature = "rp2040")] + voltage_stabilization_delay_us: None, + // gpin0: None, + // gpin1: None, + } + } +} + impl ClockConfig { /// Clock configuration derived from external crystal. + /// + /// This uses default settings for most parameters, suitable for typical use cases. + /// For manual control of PLL parameters, use `new_manual()` or modify the struct fields directly. pub fn crystal(crystal_hz: u32) -> Self { Self { rosc: Some(RoscConfig { @@ -217,101 +363,6 @@ impl ClockConfig { } } - /// Clock configuration derived from external crystal, targeting a specific SYS clock frequency for RP2040. - /// - /// This function calculates the required PLL settings and core voltage based on the target frequency. - /// - /// # Arguments - /// - /// * `crystal_hz`: The frequency of the external crystal (e.g., 12_000_000 for 12MHz). - /// * `sys_freq_hz`: The target system clock frequency. - /// - /// # Panics - /// - /// Panics if the requested frequency is impossible to achieve with the given crystal, - /// or if the required voltage for the frequency is not supported or known. - /// - /// # Safety Notes (RP2040) - /// - /// * Frequencies > 133MHz require increased core voltage. - /// * This function automatically selects `VoltageScale::V1_15` for frequencies > 133MHz and <= 200MHz. - /// * Frequencies > 200MHz might require `VoltageScale::V1_20` or higher and are considered overclocking beyond datasheet recommendations. - /// This function will select `VoltageScale::V1_20` for frequencies > 200MHz, use with caution. - /// * Ensure your hardware supports the selected voltage and frequency. - #[cfg(feature = "rp2040")] - pub fn crystal_freq(crystal_hz: u32, sys_freq_hz: u32) -> Self { - // Determine required voltage based on target frequency - let voltage_scale = match sys_freq_hz { - 0..=133_000_000 => VoltageScale::V1_10, // Default voltage is sufficient - 133_000_001..=200_000_000 => VoltageScale::V1_15, // Requires 1.15V - _ => VoltageScale::V1_20, // Frequencies > 200MHz require at least 1.20V (Overclocking) - }; - - // Find suitable PLL parameters - let pll_params = match find_pll_params(crystal_hz, sys_freq_hz) { - Some(params) => params, - None => { - // If we can't find valid parameters for the requested frequency, - // fall back to safe defaults (125 MHz for RP2040) - let safe_freq = 125_000_000; // Safe default frequency - find_pll_params(crystal_hz, safe_freq) - .expect("Could not find valid PLL parameters even for safe default frequency") - } - }; - - Self { - rosc: Some(RoscConfig { - hz: 6_500_000, - range: RoscRange::Medium, - drive_strength: [0; 8], - div: 16, - }), - xosc: Some(XoscConfig { - hz: crystal_hz, - sys_pll: Some(pll_params), - // Keep USB PLL at 48MHz for compatibility - usb_pll: Some(PllConfig { - refdiv: 1, - fbdiv: 120, - post_div1: 6, - post_div2: 5, - }), - delay_multiplier: 128, - }), - ref_clk: RefClkConfig { - src: RefClkSrc::Xosc, - div: 1, - }, - sys_clk: SysClkConfig { - src: SysClkSrc::PllSys, - div_int: 1, - div_frac: 0, - }, - peri_clk_src: Some(PeriClkSrc::Sys), - usb_clk: Some(UsbClkConfig { - src: UsbClkSrc::PllUsb, - div: 1, - phase: 0, - }), - adc_clk: Some(AdcClkConfig { - src: AdcClkSrc::PllUsb, - div: 1, - phase: 0, - }), - rtc_clk: Some(RtcClkConfig { - src: RtcClkSrc::PllUsb, - div_int: 1024, - div_frac: 0, - phase: 0, - }), - voltage_scale: Some(voltage_scale), - #[cfg(feature = "rp2040")] - voltage_stabilization_delay_us: None, - // gpin0: None, - // gpin1: None, - } - } - /// Clock configuration from internal oscillator. pub fn rosc() -> Self { Self { @@ -366,22 +417,17 @@ impl ClockConfig { /// /// * `sys_freq_mhz` - The target system clock frequency in MHz /// - /// # Safety Notes - /// - /// * Frequencies > 133MHz require increased core voltage and are considered overclocking. - /// * Frequencies > 250MHz are extreme overclocking and may not be stable on all chips. - /// /// # Example /// /// ``` /// // Configure for standard 125MHz clock - /// let config = ClockConfig::with_speed_mhz(125); + /// let config = ClockConfig::at_sys_frequency_mhz(125); /// - /// // Overclock to 200MHz (requires higher voltage) - /// let config = ClockConfig::with_speed_mhz(200); + /// // Overclock to 200MHz + /// let config = ClockConfig::at_sys_frequency_mhz(200); /// ``` #[cfg(feature = "rp2040")] - pub fn with_speed_mhz(sys_freq_mhz: u32) -> Self { + pub fn at_sys_frequency_mhz(sys_freq_mhz: u32) -> Self { // For 125MHz, use exactly the same config as the default to avoid any differences if sys_freq_mhz == 125 { return Self::crystal(12_000_000); @@ -392,12 +438,7 @@ impl ClockConfig { const DEFAULT_CRYSTAL_HZ: u32 = 12_000_000; let sys_freq_hz = sys_freq_mhz * 1_000_000; - let mut config = Self::crystal_freq(DEFAULT_CRYSTAL_HZ, sys_freq_hz); - - // For frequencies above 200MHz, ensure we're using the highest voltage - if sys_freq_mhz > 200 { - config.voltage_scale = Some(VoltageScale::V1_20); - } + let config = Self::crystal_freq(DEFAULT_CRYSTAL_HZ, sys_freq_hz); config } @@ -412,11 +453,6 @@ impl ClockConfig { /// * `crystal_hz` - The frequency of the external crystal in Hz /// * `sys_freq_hz` - The target system clock frequency in Hz /// - /// # Safety Notes - /// - /// * Frequencies > 133MHz require increased core voltage and are considered overclocking. - /// * Frequencies > 250MHz are extreme overclocking and may not be stable on all chips. - /// /// # Example /// /// ``` @@ -428,58 +464,93 @@ impl ClockConfig { Self::crystal_freq(crystal_hz, sys_freq_hz) } - #[cfg(feature = "rp2040")] - pub fn with_speed_mhz_test_voltage(sys_freq_mhz: u32, voltage: Option) -> Self { - // Create a config with the requested frequency - let sys_freq_hz = sys_freq_mhz * 1_000_000; - let mut config = Self::crystal_freq(12_000_000, sys_freq_hz); - - // Override the voltage setting - config.voltage_scale = voltage; - - // For debugging - // println!("Debug: Setting freq to {}MHz with voltage {:?}", sys_freq_mhz, voltage); - - config - } - - /// Similar to `with_speed_mhz_test_voltage` but with an extended voltage stabilization delay. + /// Configure clocks derived from an external crystal with specific system frequency. /// - /// This function is useful for testing voltage stability issues where the default delay - /// may not be sufficient for the voltage regulator to fully stabilize. + /// This function calculates optimal PLL parameters to achieve the requested system + /// frequency from the given crystal frequency. It's used internally by higher-level + /// configuration functions. /// /// # Arguments /// - /// * `sys_freq_mhz` - The target system clock frequency in MHz - /// * `voltage` - The desired voltage scale setting - /// * `stabilization_delay_us` - Voltage stabilization delay in microseconds (default: 500μs) + /// * `crystal_hz` - The frequency of the external crystal in Hz + /// * `sys_freq_hz` - The desired system clock frequency in Hz + /// + /// # Returns + /// + /// A ClockConfig configured to achieve the requested system frequency using the + /// specified crystal, or panic if no valid parameters can be found. #[cfg(feature = "rp2040")] - pub fn with_speed_mhz_test_voltage_extended_delay( - sys_freq_mhz: u32, - voltage: Option, - stabilization_delay_us: Option, - ) -> Self { - // Create a config with the requested frequency - let sys_freq_hz = sys_freq_mhz * 1_000_000; - let mut config = Self::crystal_freq(12_000_000, sys_freq_hz); + fn crystal_freq(crystal_hz: u32, sys_freq_hz: u32) -> Self { + // Find optimal PLL parameters for the requested frequency + let sys_pll_params = find_pll_params(crystal_hz, sys_freq_hz) + .unwrap_or_else(|| panic!("Could not find valid PLL parameters for system clock")); - // Override the voltage setting - config.voltage_scale = voltage; + // Set the voltage scale based on the target frequency + // Higher frequencies require higher voltage + let voltage_scale = match sys_freq_hz { + freq if freq > 200_000_000 => Some(VoltageScale::V1_20), + freq if freq > 133_000_000 => Some(VoltageScale::V1_15), + _ => None, // Use default voltage (V1_10) + }; - // Add a custom voltage stabilization delay - config.voltage_stabilization_delay_us = stabilization_delay_us; + // For USB PLL, we always want 48MHz for USB + let usb_pll_params = if crystal_hz == 12_000_000 { + // For standard 12MHz crystal, use the default parameters + PllConfig { + refdiv: 1, + fbdiv: 120, + post_div1: 6, + post_div2: 5, + } + } else { + // For other crystals, calculate parameters to get 48MHz + find_pll_params(crystal_hz, 48_000_000) + .unwrap_or_else(|| panic!("Could not find valid PLL parameters for USB clock")) + }; - config + Self { + rosc: Some(RoscConfig { + hz: 6_500_000, + range: RoscRange::Medium, + drive_strength: [0; 8], + div: 16, + }), + xosc: Some(XoscConfig { + hz: crystal_hz, + sys_pll: Some(sys_pll_params), + usb_pll: Some(usb_pll_params), + delay_multiplier: 128, + }), + ref_clk: RefClkConfig { + src: RefClkSrc::Xosc, + div: 1, + }, + sys_clk: SysClkConfig { + src: SysClkSrc::PllSys, + div_int: 1, + div_frac: 0, + }, + peri_clk_src: Some(PeriClkSrc::Sys), + usb_clk: Some(UsbClkConfig { + src: UsbClkSrc::PllUsb, + div: 1, + phase: 0, + }), + adc_clk: Some(AdcClkConfig { + src: AdcClkSrc::PllUsb, + div: 1, + phase: 0, + }), + rtc_clk: Some(RtcClkConfig { + src: RtcClkSrc::PllUsb, + div_int: 1024, + div_frac: 0, + phase: 0, + }), + voltage_scale, + voltage_stabilization_delay_us: None, + } } - // pub fn bind_gpin(&mut self, gpin: Gpin<'static, P>, hz: u32) { - // match P::NR { - // 0 => self.gpin0 = Some((hz, gpin.into())), - // 1 => self.gpin1 = Some((hz, gpin.into())), - // _ => unreachable!(), - // } - // // pin is now provisionally bound. if the config is applied it must be forgotten, - // // or Gpin::drop will deconfigure the clock input. - // } } /// ROSC freq range. @@ -525,6 +596,30 @@ pub struct XoscConfig { } /// PLL configuration. +/// +/// This struct defines the parameters used to configure the Phase-Locked Loop (PLL) +/// in the RP2040. The parameters follow the definitions from the RP2040 datasheet, +/// section 2.18.3. +/// +/// # Parameters +/// +/// * `refdiv` - Reference divider (1-63) +/// * `fbdiv` - VCO feedback divider (16-320) +/// * `post_div1` - First post divider (1-7) +/// * `post_div2` - Second post divider (1-7) - must be less than or equal to post_div1 +/// +/// # Constraints +/// +/// * VCO frequency (input_hz / refdiv * fbdiv) must be between 750MHz and 1800MHz +/// * post_div2 must be less than or equal to post_div1 +/// +/// # Calculation +/// +/// The output frequency of the PLL is calculated as: +/// +/// `output_hz = (input_hz / refdiv * fbdiv) / (post_div1 * post_div2)` +/// +/// Where input_hz is typically the crystal frequency (e.g., 12MHz). #[derive(Clone, Copy, Debug)] pub struct PllConfig { /// Reference divisor. @@ -537,6 +632,50 @@ pub struct PllConfig { pub post_div2: u8, } +impl PllConfig { + /// Calculate the output frequency for this PLL configuration + /// given an input frequency. + pub fn output_frequency(&self, input_hz: u32) -> u32 { + let ref_freq = input_hz / self.refdiv as u32; + let vco_freq = ref_freq * self.fbdiv as u32; + vco_freq / ((self.post_div1 * self.post_div2) as u32) + } + + /// Check if this PLL configuration is valid for the given input frequency. + pub fn is_valid(&self, input_hz: u32) -> bool { + // Check divisor constraints + if self.refdiv < 1 || self.refdiv > 63 { + return false; + } + if self.fbdiv < 16 || self.fbdiv > 320 { + return false; + } + if self.post_div1 < 1 || self.post_div1 > 7 { + return false; + } + if self.post_div2 < 1 || self.post_div2 > 7 { + return false; + } + if self.post_div2 > self.post_div1 { + return false; + } + + // Calculate reference frequency + let ref_freq = input_hz / self.refdiv as u32; + + // Check reference frequency range + if ref_freq < 5_000_000 || ref_freq > 800_000_000 { + return false; + } + + // Calculate VCO frequency + let vco_freq = ref_freq * self.fbdiv as u32; + + // Check VCO frequency range + vco_freq >= 750_000_000 && vco_freq <= 1_800_000_000 + } +} + /// Reference clock config. pub struct RefClkConfig { /// Reference clock source. @@ -683,6 +822,35 @@ pub struct RtcClkConfig { /// Find valid PLL parameters (refdiv, fbdiv, post_div1, post_div2) for a target output frequency /// based on the input frequency. /// +/// This function searches for the best PLL configuration to achieve the requested target frequency +/// while staying within the VCO frequency range of 750MHz to 1800MHz. It prioritizes stability +/// over exact frequency matching by using larger divisors where possible. +/// +/// # Parameters +/// +/// * `input_hz`: The input frequency in Hz (typically the crystal frequency, e.g. 12MHz) +/// * `target_hz`: The desired output frequency in Hz (e.g. 125MHz for standard RP2040 operation) +/// +/// # Returns +/// +/// * `Some(PllConfig)` if valid parameters were found +/// * `None` if no valid parameters could be found for the requested combination +/// +/// # Algorithm +/// +/// 1. Set reference divider to 1 (fixed for simplicity) +/// 2. Try different feedback divisors (fbdiv) starting from highest to lowest +/// 3. For each fbdiv value, check if the resulting VCO frequency is valid (750-1800MHz) +/// 4. Find post-divider combinations that give the exact requested frequency +/// 5. If no exact match, return the closest approximation +/// +/// # Example +/// +/// ``` +/// // Find parameters for 133MHz system clock from 12MHz crystal +/// let pll_params = find_pll_params(12_000_000, 133_000_000).unwrap(); +/// ``` +/// /// Similar to the Pico SDK's parameter selection approach, prioritizing stability. /// See RP2040 Datasheet section 2.16.3. Reference Clock (ref) and 2.18.3. PLL #[cfg(feature = "rp2040")] @@ -766,43 +934,6 @@ fn find_pll_params(input_hz: u32, target_hz: u32) -> Option { best_config } -#[cfg(feature = "rp2040")] -pub fn compare_pll_params() { - // Parameters from default configuration - let default_params = PllConfig { - refdiv: 1, - fbdiv: 125, - post_div1: 6, - post_div2: 2, - }; - - // Calculate parameters using our find_pll_params function - let crystal_hz = 12_000_000; - let target_hz = 125_000_000; - let calculated_params = find_pll_params(crystal_hz, target_hz).expect("Failed to find PLL parameters"); - - // Check if they're identical - let params_match = default_params.refdiv == calculated_params.refdiv - && default_params.fbdiv == calculated_params.fbdiv - && default_params.post_div1 == calculated_params.post_div1 - && default_params.post_div2 == calculated_params.post_div2; - - // Here we'd normally print results, but without a console we'll just - // use this for debugging in our IDE - let _default_output_freq = crystal_hz / default_params.refdiv as u32 * default_params.fbdiv as u32 - / (default_params.post_div1 * default_params.post_div2) as u32; - - let _calculated_output_freq = crystal_hz / calculated_params.refdiv as u32 * calculated_params.fbdiv as u32 - / (calculated_params.post_div1 * calculated_params.post_div2) as u32; - - // Parameters: default vs calculated - // refdiv: 1 vs {calculated_params.refdiv} - // fbdiv: 125 vs {calculated_params.fbdiv} - // post_div1: 6 vs {calculated_params.post_div1} - // post_div2: 2 vs {calculated_params.post_div2} - // params_match: {params_match} -} - /// safety: must be called exactly once at bootup pub(crate) unsafe fn init(config: ClockConfig) { // Reset everything except: @@ -1603,6 +1734,7 @@ impl rand_core::RngCore for RoscRng { dest.fill_with(Self::next_u8) } } + /// Enter the `DORMANT` sleep state. This will stop *all* internal clocks /// and can only be exited through resets, dormant-wake GPIO interrupts, /// and RTC interrupts. If RTC is clocked from an internal clock source diff --git a/examples/rp/src/bin/overclock.rs b/examples/rp/src/bin/overclock.rs index db6c8f448..9027f1516 100644 --- a/examples/rp/src/bin/overclock.rs +++ b/examples/rp/src/bin/overclock.rs @@ -14,7 +14,18 @@ const COUNT_TO: i64 = 10_000_000; #[embassy_executor::main] async fn main(_spawner: Spawner) -> ! { // Set up for clock frequency of 200 MHz - let config = Config::new(ClockConfig::with_speed_mhz(200)); + // This will set all the necessary defaults including slightly raised voltage + // See embassy_rp::clocks::ClockConfig for more options, including full manual control + let config = Config::new(ClockConfig::at_sys_frequency_mhz(200)); + + // Show the voltage scale and brownout-detection for verification + info!("System core voltage: {}", Debug2Format(&config.clocks.voltage_scale)); + // info!( + // "Brownout detection: {}", + // Debug2Format(&config.clocks.brownout_detection) + // ); + + // Initialize the peripherals let p = embassy_rp::init(config); // Show CPU frequency for verification From d44b94523576d3f8c1f586811f600eb3ba223606 Mon Sep 17 00:00:00 2001 From: 1-rafael-1 Date: Tue, 29 Apr 2025 22:49:53 +0200 Subject: [PATCH 1035/1217] Remove unused embassy-rp/sdk examples subproject --- embassy-rp/sdk examples | 1 - 1 file changed, 1 deletion(-) delete mode 160000 embassy-rp/sdk examples diff --git a/embassy-rp/sdk examples b/embassy-rp/sdk examples deleted file mode 160000 index ee68c78d0..000000000 --- a/embassy-rp/sdk examples +++ /dev/null @@ -1 +0,0 @@ -Subproject commit ee68c78d0afae2b69c03ae1a72bf5cc267a2d94c From 34b6a518f87a528856f1891d32ac1a48d6239b18 Mon Sep 17 00:00:00 2001 From: Curly Date: Wed, 30 Apr 2025 07:50:13 -0700 Subject: [PATCH 1036/1217] add 133MHz tick rate to support PR2040 @ 133MHz when `TIMERx`'s `SOURCE` is set to `SYSCLK` --- embassy-time-driver/Cargo.toml | 2 ++ embassy-time-driver/gen_tick.py | 1 + embassy-time-driver/src/tick.rs | 3 +++ embassy-time/Cargo.toml | 2 ++ 4 files changed, 8 insertions(+) diff --git a/embassy-time-driver/Cargo.toml b/embassy-time-driver/Cargo.toml index b709cafc1..16213cb75 100644 --- a/embassy-time-driver/Cargo.toml +++ b/embassy-time-driver/Cargo.toml @@ -226,6 +226,8 @@ tick-hz-128_000_000 = [] tick-hz-130_000_000 = [] ## 131.072MHz Tick Rate tick-hz-131_072_000 = [] +## 133.0MHz Tick Rate +tick-hz-133_000_000 = [] ## 140.0MHz Tick Rate tick-hz-140_000_000 = [] ## 144.0MHz Tick Rate diff --git a/embassy-time-driver/gen_tick.py b/embassy-time-driver/gen_tick.py index af194c31f..080434457 100644 --- a/embassy-time-driver/gen_tick.py +++ b/embassy-time-driver/gen_tick.py @@ -22,6 +22,7 @@ for i in range(1, 30): ticks.append(10 * i * 1_000_000) for i in range(15, 50): ticks.append(20 * i * 1_000_000) +ticks.append(133 * 1_000_000) seen = set() ticks = sorted([x for x in ticks if not (x in seen or seen.add(x))]) diff --git a/embassy-time-driver/src/tick.rs b/embassy-time-driver/src/tick.rs index 916ae9498..5059e1628 100644 --- a/embassy-time-driver/src/tick.rs +++ b/embassy-time-driver/src/tick.rs @@ -182,6 +182,8 @@ pub const TICK_HZ: u64 = 128_000_000; pub const TICK_HZ: u64 = 130_000_000; #[cfg(feature = "tick-hz-131_072_000")] pub const TICK_HZ: u64 = 131_072_000; +#[cfg(feature = "tick-hz-133_000_000")] +pub const TICK_HZ: u64 = 133_000_000; #[cfg(feature = "tick-hz-140_000_000")] pub const TICK_HZ: u64 = 140_000_000; #[cfg(feature = "tick-hz-144_000_000")] @@ -410,6 +412,7 @@ pub const TICK_HZ: u64 = 5_242_880_000; feature = "tick-hz-128_000_000", feature = "tick-hz-130_000_000", feature = "tick-hz-131_072_000", + feature = "tick-hz-133_000_000", feature = "tick-hz-140_000_000", feature = "tick-hz-144_000_000", feature = "tick-hz-150_000_000", diff --git a/embassy-time/Cargo.toml b/embassy-time/Cargo.toml index 80a39dbf5..dc144ec3c 100644 --- a/embassy-time/Cargo.toml +++ b/embassy-time/Cargo.toml @@ -274,6 +274,8 @@ tick-hz-128_000_000 = ["embassy-time-driver/tick-hz-128_000_000"] tick-hz-130_000_000 = ["embassy-time-driver/tick-hz-130_000_000"] ## 131.072MHz Tick Rate tick-hz-131_072_000 = ["embassy-time-driver/tick-hz-131_072_000"] +## 133.0MHz Tick Rate +tick-hz-133_000_000 = ["embassy-time-driver/tick-hz-133_000_000"] ## 140.0MHz Tick Rate tick-hz-140_000_000 = ["embassy-time-driver/tick-hz-140_000_000"] ## 144.0MHz Tick Rate From 0591d60a7931255fd1161608c69c4935d6a16676 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Wed, 30 Apr 2025 18:00:17 +0200 Subject: [PATCH 1037/1217] stm32/otg: calculate TRDT using AHB freq instead of kernel freq. --- embassy-stm32/build.rs | 5 +++++ embassy-stm32/src/rcc/mod.rs | 2 ++ embassy-stm32/src/usb/otg.rs | 2 +- 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index f9f03c51b..3fefa9717 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -647,6 +647,8 @@ fn main() { PeripheralRccKernelClock::Clock(clock) => clock_gen.gen_clock(p.name, clock), }; + let bus_clock_frequency = clock_gen.gen_clock(p.name, &rcc.bus_clock); + // A refcount leak can result if the same field is shared by peripherals with different stop modes // This condition should be checked in stm32-data let stop_mode = match rcc.stop_mode { @@ -660,6 +662,9 @@ fn main() { fn frequency() -> crate::time::Hertz { #clock_frequency } + fn bus_frequency() -> crate::time::Hertz { + #bus_clock_frequency + } const RCC_INFO: crate::rcc::RccInfo = unsafe { crate::rcc::RccInfo::new( diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index 4f43d3748..150daa4a7 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs @@ -97,6 +97,8 @@ pub(crate) unsafe fn get_freqs() -> &'static Clocks { pub(crate) trait SealedRccPeripheral { fn frequency() -> Hertz; + #[allow(dead_code)] + fn bus_frequency() -> Hertz; const RCC_INFO: RccInfo; } diff --git a/embassy-stm32/src/usb/otg.rs b/embassy-stm32/src/usb/otg.rs index 2aca3d929..590d1a427 100644 --- a/embassy-stm32/src/usb/otg.rs +++ b/embassy-stm32/src/usb/otg.rs @@ -549,7 +549,7 @@ foreach_interrupt!( ); fn calculate_trdt(speed: Dspd) -> u8 { - let ahb_freq = T::frequency().0; + let ahb_freq = T::bus_frequency().0; match speed { Dspd::HIGH_SPEED => { // From RM0431 (F72xx), RM0090 (F429), RM0390 (F446) From 22b5f73811a7cc0dbca920e02b5d001d252d344c Mon Sep 17 00:00:00 2001 From: 1-rafael-1 Date: Thu, 1 May 2025 00:11:56 +0200 Subject: [PATCH 1038/1217] add manual overclock example, finalize API, cleanup --- embassy-rp/src/clocks.rs | 268 +++++++++++++----------- examples/rp/src/bin/overclock.rs | 24 +-- examples/rp/src/bin/overclock_manual.rs | 81 +++++++ 3 files changed, 227 insertions(+), 146 deletions(-) create mode 100644 examples/rp/src/bin/overclock_manual.rs diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs index 1f5c27df1..86c172879 100644 --- a/embassy-rp/src/clocks.rs +++ b/embassy-rp/src/clocks.rs @@ -147,56 +147,30 @@ pub enum PeriClkSrc { /// Core voltage scaling options for RP2040. /// /// The RP2040 voltage regulator can be configured for different output voltages. -/// Higher voltages allow for higher clock frequencies but increase power consumption. -/// -/// # Typical Use Cases -/// -/// - `V0_85` to `V1_05`: Power saving for lower frequencies (below 100MHz) -/// - `V1_10`: Default voltage, safe for standard 125MHz operation -/// - `V1_15`: Required for frequencies above 133MHz (e.g., 200MHz overclocking) -/// - `V1_20`: For more extreme overclocking (200MHz+) -/// - `V1_25` and `V1_30`: Highest voltage settings, use with caution -/// -/// # Overclocking Notes -/// -/// When overclocking: -/// - Frequencies up to 133MHz are typically stable at default voltage (`V1_10`) -/// - Frequencies from 133MHz to 200MHz generally require `V1_15` -/// - Frequencies above 200MHz typically require `V1_20` or higher -/// -/// # Power Consumption -/// -/// Higher voltages increase power consumption and heat generation. In battery-powered -/// applications, consider using lower voltages when maximum performance is not required. -/// -/// # Safety -/// -/// Increased voltage can reduce the lifespan of the chip if used for extended periods, -/// especially at `V1_25` and `V1_30`. These higher voltages should be used with -/// consideration of thermal management. +/// Higher voltages allow for higher clock frequencies but increase power consumption and heat. #[cfg(feature = "rp2040")] #[derive(Clone, Copy, Debug, PartialEq, Eq)] #[repr(u8)] pub enum VoltageScale { - /// 0.85V - Lowest power consumption, suitable for low frequencies + /// 0.85V V0_85 = 0b0110, - /// 0.90V - Low power consumption + /// 0.90V V0_90 = 0b0111, - /// 0.95V - Low power consumption + /// 0.95V V0_95 = 0b1000, - /// 1.00V - Medium power consumption + /// 1.00V V1_00 = 0b1001, - /// 1.05V - Medium power consumption + /// 1.05V V1_05 = 0b1010, - /// 1.10V (Default) - Standard voltage for 125MHz operation + /// 1.10V V1_10 = 0b1011, - /// 1.15V - Required for frequencies above 133MHz + /// 1.15V V1_15 = 0b1100, - /// 1.20V - For higher overclocking (200MHz+) + /// 1.20V V1_20 = 0b1101, - /// 1.25V - High voltage, use with caution + /// 1.25V V1_25 = 0b1110, - /// 1.30V - Maximum voltage, use with extreme caution + /// 1.30V V1_30 = 0b1111, } @@ -204,10 +178,8 @@ pub enum VoltageScale { impl VoltageScale { /// Get the recommended Brown-Out Detection (BOD) setting for this voltage. /// Sets the BOD threshold to approximately 90% of the core voltage. - /// See RP2040 Datasheet, Table 190, BOD Register fn recommended_bod(self) -> u8 { match self { - // ~90% of voltage setting based on Table 190 values VoltageScale::V0_85 => 0b0111, // 0.774V (~91% of 0.85V) VoltageScale::V0_90 => 0b1000, // 0.817V (~91% of 0.90V) VoltageScale::V0_95 => 0b1001, // 0.860V (~91% of 0.95V) @@ -246,7 +218,7 @@ pub struct ClockConfig { #[cfg(feature = "rp2040")] pub voltage_scale: Option, /// Voltage stabilization delay in microseconds. - /// If not set, appropriate defaults will be used based on voltage level. + /// If not set, defaults will be used based on voltage level. #[cfg(feature = "rp2040")] pub voltage_stabilization_delay_us: Option, // gpin0: Option<(u32, Gpin<'static, AnyPin>)>, @@ -409,7 +381,7 @@ impl ClockConfig { /// Configure the system clock to a specific frequency in MHz. /// - /// This is a more user-friendly way to configure the system clock, similar to + /// This is a user-friendly way to configure the system clock, similar to /// the Pico SDK's approach. It automatically handles voltage scaling based on the /// requested frequency and uses the standard 12MHz crystal found on most RP2040 boards. /// @@ -420,9 +392,6 @@ impl ClockConfig { /// # Example /// /// ``` - /// // Configure for standard 125MHz clock - /// let config = ClockConfig::at_sys_frequency_mhz(125); - /// /// // Overclock to 200MHz /// let config = ClockConfig::at_sys_frequency_mhz(200); /// ``` @@ -551,6 +520,98 @@ impl ClockConfig { voltage_stabilization_delay_us: None, } } + + /// Configure with manual PLL settings for full control over system clock + /// + /// This method provides a simple way to configure the system with custom PLL parameters + /// without needing to understand the full nested configuration structure. + /// + /// # Arguments + /// + /// * `xosc_hz` - The frequency of the external crystal in Hz + /// * `pll_config` - The PLL configuration parameters to achieve desired frequency + /// * `voltage_scale` - Optional voltage scaling for overclocking (required for >133MHz) + /// + /// # Returns + /// + /// A ClockConfig configured with the specified PLL parameters + /// + /// # Example + /// + /// ```rust,ignore + /// // Configure for 200MHz operation + /// let config = Config::default(); + /// config.clocks = ClockConfig::manual_pll( + /// 12_000_000, + /// PllConfig { + /// refdiv: 1, // Reference divider (12 MHz / 1 = 12 MHz) + /// fbdiv: 100, // Feedback divider (12 MHz * 100 = 1200 MHz VCO) + /// post_div1: 3, // First post divider (1200 MHz / 3 = 400 MHz) + /// post_div2: 2, // Second post divider (400 MHz / 2 = 200 MHz) + /// }, + /// Some(VoltageScale::V1_15) + /// ); + /// ``` + #[cfg(feature = "rp2040")] + pub fn manual_pll(xosc_hz: u32, pll_config: PllConfig, voltage_scale: Option) -> Self { + // Calculate the actual output frequency for documentation + // let ref_freq = xosc_hz / pll_config.refdiv as u32; + // let vco_freq = ref_freq * pll_config.fbdiv as u32; + // let sys_freq = vco_freq / ((pll_config.post_div1 * pll_config.post_div2) as u32); + + // Validate PLL parameters + assert!(pll_config.is_valid(xosc_hz), "Invalid PLL parameters"); + + let mut config = Self::default(); + + config.xosc = Some(XoscConfig { + hz: xosc_hz, + sys_pll: Some(pll_config), + usb_pll: Some(PllConfig { + refdiv: 1, + fbdiv: 120, + post_div1: 6, + post_div2: 5, + }), + delay_multiplier: 128, + }); + + config.ref_clk = RefClkConfig { + src: RefClkSrc::Xosc, + div: 1, + }; + + config.sys_clk = SysClkConfig { + src: SysClkSrc::PllSys, + div_int: 1, + div_frac: 0, + }; + + config.voltage_scale = voltage_scale; + config.peri_clk_src = Some(PeriClkSrc::Sys); + + // Set reasonable defaults for other clocks + config.usb_clk = Some(UsbClkConfig { + src: UsbClkSrc::PllUsb, + div: 1, + phase: 0, + }); + + config.adc_clk = Some(AdcClkConfig { + src: AdcClkSrc::PllUsb, + div: 1, + phase: 0, + }); + + config.rtc_clk = Some(RtcClkConfig { + src: RtcClkSrc::PllUsb, + div_int: 1024, + div_frac: 0, + phase: 0, + }); + + config + } } /// ROSC freq range. @@ -596,30 +657,6 @@ pub struct XoscConfig { } /// PLL configuration. -/// -/// This struct defines the parameters used to configure the Phase-Locked Loop (PLL) -/// in the RP2040. The parameters follow the definitions from the RP2040 datasheet, -/// section 2.18.3. -/// -/// # Parameters -/// -/// * `refdiv` - Reference divider (1-63) -/// * `fbdiv` - VCO feedback divider (16-320) -/// * `post_div1` - First post divider (1-7) -/// * `post_div2` - Second post divider (1-7) - must be less than or equal to post_div1 -/// -/// # Constraints -/// -/// * VCO frequency (input_hz / refdiv * fbdiv) must be between 750MHz and 1800MHz -/// * post_div2 must be less than or equal to post_div1 -/// -/// # Calculation -/// -/// The output frequency of the PLL is calculated as: -/// -/// `output_hz = (input_hz / refdiv * fbdiv) / (post_div1 * post_div2)` -/// -/// Where input_hz is typically the crystal frequency (e.g., 12MHz). #[derive(Clone, Copy, Debug)] pub struct PllConfig { /// Reference divisor. @@ -836,35 +873,17 @@ pub struct RtcClkConfig { /// * `Some(PllConfig)` if valid parameters were found /// * `None` if no valid parameters could be found for the requested combination /// -/// # Algorithm -/// -/// 1. Set reference divider to 1 (fixed for simplicity) -/// 2. Try different feedback divisors (fbdiv) starting from highest to lowest -/// 3. For each fbdiv value, check if the resulting VCO frequency is valid (750-1800MHz) -/// 4. Find post-divider combinations that give the exact requested frequency -/// 5. If no exact match, return the closest approximation -/// /// # Example /// /// ``` /// // Find parameters for 133MHz system clock from 12MHz crystal /// let pll_params = find_pll_params(12_000_000, 133_000_000).unwrap(); /// ``` -/// -/// Similar to the Pico SDK's parameter selection approach, prioritizing stability. -/// See RP2040 Datasheet section 2.16.3. Reference Clock (ref) and 2.18.3. PLL #[cfg(feature = "rp2040")] fn find_pll_params(input_hz: u32, target_hz: u32) -> Option { // Fixed reference divider for system PLL const PLL_SYS_REFDIV: u8 = 1; - // Constraints from datasheet: - // REFDIV: 1..=63 - // FBDIV: 16..=320 - // POSTDIV1: 1..=7 - // POSTDIV2: 1..=7 (must be <= POSTDIV1) - // VCO frequency (input_hz / refdiv * fbdiv): 750MHz ..= 1800MHz - // Calculate reference frequency let reference_freq = input_hz / PLL_SYS_REFDIV as u32; @@ -969,8 +988,7 @@ pub(crate) unsafe fn init(config: ClockConfig) { #[cfg(feature = "_rp235x")] while c.clk_ref_selected().read() != pac::clocks::regs::ClkRefSelected(1) {} - // Set Core Voltage (RP2040 only) BEFORE doing anything with PLLs - // This is critical for overclocking - must be done before PLL setup + // Set Core Voltage (RP2040 only), if we have config for it and we're not using the default #[cfg(feature = "rp2040")] if let Some(voltage) = config.voltage_scale { let vreg = pac::VREG_AND_CHIP_RESET; @@ -978,17 +996,15 @@ pub(crate) unsafe fn init(config: ClockConfig) { let target_vsel = voltage as u8; if target_vsel != current_vsel { - // IMPORTANT: Use modify() instead of write() to preserve the HIZ and EN bits - // This is critical - otherwise we might disable the regulator when changing voltage + // Use modify() instead of write() to preserve the HIZ and EN bits - otherwise we will disable the regulator when changing voltage vreg.vreg().modify(|w| w.set_vsel(target_vsel)); - // For higher voltage settings (overclocking), we need a longer stabilization time - // Default to 1000 µs (1ms) like the SDK, but allow user override + // Wait for the voltage to stabilize. Use the provided delay or default based on voltage let settling_time_us = config.voltage_stabilization_delay_us.unwrap_or_else(|| { match voltage { - VoltageScale::V1_15 => 1000, // 1ms for 1.15V (matches SDK default) + VoltageScale::V1_15 => 1000, // 1ms for 1.15V VoltageScale::V1_20 | VoltageScale::V1_25 | VoltageScale::V1_30 => 2000, // 2ms for higher voltages - _ => 500, // 500 µs for standard voltages + _ => 0, // no delay for all others } }); @@ -1001,7 +1017,7 @@ pub(crate) unsafe fn init(config: ClockConfig) { // Wait for voltage to stabilize cortex_m::asm::delay(delay_cycles); - // Only NOW set the BOD level after voltage has stabilized + // Only now set the BOD level after voltage has stabilized vreg.bod().write(|w| w.set_vsel(voltage.recommended_bod())); } } @@ -1026,9 +1042,9 @@ pub(crate) unsafe fn init(config: ClockConfig) { // SETUP TEMPORARY STABLE CLOCKS FIRST // Configure USB PLL for our stable temporary clock // This follows the SDK's approach of using USB PLL as a stable intermediate clock - let usb_pll_freq = match &config.xosc { + let pll_usb_freq = match &config.xosc { Some(config) => match &config.usb_pll { - Some(usb_pll_config) => { + Some(pll_usb_config) => { // Reset USB PLL let mut peris = reset::Peripherals(0); peris.set_pll_usb(true); @@ -1036,7 +1052,7 @@ pub(crate) unsafe fn init(config: ClockConfig) { reset::unreset_wait(peris); // Configure the USB PLL - this should give us 48MHz - let usb_pll_freq = configure_pll(pac::PLL_USB, xosc_freq, *usb_pll_config); + let usb_pll_freq = configure_pll(pac::PLL_USB, xosc_freq, *pll_usb_config); CLOCKS.pll_usb.store(usb_pll_freq, Ordering::Relaxed); usb_pll_freq } @@ -1122,7 +1138,7 @@ pub(crate) unsafe fn init(config: ClockConfig) { let (src, aux, freq) = match config.sys_clk.src { SysClkSrc::Ref => (Src::CLK_REF, Aux::CLKSRC_PLL_SYS, clk_ref_freq), SysClkSrc::PllSys => (Src::CLKSRC_CLK_SYS_AUX, Aux::CLKSRC_PLL_SYS, pll_sys_freq), - SysClkSrc::PllUsb => (Src::CLKSRC_CLK_SYS_AUX, Aux::CLKSRC_PLL_USB, usb_pll_freq), + SysClkSrc::PllUsb => (Src::CLKSRC_CLK_SYS_AUX, Aux::CLKSRC_PLL_USB, pll_usb_freq), SysClkSrc::Rosc => (Src::CLKSRC_CLK_SYS_AUX, Aux::ROSC_CLKSRC, rosc_freq), SysClkSrc::Xosc => (Src::CLKSRC_CLK_SYS_AUX, Aux::XOSC_CLKSRC, xosc_freq), // SysClkSrc::Gpin0 => (Src::CLKSRC_CLK_SYS_AUX, Aux::CLKSRC_GPIN0, gpin0_freq), @@ -1185,7 +1201,7 @@ pub(crate) unsafe fn init(config: ClockConfig) { let peri_freq = match src { PeriClkSrc::Sys => clk_sys_freq, PeriClkSrc::PllSys => pll_sys_freq, - PeriClkSrc::PllUsb => usb_pll_freq, + PeriClkSrc::PllUsb => pll_usb_freq, PeriClkSrc::Rosc => rosc_freq, PeriClkSrc::Xosc => xosc_freq, // PeriClkSrc::Gpin0 => gpin0_freq, @@ -1210,7 +1226,7 @@ pub(crate) unsafe fn init(config: ClockConfig) { w.set_auxsrc(ClkUsbCtrlAuxsrc::from_bits(conf.src as _)); }); let usb_freq = match conf.src { - UsbClkSrc::PllUsb => usb_pll_freq, + UsbClkSrc::PllUsb => pll_usb_freq, UsbClkSrc::PllSys => pll_sys_freq, UsbClkSrc::Rosc => rosc_freq, UsbClkSrc::Xosc => xosc_freq, @@ -1234,7 +1250,7 @@ pub(crate) unsafe fn init(config: ClockConfig) { w.set_auxsrc(ClkAdcCtrlAuxsrc::from_bits(conf.src as _)); }); let adc_in_freq = match conf.src { - AdcClkSrc::PllUsb => usb_pll_freq, + AdcClkSrc::PllUsb => pll_usb_freq, AdcClkSrc::PllSys => pll_sys_freq, AdcClkSrc::Rosc => rosc_freq, AdcClkSrc::Xosc => xosc_freq, @@ -1262,7 +1278,7 @@ pub(crate) unsafe fn init(config: ClockConfig) { w.set_auxsrc(ClkRtcCtrlAuxsrc::from_bits(conf.src as _)); }); let rtc_in_freq = match conf.src { - RtcClkSrc::PllUsb => usb_pll_freq, + RtcClkSrc::PllUsb => pll_usb_freq, RtcClkSrc::PllSys => pll_sys_freq, RtcClkSrc::Rosc => rosc_freq, RtcClkSrc::Xosc => xosc_freq, @@ -1390,40 +1406,36 @@ fn start_xosc(crystal_hz: u32, delay_multiplier: u32) { while !pac::XOSC.status().read().stable() {} } +/// PLL (Phase-Locked Loop) configuration #[inline(always)] fn configure_pll(p: pac::pll::Pll, input_freq: u32, config: PllConfig) -> u32 { // Calculate reference frequency let ref_freq = input_freq / config.refdiv as u32; // Validate PLL parameters - assert!( - config.fbdiv >= 16 && config.fbdiv <= 320, - "fbdiv must be between 16 and 320" - ); - assert!( - config.post_div1 >= 1 && config.post_div1 <= 7, - "post_div1 must be between 1 and 7" - ); - assert!( - config.post_div2 >= 1 && config.post_div2 <= 7, - "post_div2 must be between 1 and 7" - ); - assert!(config.post_div2 <= config.post_div1, "post_div2 must be <= post_div1"); - assert!( - config.refdiv >= 1 && config.refdiv <= 63, - "refdiv must be between 1 and 63" - ); - assert!( - ref_freq >= 5_000_000 && ref_freq <= 800_000_000, - "ref_freq must be between 5MHz and 800MHz" - ); + // Feedback divider (FBDIV) must be between 16 and 320 + assert!(config.fbdiv >= 16 && config.fbdiv <= 320); + + // Post divider 1 (POSTDIV1) must be between 1 and 7 + assert!(config.post_div1 >= 1 && config.post_div1 <= 7); + + // Post divider 2 (POSTDIV2) must be between 1 and 7 + assert!(config.post_div2 >= 1 && config.post_div2 <= 7); + + // Post divider 2 (POSTDIV2) must be less than or equal to post divider 1 (POSTDIV1) + assert!(config.post_div2 <= config.post_div1); + + // Reference divider (REFDIV) must be between 1 and 63 + assert!(config.refdiv >= 1 && config.refdiv <= 63); + + // Reference frequency (REF_FREQ) must be between 5MHz and 800MHz + assert!(ref_freq >= 5_000_000 && ref_freq <= 800_000_000); // Calculate VCO frequency let vco_freq = ref_freq.saturating_mul(config.fbdiv as u32); - assert!( - vco_freq >= 750_000_000 && vco_freq <= 1_800_000_000, - "VCO frequency must be between 750MHz and 1800MHz" - ); + + // VCO (Voltage Controlled Oscillator) frequency must be between 750MHz and 1800MHz + assert!(vco_freq >= 750_000_000 && vco_freq <= 1_800_000_000); // We follow the SDK's approach to PLL configuration which is: // 1. Power down PLL diff --git a/examples/rp/src/bin/overclock.rs b/examples/rp/src/bin/overclock.rs index 9027f1516..e3ac77340 100644 --- a/examples/rp/src/bin/overclock.rs +++ b/examples/rp/src/bin/overclock.rs @@ -1,9 +1,13 @@ +//! # Overclocking the RP2040 to 200 MHz +//! +//! This example demonstrates how to configure the RP2040 to run at 200 MHz using a higher level API. + #![no_std] #![no_main] use defmt::*; use embassy_executor::Spawner; -use embassy_rp::clocks::{clk_sys_freq, ClockConfig, VoltageScale}; +use embassy_rp::clocks::{clk_sys_freq, ClockConfig}; use embassy_rp::config::Config; use embassy_rp::gpio::{Level, Output}; use embassy_time::{Duration, Instant, Timer}; @@ -15,15 +19,10 @@ const COUNT_TO: i64 = 10_000_000; async fn main(_spawner: Spawner) -> ! { // Set up for clock frequency of 200 MHz // This will set all the necessary defaults including slightly raised voltage - // See embassy_rp::clocks::ClockConfig for more options, including full manual control let config = Config::new(ClockConfig::at_sys_frequency_mhz(200)); - // Show the voltage scale and brownout-detection for verification + // Show the voltage scale for verification info!("System core voltage: {}", Debug2Format(&config.clocks.voltage_scale)); - // info!( - // "Brownout detection: {}", - // Debug2Format(&config.clocks.brownout_detection) - // ); // Initialize the peripherals let p = embassy_rp::init(config); @@ -64,14 +63,3 @@ async fn main(_spawner: Spawner) -> ! { Timer::after(Duration::from_secs(2)).await; } } - -// let config = Config::new(ClockConfig::with_speed_mhz_test_voltage(125, Some(VoltageScale::V1_10))); -// let config = Config::default(); -// let config = Config::new(ClockConfig::with_speed_mhz_test_voltage_extended_delay( -// 200, // Standard 125MHz clock -// Some(VoltageScale::V1_15), // 1.15V voltage -// Some(1000), // 1000μs (1ms) stabilization delay - significantly longer than default -// )); -// Initialize the peripherals - -// let p = embassy_rp::init(Default::default()); //testing the bog standard diff --git a/examples/rp/src/bin/overclock_manual.rs b/examples/rp/src/bin/overclock_manual.rs new file mode 100644 index 000000000..ad6abf0e7 --- /dev/null +++ b/examples/rp/src/bin/overclock_manual.rs @@ -0,0 +1,81 @@ +//! # Overclocking the RP2040 to 200 MHz manually +//! +//! This example demonstrates how to manually configure the RP2040 to run at 200 MHz. + +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_rp::clocks; +use embassy_rp::clocks::{ClockConfig, PllConfig, VoltageScale}; +use embassy_rp::config::Config; +use embassy_rp::gpio::{Level, Output}; +use embassy_time::{Duration, Instant, Timer}; +use {defmt_rtt as _, panic_probe as _}; + +const COUNT_TO: i64 = 10_000_000; + +/// Configure the RP2040 for 200 MHz operation by manually specifying +/// all the required parameters instead of using higher-level APIs. +fn configure_manual_overclock() -> Config { + // Set the PLL configuration manually, starting from default values + let mut config = Config::default(); + + // Set the system clock to 200 MHz using a PLL with a reference frequency of 12 MHz + config.clocks = ClockConfig::manual_pll( + 12_000_000, + PllConfig { + refdiv: 1, + fbdiv: 100, + post_div1: 3, + post_div2: 2, + }, + // For 200 MHz, we need a voltage scale of 1.15V + Some(VoltageScale::V1_15), + ); + + config +} + +#[embassy_executor::main] +async fn main(_spawner: Spawner) -> ! { + // Initialize with our manual overclock configuration + let p = embassy_rp::init(configure_manual_overclock()); + + // Verify the actual system clock frequency + let sys_freq = clocks::clk_sys_freq(); + info!("System clock frequency: {} MHz", sys_freq / 1_000_000); + + // LED to indicate the system is running + let mut led = Output::new(p.PIN_25, Level::Low); + + loop { + // Reset the counter at the start of measurement period + let mut counter = 0; + + // Turn LED on while counting + led.set_high(); + + let start = Instant::now(); + + // This is a busy loop that will take some time to complete + while counter < COUNT_TO { + counter += 1; + } + + let elapsed = Instant::now() - start; + + // Report the elapsed time + led.set_low(); + info!( + "At {}Mhz: Elapsed time to count to {}: {}ms", + sys_freq / 1_000_000, + counter, + elapsed.as_millis() + ); + + // Wait 2 seconds before starting the next measurement + Timer::after(Duration::from_secs(2)).await; + } +} From ace20f40ad1b2168c9d2b78155c0cf29244bc456 Mon Sep 17 00:00:00 2001 From: Dion Dokter Date: Thu, 1 May 2025 10:35:10 +0200 Subject: [PATCH 1039/1217] Maybe fixed all CI --- .github/ci/test.sh | 4 ++-- embassy-stm32/Cargo.toml | 4 ++-- examples/stm32l4/Cargo.toml | 2 +- tests/stm32/Cargo.toml | 8 +++++--- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/.github/ci/test.sh b/.github/ci/test.sh index c78865e54..88962a533 100755 --- a/.github/ci/test.sh +++ b/.github/ci/test.sh @@ -29,8 +29,8 @@ cargo test --manifest-path ./embassy-nrf/Cargo.toml --no-default-features --feat cargo test --manifest-path ./embassy-rp/Cargo.toml --no-default-features --features time-driver,rp2040,_test cargo test --manifest-path ./embassy-rp/Cargo.toml --no-default-features --features time-driver,rp235xa,_test -cargo test --manifest-path ./embassy-stm32/Cargo.toml --no-default-features --features stm32f429vg,exti,time-driver-any,exti +cargo test --manifest-path ./embassy-stm32/Cargo.toml --no-default-features --features stm32f429vg,exti,time-driver-any,exti,dual-bank cargo test --manifest-path ./embassy-stm32/Cargo.toml --no-default-features --features stm32f732ze,exti,time-driver-any,exti -cargo test --manifest-path ./embassy-stm32/Cargo.toml --no-default-features --features stm32f769ni,exti,time-driver-any,exti +cargo test --manifest-path ./embassy-stm32/Cargo.toml --no-default-features --features stm32f769ni,exti,time-driver-any,exti,single-bank cargo test --manifest-path ./embassy-net-adin1110/Cargo.toml diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 5ed5c3519..ec22325f9 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -74,7 +74,7 @@ sdio-host = "0.9.0" critical-section = "1.1" #stm32-metapac = { version = "16" } # stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-380f03cb71f43a242adc45e83607a380ffe0447b" } -stm32-metapac = { git="https://ci.embassy.dev/jobs/039aa6808ef1/artifacts/generated.git" } +stm32-metapac = { git="https://ci.embassy.dev/jobs/3de13111608a/artifacts/generated.git" } vcell = "0.1.3" nb = "1.0.0" @@ -104,7 +104,7 @@ quote = "1.0.15" #stm32-metapac = { version = "16", default-features = false, features = ["metadata"]} # stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-380f03cb71f43a242adc45e83607a380ffe0447b", default-features = false, features = ["metadata"] } -stm32-metapac = { git="https://ci.embassy.dev/jobs/039aa6808ef1/artifacts/generated.git", default-features = false, features = ["metadata"] } +stm32-metapac = { git="https://ci.embassy.dev/jobs/3de13111608a/artifacts/generated.git", default-features = false, features = ["metadata"] } [features] default = ["rt"] diff --git a/examples/stm32l4/Cargo.toml b/examples/stm32l4/Cargo.toml index b609110af..239bfcd79 100644 --- a/examples/stm32l4/Cargo.toml +++ b/examples/stm32l4/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32l4s5vi to your chip name, if necessary. -embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32l4r5zi", "memory-x", "time-driver-any", "exti", "chrono"] } +embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32l4r5zi", "memory-x", "time-driver-any", "exti", "chrono", "dual-bank"] } embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768", ] } diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml index a676aee53..3a347e279 100644 --- a/tests/stm32/Cargo.toml +++ b/tests/stm32/Cargo.toml @@ -12,7 +12,7 @@ stm32f207zg = ["embassy-stm32/stm32f207zg", "spi-v1", "chrono", "not-gpdma", "et stm32f303ze = ["embassy-stm32/stm32f303ze", "chrono", "not-gpdma"] stm32f429zi = ["embassy-stm32/stm32f429zi", "spi-v1", "chrono", "eth", "stop", "can", "not-gpdma", "dac", "rng"] stm32f446re = ["embassy-stm32/stm32f446re", "spi-v1", "chrono", "stop", "can", "not-gpdma", "dac", "sdmmc"] -stm32f767zi = ["embassy-stm32/stm32f767zi", "chrono", "not-gpdma", "eth", "rng"] +stm32f767zi = ["embassy-stm32/stm32f767zi", "chrono", "not-gpdma", "eth", "rng", "single-bank"] stm32g071rb = ["embassy-stm32/stm32g071rb", "cm0", "not-gpdma", "dac", "ucpd"] stm32g491re = ["embassy-stm32/stm32g491re", "chrono", "stop", "not-gpdma", "rng", "fdcan", "cordic"] stm32h563zi = ["embassy-stm32/stm32h563zi", "spi-v345", "chrono", "eth", "rng", "fdcan", "hash", "cordic", "stop"] @@ -23,8 +23,8 @@ stm32l073rz = ["embassy-stm32/stm32l073rz", "cm0", "not-gpdma", "rng"] stm32l152re = ["embassy-stm32/stm32l152re", "spi-v1", "chrono", "not-gpdma"] stm32l496zg = ["embassy-stm32/stm32l496zg", "not-gpdma", "rng"] stm32l4a6zg = ["embassy-stm32/stm32l4a6zg", "chrono", "not-gpdma", "rng", "hash"] -stm32l4r5zi = ["embassy-stm32/stm32l4r5zi", "chrono", "not-gpdma", "rng"] -stm32l552ze = ["embassy-stm32/stm32l552ze", "not-gpdma", "rng", "hash"] +stm32l4r5zi = ["embassy-stm32/stm32l4r5zi", "chrono", "not-gpdma", "rng", "dual-bank"] +stm32l552ze = ["embassy-stm32/stm32l552ze", "not-gpdma", "rng", "hash", "dual-bank"] stm32u585ai = ["embassy-stm32/stm32u585ai", "spi-v345", "chrono", "rng", "hash", "cordic"] stm32u5a5zj = ["embassy-stm32/stm32u5a5zj", "spi-v345", "chrono", "rng", "hash"] # FIXME: cordic test cause it crash stm32wb55rg = ["embassy-stm32/stm32wb55rg", "chrono", "not-gpdma", "ble", "mac" , "rng"] @@ -53,6 +53,8 @@ not-gpdma = [] dac = [] ucpd = [] cordic = ["dep:num-traits"] +dual-bank = ["embassy-stm32/dual-bank"] +single-bank = ["embassy-stm32/single-bank"] cm0 = ["portable-atomic/unsafe-assume-single-core"] From a83726b77e1f40293b6c0701c7d203160bc150fb Mon Sep 17 00:00:00 2001 From: Dion Dokter Date: Thu, 1 May 2025 11:15:14 +0200 Subject: [PATCH 1040/1217] Fix the f4 flash tests by throwing away alt mode --- embassy-stm32/src/flash/f4.rs | 299 +++++++--------------------------- 1 file changed, 59 insertions(+), 240 deletions(-) diff --git a/embassy-stm32/src/flash/f4.rs b/embassy-stm32/src/flash/f4.rs index ba3067556..7d789a6bb 100644 --- a/embassy-stm32/src/flash/f4.rs +++ b/embassy-stm32/src/flash/f4.rs @@ -8,173 +8,6 @@ use super::{FlashBank, FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; use crate::_generated::FLASH_SIZE; use crate::flash::Error; use crate::pac; -#[allow(missing_docs)] // TODO -#[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479))] -mod alt_regions { - use core::marker::PhantomData; - - use crate::Peri; - use crate::_generated::flash_regions::{OTPRegion, BANK1_REGION1, BANK1_REGION2, BANK1_REGION3, OTP_REGION}; - use crate::_generated::FLASH_SIZE; - use crate::flash::{asynch, Async, Bank1Region1, Bank1Region2, Blocking, Error, Flash, FlashBank, FlashRegion}; - use crate::peripherals::FLASH; - - pub const ALT_BANK1_REGION3: FlashRegion = FlashRegion { - size: 3 * BANK1_REGION3.erase_size, - ..BANK1_REGION3 - }; - pub const ALT_BANK2_REGION1: FlashRegion = FlashRegion { - bank: FlashBank::Bank2, - base: BANK1_REGION1.base + FLASH_SIZE as u32 / 2, - ..BANK1_REGION1 - }; - pub const ALT_BANK2_REGION2: FlashRegion = FlashRegion { - bank: FlashBank::Bank2, - base: BANK1_REGION2.base + FLASH_SIZE as u32 / 2, - ..BANK1_REGION2 - }; - pub const ALT_BANK2_REGION3: FlashRegion = FlashRegion { - bank: FlashBank::Bank2, - base: BANK1_REGION3.base + FLASH_SIZE as u32 / 2, - size: 3 * BANK1_REGION3.erase_size, - ..BANK1_REGION3 - }; - - pub const ALT_FLASH_REGIONS: [&FlashRegion; 6] = [ - &BANK1_REGION1, - &BANK1_REGION2, - &ALT_BANK1_REGION3, - &ALT_BANK2_REGION1, - &ALT_BANK2_REGION2, - &ALT_BANK2_REGION3, - ]; - - pub struct AltBank1Region3<'d, MODE = Async>(pub &'static FlashRegion, Peri<'d, FLASH>, PhantomData); - pub struct AltBank2Region1<'d, MODE = Async>(pub &'static FlashRegion, Peri<'d, FLASH>, PhantomData); - pub struct AltBank2Region2<'d, MODE = Async>(pub &'static FlashRegion, Peri<'d, FLASH>, PhantomData); - pub struct AltBank2Region3<'d, MODE = Async>(pub &'static FlashRegion, Peri<'d, FLASH>, PhantomData); - - pub struct AltFlashLayout<'d, MODE = Async> { - pub bank1_region1: Bank1Region1<'d, MODE>, - pub bank1_region2: Bank1Region2<'d, MODE>, - pub bank1_region3: AltBank1Region3<'d, MODE>, - pub bank2_region1: AltBank2Region1<'d, MODE>, - pub bank2_region2: AltBank2Region2<'d, MODE>, - pub bank2_region3: AltBank2Region3<'d, MODE>, - pub otp_region: OTPRegion<'d, MODE>, - } - - impl<'d> Flash<'d> { - pub fn into_alt_regions(self) -> AltFlashLayout<'d, Async> { - assert!(!super::is_default_layout()); - - // SAFETY: We never expose the cloned peripheral references, and their instance is not public. - // Also, all async flash region operations are protected with a mutex. - let p = self.inner; - AltFlashLayout { - bank1_region1: Bank1Region1(&BANK1_REGION1, unsafe { p.clone_unchecked() }, PhantomData), - bank1_region2: Bank1Region2(&BANK1_REGION2, unsafe { p.clone_unchecked() }, PhantomData), - bank1_region3: AltBank1Region3(&ALT_BANK1_REGION3, unsafe { p.clone_unchecked() }, PhantomData), - bank2_region1: AltBank2Region1(&ALT_BANK2_REGION1, unsafe { p.clone_unchecked() }, PhantomData), - bank2_region2: AltBank2Region2(&ALT_BANK2_REGION2, unsafe { p.clone_unchecked() }, PhantomData), - bank2_region3: AltBank2Region3(&ALT_BANK2_REGION3, unsafe { p.clone_unchecked() }, PhantomData), - otp_region: OTPRegion(&OTP_REGION, unsafe { p.clone_unchecked() }, PhantomData), - } - } - - pub fn into_alt_blocking_regions(self) -> AltFlashLayout<'d, Blocking> { - assert!(!super::is_default_layout()); - - // SAFETY: We never expose the cloned peripheral references, and their instance is not public. - // Also, all blocking flash region operations are protected with a cs. - let p = self.inner; - AltFlashLayout { - bank1_region1: Bank1Region1(&BANK1_REGION1, unsafe { p.clone_unchecked() }, PhantomData), - bank1_region2: Bank1Region2(&BANK1_REGION2, unsafe { p.clone_unchecked() }, PhantomData), - bank1_region3: AltBank1Region3(&ALT_BANK1_REGION3, unsafe { p.clone_unchecked() }, PhantomData), - bank2_region1: AltBank2Region1(&ALT_BANK2_REGION1, unsafe { p.clone_unchecked() }, PhantomData), - bank2_region2: AltBank2Region2(&ALT_BANK2_REGION2, unsafe { p.clone_unchecked() }, PhantomData), - bank2_region3: AltBank2Region3(&ALT_BANK2_REGION3, unsafe { p.clone_unchecked() }, PhantomData), - otp_region: OTPRegion(&OTP_REGION, unsafe { p.clone_unchecked() }, PhantomData), - } - } - } - - macro_rules! foreach_altflash_region { - ($type_name:ident, $region:ident) => { - impl $type_name<'_, MODE> { - pub fn blocking_read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { - crate::flash::common::blocking_read(self.0.base, self.0.size, offset, bytes) - } - } - - impl $type_name<'_, Async> { - pub async fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { - self.blocking_read(offset, bytes) - } - - pub async fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> { - let _guard = asynch::REGION_ACCESS.lock().await; - unsafe { asynch::write_chunked(self.0.base, self.0.size, offset, bytes).await } - } - - pub async fn erase(&mut self, from: u32, to: u32) -> Result<(), Error> { - let _guard = asynch::REGION_ACCESS.lock().await; - unsafe { asynch::erase_sectored(self.0.base, from, to).await } - } - } - - impl embedded_storage::nor_flash::ErrorType for $type_name<'_, MODE> { - type Error = Error; - } - - impl embedded_storage::nor_flash::ReadNorFlash for $type_name<'_, MODE> { - const READ_SIZE: usize = crate::flash::READ_SIZE; - - fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { - self.blocking_read(offset, bytes) - } - - fn capacity(&self) -> usize { - self.0.size as usize - } - } - - impl embedded_storage_async::nor_flash::ReadNorFlash for $type_name<'_, Async> { - const READ_SIZE: usize = crate::flash::READ_SIZE; - - async fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { - self.read(offset, bytes).await - } - - fn capacity(&self) -> usize { - self.0.size as usize - } - } - - impl embedded_storage_async::nor_flash::NorFlash for $type_name<'_, Async> { - const WRITE_SIZE: usize = $region.write_size as usize; - const ERASE_SIZE: usize = $region.erase_size as usize; - - async fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> { - self.write(offset, bytes).await - } - - async fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> { - self.erase(from, to).await - } - } - }; - } - - foreach_altflash_region!(AltBank1Region3, ALT_BANK1_REGION3); - foreach_altflash_region!(AltBank2Region1, ALT_BANK2_REGION1); - foreach_altflash_region!(AltBank2Region2, ALT_BANK2_REGION2); - foreach_altflash_region!(AltBank2Region3, ALT_BANK2_REGION3); -} - -#[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479))] -pub use alt_regions::*; static WAKER: AtomicWaker = AtomicWaker::new(); static DATA_CACHE_WAS_ENABLED: AtomicBool = AtomicBool::new(false); @@ -185,26 +18,10 @@ impl FlashSector { } } -#[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479))] -pub(crate) fn is_default_layout() -> bool { - !pac::FLASH.optcr().read().db1m() -} - -#[cfg(not(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479)))] pub(crate) const fn is_default_layout() -> bool { true } -#[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479))] -pub fn get_flash_regions() -> &'static [&'static FlashRegion] { - if is_default_layout() { - &FLASH_REGIONS - } else { - &ALT_FLASH_REGIONS - } -} - -#[cfg(not(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f469, stm32f479)))] pub const fn get_flash_regions() -> &'static [&'static FlashRegion] { &FLASH_REGIONS } @@ -487,72 +304,74 @@ mod tests { const MEDIUM_SECTOR_SIZE: u32 = 64 * 1024; const LARGE_SECTOR_SIZE: u32 = 128 * 1024; - let assert_sector = |snb: u8, index_in_bank: u8, start: u32, size: u32, address: u32| { - let sector = get_sector(address, &FLASH_REGIONS); - assert_eq!(snb, sector.snb()); - assert_eq!( - FlashSector { - bank: FlashBank::Bank1, - index_in_bank, - start, - size - }, - sector - ); - }; + if !cfg!(feature = "dual-bank") { + let assert_sector = |snb: u8, index_in_bank: u8, start: u32, size: u32, address: u32| { + let sector = get_sector(address, &FLASH_REGIONS); + assert_eq!(snb, sector.snb()); + assert_eq!( + FlashSector { + bank: sector.bank, + index_in_bank, + start, + size + }, + sector + ); + }; - assert_sector(0x00, 0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_0000); - assert_sector(0x00, 0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_3FFF); - assert_sector(0x03, 3, 0x0800_C000, SMALL_SECTOR_SIZE, 0x0800_C000); - assert_sector(0x03, 3, 0x0800_C000, SMALL_SECTOR_SIZE, 0x0800_FFFF); + assert_sector(0x00, 0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_0000); + assert_sector(0x00, 0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_3FFF); + assert_sector(0x03, 3, 0x0800_C000, SMALL_SECTOR_SIZE, 0x0800_C000); + assert_sector(0x03, 3, 0x0800_C000, SMALL_SECTOR_SIZE, 0x0800_FFFF); - assert_sector(0x04, 4, 0x0801_0000, MEDIUM_SECTOR_SIZE, 0x0801_0000); - assert_sector(0x04, 4, 0x0801_0000, MEDIUM_SECTOR_SIZE, 0x0801_FFFF); + assert_sector(0x04, 4, 0x0801_0000, MEDIUM_SECTOR_SIZE, 0x0801_0000); + assert_sector(0x04, 4, 0x0801_0000, MEDIUM_SECTOR_SIZE, 0x0801_FFFF); - assert_sector(0x05, 5, 0x0802_0000, LARGE_SECTOR_SIZE, 0x0802_0000); - assert_sector(0x05, 5, 0x0802_0000, LARGE_SECTOR_SIZE, 0x0803_FFFF); - assert_sector(0x0B, 11, 0x080E_0000, LARGE_SECTOR_SIZE, 0x080E_0000); - assert_sector(0x0B, 11, 0x080E_0000, LARGE_SECTOR_SIZE, 0x080F_FFFF); + assert_sector(0x05, 5, 0x0802_0000, LARGE_SECTOR_SIZE, 0x0802_0000); + assert_sector(0x05, 5, 0x0802_0000, LARGE_SECTOR_SIZE, 0x0803_FFFF); + assert_sector(0x0B, 11, 0x080E_0000, LARGE_SECTOR_SIZE, 0x080E_0000); + assert_sector(0x0B, 11, 0x080E_0000, LARGE_SECTOR_SIZE, 0x080F_FFFF); + } else { + let assert_sector = |snb: u8, bank: FlashBank, index_in_bank: u8, start: u32, size: u32, address: u32| { + let sector = get_sector(address, &FLASH_REGIONS); + assert_eq!(snb, sector.snb()); + assert_eq!( + FlashSector { + bank, + index_in_bank, + start, + size + }, + sector + ) + }; - let assert_sector = |snb: u8, bank: FlashBank, index_in_bank: u8, start: u32, size: u32, address: u32| { - let sector = get_sector(address, &ALT_FLASH_REGIONS); - assert_eq!(snb, sector.snb()); - assert_eq!( - FlashSector { - bank, - index_in_bank, - start, - size - }, - sector - ) - }; + assert_sector(0x00, FlashBank::Bank1, 0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_0000); + assert_sector(0x00, FlashBank::Bank1, 0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_3FFF); + assert_sector(0x03, FlashBank::Bank1, 3, 0x0800_C000, SMALL_SECTOR_SIZE, 0x0800_C000); + assert_sector(0x03, FlashBank::Bank1, 3, 0x0800_C000, SMALL_SECTOR_SIZE, 0x0800_FFFF); - assert_sector(0x00, FlashBank::Bank1, 0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_0000); - assert_sector(0x00, FlashBank::Bank1, 0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_3FFF); - assert_sector(0x03, FlashBank::Bank1, 3, 0x0800_C000, SMALL_SECTOR_SIZE, 0x0800_C000); - assert_sector(0x03, FlashBank::Bank1, 3, 0x0800_C000, SMALL_SECTOR_SIZE, 0x0800_FFFF); + assert_sector(0x04, FlashBank::Bank1, 4, 0x0801_0000, MEDIUM_SECTOR_SIZE, 0x0801_0000); + assert_sector(0x04, FlashBank::Bank1, 4, 0x0801_0000, MEDIUM_SECTOR_SIZE, 0x0801_FFFF); - assert_sector(0x04, FlashBank::Bank1, 4, 0x0801_0000, MEDIUM_SECTOR_SIZE, 0x0801_0000); - assert_sector(0x04, FlashBank::Bank1, 4, 0x0801_0000, MEDIUM_SECTOR_SIZE, 0x0801_FFFF); + assert_sector(0x05, FlashBank::Bank1, 5, 0x0802_0000, LARGE_SECTOR_SIZE, 0x0802_0000); + assert_sector(0x05, FlashBank::Bank1, 5, 0x0802_0000, LARGE_SECTOR_SIZE, 0x0803_FFFF); + assert_sector(0x07, FlashBank::Bank1, 7, 0x0806_0000, LARGE_SECTOR_SIZE, 0x0806_0000); + assert_sector(0x07, FlashBank::Bank1, 7, 0x0806_0000, LARGE_SECTOR_SIZE, 0x0807_FFFF); - assert_sector(0x05, FlashBank::Bank1, 5, 0x0802_0000, LARGE_SECTOR_SIZE, 0x0802_0000); - assert_sector(0x05, FlashBank::Bank1, 5, 0x0802_0000, LARGE_SECTOR_SIZE, 0x0803_FFFF); - assert_sector(0x07, FlashBank::Bank1, 7, 0x0806_0000, LARGE_SECTOR_SIZE, 0x0806_0000); - assert_sector(0x07, FlashBank::Bank1, 7, 0x0806_0000, LARGE_SECTOR_SIZE, 0x0807_FFFF); + assert_sector(0x10, FlashBank::Bank2, 0, 0x0808_0000, SMALL_SECTOR_SIZE, 0x0808_0000); + assert_sector(0x10, FlashBank::Bank2, 0, 0x0808_0000, SMALL_SECTOR_SIZE, 0x0808_3FFF); + assert_sector(0x13, FlashBank::Bank2, 3, 0x0808_C000, SMALL_SECTOR_SIZE, 0x0808_C000); + assert_sector(0x13, FlashBank::Bank2, 3, 0x0808_C000, SMALL_SECTOR_SIZE, 0x0808_FFFF); - assert_sector(0x10, FlashBank::Bank2, 0, 0x0808_0000, SMALL_SECTOR_SIZE, 0x0808_0000); - assert_sector(0x10, FlashBank::Bank2, 0, 0x0808_0000, SMALL_SECTOR_SIZE, 0x0808_3FFF); - assert_sector(0x13, FlashBank::Bank2, 3, 0x0808_C000, SMALL_SECTOR_SIZE, 0x0808_C000); - assert_sector(0x13, FlashBank::Bank2, 3, 0x0808_C000, SMALL_SECTOR_SIZE, 0x0808_FFFF); + assert_sector(0x14, FlashBank::Bank2, 4, 0x0809_0000, MEDIUM_SECTOR_SIZE, 0x0809_0000); + assert_sector(0x14, FlashBank::Bank2, 4, 0x0809_0000, MEDIUM_SECTOR_SIZE, 0x0809_FFFF); - assert_sector(0x14, FlashBank::Bank2, 4, 0x0809_0000, MEDIUM_SECTOR_SIZE, 0x0809_0000); - assert_sector(0x14, FlashBank::Bank2, 4, 0x0809_0000, MEDIUM_SECTOR_SIZE, 0x0809_FFFF); - - assert_sector(0x15, FlashBank::Bank2, 5, 0x080A_0000, LARGE_SECTOR_SIZE, 0x080A_0000); - assert_sector(0x15, FlashBank::Bank2, 5, 0x080A_0000, LARGE_SECTOR_SIZE, 0x080B_FFFF); - assert_sector(0x17, FlashBank::Bank2, 7, 0x080E_0000, LARGE_SECTOR_SIZE, 0x080E_0000); - assert_sector(0x17, FlashBank::Bank2, 7, 0x080E_0000, LARGE_SECTOR_SIZE, 0x080F_FFFF); + assert_sector(0x15, FlashBank::Bank2, 5, 0x080A_0000, LARGE_SECTOR_SIZE, 0x080A_0000); + assert_sector(0x15, FlashBank::Bank2, 5, 0x080A_0000, LARGE_SECTOR_SIZE, 0x080B_FFFF); + assert_sector(0x17, FlashBank::Bank2, 7, 0x080E_0000, LARGE_SECTOR_SIZE, 0x080E_0000); + assert_sector(0x17, FlashBank::Bank2, 7, 0x080E_0000, LARGE_SECTOR_SIZE, 0x080F_FFFF); + } } } From 28a98ed0df5a6536190e267e46bc6822c532dba6 Mon Sep 17 00:00:00 2001 From: Dion Dokter Date: Thu, 1 May 2025 11:20:38 +0200 Subject: [PATCH 1041/1217] Fix f7 example --- examples/stm32f7/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/stm32f7/Cargo.toml b/examples/stm32f7/Cargo.toml index 9fbe2efc3..1a46931d9 100644 --- a/examples/stm32f7/Cargo.toml +++ b/examples/stm32f7/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32f777zi to your chip name, if necessary. -embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = ["defmt", "stm32f777zi", "memory-x", "unstable-pac", "time-driver-any", "exti"] } +embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = ["defmt", "stm32f777zi", "memory-x", "unstable-pac", "time-driver-any", "exti", "single-bank"] } embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } From 66b8fdc818cd9faba6919b0c57fd1938546cca9e Mon Sep 17 00:00:00 2001 From: Dion Dokter Date: Thu, 1 May 2025 11:28:57 +0200 Subject: [PATCH 1042/1217] Fix f7 boot example --- examples/boot/application/stm32f7/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/boot/application/stm32f7/Cargo.toml b/examples/boot/application/stm32f7/Cargo.toml index 6a5a500de..d62c67742 100644 --- a/examples/boot/application/stm32f7/Cargo.toml +++ b/examples/boot/application/stm32f7/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" embassy-sync = { version = "0.6.2", path = "../../../../embassy-sync" } embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } -embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32f767zi", "time-driver-any", "exti"] } +embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32f767zi", "time-driver-any", "exti", "single-bank"] } embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } embassy-embedded-hal = { version = "0.3.0", path = "../../../../embassy-embedded-hal" } From cff6eb9a81a34f7e7437f30470c0914177ca3a27 Mon Sep 17 00:00:00 2001 From: Dion Dokter Date: Thu, 1 May 2025 11:52:22 +0200 Subject: [PATCH 1043/1217] Fix more CI --- ci.sh | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/ci.sh b/ci.sh index 5a438f0b1..6e320e4d1 100755 --- a/ci.sh +++ b/ci.sh @@ -88,16 +88,17 @@ cargo batch \ --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv8m.main-none-eabihf --features time-driver,defmt,rp235xa \ --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv8m.main-none-eabihf --features time-driver,log,rp235xa \ --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv8m.main-none-eabihf --features time-driver,rp235xa,binary-info \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,exti,time-driver-any,time \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,time-driver-any,time \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,exti,time \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,time \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,exti,time-driver-any,time \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,time-driver-any,time \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,exti,time \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,time \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,exti \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,dual-bank,defmt,exti,time-driver-any,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,dual-bank,defmt,time-driver-any,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,dual-bank,defmt,exti,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,dual-bank,defmt,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,dual-bank,defmt,exti,time-driver-any,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,dual-bank,defmt,time-driver-any,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,dual-bank,defmt,exti,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,dual-bank,defmt,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,dual-bank,defmt,exti \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,dual-bank,defmt \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,single-bank,defmt \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32f038f6,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32f030c6,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32f058t8,defmt,exti,time-driver-any,time \ @@ -153,10 +154,10 @@ cargo batch \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f378cc,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32g0c1ve,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f217zg,defmt,exti,time-driver-any,time \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,exti,time-driver-any,low-power,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,dual-bank,defmt,exti,time-driver-any,low-power,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32wl54jc-cm0p,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wle5jb,defmt,exti,time-driver-any,time \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32g474pe,defmt,exti,time-driver-any,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32g474pe,dual-bank,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f107vc,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f103re,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f100c4,defmt,exti,time-driver-any,time \ From 59d839a2b8a488bf1e9056f46ba1dff61148642b Mon Sep 17 00:00:00 2001 From: Dion Dokter Date: Thu, 1 May 2025 13:37:12 +0200 Subject: [PATCH 1044/1217] Fix dual bank support for F7 --- .github/ci/test.sh | 8 +++-- embassy-stm32/src/flash/f7.rs | 57 +++++++++++++++++++++++++++++++++-- 2 files changed, 60 insertions(+), 5 deletions(-) diff --git a/.github/ci/test.sh b/.github/ci/test.sh index 88962a533..c9b332cf8 100755 --- a/.github/ci/test.sh +++ b/.github/ci/test.sh @@ -29,8 +29,10 @@ cargo test --manifest-path ./embassy-nrf/Cargo.toml --no-default-features --feat cargo test --manifest-path ./embassy-rp/Cargo.toml --no-default-features --features time-driver,rp2040,_test cargo test --manifest-path ./embassy-rp/Cargo.toml --no-default-features --features time-driver,rp235xa,_test -cargo test --manifest-path ./embassy-stm32/Cargo.toml --no-default-features --features stm32f429vg,exti,time-driver-any,exti,dual-bank -cargo test --manifest-path ./embassy-stm32/Cargo.toml --no-default-features --features stm32f732ze,exti,time-driver-any,exti -cargo test --manifest-path ./embassy-stm32/Cargo.toml --no-default-features --features stm32f769ni,exti,time-driver-any,exti,single-bank +cargo test --manifest-path ./embassy-stm32/Cargo.toml --no-default-features --features stm32f429vg,time-driver-any,exti,single-bank +cargo test --manifest-path ./embassy-stm32/Cargo.toml --no-default-features --features stm32f429vg,time-driver-any,exti,dual-bank +cargo test --manifest-path ./embassy-stm32/Cargo.toml --no-default-features --features stm32f732ze,time-driver-any,exti +cargo test --manifest-path ./embassy-stm32/Cargo.toml --no-default-features --features stm32f769ni,time-driver-any,exti,single-bank +cargo test --manifest-path ./embassy-stm32/Cargo.toml --no-default-features --features stm32f769ni,time-driver-any,exti,dual-bank cargo test --manifest-path ./embassy-net-adin1110/Cargo.toml diff --git a/embassy-stm32/src/flash/f7.rs b/embassy-stm32/src/flash/f7.rs index 043382590..27a7afadf 100644 --- a/embassy-stm32/src/flash/f7.rs +++ b/embassy-stm32/src/flash/f7.rs @@ -5,6 +5,12 @@ use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; use crate::flash::Error; use crate::pac; +impl FlashSector { + const fn snb(&self) -> u8 { + ((self.bank as u8) << 4) + self.index_in_bank + } +} + pub(crate) const fn is_default_layout() -> bool { true } @@ -53,7 +59,7 @@ pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> { pac::FLASH.cr().modify(|w| { w.set_ser(true); - w.set_snb(sector.index_in_bank) + w.set_snb(sector.snb()) }); pac::FLASH.cr().modify(|w| { @@ -137,7 +143,7 @@ mod tests { } #[test] - #[cfg(stm32f769)] + #[cfg(all(stm32f769, feature = "single-bank"))] fn can_get_sector() { const SMALL_SECTOR_SIZE: u32 = 32 * 1024; const MEDIUM_SECTOR_SIZE: u32 = 128 * 1024; @@ -168,6 +174,53 @@ mod tests { assert_sector(7, 0x080C_0000, LARGE_SECTOR_SIZE, 0x080C_0000); assert_sector(7, 0x080C_0000, LARGE_SECTOR_SIZE, 0x080F_FFFF); } + + #[test] + #[cfg(all(stm32f769, feature = "dual-bank"))] + fn can_get_sector() { + const SMALL_SECTOR_SIZE: u32 = 16 * 1024; + const MEDIUM_SECTOR_SIZE: u32 = 64 * 1024; + const LARGE_SECTOR_SIZE: u32 = 128 * 1024; + + let assert_sector = |index_in_bank: u8, start: u32, size: u32, address: u32, snb: u8, bank: FlashBank| { + assert_eq!( + FlashSector { + bank: bank, + index_in_bank, + start, + size + }, + get_sector(address, &FLASH_REGIONS) + ); + assert_eq!(get_sector(address, &FLASH_REGIONS).snb(), snb); + }; + + assert_sector(0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_0000, 0x00, FlashBank::Bank1); + assert_sector(0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_3FFF, 0x00, FlashBank::Bank1); + assert_sector(3, 0x0800_C000, SMALL_SECTOR_SIZE, 0x0800_C000, 0x03, FlashBank::Bank1); + assert_sector(3, 0x0800_C000, SMALL_SECTOR_SIZE, 0x0800_FFFF, 0x03, FlashBank::Bank1); + + assert_sector(4, 0x0801_0000, MEDIUM_SECTOR_SIZE, 0x0801_0000, 0x04, FlashBank::Bank1); + assert_sector(4, 0x0801_0000, MEDIUM_SECTOR_SIZE, 0x0801_FFFF, 0x04, FlashBank::Bank1); + + assert_sector(5, 0x0802_0000, LARGE_SECTOR_SIZE, 0x0802_0000, 0x05, FlashBank::Bank1); + assert_sector(5, 0x0802_0000, LARGE_SECTOR_SIZE, 0x0803_FFFF, 0x05, FlashBank::Bank1); + assert_sector(10, 0x080C_0000, LARGE_SECTOR_SIZE, 0x080C_0000, 0x0A, FlashBank::Bank1); + assert_sector(10, 0x080C_0000, LARGE_SECTOR_SIZE, 0x080D_FFFF, 0x0A, FlashBank::Bank1); + + assert_sector(0, 0x0810_0000, SMALL_SECTOR_SIZE, 0x0810_0000, 0x10, FlashBank::Bank2); + assert_sector(0, 0x0810_0000, SMALL_SECTOR_SIZE, 0x0810_3FFF, 0x10, FlashBank::Bank2); + assert_sector(3, 0x0810_C000, SMALL_SECTOR_SIZE, 0x0810_C000, 0x13, FlashBank::Bank2); + assert_sector(3, 0x0810_C000, SMALL_SECTOR_SIZE, 0x0810_FFFF, 0x13, FlashBank::Bank2); + + assert_sector(4, 0x0811_0000, MEDIUM_SECTOR_SIZE, 0x0811_0000, 0x14, FlashBank::Bank2); + assert_sector(4, 0x0811_0000, MEDIUM_SECTOR_SIZE, 0x0811_FFFF, 0x14, FlashBank::Bank2); + + assert_sector(5, 0x0812_0000, LARGE_SECTOR_SIZE, 0x0812_0000, 0x15, FlashBank::Bank2); + assert_sector(5, 0x0812_0000, LARGE_SECTOR_SIZE, 0x0813_FFFF, 0x15, FlashBank::Bank2); + assert_sector(10, 0x081C_0000, LARGE_SECTOR_SIZE, 0x081C_0000, 0x1A, FlashBank::Bank2); + assert_sector(10, 0x081C_0000, LARGE_SECTOR_SIZE, 0x081D_FFFF, 0x1A, FlashBank::Bank2); + } } #[cfg(all(bank_setup_configurable))] From e478bdf1df1c41cee0fd0aad29a66db4cf6f93f5 Mon Sep 17 00:00:00 2001 From: Dion Dokter Date: Thu, 1 May 2025 13:49:29 +0200 Subject: [PATCH 1045/1217] Remove all notion of 'default' and 'alt' flash layouts. Now there's just the one layout. --- embassy-stm32/src/flash/asynch.rs | 7 +++---- embassy-stm32/src/flash/common.rs | 7 +++---- embassy-stm32/src/flash/f0.rs | 10 +--------- embassy-stm32/src/flash/f1f3.rs | 10 +--------- embassy-stm32/src/flash/f2.rs | 10 +--------- embassy-stm32/src/flash/f4.rs | 14 +++----------- embassy-stm32/src/flash/f7.rs | 18 +++++------------- embassy-stm32/src/flash/g.rs | 10 +--------- embassy-stm32/src/flash/h5.rs | 14 +------------- embassy-stm32/src/flash/h50.rs | 10 +--------- embassy-stm32/src/flash/h7.rs | 10 +--------- embassy-stm32/src/flash/l.rs | 10 +--------- embassy-stm32/src/flash/mod.rs | 10 +--------- embassy-stm32/src/flash/other.rs | 10 +--------- embassy-stm32/src/flash/u0.rs | 10 +--------- embassy-stm32/src/flash/u5.rs | 10 +--------- 16 files changed, 26 insertions(+), 144 deletions(-) diff --git a/embassy-stm32/src/flash/asynch.rs b/embassy-stm32/src/flash/asynch.rs index 599b7bb4e..006dcddeb 100644 --- a/embassy-stm32/src/flash/asynch.rs +++ b/embassy-stm32/src/flash/asynch.rs @@ -6,8 +6,8 @@ use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::mutex::Mutex; use super::{ - blocking_read, ensure_sector_aligned, family, get_sector, Async, Error, Flash, FlashLayout, FLASH_BASE, FLASH_SIZE, - WRITE_SIZE, + blocking_read, ensure_sector_aligned, family, get_flash_regions, get_sector, Async, Error, Flash, FlashLayout, + FLASH_BASE, FLASH_SIZE, WRITE_SIZE, }; use crate::interrupt::InterruptExt; use crate::peripherals::FLASH; @@ -34,7 +34,6 @@ impl<'d> Flash<'d, Async> { /// /// See module-level documentation for details on how memory regions work. pub fn into_regions(self) -> FlashLayout<'d, Async> { - assert!(family::is_default_layout()); FlashLayout::new(self.inner) } @@ -123,7 +122,7 @@ pub(super) async unsafe fn write_chunked(base: u32, size: u32, offset: u32, byte pub(super) async unsafe fn erase_sectored(base: u32, from: u32, to: u32) -> Result<(), Error> { let start_address = base + from; let end_address = base + to; - let regions = family::get_flash_regions(); + let regions = get_flash_regions(); ensure_sector_aligned(start_address, end_address, regions)?; diff --git a/embassy-stm32/src/flash/common.rs b/embassy-stm32/src/flash/common.rs index 93d734b20..10023e637 100644 --- a/embassy-stm32/src/flash/common.rs +++ b/embassy-stm32/src/flash/common.rs @@ -4,8 +4,8 @@ use core::sync::atomic::{fence, Ordering}; use embassy_hal_internal::drop::OnDrop; use super::{ - family, Async, Blocking, Error, FlashBank, FlashLayout, FlashRegion, FlashSector, FLASH_SIZE, MAX_ERASE_SIZE, - READ_SIZE, WRITE_SIZE, + family, get_flash_regions, Async, Blocking, Error, FlashBank, FlashLayout, FlashRegion, FlashSector, FLASH_SIZE, + MAX_ERASE_SIZE, READ_SIZE, WRITE_SIZE, }; use crate::Peri; use crate::_generated::FLASH_BASE; @@ -36,7 +36,6 @@ impl<'d, MODE> Flash<'d, MODE> { /// /// See module-level documentation for details on how memory regions work. pub fn into_blocking_regions(self) -> FlashLayout<'d, Blocking> { - assert!(family::is_default_layout()); FlashLayout::new(self.inner) } @@ -141,7 +140,7 @@ pub(super) unsafe fn blocking_erase( ) -> Result<(), Error> { let start_address = base + from; let end_address = base + to; - let regions = family::get_flash_regions(); + let regions = get_flash_regions(); ensure_sector_aligned(start_address, end_address, regions)?; diff --git a/embassy-stm32/src/flash/f0.rs b/embassy-stm32/src/flash/f0.rs index 402312f68..3f9dbe945 100644 --- a/embassy-stm32/src/flash/f0.rs +++ b/embassy-stm32/src/flash/f0.rs @@ -1,18 +1,10 @@ use core::ptr::write_volatile; use core::sync::atomic::{fence, Ordering}; -use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; +use super::{FlashSector, WRITE_SIZE}; use crate::flash::Error; use crate::pac; -pub(crate) const fn is_default_layout() -> bool { - true -} - -pub(crate) const fn get_flash_regions() -> &'static [&'static FlashRegion] { - &FLASH_REGIONS -} - pub(crate) unsafe fn lock() { pac::FLASH.cr().modify(|w| w.set_lock(true)); } diff --git a/embassy-stm32/src/flash/f1f3.rs b/embassy-stm32/src/flash/f1f3.rs index ec237b9ff..bf9ad2893 100644 --- a/embassy-stm32/src/flash/f1f3.rs +++ b/embassy-stm32/src/flash/f1f3.rs @@ -1,18 +1,10 @@ use core::ptr::write_volatile; use core::sync::atomic::{fence, Ordering}; -use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; +use super::{FlashSector, WRITE_SIZE}; use crate::flash::Error; use crate::pac; -pub(crate) const fn is_default_layout() -> bool { - true -} - -pub(crate) const fn get_flash_regions() -> &'static [&'static FlashRegion] { - &FLASH_REGIONS -} - pub(crate) unsafe fn lock() { pac::FLASH.cr().modify(|w| w.set_lock(true)); } diff --git a/embassy-stm32/src/flash/f2.rs b/embassy-stm32/src/flash/f2.rs index cdab1fd2d..67e380619 100644 --- a/embassy-stm32/src/flash/f2.rs +++ b/embassy-stm32/src/flash/f2.rs @@ -3,7 +3,7 @@ use core::sync::atomic::{fence, AtomicBool, Ordering}; use pac::flash::regs::Sr; -use super::{FlashBank, FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; +use super::{get_flash_regions, FlashBank, FlashSector, WRITE_SIZE}; use crate::flash::Error; use crate::pac; @@ -15,14 +15,6 @@ impl FlashSector { } } -pub(crate) const fn is_default_layout() -> bool { - true -} - -pub(crate) const fn get_flash_regions() -> &'static [&'static FlashRegion] { - &FLASH_REGIONS -} - pub(crate) unsafe fn lock() { pac::FLASH.cr().modify(|w| w.set_lock(true)); } diff --git a/embassy-stm32/src/flash/f4.rs b/embassy-stm32/src/flash/f4.rs index 7d789a6bb..62e0492b5 100644 --- a/embassy-stm32/src/flash/f4.rs +++ b/embassy-stm32/src/flash/f4.rs @@ -4,7 +4,7 @@ use core::sync::atomic::{fence, AtomicBool, Ordering}; use embassy_sync::waitqueue::AtomicWaker; use pac::flash::regs::Sr; -use super::{FlashBank, FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; +use super::{get_flash_regions, FlashBank, FlashSector, WRITE_SIZE}; use crate::_generated::FLASH_SIZE; use crate::flash::Error; use crate::pac; @@ -18,14 +18,6 @@ impl FlashSector { } } -pub(crate) const fn is_default_layout() -> bool { - true -} - -pub const fn get_flash_regions() -> &'static [&'static FlashRegion] { - &FLASH_REGIONS -} - pub(crate) unsafe fn on_interrupt() { // Clear IRQ flags pac::FLASH.sr().write(|w| { @@ -306,7 +298,7 @@ mod tests { if !cfg!(feature = "dual-bank") { let assert_sector = |snb: u8, index_in_bank: u8, start: u32, size: u32, address: u32| { - let sector = get_sector(address, &FLASH_REGIONS); + let sector = get_sector(address, crate::flash::get_flash_regions()); assert_eq!(snb, sector.snb()); assert_eq!( FlashSector { @@ -333,7 +325,7 @@ mod tests { assert_sector(0x0B, 11, 0x080E_0000, LARGE_SECTOR_SIZE, 0x080F_FFFF); } else { let assert_sector = |snb: u8, bank: FlashBank, index_in_bank: u8, start: u32, size: u32, address: u32| { - let sector = get_sector(address, &FLASH_REGIONS); + let sector = get_sector(address, crate::flash::get_flash_regions()); assert_eq!(snb, sector.snb()); assert_eq!( FlashSector { diff --git a/embassy-stm32/src/flash/f7.rs b/embassy-stm32/src/flash/f7.rs index 27a7afadf..0547c747a 100644 --- a/embassy-stm32/src/flash/f7.rs +++ b/embassy-stm32/src/flash/f7.rs @@ -1,7 +1,7 @@ use core::ptr::write_volatile; use core::sync::atomic::{fence, Ordering}; -use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; +use super::{FlashSector, WRITE_SIZE}; use crate::flash::Error; use crate::pac; @@ -11,14 +11,6 @@ impl FlashSector { } } -pub(crate) const fn is_default_layout() -> bool { - true -} - -pub(crate) const fn get_flash_regions() -> &'static [&'static FlashRegion] { - &FLASH_REGIONS -} - pub(crate) unsafe fn lock() { pac::FLASH.cr().modify(|w| w.set_lock(true)); } @@ -124,7 +116,7 @@ mod tests { start, size }, - get_sector(address, &FLASH_REGIONS) + get_sector(address, crate::flash::get_flash_regions()) ) }; @@ -157,7 +149,7 @@ mod tests { start, size }, - get_sector(address, &FLASH_REGIONS) + get_sector(address, crate::flash::get_flash_regions()) ) }; @@ -190,9 +182,9 @@ mod tests { start, size }, - get_sector(address, &FLASH_REGIONS) + get_sector(address, crate::flash::get_flash_regions()) ); - assert_eq!(get_sector(address, &FLASH_REGIONS).snb(), snb); + assert_eq!(get_sector(address, crate::flash::get_flash_regions()).snb(), snb); }; assert_sector(0, 0x0800_0000, SMALL_SECTOR_SIZE, 0x0800_0000, 0x00, FlashBank::Bank1); diff --git a/embassy-stm32/src/flash/g.rs b/embassy-stm32/src/flash/g.rs index 70e472dcf..bc1fd360c 100644 --- a/embassy-stm32/src/flash/g.rs +++ b/embassy-stm32/src/flash/g.rs @@ -3,18 +3,10 @@ use core::sync::atomic::{fence, Ordering}; use cortex_m::interrupt; -use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; +use super::{FlashSector, WRITE_SIZE}; use crate::flash::Error; use crate::pac; -pub(crate) const fn is_default_layout() -> bool { - true -} - -pub(crate) const fn get_flash_regions() -> &'static [&'static FlashRegion] { - &FLASH_REGIONS -} - pub(crate) unsafe fn lock() { pac::FLASH.cr().modify(|w| w.set_lock(true)); } diff --git a/embassy-stm32/src/flash/h5.rs b/embassy-stm32/src/flash/h5.rs index d95de2e38..fd9bfcc75 100644 --- a/embassy-stm32/src/flash/h5.rs +++ b/embassy-stm32/src/flash/h5.rs @@ -1,22 +1,10 @@ use core::ptr::write_volatile; use core::sync::atomic::{fence, Ordering}; -use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; +use super::{FlashSector, WRITE_SIZE}; use crate::flash::Error; use crate::pac; -pub(crate) const fn is_default_layout() -> bool { - true -} - -// const fn is_dual_bank() -> bool { -// FLASH_REGIONS.len() >= 2 -// } - -pub(crate) fn get_flash_regions() -> &'static [&'static FlashRegion] { - &FLASH_REGIONS -} - pub(crate) unsafe fn lock() { if !pac::FLASH.nscr().read().lock() { pac::FLASH.nscr().modify(|r| { diff --git a/embassy-stm32/src/flash/h50.rs b/embassy-stm32/src/flash/h50.rs index 74cd6cc03..f8e210556 100644 --- a/embassy-stm32/src/flash/h50.rs +++ b/embassy-stm32/src/flash/h50.rs @@ -8,17 +8,9 @@ use cortex_m::interrupt; use pac::flash::regs::Nssr; use pac::flash::vals::Bksel; -use super::{Error, FlashBank, FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; +use super::{Error, FlashBank, FlashSector, WRITE_SIZE}; use crate::pac; -pub(crate) const fn is_default_layout() -> bool { - true -} - -pub(crate) const fn get_flash_regions() -> &'static [&'static FlashRegion] { - &FLASH_REGIONS -} - pub(crate) unsafe fn lock() { pac::FLASH.nscr().modify(|w| w.set_lock(true)); } diff --git a/embassy-stm32/src/flash/h7.rs b/embassy-stm32/src/flash/h7.rs index 254915381..f1d84101c 100644 --- a/embassy-stm32/src/flash/h7.rs +++ b/embassy-stm32/src/flash/h7.rs @@ -1,22 +1,14 @@ use core::ptr::write_volatile; use core::sync::atomic::{fence, Ordering}; -use super::{FlashRegion, FlashSector, BANK1_REGION, FLASH_REGIONS, WRITE_SIZE}; +use super::{FlashSector, BANK1_REGION, FLASH_REGIONS, WRITE_SIZE}; use crate::flash::Error; use crate::pac; -pub(crate) const fn is_default_layout() -> bool { - true -} - const fn is_dual_bank() -> bool { FLASH_REGIONS.len() >= 2 } -pub(crate) fn get_flash_regions() -> &'static [&'static FlashRegion] { - &FLASH_REGIONS -} - pub(crate) unsafe fn lock() { pac::FLASH.bank(0).cr().modify(|w| w.set_lock(true)); if is_dual_bank() { diff --git a/embassy-stm32/src/flash/l.rs b/embassy-stm32/src/flash/l.rs index 3b62fa2ee..65cea005c 100644 --- a/embassy-stm32/src/flash/l.rs +++ b/embassy-stm32/src/flash/l.rs @@ -1,18 +1,10 @@ use core::ptr::write_volatile; use core::sync::atomic::{fence, Ordering}; -use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; +use super::{FlashSector, WRITE_SIZE}; use crate::flash::Error; use crate::pac; -pub(crate) const fn is_default_layout() -> bool { - true -} - -pub(crate) const fn get_flash_regions() -> &'static [&'static FlashRegion] { - &FLASH_REGIONS -} - pub(crate) unsafe fn lock() { #[cfg(any(flash_wl, flash_wb, flash_l4))] pac::FLASH.cr().modify(|w| w.set_lock(true)); diff --git a/embassy-stm32/src/flash/mod.rs b/embassy-stm32/src/flash/mod.rs index c7488c8ef..adc45db9c 100644 --- a/embassy-stm32/src/flash/mod.rs +++ b/embassy-stm32/src/flash/mod.rs @@ -14,17 +14,9 @@ pub use common::*; pub use crate::_generated::flash_regions::*; pub use crate::_generated::{FLASH_BASE, FLASH_SIZE, MAX_ERASE_SIZE, WRITE_SIZE}; -/// Get whether the default flash layout is being used. -/// -/// In some chips, dual-bank is not default. This will then return `false` -/// when dual-bank is enabled. -pub fn is_default_layout() -> bool { - family::is_default_layout() -} - /// Get all flash regions. pub fn get_flash_regions() -> &'static [&'static FlashRegion] { - family::get_flash_regions() + &FLASH_REGIONS } /// Read size (always 1) diff --git a/embassy-stm32/src/flash/other.rs b/embassy-stm32/src/flash/other.rs index 20f84a72f..293a79be3 100644 --- a/embassy-stm32/src/flash/other.rs +++ b/embassy-stm32/src/flash/other.rs @@ -1,14 +1,6 @@ #![allow(unused)] -use super::{Error, FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; - -pub(crate) const fn is_default_layout() -> bool { - true -} - -pub(crate) const fn get_flash_regions() -> &'static [&'static FlashRegion] { - &FLASH_REGIONS -} +use super::{Error, FlashSector, WRITE_SIZE}; pub(crate) unsafe fn lock() { unimplemented!(); diff --git a/embassy-stm32/src/flash/u0.rs b/embassy-stm32/src/flash/u0.rs index bfdbd15a5..68d847eca 100644 --- a/embassy-stm32/src/flash/u0.rs +++ b/embassy-stm32/src/flash/u0.rs @@ -3,18 +3,10 @@ use core::sync::atomic::{fence, Ordering}; use cortex_m::interrupt; -use super::{FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; +use super::{FlashSector, WRITE_SIZE}; use crate::flash::Error; use crate::pac; -pub(crate) const fn is_default_layout() -> bool { - true -} - -pub(crate) const fn get_flash_regions() -> &'static [&'static FlashRegion] { - &FLASH_REGIONS -} - pub(crate) unsafe fn lock() { pac::FLASH.cr().modify(|w| w.set_lock(true)); } diff --git a/embassy-stm32/src/flash/u5.rs b/embassy-stm32/src/flash/u5.rs index dad698316..131caa195 100644 --- a/embassy-stm32/src/flash/u5.rs +++ b/embassy-stm32/src/flash/u5.rs @@ -1,18 +1,10 @@ use core::ptr::write_volatile; use core::sync::atomic::{fence, Ordering}; -use super::{FlashBank, FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; +use super::{FlashBank, FlashSector, WRITE_SIZE}; use crate::flash::Error; use crate::pac; -pub(crate) const fn is_default_layout() -> bool { - true -} - -pub(crate) const fn get_flash_regions() -> &'static [&'static FlashRegion] { - &FLASH_REGIONS -} - pub(crate) unsafe fn lock() { #[cfg(feature = "trustzone-secure")] pac::FLASH.seccr().modify(|w| w.set_lock(true)); From df84dfec7a55bed44ad5609511e4a2f596a156af Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 1 May 2025 14:35:46 +0200 Subject: [PATCH 1046/1217] Remove embassy_nrf::radio::ble. Fixes #4144 --- embassy-nrf/src/radio/ble.rs | 394 ---------------------------- embassy-nrf/src/radio/ieee802154.rs | 7 +- embassy-nrf/src/radio/mod.rs | 8 +- 3 files changed, 5 insertions(+), 404 deletions(-) delete mode 100644 embassy-nrf/src/radio/ble.rs diff --git a/embassy-nrf/src/radio/ble.rs b/embassy-nrf/src/radio/ble.rs deleted file mode 100644 index d42bbe5f6..000000000 --- a/embassy-nrf/src/radio/ble.rs +++ /dev/null @@ -1,394 +0,0 @@ -//! Radio driver implementation focused on Bluetooth Low-Energy transmission. - -use core::future::poll_fn; -use core::sync::atomic::{compiler_fence, Ordering}; -use core::task::Poll; - -use embassy_hal_internal::drop::OnDrop; -pub use pac::radio::vals::Mode; -#[cfg(not(feature = "_nrf51"))] -use pac::radio::vals::Plen as PreambleLength; - -use crate::interrupt::typelevel::Interrupt; -use crate::pac::radio::vals; -use crate::radio::*; -pub use crate::radio::{Error, TxPower}; -use crate::util::slice_in_ram_or; -use crate::Peri; - -/// Radio driver. -pub struct Radio<'d, T: Instance> { - _p: Peri<'d, T>, -} - -impl<'d, T: Instance> Radio<'d, T> { - /// Create a new radio driver. - pub fn new( - radio: Peri<'d, T>, - _irq: impl interrupt::typelevel::Binding> + 'd, - ) -> Self { - let r = T::regs(); - - r.pcnf1().write(|w| { - // It is 0 bytes long in a standard BLE packet - w.set_statlen(0); - // MaxLen configures the maximum packet payload plus add-on size in - // number of bytes that can be transmitted or received by the RADIO. This feature can be used to ensure - // that the RADIO does not overwrite, or read beyond, the RAM assigned to the packet payload. This means - // that if the packet payload length defined by PCNF1.STATLEN and the LENGTH field in the packet specifies a - // packet larger than MAXLEN, the payload will be truncated at MAXLEN - // - // To simplify the implementation, It is setted as the maximum value - // and the length of the packet is controlled only by the LENGTH field in the packet - w.set_maxlen(255); - // Configure the length of the address field in the packet - // The prefix after the address fields is always appended, so is always 1 byte less than the size of the address - // The base address is truncated from the least significant byte if the BALEN is less than 4 - // - // BLE address is always 4 bytes long - w.set_balen(3); // 3 bytes base address (+ 1 prefix); - // Configure the endianess - // For BLE is always little endian (LSB first) - w.set_endian(vals::Endian::LITTLE); - // Data whitening is used to avoid long sequences of zeros or - // ones, e.g., 0b0000000 or 0b1111111, in the data bit stream. - // The whitener and de-whitener are defined the same way, - // using a 7-bit linear feedback shift register with the - // polynomial x7 + x4 + 1. - // - // In BLE Whitening shall be applied on the PDU and CRC of all - // Link Layer packets and is performed after the CRC generation - // in the transmitter. No other parts of the packets are whitened. - // De-whitening is performed before the CRC checking in the receiver - // Before whitening or de-whitening, the shift register should be - // initialized based on the channel index. - w.set_whiteen(true); - }); - - // Configure CRC - r.crccnf().write(|w| { - // In BLE the CRC shall be calculated on the PDU of all Link Layer - // packets (even if the packet is encrypted). - // It skips the address field - w.set_skipaddr(vals::Skipaddr::SKIP); - // In BLE 24-bit CRC = 3 bytes - w.set_len(vals::Len::THREE); - }); - - // Ch map between 2400 MHZ .. 2500 MHz - // All modes use this range - #[cfg(not(feature = "_nrf51"))] - r.frequency().write(|w| w.set_map(vals::Map::DEFAULT)); - - // Configure shortcuts to simplify and speed up sending and receiving packets. - r.shorts().write(|w| { - // start transmission/recv immediately after ramp-up - // disable radio when transmission/recv is done - w.set_ready_start(true); - w.set_end_disable(true); - }); - - // Enable NVIC interrupt - T::Interrupt::unpend(); - unsafe { T::Interrupt::enable() }; - - Self { _p: radio } - } - - fn state(&self) -> RadioState { - super::state(T::regs()) - } - - /// Set the radio mode - /// - /// The radio must be disabled before calling this function - pub fn set_mode(&mut self, mode: Mode) { - assert!(self.state() == RadioState::DISABLED); - - let r = T::regs(); - r.mode().write(|w| w.set_mode(mode)); - - #[cfg(not(feature = "_nrf51"))] - r.pcnf0().write(|w| { - w.set_plen(match mode { - Mode::BLE_1MBIT => PreambleLength::_8BIT, - Mode::BLE_2MBIT => PreambleLength::_16BIT, - #[cfg(any( - feature = "nrf52811", - feature = "nrf52820", - feature = "nrf52833", - feature = "nrf52840", - feature = "_nrf5340-net" - ))] - Mode::BLE_LR125KBIT | Mode::BLE_LR500KBIT => PreambleLength::LONG_RANGE, - _ => unimplemented!(), - }) - }); - } - - /// Set the header size changing the S1's len field - /// - /// The radio must be disabled before calling this function - pub fn set_header_expansion(&mut self, use_s1_field: bool) { - assert!(self.state() == RadioState::DISABLED); - - let r = T::regs(); - - // s1 len in bits - let s1len: u8 = match use_s1_field { - false => 0, - true => 8, - }; - - r.pcnf0().write(|w| { - // Configure S0 to 1 byte length, this will represent the Data/Adv header flags - w.set_s0len(true); - // Configure the length (in bits) field to 1 byte length, this will represent the length of the payload - // and also be used to know how many bytes to read/write from/to the buffer - w.set_lflen(0); - // Configure the lengh (in bits) of bits in the S1 field. It could be used to represent the CTEInfo for data packages in BLE. - w.set_s1len(s1len); - }); - } - - /// Set initial data whitening value - /// Data whitening is used to avoid long sequences of zeros or ones, e.g., 0b0000000 or 0b1111111, in the data bit stream - /// On BLE the initial value is the channel index | 0x40 - /// - /// The radio must be disabled before calling this function - pub fn set_whitening_init(&mut self, whitening_init: u8) { - assert!(self.state() == RadioState::DISABLED); - - let r = T::regs(); - - r.datawhiteiv().write(|w| w.set_datawhiteiv(whitening_init)); - } - - /// Set the central frequency to be used - /// It should be in the range 2400..2500 - /// - /// [The radio must be disabled before calling this function](https://devzone.nordicsemi.com/f/nordic-q-a/15829/radio-frequency-change) - pub fn set_frequency(&mut self, frequency: u32) { - assert!(self.state() == RadioState::DISABLED); - assert!((2400..=2500).contains(&frequency)); - - let r = T::regs(); - - r.frequency().write(|w| w.set_frequency((frequency - 2400) as u8)); - } - - /// Set the acess address - /// This address is always constants for advertising - /// And a random value generate on each connection - /// It is used to filter the packages - /// - /// The radio must be disabled before calling this function - pub fn set_access_address(&mut self, access_address: u32) { - assert!(self.state() == RadioState::DISABLED); - - let r = T::regs(); - - // Configure logical address - // The byte ordering on air is always least significant byte first for the address - // So for the address 0xAA_BB_CC_DD, the address on air will be DD CC BB AA - // The package order is BASE, PREFIX so BASE=0xBB_CC_DD and PREFIX=0xAA - r.prefix0().write(|w| w.set_ap0((access_address >> 24) as u8)); - - // The base address is truncated from the least significant byte (because the BALEN is less than 4) - // So it shifts the address to the right - r.base0().write_value(access_address << 8); - - // Don't match tx address - r.txaddress().write(|w| w.set_txaddress(0)); - - // Match on logical address - // This config only filter the packets by the address, - // so only packages send to the previous address - // will finish the reception (TODO: check the explanation) - r.rxaddresses().write(|w| { - w.set_addr0(true); - w.set_addr1(true); - w.set_addr2(true); - w.set_addr3(true); - w.set_addr4(true); - }); - } - - /// Set the CRC polynomial - /// It only uses the 24 least significant bits - /// - /// The radio must be disabled before calling this function - pub fn set_crc_poly(&mut self, crc_poly: u32) { - assert!(self.state() == RadioState::DISABLED); - - let r = T::regs(); - - r.crcpoly().write(|w| { - // Configure the CRC polynomial - // Each term in the CRC polynomial is mapped to a bit in this - // register which index corresponds to the term's exponent. - // The least significant term/bit is hard-wired internally to - // 1, and bit number 0 of the register content is ignored by - // the hardware. The following example is for an 8 bit CRC - // polynomial: x8 + x7 + x3 + x2 + 1 = 1 1000 1101 . - w.set_crcpoly(crc_poly & 0xFFFFFF) - }); - } - - /// Set the CRC init value - /// It only uses the 24 least significant bits - /// The CRC initial value varies depending of the PDU type - /// - /// The radio must be disabled before calling this function - pub fn set_crc_init(&mut self, crc_init: u32) { - assert!(self.state() == RadioState::DISABLED); - - let r = T::regs(); - - r.crcinit().write(|w| w.set_crcinit(crc_init & 0xFFFFFF)); - } - - /// Set the radio tx power - /// - /// The radio must be disabled before calling this function - pub fn set_tx_power(&mut self, tx_power: TxPower) { - assert!(self.state() == RadioState::DISABLED); - - let r = T::regs(); - - r.txpower().write(|w| w.set_txpower(tx_power)); - } - - /// Set buffer to read/write - /// - /// This method is unsound. You should guarantee that the buffer will live - /// for the life time of the transmission or if the buffer will be modified. - /// Also if the buffer is smaller than the packet length, the radio will - /// read/write memory out of the buffer bounds. - fn set_buffer(&mut self, buffer: &[u8]) -> Result<(), Error> { - slice_in_ram_or(buffer, Error::BufferNotInRAM)?; - - let r = T::regs(); - - // Here it consider that the length of the packet is - // correctly set in the buffer, otherwise it will send - // unowned regions of memory - let ptr = buffer.as_ptr(); - - // Configure the payload - r.packetptr().write_value(ptr as u32); - - Ok(()) - } - - /// Send packet - /// If the length byte in the package is greater than the buffer length - /// the radio will read memory out of the buffer bounds - pub async fn transmit(&mut self, buffer: &[u8]) -> Result<(), Error> { - self.set_buffer(buffer)?; - - let r = T::regs(); - self.trigger_and_wait_end(move || { - // Initialize the transmission - // trace!("txen"); - - r.tasks_txen().write_value(1); - }) - .await; - - Ok(()) - } - - /// Receive packet - /// If the length byte in the received package is greater than the buffer length - /// the radio will write memory out of the buffer bounds - pub async fn receive(&mut self, buffer: &mut [u8]) -> Result<(), Error> { - self.set_buffer(buffer)?; - - let r = T::regs(); - self.trigger_and_wait_end(move || { - // Initialize the transmission - // trace!("rxen"); - r.tasks_rxen().write_value(1); - }) - .await; - - Ok(()) - } - - async fn trigger_and_wait_end(&mut self, trigger: impl FnOnce()) { - let r = T::regs(); - let s = T::state(); - - // If the Future is dropped before the end of the transmission - // it disable the interrupt and stop the transmission - // to keep the state consistent - let drop = OnDrop::new(|| { - trace!("radio drop: stopping"); - - r.intenclr().write(|w| w.set_end(true)); - - r.tasks_stop().write_value(1); - - r.events_end().write_value(0); - - trace!("radio drop: stopped"); - }); - - // trace!("radio:enable interrupt"); - // Clear some remnant side-effects (TODO: check if this is necessary) - r.events_end().write_value(0); - - // Enable interrupt - r.intenset().write(|w| w.set_end(true)); - - compiler_fence(Ordering::SeqCst); - - // Trigger the transmission - trigger(); - - // On poll check if interrupt happen - poll_fn(|cx| { - s.event_waker.register(cx.waker()); - if r.events_end().read() == 1 { - // trace!("radio:end"); - return core::task::Poll::Ready(()); - } - Poll::Pending - }) - .await; - - compiler_fence(Ordering::SeqCst); - r.events_end().write_value(0); // ACK - - // Everthing ends fine, so it disable the drop - drop.defuse(); - } - - /// Disable the radio - fn disable(&mut self) { - let r = T::regs(); - - compiler_fence(Ordering::SeqCst); - // If it is already disabled, do nothing - if self.state() != RadioState::DISABLED { - trace!("radio:disable"); - // Trigger the disable task - r.tasks_disable().write_value(1); - - // Wait until the radio is disabled - while r.events_disabled().read() == 0 {} - - compiler_fence(Ordering::SeqCst); - - // Acknowledge it - r.events_disabled().write_value(0); - } - } -} - -impl<'d, T: Instance> Drop for Radio<'d, T> { - fn drop(&mut self) { - self.disable(); - } -} diff --git a/embassy-nrf/src/radio/ieee802154.rs b/embassy-nrf/src/radio/ieee802154.rs index 2f0bcbe04..7f4f8f462 100644 --- a/embassy-nrf/src/radio/ieee802154.rs +++ b/embassy-nrf/src/radio/ieee802154.rs @@ -5,10 +5,11 @@ use core::task::Poll; use embassy_hal_internal::drop::OnDrop; -use super::{state, Error, Instance, InterruptHandler, RadioState, TxPower}; +use super::{Error, Instance, InterruptHandler, TxPower}; use crate::interrupt::typelevel::Interrupt; use crate::interrupt::{self}; use crate::pac::radio::vals; +pub use crate::pac::radio::vals::State as RadioState; use crate::Peri; /// Default (IEEE compliant) Start of Frame Delimiter @@ -200,7 +201,7 @@ impl<'d, T: Instance> Radio<'d, T> { /// Get the current radio state fn state(&self) -> RadioState { - state(T::regs()) + T::regs().state().read().state() } /// Moves the radio from any state to the DISABLED state @@ -293,7 +294,7 @@ impl<'d, T: Instance> Radio<'d, T> { r.shorts().write(|_| {}); r.tasks_stop().write_value(1); loop { - match state(r) { + match r.state().read().state() { RadioState::DISABLED | RadioState::RX_IDLE => break, _ => (), } diff --git a/embassy-nrf/src/radio/mod.rs b/embassy-nrf/src/radio/mod.rs index 982436266..608ef9024 100644 --- a/embassy-nrf/src/radio/mod.rs +++ b/embassy-nrf/src/radio/mod.rs @@ -6,7 +6,6 @@ #![macro_use] /// Bluetooth Low Energy Radio driver. -pub mod ble; #[cfg(any( feature = "nrf52811", feature = "nrf52820", @@ -21,7 +20,6 @@ use core::marker::PhantomData; use embassy_hal_internal::PeripheralType; use embassy_sync::waitqueue::AtomicWaker; -use pac::radio::vals::State as RadioState; pub use pac::radio::vals::Txpower as TxPower; use crate::{interrupt, pac}; @@ -82,6 +80,7 @@ macro_rules! impl_radio { pac::$pac_type } + #[allow(unused)] fn state() -> &'static crate::radio::State { static STATE: crate::radio::State = crate::radio::State::new(); &STATE @@ -99,8 +98,3 @@ pub trait Instance: SealedInstance + PeripheralType + 'static + Send { /// Interrupt for this peripheral. type Interrupt: interrupt::typelevel::Interrupt; } - -/// Get the state of the radio -pub(crate) fn state(radio: pac::radio::Radio) -> RadioState { - radio.state().read().state() -} From c01776a3d779caf5f43fda03e5506f569f1bf9ac Mon Sep 17 00:00:00 2001 From: 1-rafael-1 Date: Thu, 1 May 2025 17:07:48 +0200 Subject: [PATCH 1047/1217] - two more doc examples test ignored - added tests for the new calculations and fixed an overflow issue these tests surfaced. - Activate brownout detection. --- embassy-rp/src/clocks.rs | 222 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 214 insertions(+), 8 deletions(-) diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs index 86c172879..005564b8b 100644 --- a/embassy-rp/src/clocks.rs +++ b/embassy-rp/src/clocks.rs @@ -391,7 +391,7 @@ impl ClockConfig { /// /// # Example /// - /// ``` + /// ```rust,ignore /// // Overclock to 200MHz /// let config = ClockConfig::at_sys_frequency_mhz(200); /// ``` @@ -424,7 +424,7 @@ impl ClockConfig { /// /// # Example /// - /// ``` + /// ```rust,ignore /// // Use a non-standard 16MHz crystal to achieve 250MHz /// let config = ClockConfig::with_custom_crystal(16_000_000, 250_000_000); /// ``` @@ -875,7 +875,7 @@ pub struct RtcClkConfig { /// /// # Example /// -/// ``` +/// ```rust,ignore /// // Find parameters for 133MHz system clock from 12MHz crystal /// let pll_params = find_pll_params(12_000_000, 133_000_000).unwrap(); /// ``` @@ -885,7 +885,7 @@ fn find_pll_params(input_hz: u32, target_hz: u32) -> Option { const PLL_SYS_REFDIV: u8 = 1; // Calculate reference frequency - let reference_freq = input_hz / PLL_SYS_REFDIV as u32; + let reference_freq = input_hz as u64 / PLL_SYS_REFDIV as u64; // Start from highest fbdiv for better stability (like SDK does) for fbdiv in (16..=320).rev() { @@ -900,10 +900,10 @@ fn find_pll_params(input_hz: u32, target_hz: u32) -> Option { // (more conservative/stable approach) for post_div1 in (1..=7).rev() { for post_div2 in (1..=post_div1).rev() { - let out_freq = vco_freq / (post_div1 * post_div2) as u32; + let out_freq = vco_freq / (post_div1 * post_div2); // Check if we get the exact target frequency without remainder - if out_freq == target_hz && (vco_freq % (post_div1 * post_div2) as u32 == 0) { + if out_freq == target_hz as u64 && (vco_freq % (post_div1 * post_div2) == 0) { return Some(PllConfig { refdiv: PLL_SYS_REFDIV, fbdiv: fbdiv as u16, @@ -928,7 +928,7 @@ fn find_pll_params(input_hz: u32, target_hz: u32) -> Option { for post_div1 in (1..=7).rev() { for post_div2 in (1..=post_div1).rev() { - let out_freq = vco_freq / (post_div1 * post_div2) as u32; + let out_freq = (vco_freq / (post_div1 * post_div2) as u64) as u32; let diff = if out_freq > target_hz { out_freq - target_hz } else { @@ -1018,7 +1018,10 @@ pub(crate) unsafe fn init(config: ClockConfig) { cortex_m::asm::delay(delay_cycles); // Only now set the BOD level after voltage has stabilized - vreg.bod().write(|w| w.set_vsel(voltage.recommended_bod())); + vreg.bod().write(|w| { + w.set_vsel(voltage.recommended_bod()); + w.set_en(true); // Enable brownout detection + }); } } @@ -1875,3 +1878,206 @@ pub fn dormant_sleep() { } } } + +#[cfg(test)] +mod tests { + use super::*; + + #[cfg(feature = "rp2040")] + #[test] + fn test_voltage_scale_bod_values() { + // Test that each voltage level maps to the correct BOD threshold (approx. 90% of VDD) + // This verifies our BOD settings match our documentation + { + assert_eq!(VoltageScale::V0_85.recommended_bod(), 0b0111); // ~0.774V (91% of 0.85V) + assert_eq!(VoltageScale::V0_90.recommended_bod(), 0b1000); // ~0.817V (91% of 0.90V) + assert_eq!(VoltageScale::V0_95.recommended_bod(), 0b1001); // ~0.860V (91% of 0.95V) + assert_eq!(VoltageScale::V1_00.recommended_bod(), 0b1010); // ~0.903V (90% of 1.00V) + assert_eq!(VoltageScale::V1_05.recommended_bod(), 0b1011); // ~0.946V (90% of 1.05V) + assert_eq!(VoltageScale::V1_10.recommended_bod(), 0b1100); // ~0.989V (90% of 1.10V) + assert_eq!(VoltageScale::V1_15.recommended_bod(), 0b1101); // ~1.032V (90% of 1.15V) + assert_eq!(VoltageScale::V1_20.recommended_bod(), 0b1110); // ~1.075V (90% of 1.20V) + assert_eq!(VoltageScale::V1_25.recommended_bod(), 0b1111); // ~1.118V (89% of 1.25V) + assert_eq!(VoltageScale::V1_30.recommended_bod(), 0b1111); // ~1.118V (86% of 1.30V) - using max available + } + } + + #[cfg(feature = "rp2040")] + #[test] + fn test_find_pll_params() { + #[cfg(feature = "rp2040")] + { + // Test standard 125 MHz configuration with 12 MHz crystal + let params = find_pll_params(12_000_000, 125_000_000).unwrap(); + assert_eq!(params.refdiv, 1); + assert_eq!(params.fbdiv, 125); + + // Test USB PLL configuration for 48MHz + // The algorithm may find different valid parameters than the SDK defaults + // We'll check that it generates a valid configuration that produces 48MHz + let params = find_pll_params(12_000_000, 48_000_000).unwrap(); + assert_eq!(params.refdiv, 1); + + // Calculate the actual output frequency + let ref_freq = 12_000_000 / params.refdiv as u32; + let vco_freq = ref_freq as u64 * params.fbdiv as u64; + let output_freq = (vco_freq / ((params.post_div1 * params.post_div2) as u64)) as u32; + + // Verify the output frequency is correct + assert_eq!(output_freq, 48_000_000); + + // Verify VCO frequency is in valid range + assert!(vco_freq >= 750_000_000 && vco_freq <= 1_800_000_000); + + // Test overclocked configuration for 200 MHz + let params = find_pll_params(12_000_000, 200_000_000).unwrap(); + assert_eq!(params.refdiv, 1); + let vco_freq = 12_000_000 as u64 * params.fbdiv as u64; + let output_freq = (vco_freq / ((params.post_div1 * params.post_div2) as u64)) as u32; + assert_eq!(output_freq, 200_000_000); + assert!(vco_freq >= 750_000_000 && vco_freq <= 1_800_000_000); // VCO in valid range + + // Test non-standard crystal with 16 MHz + let params = find_pll_params(16_000_000, 125_000_000).unwrap(); + let vco_freq = (16_000_000 / params.refdiv as u32) as u64 * params.fbdiv as u64; + let output_freq = (vco_freq / ((params.post_div1 * params.post_div2) as u64)) as u32; + + // With a 16 MHz crystal, we might not get exactly 125 MHz + // Check that it's close enough (within 0.2% margin) + let freq_diff = if output_freq > 125_000_000 { + output_freq - 125_000_000 + } else { + 125_000_000 - output_freq + }; + let error_percentage = (freq_diff as f64 / 125_000_000.0) * 100.0; + assert!( + error_percentage < 0.2, + "Output frequency {} is not close enough to target 125 MHz. Error: {:.2}%", + output_freq, + error_percentage + ); + + assert!(vco_freq >= 750_000_000 && vco_freq <= 1_800_000_000); + } + } + + #[cfg(feature = "rp2040")] + #[test] + fn test_pll_config_validation() { + // Test PLL configuration validation logic + let valid_config = PllConfig { + refdiv: 1, + fbdiv: 125, + post_div1: 6, + post_div2: 2, + }; + + // Valid configuration should pass validation + assert!(valid_config.is_valid(12_000_000)); + + // Test fbdiv constraints + let mut invalid_config = valid_config; + invalid_config.fbdiv = 15; // Below minimum of 16 + assert!(!invalid_config.is_valid(12_000_000)); + + invalid_config.fbdiv = 321; // Above maximum of 320 + assert!(!invalid_config.is_valid(12_000_000)); + + // Test post_div constraints + invalid_config = valid_config; + invalid_config.post_div1 = 0; // Below minimum of 1 + assert!(!invalid_config.is_valid(12_000_000)); + + invalid_config = valid_config; + invalid_config.post_div1 = 8; // Above maximum of 7 + assert!(!invalid_config.is_valid(12_000_000)); + + // Test post_div2 must be <= post_div1 + invalid_config = valid_config; + invalid_config.post_div2 = 7; + invalid_config.post_div1 = 3; + assert!(!invalid_config.is_valid(12_000_000)); + + // Test reference frequency constraints + invalid_config = valid_config; + assert!(!invalid_config.is_valid(4_000_000)); // Below minimum of 5 MHz + assert!(!invalid_config.is_valid(900_000_000)); // Above maximum of 800 MHz + + // Test VCO frequency constraints + invalid_config = valid_config; + invalid_config.fbdiv = 16; + assert!(!invalid_config.is_valid(12_000_000)); // VCO too low: 12MHz * 16 = 192MHz + + // Test VCO frequency constraints - too high + invalid_config = valid_config; + invalid_config.fbdiv = 200; + invalid_config.refdiv = 1; + // This should be INVALID: 12MHz * 200 = 2400MHz exceeds max VCO of 1800MHz + assert!(!invalid_config.is_valid(12_000_000)); + + // Test a valid high VCO configuration + invalid_config.fbdiv = 150; // 12MHz * 150 = 1800MHz, exactly at the limit + assert!(invalid_config.is_valid(12_000_000)); + } + + #[cfg(feature = "rp2040")] + #[test] + fn test_manual_pll_helper() { + { + // Test the new manual_pll helper method + let config = ClockConfig::manual_pll( + 12_000_000, + PllConfig { + refdiv: 1, + fbdiv: 100, + post_div1: 3, + post_div2: 2, + }, + Some(VoltageScale::V1_15), + ); + + // Check voltage scale was set correctly + assert_eq!(config.voltage_scale, Some(VoltageScale::V1_15)); + + // Check PLL config was set correctly + assert_eq!(config.xosc.as_ref().unwrap().sys_pll.as_ref().unwrap().refdiv, 1); + assert_eq!(config.xosc.as_ref().unwrap().sys_pll.as_ref().unwrap().fbdiv, 100); + assert_eq!(config.xosc.as_ref().unwrap().sys_pll.as_ref().unwrap().post_div1, 3); + assert_eq!(config.xosc.as_ref().unwrap().sys_pll.as_ref().unwrap().post_div2, 2); + + // Check we get the expected frequency + assert_eq!( + config + .xosc + .as_ref() + .unwrap() + .sys_pll + .as_ref() + .unwrap() + .output_frequency(12_000_000), + 200_000_000 + ); + } + } + + #[cfg(feature = "rp2040")] + #[test] + fn test_auto_voltage_scaling() { + { + // Test automatic voltage scaling based on frequency + // Under 133 MHz should use default voltage (None) + let config = ClockConfig::at_sys_frequency_mhz(125); + assert_eq!(config.voltage_scale, None); + + // 133-200 MHz should use V1_15 + let config = ClockConfig::at_sys_frequency_mhz(150); + assert_eq!(config.voltage_scale, Some(VoltageScale::V1_15)); + let config = ClockConfig::at_sys_frequency_mhz(200); + assert_eq!(config.voltage_scale, Some(VoltageScale::V1_15)); + + // Above 200 MHz should use V1_20 + let config = ClockConfig::at_sys_frequency_mhz(250); + assert_eq!(config.voltage_scale, Some(VoltageScale::V1_20)); + } + } +} From 3c559378a5f3662134cb7db2d902302d7cb8f937 Mon Sep 17 00:00:00 2001 From: 1-rafael-1 Date: Thu, 1 May 2025 18:29:13 +0200 Subject: [PATCH 1048/1217] Add overclocking test for RP2040 with timer and PWM tests at 200Mhz --- tests/rp/src/bin/overclock.rs | 62 +++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 tests/rp/src/bin/overclock.rs diff --git a/tests/rp/src/bin/overclock.rs b/tests/rp/src/bin/overclock.rs new file mode 100644 index 000000000..c7b9180a0 --- /dev/null +++ b/tests/rp/src/bin/overclock.rs @@ -0,0 +1,62 @@ +#![no_std] +#![no_main] +#[cfg(feature = "rp2040")] +teleprobe_meta::target!(b"rpi-pico"); + +use defmt::{assert, assert_eq, info}; +use embassy_executor::Spawner; +use embassy_rp::config::Config; +use embassy_rp::gpio::{Input, Pull}; +use embassy_rp::pwm::{Config as PwmConfig, Pwm}; +use embassy_time::{Instant, Timer}; +use {defmt_rtt as _, panic_probe as _}; + +#[cfg(feature = "rp2040")] +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + // Initialize with 200MHz clock configuration for RP2040 + let mut config = Config::default(); + config.clocks = embassy_rp::clocks::ClockConfig::at_sys_frequency_mhz(200); + + let p = embassy_rp::init(config); + + info!("RP2040 overclocked to 200MHz!"); + info!("System clock frequency: {} Hz", embassy_rp::clocks::clk_sys_freq()); + + // Test 1: Timer accuracy at 200MHz + info!("Testing timer accuracy at 200MHz..."); + let start = Instant::now(); + Timer::after_millis(100).await; + let end = Instant::now(); + let ms = (end - start).as_millis(); + info!("slept for {} ms", ms); + assert!(ms >= 99); + assert!(ms < 110); + info!("Timer test passed!"); + + // Test 2: PWM functionality at 200MHz + info!("Testing PWM functionality at 200MHz..."); + let pwm_cfg = { + let mut c = PwmConfig::default(); + c.divider = ((embassy_rp::clocks::clk_sys_freq() / 1_000_000) as u8).into(); + c.top = 10000; + c.compare_a = 5000; + c.compare_b = 5000; + c + }; + + // Test PWM output + let pin1 = Input::new(p.PIN_9, Pull::None); + let _pwm = Pwm::new_output_a(p.PWM_SLICE3, p.PIN_6, pwm_cfg); + Timer::after_millis(1).await; + let initial_state = pin1.is_low(); + Timer::after_millis(5).await; + assert_eq!(pin1.is_high(), initial_state); + Timer::after_millis(5).await; + assert_eq!(pin1.is_low(), initial_state); + info!("PWM test passed!"); + + info!("All tests passed at 200MHz!"); + info!("Overclock test successful"); + cortex_m::asm::bkpt(); +} From 7fa59a6b31c7c9744e5cdef3826bc4e726736606 Mon Sep 17 00:00:00 2001 From: 1-rafael-1 Date: Thu, 1 May 2025 18:38:03 +0200 Subject: [PATCH 1049/1217] Refactor overclock test for RP2040: add unused imports conditionally and ensure placeholder main function for non-RP2040 targets --- tests/rp/src/bin/overclock.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tests/rp/src/bin/overclock.rs b/tests/rp/src/bin/overclock.rs index c7b9180a0..c4393dde4 100644 --- a/tests/rp/src/bin/overclock.rs +++ b/tests/rp/src/bin/overclock.rs @@ -1,14 +1,23 @@ #![no_std] #![no_main] +#![cfg_attr(not(feature = "rp2040"), allow(unused_imports))] + #[cfg(feature = "rp2040")] teleprobe_meta::target!(b"rpi-pico"); +#[cfg(feature = "rp2040")] use defmt::{assert, assert_eq, info}; +#[cfg(feature = "rp2040")] use embassy_executor::Spawner; +#[cfg(feature = "rp2040")] use embassy_rp::config::Config; +#[cfg(feature = "rp2040")] use embassy_rp::gpio::{Input, Pull}; +#[cfg(feature = "rp2040")] use embassy_rp::pwm::{Config as PwmConfig, Pwm}; +#[cfg(feature = "rp2040")] use embassy_time::{Instant, Timer}; +#[cfg(feature = "rp2040")] use {defmt_rtt as _, panic_probe as _}; #[cfg(feature = "rp2040")] @@ -60,3 +69,11 @@ async fn main(_spawner: Spawner) { info!("Overclock test successful"); cortex_m::asm::bkpt(); } + +#[cfg(not(feature = "rp2040"))] +#[embassy_executor::main] +async fn main(_spawner: embassy_executor::Spawner) { + // This is an empty placeholder main function for non-RP2040 targets + // It should never be called since the test only runs on RP2040 + cortex_m::asm::bkpt(); +} From 38fd357536e0332c3295d760eed4f481f4d01ce2 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 1 May 2025 18:38:37 +0200 Subject: [PATCH 1050/1217] Update stm32-metapac --- embassy-stm32/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 54badc8f2..e9f236881 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -73,7 +73,7 @@ rand_core = "0.6.3" sdio-host = "0.9.0" critical-section = "1.1" #stm32-metapac = { version = "16" } -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-a821bf5dd8d283c1e8de88fc7699235777a07e78" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-169e38298f9421dddbabc0eb81d0c30fb1eec0a7" } vcell = "0.1.3" nb = "1.0.0" @@ -102,7 +102,7 @@ proc-macro2 = "1.0.36" quote = "1.0.15" #stm32-metapac = { version = "16", default-features = false, features = ["metadata"]} -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-a821bf5dd8d283c1e8de88fc7699235777a07e78", default-features = false, features = ["metadata"] } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-169e38298f9421dddbabc0eb81d0c30fb1eec0a7", default-features = false, features = ["metadata"] } [features] default = ["rt"] From 561356f68ab2d3d6fbe1f85245eb320dbc3e59f0 Mon Sep 17 00:00:00 2001 From: 1-rafael-1 Date: Thu, 1 May 2025 22:17:25 +0200 Subject: [PATCH 1051/1217] overclock test, should now run on all rp chips --- tests/rp/src/bin/overclock.rs | 96 +++++++++++++++-------------------- 1 file changed, 41 insertions(+), 55 deletions(-) diff --git a/tests/rp/src/bin/overclock.rs b/tests/rp/src/bin/overclock.rs index c4393dde4..d6d6062f2 100644 --- a/tests/rp/src/bin/overclock.rs +++ b/tests/rp/src/bin/overclock.rs @@ -1,79 +1,65 @@ #![no_std] #![no_main] -#![cfg_attr(not(feature = "rp2040"), allow(unused_imports))] #[cfg(feature = "rp2040")] teleprobe_meta::target!(b"rpi-pico"); +#[cfg(feature = "rp235xb")] +teleprobe_meta::target!(b"pimoroni-pico-plus-2"); -#[cfg(feature = "rp2040")] use defmt::{assert, assert_eq, info}; -#[cfg(feature = "rp2040")] use embassy_executor::Spawner; +use embassy_rp::clocks; #[cfg(feature = "rp2040")] +use embassy_rp::clocks::ClockConfig; +#[cfg(feature = "rp2040")] +use embassy_rp::clocks::VoltageScale; use embassy_rp::config::Config; -#[cfg(feature = "rp2040")] -use embassy_rp::gpio::{Input, Pull}; -#[cfg(feature = "rp2040")] -use embassy_rp::pwm::{Config as PwmConfig, Pwm}; -#[cfg(feature = "rp2040")] -use embassy_time::{Instant, Timer}; -#[cfg(feature = "rp2040")] +use embassy_time::Instant; use {defmt_rtt as _, panic_probe as _}; -#[cfg(feature = "rp2040")] +const COUNT_TO: i64 = 10_000_000; + #[embassy_executor::main] async fn main(_spawner: Spawner) { - // Initialize with 200MHz clock configuration for RP2040 let mut config = Config::default(); - config.clocks = embassy_rp::clocks::ClockConfig::at_sys_frequency_mhz(200); - let p = embassy_rp::init(config); + // Initialize with 200MHz clock configuration for RP2040, other chips will use default clock + #[cfg(feature = "rp2040")] + { + config.clocks = ClockConfig::at_sys_frequency_mhz(200); + let voltage = config.clocks.voltage_scale.unwrap(); + assert!(matches!(voltage, VoltageScale::V1_15), "Expected voltage scale V1_15"); + } - info!("RP2040 overclocked to 200MHz!"); - info!("System clock frequency: {} Hz", embassy_rp::clocks::clk_sys_freq()); + let _p = embassy_rp::init(config); - // Test 1: Timer accuracy at 200MHz - info!("Testing timer accuracy at 200MHz..."); - let start = Instant::now(); - Timer::after_millis(100).await; - let end = Instant::now(); - let ms = (end - start).as_millis(); - info!("slept for {} ms", ms); - assert!(ms >= 99); - assert!(ms < 110); - info!("Timer test passed!"); + let (time_elapsed, clk_sys_freq) = { + // Test the system speed + let mut counter = 0; + let start = Instant::now(); + while counter < COUNT_TO { + counter += 1; + } + let elapsed = Instant::now() - start; - // Test 2: PWM functionality at 200MHz - info!("Testing PWM functionality at 200MHz..."); - let pwm_cfg = { - let mut c = PwmConfig::default(); - c.divider = ((embassy_rp::clocks::clk_sys_freq() / 1_000_000) as u8).into(); - c.top = 10000; - c.compare_a = 5000; - c.compare_b = 5000; - c + (elapsed.as_millis(), clocks::clk_sys_freq()) }; - // Test PWM output - let pin1 = Input::new(p.PIN_9, Pull::None); - let _pwm = Pwm::new_output_a(p.PWM_SLICE3, p.PIN_6, pwm_cfg); - Timer::after_millis(1).await; - let initial_state = pin1.is_low(); - Timer::after_millis(5).await; - assert_eq!(pin1.is_high(), initial_state); - Timer::after_millis(5).await; - assert_eq!(pin1.is_low(), initial_state); - info!("PWM test passed!"); + // Report the elapsed time, so that the compiler doesn't optimize it away for chips other than RP2040 + info!( + "At {}Mhz: Elapsed time to count to {}: {}ms", + clk_sys_freq / 1_000_000, + COUNT_TO, + time_elapsed + ); + + #[cfg(feature = "rp2040")] + { + // we should be at 200MHz + assert_eq!(clk_sys_freq, 200_000_000, "System clock frequency is not 200MHz"); + // At 200MHz, the time to count to 10_000_000 should be at 600ms, testing with 1% margin + assert!(time_elapsed <= 606, "Elapsed time is too long"); + } - info!("All tests passed at 200MHz!"); - info!("Overclock test successful"); - cortex_m::asm::bkpt(); -} - -#[cfg(not(feature = "rp2040"))] -#[embassy_executor::main] -async fn main(_spawner: embassy_executor::Spawner) { - // This is an empty placeholder main function for non-RP2040 targets - // It should never be called since the test only runs on RP2040 cortex_m::asm::bkpt(); } From a33e7172f6bf7dc9590432dd62c2b71d0215d99d Mon Sep 17 00:00:00 2001 From: 1-rafael-1 Date: Thu, 1 May 2025 22:23:14 +0200 Subject: [PATCH 1052/1217] make ci happy --- tests/rp/src/bin/overclock.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/rp/src/bin/overclock.rs b/tests/rp/src/bin/overclock.rs index d6d6062f2..e4845a55f 100644 --- a/tests/rp/src/bin/overclock.rs +++ b/tests/rp/src/bin/overclock.rs @@ -6,7 +6,9 @@ teleprobe_meta::target!(b"rpi-pico"); #[cfg(feature = "rp235xb")] teleprobe_meta::target!(b"pimoroni-pico-plus-2"); -use defmt::{assert, assert_eq, info}; +use defmt::info; +#[cfg(feature = "rp2040")] +use defmt::{assert, assert_eq}; use embassy_executor::Spawner; use embassy_rp::clocks; #[cfg(feature = "rp2040")] @@ -21,7 +23,10 @@ const COUNT_TO: i64 = 10_000_000; #[embassy_executor::main] async fn main(_spawner: Spawner) { + #[cfg(feature = "rp2040")] let mut config = Config::default(); + #[cfg(not(feature = "rp2040"))] + let config = Config::default(); // Initialize with 200MHz clock configuration for RP2040, other chips will use default clock #[cfg(feature = "rp2040")] From 2fd803f7c336dd6aa042c34e11e213e6e4eb13ad Mon Sep 17 00:00:00 2001 From: Marc <35759328+marcemmers@users.noreply.github.com> Date: Fri, 2 May 2025 12:17:35 +0200 Subject: [PATCH 1053/1217] Removed instance from uart types --- embassy-rp/src/uart/buffered.rs | 306 +++++++++++++++++--------------- embassy-rp/src/uart/mod.rs | 291 +++++++++++++++++------------- 2 files changed, 324 insertions(+), 273 deletions(-) diff --git a/embassy-rp/src/uart/buffered.rs b/embassy-rp/src/uart/buffered.rs index da18138b5..44b6ee469 100644 --- a/embassy-rp/src/uart/buffered.rs +++ b/embassy-rp/src/uart/buffered.rs @@ -34,28 +34,31 @@ impl State { } /// Buffered UART driver. -pub struct BufferedUart<'d, T: Instance> { - pub(crate) rx: BufferedUartRx<'d, T>, - pub(crate) tx: BufferedUartTx<'d, T>, +pub struct BufferedUart { + pub(super) rx: BufferedUartRx, + pub(super) tx: BufferedUartTx, } /// Buffered UART RX handle. -pub struct BufferedUartRx<'d, T: Instance> { - pub(crate) phantom: PhantomData<&'d mut T>, +pub struct BufferedUartRx { + pub(super) info: &'static Info, + pub(super) state: &'static State, + // pub(crate) phantom: PhantomData<&'d mut T>, } /// Buffered UART TX handle. -pub struct BufferedUartTx<'d, T: Instance> { - pub(crate) phantom: PhantomData<&'d mut T>, +pub struct BufferedUartTx { + pub(super) info: &'static Info, + pub(super) state: &'static State, + // pub(crate) phantom: PhantomData<&'d mut T>, } -pub(crate) fn init_buffers<'d, T: Instance + 'd>( - _irq: impl Binding>, +pub(super) fn init_buffers<'d>( + info: &Info, + state: &State, tx_buffer: Option<&'d mut [u8]>, rx_buffer: Option<&'d mut [u8]>, ) { - let state = T::buffered_state(); - if let Some(tx_buffer) = tx_buffer { let len = tx_buffer.len(); unsafe { state.tx_buf.init(tx_buffer.as_mut_ptr(), len) }; @@ -76,61 +79,73 @@ pub(crate) fn init_buffers<'d, T: Instance + 'd>( // This means we can leave the interrupt enabled the whole time as long as // we clear it after it happens. The downside is that the we manually have // to pend the ISR when we want data transmission to start. - let regs = T::regs(); - regs.uartimsc().write(|w| { + info.regs.uartimsc().write(|w| { w.set_rxim(true); w.set_rtim(true); w.set_txim(true); }); - T::Interrupt::unpend(); - unsafe { T::Interrupt::enable() }; + info.interrupt.unpend(); + unsafe { info.interrupt.enable() }; } -impl<'d, T: Instance> BufferedUart<'d, T> { +impl BufferedUart { /// Create a buffered UART instance. - pub fn new( + pub fn new<'d, T: Instance>( _uart: Peri<'d, T>, tx: Peri<'d, impl TxPin>, rx: Peri<'d, impl RxPin>, - irq: impl Binding>, + _irq: impl Binding>, tx_buffer: &'d mut [u8], rx_buffer: &'d mut [u8], config: Config, ) -> Self { - super::Uart::<'d, T, Async>::init(Some(tx.into()), Some(rx.into()), None, None, config); - init_buffers::(irq, Some(tx_buffer), Some(rx_buffer)); + super::Uart::<'d, Async>::init(T::info(), Some(tx.into()), Some(rx.into()), None, None, config); + init_buffers(T::info(), T::buffered_state(), Some(tx_buffer), Some(rx_buffer)); Self { - rx: BufferedUartRx { phantom: PhantomData }, - tx: BufferedUartTx { phantom: PhantomData }, + rx: BufferedUartRx { + info: T::info(), + state: T::buffered_state(), + }, + tx: BufferedUartTx { + info: T::info(), + state: T::buffered_state(), + }, } } /// Create a buffered UART instance with flow control. - pub fn new_with_rtscts( + pub fn new_with_rtscts<'d, T: Instance>( _uart: Peri<'d, T>, tx: Peri<'d, impl TxPin>, rx: Peri<'d, impl RxPin>, rts: Peri<'d, impl RtsPin>, cts: Peri<'d, impl CtsPin>, - irq: impl Binding>, + _irq: impl Binding>, tx_buffer: &'d mut [u8], rx_buffer: &'d mut [u8], config: Config, ) -> Self { - super::Uart::<'d, T, Async>::init( + super::Uart::<'d, Async>::init( + T::info(), Some(tx.into()), Some(rx.into()), Some(rts.into()), Some(cts.into()), config, ); - init_buffers::(irq, Some(tx_buffer), Some(rx_buffer)); + init_buffers(T::info(), T::buffered_state(), Some(tx_buffer), Some(rx_buffer)); Self { - rx: BufferedUartRx { phantom: PhantomData }, - tx: BufferedUartTx { phantom: PhantomData }, + rx: BufferedUartRx { + info: T::info(), + state: T::buffered_state(), + }, + tx: BufferedUartTx { + info: T::info(), + state: T::buffered_state(), + }, } } @@ -160,68 +175,75 @@ impl<'d, T: Instance> BufferedUart<'d, T> { } /// sets baudrate on runtime - pub fn set_baudrate(&mut self, baudrate: u32) { - super::Uart::<'d, T, Async>::set_baudrate_inner(baudrate); + pub fn set_baudrate<'d>(&mut self, baudrate: u32) { + super::Uart::<'d, Async>::set_baudrate_inner(self.rx.info, baudrate); } /// Split into separate RX and TX handles. - pub fn split(self) -> (BufferedUartTx<'d, T>, BufferedUartRx<'d, T>) { + pub fn split(self) -> (BufferedUartTx, BufferedUartRx) { (self.tx, self.rx) } /// Split the Uart into a transmitter and receiver by mutable reference, /// which is particularly useful when having two tasks correlating to /// transmitting and receiving. - pub fn split_ref(&mut self) -> (&mut BufferedUartTx<'d, T>, &mut BufferedUartRx<'d, T>) { + pub fn split_ref(&mut self) -> (&mut BufferedUartTx, &mut BufferedUartRx) { (&mut self.tx, &mut self.rx) } } -impl<'d, T: Instance> BufferedUartRx<'d, T> { +impl BufferedUartRx { /// Create a new buffered UART RX. - pub fn new( + pub fn new<'d, T: Instance>( _uart: Peri<'d, T>, - irq: impl Binding>, + _irq: impl Binding>, rx: Peri<'d, impl RxPin>, rx_buffer: &'d mut [u8], config: Config, ) -> Self { - super::Uart::<'d, T, Async>::init(None, Some(rx.into()), None, None, config); - init_buffers::(irq, None, Some(rx_buffer)); + super::Uart::<'d, Async>::init(T::info(), None, Some(rx.into()), None, None, config); + init_buffers(T::info(), T::buffered_state(), None, Some(rx_buffer)); - Self { phantom: PhantomData } + Self { + info: T::info(), + state: T::buffered_state(), + } } /// Create a new buffered UART RX with flow control. - pub fn new_with_rts( + pub fn new_with_rts<'d, T: Instance>( _uart: Peri<'d, T>, - irq: impl Binding>, + _irq: impl Binding>, rx: Peri<'d, impl RxPin>, rts: Peri<'d, impl RtsPin>, rx_buffer: &'d mut [u8], config: Config, ) -> Self { - super::Uart::<'d, T, Async>::init(None, Some(rx.into()), Some(rts.into()), None, config); - init_buffers::(irq, None, Some(rx_buffer)); + super::Uart::<'d, Async>::init(T::info(), None, Some(rx.into()), Some(rts.into()), None, config); + init_buffers(T::info(), T::buffered_state(), None, Some(rx_buffer)); - Self { phantom: PhantomData } + Self { + info: T::info(), + state: T::buffered_state(), + } } - fn read<'a>(buf: &'a mut [u8]) -> impl Future> + 'a - where - T: 'd, - { + fn read<'a>( + info: &'static Info, + state: &'static State, + buf: &'a mut [u8], + ) -> impl Future> + 'a { poll_fn(move |cx| { - if let Poll::Ready(r) = Self::try_read(buf) { + if let Poll::Ready(r) = Self::try_read(info, state, buf) { return Poll::Ready(r); } - T::buffered_state().rx_waker.register(cx.waker()); + state.rx_waker.register(cx.waker()); Poll::Pending }) } - fn get_rx_error() -> Option { - let errs = T::buffered_state().rx_error.swap(0, Ordering::Relaxed); + fn get_rx_error(state: &State) -> Option { + let errs = state.rx_error.swap(0, Ordering::Relaxed); if errs & RXE_OVERRUN != 0 { Some(Error::Overrun) } else if errs & RXE_BREAK != 0 { @@ -235,15 +257,11 @@ impl<'d, T: Instance> BufferedUartRx<'d, T> { } } - fn try_read(buf: &mut [u8]) -> Poll> - where - T: 'd, - { + fn try_read(info: &Info, state: &State, buf: &mut [u8]) -> Poll> { if buf.is_empty() { return Poll::Ready(Ok(0)); } - let state = T::buffered_state(); let mut rx_reader = unsafe { state.rx_buf.reader() }; let n = rx_reader.pop(|data| { let n = data.len().min(buf.len()); @@ -252,7 +270,7 @@ impl<'d, T: Instance> BufferedUartRx<'d, T> { }); let result = if n == 0 { - match Self::get_rx_error() { + match Self::get_rx_error(state) { None => return Poll::Pending, Some(e) => Err(e), } @@ -262,8 +280,7 @@ impl<'d, T: Instance> BufferedUartRx<'d, T> { // (Re-)Enable the interrupt to receive more data in case it was // disabled because the buffer was full or errors were detected. - let regs = T::regs(); - regs.uartimsc().write_set(|w| { + info.regs.uartimsc().write_set(|w| { w.set_rxim(true); w.set_rtim(true); }); @@ -274,23 +291,19 @@ impl<'d, T: Instance> BufferedUartRx<'d, T> { /// Read from UART RX buffer blocking execution until done. pub fn blocking_read(&mut self, buf: &mut [u8]) -> Result { loop { - match Self::try_read(buf) { + match Self::try_read(self.info, self.state, buf) { Poll::Ready(res) => return res, Poll::Pending => continue, } } } - fn fill_buf<'a>() -> impl Future> - where - T: 'd, - { + fn fill_buf<'a>(state: &'static State) -> impl Future> { poll_fn(move |cx| { - let state = T::buffered_state(); let mut rx_reader = unsafe { state.rx_buf.reader() }; let (p, n) = rx_reader.pop_buf(); let result = if n == 0 { - match Self::get_rx_error() { + match Self::get_rx_error(state) { None => { state.rx_waker.register(cx.waker()); return Poll::Pending; @@ -306,64 +319,70 @@ impl<'d, T: Instance> BufferedUartRx<'d, T> { }) } - fn consume(amt: usize) { - let state = T::buffered_state(); + fn consume(info: &Info, state: &State, amt: usize) { let mut rx_reader = unsafe { state.rx_buf.reader() }; rx_reader.pop_done(amt); // (Re-)Enable the interrupt to receive more data in case it was // disabled because the buffer was full or errors were detected. - let regs = T::regs(); - regs.uartimsc().write_set(|w| { + info.regs.uartimsc().write_set(|w| { w.set_rxim(true); w.set_rtim(true); }); } /// we are ready to read if there is data in the buffer - fn read_ready() -> Result { - let state = T::buffered_state(); + fn read_ready(state: &State) -> Result { Ok(!state.rx_buf.is_empty()) } } -impl<'d, T: Instance> BufferedUartTx<'d, T> { +impl BufferedUartTx { /// Create a new buffered UART TX. - pub fn new( + pub fn new<'d, T: Instance>( _uart: Peri<'d, T>, - irq: impl Binding>, + _irq: impl Binding>, tx: Peri<'d, impl TxPin>, tx_buffer: &'d mut [u8], config: Config, ) -> Self { - super::Uart::<'d, T, Async>::init(Some(tx.into()), None, None, None, config); - init_buffers::(irq, Some(tx_buffer), None); + super::Uart::<'d, Async>::init(T::info(), Some(tx.into()), None, None, None, config); + init_buffers(T::info(), T::buffered_state(), Some(tx_buffer), None); - Self { phantom: PhantomData } + Self { + info: T::info(), + state: T::buffered_state(), + } } /// Create a new buffered UART TX with flow control. - pub fn new_with_cts( + pub fn new_with_cts<'d, T: Instance>( _uart: Peri<'d, T>, - irq: impl Binding>, + _irq: impl Binding>, tx: Peri<'d, impl TxPin>, cts: Peri<'d, impl CtsPin>, tx_buffer: &'d mut [u8], config: Config, ) -> Self { - super::Uart::<'d, T, Async>::init(Some(tx.into()), None, None, Some(cts.into()), config); - init_buffers::(irq, Some(tx_buffer), None); + super::Uart::<'d, Async>::init(T::info(), Some(tx.into()), None, None, Some(cts.into()), config); + init_buffers(T::info(), T::buffered_state(), Some(tx_buffer), None); - Self { phantom: PhantomData } + Self { + info: T::info(), + state: T::buffered_state(), + } } - fn write(buf: &[u8]) -> impl Future> + '_ { + fn write<'d>( + info: &'static Info, + state: &'static State, + buf: &'d [u8], + ) -> impl Future> + 'd { poll_fn(move |cx| { if buf.is_empty() { return Poll::Ready(Ok(0)); } - let state = T::buffered_state(); let mut tx_writer = unsafe { state.tx_buf.writer() }; let n = tx_writer.push(|data| { let n = data.len().min(buf.len()); @@ -379,14 +398,13 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> { // FIFO and the number of bytes drops below a threshold. When the // FIFO was empty we have to manually pend the interrupt to shovel // TX data from the buffer into the FIFO. - T::Interrupt::pend(); + info.interrupt.pend(); Poll::Ready(Ok(n)) }) } - fn flush() -> impl Future> { + fn flush(state: &'static State) -> impl Future> { poll_fn(move |cx| { - let state = T::buffered_state(); if !state.tx_buf.is_empty() { state.tx_waker.register(cx.waker()); return Poll::Pending; @@ -403,8 +421,7 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> { } loop { - let state = T::buffered_state(); - let mut tx_writer = unsafe { state.tx_buf.writer() }; + let mut tx_writer = unsafe { self.state.tx_buf.writer() }; let n = tx_writer.push(|data| { let n = data.len().min(buf.len()); data[..n].copy_from_slice(&buf[..n]); @@ -416,7 +433,7 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> { // FIFO and the number of bytes drops below a threshold. When the // FIFO was empty we have to manually pend the interrupt to shovel // TX data from the buffer into the FIFO. - T::Interrupt::pend(); + self.info.interrupt.pend(); return Ok(n); } } @@ -425,8 +442,7 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> { /// Flush UART TX blocking execution until done. pub fn blocking_flush(&mut self) -> Result<(), Error> { loop { - let state = T::buffered_state(); - if state.tx_buf.is_empty() { + if self.state.tx_buf.is_empty() { return Ok(()); } } @@ -434,7 +450,7 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> { /// Check if UART is busy. pub fn busy(&self) -> bool { - T::regs().uartfr().read().busy() + self.info.regs.uartfr().read().busy() } /// Assert a break condition after waiting for the transmit buffers to empty, @@ -445,7 +461,7 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> { /// This method may block for a long amount of time since it has to wait /// for the transmit fifo to empty, which may take a while on slow links. pub async fn send_break(&mut self, bits: u32) { - let regs = T::regs(); + let regs = self.info.regs; let bits = bits.max({ let lcr = regs.uartlcr_h().read(); let width = lcr.wlen() as u32 + 5; @@ -458,7 +474,7 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> { let div_clk = clk_peri_freq() as u64 * 64; let wait_usecs = (1_000_000 * bits as u64 * divx64 * 16 + div_clk - 1) / div_clk; - Self::flush().await.unwrap(); + Self::flush(self.state).await.unwrap(); while self.busy() {} regs.uartlcr_h().write_set(|w| w.set_brk(true)); Timer::after_micros(wait_usecs).await; @@ -466,28 +482,26 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> { } } -impl<'d, T: Instance> Drop for BufferedUartRx<'d, T> { +impl Drop for BufferedUartRx { fn drop(&mut self) { - let state = T::buffered_state(); - unsafe { state.rx_buf.deinit() } + unsafe { self.state.rx_buf.deinit() } // TX is inactive if the buffer is not available. // We can now unregister the interrupt handler - if !state.tx_buf.is_available() { - T::Interrupt::disable(); + if !self.state.tx_buf.is_available() { + self.info.interrupt.disable(); } } } -impl<'d, T: Instance> Drop for BufferedUartTx<'d, T> { +impl Drop for BufferedUartTx { fn drop(&mut self) { - let state = T::buffered_state(); - unsafe { state.tx_buf.deinit() } + unsafe { self.state.tx_buf.deinit() } // RX is inactive if the buffer is not available. // We can now unregister the interrupt handler - if !state.rx_buf.is_available() { - T::Interrupt::disable(); + if !self.state.rx_buf.is_available() { + self.info.interrupt.disable(); } } } @@ -499,7 +513,7 @@ pub struct BufferedInterruptHandler { impl interrupt::typelevel::Handler for BufferedInterruptHandler { unsafe fn on_interrupt() { - let r = T::regs(); + let r = T::info().regs; if r.uartdmacr().read().rxdmae() { return; } @@ -603,95 +617,95 @@ impl embedded_io::Error for Error { } } -impl<'d, T: Instance> embedded_io_async::ErrorType for BufferedUart<'d, T> { +impl embedded_io_async::ErrorType for BufferedUart { type Error = Error; } -impl<'d, T: Instance> embedded_io_async::ErrorType for BufferedUartRx<'d, T> { +impl embedded_io_async::ErrorType for BufferedUartRx { type Error = Error; } -impl<'d, T: Instance> embedded_io_async::ErrorType for BufferedUartTx<'d, T> { +impl embedded_io_async::ErrorType for BufferedUartTx { type Error = Error; } -impl<'d, T: Instance + 'd> embedded_io_async::Read for BufferedUart<'d, T> { +impl embedded_io_async::Read for BufferedUart { async fn read(&mut self, buf: &mut [u8]) -> Result { - BufferedUartRx::<'d, T>::read(buf).await + BufferedUartRx::read(self.rx.info, self.rx.state, buf).await } } -impl<'d, T: Instance + 'd> embedded_io_async::Read for BufferedUartRx<'d, T> { +impl embedded_io_async::Read for BufferedUartRx { async fn read(&mut self, buf: &mut [u8]) -> Result { - Self::read(buf).await + Self::read(self.info, self.state, buf).await } } -impl<'d, T: Instance + 'd> embedded_io_async::ReadReady for BufferedUart<'d, T> { +impl embedded_io_async::ReadReady for BufferedUart { fn read_ready(&mut self) -> Result { - BufferedUartRx::<'d, T>::read_ready() + BufferedUartRx::read_ready(self.rx.state) } } -impl<'d, T: Instance + 'd> embedded_io_async::ReadReady for BufferedUartRx<'d, T> { +impl embedded_io_async::ReadReady for BufferedUartRx { fn read_ready(&mut self) -> Result { - Self::read_ready() + Self::read_ready(self.state) } } -impl<'d, T: Instance + 'd> embedded_io_async::BufRead for BufferedUart<'d, T> { +impl embedded_io_async::BufRead for BufferedUart { async fn fill_buf(&mut self) -> Result<&[u8], Self::Error> { - BufferedUartRx::<'d, T>::fill_buf().await + BufferedUartRx::fill_buf(self.rx.state).await } fn consume(&mut self, amt: usize) { - BufferedUartRx::<'d, T>::consume(amt) + BufferedUartRx::consume(self.rx.info, self.rx.state, amt) } } -impl<'d, T: Instance + 'd> embedded_io_async::BufRead for BufferedUartRx<'d, T> { +impl embedded_io_async::BufRead for BufferedUartRx { async fn fill_buf(&mut self) -> Result<&[u8], Self::Error> { - Self::fill_buf().await + Self::fill_buf(self.state).await } fn consume(&mut self, amt: usize) { - Self::consume(amt) + Self::consume(self.info, self.state, amt) } } -impl<'d, T: Instance + 'd> embedded_io_async::Write for BufferedUart<'d, T> { +impl embedded_io_async::Write for BufferedUart { async fn write(&mut self, buf: &[u8]) -> Result { - BufferedUartTx::<'d, T>::write(buf).await + BufferedUartTx::write(self.tx.info, self.tx.state, buf).await } async fn flush(&mut self) -> Result<(), Self::Error> { - BufferedUartTx::<'d, T>::flush().await + BufferedUartTx::flush(self.tx.state).await } } -impl<'d, T: Instance + 'd> embedded_io_async::Write for BufferedUartTx<'d, T> { +impl embedded_io_async::Write for BufferedUartTx { async fn write(&mut self, buf: &[u8]) -> Result { - Self::write(buf).await + Self::write(self.info, self.state, buf).await } async fn flush(&mut self) -> Result<(), Self::Error> { - Self::flush().await + Self::flush(self.state).await } } -impl<'d, T: Instance + 'd> embedded_io::Read for BufferedUart<'d, T> { +impl embedded_io::Read for BufferedUart { fn read(&mut self, buf: &mut [u8]) -> Result { self.rx.blocking_read(buf) } } -impl<'d, T: Instance + 'd> embedded_io::Read for BufferedUartRx<'d, T> { +impl embedded_io::Read for BufferedUartRx { fn read(&mut self, buf: &mut [u8]) -> Result { self.blocking_read(buf) } } -impl<'d, T: Instance + 'd> embedded_io::Write for BufferedUart<'d, T> { +impl embedded_io::Write for BufferedUart { fn write(&mut self, buf: &[u8]) -> Result { self.tx.blocking_write(buf) } @@ -701,7 +715,7 @@ impl<'d, T: Instance + 'd> embedded_io::Write for BufferedUart<'d, T> { } } -impl<'d, T: Instance + 'd> embedded_io::Write for BufferedUartTx<'d, T> { +impl embedded_io::Write for BufferedUartTx { fn write(&mut self, buf: &[u8]) -> Result { self.blocking_write(buf) } @@ -711,11 +725,11 @@ impl<'d, T: Instance + 'd> embedded_io::Write for BufferedUartTx<'d, T> { } } -impl<'d, T: Instance> embedded_hal_02::serial::Read for BufferedUartRx<'d, T> { +impl embedded_hal_02::serial::Read for BufferedUartRx { type Error = Error; fn read(&mut self) -> Result> { - let r = T::regs(); + let r = self.info.regs; if r.uartfr().read().rxfe() { return Err(nb::Error::WouldBlock); } @@ -736,7 +750,7 @@ impl<'d, T: Instance> embedded_hal_02::serial::Read for BufferedUartRx<'d, T } } -impl<'d, T: Instance> embedded_hal_02::blocking::serial::Write for BufferedUartTx<'d, T> { +impl embedded_hal_02::blocking::serial::Write for BufferedUartTx { type Error = Error; fn bwrite_all(&mut self, mut buffer: &[u8]) -> Result<(), Self::Error> { @@ -755,7 +769,7 @@ impl<'d, T: Instance> embedded_hal_02::blocking::serial::Write for BufferedU } } -impl<'d, T: Instance> embedded_hal_02::serial::Read for BufferedUart<'d, T> { +impl embedded_hal_02::serial::Read for BufferedUart { type Error = Error; fn read(&mut self) -> Result> { @@ -763,7 +777,7 @@ impl<'d, T: Instance> embedded_hal_02::serial::Read for BufferedUart<'d, T> } } -impl<'d, T: Instance> embedded_hal_02::blocking::serial::Write for BufferedUart<'d, T> { +impl embedded_hal_02::blocking::serial::Write for BufferedUart { type Error = Error; fn bwrite_all(&mut self, mut buffer: &[u8]) -> Result<(), Self::Error> { @@ -782,25 +796,25 @@ impl<'d, T: Instance> embedded_hal_02::blocking::serial::Write for BufferedU } } -impl<'d, T: Instance> embedded_hal_nb::serial::ErrorType for BufferedUartRx<'d, T> { +impl embedded_hal_nb::serial::ErrorType for BufferedUartRx { type Error = Error; } -impl<'d, T: Instance> embedded_hal_nb::serial::ErrorType for BufferedUartTx<'d, T> { +impl embedded_hal_nb::serial::ErrorType for BufferedUartTx { type Error = Error; } -impl<'d, T: Instance> embedded_hal_nb::serial::ErrorType for BufferedUart<'d, T> { +impl embedded_hal_nb::serial::ErrorType for BufferedUart { type Error = Error; } -impl<'d, T: Instance> embedded_hal_nb::serial::Read for BufferedUartRx<'d, T> { +impl embedded_hal_nb::serial::Read for BufferedUartRx { fn read(&mut self) -> nb::Result { embedded_hal_02::serial::Read::read(self) } } -impl<'d, T: Instance> embedded_hal_nb::serial::Write for BufferedUartTx<'d, T> { +impl embedded_hal_nb::serial::Write for BufferedUartTx { fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> { self.blocking_write(&[char]).map(drop).map_err(nb::Error::Other) } @@ -810,13 +824,13 @@ impl<'d, T: Instance> embedded_hal_nb::serial::Write for BufferedUartTx<'d, T> { } } -impl<'d, T: Instance> embedded_hal_nb::serial::Read for BufferedUart<'d, T> { +impl embedded_hal_nb::serial::Read for BufferedUart { fn read(&mut self) -> Result> { embedded_hal_02::serial::Read::read(&mut self.rx) } } -impl<'d, T: Instance> embedded_hal_nb::serial::Write for BufferedUart<'d, T> { +impl embedded_hal_nb::serial::Write for BufferedUart { fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> { self.blocking_write(&[char]).map(drop).map_err(nb::Error::Other) } diff --git a/embassy-rp/src/uart/mod.rs b/embassy-rp/src/uart/mod.rs index 7ce074a3f..d36884109 100644 --- a/embassy-rp/src/uart/mod.rs +++ b/embassy-rp/src/uart/mod.rs @@ -13,7 +13,8 @@ use pac::uart::regs::Uartris; use crate::clocks::clk_peri_freq; use crate::dma::{AnyChannel, Channel}; use crate::gpio::{AnyPin, SealedPin}; -use crate::interrupt::typelevel::{Binding, Interrupt}; +use crate::interrupt::typelevel::{Binding, Interrupt as _}; +use crate::interrupt::{Interrupt, InterruptExt}; use crate::pac::io::vals::{Inover, Outover}; use crate::{interrupt, pac, peripherals, RegExt}; @@ -135,37 +136,41 @@ pub struct DmaState { } /// UART driver. -pub struct Uart<'d, T: Instance, M: Mode> { - tx: UartTx<'d, T, M>, - rx: UartRx<'d, T, M>, +pub struct Uart<'d, M: Mode> { + tx: UartTx<'d, M>, + rx: UartRx<'d, M>, } /// UART TX driver. -pub struct UartTx<'d, T: Instance, M: Mode> { +pub struct UartTx<'d, M: Mode> { + info: &'static Info, tx_dma: Option>, - phantom: PhantomData<(&'d mut T, M)>, + phantom: PhantomData, } /// UART RX driver. -pub struct UartRx<'d, T: Instance, M: Mode> { +pub struct UartRx<'d, M: Mode> { + info: &'static Info, + dma_state: &'static DmaState, rx_dma: Option>, - phantom: PhantomData<(&'d mut T, M)>, + phantom: PhantomData, } -impl<'d, T: Instance, M: Mode> UartTx<'d, T, M> { +impl<'d, M: Mode> UartTx<'d, M> { /// Create a new DMA-enabled UART which can only send data - pub fn new( + pub fn new( _uart: Peri<'d, T>, tx: Peri<'d, impl TxPin>, tx_dma: Peri<'d, impl Channel>, config: Config, ) -> Self { - Uart::::init(Some(tx.into()), None, None, None, config); - Self::new_inner(Some(tx_dma.into())) + Uart::::init(T::info(), Some(tx.into()), None, None, None, config); + Self::new_inner::(Some(tx_dma.into())) } - fn new_inner(tx_dma: Option>) -> Self { + fn new_inner(tx_dma: Option>) -> Self { Self { + info: T::info(), tx_dma, phantom: PhantomData, } @@ -173,7 +178,7 @@ impl<'d, T: Instance, M: Mode> UartTx<'d, T, M> { /// Transmit the provided buffer blocking execution until done. pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> { - let r = T::regs(); + let r = self.info.regs; for &b in buffer { while r.uartfr().read().txff() {} r.uartdr().write(|w| w.set_data(b)); @@ -183,14 +188,13 @@ impl<'d, T: Instance, M: Mode> UartTx<'d, T, M> { /// Flush UART TX blocking execution until done. pub fn blocking_flush(&mut self) -> Result<(), Error> { - let r = T::regs(); - while !r.uartfr().read().txfe() {} + while !self.info.regs.uartfr().read().txfe() {} Ok(()) } /// Check if UART is busy transmitting. pub fn busy(&self) -> bool { - T::regs().uartfr().read().busy() + self.info.regs.uartfr().read().busy() } /// Assert a break condition after waiting for the transmit buffers to empty, @@ -201,7 +205,7 @@ impl<'d, T: Instance, M: Mode> UartTx<'d, T, M> { /// This method may block for a long amount of time since it has to wait /// for the transmit fifo to empty, which may take a while on slow links. pub async fn send_break(&mut self, bits: u32) { - let regs = T::regs(); + let regs = self.info.regs; let bits = bits.max({ let lcr = regs.uartlcr_h().read(); let width = lcr.wlen() as u32 + 5; @@ -222,65 +226,75 @@ impl<'d, T: Instance, M: Mode> UartTx<'d, T, M> { } } -impl<'d, T: Instance> UartTx<'d, T, Blocking> { +impl<'d> UartTx<'d, Blocking> { /// Create a new UART TX instance for blocking mode operations. - pub fn new_blocking(_uart: Peri<'d, T>, tx: Peri<'d, impl TxPin>, config: Config) -> Self { - Uart::::init(Some(tx.into()), None, None, None, config); - Self::new_inner(None) + pub fn new_blocking(_uart: Peri<'d, T>, tx: Peri<'d, impl TxPin>, config: Config) -> Self { + Uart::::init(T::info(), Some(tx.into()), None, None, None, config); + Self::new_inner::(None) } /// Convert this uart TX instance into a buffered uart using the provided /// irq and transmit buffer. - pub fn into_buffered( + pub fn into_buffered( self, - irq: impl Binding>, + _irq: impl Binding>, tx_buffer: &'d mut [u8], - ) -> BufferedUartTx<'d, T> { - buffered::init_buffers::(irq, Some(tx_buffer), None); + ) -> BufferedUartTx { + buffered::init_buffers(T::info(), T::buffered_state(), Some(tx_buffer), None); - BufferedUartTx { phantom: PhantomData } + BufferedUartTx { + info: T::info(), + state: T::buffered_state(), + } } } -impl<'d, T: Instance> UartTx<'d, T, Async> { +impl<'d> UartTx<'d, Async> { /// Write to UART TX from the provided buffer using DMA. pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> { let ch = self.tx_dma.as_mut().unwrap().reborrow(); let transfer = unsafe { - T::regs().uartdmacr().write_set(|reg| { + self.info.regs.uartdmacr().write_set(|reg| { reg.set_txdmae(true); }); // If we don't assign future to a variable, the data register pointer // is held across an await and makes the future non-Send. - crate::dma::write(ch, buffer, T::regs().uartdr().as_ptr() as *mut _, T::TX_DREQ.into()) + crate::dma::write( + ch, + buffer, + self.info.regs.uartdr().as_ptr() as *mut _, + self.info.tx_dreq.into(), + ) }; transfer.await; Ok(()) } } -impl<'d, T: Instance, M: Mode> UartRx<'d, T, M> { +impl<'d, M: Mode> UartRx<'d, M> { /// Create a new DMA-enabled UART which can only receive data - pub fn new( + pub fn new( _uart: Peri<'d, T>, rx: Peri<'d, impl RxPin>, _irq: impl Binding>, rx_dma: Peri<'d, impl Channel>, config: Config, ) -> Self { - Uart::::init(None, Some(rx.into()), None, None, config); - Self::new_inner(true, Some(rx_dma.into())) + Uart::::init(T::info(), None, Some(rx.into()), None, None, config); + Self::new_inner::(true, Some(rx_dma.into())) } - fn new_inner(has_irq: bool, rx_dma: Option>) -> Self { + fn new_inner(has_irq: bool, rx_dma: Option>) -> Self { debug_assert_eq!(has_irq, rx_dma.is_some()); if has_irq { // disable all error interrupts initially - T::regs().uartimsc().write(|w| w.0 = 0); + T::info().regs.uartimsc().write(|w| w.0 = 0); T::Interrupt::unpend(); unsafe { T::Interrupt::enable() }; } Self { + info: T::info(), + dma_state: T::dma_state(), rx_dma, phantom: PhantomData, } @@ -299,7 +313,7 @@ impl<'d, T: Instance, M: Mode> UartRx<'d, T, M> { /// encountered. in both cases, `len` is the number of *good* bytes copied into /// `buffer`. fn drain_fifo(&mut self, buffer: &mut [u8]) -> Result { - let r = T::regs(); + let r = self.info.regs; for (i, b) in buffer.iter_mut().enumerate() { if r.uartfr().read().rxfe() { return Ok(i); @@ -323,12 +337,12 @@ impl<'d, T: Instance, M: Mode> UartRx<'d, T, M> { } } -impl<'d, T: Instance, M: Mode> Drop for UartRx<'d, T, M> { +impl<'d, M: Mode> Drop for UartRx<'d, M> { fn drop(&mut self) { if self.rx_dma.is_some() { - T::Interrupt::disable(); + self.info.interrupt.disable(); // clear dma flags. irq handlers use these to disambiguate among themselves. - T::regs().uartdmacr().write_clear(|reg| { + self.info.regs.uartdmacr().write_clear(|reg| { reg.set_rxdmae(true); reg.set_txdmae(true); reg.set_dmaonerr(true); @@ -337,23 +351,26 @@ impl<'d, T: Instance, M: Mode> Drop for UartRx<'d, T, M> { } } -impl<'d, T: Instance> UartRx<'d, T, Blocking> { +impl<'d> UartRx<'d, Blocking> { /// Create a new UART RX instance for blocking mode operations. - pub fn new_blocking(_uart: Peri<'d, T>, rx: Peri<'d, impl RxPin>, config: Config) -> Self { - Uart::::init(None, Some(rx.into()), None, None, config); - Self::new_inner(false, None) + pub fn new_blocking(_uart: Peri<'d, T>, rx: Peri<'d, impl RxPin>, config: Config) -> Self { + Uart::::init(T::info(), None, Some(rx.into()), None, None, config); + Self::new_inner::(false, None) } /// Convert this uart RX instance into a buffered uart using the provided /// irq and receive buffer. - pub fn into_buffered( + pub fn into_buffered( self, - irq: impl Binding>, + _irq: impl Binding>, rx_buffer: &'d mut [u8], - ) -> BufferedUartRx<'d, T> { - buffered::init_buffers::(irq, None, Some(rx_buffer)); + ) -> BufferedUartRx { + buffered::init_buffers(T::info(), T::buffered_state(), None, Some(rx_buffer)); - BufferedUartRx { phantom: PhantomData } + BufferedUartRx { + info: T::info(), + state: T::buffered_state(), + } } } @@ -364,7 +381,7 @@ pub struct InterruptHandler { impl interrupt::typelevel::Handler for InterruptHandler { unsafe fn on_interrupt() { - let uart = T::regs(); + let uart = T::info().regs; if !uart.uartdmacr().read().rxdmae() { return; } @@ -380,13 +397,13 @@ impl interrupt::typelevel::Handler for InterruptHandl } } -impl<'d, T: Instance> UartRx<'d, T, Async> { +impl<'d> UartRx<'d, Async> { /// Read from UART RX into the provided buffer. pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { // clear error flags before we drain the fifo. errors that have accumulated // in the flags will also be present in the fifo. - T::dma_state().rx_errs.store(0, Ordering::Relaxed); - T::regs().uarticr().write(|w| { + self.dma_state.rx_errs.store(0, Ordering::Relaxed); + self.info.regs.uarticr().write(|w| { w.set_oeic(true); w.set_beic(true); w.set_peic(true); @@ -408,28 +425,33 @@ impl<'d, T: Instance> UartRx<'d, T, Async> { // interrupt flags will have been raised, and those will be picked up immediately // by the interrupt handler. let ch = self.rx_dma.as_mut().unwrap().reborrow(); - T::regs().uartimsc().write_set(|w| { + self.info.regs.uartimsc().write_set(|w| { w.set_oeim(true); w.set_beim(true); w.set_peim(true); w.set_feim(true); }); - T::regs().uartdmacr().write_set(|reg| { + self.info.regs.uartdmacr().write_set(|reg| { reg.set_rxdmae(true); reg.set_dmaonerr(true); }); let transfer = unsafe { // If we don't assign future to a variable, the data register pointer // is held across an await and makes the future non-Send. - crate::dma::read(ch, T::regs().uartdr().as_ptr() as *const _, buffer, T::RX_DREQ.into()) + crate::dma::read( + ch, + self.info.regs.uartdr().as_ptr() as *const _, + buffer, + self.info.rx_dreq.into(), + ) }; // wait for either the transfer to complete or an error to happen. let transfer_result = select( transfer, poll_fn(|cx| { - T::dma_state().rx_err_waker.register(cx.waker()); - match T::dma_state().rx_errs.swap(0, Ordering::Relaxed) { + self.dma_state.rx_err_waker.register(cx.waker()); + match self.dma_state.rx_errs.swap(0, Ordering::Relaxed) { 0 => Poll::Pending, e => Poll::Ready(Uartris(e as u32)), } @@ -441,7 +463,7 @@ impl<'d, T: Instance> UartRx<'d, T, Async> { Either::First(()) => { // We're here because the DMA finished, BUT if an error occurred on the LAST // byte, then we may still need to grab the error state! - Uartris(T::dma_state().rx_errs.swap(0, Ordering::Relaxed) as u32) + Uartris(self.dma_state.rx_errs.swap(0, Ordering::Relaxed) as u32) } Either::Second(e) => { // We're here because we errored, which means this is the error that @@ -521,8 +543,8 @@ impl<'d, T: Instance> UartRx<'d, T, Async> { ) -> Result { // clear error flags before we drain the fifo. errors that have accumulated // in the flags will also be present in the fifo. - T::dma_state().rx_errs.store(0, Ordering::Relaxed); - T::regs().uarticr().write(|w| { + self.dma_state.rx_errs.store(0, Ordering::Relaxed); + self.info.regs.uarticr().write(|w| { w.set_oeic(true); w.set_beic(true); w.set_peic(true); @@ -555,13 +577,13 @@ impl<'d, T: Instance> UartRx<'d, T, Async> { // interrupt flags will have been raised, and those will be picked up immediately // by the interrupt handler. let ch = self.rx_dma.as_mut().unwrap(); - T::regs().uartimsc().write_set(|w| { + self.info.regs.uartimsc().write_set(|w| { w.set_oeim(true); w.set_beim(true); w.set_peim(true); w.set_feim(true); }); - T::regs().uartdmacr().write_set(|reg| { + self.info.regs.uartdmacr().write_set(|reg| { reg.set_rxdmae(true); reg.set_dmaonerr(true); }); @@ -572,9 +594,9 @@ impl<'d, T: Instance> UartRx<'d, T, Async> { // is held across an await and makes the future non-Send. crate::dma::read( ch.reborrow(), - T::regs().uartdr().as_ptr() as *const _, + self.info.regs.uartdr().as_ptr() as *const _, sbuffer, - T::RX_DREQ.into(), + self.info.rx_dreq.into(), ) }; @@ -582,8 +604,8 @@ impl<'d, T: Instance> UartRx<'d, T, Async> { let transfer_result = select( transfer, poll_fn(|cx| { - T::dma_state().rx_err_waker.register(cx.waker()); - match T::dma_state().rx_errs.swap(0, Ordering::Relaxed) { + self.dma_state.rx_err_waker.register(cx.waker()); + match self.dma_state.rx_errs.swap(0, Ordering::Relaxed) { 0 => Poll::Pending, e => Poll::Ready(Uartris(e as u32)), } @@ -596,7 +618,7 @@ impl<'d, T: Instance> UartRx<'d, T, Async> { Either::First(()) => { // We're here because the DMA finished, BUT if an error occurred on the LAST // byte, then we may still need to grab the error state! - Uartris(T::dma_state().rx_errs.swap(0, Ordering::Relaxed) as u32) + Uartris(self.dma_state.rx_errs.swap(0, Ordering::Relaxed) as u32) } Either::Second(e) => { // We're here because we errored, which means this is the error that @@ -635,7 +657,7 @@ impl<'d, T: Instance> UartRx<'d, T, Async> { continue; } - let regs = T::regs(); + let regs = self.info.regs; let all_full = next_addr == eval; // NOTE: This is off label usage of RSR! See the issue below for @@ -685,9 +707,9 @@ impl<'d, T: Instance> UartRx<'d, T, Async> { } } -impl<'d, T: Instance> Uart<'d, T, Blocking> { +impl<'d> Uart<'d, Blocking> { /// Create a new UART without hardware flow control - pub fn new_blocking( + pub fn new_blocking( uart: Peri<'d, T>, tx: Peri<'d, impl TxPin>, rx: Peri<'d, impl RxPin>, @@ -697,7 +719,7 @@ impl<'d, T: Instance> Uart<'d, T, Blocking> { } /// Create a new UART with hardware flow control (RTS/CTS) - pub fn new_with_rtscts_blocking( + pub fn new_with_rtscts_blocking( uart: Peri<'d, T>, tx: Peri<'d, impl TxPin>, rx: Peri<'d, impl RxPin>, @@ -720,24 +742,30 @@ impl<'d, T: Instance> Uart<'d, T, Blocking> { /// Convert this uart instance into a buffered uart using the provided /// irq, transmit and receive buffers. - pub fn into_buffered( + pub fn into_buffered( self, - irq: impl Binding>, + _irq: impl Binding>, tx_buffer: &'d mut [u8], rx_buffer: &'d mut [u8], - ) -> BufferedUart<'d, T> { - buffered::init_buffers::(irq, Some(tx_buffer), Some(rx_buffer)); + ) -> BufferedUart { + buffered::init_buffers(T::info(), T::buffered_state(), Some(tx_buffer), Some(rx_buffer)); BufferedUart { - rx: BufferedUartRx { phantom: PhantomData }, - tx: BufferedUartTx { phantom: PhantomData }, + rx: BufferedUartRx { + info: T::info(), + state: T::buffered_state(), + }, + tx: BufferedUartTx { + info: T::info(), + state: T::buffered_state(), + }, } } } -impl<'d, T: Instance> Uart<'d, T, Async> { +impl<'d> Uart<'d, Async> { /// Create a new DMA enabled UART without hardware flow control - pub fn new( + pub fn new( uart: Peri<'d, T>, tx: Peri<'d, impl TxPin>, rx: Peri<'d, impl RxPin>, @@ -760,7 +788,7 @@ impl<'d, T: Instance> Uart<'d, T, Async> { } /// Create a new DMA enabled UART with hardware flow control (RTS/CTS) - pub fn new_with_rtscts( + pub fn new_with_rtscts( uart: Peri<'d, T>, tx: Peri<'d, impl TxPin>, rx: Peri<'d, impl RxPin>, @@ -785,8 +813,8 @@ impl<'d, T: Instance> Uart<'d, T, Async> { } } -impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> { - fn new_inner( +impl<'d, M: Mode> Uart<'d, M> { + fn new_inner( _uart: Peri<'d, T>, mut tx: Peri<'d, AnyPin>, mut rx: Peri<'d, AnyPin>, @@ -798,6 +826,7 @@ impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> { config: Config, ) -> Self { Self::init( + T::info(), Some(tx.reborrow()), Some(rx.reborrow()), rts.as_mut().map(|x| x.reborrow()), @@ -806,19 +835,20 @@ impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> { ); Self { - tx: UartTx::new_inner(tx_dma), - rx: UartRx::new_inner(has_irq, rx_dma), + tx: UartTx::new_inner::(tx_dma), + rx: UartRx::new_inner::(has_irq, rx_dma), } } fn init( + info: &Info, tx: Option>, rx: Option>, rts: Option>, cts: Option>, config: Config, ) { - let r = T::regs(); + let r = info.regs; if let Some(pin) = &tx { let funcsel = { let pin_number = ((pin.gpio().as_ptr() as u32) & 0x1FF) / 8; @@ -896,7 +926,7 @@ impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> { }); } - Self::set_baudrate_inner(config.baudrate); + Self::set_baudrate_inner(info, config.baudrate); let (pen, eps) = match config.parity { Parity::ParityNone => (false, false), @@ -926,8 +956,8 @@ impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> { }); } - fn lcr_modify(f: impl FnOnce(&mut crate::pac::uart::regs::UartlcrH) -> R) -> R { - let r = T::regs(); + fn lcr_modify(info: &Info, f: impl FnOnce(&mut crate::pac::uart::regs::UartlcrH) -> R) -> R { + let r = info.regs; // Notes from PL011 reference manual: // @@ -978,11 +1008,11 @@ impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> { /// sets baudrate on runtime pub fn set_baudrate(&mut self, baudrate: u32) { - Self::set_baudrate_inner(baudrate); + Self::set_baudrate_inner(self.tx.info, baudrate); } - fn set_baudrate_inner(baudrate: u32) { - let r = T::regs(); + fn set_baudrate_inner(info: &Info, baudrate: u32) { + let r = info.regs; let clk_base = crate::clocks::clk_peri_freq(); @@ -1002,11 +1032,11 @@ impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> { r.uartibrd().write_value(pac::uart::regs::Uartibrd(baud_ibrd)); r.uartfbrd().write_value(pac::uart::regs::Uartfbrd(baud_fbrd)); - Self::lcr_modify(|_| {}); + Self::lcr_modify(info, |_| {}); } } -impl<'d, T: Instance, M: Mode> Uart<'d, T, M> { +impl<'d, M: Mode> Uart<'d, M> { /// Transmit the provided buffer blocking execution until done. pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> { self.tx.blocking_write(buffer) @@ -1034,19 +1064,19 @@ impl<'d, T: Instance, M: Mode> Uart<'d, T, M> { /// Split the Uart into a transmitter and receiver, which is particularly /// useful when having two tasks correlating to transmitting and receiving. - pub fn split(self) -> (UartTx<'d, T, M>, UartRx<'d, T, M>) { + pub fn split(self) -> (UartTx<'d, M>, UartRx<'d, M>) { (self.tx, self.rx) } /// Split the Uart into a transmitter and receiver by mutable reference, /// which is particularly useful when having two tasks correlating to /// transmitting and receiving. - pub fn split_ref(&mut self) -> (&mut UartTx<'d, T, M>, &mut UartRx<'d, T, M>) { + pub fn split_ref(&mut self) -> (&mut UartTx<'d, M>, &mut UartRx<'d, M>) { (&mut self.tx, &mut self.rx) } } -impl<'d, T: Instance> Uart<'d, T, Async> { +impl<'d> Uart<'d, Async> { /// Write to UART TX from the provided buffer. pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> { self.tx.write(buffer).await @@ -1076,10 +1106,10 @@ impl<'d, T: Instance> Uart<'d, T, Async> { } } -impl<'d, T: Instance, M: Mode> embedded_hal_02::serial::Read for UartRx<'d, T, M> { +impl<'d, M: Mode> embedded_hal_02::serial::Read for UartRx<'d, M> { type Error = Error; fn read(&mut self) -> Result> { - let r = T::regs(); + let r = self.info.regs; if r.uartfr().read().rxfe() { return Err(nb::Error::WouldBlock); } @@ -1100,11 +1130,11 @@ impl<'d, T: Instance, M: Mode> embedded_hal_02::serial::Read for UartRx<'d, } } -impl<'d, T: Instance, M: Mode> embedded_hal_02::serial::Write for UartTx<'d, T, M> { +impl<'d, M: Mode> embedded_hal_02::serial::Write for UartTx<'d, M> { type Error = Error; fn write(&mut self, word: u8) -> Result<(), nb::Error> { - let r = T::regs(); + let r = self.info.regs; if r.uartfr().read().txff() { return Err(nb::Error::WouldBlock); } @@ -1114,7 +1144,7 @@ impl<'d, T: Instance, M: Mode> embedded_hal_02::serial::Write for UartTx<'d, } fn flush(&mut self) -> Result<(), nb::Error> { - let r = T::regs(); + let r = self.info.regs; if !r.uartfr().read().txfe() { return Err(nb::Error::WouldBlock); } @@ -1122,7 +1152,7 @@ impl<'d, T: Instance, M: Mode> embedded_hal_02::serial::Write for UartTx<'d, } } -impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::serial::Write for UartTx<'d, T, M> { +impl<'d, M: Mode> embedded_hal_02::blocking::serial::Write for UartTx<'d, M> { type Error = Error; fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { @@ -1134,7 +1164,7 @@ impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::serial::Write for } } -impl<'d, T: Instance, M: Mode> embedded_hal_02::serial::Read for Uart<'d, T, M> { +impl<'d, M: Mode> embedded_hal_02::serial::Read for Uart<'d, M> { type Error = Error; fn read(&mut self) -> Result> { @@ -1142,7 +1172,7 @@ impl<'d, T: Instance, M: Mode> embedded_hal_02::serial::Read for Uart<'d, T, } } -impl<'d, T: Instance, M: Mode> embedded_hal_02::serial::Write for Uart<'d, T, M> { +impl<'d, M: Mode> embedded_hal_02::serial::Write for Uart<'d, M> { type Error = Error; fn write(&mut self, word: u8) -> Result<(), nb::Error> { @@ -1154,7 +1184,7 @@ impl<'d, T: Instance, M: Mode> embedded_hal_02::serial::Write for Uart<'d, T } } -impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::serial::Write for Uart<'d, T, M> { +impl<'d, M: Mode> embedded_hal_02::blocking::serial::Write for Uart<'d, M> { type Error = Error; fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { @@ -1177,21 +1207,21 @@ impl embedded_hal_nb::serial::Error for Error { } } -impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::ErrorType for UartRx<'d, T, M> { +impl<'d, M: Mode> embedded_hal_nb::serial::ErrorType for UartRx<'d, M> { type Error = Error; } -impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::ErrorType for UartTx<'d, T, M> { +impl<'d, M: Mode> embedded_hal_nb::serial::ErrorType for UartTx<'d, M> { type Error = Error; } -impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::ErrorType for Uart<'d, T, M> { +impl<'d, M: Mode> embedded_hal_nb::serial::ErrorType for Uart<'d, M> { type Error = Error; } -impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::Read for UartRx<'d, T, M> { +impl<'d, M: Mode> embedded_hal_nb::serial::Read for UartRx<'d, M> { fn read(&mut self) -> nb::Result { - let r = T::regs(); + let r = self.info.regs; if r.uartfr().read().rxfe() { return Err(nb::Error::WouldBlock); } @@ -1212,7 +1242,7 @@ impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::Read for UartRx<'d, T, M } } -impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::Write for UartTx<'d, T, M> { +impl<'d, M: Mode> embedded_hal_nb::serial::Write for UartTx<'d, M> { fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> { self.blocking_write(&[char]).map_err(nb::Error::Other) } @@ -1222,11 +1252,11 @@ impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::Write for UartTx<'d, T, } } -impl<'d, T: Instance> embedded_io::ErrorType for UartTx<'d, T, Blocking> { +impl<'d> embedded_io::ErrorType for UartTx<'d, Blocking> { type Error = Error; } -impl<'d, T: Instance> embedded_io::Write for UartTx<'d, T, Blocking> { +impl<'d> embedded_io::Write for UartTx<'d, Blocking> { fn write(&mut self, buf: &[u8]) -> Result { self.blocking_write(buf).map(|_| buf.len()) } @@ -1236,13 +1266,13 @@ impl<'d, T: Instance> embedded_io::Write for UartTx<'d, T, Blocking> { } } -impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::Read for Uart<'d, T, M> { +impl<'d, M: Mode> embedded_hal_nb::serial::Read for Uart<'d, M> { fn read(&mut self) -> Result> { embedded_hal_02::serial::Read::read(&mut self.rx) } } -impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::Write for Uart<'d, T, M> { +impl<'d, M: Mode> embedded_hal_nb::serial::Write for Uart<'d, M> { fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> { self.blocking_write(&[char]).map_err(nb::Error::Other) } @@ -1252,11 +1282,11 @@ impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::Write for Uart<'d, T, M> } } -impl<'d, T: Instance> embedded_io::ErrorType for Uart<'d, T, Blocking> { +impl<'d> embedded_io::ErrorType for Uart<'d, Blocking> { type Error = Error; } -impl<'d, T: Instance> embedded_io::Write for Uart<'d, T, Blocking> { +impl<'d> embedded_io::Write for Uart<'d, Blocking> { fn write(&mut self, buf: &[u8]) -> Result { self.blocking_write(buf).map(|_| buf.len()) } @@ -1266,13 +1296,17 @@ impl<'d, T: Instance> embedded_io::Write for Uart<'d, T, Blocking> { } } +struct Info { + regs: pac::uart::Uart, + tx_dreq: pac::dma::vals::TreqSel, + rx_dreq: pac::dma::vals::TreqSel, + interrupt: Interrupt, +} + trait SealedMode {} trait SealedInstance { - const TX_DREQ: pac::dma::vals::TreqSel; - const RX_DREQ: pac::dma::vals::TreqSel; - - fn regs() -> pac::uart::Uart; + fn info() -> &'static Info; fn buffered_state() -> &'static buffered::State; @@ -1308,11 +1342,14 @@ pub trait Instance: SealedInstance + PeripheralType { macro_rules! impl_instance { ($inst:ident, $irq:ident, $tx_dreq:expr, $rx_dreq:expr) => { impl SealedInstance for peripherals::$inst { - const TX_DREQ: pac::dma::vals::TreqSel = $tx_dreq; - const RX_DREQ: pac::dma::vals::TreqSel = $rx_dreq; - - fn regs() -> pac::uart::Uart { - pac::$inst + fn info() -> &'static Info { + static INFO: Info = Info { + regs: pac::$inst, + tx_dreq: $tx_dreq, + rx_dreq: $rx_dreq, + interrupt: crate::interrupt::typelevel::$irq::IRQ, + }; + &INFO } fn buffered_state() -> &'static buffered::State { From 1efe59ec475aa38948d1fc95feb34860f08c8dcd Mon Sep 17 00:00:00 2001 From: Marc <35759328+marcemmers@users.noreply.github.com> Date: Fri, 2 May 2025 12:52:04 +0200 Subject: [PATCH 1054/1217] Update examples and tests --- examples/rp/src/bin/uart_buffered_split.rs | 2 +- examples/rp/src/bin/uart_unidir.rs | 2 +- tests/rp/src/bin/uart.rs | 6 +++--- tests/rp/src/bin/uart_buffered.rs | 6 +++--- tests/rp/src/bin/uart_dma.rs | 6 +++--- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/examples/rp/src/bin/uart_buffered_split.rs b/examples/rp/src/bin/uart_buffered_split.rs index da7e94139..3adbc18ab 100644 --- a/examples/rp/src/bin/uart_buffered_split.rs +++ b/examples/rp/src/bin/uart_buffered_split.rs @@ -48,7 +48,7 @@ async fn main(spawner: Spawner) { } #[embassy_executor::task] -async fn reader(mut rx: BufferedUartRx<'static, UART0>) { +async fn reader(mut rx: BufferedUartRx) { info!("Reading..."); loop { let mut buf = [0; 31]; diff --git a/examples/rp/src/bin/uart_unidir.rs b/examples/rp/src/bin/uart_unidir.rs index a45f40756..c2c8dfad8 100644 --- a/examples/rp/src/bin/uart_unidir.rs +++ b/examples/rp/src/bin/uart_unidir.rs @@ -39,7 +39,7 @@ async fn main(spawner: Spawner) { } #[embassy_executor::task] -async fn reader(mut rx: UartRx<'static, UART1, Async>) { +async fn reader(mut rx: UartRx<'static, Async>) { info!("Reading..."); loop { // read a total of 4 transmissions (32 / 8) and then print the result diff --git a/tests/rp/src/bin/uart.rs b/tests/rp/src/bin/uart.rs index 84744ab77..80230f3fe 100644 --- a/tests/rp/src/bin/uart.rs +++ b/tests/rp/src/bin/uart.rs @@ -8,17 +8,17 @@ teleprobe_meta::target!(b"pimoroni-pico-plus-2"); use defmt::{assert_eq, *}; use embassy_executor::Spawner; use embassy_rp::gpio::{Level, Output}; -use embassy_rp::uart::{Blocking, Config, Error, Instance, Parity, Uart, UartRx}; +use embassy_rp::uart::{Blocking, Config, Error, Parity, Uart, UartRx}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; -fn read(uart: &mut Uart<'_, impl Instance, Blocking>) -> Result<[u8; N], Error> { +fn read(uart: &mut Uart<'_, Blocking>) -> Result<[u8; N], Error> { let mut buf = [255; N]; uart.blocking_read(&mut buf)?; Ok(buf) } -fn read1(uart: &mut UartRx<'_, impl Instance, Blocking>) -> Result<[u8; N], Error> { +fn read1(uart: &mut UartRx<'_, Blocking>) -> Result<[u8; N], Error> { let mut buf = [255; N]; uart.blocking_read(&mut buf)?; Ok(buf) diff --git a/tests/rp/src/bin/uart_buffered.rs b/tests/rp/src/bin/uart_buffered.rs index d5f655e9b..cb78fc142 100644 --- a/tests/rp/src/bin/uart_buffered.rs +++ b/tests/rp/src/bin/uart_buffered.rs @@ -10,7 +10,7 @@ use embassy_executor::Spawner; use embassy_rp::bind_interrupts; use embassy_rp::gpio::{Level, Output}; use embassy_rp::peripherals::UART0; -use embassy_rp::uart::{BufferedInterruptHandler, BufferedUart, BufferedUartRx, Config, Error, Instance, Parity}; +use embassy_rp::uart::{BufferedInterruptHandler, BufferedUart, BufferedUartRx, Config, Error, Parity}; use embassy_time::Timer; use embedded_io_async::{Read, ReadExactError, Write}; use {defmt_rtt as _, panic_probe as _}; @@ -19,7 +19,7 @@ bind_interrupts!(struct Irqs { UART0_IRQ => BufferedInterruptHandler; }); -async fn read(uart: &mut BufferedUart<'_, impl Instance>) -> Result<[u8; N], Error> { +async fn read(uart: &mut BufferedUart) -> Result<[u8; N], Error> { let mut buf = [255; N]; match uart.read_exact(&mut buf).await { Ok(()) => Ok(buf), @@ -29,7 +29,7 @@ async fn read(uart: &mut BufferedUart<'_, impl Instance>) -> Res } } -async fn read1(uart: &mut BufferedUartRx<'_, impl Instance>) -> Result<[u8; N], Error> { +async fn read1(uart: &mut BufferedUartRx) -> Result<[u8; N], Error> { let mut buf = [255; N]; match uart.read_exact(&mut buf).await { Ok(()) => Ok(buf), diff --git a/tests/rp/src/bin/uart_dma.rs b/tests/rp/src/bin/uart_dma.rs index a09101223..a7af81f5f 100644 --- a/tests/rp/src/bin/uart_dma.rs +++ b/tests/rp/src/bin/uart_dma.rs @@ -10,7 +10,7 @@ use embassy_executor::Spawner; use embassy_rp::bind_interrupts; use embassy_rp::gpio::{Level, Output}; use embassy_rp::peripherals::UART0; -use embassy_rp::uart::{Async, Config, Error, Instance, InterruptHandler, Parity, Uart, UartRx}; +use embassy_rp::uart::{Async, Config, Error, InterruptHandler, Parity, Uart, UartRx}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; @@ -18,13 +18,13 @@ bind_interrupts!(struct Irqs { UART0_IRQ => InterruptHandler; }); -async fn read(uart: &mut Uart<'_, impl Instance, Async>) -> Result<[u8; N], Error> { +async fn read(uart: &mut Uart<'_, Async>) -> Result<[u8; N], Error> { let mut buf = [255; N]; uart.read(&mut buf).await?; Ok(buf) } -async fn read1(uart: &mut UartRx<'_, impl Instance, Async>) -> Result<[u8; N], Error> { +async fn read1(uart: &mut UartRx<'_, Async>) -> Result<[u8; N], Error> { let mut buf = [255; N]; uart.read(&mut buf).await?; Ok(buf) From 407540c8fe5061dfd245d605775fea36c2dd00ce Mon Sep 17 00:00:00 2001 From: Marc <35759328+marcemmers@users.noreply.github.com> Date: Fri, 2 May 2025 13:32:09 +0200 Subject: [PATCH 1055/1217] Remove some forgotten commented out code --- embassy-rp/src/uart/buffered.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/embassy-rp/src/uart/buffered.rs b/embassy-rp/src/uart/buffered.rs index 44b6ee469..02649ad81 100644 --- a/embassy-rp/src/uart/buffered.rs +++ b/embassy-rp/src/uart/buffered.rs @@ -43,14 +43,12 @@ pub struct BufferedUart { pub struct BufferedUartRx { pub(super) info: &'static Info, pub(super) state: &'static State, - // pub(crate) phantom: PhantomData<&'d mut T>, } /// Buffered UART TX handle. pub struct BufferedUartTx { pub(super) info: &'static Info, pub(super) state: &'static State, - // pub(crate) phantom: PhantomData<&'d mut T>, } pub(super) fn init_buffers<'d>( From d799af9dd82cda9cef3e5de91ae3e8555ad1d2d2 Mon Sep 17 00:00:00 2001 From: Marc <35759328+marcemmers@users.noreply.github.com> Date: Fri, 2 May 2025 13:40:50 +0200 Subject: [PATCH 1056/1217] Replace generic inner with arguments --- embassy-rp/src/uart/mod.rs | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/embassy-rp/src/uart/mod.rs b/embassy-rp/src/uart/mod.rs index d36884109..c3a15fda5 100644 --- a/embassy-rp/src/uart/mod.rs +++ b/embassy-rp/src/uart/mod.rs @@ -165,12 +165,12 @@ impl<'d, M: Mode> UartTx<'d, M> { config: Config, ) -> Self { Uart::::init(T::info(), Some(tx.into()), None, None, None, config); - Self::new_inner::(Some(tx_dma.into())) + Self::new_inner(T::info(), Some(tx_dma.into())) } - fn new_inner(tx_dma: Option>) -> Self { + fn new_inner(info: &'static Info, tx_dma: Option>) -> Self { Self { - info: T::info(), + info, tx_dma, phantom: PhantomData, } @@ -230,7 +230,7 @@ impl<'d> UartTx<'d, Blocking> { /// Create a new UART TX instance for blocking mode operations. pub fn new_blocking(_uart: Peri<'d, T>, tx: Peri<'d, impl TxPin>, config: Config) -> Self { Uart::::init(T::info(), Some(tx.into()), None, None, None, config); - Self::new_inner::(None) + Self::new_inner(T::info(), None) } /// Convert this uart TX instance into a buffered uart using the provided @@ -281,20 +281,25 @@ impl<'d, M: Mode> UartRx<'d, M> { config: Config, ) -> Self { Uart::::init(T::info(), None, Some(rx.into()), None, None, config); - Self::new_inner::(true, Some(rx_dma.into())) + Self::new_inner(T::info(), T::dma_state(), true, Some(rx_dma.into())) } - fn new_inner(has_irq: bool, rx_dma: Option>) -> Self { + fn new_inner( + info: &'static Info, + dma_state: &'static DmaState, + has_irq: bool, + rx_dma: Option>, + ) -> Self { debug_assert_eq!(has_irq, rx_dma.is_some()); if has_irq { // disable all error interrupts initially - T::info().regs.uartimsc().write(|w| w.0 = 0); - T::Interrupt::unpend(); - unsafe { T::Interrupt::enable() }; + info.regs.uartimsc().write(|w| w.0 = 0); + info.interrupt.unpend(); + unsafe { info.interrupt.enable() }; } Self { - info: T::info(), - dma_state: T::dma_state(), + info, + dma_state, rx_dma, phantom: PhantomData, } @@ -355,7 +360,7 @@ impl<'d> UartRx<'d, Blocking> { /// Create a new UART RX instance for blocking mode operations. pub fn new_blocking(_uart: Peri<'d, T>, rx: Peri<'d, impl RxPin>, config: Config) -> Self { Uart::::init(T::info(), None, Some(rx.into()), None, None, config); - Self::new_inner::(false, None) + Self::new_inner(T::info(), T::dma_state(), false, None) } /// Convert this uart RX instance into a buffered uart using the provided @@ -835,8 +840,8 @@ impl<'d, M: Mode> Uart<'d, M> { ); Self { - tx: UartTx::new_inner::(tx_dma), - rx: UartRx::new_inner::(has_irq, rx_dma), + tx: UartTx::new_inner(T::info(), tx_dma), + rx: UartRx::new_inner(T::info(), T::dma_state(), has_irq, rx_dma), } } From 371373886bb6cfa2a082835d87786a2916c74562 Mon Sep 17 00:00:00 2001 From: Marc <35759328+marcemmers@users.noreply.github.com> Date: Fri, 2 May 2025 14:23:58 +0200 Subject: [PATCH 1057/1217] Fix examples for rp235x --- examples/rp235x/src/bin/sharing.rs | 2 +- examples/rp235x/src/bin/uart_buffered_split.rs | 2 +- examples/rp235x/src/bin/uart_unidir.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/rp235x/src/bin/sharing.rs b/examples/rp235x/src/bin/sharing.rs index 5416e20ce..497c4f845 100644 --- a/examples/rp235x/src/bin/sharing.rs +++ b/examples/rp235x/src/bin/sharing.rs @@ -31,7 +31,7 @@ use rand::RngCore; use static_cell::{ConstStaticCell, StaticCell}; use {defmt_rtt as _, panic_probe as _}; -type UartAsyncMutex = mutex::Mutex>; +type UartAsyncMutex = mutex::Mutex>; struct MyType { inner: u32, diff --git a/examples/rp235x/src/bin/uart_buffered_split.rs b/examples/rp235x/src/bin/uart_buffered_split.rs index f707c4b5e..7cad09f9b 100644 --- a/examples/rp235x/src/bin/uart_buffered_split.rs +++ b/examples/rp235x/src/bin/uart_buffered_split.rs @@ -48,7 +48,7 @@ async fn main(spawner: Spawner) { } #[embassy_executor::task] -async fn reader(mut rx: BufferedUartRx<'static, UART0>) { +async fn reader(mut rx: BufferedUartRx) { info!("Reading..."); loop { let mut buf = [0; 31]; diff --git a/examples/rp235x/src/bin/uart_unidir.rs b/examples/rp235x/src/bin/uart_unidir.rs index 4e98f9e1e..45c9c8407 100644 --- a/examples/rp235x/src/bin/uart_unidir.rs +++ b/examples/rp235x/src/bin/uart_unidir.rs @@ -39,7 +39,7 @@ async fn main(spawner: Spawner) { } #[embassy_executor::task] -async fn reader(mut rx: UartRx<'static, UART1, Async>) { +async fn reader(mut rx: UartRx<'static, Async>) { info!("Reading..."); loop { // read a total of 4 transmissions (32 / 8) and then print the result From 8f3b6643b311a5a16fe6a64227066627990452b9 Mon Sep 17 00:00:00 2001 From: Marc <35759328+marcemmers@users.noreply.github.com> Date: Fri, 2 May 2025 14:36:08 +0200 Subject: [PATCH 1058/1217] And another fix, should be the last failing example --- examples/rp/src/bin/sharing.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/rp/src/bin/sharing.rs b/examples/rp/src/bin/sharing.rs index 5416e20ce..497c4f845 100644 --- a/examples/rp/src/bin/sharing.rs +++ b/examples/rp/src/bin/sharing.rs @@ -31,7 +31,7 @@ use rand::RngCore; use static_cell::{ConstStaticCell, StaticCell}; use {defmt_rtt as _, panic_probe as _}; -type UartAsyncMutex = mutex::Mutex>; +type UartAsyncMutex = mutex::Mutex>; struct MyType { inner: u32, From 3441e805070c7efb7cad20a84d1986e215b4de3d Mon Sep 17 00:00:00 2001 From: 1-rafael-1 Date: Fri, 2 May 2025 23:51:28 +0200 Subject: [PATCH 1059/1217] first batch of changes after review --- embassy-rp/src/clocks.rs | 322 +++++++++--------------- examples/rp/src/bin/overclock.rs | 11 +- examples/rp/src/bin/overclock_manual.rs | 20 +- tests/rp/src/bin/overclock.rs | 10 +- 4 files changed, 133 insertions(+), 230 deletions(-) diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs index 005564b8b..107e499b7 100644 --- a/embassy-rp/src/clocks.rs +++ b/embassy-rp/src/clocks.rs @@ -9,9 +9,8 @@ //! //! For most users, these functions provide an easy way to configure clocks: //! -//! - `ClockConfig::crystal(12_000_000)` - Default configuration with 12MHz crystal giving 125MHz system clock //! - `ClockConfig::at_sys_frequency_mhz(200)` - Set system clock to a specific frequency with automatic voltage scaling -//! - `ClockConfig::with_external_crystal(16_000_000)` - Configure with a non-standard crystal frequency +//! - `ClockConfig::crystal(12_000_000)` - Default configuration with 12MHz crystal giving 125MHz system clock //! //! ## Manual Configuration //! @@ -34,19 +33,9 @@ //! }); //! //! // Set voltage for overclocking -//! config.voltage_scale = Some(VoltageScale::V1_15); +//! config.core_voltage = CoreVoltage::V1_15; //! ``` //! -//! ## Voltage Scaling for Overclocking (RP2040 only) -//! -//! When overclocking beyond 133MHz, higher core voltages are needed: -//! -//! - Up to 133MHz: `VoltageScale::V1_10` (default) -//! - 133-200MHz: `VoltageScale::V1_15` -//! - Above 200MHz: `VoltageScale::V1_20` or higher -//! -//! The `at_sys_frequency_mhz()` function automatically sets appropriate voltages. -//! //! ## Examples //! //! ### Standard 125MHz configuration @@ -61,16 +50,16 @@ //! //! ### Overclock to 200MHz //! ```rust,ignore -//! let config = ClockConfig::at_sys_frequency_mhz(200); +//! let config = ClockConfig::crystal_freq(200_000_000); //! ``` //! //! ### Manual configuration for advanced scenarios //! ```rust,ignore -//! use embassy_rp::clocks::{ClockConfig, XoscConfig, PllConfig, VoltageScale}; +//! use embassy_rp::clocks::{ClockConfig, XoscConfig, PllConfig, CoreVoltage}; //! //! // Start with defaults and customize //! let mut config = ClockConfig::default(); -//! config.voltage_scale = Some(VoltageScale::V1_15); +//! config.core_voltage = CoreVoltage::V1_15; //! // Set other parameters as needed... //! ``` @@ -144,14 +133,16 @@ pub enum PeriClkSrc { // Gpin1 = ClkPeriCtrlAuxsrc::CLKSRC_GPIN1 as _ , } -/// Core voltage scaling options for RP2040. +/// Core voltage regulator settings for RP2040. /// /// The RP2040 voltage regulator can be configured for different output voltages. /// Higher voltages allow for higher clock frequencies but increase power consumption and heat. #[cfg(feature = "rp2040")] #[derive(Clone, Copy, Debug, PartialEq, Eq)] #[repr(u8)] -pub enum VoltageScale { +pub enum CoreVoltage { + /// 0.80V - Suitable for lower frequencies + V0_80 = 0b0000, /// 0.85V V0_85 = 0b0110, /// 0.90V @@ -162,11 +153,11 @@ pub enum VoltageScale { V1_00 = 0b1001, /// 1.05V V1_05 = 0b1010, - /// 1.10V + /// 1.10V - Default voltage level V1_10 = 0b1011, - /// 1.15V + /// 1.15V - Required for overclocking to 133-200MHz V1_15 = 0b1100, - /// 1.20V + /// 1.20V - Required for overclocking above 200MHz V1_20 = 0b1101, /// 1.25V V1_25 = 0b1110, @@ -175,21 +166,22 @@ pub enum VoltageScale { } #[cfg(feature = "rp2040")] -impl VoltageScale { +impl CoreVoltage { /// Get the recommended Brown-Out Detection (BOD) setting for this voltage. /// Sets the BOD threshold to approximately 90% of the core voltage. fn recommended_bod(self) -> u8 { match self { - VoltageScale::V0_85 => 0b0111, // 0.774V (~91% of 0.85V) - VoltageScale::V0_90 => 0b1000, // 0.817V (~91% of 0.90V) - VoltageScale::V0_95 => 0b1001, // 0.860V (~91% of 0.95V) - VoltageScale::V1_00 => 0b1010, // 0.903V (~90% of 1.00V) - VoltageScale::V1_05 => 0b1011, // 0.946V (~90% of 1.05V) - VoltageScale::V1_10 => 0b1100, // 0.989V (~90% of 1.10V) - VoltageScale::V1_15 => 0b1101, // 1.032V (~90% of 1.15V) - VoltageScale::V1_20 => 0b1110, // 1.075V (~90% of 1.20V) - VoltageScale::V1_25 => 0b1111, // 1.118V (~89% of 1.25V) - VoltageScale::V1_30 => 0b1111, // 1.118V (~86% of 1.30V) - using max available threshold + CoreVoltage::V0_80 => 0b0110, // 0.720V (~90% of 0.80V) + CoreVoltage::V0_85 => 0b0111, // 0.774V (~91% of 0.85V) + CoreVoltage::V0_90 => 0b1000, // 0.817V (~91% of 0.90V) + CoreVoltage::V0_95 => 0b1001, // 0.860V (~91% of 0.95V) + CoreVoltage::V1_00 => 0b1010, // 0.903V (~90% of 1.00V) + CoreVoltage::V1_05 => 0b1011, // 0.946V (~90% of 1.05V) + CoreVoltage::V1_10 => 0b1100, // 0.989V (~90% of 1.10V) + CoreVoltage::V1_15 => 0b1101, // 1.032V (~90% of 1.15V) + CoreVoltage::V1_20 => 0b1110, // 1.075V (~90% of 1.20V) + CoreVoltage::V1_25 => 0b1111, // 1.118V (~89% of 1.25V) + CoreVoltage::V1_30 => 0b1111, // 1.118V (~86% of 1.30V) - using max available threshold } } } @@ -214,9 +206,9 @@ pub struct ClockConfig { /// RTC clock configuration. #[cfg(feature = "rp2040")] pub rtc_clk: Option, - /// Core voltage scaling (RP2040 only). Defaults to 1.10V if None. + /// Core voltage scaling (RP2040 only). Defaults to 1.10V. #[cfg(feature = "rp2040")] - pub voltage_scale: Option, + pub core_voltage: CoreVoltage, /// Voltage stabilization delay in microseconds. /// If not set, defaults will be used based on voltage level. #[cfg(feature = "rp2040")] @@ -255,7 +247,7 @@ impl Default for ClockConfig { #[cfg(feature = "rp2040")] rtc_clk: None, #[cfg(feature = "rp2040")] - voltage_scale: None, + core_voltage: CoreVoltage::V1_10, #[cfg(feature = "rp2040")] voltage_stabilization_delay_us: None, // gpin0: None, @@ -327,7 +319,7 @@ impl ClockConfig { phase: 0, }), #[cfg(feature = "rp2040")] - voltage_scale: None, // Use hardware default (1.10V) + core_voltage: CoreVoltage::V1_10, // Use hardware default (1.10V) #[cfg(feature = "rp2040")] voltage_stabilization_delay_us: None, // gpin0: None, @@ -371,7 +363,7 @@ impl ClockConfig { phase: 0, }), #[cfg(feature = "rp2040")] - voltage_scale: None, // Use hardware default (1.10V) + core_voltage: CoreVoltage::V1_10, // Use hardware default (1.10V) #[cfg(feature = "rp2040")] voltage_stabilization_delay_us: None, // gpin0: None, @@ -379,146 +371,59 @@ impl ClockConfig { } } - /// Configure the system clock to a specific frequency in MHz. - /// - /// This is a user-friendly way to configure the system clock, similar to - /// the Pico SDK's approach. It automatically handles voltage scaling based on the - /// requested frequency and uses the standard 12MHz crystal found on most RP2040 boards. - /// - /// # Arguments - /// - /// * `sys_freq_mhz` - The target system clock frequency in MHz - /// - /// # Example - /// - /// ```rust,ignore - /// // Overclock to 200MHz - /// let config = ClockConfig::at_sys_frequency_mhz(200); - /// ``` - #[cfg(feature = "rp2040")] - pub fn at_sys_frequency_mhz(sys_freq_mhz: u32) -> Self { - // For 125MHz, use exactly the same config as the default to avoid any differences - if sys_freq_mhz == 125 { - return Self::crystal(12_000_000); - } - - // For other frequencies, provide appropriate voltage scaling and PLL configuration - // Standard crystal on Raspberry Pi Pico boards is 12MHz - const DEFAULT_CRYSTAL_HZ: u32 = 12_000_000; - - let sys_freq_hz = sys_freq_mhz * 1_000_000; - let config = Self::crystal_freq(DEFAULT_CRYSTAL_HZ, sys_freq_hz); - - config - } - - /// Configure the system clock to a specific frequency in Hz, using a custom crystal frequency. - /// - /// This more flexible version allows specifying both the crystal frequency and target - /// system frequency for boards with non-standard crystals. - /// - /// # Arguments - /// - /// * `crystal_hz` - The frequency of the external crystal in Hz - /// * `sys_freq_hz` - The target system clock frequency in Hz - /// - /// # Example - /// - /// ```rust,ignore - /// // Use a non-standard 16MHz crystal to achieve 250MHz - /// let config = ClockConfig::with_custom_crystal(16_000_000, 250_000_000); - /// ``` - #[cfg(feature = "rp2040")] - pub fn with_custom_crystal(crystal_hz: u32, sys_freq_hz: u32) -> Self { - Self::crystal_freq(crystal_hz, sys_freq_hz) - } - /// Configure clocks derived from an external crystal with specific system frequency. /// /// This function calculates optimal PLL parameters to achieve the requested system - /// frequency from the given crystal frequency. It's used internally by higher-level - /// configuration functions. + /// frequency. This only works for the usual 12MHz crystal. In case a different crystal is used, + /// You will have to set the PLL parameters manually. /// /// # Arguments /// - /// * `crystal_hz` - The frequency of the external crystal in Hz /// * `sys_freq_hz` - The desired system clock frequency in Hz /// /// # Returns /// /// A ClockConfig configured to achieve the requested system frequency using the - /// specified crystal, or panic if no valid parameters can be found. + /// the usual 12Mhz crystal, or panic if no valid parameters can be found. + /// + /// # Note on core voltage: + /// To date the only officially documented core voltages (see Datasheet section 2.15.3.1. Instances) are: + /// - Up to 133MHz: V1_10 (default) + /// - Above 133MHz: V1_15, but in the context of the datasheet covering reaching up to 200Mhz + /// That way all other frequencies below 133MHz or above 200MHz are not explicitly documented and not covered here. + /// In case You want to go below 133MHz or above 200MHz and want a different voltage, You will have to set that manually and with caution. #[cfg(feature = "rp2040")] - fn crystal_freq(crystal_hz: u32, sys_freq_hz: u32) -> Self { + pub fn crystal_freq(sys_freq_hz: u32) -> Self { + // Start with the standard configuration from crystal() + const DEFAULT_CRYSTAL_HZ: u32 = 12_000_000; + let mut config = Self::crystal(DEFAULT_CRYSTAL_HZ); + + // No need to modify anything if target frequency is already 125MHz + // (which is what crystal() configures by default) + if sys_freq_hz == 125_000_000 { + return config; + } + // Find optimal PLL parameters for the requested frequency - let sys_pll_params = find_pll_params(crystal_hz, sys_freq_hz) + let sys_pll_params = find_pll_params(DEFAULT_CRYSTAL_HZ, sys_freq_hz) .unwrap_or_else(|| panic!("Could not find valid PLL parameters for system clock")); + // Replace the sys_pll configuration with our custom parameters + if let Some(xosc) = &mut config.xosc { + xosc.sys_pll = Some(sys_pll_params); + } + // Set the voltage scale based on the target frequency // Higher frequencies require higher voltage - let voltage_scale = match sys_freq_hz { - freq if freq > 200_000_000 => Some(VoltageScale::V1_20), - freq if freq > 133_000_000 => Some(VoltageScale::V1_15), - _ => None, // Use default voltage (V1_10) - }; - - // For USB PLL, we always want 48MHz for USB - let usb_pll_params = if crystal_hz == 12_000_000 { - // For standard 12MHz crystal, use the default parameters - PllConfig { - refdiv: 1, - fbdiv: 120, - post_div1: 6, - post_div2: 5, - } - } else { - // For other crystals, calculate parameters to get 48MHz - find_pll_params(crystal_hz, 48_000_000) - .unwrap_or_else(|| panic!("Could not find valid PLL parameters for USB clock")) - }; - - Self { - rosc: Some(RoscConfig { - hz: 6_500_000, - range: RoscRange::Medium, - drive_strength: [0; 8], - div: 16, - }), - xosc: Some(XoscConfig { - hz: crystal_hz, - sys_pll: Some(sys_pll_params), - usb_pll: Some(usb_pll_params), - delay_multiplier: 128, - }), - ref_clk: RefClkConfig { - src: RefClkSrc::Xosc, - div: 1, - }, - sys_clk: SysClkConfig { - src: SysClkSrc::PllSys, - div_int: 1, - div_frac: 0, - }, - peri_clk_src: Some(PeriClkSrc::Sys), - usb_clk: Some(UsbClkConfig { - src: UsbClkSrc::PllUsb, - div: 1, - phase: 0, - }), - adc_clk: Some(AdcClkConfig { - src: AdcClkSrc::PllUsb, - div: 1, - phase: 0, - }), - rtc_clk: Some(RtcClkConfig { - src: RtcClkSrc::PllUsb, - div_int: 1024, - div_frac: 0, - phase: 0, - }), - voltage_scale, - voltage_stabilization_delay_us: None, + #[cfg(feature = "rp2040")] + { + config.core_voltage = match sys_freq_hz { + freq if freq > 133_000_000 => CoreVoltage::V1_15, + _ => CoreVoltage::V1_10, // Use default voltage (V1_10) + }; } + + config } /// Configure with manual PLL settings for full control over system clock @@ -530,7 +435,7 @@ impl ClockConfig { /// /// * `xosc_hz` - The frequency of the external crystal in Hz /// * `pll_config` - The PLL configuration parameters to achieve desired frequency - /// * `voltage_scale` - Optional voltage scaling for overclocking (required for >133MHz) + /// * `core_voltage` - Voltage scaling for overclocking (required for >133MHz) /// /// # Returns /// @@ -549,11 +454,11 @@ impl ClockConfig { /// post_div1: 3, // First post divider (1200 MHz / 3 = 400 MHz) /// post_div2: 2, // Second post divider (400 MHz / 2 = 200 MHz) /// }, - /// Some(VoltageScale::V1_15) + /// CoreVoltage::V1_15 /// ); /// ``` #[cfg(feature = "rp2040")] - pub fn manual_pll(xosc_hz: u32, pll_config: PllConfig, voltage_scale: Option) -> Self { + pub fn manual_pll(xosc_hz: u32, pll_config: PllConfig, core_voltage: CoreVoltage) -> Self { // Calculate the actual output frequency for documentation // let ref_freq = xosc_hz / pll_config.refdiv as u32; // let vco_freq = ref_freq * pll_config.fbdiv as u32; @@ -587,7 +492,7 @@ impl ClockConfig { div_frac: 0, }; - config.voltage_scale = voltage_scale; + config.core_voltage = core_voltage; config.peri_clk_src = Some(PeriClkSrc::Sys); // Set reasonable defaults for other clocks @@ -865,7 +770,7 @@ pub struct RtcClkConfig { /// /// # Parameters /// -/// * `input_hz`: The input frequency in Hz (typically the crystal frequency, e.g. 12MHz) +/// * `input_hz`: The input frequency in Hz (typically the crystal frequency, e.g. 12MHz for th most common one used on rp2040 boards) /// * `target_hz`: The desired output frequency in Hz (e.g. 125MHz for standard RP2040 operation) /// /// # Returns @@ -990,7 +895,8 @@ pub(crate) unsafe fn init(config: ClockConfig) { // Set Core Voltage (RP2040 only), if we have config for it and we're not using the default #[cfg(feature = "rp2040")] - if let Some(voltage) = config.voltage_scale { + { + let voltage = config.core_voltage; let vreg = pac::VREG_AND_CHIP_RESET; let current_vsel = vreg.vreg().read().vsel(); let target_vsel = voltage as u8; @@ -1002,9 +908,9 @@ pub(crate) unsafe fn init(config: ClockConfig) { // Wait for the voltage to stabilize. Use the provided delay or default based on voltage let settling_time_us = config.voltage_stabilization_delay_us.unwrap_or_else(|| { match voltage { - VoltageScale::V1_15 => 1000, // 1ms for 1.15V - VoltageScale::V1_20 | VoltageScale::V1_25 | VoltageScale::V1_30 => 2000, // 2ms for higher voltages - _ => 0, // no delay for all others + CoreVoltage::V1_15 => 1000, // 1ms for 1.15V + CoreVoltage::V1_20 | CoreVoltage::V1_25 | CoreVoltage::V1_30 => 2000, // 2ms for higher voltages + _ => 0, // no delay for all others } }); @@ -1042,9 +948,8 @@ pub(crate) unsafe fn init(config: ClockConfig) { }; CLOCKS.xosc.store(xosc_freq, Ordering::Relaxed); - // SETUP TEMPORARY STABLE CLOCKS FIRST + // Setup temporary stable clocks first // Configure USB PLL for our stable temporary clock - // This follows the SDK's approach of using USB PLL as a stable intermediate clock let pll_usb_freq = match &config.xosc { Some(config) => match &config.usb_pll { Some(pll_usb_config) => { @@ -1055,7 +960,13 @@ pub(crate) unsafe fn init(config: ClockConfig) { reset::unreset_wait(peris); // Configure the USB PLL - this should give us 48MHz - let usb_pll_freq = configure_pll(pac::PLL_USB, xosc_freq, *pll_usb_config); + let usb_pll_freq = match configure_pll(pac::PLL_USB, xosc_freq, *pll_usb_config) { + Ok(freq) => freq, + Err(_) => { + panic!("Failed to configure USB PLL"); + } + }; + CLOCKS.pll_usb.store(usb_pll_freq, Ordering::Relaxed); usb_pll_freq } @@ -1074,7 +985,7 @@ pub(crate) unsafe fn init(config: ClockConfig) { while c.clk_ref_selected().read() != pac::clocks::regs::ClkRefSelected(1 << ClkRefCtrlSrc::XOSC_CLKSRC as u32) {} // First switch the system clock to a stable source (USB PLL at 48MHz) - // This follows the Pico SDK's approach to ensure stability during reconfiguration + // This follows the official Pico SDK's approach to ensure stability during reconfiguration c.clk_sys_ctrl().write(|w| { w.set_auxsrc(ClkSysCtrlAuxsrc::CLKSRC_PLL_USB); w.set_src(ClkSysCtrlSrc::CLKSRC_CLK_SYS_AUX); @@ -1101,7 +1012,12 @@ pub(crate) unsafe fn init(config: ClockConfig) { reset::unreset_wait(peris); // Configure the SYS PLL - let pll_sys_freq = configure_pll(pac::PLL_SYS, xosc_freq, *sys_pll_config); + let pll_sys_freq = match configure_pll(pac::PLL_SYS, xosc_freq, *sys_pll_config) { + Ok(freq) => freq, + Err(_) => { + panic!("Failed to configure system PLL"); + } + }; // Ensure PLL is locked and stable cortex_m::asm::delay(100); @@ -1411,7 +1327,7 @@ fn start_xosc(crystal_hz: u32, delay_multiplier: u32) { /// PLL (Phase-Locked Loop) configuration #[inline(always)] -fn configure_pll(p: pac::pll::Pll, input_freq: u32, config: PllConfig) -> u32 { +fn configure_pll(p: pac::pll::Pll, input_freq: u32, config: PllConfig) -> Result { // Calculate reference frequency let ref_freq = input_freq / config.refdiv as u32; @@ -1482,7 +1398,7 @@ fn configure_pll(p: pac::pll::Pll, input_freq: u32, config: PllConfig) -> u32 { timeout -= 1; if timeout == 0 { // PLL failed to lock, return 0 to indicate failure - return 0; + return Err("PLL failed to lock"); } } @@ -1502,7 +1418,7 @@ fn configure_pll(p: pac::pll::Pll, input_freq: u32, config: PllConfig) -> u32 { cortex_m::asm::delay(100); // Calculate and return actual output frequency - vco_freq / ((config.post_div1 * config.post_div2) as u32) + Ok(vco_freq / ((config.post_div1 * config.post_div2) as u32)) } /// General purpose input clock pin. @@ -1883,25 +1799,6 @@ pub fn dormant_sleep() { mod tests { use super::*; - #[cfg(feature = "rp2040")] - #[test] - fn test_voltage_scale_bod_values() { - // Test that each voltage level maps to the correct BOD threshold (approx. 90% of VDD) - // This verifies our BOD settings match our documentation - { - assert_eq!(VoltageScale::V0_85.recommended_bod(), 0b0111); // ~0.774V (91% of 0.85V) - assert_eq!(VoltageScale::V0_90.recommended_bod(), 0b1000); // ~0.817V (91% of 0.90V) - assert_eq!(VoltageScale::V0_95.recommended_bod(), 0b1001); // ~0.860V (91% of 0.95V) - assert_eq!(VoltageScale::V1_00.recommended_bod(), 0b1010); // ~0.903V (90% of 1.00V) - assert_eq!(VoltageScale::V1_05.recommended_bod(), 0b1011); // ~0.946V (90% of 1.05V) - assert_eq!(VoltageScale::V1_10.recommended_bod(), 0b1100); // ~0.989V (90% of 1.10V) - assert_eq!(VoltageScale::V1_15.recommended_bod(), 0b1101); // ~1.032V (90% of 1.15V) - assert_eq!(VoltageScale::V1_20.recommended_bod(), 0b1110); // ~1.075V (90% of 1.20V) - assert_eq!(VoltageScale::V1_25.recommended_bod(), 0b1111); // ~1.118V (89% of 1.25V) - assert_eq!(VoltageScale::V1_30.recommended_bod(), 0b1111); // ~1.118V (86% of 1.30V) - using max available - } - } - #[cfg(feature = "rp2040")] #[test] fn test_find_pll_params() { @@ -1942,7 +1839,12 @@ mod tests { let vco_freq = (16_000_000 / params.refdiv as u32) as u64 * params.fbdiv as u64; let output_freq = (vco_freq / ((params.post_div1 * params.post_div2) as u64)) as u32; - // With a 16 MHz crystal, we might not get exactly 125 MHz + // Test non-standard crystal with 15 MHz + let params = find_pll_params(15_000_000, 125_000_000).unwrap(); + let vco_freq = (15_000_000 / params.refdiv as u32) as u64 * params.fbdiv as u64; + let output_freq = (vco_freq / ((params.post_div1 * params.post_div2) as u64)) as u32; + + // With a 15 MHz crystal, we might not get exactly 125 MHz // Check that it's close enough (within 0.2% margin) let freq_diff = if output_freq > 125_000_000 { output_freq - 125_000_000 @@ -2033,11 +1935,11 @@ mod tests { post_div1: 3, post_div2: 2, }, - Some(VoltageScale::V1_15), + CoreVoltage::V1_15, ); // Check voltage scale was set correctly - assert_eq!(config.voltage_scale, Some(VoltageScale::V1_15)); + assert_eq!(config.core_voltage, CoreVoltage::V1_15); // Check PLL config was set correctly assert_eq!(config.xosc.as_ref().unwrap().sys_pll.as_ref().unwrap().refdiv, 1); @@ -2065,19 +1967,23 @@ mod tests { fn test_auto_voltage_scaling() { { // Test automatic voltage scaling based on frequency - // Under 133 MHz should use default voltage (None) - let config = ClockConfig::at_sys_frequency_mhz(125); - assert_eq!(config.voltage_scale, None); + // Under 133 MHz should use default voltage (V1_10) + let config = ClockConfig::crystal_freq(125_000_000); + assert_eq!(config.core_voltage, CoreVoltage::V1_10); // 133-200 MHz should use V1_15 - let config = ClockConfig::at_sys_frequency_mhz(150); - assert_eq!(config.voltage_scale, Some(VoltageScale::V1_15)); - let config = ClockConfig::at_sys_frequency_mhz(200); - assert_eq!(config.voltage_scale, Some(VoltageScale::V1_15)); + let config = ClockConfig::crystal_freq(150_000_000); + assert_eq!(config.core_voltage, CoreVoltage::V1_15); + let config = ClockConfig::crystal_freq(200_000_000); + assert_eq!(config.core_voltage, CoreVoltage::V1_15); - // Above 200 MHz should use V1_20 - let config = ClockConfig::at_sys_frequency_mhz(250); - assert_eq!(config.voltage_scale, Some(VoltageScale::V1_20)); + // Above 200 MHz should use V1_25 + let config = ClockConfig::crystal_freq(250_000_000); + assert_eq!(config.core_voltage, CoreVoltage::V1_15); + + // Below 125 MHz should use V1_10 + let config = ClockConfig::crystal_freq(100_000_000); + assert_eq!(config.core_voltage, CoreVoltage::V1_10); } } } diff --git a/examples/rp/src/bin/overclock.rs b/examples/rp/src/bin/overclock.rs index e3ac77340..f9a8c94d0 100644 --- a/examples/rp/src/bin/overclock.rs +++ b/examples/rp/src/bin/overclock.rs @@ -1,6 +1,6 @@ //! # Overclocking the RP2040 to 200 MHz //! -//! This example demonstrates how to configure the RP2040 to run at 200 MHz using a higher level API. +//! This example demonstrates how to configure the RP2040 to run at 200 MHz. #![no_std] #![no_main] @@ -17,19 +17,18 @@ const COUNT_TO: i64 = 10_000_000; #[embassy_executor::main] async fn main(_spawner: Spawner) -> ! { - // Set up for clock frequency of 200 MHz - // This will set all the necessary defaults including slightly raised voltage - let config = Config::new(ClockConfig::at_sys_frequency_mhz(200)); + // Set up for clock frequency of 200 MHz, setting all necessary defaults. + let config = Config::new(ClockConfig::crystal_freq(200_000_000)); // Show the voltage scale for verification - info!("System core voltage: {}", Debug2Format(&config.clocks.voltage_scale)); + info!("System core voltage: {}", Debug2Format(&config.clocks.core_voltage)); // Initialize the peripherals let p = embassy_rp::init(config); // Show CPU frequency for verification let sys_freq = clk_sys_freq(); - info!("System clock frequency: {} Hz", sys_freq); + info!("System clock frequency: {} MHz", sys_freq / 1_000_000); // LED to indicate the system is running let mut led = Output::new(p.PIN_25, Level::Low); diff --git a/examples/rp/src/bin/overclock_manual.rs b/examples/rp/src/bin/overclock_manual.rs index ad6abf0e7..35160b250 100644 --- a/examples/rp/src/bin/overclock_manual.rs +++ b/examples/rp/src/bin/overclock_manual.rs @@ -8,7 +8,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_rp::clocks; -use embassy_rp::clocks::{ClockConfig, PllConfig, VoltageScale}; +use embassy_rp::clocks::{ClockConfig, CoreVoltage, PllConfig}; use embassy_rp::config::Config; use embassy_rp::gpio::{Level, Output}; use embassy_time::{Duration, Instant, Timer}; @@ -16,23 +16,21 @@ use {defmt_rtt as _, panic_probe as _}; const COUNT_TO: i64 = 10_000_000; -/// Configure the RP2040 for 200 MHz operation by manually specifying -/// all the required parameters instead of using higher-level APIs. +/// Configure the RP2040 for 200 MHz operation by manually specifying the PLL settings. fn configure_manual_overclock() -> Config { // Set the PLL configuration manually, starting from default values let mut config = Config::default(); - // Set the system clock to 200 MHz using a PLL with a reference frequency of 12 MHz + // Set the system clock to 200 MHz config.clocks = ClockConfig::manual_pll( - 12_000_000, + 12_000_000, // Crystal frequency, 12 MHz is common. If using custom, set to your value. PllConfig { - refdiv: 1, - fbdiv: 100, - post_div1: 3, - post_div2: 2, + refdiv: 1, // Reference divider + fbdiv: 100, // Feedback divider + post_div1: 3, // Post divider 1 + post_div2: 2, // Post divider 2 }, - // For 200 MHz, we need a voltage scale of 1.15V - Some(VoltageScale::V1_15), + CoreVoltage::V1_15, // Core voltage, should be set to V1_15 for 200 MHz ); config diff --git a/tests/rp/src/bin/overclock.rs b/tests/rp/src/bin/overclock.rs index e4845a55f..6c58a6b90 100644 --- a/tests/rp/src/bin/overclock.rs +++ b/tests/rp/src/bin/overclock.rs @@ -14,7 +14,7 @@ use embassy_rp::clocks; #[cfg(feature = "rp2040")] use embassy_rp::clocks::ClockConfig; #[cfg(feature = "rp2040")] -use embassy_rp::clocks::VoltageScale; +use embassy_rp::clocks::CoreVoltage; use embassy_rp::config::Config; use embassy_time::Instant; use {defmt_rtt as _, panic_probe as _}; @@ -31,15 +31,15 @@ async fn main(_spawner: Spawner) { // Initialize with 200MHz clock configuration for RP2040, other chips will use default clock #[cfg(feature = "rp2040")] { - config.clocks = ClockConfig::at_sys_frequency_mhz(200); - let voltage = config.clocks.voltage_scale.unwrap(); - assert!(matches!(voltage, VoltageScale::V1_15), "Expected voltage scale V1_15"); + config.clocks = ClockConfig::crystal_freq(200_000_000); + let voltage = config.clocks.core_voltage; + assert!(matches!(voltage, CoreVoltage::V1_15), "Expected voltage scale V1_15"); } let _p = embassy_rp::init(config); + // Test the system speed let (time_elapsed, clk_sys_freq) = { - // Test the system speed let mut counter = 0; let start = Instant::now(); while counter < COUNT_TO { From e5c03e1e791bf3460fe6e0af65a02f2259763eaa Mon Sep 17 00:00:00 2001 From: Yuri Astrakhan Date: Fri, 2 May 2025 17:56:32 -0400 Subject: [PATCH 1060/1217] chore: use `probe-rs` instead of `probe-run` I found a few remaining deprecated `probe-run` cases. --- docs/examples/basic/.cargo/config.toml | 4 ++-- docs/examples/layer-by-layer/.cargo/config.toml | 3 ++- docs/pages/getting_started.adoc | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/docs/examples/basic/.cargo/config.toml b/docs/examples/basic/.cargo/config.toml index 8ca28df39..17616a054 100644 --- a/docs/examples/basic/.cargo/config.toml +++ b/docs/examples/basic/.cargo/config.toml @@ -1,6 +1,6 @@ [target.'cfg(all(target_arch = "arm", target_os = "none"))'] -# replace nRF82840_xxAA with your chip as listed in `probe-run --list-chips` -runner = "probe-run --chip nRF52840_xxAA" +# replace nRF82840_xxAA with your chip as listed in `probe-rs chip list` +runner = "probe-rs run --chip nRF52840_xxAA" [build] target = "thumbv7em-none-eabi" diff --git a/docs/examples/layer-by-layer/.cargo/config.toml b/docs/examples/layer-by-layer/.cargo/config.toml index 3012f05dc..f30d9e446 100644 --- a/docs/examples/layer-by-layer/.cargo/config.toml +++ b/docs/examples/layer-by-layer/.cargo/config.toml @@ -1,5 +1,6 @@ [target.'cfg(all(target_arch = "arm", target_os = "none"))'] -runner = "probe-run --chip STM32L475VG" +# replace your chip as listed in `probe-rs chip list` +runner = "probe-rs run --chip STM32L475VG" rustflags = [ "-C", "link-arg=--nmagic", diff --git a/docs/pages/getting_started.adoc b/docs/pages/getting_started.adoc index 954f3fd28..d1f65a885 100644 --- a/docs/pages/getting_started.adoc +++ b/docs/pages/getting_started.adoc @@ -66,7 +66,7 @@ If everything worked correctly, you should see a blinking LED on your board, and [source] ---- Finished dev [unoptimized + debuginfo] target(s) in 1m 56s - Running `probe-run --chip STM32F407VGTx target/thumbv7em-none-eabi/debug/blinky` + Running `probe-rs run --chip STM32F407VGTx target/thumbv7em-none-eabi/debug/blinky` (HOST) INFO flashing program (71.36 KiB) (HOST) INFO success! ──────────────────────────────────────────────────────────────────────────────── From 7f259aaff26bb060e49f91f894ff00e257e1a744 Mon Sep 17 00:00:00 2001 From: Yuri Astrakhan Date: Fri, 2 May 2025 21:54:21 -0400 Subject: [PATCH 1061/1217] chore: minor readme cleanup use simpler markdown linking, minor grammar cleanup --- README.md | 85 +++++++++++++++++++++++++++++-------------------------- 1 file changed, 45 insertions(+), 40 deletions(-) diff --git a/README.md b/README.md index 383fb6671..669fa469b 100644 --- a/README.md +++ b/README.md @@ -1,52 +1,55 @@ # Embassy -Embassy is the next-generation framework for embedded applications. Write safe, correct and energy-efficient embedded code faster, using the Rust programming language, its async facilities, and the Embassy libraries. +Embassy is the next-generation framework for embedded applications. Write safe, correct, and energy-efficient embedded code faster, using the Rust programming language, its async facilities, and the Embassy libraries. + +## [Documentation](https://embassy.dev/book/index.html) - [API reference](https://docs.embassy.dev/) - [Website](https://embassy.dev/) - [Chat](https://matrix.to/#/#embassy-rs:matrix.org) -## Documentation - API reference - Website - Chat ## Rust + async â¤ï¸ embedded -The Rust programming language is blazingly fast and memory-efficient, with no runtime, garbage collector or OS. It catches a wide variety of bugs at compile time, thanks to its full memory- and thread-safety, and expressive type system. +The Rust programming language is blazingly fast and memory-efficient, with no runtime, garbage collector, or OS. It catches a wide variety of bugs at compile time, thanks to its full memory- and thread-safety, and expressive type system. -Rust's async/await allows for unprecedentedly easy and efficient multitasking in embedded systems. Tasks get transformed at compile time into state machines that get run cooperatively. It requires no dynamic memory allocation, and runs on a single stack, so no per-task stack size tuning is required. It obsoletes the need for a traditional RTOS with kernel context switching, and is faster and smaller than one! +Rust's [async/await](https://rust-lang.github.io/async-book/) allows for unprecedentedly easy and efficient multitasking in embedded systems. Tasks get transformed at compile time into state machines that get run cooperatively. It requires no dynamic memory allocation and runs on a single stack, so no per-task stack size tuning is required. It obsoletes the need for a traditional RTOS with kernel context switching, and is [faster and smaller than one!](https://tweedegolf.nl/en/blog/65/async-rust-vs-rtos-showdown) ## Batteries included -- **Hardware Abstraction Layers** - HALs implement safe, idiomatic Rust APIs to use the hardware capabilities, so raw register manipulation is not needed. The Embassy project maintains HALs for select hardware, but you can still use HALs from other projects with Embassy. - - embassy-stm32, for all STM32 microcontroller families. - - embassy-nrf, for the Nordic Semiconductor nRF52, nRF53, nRF54 and nRF91 series. - - embassy-rp, for the Raspberry Pi RP2040 and RP23xx microcontrollers. - - embassy-mspm0, for the Texas Instruments MSPM0 microcontrollers. - - esp-rs, for the Espressif Systems ESP32 series of chips. - - Embassy HAL support for Espressif chips, as well as Async WiFi, Bluetooth and ESP-NOW, is being developed in the [esp-rs/esp-hal](https://github.com/esp-rs/esp-hal) repository. - - ch32-hal, for the WCH 32-bit RISC-V(CH32V) series of chips. - - mpfs-hal, for the Microchip PolarFire SoC. - - py32-hal, for the Puya Semiconductor PY32 series of microcontrollers. +- **Hardware Abstraction Layers + ** - HALs implement safe, idiomatic Rust APIs to use the hardware capabilities, so raw register manipulation is not needed. The Embassy project maintains HALs for select hardware, but you can still use HALs from other projects with Embassy. + - [embassy-stm32](https://docs.embassy.dev/embassy-stm32/), for all STM32 microcontroller families. + - [embassy-nrf](https://docs.embassy.dev/embassy-nrf/), for the Nordic Semiconductor nRF52, nRF53, nRF54 and nRF91 series. + - [embassy-rp](https://docs.embassy.dev/embassy-rp/), for the Raspberry Pi RP2040 and RP23xx microcontrollers. + - [embassy-mspm0](https://docs.embassy.dev/embassy-mspm0/), for the Texas Instruments MSPM0 microcontrollers. + - [esp-rs](https://github.com/esp-rs), for the Espressif Systems ESP32 series of chips. + - Embassy HAL support for Espressif chips, as well as Async Wi-Fi, Bluetooth, and ESP-NOW, is being developed in the [esp-rs/esp-hal](https://github.com/esp-rs/esp-hal) repository. + - [ch32-hal](https://github.com/ch32-rs/ch32-hal), for the WCH 32-bit RISC-V(CH32V) series of chips. + - [mpfs-hal](https://github.com/AlexCharlton/mpfs-hal), for the Microchip PolarFire SoC. + - [py32-hal](https://github.com/py32-rs/py32-hal), for the Puya Semiconductor PY32 series of microcontrollers. -- **Time that Just Works** - -No more messing with hardware timers. embassy_time provides Instant, Duration and Timer types that are globally available and never overflow. +- **Time that Just Works** - + No more messing with hardware timers. [embassy_time](https://docs.embassy.dev/embassy-time) provides Instant, Duration, and Timer types that are globally available and never overflow. -- **Real-time ready** - -Tasks on the same async executor run cooperatively, but you can create multiple executors with different priorities, so that higher priority tasks preempt lower priority ones. See the example. +- **Real-time ready** - + Tasks on the same async executor run cooperatively, but you can create multiple executors with different priorities so that higher priority tasks preempt lower priority ones. See the [example](https://github.com/embassy-rs/embassy/blob/master/examples/nrf52840/src/bin/multiprio.rs). -- **Low-power ready** - -Easily build devices with years of battery life. The async executor automatically puts the core to sleep when there's no work to do. Tasks are woken by interrupts, there is no busy-loop polling while waiting. - -- **Networking** - -The embassy-net network stack implements extensive networking functionality, including Ethernet, IP, TCP, UDP, ICMP and DHCP. Async drastically simplifies managing timeouts and serving multiple connections concurrently. +- **Low-power ready** - + Easily build devices with years of battery life. The async executor automatically puts the core to sleep when there's no work to do. Tasks are woken by interrupts, there is no busy-loop polling while waiting. + +- **Networking** - + The [embassy-net](https://docs.embassy.dev/embassy-net/) network stack implements extensive networking functionality, including Ethernet, IP, TCP, UDP, ICMP, and DHCP. Async drastically simplifies managing timeouts and serving multiple connections concurrently. - **Bluetooth** - - The trouble crate provides a Bluetooth Low Energy 4.x and 5.x Host that runs on any microcontroller implementing the bt-hci traits (currently `nRF52`, `rp2040`, `rp23xx` and `esp32` and `serial` controllers are supported). - - The nrf-softdevice crate provides Bluetooth Low Energy 4.x and 5.x support for nRF52 microcontrollers. - - The embassy-stm32-wpan crate provides Bluetooth Low Energy 5.x support for stm32wb microcontrollers. + - The [trouble](https://github.com/embassy-rs/trouble) crate provides a Bluetooth Low Energy 4.x and 5.x Host that runs on any microcontroller implementing the [bt-hci](https://github.com/embassy-rs/bt-hci) traits (currently + `nRF52`, `rp2040`, `rp23xx` and `esp32` and `serial` controllers are supported). + - The [nrf-softdevice](https://github.com/embassy-rs/nrf-softdevice) crate provides Bluetooth Low Energy 4.x and 5.x support for nRF52 microcontrollers. + - The [embassy-stm32-wpan](https://github.com/embassy-rs/embassy/tree/main/embassy-stm32-wpan) crate provides Bluetooth Low Energy 5.x support for stm32wb microcontrollers. -- **LoRa** - The lora-rs project provides an async LoRa and LoRaWAN stack that works well on Embassy. +- **LoRa** - + The [lora-rs](https://github.com/lora-rs/lora-rs) project provides an async LoRa and LoRaWAN stack that works well on Embassy. -- **USB** - -embassy-usb implements a device-side USB stack. Implementations for common classes such as USB serial (CDC ACM) and USB HID are available, and a rich builder API allows building your own. - -- **Bootloader and DFU** - -embassy-boot is a lightweight bootloader supporting firmware application upgrades in a power-fail-safe way, with trial boots and rollbacks. +- **USB** - + [embassy-usb](https://docs.embassy.dev/embassy-usb/) implements a device-side USB stack. Implementations for common classes such as USB serial (CDC ACM) and USB HID are available, and a rich builder API allows building your own. +- **Bootloader and DFU** - + [embassy-boot](https://github.com/embassy-rs/embassy/tree/master/embassy-boot) is a lightweight bootloader supporting firmware application upgrades in a power-fail-safe way, with trial boots and rollbacks. ## Sneak peek @@ -93,13 +96,15 @@ async fn main(spawner: Spawner) { ## Examples -Examples are found in the `examples/` folder separated by the chip manufacturer they are designed to run on. For example: +Examples are found in the +`examples/` folder separated by the chip manufacturer they are designed to run on. For example: -* `examples/nrf52840` run on the `nrf52840-dk` board (PCA10056) but should be easily adaptable to other nRF52 chips and boards. -* `examples/nrf5340` run on the `nrf5340-dk` board (PCA10095). -* `examples/stm32xx` for the various STM32 families. -* `examples/rp` are for the RP2040 chip. -* `examples/std` are designed to run locally on your PC. +* `examples/nrf52840` run on the + `nrf52840-dk` board (PCA10056) but should be easily adaptable to other nRF52 chips and boards. +* `examples/nrf5340` run on the `nrf5340-dk` board (PCA10095). +* `examples/stm32xx` for the various STM32 families. +* `examples/rp` are for the RP2040 chip. +* `examples/std` are designed to run locally on your PC. ### Running examples @@ -126,7 +131,7 @@ cargo run --release --bin blinky For more help getting started, see [Getting Started][1] and [Running the Examples][2]. -## Developing Embassy with Rust Analyzer based editors +## Developing Embassy with Rust Analyzer-based editors The [Rust Analyzer](https://rust-analyzer.github.io/) is used by [Visual Studio Code](https://code.visualstudio.com/) and others. Given the multiple targets that Embassy serves, there is no Cargo workspace file. Instead, the Rust Analyzer @@ -136,7 +141,7 @@ please refer to the `.vscode/settings.json` file's `rust-analyzer.linkedProjects ## Minimum supported Rust version (MSRV) Embassy is guaranteed to compile on stable Rust 1.75 and up. It *might* -compile with older versions but that may change in any new patch release. +compile with older versions, but that may change in any new patch release. ## Why the name? From 3d9cac361ed6bd0cd00cab7bf924608c89de9108 Mon Sep 17 00:00:00 2001 From: 1-rafael-1 Date: Sat, 3 May 2025 14:46:30 +0200 Subject: [PATCH 1062/1217] Add PIO clock divider utility and refactor related modules --- embassy-rp/src/pio_programs/clock_divider.rs | 25 +++++++++++++++++++ embassy-rp/src/pio_programs/hd44780.rs | 14 ++++------- embassy-rp/src/pio_programs/mod.rs | 1 + embassy-rp/src/pio_programs/rotary_encoder.rs | 10 +++----- embassy-rp/src/pio_programs/stepper.rs | 18 ++++++------- 5 files changed, 43 insertions(+), 25 deletions(-) create mode 100644 embassy-rp/src/pio_programs/clock_divider.rs diff --git a/embassy-rp/src/pio_programs/clock_divider.rs b/embassy-rp/src/pio_programs/clock_divider.rs new file mode 100644 index 000000000..02e353f53 --- /dev/null +++ b/embassy-rp/src/pio_programs/clock_divider.rs @@ -0,0 +1,25 @@ +//! Helper functions for calculating PIO clock dividers + +use fixed::traits::ToFixed; +use fixed::types::extra::U8; + +use crate::clocks::clk_sys_freq; + +/// Calculate a PIO clock divider value based on the desired target frequency. +/// +/// # Arguments +/// +/// * `target_hz` - The desired PIO clock frequency in Hz +/// +/// # Returns +/// +/// A fixed-point divider value suitable for use in a PIO state machine configuration +#[inline] +pub fn calculate_pio_clock_divider(target_hz: u32) -> fixed::FixedU32 { + // Requires a non-zero frequency + assert!(target_hz > 0, "PIO clock frequency cannot be zero"); + + // Calculate the divider + let divider = (clk_sys_freq() + target_hz / 2) / target_hz; + divider.to_fixed() +} diff --git a/embassy-rp/src/pio_programs/hd44780.rs b/embassy-rp/src/pio_programs/hd44780.rs index 3aa54495f..546c85a89 100644 --- a/embassy-rp/src/pio_programs/hd44780.rs +++ b/embassy-rp/src/pio_programs/hd44780.rs @@ -1,11 +1,11 @@ //! [HD44780 display driver](https://www.sparkfun.com/datasheets/LCD/HD44780.pdf) -use crate::clocks::clk_sys_freq; use crate::dma::{AnyChannel, Channel}; use crate::pio::{ Common, Config, Direction, FifoJoin, Instance, Irq, LoadedProgram, PioPin, ShiftConfig, ShiftDirection, StateMachine, }; +use crate::pio_programs::clock_divider::calculate_pio_clock_divider; use crate::Peri; /// This struct represents a HD44780 program that takes command words ( <0:4>) @@ -136,10 +136,8 @@ impl<'l, P: Instance, const S: usize> PioHD44780<'l, P, S> { let mut cfg = Config::default(); cfg.use_program(&word_prg.prg, &[&e]); - // Scale the divider based on system clock frequency - // Original: 125 at 125 MHz (1 MHz PIO clock) - let word_divider = (clk_sys_freq() / 1_000_000) as u8; // Target 1 MHz PIO clock - cfg.clock_divider = word_divider.into(); + // Target 1 MHz PIO clock (each cycle is 1µs) + cfg.clock_divider = calculate_pio_clock_divider(1_000_000); cfg.set_out_pins(&[&db4, &db5, &db6, &db7]); cfg.shift_out = ShiftConfig { @@ -167,10 +165,8 @@ impl<'l, P: Instance, const S: usize> PioHD44780<'l, P, S> { let mut cfg = Config::default(); cfg.use_program(&seq_prg.prg, &[&e]); - // Original: 8 at 125 MHz (~15.6 MHz PIO clock) - // Comment says ~64ns/insn which is 1/(15.6 MHz) = ~64ns - let seq_divider = (clk_sys_freq() / 15_600_000) as u8; // Target ~15.6 MHz PIO clock (~64ns/insn) - cfg.clock_divider = seq_divider.into(); + // Target ~15.6 MHz PIO clock (~64ns/insn) + cfg.clock_divider = calculate_pio_clock_divider(15_600_000); cfg.set_jmp_pin(&db7); cfg.set_set_pins(&[&rs, &rw]); diff --git a/embassy-rp/src/pio_programs/mod.rs b/embassy-rp/src/pio_programs/mod.rs index 74537825b..8eac328b3 100644 --- a/embassy-rp/src/pio_programs/mod.rs +++ b/embassy-rp/src/pio_programs/mod.rs @@ -1,5 +1,6 @@ //! Pre-built pio programs for common interfaces +pub mod clock_divider; pub mod hd44780; pub mod i2s; pub mod onewire; diff --git a/embassy-rp/src/pio_programs/rotary_encoder.rs b/embassy-rp/src/pio_programs/rotary_encoder.rs index 71567a602..70b3795e9 100644 --- a/embassy-rp/src/pio_programs/rotary_encoder.rs +++ b/embassy-rp/src/pio_programs/rotary_encoder.rs @@ -1,12 +1,10 @@ //! PIO backed quadrature encoder -use fixed::traits::ToFixed; - -use crate::clocks::clk_sys_freq; use crate::gpio::Pull; use crate::pio::{ Common, Config, Direction as PioDirection, FifoJoin, Instance, LoadedProgram, PioPin, ShiftDirection, StateMachine, }; +use crate::pio_programs::clock_divider::calculate_pio_clock_divider; use crate::Peri; /// This struct represents an Encoder program loaded into pio instruction memory. @@ -50,10 +48,8 @@ impl<'d, T: Instance, const SM: usize> PioEncoder<'d, T, SM> { cfg.fifo_join = FifoJoin::RxOnly; cfg.shift_in.direction = ShiftDirection::Left; - // Original: 10_000 at 125 MHz (12.5 KHz PIO clock) - // Scale divider to maintain same PIO clock frequency at different system clocks - let divider = (clk_sys_freq() as f32 / 12_500.0).to_fixed(); - cfg.clock_divider = divider; + // Target 12.5 KHz PIO clock + cfg.clock_divider = calculate_pio_clock_divider(12_500); cfg.use_program(&program.prg, &[]); sm.set_config(&cfg); diff --git a/embassy-rp/src/pio_programs/stepper.rs b/embassy-rp/src/pio_programs/stepper.rs index 6878c32f5..0e9a8daf9 100644 --- a/embassy-rp/src/pio_programs/stepper.rs +++ b/embassy-rp/src/pio_programs/stepper.rs @@ -2,12 +2,8 @@ use core::mem::{self, MaybeUninit}; -use fixed::traits::ToFixed; -use fixed::types::extra::U8; -use fixed::FixedU32; - -use crate::clocks::clk_sys_freq; use crate::pio::{Common, Config, Direction, Instance, Irq, LoadedProgram, PioPin, StateMachine}; +use crate::pio_programs::clock_divider::calculate_pio_clock_divider; use crate::Peri; /// This struct represents a Stepper driver program loaded into pio instruction memory. @@ -65,7 +61,9 @@ impl<'d, T: Instance, const SM: usize> PioStepper<'d, T, SM> { sm.set_pin_dirs(Direction::Out, &[&pin0, &pin1, &pin2, &pin3]); let mut cfg = Config::default(); cfg.set_out_pins(&[&pin0, &pin1, &pin2, &pin3]); - cfg.clock_divider = (clk_sys_freq() / (100 * 136)).to_fixed(); + + cfg.clock_divider = calculate_pio_clock_divider(100 * 136); + cfg.use_program(&program.prg, &[]); sm.set_config(&cfg); sm.set_enable(true); @@ -74,9 +72,11 @@ impl<'d, T: Instance, const SM: usize> PioStepper<'d, T, SM> { /// Set pulse frequency pub fn set_frequency(&mut self, freq: u32) { - let clock_divider: FixedU32 = (clk_sys_freq() / (freq * 136)).to_fixed(); - assert!(clock_divider <= 65536, "clkdiv must be <= 65536"); - assert!(clock_divider >= 1, "clkdiv must be >= 1"); + let clock_divider = calculate_pio_clock_divider(freq * 136); + let divider_f32 = clock_divider.to_num::(); + assert!(divider_f32 <= 65536.0, "clkdiv must be <= 65536"); + assert!(divider_f32 >= 1.0, "clkdiv must be >= 1"); + self.sm.set_clock_divider(clock_divider); self.sm.clkdiv_restart(); } From 0406b83c526f03567863d80a603db77c514df27f Mon Sep 17 00:00:00 2001 From: Hiroaki Yutani Date: Sun, 4 May 2025 09:39:35 +0900 Subject: [PATCH 1063/1217] Tweak the example `rust-toolchain.toml` in doc --- docs/pages/project_structure.adoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/pages/project_structure.adoc b/docs/pages/project_structure.adoc index 722ec8d9d..227508b97 100644 --- a/docs/pages/project_structure.adoc +++ b/docs/pages/project_structure.adoc @@ -85,9 +85,9 @@ A minimal example: [source,toml] ---- [toolchain] -channel = "nightly-2023-08-19" # <- as of writing, this is the exact rust version embassy uses +channel = "1.85" # <- as of writing, this is the exact rust version embassy uses components = [ "rust-src", "rustfmt" ] # <- optionally add "llvm-tools-preview" for some extra features like "cargo size" targets = [ - "thumbv6m-none-eabi" # <-change for your platform + "thumbv6m-none-eabi" # <- change for your platform ] ---- From a42fa0a67aef90453b239b62b81df8db20664c87 Mon Sep 17 00:00:00 2001 From: Hiroaki Yutani Date: Sun, 4 May 2025 09:54:37 +0900 Subject: [PATCH 1064/1217] Tweak --- docs/pages/new_project.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/pages/new_project.adoc b/docs/pages/new_project.adoc index af1cb75c5..cd943b4f6 100644 --- a/docs/pages/new_project.adoc +++ b/docs/pages/new_project.adoc @@ -150,7 +150,7 @@ stm32g474-example # Before upgrading check that everything is available on all tier1 targets here: # https://rust-lang.github.io/rustup-components-history [toolchain] -channel = "nightly-2023-11-01" +channel = "1.85" components = [ "rust-src", "rustfmt", "llvm-tools", "miri" ] targets = ["thumbv7em-none-eabi"] ---- From 723ebfcb4f17e48f2a614f0e1e124e8da9c75b70 Mon Sep 17 00:00:00 2001 From: JuliDi <20155974+JuliDi@users.noreply.github.com> Date: Sun, 4 May 2025 16:31:26 +0200 Subject: [PATCH 1065/1217] clarify docs for signal and watch --- embassy-sync/src/signal.rs | 5 +++-- embassy-sync/src/watch.rs | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/embassy-sync/src/signal.rs b/embassy-sync/src/signal.rs index a0f4b5a74..e7095401e 100644 --- a/embassy-sync/src/signal.rs +++ b/embassy-sync/src/signal.rs @@ -6,7 +6,7 @@ use core::task::{Context, Poll, Waker}; use crate::blocking_mutex::raw::RawMutex; use crate::blocking_mutex::Mutex; -/// Single-slot signaling primitive. +/// Single-slot signaling primitive for a _single_ consumer. /// /// This is similar to a [`Channel`](crate::channel::Channel) with a buffer size of 1, except /// "sending" to it (calling [`Signal::signal`]) when full will overwrite the previous value instead @@ -17,6 +17,7 @@ use crate::blocking_mutex::Mutex; /// updates. /// /// For more advanced use cases, you might want to use [`Channel`](crate::channel::Channel) instead. +/// For multiple consumers, use [`Watch`](crate::watch::Watch) instead. /// /// Signals are generally declared as `static`s and then borrowed as required. /// @@ -106,7 +107,7 @@ where }) } - /// Future that completes when this Signal has been signaled. + /// Future that completes when this Signal has been signaled, taking the value out of the signal. pub fn wait(&self) -> impl Future + '_ { poll_fn(move |cx| self.poll_wait(cx)) } diff --git a/embassy-sync/src/watch.rs b/embassy-sync/src/watch.rs index e76646c0b..08d6a833d 100644 --- a/embassy-sync/src/watch.rs +++ b/embassy-sync/src/watch.rs @@ -10,7 +10,7 @@ use crate::blocking_mutex::raw::RawMutex; use crate::blocking_mutex::Mutex; use crate::waitqueue::MultiWakerRegistration; -/// The `Watch` is a single-slot signaling primitive that allows multiple receivers to concurrently await +/// The `Watch` is a single-slot signaling primitive that allows _multiple_ (`N`) receivers to concurrently await /// changes to the value. Unlike a [`Signal`](crate::signal::Signal), `Watch` supports multiple receivers, /// and unlike a [`PubSubChannel`](crate::pubsub::PubSubChannel), `Watch` immediately overwrites the previous /// value when a new one is sent, without waiting for all receivers to read the previous value. @@ -298,7 +298,7 @@ impl WatchBehavior for Watch } impl Watch { - /// Create a new `Watch` channel. + /// Create a new `Watch` channel for `N` receivers. pub const fn new() -> Self { Self { mutex: Mutex::new(RefCell::new(WatchState { From a97be9c7400cb6608ff94ef3c887ac7cc816e4ec Mon Sep 17 00:00:00 2001 From: Hiroaki Yutani Date: Mon, 5 May 2025 12:41:20 +0900 Subject: [PATCH 1066/1217] Handle negative value --- examples/rp235x/src/bin/pio_rotary_encoder_rxf.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/rp235x/src/bin/pio_rotary_encoder_rxf.rs b/examples/rp235x/src/bin/pio_rotary_encoder_rxf.rs index ccc601661..33499babb 100644 --- a/examples/rp235x/src/bin/pio_rotary_encoder_rxf.rs +++ b/examples/rp235x/src/bin/pio_rotary_encoder_rxf.rs @@ -88,8 +88,8 @@ impl<'d, T: Instance, const SM: usize> PioEncoder<'d, T, SM> { Self { sm } } - pub async fn read(&mut self) -> u32 { - self.sm.get_rxf_entry(0) + pub async fn read(&mut self) -> i32 { + self.sm.get_rxf_entry(0) as i32 } } From 0d03aa0bec01fb0289915861d997bf7f2cf8d232 Mon Sep 17 00:00:00 2001 From: 1-rafael-1 Date: Mon, 5 May 2025 22:55:09 +0200 Subject: [PATCH 1067/1217] rework init() --- embassy-rp/src/clocks.rs | 266 ++++++++++++++++----------------------- 1 file changed, 108 insertions(+), 158 deletions(-) diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs index 107e499b7..a4cc129ab 100644 --- a/embassy-rp/src/clocks.rs +++ b/embassy-rp/src/clocks.rs @@ -168,20 +168,20 @@ pub enum CoreVoltage { #[cfg(feature = "rp2040")] impl CoreVoltage { /// Get the recommended Brown-Out Detection (BOD) setting for this voltage. - /// Sets the BOD threshold to approximately 90% of the core voltage. + /// Sets the BOD threshold to approximately 80% of the core voltage. fn recommended_bod(self) -> u8 { match self { - CoreVoltage::V0_80 => 0b0110, // 0.720V (~90% of 0.80V) - CoreVoltage::V0_85 => 0b0111, // 0.774V (~91% of 0.85V) - CoreVoltage::V0_90 => 0b1000, // 0.817V (~91% of 0.90V) - CoreVoltage::V0_95 => 0b1001, // 0.860V (~91% of 0.95V) - CoreVoltage::V1_00 => 0b1010, // 0.903V (~90% of 1.00V) - CoreVoltage::V1_05 => 0b1011, // 0.946V (~90% of 1.05V) - CoreVoltage::V1_10 => 0b1100, // 0.989V (~90% of 1.10V) - CoreVoltage::V1_15 => 0b1101, // 1.032V (~90% of 1.15V) - CoreVoltage::V1_20 => 0b1110, // 1.075V (~90% of 1.20V) - CoreVoltage::V1_25 => 0b1111, // 1.118V (~89% of 1.25V) - CoreVoltage::V1_30 => 0b1111, // 1.118V (~86% of 1.30V) - using max available threshold + CoreVoltage::V0_80 => 0b0100, // 0.645V (~81% of 0.80V) + CoreVoltage::V0_85 => 0b0101, // 0.688V (~81% of 0.85V) + CoreVoltage::V0_90 => 0b0110, // 0.731V (~81% of 0.90V) + CoreVoltage::V0_95 => 0b0111, // 0.774V (~81% of 0.95V) + CoreVoltage::V1_00 => 0b1000, // 0.817V (~82% of 1.00V) + CoreVoltage::V1_05 => 0b1000, // 0.817V (~78% of 1.05V) + CoreVoltage::V1_10 => 0b1001, // 0.860V (~78% of 1.10V) + CoreVoltage::V1_15 => 0b1010, // 0.903V (~79% of 1.15V) + CoreVoltage::V1_20 => 0b1011, // 0.946V (~79% of 1.20V) + CoreVoltage::V1_25 => 0b1100, // 0.989V (~79% of 1.25V) + CoreVoltage::V1_30 => 0b1101, // 1.032V (~79% of 1.30V) } } } @@ -459,11 +459,6 @@ impl ClockConfig { /// ``` #[cfg(feature = "rp2040")] pub fn manual_pll(xosc_hz: u32, pll_config: PllConfig, core_voltage: CoreVoltage) -> Self { - // Calculate the actual output frequency for documentation - // let ref_freq = xosc_hz / pll_config.refdiv as u32; - // let vco_freq = ref_freq * pll_config.fbdiv as u32; - // let sys_freq = vco_freq / ((pll_config.post_div1 * pll_config.post_div2) as u32); - // Validate PLL parameters assert!(pll_config.is_valid(xosc_hz), "Invalid PLL parameters"); @@ -893,6 +888,30 @@ pub(crate) unsafe fn init(config: ClockConfig) { #[cfg(feature = "_rp235x")] while c.clk_ref_selected().read() != pac::clocks::regs::ClkRefSelected(1) {} + // Reset the PLLs + let mut peris = reset::Peripherals(0); + peris.set_pll_sys(true); + peris.set_pll_usb(true); + reset::reset(peris); + reset::unreset_wait(peris); + + // let gpin0_freq = config.gpin0.map_or(0, |p| { + // core::mem::forget(p.1); + // p.0 + // }); + // CLOCKS.gpin0.store(gpin0_freq, Ordering::Relaxed); + // let gpin1_freq = config.gpin1.map_or(0, |p| { + // core::mem::forget(p.1); + // p.0 + // }); + // CLOCKS.gpin1.store(gpin1_freq, Ordering::Relaxed); + + let rosc_freq = match config.rosc { + Some(config) => configure_rosc(config), + None => 0, + }; + CLOCKS.rosc.store(rosc_freq, Ordering::Relaxed); + // Set Core Voltage (RP2040 only), if we have config for it and we're not using the default #[cfg(feature = "rp2040")] { @@ -901,8 +920,9 @@ pub(crate) unsafe fn init(config: ClockConfig) { let current_vsel = vreg.vreg().read().vsel(); let target_vsel = voltage as u8; + // If the target voltage is different from the current one, we need to change it if target_vsel != current_vsel { - // Use modify() instead of write() to preserve the HIZ and EN bits - otherwise we will disable the regulator when changing voltage + // Use modify() to preserve the HIZ and EN bits - otherwise we will disable the regulator when changing voltage vreg.vreg().modify(|w| w.set_vsel(target_vsel)); // Wait for the voltage to stabilize. Use the provided delay or default based on voltage @@ -914,16 +934,14 @@ pub(crate) unsafe fn init(config: ClockConfig) { } }); - // We need a clock that's guaranteed to be running at this point - // Use ROSC which should be configured by now - let rosc_freq_rough = 6_000_000; // Rough ROSC frequency estimate - let cycles_per_us = rosc_freq_rough / 1_000_000; - let delay_cycles = settling_time_us * cycles_per_us; + if settling_time_us != 0 { + // Delay in microseconds, using the ROSC frequency to calculate cycles + let cycles_per_us = rosc_freq / 1_000_000; + let delay_cycles = settling_time_us * cycles_per_us; + cortex_m::asm::delay(delay_cycles); + } - // Wait for voltage to stabilize - cortex_m::asm::delay(delay_cycles); - - // Only now set the BOD level after voltage has stabilized + // Only now set the BOD level. At htis point the voltage is considered stable. vreg.bod().write(|w| { w.set_vsel(voltage.recommended_bod()); w.set_en(true); // Enable brownout detection @@ -931,108 +949,64 @@ pub(crate) unsafe fn init(config: ClockConfig) { } } - // Configure ROSC first if present - let rosc_freq = match config.rosc { - Some(config) => configure_rosc(config), - None => 0, - }; - CLOCKS.rosc.store(rosc_freq, Ordering::Relaxed); - - // Configure XOSC - we'll need this for our temporary stable clock - let xosc_freq = match &config.xosc { + let (xosc_freq, pll_sys_freq, pll_usb_freq) = match config.xosc { Some(config) => { + // start XOSC + // datasheet mentions support for clock inputs into XIN, but doesn't go into + // how this is achieved. pico-sdk doesn't support this at all. start_xosc(config.hz, config.delay_multiplier); - config.hz + + let pll_sys_freq = match config.sys_pll { + Some(sys_pll_config) => match configure_pll(pac::PLL_SYS, config.hz, sys_pll_config) { + Ok(freq) => freq, + Err(e) => panic!("Failed to configure PLL_SYS: {}", e), + }, + None => 0, + }; + let pll_usb_freq = match config.usb_pll { + Some(usb_pll_config) => match configure_pll(pac::PLL_USB, config.hz, usb_pll_config) { + Ok(freq) => freq, + Err(e) => panic!("Failed to configure PLL_USB: {}", e), + }, + None => 0, + }; + + (config.hz, pll_sys_freq, pll_usb_freq) } - None => 0, + None => (0, 0, 0), }; + CLOCKS.xosc.store(xosc_freq, Ordering::Relaxed); + CLOCKS.pll_sys.store(pll_sys_freq, Ordering::Relaxed); + CLOCKS.pll_usb.store(pll_usb_freq, Ordering::Relaxed); - // Setup temporary stable clocks first - // Configure USB PLL for our stable temporary clock - let pll_usb_freq = match &config.xosc { - Some(config) => match &config.usb_pll { - Some(pll_usb_config) => { - // Reset USB PLL - let mut peris = reset::Peripherals(0); - peris.set_pll_usb(true); - reset::reset(peris); - reset::unreset_wait(peris); - - // Configure the USB PLL - this should give us 48MHz - let usb_pll_freq = match configure_pll(pac::PLL_USB, xosc_freq, *pll_usb_config) { - Ok(freq) => freq, - Err(_) => { - panic!("Failed to configure USB PLL"); - } - }; - - CLOCKS.pll_usb.store(usb_pll_freq, Ordering::Relaxed); - usb_pll_freq - } - None => 0, - }, - None => 0, + let (ref_src, ref_aux, clk_ref_freq) = { + use {ClkRefCtrlAuxsrc as Aux, ClkRefCtrlSrc as Src}; + let div = config.ref_clk.div as u32; + assert!(div >= 1 && div <= 4); + match config.ref_clk.src { + RefClkSrc::Xosc => (Src::XOSC_CLKSRC, Aux::CLKSRC_PLL_USB, xosc_freq / div), + RefClkSrc::Rosc => (Src::ROSC_CLKSRC_PH, Aux::CLKSRC_PLL_USB, rosc_freq / div), + RefClkSrc::PllUsb => (Src::CLKSRC_CLK_REF_AUX, Aux::CLKSRC_PLL_USB, pll_usb_freq / div), + // RefClkSrc::Gpin0 => (Src::CLKSRC_CLK_REF_AUX, Aux::CLKSRC_GPIN0, gpin0_freq / div), + // RefClkSrc::Gpin1 => (Src::CLKSRC_CLK_REF_AUX, Aux::CLKSRC_GPIN1, gpin1_freq / div), + } }; - - // Configure REF clock to use XOSC - c.clk_ref_ctrl().write(|w| { - w.set_src(ClkRefCtrlSrc::XOSC_CLKSRC); - }); - #[cfg(feature = "rp2040")] - while c.clk_ref_selected().read() != (1 << ClkRefCtrlSrc::XOSC_CLKSRC as u32) {} - #[cfg(feature = "_rp235x")] - while c.clk_ref_selected().read() != pac::clocks::regs::ClkRefSelected(1 << ClkRefCtrlSrc::XOSC_CLKSRC as u32) {} - - // First switch the system clock to a stable source (USB PLL at 48MHz) - // This follows the official Pico SDK's approach to ensure stability during reconfiguration - c.clk_sys_ctrl().write(|w| { - w.set_auxsrc(ClkSysCtrlAuxsrc::CLKSRC_PLL_USB); - w.set_src(ClkSysCtrlSrc::CLKSRC_CLK_SYS_AUX); - }); - - #[cfg(feature = "rp2040")] - while c.clk_sys_selected().read() != (1 << ClkSysCtrlSrc::CLKSRC_CLK_SYS_AUX as u32) {} - #[cfg(feature = "_rp235x")] - while c.clk_sys_selected().read() - != pac::clocks::regs::ClkSysSelected(1 << ClkSysCtrlSrc::CLKSRC_CLK_SYS_AUX as u32) - {} - - // Short delay after switching to USB PLL to ensure stability - cortex_m::asm::delay(100); - - // NOW CONFIGURE THE SYSTEM PLL (safely, since we're running from the USB PLL) - let pll_sys_freq = match &config.xosc { - Some(config) => match &config.sys_pll { - Some(sys_pll_config) => { - // Reset SYS PLL - let mut peris = reset::Peripherals(0); - peris.set_pll_sys(true); - reset::reset(peris); - reset::unreset_wait(peris); - - // Configure the SYS PLL - let pll_sys_freq = match configure_pll(pac::PLL_SYS, xosc_freq, *sys_pll_config) { - Ok(freq) => freq, - Err(_) => { - panic!("Failed to configure system PLL"); - } - }; - - // Ensure PLL is locked and stable - cortex_m::asm::delay(100); - - CLOCKS.pll_sys.store(pll_sys_freq, Ordering::Relaxed); - pll_sys_freq - } - None => 0, - }, - None => 0, - }; - - // Configure tick generation using REF clock - let clk_ref_freq = xosc_freq; // REF clock is now XOSC + assert!(clk_ref_freq != 0); CLOCKS.reference.store(clk_ref_freq, Ordering::Relaxed); + c.clk_ref_ctrl().write(|w| { + w.set_src(ref_src); + w.set_auxsrc(ref_aux); + }); + #[cfg(feature = "rp2040")] + while c.clk_ref_selected().read() != (1 << ref_src as u32) {} + #[cfg(feature = "_rp235x")] + while c.clk_ref_selected().read() != pac::clocks::regs::ClkRefSelected(1 << ref_src as u32) {} + c.clk_ref_div().write(|w| { + w.set_int(config.ref_clk.div); + }); + + // Configure tick generation on the 2040. #[cfg(feature = "rp2040")] pac::WATCHDOG.tick().write(|w| { w.set_cycles((clk_ref_freq / 1_000_000) as u16); @@ -1050,8 +1024,6 @@ pub(crate) unsafe fn init(config: ClockConfig) { pac::TICKS.watchdog_ctrl().write(|w| w.set_enable(true)); } - // NOW SWITCH THE SYSTEM CLOCK TO THE CONFIGURED SOURCE - // The SYS PLL is now stable and we can safely switch to it let (sys_src, sys_aux, clk_sys_freq) = { use {ClkSysCtrlAuxsrc as Aux, ClkSysCtrlSrc as Src}; let (src, aux, freq) = match config.sys_clk.src { @@ -1068,48 +1040,28 @@ pub(crate) unsafe fn init(config: ClockConfig) { }; assert!(clk_sys_freq != 0); CLOCKS.sys.store(clk_sys_freq, Ordering::Relaxed); - - // Set the divider before changing the source if it's increasing - if config.sys_clk.div_int > 1 || config.sys_clk.div_frac > 0 { - c.clk_sys_div().write(|w| { - w.set_int(config.sys_clk.div_int); - w.set_frac(config.sys_clk.div_frac); - }); + if sys_src != ClkSysCtrlSrc::CLK_REF { + c.clk_sys_ctrl().write(|w| w.set_src(ClkSysCtrlSrc::CLK_REF)); + #[cfg(feature = "rp2040")] + while c.clk_sys_selected().read() != (1 << ClkSysCtrlSrc::CLK_REF as u32) {} + #[cfg(feature = "_rp235x")] + while c.clk_sys_selected().read() != pac::clocks::regs::ClkSysSelected(1 << ClkSysCtrlSrc::CLK_REF as u32) {} } - - // Configure aux source first if needed - if sys_src == ClkSysCtrlSrc::CLKSRC_CLK_SYS_AUX { - c.clk_sys_ctrl().modify(|w| { - w.set_auxsrc(sys_aux); - }); - } - - // Now set the source c.clk_sys_ctrl().write(|w| { - if sys_src == ClkSysCtrlSrc::CLKSRC_CLK_SYS_AUX { - w.set_auxsrc(sys_aux); - } + w.set_auxsrc(sys_aux); w.set_src(sys_src); }); - // Wait for the clock to be selected #[cfg(feature = "rp2040")] while c.clk_sys_selected().read() != (1 << sys_src as u32) {} #[cfg(feature = "_rp235x")] while c.clk_sys_selected().read() != pac::clocks::regs::ClkSysSelected(1 << sys_src as u32) {} - // Short delay after final clock switch to ensure stability - cortex_m::asm::delay(100); + c.clk_sys_div().write(|w| { + w.set_int(config.sys_clk.div_int); + w.set_frac(config.sys_clk.div_frac); + }); - // Set the divider after changing the source if it's decreasing - if config.sys_clk.div_int == 1 && config.sys_clk.div_frac == 0 { - c.clk_sys_div().write(|w| { - w.set_int(config.sys_clk.div_int); - w.set_frac(config.sys_clk.div_frac); - }); - } - - // CONFIGURE PERIPHERAL CLOCK let mut peris = reset::ALL_PERIPHERALS; if let Some(src) = config.peri_clk_src { @@ -1136,7 +1088,6 @@ pub(crate) unsafe fn init(config: ClockConfig) { CLOCKS.peri.store(0, Ordering::Relaxed); } - // CONFIGURE USB CLOCK if let Some(conf) = config.usb_clk { c.clk_usb_div().write(|w| w.set_int(conf.div)); c.clk_usb_ctrl().write(|w| { @@ -1160,7 +1111,6 @@ pub(crate) unsafe fn init(config: ClockConfig) { CLOCKS.usb.store(0, Ordering::Relaxed); } - // CONFIGURE ADC CLOCK if let Some(conf) = config.adc_clk { c.clk_adc_div().write(|w| w.set_int(conf.div)); c.clk_adc_ctrl().write(|w| { @@ -1184,7 +1134,7 @@ pub(crate) unsafe fn init(config: ClockConfig) { CLOCKS.adc.store(0, Ordering::Relaxed); } - // CONFIGURE RTC CLOCK + // rp2040 specific clocks #[cfg(feature = "rp2040")] if let Some(conf) = config.rtc_clk { c.clk_rtc_div().write(|w| { @@ -1393,7 +1343,7 @@ fn configure_pll(p: pac::pll::Pll, input_freq: u32, config: PllConfig) -> Result }); // 5. Wait for PLL to lock with a timeout - let mut timeout = 1_000_000; // Reasonable timeout value + let mut timeout = 1_000_000; while !p.cs().read().lock() { timeout -= 1; if timeout == 0 { From 57938d1174a2c8f29448b4fffaea33dba06ae653 Mon Sep 17 00:00:00 2001 From: vinsynth <1.5vhunt@gmail.com> Date: Mon, 5 May 2025 17:32:38 -0400 Subject: [PATCH 1068/1217] fix h7 sai example start sequence --- examples/stm32h7/src/bin/sai.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/examples/stm32h7/src/bin/sai.rs b/examples/stm32h7/src/bin/sai.rs index 95ffe257a..79a856b3b 100644 --- a/examples/stm32h7/src/bin/sai.rs +++ b/examples/stm32h7/src/bin/sai.rs @@ -112,8 +112,10 @@ async fn main(_spawner: Spawner) { let mut buf = [0u32; HALF_DMA_BUFFER_LENGTH]; loop { - sai_receiver.read(&mut buf).await.unwrap(); + // write() must be called before read() to start the master (transmitter) + // clock used by the receiver sai_transmitter.write(&buf).await.unwrap(); + sai_receiver.read(&mut buf).await.unwrap(); } } From 0460a924ac06a7dd33b4e50396948ba9bcb5374e Mon Sep 17 00:00:00 2001 From: Hiroaki Yutani Date: Tue, 6 May 2025 09:09:22 +0900 Subject: [PATCH 1069/1217] chore: Wrap link_section attribute with unsafe --- docs/pages/faq.adoc | 2 +- embassy-rp/Cargo.toml | 4 +- embassy-rp/src/bootsel.rs | 2 +- embassy-rp/src/flash.rs | 6 +-- embassy-rp/src/lib.rs | 8 +-- embassy-rp/src/multicore.rs | 4 +- embassy-stm32-wpan/src/tables.rs | 50 +++++++++---------- embassy-stm32/src/lib.rs | 2 +- .../boot/application/stm32wl/src/bin/a.rs | 2 +- .../boot/application/stm32wl/src/bin/b.rs | 2 +- examples/mimxrt6/build.rs | 2 +- examples/mimxrt6/src/lib.rs | 6 +-- examples/rp235x/src/bin/blinky.rs | 2 +- examples/rp235x/src/bin/blinky_wifi.rs | 2 +- .../rp235x/src/bin/blinky_wifi_pico_plus_2.rs | 2 +- .../rp235x/src/bin/pio_rotary_encoder_rxf.rs | 2 +- examples/stm32h7/src/bin/adc_dma.rs | 2 +- examples/stm32h7/src/bin/sai.rs | 4 +- examples/stm32h7/src/bin/spi_bdma.rs | 2 +- examples/stm32h723/src/bin/spdifrx.rs | 4 +- examples/stm32h755cm4/src/bin/blinky.rs | 2 +- examples/stm32h755cm7/src/bin/blinky.rs | 2 +- examples/stm32wl/src/bin/blinky.rs | 2 +- examples/stm32wl/src/bin/button.rs | 2 +- examples/stm32wl/src/bin/button_exti.rs | 2 +- examples/stm32wl/src/bin/flash.rs | 2 +- examples/stm32wl/src/bin/random.rs | 2 +- examples/stm32wl/src/bin/rtc.rs | 2 +- examples/stm32wl/src/bin/uart_async.rs | 2 +- 29 files changed, 64 insertions(+), 64 deletions(-) diff --git a/docs/pages/faq.adoc b/docs/pages/faq.adoc index a535e89f8..b21be9a30 100644 --- a/docs/pages/faq.adoc +++ b/docs/pages/faq.adoc @@ -268,7 +268,7 @@ General steps: 1. Find out which memory region BDMA has access to. You can get this information from the bus matrix and the memory mapping table in the STM32 datasheet. 2. Add the memory region to `memory.x`, you can modify the generated one from https://github.com/embassy-rs/stm32-data-generated/tree/main/data/chips. 3. You might need to modify `build.rs` to make cargo pick up the modified `memory.x`. -4. In your code, access the defined memory region using `#[link_section = ".xxx"]` +4. In your code, access the defined memory region using `#[unsafe(link_section = ".xxx")]` 5. Copy data to that region before using BDMA. See link:https://github.com/embassy-rs/embassy/blob/main/examples/stm32h7/src/bin/spi_bdma.rs[SMT32H7 SPI BDMA example] for more details. diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index b440591cf..a073c8b9e 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml @@ -86,7 +86,7 @@ boot2-w25x10cl = [] ## Have embassy-rp not provide the boot2 so you can use your own. ## Place your own in the ".boot2" section like: ## ``` -## #[link_section = ".boot2"] +## #[unsafe(link_section = ".boot2")] ## #[used] ## static BOOT2: [u8; 256] = [0; 256]; // Provide your own with e.g. include_bytes! ## ``` @@ -109,7 +109,7 @@ imagedef-nonsecure-exe = [] ## ```ignore ## use embassy_rp::block::ImageDef; ## -## #[link_section = ".start_block"] +## #[unsafe(link_section = ".start_block")] ## #[used] ## static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); // Update this with your own implementation. ## ``` diff --git a/embassy-rp/src/bootsel.rs b/embassy-rp/src/bootsel.rs index 14f9e46aa..5f0bac248 100644 --- a/embassy-rp/src/bootsel.rs +++ b/embassy-rp/src/bootsel.rs @@ -36,7 +36,7 @@ mod ram_helpers { /// This function must live in ram. It uses inline asm to avoid any /// potential calls to ABI functions that might be in flash. #[inline(never)] - #[link_section = ".data.ram_func"] + #[unsafe(link_section = ".data.ram_func")] #[cfg(target_arch = "arm")] pub unsafe fn read_cs_status() -> GpioStatus { let result: u32; diff --git a/embassy-rp/src/flash.rs b/embassy-rp/src/flash.rs index ef1cd9212..1ac15a677 100644 --- a/embassy-rp/src/flash.rs +++ b/embassy-rp/src/flash.rs @@ -623,7 +623,7 @@ mod ram_helpers { /// Length of data must be a multiple of 4096 /// addr must be aligned to 4096 #[inline(never)] - #[link_section = ".data.ram_func"] + #[unsafe(link_section = ".data.ram_func")] #[cfg(feature = "rp2040")] unsafe fn write_flash_inner(addr: u32, len: u32, data: Option<&[u8]>, ptrs: *const FlashFunctionPointers) { #[cfg(target_arch = "arm")] @@ -688,7 +688,7 @@ mod ram_helpers { /// Length of data must be a multiple of 4096 /// addr must be aligned to 4096 #[inline(never)] - #[link_section = ".data.ram_func"] + #[unsafe(link_section = ".data.ram_func")] #[cfg(feature = "_rp235x")] unsafe fn write_flash_inner(addr: u32, len: u32, data: Option<&[u8]>, ptrs: *const FlashFunctionPointers) { let data = data.map(|d| d.as_ptr()).unwrap_or(core::ptr::null()); @@ -807,7 +807,7 @@ mod ram_helpers { /// /// Credit: taken from `rp2040-flash` (also licensed Apache+MIT) #[inline(never)] - #[link_section = ".data.ram_func"] + #[unsafe(link_section = ".data.ram_func")] #[cfg(feature = "rp2040")] unsafe fn read_flash_inner(cmd: FlashCommand, ptrs: *const FlashFunctionPointers) { #[cfg(target_arch = "arm")] diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs index f549446bc..9b7c2b6ea 100644 --- a/embassy-rp/src/lib.rs +++ b/embassy-rp/src/lib.rs @@ -434,13 +434,13 @@ macro_rules! select_bootloader { ( $( $feature:literal => $loader:ident, )+ default => $default:ident ) => { $( #[cfg(feature = $feature)] - #[link_section = ".boot2"] + #[unsafe(link_section = ".boot2")] #[used] static BOOT2: [u8; 256] = rp2040_boot2::$loader; )* #[cfg(not(any( $( feature = $feature),* )))] - #[link_section = ".boot2"] + #[unsafe(link_section = ".boot2")] #[used] static BOOT2: [u8; 256] = rp2040_boot2::$default; } @@ -463,13 +463,13 @@ macro_rules! select_imagedef { ( $( $feature:literal => $imagedef:ident, )+ default => $default:ident ) => { $( #[cfg(feature = $feature)] - #[link_section = ".start_block"] + #[unsafe(link_section = ".start_block")] #[used] static IMAGE_DEF: crate::block::ImageDef = crate::block::ImageDef::$imagedef(); )* #[cfg(not(any( $( feature = $feature),* )))] - #[link_section = ".start_block"] + #[unsafe(link_section = ".start_block")] #[used] static IMAGE_DEF: crate::block::ImageDef = crate::block::ImageDef::$default(); } diff --git a/embassy-rp/src/multicore.rs b/embassy-rp/src/multicore.rs index d10b6837c..ec05bfdf5 100644 --- a/embassy-rp/src/multicore.rs +++ b/embassy-rp/src/multicore.rs @@ -90,7 +90,7 @@ impl Stack { #[cfg(all(feature = "rt", feature = "rp2040"))] #[interrupt] -#[link_section = ".data.ram_func"] +#[unsafe(link_section = ".data.ram_func")] unsafe fn SIO_IRQ_PROC1() { let sio = pac::SIO; // Clear IRQ @@ -115,7 +115,7 @@ unsafe fn SIO_IRQ_PROC1() { #[cfg(all(feature = "rt", feature = "_rp235x"))] #[interrupt] -#[link_section = ".data.ram_func"] +#[unsafe(link_section = ".data.ram_func")] unsafe fn SIO_IRQ_FIFO() { let sio = pac::SIO; // Clear IRQ diff --git a/embassy-stm32-wpan/src/tables.rs b/embassy-stm32-wpan/src/tables.rs index fe6fc47a3..204790e6d 100644 --- a/embassy-stm32-wpan/src/tables.rs +++ b/embassy-stm32-wpan/src/tables.rs @@ -190,94 +190,94 @@ pub struct RefTable { } // --------------------- ref table --------------------- -#[link_section = "TL_REF_TABLE"] +#[unsafe(link_section = "TL_REF_TABLE")] pub static mut TL_REF_TABLE: MaybeUninit = MaybeUninit::uninit(); -#[link_section = "MB_MEM1"] +#[unsafe(link_section = "MB_MEM1")] pub static mut TL_DEVICE_INFO_TABLE: Aligned> = Aligned(MaybeUninit::uninit()); -#[link_section = "MB_MEM1"] +#[unsafe(link_section = "MB_MEM1")] pub static mut TL_BLE_TABLE: Aligned> = Aligned(MaybeUninit::uninit()); -#[link_section = "MB_MEM1"] +#[unsafe(link_section = "MB_MEM1")] pub static mut TL_THREAD_TABLE: Aligned> = Aligned(MaybeUninit::uninit()); -#[link_section = "MB_MEM1"] +#[unsafe(link_section = "MB_MEM1")] pub static mut TL_LLD_TESTS_TABLE: Aligned> = Aligned(MaybeUninit::uninit()); -#[link_section = "MB_MEM1"] +#[unsafe(link_section = "MB_MEM1")] pub static mut TL_BLE_LLD_TABLE: Aligned> = Aligned(MaybeUninit::uninit()); -#[link_section = "MB_MEM1"] +#[unsafe(link_section = "MB_MEM1")] pub static mut TL_SYS_TABLE: Aligned> = Aligned(MaybeUninit::uninit()); -#[link_section = "MB_MEM1"] +#[unsafe(link_section = "MB_MEM1")] pub static mut TL_MEM_MANAGER_TABLE: Aligned> = Aligned(MaybeUninit::uninit()); -#[link_section = "MB_MEM1"] +#[unsafe(link_section = "MB_MEM1")] pub static mut TL_TRACES_TABLE: Aligned> = Aligned(MaybeUninit::uninit()); -#[link_section = "MB_MEM1"] +#[unsafe(link_section = "MB_MEM1")] pub static mut TL_MAC_802_15_4_TABLE: Aligned> = Aligned(MaybeUninit::uninit()); -#[link_section = "MB_MEM1"] +#[unsafe(link_section = "MB_MEM1")] pub static mut TL_ZIGBEE_TABLE: Aligned> = Aligned(MaybeUninit::uninit()); // --------------------- tables --------------------- -#[link_section = "MB_MEM1"] +#[unsafe(link_section = "MB_MEM1")] pub static mut FREE_BUF_QUEUE: Aligned> = Aligned(MaybeUninit::uninit()); #[allow(dead_code)] -#[link_section = "MB_MEM1"] +#[unsafe(link_section = "MB_MEM1")] pub static mut TRACES_EVT_QUEUE: Aligned> = Aligned(MaybeUninit::uninit()); -#[link_section = "MB_MEM2"] +#[unsafe(link_section = "MB_MEM2")] pub static mut CS_BUFFER: Aligned> = Aligned(MaybeUninit::uninit()); -#[link_section = "MB_MEM2"] +#[unsafe(link_section = "MB_MEM2")] pub static mut EVT_QUEUE: Aligned> = Aligned(MaybeUninit::uninit()); -#[link_section = "MB_MEM2"] +#[unsafe(link_section = "MB_MEM2")] pub static mut SYSTEM_EVT_QUEUE: Aligned> = Aligned(MaybeUninit::uninit()); // --------------------- app tables --------------------- #[cfg(feature = "mac")] -#[link_section = "MB_MEM2"] +#[unsafe(link_section = "MB_MEM2")] pub static mut MAC_802_15_4_CMD_BUFFER: Aligned> = Aligned(MaybeUninit::uninit()); #[cfg(feature = "mac")] -#[link_section = "MB_MEM2"] +#[unsafe(link_section = "MB_MEM2")] pub static mut MAC_802_15_4_NOTIF_RSP_EVT_BUFFER: MaybeUninit< Aligned, > = MaybeUninit::uninit(); -#[link_section = "MB_MEM2"] +#[unsafe(link_section = "MB_MEM2")] pub static mut EVT_POOL: Aligned> = Aligned(MaybeUninit::uninit()); -#[link_section = "MB_MEM2"] +#[unsafe(link_section = "MB_MEM2")] pub static mut SYS_CMD_BUF: Aligned> = Aligned(MaybeUninit::uninit()); -#[link_section = "MB_MEM2"] +#[unsafe(link_section = "MB_MEM2")] pub static mut SYS_SPARE_EVT_BUF: Aligned> = Aligned(MaybeUninit::uninit()); #[cfg(feature = "mac")] -#[link_section = "MB_MEM2"] +#[unsafe(link_section = "MB_MEM2")] pub static mut MAC_802_15_4_CNFINDNOT: Aligned> = Aligned(MaybeUninit::uninit()); #[cfg(feature = "ble")] -#[link_section = "MB_MEM1"] +#[unsafe(link_section = "MB_MEM1")] pub static mut BLE_CMD_BUFFER: Aligned> = Aligned(MaybeUninit::uninit()); #[cfg(feature = "ble")] -#[link_section = "MB_MEM2"] +#[unsafe(link_section = "MB_MEM2")] pub static mut BLE_SPARE_EVT_BUF: Aligned> = Aligned(MaybeUninit::uninit()); #[cfg(feature = "ble")] -#[link_section = "MB_MEM2"] +#[unsafe(link_section = "MB_MEM2")] // fuck these "magic" numbers from ST ---v---v pub static mut HCI_ACL_DATA_BUFFER: Aligned> = Aligned(MaybeUninit::uninit()); diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 226293a9d..8ba604830 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -331,7 +331,7 @@ mod dual_core { /// use core::mem::MaybeUninit; /// use embassy_stm32::{init_secondary, SharedData}; /// - /// #[link_section = ".ram_d3"] + /// #[unsafe(link_section = ".ram_d3")] /// static SHARED_DATA: MaybeUninit = MaybeUninit::uninit(); /// /// init_secondary(&SHARED_DATA); diff --git a/examples/boot/application/stm32wl/src/bin/a.rs b/examples/boot/application/stm32wl/src/bin/a.rs index 127de0237..e4526927f 100644 --- a/examples/boot/application/stm32wl/src/bin/a.rs +++ b/examples/boot/application/stm32wl/src/bin/a.rs @@ -20,7 +20,7 @@ static APP_B: &[u8] = &[0, 1, 2, 3]; #[cfg(not(feature = "skip-include"))] static APP_B: &[u8] = include_bytes!("../../b.bin"); -#[link_section = ".shared_data"] +#[unsafe(link_section = ".shared_data")] static SHARED_DATA: MaybeUninit = MaybeUninit::uninit(); #[embassy_executor::main] diff --git a/examples/boot/application/stm32wl/src/bin/b.rs b/examples/boot/application/stm32wl/src/bin/b.rs index 768dadf8b..6016a9555 100644 --- a/examples/boot/application/stm32wl/src/bin/b.rs +++ b/examples/boot/application/stm32wl/src/bin/b.rs @@ -11,7 +11,7 @@ use embassy_stm32::SharedData; use embassy_time::Timer; use panic_reset as _; -#[link_section = ".shared_data"] +#[unsafe(link_section = ".shared_data")] static SHARED_DATA: MaybeUninit = MaybeUninit::uninit(); #[embassy_executor::main] diff --git a/examples/mimxrt6/build.rs b/examples/mimxrt6/build.rs index 9c0ed3213..56010dfd6 100644 --- a/examples/mimxrt6/build.rs +++ b/examples/mimxrt6/build.rs @@ -25,7 +25,7 @@ fn main() { .write_all( format!( r##" -#[link_section = ".biv"] +#[unsafe(link_section = ".biv")] #[used] static BOOT_IMAGE_VERSION: u32 = 0x{:02x}{:02x}{:02x}00; "##, diff --git a/examples/mimxrt6/src/lib.rs b/examples/mimxrt6/src/lib.rs index da6e14427..3c3ea1981 100644 --- a/examples/mimxrt6/src/lib.rs +++ b/examples/mimxrt6/src/lib.rs @@ -6,15 +6,15 @@ use {defmt_rtt as _, panic_probe as _}; // auto-generated version information from Cargo.toml include!(concat!(env!("OUT_DIR"), "/biv.rs")); -#[link_section = ".otfad"] +#[unsafe(link_section = ".otfad")] #[used] static OTFAD: [u8; 256] = [0; 256]; #[rustfmt::skip] -#[link_section = ".fcb"] +#[unsafe(link_section = ".fcb")] #[used] static FCB: FlexSPIFlashConfigurationBlock = FlexSPIFlashConfigurationBlock::build(); -#[link_section = ".keystore"] +#[unsafe(link_section = ".keystore")] #[used] static KEYSTORE: [u8; 2048] = [0; 2048]; diff --git a/examples/rp235x/src/bin/blinky.rs b/examples/rp235x/src/bin/blinky.rs index a36029f92..8a2464fbb 100644 --- a/examples/rp235x/src/bin/blinky.rs +++ b/examples/rp235x/src/bin/blinky.rs @@ -14,7 +14,7 @@ use {defmt_rtt as _, panic_probe as _}; // Program metadata for `picotool info`. // This isn't needed, but it's recomended to have these minimal entries. -#[link_section = ".bi_entries"] +#[unsafe(link_section = ".bi_entries")] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ embassy_rp::binary_info::rp_program_name!(c"Blinky Example"), diff --git a/examples/rp235x/src/bin/blinky_wifi.rs b/examples/rp235x/src/bin/blinky_wifi.rs index ef029867a..8c352ebc4 100644 --- a/examples/rp235x/src/bin/blinky_wifi.rs +++ b/examples/rp235x/src/bin/blinky_wifi.rs @@ -18,7 +18,7 @@ use {defmt_rtt as _, panic_probe as _}; // Program metadata for `picotool info`. // This isn't needed, but it's recommended to have these minimal entries. -#[link_section = ".bi_entries"] +#[unsafe(link_section = ".bi_entries")] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ embassy_rp::binary_info::rp_program_name!(c"Blinky Example"), diff --git a/examples/rp235x/src/bin/blinky_wifi_pico_plus_2.rs b/examples/rp235x/src/bin/blinky_wifi_pico_plus_2.rs index 2a919a1ea..0a5bccfb3 100644 --- a/examples/rp235x/src/bin/blinky_wifi_pico_plus_2.rs +++ b/examples/rp235x/src/bin/blinky_wifi_pico_plus_2.rs @@ -18,7 +18,7 @@ use {defmt_rtt as _, panic_probe as _}; // Program metadata for `picotool info`. // This isn't needed, but it's recomended to have these minimal entries. -#[link_section = ".bi_entries"] +#[unsafe(link_section = ".bi_entries")] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ embassy_rp::binary_info::rp_program_name!(c"Blinky Example"), diff --git a/examples/rp235x/src/bin/pio_rotary_encoder_rxf.rs b/examples/rp235x/src/bin/pio_rotary_encoder_rxf.rs index ccc601661..0e3b4e5f9 100644 --- a/examples/rp235x/src/bin/pio_rotary_encoder_rxf.rs +++ b/examples/rp235x/src/bin/pio_rotary_encoder_rxf.rs @@ -16,7 +16,7 @@ use pio::{Common, Config, FifoJoin, Instance, InterruptHandler, Pio, PioPin, Shi use {defmt_rtt as _, panic_probe as _}; // Program metadata for `picotool info` -#[link_section = ".bi_entries"] +#[unsafe(link_section = ".bi_entries")] #[used] pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ embassy_rp::binary_info::rp_program_name!(c"example_pio_rotary_encoder_rxf"), diff --git a/examples/stm32h7/src/bin/adc_dma.rs b/examples/stm32h7/src/bin/adc_dma.rs index dc775f18a..f06b5d06e 100644 --- a/examples/stm32h7/src/bin/adc_dma.rs +++ b/examples/stm32h7/src/bin/adc_dma.rs @@ -8,7 +8,7 @@ use embassy_stm32::Config; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; -#[link_section = ".ram_d3"] +#[unsafe(link_section = ".ram_d3")] static mut DMA_BUF: [u16; 2] = [0; 2]; #[embassy_executor::main] diff --git a/examples/stm32h7/src/bin/sai.rs b/examples/stm32h7/src/bin/sai.rs index 95ffe257a..c2bf7d6f2 100644 --- a/examples/stm32h7/src/bin/sai.rs +++ b/examples/stm32h7/src/bin/sai.rs @@ -16,9 +16,9 @@ const DMA_BUFFER_LENGTH: usize = HALF_DMA_BUFFER_LENGTH * 2; // 2 half-blocks const SAMPLE_RATE: u32 = 48000; //DMA buffer must be in special region. Refer https://embassy.dev/book/#_stm32_bdma_only_working_out_of_some_ram_regions -#[link_section = ".sram1_bss"] +#[unsafe(link_section = ".sram1_bss")] static mut TX_BUFFER: GroundedArrayCell = GroundedArrayCell::uninit(); -#[link_section = ".sram1_bss"] +#[unsafe(link_section = ".sram1_bss")] static mut RX_BUFFER: GroundedArrayCell = GroundedArrayCell::uninit(); #[embassy_executor::main] diff --git a/examples/stm32h7/src/bin/spi_bdma.rs b/examples/stm32h7/src/bin/spi_bdma.rs index 9166fe9b6..5a7dff572 100644 --- a/examples/stm32h7/src/bin/spi_bdma.rs +++ b/examples/stm32h7/src/bin/spi_bdma.rs @@ -16,7 +16,7 @@ use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; // Defined in memory.x -#[link_section = ".ram_d3"] +#[unsafe(link_section = ".ram_d3")] static mut RAM_D3: GroundedArrayCell = GroundedArrayCell::uninit(); #[embassy_executor::task] diff --git a/examples/stm32h723/src/bin/spdifrx.rs b/examples/stm32h723/src/bin/spdifrx.rs index bc8249ced..a04d7cb34 100644 --- a/examples/stm32h723/src/bin/spdifrx.rs +++ b/examples/stm32h723/src/bin/spdifrx.rs @@ -24,10 +24,10 @@ const HALF_DMA_BUFFER_LENGTH: usize = BLOCK_LENGTH * CHANNEL_COUNT; const DMA_BUFFER_LENGTH: usize = HALF_DMA_BUFFER_LENGTH * 2; // 2 half-blocks // DMA buffers must be in special regions. Refer https://embassy.dev/book/#_stm32_bdma_only_working_out_of_some_ram_regions -#[link_section = ".sram1"] +#[unsafe(link_section = ".sram1")] static mut SPDIFRX_BUFFER: GroundedArrayCell = GroundedArrayCell::uninit(); -#[link_section = ".sram4"] +#[unsafe(link_section = ".sram4")] static mut SAI_BUFFER: GroundedArrayCell = GroundedArrayCell::uninit(); #[embassy_executor::main] diff --git a/examples/stm32h755cm4/src/bin/blinky.rs b/examples/stm32h755cm4/src/bin/blinky.rs index b5c547839..39112c1f5 100644 --- a/examples/stm32h755cm4/src/bin/blinky.rs +++ b/examples/stm32h755cm4/src/bin/blinky.rs @@ -10,7 +10,7 @@ use embassy_stm32::SharedData; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; -#[link_section = ".ram_d3.shared_data"] +#[unsafe(link_section = ".ram_d3.shared_data")] static SHARED_DATA: MaybeUninit = MaybeUninit::uninit(); #[embassy_executor::main] diff --git a/examples/stm32h755cm7/src/bin/blinky.rs b/examples/stm32h755cm7/src/bin/blinky.rs index 94d2226c0..b30bf4de8 100644 --- a/examples/stm32h755cm7/src/bin/blinky.rs +++ b/examples/stm32h755cm7/src/bin/blinky.rs @@ -10,7 +10,7 @@ use embassy_stm32::SharedData; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; -#[link_section = ".ram_d3.shared_data"] +#[unsafe(link_section = ".ram_d3.shared_data")] static SHARED_DATA: MaybeUninit = MaybeUninit::uninit(); #[embassy_executor::main] diff --git a/examples/stm32wl/src/bin/blinky.rs b/examples/stm32wl/src/bin/blinky.rs index ce7d0ec58..a2a90871d 100644 --- a/examples/stm32wl/src/bin/blinky.rs +++ b/examples/stm32wl/src/bin/blinky.rs @@ -10,7 +10,7 @@ use embassy_stm32::SharedData; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; -#[link_section = ".shared_data"] +#[unsafe(link_section = ".shared_data")] static SHARED_DATA: MaybeUninit = MaybeUninit::uninit(); #[embassy_executor::main] diff --git a/examples/stm32wl/src/bin/button.rs b/examples/stm32wl/src/bin/button.rs index 8b5204479..21bcd2ac6 100644 --- a/examples/stm32wl/src/bin/button.rs +++ b/examples/stm32wl/src/bin/button.rs @@ -9,7 +9,7 @@ use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed}; use embassy_stm32::SharedData; use {defmt_rtt as _, panic_probe as _}; -#[link_section = ".shared_data"] +#[unsafe(link_section = ".shared_data")] static SHARED_DATA: MaybeUninit = MaybeUninit::uninit(); #[entry] diff --git a/examples/stm32wl/src/bin/button_exti.rs b/examples/stm32wl/src/bin/button_exti.rs index 8dd1a6a5e..0a8aece34 100644 --- a/examples/stm32wl/src/bin/button_exti.rs +++ b/examples/stm32wl/src/bin/button_exti.rs @@ -10,7 +10,7 @@ use embassy_stm32::gpio::Pull; use embassy_stm32::SharedData; use {defmt_rtt as _, panic_probe as _}; -#[link_section = ".shared_data"] +#[unsafe(link_section = ".shared_data")] static SHARED_DATA: MaybeUninit = MaybeUninit::uninit(); #[embassy_executor::main] diff --git a/examples/stm32wl/src/bin/flash.rs b/examples/stm32wl/src/bin/flash.rs index 147f5d293..320a9723a 100644 --- a/examples/stm32wl/src/bin/flash.rs +++ b/examples/stm32wl/src/bin/flash.rs @@ -9,7 +9,7 @@ use embassy_stm32::flash::Flash; use embassy_stm32::SharedData; use {defmt_rtt as _, panic_probe as _}; -#[link_section = ".shared_data"] +#[unsafe(link_section = ".shared_data")] static SHARED_DATA: MaybeUninit = MaybeUninit::uninit(); #[embassy_executor::main] diff --git a/examples/stm32wl/src/bin/random.rs b/examples/stm32wl/src/bin/random.rs index df2ed0054..68b9d7d00 100644 --- a/examples/stm32wl/src/bin/random.rs +++ b/examples/stm32wl/src/bin/random.rs @@ -14,7 +14,7 @@ bind_interrupts!(struct Irqs{ RNG => rng::InterruptHandler; }); -#[link_section = ".shared_data"] +#[unsafe(link_section = ".shared_data")] static SHARED_DATA: MaybeUninit = MaybeUninit::uninit(); #[embassy_executor::main] diff --git a/examples/stm32wl/src/bin/rtc.rs b/examples/stm32wl/src/bin/rtc.rs index 69a9ddc4c..d3709120f 100644 --- a/examples/stm32wl/src/bin/rtc.rs +++ b/examples/stm32wl/src/bin/rtc.rs @@ -12,7 +12,7 @@ use embassy_stm32::{Config, SharedData}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; -#[link_section = ".shared_data"] +#[unsafe(link_section = ".shared_data")] static SHARED_DATA: MaybeUninit = MaybeUninit::uninit(); #[embassy_executor::main] diff --git a/examples/stm32wl/src/bin/uart_async.rs b/examples/stm32wl/src/bin/uart_async.rs index ece9b9201..505a85f47 100644 --- a/examples/stm32wl/src/bin/uart_async.rs +++ b/examples/stm32wl/src/bin/uart_async.rs @@ -14,7 +14,7 @@ bind_interrupts!(struct Irqs{ LPUART1 => InterruptHandler; }); -#[link_section = ".shared_data"] +#[unsafe(link_section = ".shared_data")] static SHARED_DATA: MaybeUninit = MaybeUninit::uninit(); /* From 5105442f1f0587c0899ea29b52c5202ed5c81e6c Mon Sep 17 00:00:00 2001 From: Hiroaki Yutani Date: Tue, 6 May 2025 09:44:00 +0900 Subject: [PATCH 1070/1217] Fix clippy::bad_bit_mask --- embassy-stm32/src/spdifrx/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/src/spdifrx/mod.rs b/embassy-stm32/src/spdifrx/mod.rs index 08dba04fe..9c42217f0 100644 --- a/embassy-stm32/src/spdifrx/mod.rs +++ b/embassy-stm32/src/spdifrx/mod.rs @@ -223,7 +223,7 @@ impl<'d, T: Instance> Spdifrx<'d, T> { }; for sample in data.as_mut() { - if (*sample & (0x0002_u32)) == 0x0001 { + if (*sample & (0x0002_u32)) != 0 { // Discard invalid samples, setting them to mute level. *sample = 0; } else { From 103cda49912af6cc524324d28f57e91c05da6741 Mon Sep 17 00:00:00 2001 From: Hiroaki Yutani Date: Tue, 6 May 2025 12:11:03 +0900 Subject: [PATCH 1071/1217] Add a temporary tweak --- examples/rp/Cargo.toml | 3 +++ examples/rp235x/Cargo.toml | 3 +++ 2 files changed, 6 insertions(+) diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index 45ca30e4c..97b14a327 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml @@ -67,3 +67,6 @@ opt-level = 'z' debug = 2 lto = true opt-level = "z" + +[patch.crates-io] +cortex-m-rt = { git = "https://github.com/yutannihilation/cortex-m", branch = "fix/allow-unsafe-wrap-rust2024" } diff --git a/examples/rp235x/Cargo.toml b/examples/rp235x/Cargo.toml index 345a915af..99091ee90 100644 --- a/examples/rp235x/Cargo.toml +++ b/examples/rp235x/Cargo.toml @@ -64,3 +64,6 @@ debug = 2 [profile.dev] lto = true opt-level = "z" + +[patch.crates-io] +cortex-m-rt = { git = "https://github.com/yutannihilation/cortex-m", branch = "fix/allow-unsafe-wrap-rust2024" } From 326c88c9662c1351eb5b8f5337268a8a22f114e8 Mon Sep 17 00:00:00 2001 From: Hiroaki Yutani Date: Tue, 6 May 2025 12:13:53 +0900 Subject: [PATCH 1072/1217] One more tweak --- embassy-rp/Cargo.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index a073c8b9e..e8091a2a5 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml @@ -174,3 +174,6 @@ smart-leds = "0.4.0" [dev-dependencies] embassy-executor = { version = "0.7.0", path = "../embassy-executor", features = ["arch-std", "executor-thread"] } static_cell = { version = "2" } + +[patch.crates-io] +cortex-m-rt = { git = "https://github.com/yutannihilation/cortex-m", branch = "fix/allow-unsafe-wrap-rust2024" } From b1d37cbf22cedc926eb9f61a39ec02715530f63e Mon Sep 17 00:00:00 2001 From: Hiroaki Yutani Date: Tue, 6 May 2025 12:17:46 +0900 Subject: [PATCH 1073/1217] Try another tweak --- tests/rp/Cargo.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/rp/Cargo.toml b/tests/rp/Cargo.toml index 1335aa84b..ed3a880a0 100644 --- a/tests/rp/Cargo.toml +++ b/tests/rp/Cargo.toml @@ -93,3 +93,6 @@ debug = false debug-assertions = false opt-level = 0 overflow-checks = false + +[patch.crates-io] +cortex-m-rt = { git = "https://github.com/yutannihilation/cortex-m", branch = "fix/allow-unsafe-wrap-rust2024" } From 254b203e1a88f7524911d520bc8738447f5c813c Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Tue, 6 May 2025 12:46:52 +0200 Subject: [PATCH 1074/1217] fix: update embassy-net changelog --- embassy-net/CHANGELOG.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/embassy-net/CHANGELOG.md b/embassy-net/CHANGELOG.md index cfee5f3cf..8773772ce 100644 --- a/embassy-net/CHANGELOG.md +++ b/embassy-net/CHANGELOG.md @@ -9,10 +9,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 No unreleased changes yet... Quick, go send a PR! -## 0.7 - 2025-02-14 +## 0.7 - 2025-05-06 - don't infinite loop if udp::send methods receive a buffer too large to ever be sent - add ICMP sockets and a ping utility +- configurable rate_limit for the ping utility +- Feature match udp sockets ## 0.6 - 2025-01-05 From 73f11d238a96a2186e93f786bd29b75149097e02 Mon Sep 17 00:00:00 2001 From: Dion Dokter Date: Tue, 6 May 2025 13:15:26 +0200 Subject: [PATCH 1075/1217] Updated metapac tag --- embassy-stm32/Cargo.toml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index ec22325f9..972307bec 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -73,8 +73,7 @@ rand_core = "0.6.3" sdio-host = "0.9.0" critical-section = "1.1" #stm32-metapac = { version = "16" } -# stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-380f03cb71f43a242adc45e83607a380ffe0447b" } -stm32-metapac = { git="https://ci.embassy.dev/jobs/3de13111608a/artifacts/generated.git" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-7251801e3273011ce28a89e8f2e45eec2e419e26" } vcell = "0.1.3" nb = "1.0.0" @@ -103,8 +102,7 @@ proc-macro2 = "1.0.36" quote = "1.0.15" #stm32-metapac = { version = "16", default-features = false, features = ["metadata"]} -# stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-380f03cb71f43a242adc45e83607a380ffe0447b", default-features = false, features = ["metadata"] } -stm32-metapac = { git="https://ci.embassy.dev/jobs/3de13111608a/artifacts/generated.git", default-features = false, features = ["metadata"] } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-7251801e3273011ce28a89e8f2e45eec2e419e26", default-features = false, features = ["metadata"] } [features] default = ["rt"] From f8f9c38b2e2527c6e3b8396e06fbb18fc1ce2a1c Mon Sep 17 00:00:00 2001 From: Kat Perez Date: Tue, 29 Apr 2025 08:49:19 -0400 Subject: [PATCH 1076/1217] add a task registry to tracing infrastructure --- embassy-executor/src/raw/mod.rs | 2 +- embassy-executor/src/raw/trace.rs | 139 +++++++++++++++++++++++++++++- embassy-executor/src/spawner.rs | 27 ++++++ 3 files changed, 166 insertions(+), 2 deletions(-) diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs index 88d839e07..35c82557c 100644 --- a/embassy-executor/src/raw/mod.rs +++ b/embassy-executor/src/raw/mod.rs @@ -18,7 +18,7 @@ mod state; pub mod timer_queue; #[cfg(feature = "trace")] -mod trace; +pub mod trace; pub(crate) mod util; #[cfg_attr(feature = "turbowakers", path = "waker_turbo.rs")] mod waker; diff --git a/embassy-executor/src/raw/trace.rs b/embassy-executor/src/raw/trace.rs index aba519c8f..bdd3e4706 100644 --- a/embassy-executor/src/raw/trace.rs +++ b/embassy-executor/src/raw/trace.rs @@ -83,6 +83,129 @@ use crate::raw::{SyncExecutor, TaskRef}; +use core::cell::UnsafeCell; +use core::sync::atomic::{AtomicUsize, Ordering}; +use rtos_trace::TaskInfo; + +const MAX_TASKS: usize = 1000; + +/// Represents a task being tracked in the task registry. +/// +/// Contains the task's unique identifier and optional name. +#[derive(Clone)] +pub struct TrackedTask { + task_id: u32, + name: Option<&'static str>, +} + +/// A thread-safe registry for tracking tasks in the system. +/// +/// This registry maintains a list of active tasks with their IDs and optional names. +/// It supports registering, unregistering, and querying information about tasks. +/// The registry has a fixed capacity of `MAX_TASKS`. +pub struct TaskRegistry { + tasks: [UnsafeCell>; MAX_TASKS], + count: AtomicUsize, +} + +impl TaskRegistry { + /// Creates a new empty task registry. + /// + /// This initializes a registry that can track up to `MAX_TASKS` tasks. + pub const fn new() -> Self { + const EMPTY: UnsafeCell> = UnsafeCell::new(None); + Self { + tasks: [EMPTY; MAX_TASKS], + count: AtomicUsize::new(0), + } + } + + /// Registers a new task in the registry. + /// + /// # Arguments + /// * `task_id` - Unique identifier for the task + /// * `name` - Optional name for the task + /// + /// # Note + /// If the registry is full, the task will not be registered. + pub fn register(&self, task_id: u32, name: Option<&'static str>) { + let count = self.count.load(Ordering::Relaxed); + if count < MAX_TASKS { + for i in 0..MAX_TASKS { + unsafe { + let slot = &self.tasks[i]; + let slot_ref = &mut *slot.get(); + if slot_ref.is_none() { + *slot_ref = Some(TrackedTask { task_id, name }); + self.count.fetch_add(1, Ordering::Relaxed); + break; + } + } + } + } + } + + /// Removes a task from the registry. + /// + /// # Arguments + /// * `task_id` - Unique identifier of the task to remove + pub fn unregister(&self, task_id: u32) { + for i in 0..MAX_TASKS { + unsafe { + let slot = &self.tasks[i]; + let slot_ref = &mut *slot.get(); + if let Some(task) = slot_ref { + if task.task_id == task_id { + *slot_ref = None; + self.count.fetch_sub(1, Ordering::Relaxed); + break; + } + } + } + } + } + + /// Returns an iterator over all registered tasks. + /// + /// This allows accessing information about all tasks currently in the registry. + pub fn get_all_tasks(&self) -> impl Iterator + '_ { + (0..MAX_TASKS).filter_map(move |i| unsafe { + let slot = &self.tasks[i]; + (*slot.get()).clone() + }) + } + + /// Retrieves the name of a task with the given ID. + /// + /// # Arguments + /// * `task_id` - Unique identifier of the task + /// + /// # Returns + /// The name of the task if found and named, or `None` otherwise + pub fn get_task_name(&self, task_id: u32) -> Option<&'static str> { + for i in 0..MAX_TASKS { + unsafe { + let slot = &self.tasks[i]; + let slot_ref = &*slot.get(); + if let Some(task) = slot_ref { + if task.task_id == task_id { + return task.name; + } + } + } + } + None + } +} + +unsafe impl Sync for TaskRegistry {} +unsafe impl Send for TaskRegistry {} + +/// Global task registry instance used for tracking all tasks in the system. +/// +/// This provides a centralized registry accessible from anywhere in the application. +pub static TASK_REGISTRY: TaskRegistry = TaskRegistry::new(); + #[cfg(not(feature = "rtos-trace"))] extern "Rust" { /// This callback is called when the executor begins polling. This will always @@ -153,6 +276,8 @@ pub(crate) fn poll_start(executor: &SyncExecutor) { #[inline] pub(crate) fn task_new(executor: &SyncExecutor, task: &TaskRef) { + let task_id = task.as_ptr() as u32; + #[cfg(not(feature = "rtos-trace"))] unsafe { _embassy_trace_task_new(executor as *const _ as u32, task.as_ptr() as u32) @@ -164,10 +289,14 @@ pub(crate) fn task_new(executor: &SyncExecutor, task: &TaskRef) { #[inline] pub(crate) fn task_end(executor: *const SyncExecutor, task: &TaskRef) { + let task_id = task.as_ptr() as u32; + #[cfg(not(feature = "rtos-trace"))] unsafe { _embassy_trace_task_end(executor as u32, task.as_ptr() as u32) } + + TASK_REGISTRY.unregister(task_id); } #[inline] @@ -213,7 +342,15 @@ pub(crate) fn executor_idle(executor: &SyncExecutor) { #[cfg(feature = "rtos-trace")] impl rtos_trace::RtosTraceOSCallbacks for crate::raw::SyncExecutor { fn task_list() { - // We don't know what tasks exist, so we can't send them. + for task in TASK_REGISTRY.get_all_tasks() { + let info = rtos_trace::TaskInfo { + name: TASK_REGISTRY.get_task_name(task.task_id).unwrap(), + priority: 0, + stack_base: 0, + stack_size: 0, + }; + rtos_trace::trace::task_send_info(task.task_id, info); + } } fn time() -> u64 { const fn gcd(a: u64, b: u64) -> u64 { diff --git a/embassy-executor/src/spawner.rs b/embassy-executor/src/spawner.rs index ff243081c..ea754341b 100644 --- a/embassy-executor/src/spawner.rs +++ b/embassy-executor/src/spawner.rs @@ -5,6 +5,8 @@ use core::sync::atomic::Ordering; use core::task::Poll; use super::raw; +#[cfg(feature = "rtos-trace")] +use super::raw::trace::TASK_REGISTRY; /// Token to spawn a newly-created task in an executor. /// @@ -154,6 +156,31 @@ impl Spawner { } } + /// Spawns a new task with a specified name. + /// + /// # Arguments + /// * `name` - Static string name to associate with the task + /// * `token` - Token representing the task to spawn + /// + /// # Returns + /// Result indicating whether the spawn was successful + #[cfg(feature = "rtos-trace")] + pub fn spawn_named(&self, name: &'static str, token: SpawnToken) -> Result<(), SpawnError> { + let task = token.raw_task; + mem::forget(token); + + match task { + Some(task) => { + let task_id = task.as_ptr() as u32; + TASK_REGISTRY.register(task_id, Some(name)); + + unsafe { self.executor.spawn(task) }; + Ok(()) + } + None => Err(SpawnError::Busy), + } + } + // Used by the `embassy_executor_macros::main!` macro to throw an error when spawn // fails. This is here to allow conditional use of `defmt::unwrap!` // without introducing a `defmt` feature in the `embassy_executor_macros` package, From 032898adf5848da237e4bf55b8c06c2ff73cae7c Mon Sep 17 00:00:00 2001 From: Kat Perez Date: Mon, 5 May 2025 12:14:14 -0400 Subject: [PATCH 1077/1217] add a stub implementation for spawn_named When rtos-trace is not enabled, spawn_named will use spawn instead --- embassy-executor/src/spawner.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/embassy-executor/src/spawner.rs b/embassy-executor/src/spawner.rs index ea754341b..f87700be6 100644 --- a/embassy-executor/src/spawner.rs +++ b/embassy-executor/src/spawner.rs @@ -181,6 +181,13 @@ impl Spawner { } } + /// When rtos-trace is disabled, spawn_named falls back to regular spawn. +/// This maintains API compatibility while optimizing out the name parameter. + #[cfg(not(feature = "rtos-trace"))] + pub fn spawn_named(&self, _name: &'static str, token: SpawnToken) -> Result<(), SpawnError> { + self.spawn(token) + } + // Used by the `embassy_executor_macros::main!` macro to throw an error when spawn // fails. This is here to allow conditional use of `defmt::unwrap!` // without introducing a `defmt` feature in the `embassy_executor_macros` package, From bbffd2b3f9f27dd9c3ae3f66ac88bcd1ee1dcb93 Mon Sep 17 00:00:00 2001 From: Kat Perez Date: Mon, 5 May 2025 12:17:03 -0400 Subject: [PATCH 1078/1217] whitespace in the documentation --- embassy-executor/src/spawner.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-executor/src/spawner.rs b/embassy-executor/src/spawner.rs index f87700be6..4fc4312b9 100644 --- a/embassy-executor/src/spawner.rs +++ b/embassy-executor/src/spawner.rs @@ -182,7 +182,7 @@ impl Spawner { } /// When rtos-trace is disabled, spawn_named falls back to regular spawn. -/// This maintains API compatibility while optimizing out the name parameter. + /// This maintains API compatibility while optimizing out the name parameter. #[cfg(not(feature = "rtos-trace"))] pub fn spawn_named(&self, _name: &'static str, token: SpawnToken) -> Result<(), SpawnError> { self.spawn(token) From 05d52decb2a98ad5111962b71e667c692e68c23e Mon Sep 17 00:00:00 2001 From: Kat Perez Date: Tue, 6 May 2025 09:04:21 -0400 Subject: [PATCH 1079/1217] add name to TaskHeader --- embassy-executor/src/raw/mod.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs index 35c82557c..2928848b8 100644 --- a/embassy-executor/src/raw/mod.rs +++ b/embassy-executor/src/raw/mod.rs @@ -89,6 +89,8 @@ pub(crate) struct TaskHeader { /// Integrated timer queue storage. This field should not be accessed outside of the timer queue. pub(crate) timer_queue_item: timer_queue::TimerQueueItem, + #[cfg(feature = "trace")] + pub(crate) name: Option<&'static str>, } /// This is essentially a `&'static TaskStorage` where the type of the future has been erased. @@ -190,6 +192,8 @@ impl TaskStorage { poll_fn: SyncUnsafeCell::new(None), timer_queue_item: timer_queue::TimerQueueItem::new(), + #[cfg(feature = "trace")] + name: None, }, future: UninitCell::uninit(), } From 61f0f889a0dc89410218be725a43dcd967e53003 Mon Sep 17 00:00:00 2001 From: Kat Perez Date: Tue, 6 May 2025 09:23:39 -0400 Subject: [PATCH 1080/1217] add get/set for task name --- embassy-executor/src/raw/mod.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs index 2928848b8..3f4e06350 100644 --- a/embassy-executor/src/raw/mod.rs +++ b/embassy-executor/src/raw/mod.rs @@ -151,6 +151,21 @@ impl TaskRef { pub fn as_id(self) -> u32 { self.ptr.as_ptr() as u32 } + + /// Get the name for a task + #[cfg(feature = "trace")] + pub fn name(&self) -> Option<&'static str> { + self.header().name + } + + /// Set the name for a task + #[cfg(feature = "trace")] + pub fn set_name(&self, name: Option<&'static str>) { + unsafe { + let header_ptr = self.ptr.as_ptr() as *mut TaskHeader; + (*header_ptr).name = name; + } + } } /// Raw storage in which a task can be spawned. From 54b3fb6e7a12598e0f6299c18a333060d6a3f9c7 Mon Sep 17 00:00:00 2001 From: Kat Perez Date: Tue, 6 May 2025 09:27:19 -0400 Subject: [PATCH 1081/1217] remove name from TaskRegistry and retrieve from task header instead --- embassy-executor/src/raw/trace.rs | 33 ++++++------------------------- embassy-executor/src/spawner.rs | 3 ++- 2 files changed, 8 insertions(+), 28 deletions(-) diff --git a/embassy-executor/src/raw/trace.rs b/embassy-executor/src/raw/trace.rs index bdd3e4706..28be79cee 100644 --- a/embassy-executor/src/raw/trace.rs +++ b/embassy-executor/src/raw/trace.rs @@ -81,7 +81,7 @@ #![allow(unused)] -use crate::raw::{SyncExecutor, TaskRef}; +use crate::raw::{SyncExecutor, TaskHeader, TaskRef}; use core::cell::UnsafeCell; use core::sync::atomic::{AtomicUsize, Ordering}; @@ -95,7 +95,6 @@ const MAX_TASKS: usize = 1000; #[derive(Clone)] pub struct TrackedTask { task_id: u32, - name: Option<&'static str>, } /// A thread-safe registry for tracking tasks in the system. @@ -128,7 +127,7 @@ impl TaskRegistry { /// /// # Note /// If the registry is full, the task will not be registered. - pub fn register(&self, task_id: u32, name: Option<&'static str>) { + pub fn register(&self, task_id: u32) { let count = self.count.load(Ordering::Relaxed); if count < MAX_TASKS { for i in 0..MAX_TASKS { @@ -136,7 +135,7 @@ impl TaskRegistry { let slot = &self.tasks[i]; let slot_ref = &mut *slot.get(); if slot_ref.is_none() { - *slot_ref = Some(TrackedTask { task_id, name }); + *slot_ref = Some(TrackedTask { task_id }); self.count.fetch_add(1, Ordering::Relaxed); break; } @@ -174,28 +173,6 @@ impl TaskRegistry { (*slot.get()).clone() }) } - - /// Retrieves the name of a task with the given ID. - /// - /// # Arguments - /// * `task_id` - Unique identifier of the task - /// - /// # Returns - /// The name of the task if found and named, or `None` otherwise - pub fn get_task_name(&self, task_id: u32) -> Option<&'static str> { - for i in 0..MAX_TASKS { - unsafe { - let slot = &self.tasks[i]; - let slot_ref = &*slot.get(); - if let Some(task) = slot_ref { - if task.task_id == task_id { - return task.name; - } - } - } - } - None - } } unsafe impl Sync for TaskRegistry {} @@ -343,8 +320,10 @@ pub(crate) fn executor_idle(executor: &SyncExecutor) { impl rtos_trace::RtosTraceOSCallbacks for crate::raw::SyncExecutor { fn task_list() { for task in TASK_REGISTRY.get_all_tasks() { + let task_ref = unsafe { TaskRef::from_ptr(task.task_id as *const TaskHeader) }; + let name = task_ref.name().unwrap_or("unnamed\0"); let info = rtos_trace::TaskInfo { - name: TASK_REGISTRY.get_task_name(task.task_id).unwrap(), + name, priority: 0, stack_base: 0, stack_size: 0, diff --git a/embassy-executor/src/spawner.rs b/embassy-executor/src/spawner.rs index 4fc4312b9..40202299f 100644 --- a/embassy-executor/src/spawner.rs +++ b/embassy-executor/src/spawner.rs @@ -171,8 +171,9 @@ impl Spawner { match task { Some(task) => { + task.set_name(Some(name)); let task_id = task.as_ptr() as u32; - TASK_REGISTRY.register(task_id, Some(name)); + TASK_REGISTRY.register(task_id); unsafe { self.executor.spawn(task) }; Ok(()) From f4e0cbb7cc476b171acd0b21448e9bbc848a616d Mon Sep 17 00:00:00 2001 From: Kat Perez Date: Tue, 6 May 2025 09:59:27 -0400 Subject: [PATCH 1082/1217] add ID field to TaskHeader --- embassy-executor/src/raw/mod.rs | 19 +++++++++++++++++++ embassy-executor/src/spawner.rs | 1 + 2 files changed, 20 insertions(+) diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs index 3f4e06350..075d8a254 100644 --- a/embassy-executor/src/raw/mod.rs +++ b/embassy-executor/src/raw/mod.rs @@ -91,6 +91,8 @@ pub(crate) struct TaskHeader { pub(crate) timer_queue_item: timer_queue::TimerQueueItem, #[cfg(feature = "trace")] pub(crate) name: Option<&'static str>, + #[cfg(feature = "trace")] + pub(crate) id: u32, } /// This is essentially a `&'static TaskStorage` where the type of the future has been erased. @@ -166,6 +168,21 @@ impl TaskRef { (*header_ptr).name = name; } } + + /// Get the ID for a task + #[cfg(feature = "trace")] + pub fn id(&self) -> u32 { + self.header().id + } + + /// Set the ID for a task + #[cfg(feature = "trace")] + pub fn set_id(&self, id: u32) { + unsafe { + let header_ptr = self.ptr.as_ptr() as *mut TaskHeader; + (*header_ptr).id = id; + } + } } /// Raw storage in which a task can be spawned. @@ -209,6 +226,8 @@ impl TaskStorage { timer_queue_item: timer_queue::TimerQueueItem::new(), #[cfg(feature = "trace")] name: None, + #[cfg(feature = "trace")] + id: 0, }, future: UninitCell::uninit(), } diff --git a/embassy-executor/src/spawner.rs b/embassy-executor/src/spawner.rs index 40202299f..7f907346d 100644 --- a/embassy-executor/src/spawner.rs +++ b/embassy-executor/src/spawner.rs @@ -174,6 +174,7 @@ impl Spawner { task.set_name(Some(name)); let task_id = task.as_ptr() as u32; TASK_REGISTRY.register(task_id); + task.set_id(task_id); unsafe { self.executor.spawn(task) }; Ok(()) From 6085916714b79a888e117a2d7223e78c9a5de9d3 Mon Sep 17 00:00:00 2001 From: Kat Perez Date: Tue, 6 May 2025 11:47:04 -0400 Subject: [PATCH 1083/1217] use an intrusive linked list in TaskHeader to track tasks --- embassy-executor/src/raw/mod.rs | 76 +++++++++++- embassy-executor/src/raw/trace.rs | 190 ++++++++++++++---------------- embassy-executor/src/spawner.rs | 3 - 3 files changed, 163 insertions(+), 106 deletions(-) diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs index 075d8a254..b4adfe01b 100644 --- a/embassy-executor/src/raw/mod.rs +++ b/embassy-executor/src/raw/mod.rs @@ -93,6 +93,78 @@ pub(crate) struct TaskHeader { pub(crate) name: Option<&'static str>, #[cfg(feature = "trace")] pub(crate) id: u32, + #[cfg(feature = "trace")] + all_tasks_next: AtomicPtr, +} + +/// A thread-safe tracker for all tasks in the system +/// +/// This struct uses an intrusive linked list approach to track all tasks +/// without additional memory allocations. It maintains a global list of +/// tasks that can be traversed to find all currently existing tasks. +#[cfg(feature = "trace")] +pub struct TaskTracker { + head: AtomicPtr, +} + +#[cfg(feature = "trace")] +impl TaskTracker { + /// Creates a new empty task tracker + /// + /// Initializes a tracker with no tasks in its list. + pub const fn new() -> Self { + Self { + head: AtomicPtr::new(core::ptr::null_mut()), + } + } + + /// Adds a task to the tracker + /// + /// This method inserts a task at the head of the intrusive linked list. + /// The operation is thread-safe and lock-free, using atomic operations + /// to ensure consistency even when called from different contexts. + /// + /// # Arguments + /// * `task` - The task reference to add to the tracker + pub fn add(&self, task: TaskRef) { + let task_ptr = task.as_ptr() as *mut TaskHeader; + + loop { + let current_head = self.head.load(Ordering::Acquire); + unsafe { + (*task_ptr).all_tasks_next.store(current_head, Ordering::Relaxed); + } + + if self + .head + .compare_exchange(current_head, task_ptr, Ordering::Release, Ordering::Relaxed) + .is_ok() + { + break; + } + } + } + + /// Performs an operation on each task in the tracker + /// + /// This method traverses the entire list of tasks and calls the provided + /// function for each task. This allows inspecting or processing all tasks + /// in the system without modifying the tracker's structure. + /// + /// # Arguments + /// * `f` - A function to call for each task in the tracker + pub fn for_each(&self, mut f: F) + where + F: FnMut(TaskRef), + { + let mut current = self.head.load(Ordering::Acquire); + while !current.is_null() { + let task = unsafe { TaskRef::from_ptr(current) }; + f(task); + + current = unsafe { (*current).all_tasks_next.load(Ordering::Acquire) }; + } + } } /// This is essentially a `&'static TaskStorage` where the type of the future has been erased. @@ -173,7 +245,7 @@ impl TaskRef { #[cfg(feature = "trace")] pub fn id(&self) -> u32 { self.header().id - } + } /// Set the ID for a task #[cfg(feature = "trace")] @@ -228,6 +300,8 @@ impl TaskStorage { name: None, #[cfg(feature = "trace")] id: 0, + #[cfg(feature = "trace")] + all_tasks_next: AtomicPtr::new(core::ptr::null_mut()), }, future: UninitCell::uninit(), } diff --git a/embassy-executor/src/raw/trace.rs b/embassy-executor/src/raw/trace.rs index 28be79cee..81c8a0024 100644 --- a/embassy-executor/src/raw/trace.rs +++ b/embassy-executor/src/raw/trace.rs @@ -81,107 +81,19 @@ #![allow(unused)] -use crate::raw::{SyncExecutor, TaskHeader, TaskRef}; +use crate::raw::{SyncExecutor, TaskHeader, TaskRef, TaskTracker}; use core::cell::UnsafeCell; use core::sync::atomic::{AtomicUsize, Ordering}; use rtos_trace::TaskInfo; -const MAX_TASKS: usize = 1000; - -/// Represents a task being tracked in the task registry. +/// Global task tracker instance /// -/// Contains the task's unique identifier and optional name. -#[derive(Clone)] -pub struct TrackedTask { - task_id: u32, -} - -/// A thread-safe registry for tracking tasks in the system. -/// -/// This registry maintains a list of active tasks with their IDs and optional names. -/// It supports registering, unregistering, and querying information about tasks. -/// The registry has a fixed capacity of `MAX_TASKS`. -pub struct TaskRegistry { - tasks: [UnsafeCell>; MAX_TASKS], - count: AtomicUsize, -} - -impl TaskRegistry { - /// Creates a new empty task registry. - /// - /// This initializes a registry that can track up to `MAX_TASKS` tasks. - pub const fn new() -> Self { - const EMPTY: UnsafeCell> = UnsafeCell::new(None); - Self { - tasks: [EMPTY; MAX_TASKS], - count: AtomicUsize::new(0), - } - } - - /// Registers a new task in the registry. - /// - /// # Arguments - /// * `task_id` - Unique identifier for the task - /// * `name` - Optional name for the task - /// - /// # Note - /// If the registry is full, the task will not be registered. - pub fn register(&self, task_id: u32) { - let count = self.count.load(Ordering::Relaxed); - if count < MAX_TASKS { - for i in 0..MAX_TASKS { - unsafe { - let slot = &self.tasks[i]; - let slot_ref = &mut *slot.get(); - if slot_ref.is_none() { - *slot_ref = Some(TrackedTask { task_id }); - self.count.fetch_add(1, Ordering::Relaxed); - break; - } - } - } - } - } - - /// Removes a task from the registry. - /// - /// # Arguments - /// * `task_id` - Unique identifier of the task to remove - pub fn unregister(&self, task_id: u32) { - for i in 0..MAX_TASKS { - unsafe { - let slot = &self.tasks[i]; - let slot_ref = &mut *slot.get(); - if let Some(task) = slot_ref { - if task.task_id == task_id { - *slot_ref = None; - self.count.fetch_sub(1, Ordering::Relaxed); - break; - } - } - } - } - } - - /// Returns an iterator over all registered tasks. - /// - /// This allows accessing information about all tasks currently in the registry. - pub fn get_all_tasks(&self) -> impl Iterator + '_ { - (0..MAX_TASKS).filter_map(move |i| unsafe { - let slot = &self.tasks[i]; - (*slot.get()).clone() - }) - } -} - -unsafe impl Sync for TaskRegistry {} -unsafe impl Send for TaskRegistry {} - -/// Global task registry instance used for tracking all tasks in the system. -/// -/// This provides a centralized registry accessible from anywhere in the application. -pub static TASK_REGISTRY: TaskRegistry = TaskRegistry::new(); +/// This static provides access to the global task tracker which maintains +/// a list of all tasks in the system. It's automatically updated by the +/// task lifecycle hooks in the trace module. +#[cfg(feature = "trace")] +pub static TASK_TRACKER: TaskTracker = TaskTracker::new(); #[cfg(not(feature = "rtos-trace"))] extern "Rust" { @@ -262,6 +174,9 @@ pub(crate) fn task_new(executor: &SyncExecutor, task: &TaskRef) { #[cfg(feature = "rtos-trace")] rtos_trace::trace::task_new(task.as_ptr() as u32); + + #[cfg(feature = "rtos-trace")] + TASK_TRACKER.add(*task); } #[inline] @@ -272,8 +187,6 @@ pub(crate) fn task_end(executor: *const SyncExecutor, task: &TaskRef) { unsafe { _embassy_trace_task_end(executor as u32, task.as_ptr() as u32) } - - TASK_REGISTRY.unregister(task_id); } #[inline] @@ -316,20 +229,93 @@ pub(crate) fn executor_idle(executor: &SyncExecutor) { rtos_trace::trace::system_idle(); } +/// Returns an iterator over all active tasks in the system +/// +/// This function provides a convenient way to iterate over all tasks +/// that are currently tracked in the system. The returned iterator +/// yields each task in the global task tracker. +/// +/// # Returns +/// An iterator that yields `TaskRef` items for each task +#[cfg(feature = "trace")] +pub fn get_all_active_tasks() -> impl Iterator + 'static { + struct TaskIterator<'a> { + tracker: &'a TaskTracker, + current: *mut TaskHeader, + } + + impl<'a> Iterator for TaskIterator<'a> { + type Item = TaskRef; + + fn next(&mut self) -> Option { + if self.current.is_null() { + return None; + } + + let task = unsafe { TaskRef::from_ptr(self.current) }; + self.current = unsafe { (*self.current).all_tasks_next.load(Ordering::Acquire) }; + + Some(task) + } + } + + TaskIterator { + tracker: &TASK_TRACKER, + current: TASK_TRACKER.head.load(Ordering::Acquire), + } +} + +/// Get all active tasks, filtered by a predicate function +#[cfg(feature = "trace")] +pub fn filter_active_tasks(predicate: F) -> impl Iterator + 'static +where + F: Fn(&TaskRef) -> bool + 'static, +{ + get_all_active_tasks().filter(move |task| predicate(task)) +} + +/// Count the number of active tasks +#[cfg(feature = "trace")] +pub fn count_active_tasks() -> usize { + let mut count = 0; + TASK_TRACKER.for_each(|_| count += 1); + count +} + +/// Perform an action on each active task +#[cfg(feature = "trace")] +pub fn with_all_active_tasks(f: F) +where + F: FnMut(TaskRef), +{ + TASK_TRACKER.for_each(f); +} + +/// Get tasks by name +#[cfg(feature = "trace")] +pub fn get_tasks_by_name(name: &'static str) -> impl Iterator + 'static { + filter_active_tasks(move |task| task.name() == Some(name)) +} + +/// Get tasks by ID +#[cfg(feature = "trace")] +pub fn get_task_by_id(id: u32) -> Option { + filter_active_tasks(move |task| task.id() == id).next() +} + #[cfg(feature = "rtos-trace")] impl rtos_trace::RtosTraceOSCallbacks for crate::raw::SyncExecutor { fn task_list() { - for task in TASK_REGISTRY.get_all_tasks() { - let task_ref = unsafe { TaskRef::from_ptr(task.task_id as *const TaskHeader) }; - let name = task_ref.name().unwrap_or("unnamed\0"); + with_all_active_tasks(|task| { + let name = task.name().unwrap_or("unnamed task\0"); let info = rtos_trace::TaskInfo { name, priority: 0, stack_base: 0, stack_size: 0, }; - rtos_trace::trace::task_send_info(task.task_id, info); - } + rtos_trace::trace::task_send_info(task.as_id(), info); + }); } fn time() -> u64 { const fn gcd(a: u64, b: u64) -> u64 { diff --git a/embassy-executor/src/spawner.rs b/embassy-executor/src/spawner.rs index 7f907346d..5e42f01bf 100644 --- a/embassy-executor/src/spawner.rs +++ b/embassy-executor/src/spawner.rs @@ -5,8 +5,6 @@ use core::sync::atomic::Ordering; use core::task::Poll; use super::raw; -#[cfg(feature = "rtos-trace")] -use super::raw::trace::TASK_REGISTRY; /// Token to spawn a newly-created task in an executor. /// @@ -173,7 +171,6 @@ impl Spawner { Some(task) => { task.set_name(Some(name)); let task_id = task.as_ptr() as u32; - TASK_REGISTRY.register(task_id); task.set_id(task_id); unsafe { self.executor.spawn(task) }; From f2429c212e77969bacfe726cd293bf0ab5903664 Mon Sep 17 00:00:00 2001 From: Kat Perez Date: Tue, 6 May 2025 11:54:45 -0400 Subject: [PATCH 1084/1217] fix whitespace in the imports in trace.rs --- embassy-executor/src/raw/trace.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/embassy-executor/src/raw/trace.rs b/embassy-executor/src/raw/trace.rs index 81c8a0024..c0599d2c7 100644 --- a/embassy-executor/src/raw/trace.rs +++ b/embassy-executor/src/raw/trace.rs @@ -81,12 +81,13 @@ #![allow(unused)] -use crate::raw::{SyncExecutor, TaskHeader, TaskRef, TaskTracker}; - use core::cell::UnsafeCell; use core::sync::atomic::{AtomicUsize, Ordering}; + use rtos_trace::TaskInfo; +use crate::raw::{SyncExecutor, TaskHeader, TaskRef, TaskTracker}; + /// Global task tracker instance /// /// This static provides access to the global task tracker which maintains From bd3b3b45266c3dc3bf0d443a2e727814968cb245 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=BCha=20=C3=9Cn=C3=BCvar?= <87157627+phycrax@users.noreply.github.com> Date: Wed, 7 May 2025 17:14:28 +0800 Subject: [PATCH 1085/1217] derive debug copy clone defmt for pwmpinconfig --- embassy-stm32/src/timer/simple_pwm.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs index 54ab7d0d5..8fd7e8df4 100644 --- a/embassy-stm32/src/timer/simple_pwm.rs +++ b/embassy-stm32/src/timer/simple_pwm.rs @@ -31,6 +31,8 @@ pub struct PwmPin<'d, T, C> { /// PWM pin config /// /// This configures the pwm pin settings +#[derive(Debug, Copy, Clone)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct PwmPinConfig { /// PWM Pin output type pub output_type: OutputType, From 9d9ae7c5d5bf3371a7bec2fa69a9c27415277fc0 Mon Sep 17 00:00:00 2001 From: Hiroaki Yutani Date: Wed, 7 May 2025 22:59:41 +0900 Subject: [PATCH 1086/1217] Revert --- embassy-rp/Cargo.toml | 7 ++--- embassy-rp/src/bootsel.rs | 2 +- embassy-rp/src/flash.rs | 6 ++-- embassy-rp/src/lib.rs | 8 ++--- embassy-rp/src/multicore.rs | 4 +-- embassy-stm32-wpan/src/tables.rs | 50 ++++++++++++++++---------------- embassy-stm32/src/lib.rs | 2 +- tests/rp/Cargo.toml | 3 -- 8 files changed, 38 insertions(+), 44 deletions(-) diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index e8091a2a5..b440591cf 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml @@ -86,7 +86,7 @@ boot2-w25x10cl = [] ## Have embassy-rp not provide the boot2 so you can use your own. ## Place your own in the ".boot2" section like: ## ``` -## #[unsafe(link_section = ".boot2")] +## #[link_section = ".boot2"] ## #[used] ## static BOOT2: [u8; 256] = [0; 256]; // Provide your own with e.g. include_bytes! ## ``` @@ -109,7 +109,7 @@ imagedef-nonsecure-exe = [] ## ```ignore ## use embassy_rp::block::ImageDef; ## -## #[unsafe(link_section = ".start_block")] +## #[link_section = ".start_block"] ## #[used] ## static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); // Update this with your own implementation. ## ``` @@ -174,6 +174,3 @@ smart-leds = "0.4.0" [dev-dependencies] embassy-executor = { version = "0.7.0", path = "../embassy-executor", features = ["arch-std", "executor-thread"] } static_cell = { version = "2" } - -[patch.crates-io] -cortex-m-rt = { git = "https://github.com/yutannihilation/cortex-m", branch = "fix/allow-unsafe-wrap-rust2024" } diff --git a/embassy-rp/src/bootsel.rs b/embassy-rp/src/bootsel.rs index 5f0bac248..14f9e46aa 100644 --- a/embassy-rp/src/bootsel.rs +++ b/embassy-rp/src/bootsel.rs @@ -36,7 +36,7 @@ mod ram_helpers { /// This function must live in ram. It uses inline asm to avoid any /// potential calls to ABI functions that might be in flash. #[inline(never)] - #[unsafe(link_section = ".data.ram_func")] + #[link_section = ".data.ram_func"] #[cfg(target_arch = "arm")] pub unsafe fn read_cs_status() -> GpioStatus { let result: u32; diff --git a/embassy-rp/src/flash.rs b/embassy-rp/src/flash.rs index 1ac15a677..ef1cd9212 100644 --- a/embassy-rp/src/flash.rs +++ b/embassy-rp/src/flash.rs @@ -623,7 +623,7 @@ mod ram_helpers { /// Length of data must be a multiple of 4096 /// addr must be aligned to 4096 #[inline(never)] - #[unsafe(link_section = ".data.ram_func")] + #[link_section = ".data.ram_func"] #[cfg(feature = "rp2040")] unsafe fn write_flash_inner(addr: u32, len: u32, data: Option<&[u8]>, ptrs: *const FlashFunctionPointers) { #[cfg(target_arch = "arm")] @@ -688,7 +688,7 @@ mod ram_helpers { /// Length of data must be a multiple of 4096 /// addr must be aligned to 4096 #[inline(never)] - #[unsafe(link_section = ".data.ram_func")] + #[link_section = ".data.ram_func"] #[cfg(feature = "_rp235x")] unsafe fn write_flash_inner(addr: u32, len: u32, data: Option<&[u8]>, ptrs: *const FlashFunctionPointers) { let data = data.map(|d| d.as_ptr()).unwrap_or(core::ptr::null()); @@ -807,7 +807,7 @@ mod ram_helpers { /// /// Credit: taken from `rp2040-flash` (also licensed Apache+MIT) #[inline(never)] - #[unsafe(link_section = ".data.ram_func")] + #[link_section = ".data.ram_func"] #[cfg(feature = "rp2040")] unsafe fn read_flash_inner(cmd: FlashCommand, ptrs: *const FlashFunctionPointers) { #[cfg(target_arch = "arm")] diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs index 9b7c2b6ea..f549446bc 100644 --- a/embassy-rp/src/lib.rs +++ b/embassy-rp/src/lib.rs @@ -434,13 +434,13 @@ macro_rules! select_bootloader { ( $( $feature:literal => $loader:ident, )+ default => $default:ident ) => { $( #[cfg(feature = $feature)] - #[unsafe(link_section = ".boot2")] + #[link_section = ".boot2"] #[used] static BOOT2: [u8; 256] = rp2040_boot2::$loader; )* #[cfg(not(any( $( feature = $feature),* )))] - #[unsafe(link_section = ".boot2")] + #[link_section = ".boot2"] #[used] static BOOT2: [u8; 256] = rp2040_boot2::$default; } @@ -463,13 +463,13 @@ macro_rules! select_imagedef { ( $( $feature:literal => $imagedef:ident, )+ default => $default:ident ) => { $( #[cfg(feature = $feature)] - #[unsafe(link_section = ".start_block")] + #[link_section = ".start_block"] #[used] static IMAGE_DEF: crate::block::ImageDef = crate::block::ImageDef::$imagedef(); )* #[cfg(not(any( $( feature = $feature),* )))] - #[unsafe(link_section = ".start_block")] + #[link_section = ".start_block"] #[used] static IMAGE_DEF: crate::block::ImageDef = crate::block::ImageDef::$default(); } diff --git a/embassy-rp/src/multicore.rs b/embassy-rp/src/multicore.rs index ec05bfdf5..d10b6837c 100644 --- a/embassy-rp/src/multicore.rs +++ b/embassy-rp/src/multicore.rs @@ -90,7 +90,7 @@ impl Stack { #[cfg(all(feature = "rt", feature = "rp2040"))] #[interrupt] -#[unsafe(link_section = ".data.ram_func")] +#[link_section = ".data.ram_func"] unsafe fn SIO_IRQ_PROC1() { let sio = pac::SIO; // Clear IRQ @@ -115,7 +115,7 @@ unsafe fn SIO_IRQ_PROC1() { #[cfg(all(feature = "rt", feature = "_rp235x"))] #[interrupt] -#[unsafe(link_section = ".data.ram_func")] +#[link_section = ".data.ram_func"] unsafe fn SIO_IRQ_FIFO() { let sio = pac::SIO; // Clear IRQ diff --git a/embassy-stm32-wpan/src/tables.rs b/embassy-stm32-wpan/src/tables.rs index 204790e6d..fe6fc47a3 100644 --- a/embassy-stm32-wpan/src/tables.rs +++ b/embassy-stm32-wpan/src/tables.rs @@ -190,94 +190,94 @@ pub struct RefTable { } // --------------------- ref table --------------------- -#[unsafe(link_section = "TL_REF_TABLE")] +#[link_section = "TL_REF_TABLE"] pub static mut TL_REF_TABLE: MaybeUninit = MaybeUninit::uninit(); -#[unsafe(link_section = "MB_MEM1")] +#[link_section = "MB_MEM1"] pub static mut TL_DEVICE_INFO_TABLE: Aligned> = Aligned(MaybeUninit::uninit()); -#[unsafe(link_section = "MB_MEM1")] +#[link_section = "MB_MEM1"] pub static mut TL_BLE_TABLE: Aligned> = Aligned(MaybeUninit::uninit()); -#[unsafe(link_section = "MB_MEM1")] +#[link_section = "MB_MEM1"] pub static mut TL_THREAD_TABLE: Aligned> = Aligned(MaybeUninit::uninit()); -#[unsafe(link_section = "MB_MEM1")] +#[link_section = "MB_MEM1"] pub static mut TL_LLD_TESTS_TABLE: Aligned> = Aligned(MaybeUninit::uninit()); -#[unsafe(link_section = "MB_MEM1")] +#[link_section = "MB_MEM1"] pub static mut TL_BLE_LLD_TABLE: Aligned> = Aligned(MaybeUninit::uninit()); -#[unsafe(link_section = "MB_MEM1")] +#[link_section = "MB_MEM1"] pub static mut TL_SYS_TABLE: Aligned> = Aligned(MaybeUninit::uninit()); -#[unsafe(link_section = "MB_MEM1")] +#[link_section = "MB_MEM1"] pub static mut TL_MEM_MANAGER_TABLE: Aligned> = Aligned(MaybeUninit::uninit()); -#[unsafe(link_section = "MB_MEM1")] +#[link_section = "MB_MEM1"] pub static mut TL_TRACES_TABLE: Aligned> = Aligned(MaybeUninit::uninit()); -#[unsafe(link_section = "MB_MEM1")] +#[link_section = "MB_MEM1"] pub static mut TL_MAC_802_15_4_TABLE: Aligned> = Aligned(MaybeUninit::uninit()); -#[unsafe(link_section = "MB_MEM1")] +#[link_section = "MB_MEM1"] pub static mut TL_ZIGBEE_TABLE: Aligned> = Aligned(MaybeUninit::uninit()); // --------------------- tables --------------------- -#[unsafe(link_section = "MB_MEM1")] +#[link_section = "MB_MEM1"] pub static mut FREE_BUF_QUEUE: Aligned> = Aligned(MaybeUninit::uninit()); #[allow(dead_code)] -#[unsafe(link_section = "MB_MEM1")] +#[link_section = "MB_MEM1"] pub static mut TRACES_EVT_QUEUE: Aligned> = Aligned(MaybeUninit::uninit()); -#[unsafe(link_section = "MB_MEM2")] +#[link_section = "MB_MEM2"] pub static mut CS_BUFFER: Aligned> = Aligned(MaybeUninit::uninit()); -#[unsafe(link_section = "MB_MEM2")] +#[link_section = "MB_MEM2"] pub static mut EVT_QUEUE: Aligned> = Aligned(MaybeUninit::uninit()); -#[unsafe(link_section = "MB_MEM2")] +#[link_section = "MB_MEM2"] pub static mut SYSTEM_EVT_QUEUE: Aligned> = Aligned(MaybeUninit::uninit()); // --------------------- app tables --------------------- #[cfg(feature = "mac")] -#[unsafe(link_section = "MB_MEM2")] +#[link_section = "MB_MEM2"] pub static mut MAC_802_15_4_CMD_BUFFER: Aligned> = Aligned(MaybeUninit::uninit()); #[cfg(feature = "mac")] -#[unsafe(link_section = "MB_MEM2")] +#[link_section = "MB_MEM2"] pub static mut MAC_802_15_4_NOTIF_RSP_EVT_BUFFER: MaybeUninit< Aligned, > = MaybeUninit::uninit(); -#[unsafe(link_section = "MB_MEM2")] +#[link_section = "MB_MEM2"] pub static mut EVT_POOL: Aligned> = Aligned(MaybeUninit::uninit()); -#[unsafe(link_section = "MB_MEM2")] +#[link_section = "MB_MEM2"] pub static mut SYS_CMD_BUF: Aligned> = Aligned(MaybeUninit::uninit()); -#[unsafe(link_section = "MB_MEM2")] +#[link_section = "MB_MEM2"] pub static mut SYS_SPARE_EVT_BUF: Aligned> = Aligned(MaybeUninit::uninit()); #[cfg(feature = "mac")] -#[unsafe(link_section = "MB_MEM2")] +#[link_section = "MB_MEM2"] pub static mut MAC_802_15_4_CNFINDNOT: Aligned> = Aligned(MaybeUninit::uninit()); #[cfg(feature = "ble")] -#[unsafe(link_section = "MB_MEM1")] +#[link_section = "MB_MEM1"] pub static mut BLE_CMD_BUFFER: Aligned> = Aligned(MaybeUninit::uninit()); #[cfg(feature = "ble")] -#[unsafe(link_section = "MB_MEM2")] +#[link_section = "MB_MEM2"] pub static mut BLE_SPARE_EVT_BUF: Aligned> = Aligned(MaybeUninit::uninit()); #[cfg(feature = "ble")] -#[unsafe(link_section = "MB_MEM2")] +#[link_section = "MB_MEM2"] // fuck these "magic" numbers from ST ---v---v pub static mut HCI_ACL_DATA_BUFFER: Aligned> = Aligned(MaybeUninit::uninit()); diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 8ba604830..226293a9d 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -331,7 +331,7 @@ mod dual_core { /// use core::mem::MaybeUninit; /// use embassy_stm32::{init_secondary, SharedData}; /// - /// #[unsafe(link_section = ".ram_d3")] + /// #[link_section = ".ram_d3"] /// static SHARED_DATA: MaybeUninit = MaybeUninit::uninit(); /// /// init_secondary(&SHARED_DATA); diff --git a/tests/rp/Cargo.toml b/tests/rp/Cargo.toml index ed3a880a0..1335aa84b 100644 --- a/tests/rp/Cargo.toml +++ b/tests/rp/Cargo.toml @@ -93,6 +93,3 @@ debug = false debug-assertions = false opt-level = 0 overflow-checks = false - -[patch.crates-io] -cortex-m-rt = { git = "https://github.com/yutannihilation/cortex-m", branch = "fix/allow-unsafe-wrap-rust2024" } From f5ddb9358f841d1a1e3a996eb30d7d9fd5d44d38 Mon Sep 17 00:00:00 2001 From: Hiroaki Yutani Date: Wed, 7 May 2025 23:00:39 +0900 Subject: [PATCH 1087/1217] Remove tweak --- examples/rp/Cargo.toml | 3 --- examples/rp235x/Cargo.toml | 3 --- 2 files changed, 6 deletions(-) diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index 97b14a327..45ca30e4c 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml @@ -67,6 +67,3 @@ opt-level = 'z' debug = 2 lto = true opt-level = "z" - -[patch.crates-io] -cortex-m-rt = { git = "https://github.com/yutannihilation/cortex-m", branch = "fix/allow-unsafe-wrap-rust2024" } diff --git a/examples/rp235x/Cargo.toml b/examples/rp235x/Cargo.toml index 99091ee90..345a915af 100644 --- a/examples/rp235x/Cargo.toml +++ b/examples/rp235x/Cargo.toml @@ -64,6 +64,3 @@ debug = 2 [profile.dev] lto = true opt-level = "z" - -[patch.crates-io] -cortex-m-rt = { git = "https://github.com/yutannihilation/cortex-m", branch = "fix/allow-unsafe-wrap-rust2024" } From 70e2c052056e31f06ac67d69fda503f07cae46d0 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 7 May 2025 08:33:03 -0700 Subject: [PATCH 1088/1217] Rename rtc.rs to time_driver.rs We will add another time driver for user selection. --- embassy-imxrt/src/lib.rs | 4 ++-- embassy-imxrt/src/{rtc.rs => time_driver.rs} | 0 2 files changed, 2 insertions(+), 2 deletions(-) rename embassy-imxrt/src/{rtc.rs => time_driver.rs} (100%) diff --git a/embassy-imxrt/src/lib.rs b/embassy-imxrt/src/lib.rs index 5fbf3244b..fdf07b433 100644 --- a/embassy-imxrt/src/lib.rs +++ b/embassy-imxrt/src/lib.rs @@ -22,7 +22,7 @@ pub mod gpio; pub mod iopctl; #[cfg(feature = "_time-driver")] -pub mod rtc; +pub mod time_driver; // This mod MUST go last, so that it sees all the `impl_foo!' macros #[cfg_attr(feature = "mimxrt633s", path = "chips/mimxrt633s.rs")] @@ -137,7 +137,7 @@ pub fn init(config: config::Config) -> Peripherals { // init RTC time driver #[cfg(feature = "_time-driver")] - rtc::init(config.time_interrupt_priority); + time_driver::init(config.time_interrupt_priority); peripherals } diff --git a/embassy-imxrt/src/rtc.rs b/embassy-imxrt/src/time_driver.rs similarity index 100% rename from embassy-imxrt/src/rtc.rs rename to embassy-imxrt/src/time_driver.rs From 64ce271af526a9311b0c1c251b19b5ce79032551 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 7 May 2025 10:39:25 -0700 Subject: [PATCH 1089/1217] clocks: split clock and reset operations Some peripherals need to control clock without touching the reset. Signed-off-by: Felipe Balbi --- embassy-imxrt/src/clocks.rs | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/embassy-imxrt/src/clocks.rs b/embassy-imxrt/src/clocks.rs index 1d36fb142..5be5f3925 100644 --- a/embassy-imxrt/src/clocks.rs +++ b/embassy-imxrt/src/clocks.rs @@ -1561,7 +1561,8 @@ pub(crate) unsafe fn init(config: ClockConfig) -> Result<(), ClockError> { ///Trait to expose perph clocks trait SealedSysconPeripheral { - fn enable_and_reset_perph_clock(); + fn enable_perph_clock(); + fn reset_perph(); fn disable_perph_clock(); } @@ -1574,7 +1575,18 @@ pub trait SysconPeripheral: SealedSysconPeripheral + 'static {} /// /// Peripheral must not be in use. pub fn enable_and_reset() { - T::enable_and_reset_perph_clock(); + T::enable_perph_clock(); + T::reset_perph(); +} + +/// Enables peripheral `T`. +pub fn enable() { + T::enable_perph_clock(); +} + +/// Reset peripheral `T`. +pub fn reset() { + T::reset_perph(); } /// Disables peripheral `T`. @@ -1588,15 +1600,21 @@ pub fn disable() { macro_rules! impl_perph_clk { ($peripheral:ident, $clkctl:ident, $clkreg:ident, $rstctl:ident, $rstreg:ident, $bit:expr) => { impl SealedSysconPeripheral for crate::peripherals::$peripheral { - fn enable_and_reset_perph_clock() { + fn enable_perph_clock() { // SAFETY: unsafe needed to take pointers to Rstctl1 and Clkctl1 let cc1 = unsafe { pac::$clkctl::steal() }; - let rc1 = unsafe { pac::$rstctl::steal() }; paste! { // SAFETY: unsafe due to the use of bits() cc1.[<$clkreg _set>]().write(|w| unsafe { w.bits(1 << $bit) }); + } + } + fn reset_perph() { + // SAFETY: unsafe needed to take pointers to Rstctl1 and Clkctl1 + let rc1 = unsafe { pac::$rstctl::steal() }; + + paste! { // SAFETY: unsafe due to the use of bits() rc1.[<$rstreg _clr>]().write(|w| unsafe { w.bits(1 << $bit) }); } @@ -1605,12 +1623,8 @@ macro_rules! impl_perph_clk { fn disable_perph_clock() { // SAFETY: unsafe needed to take pointers to Rstctl1 and Clkctl1 let cc1 = unsafe { pac::$clkctl::steal() }; - let rc1 = unsafe { pac::$rstctl::steal() }; paste! { - // SAFETY: unsafe due to the use of bits() - rc1.[<$rstreg _set>]().write(|w| unsafe { w.bits(1 << $bit) }); - // SAFETY: unsafe due to the use of bits() cc1.[<$clkreg _clr>]().write(|w| unsafe { w.bits(1 << $bit) }); } From a254daf4fffe74c65d1846f620dd674fa4e14aac Mon Sep 17 00:00:00 2001 From: 1-rafael-1 Date: Wed, 7 May 2025 21:19:09 +0200 Subject: [PATCH 1090/1217] Changes after review --- embassy-rp/src/clocks.rs | 51 ++++++++++++++++++++++---------- examples/rp/src/bin/overclock.rs | 2 +- tests/rp/src/bin/overclock.rs | 2 +- 3 files changed, 37 insertions(+), 18 deletions(-) diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs index a4cc129ab..0c3988aac 100644 --- a/embassy-rp/src/clocks.rs +++ b/embassy-rp/src/clocks.rs @@ -9,7 +9,7 @@ //! //! For most users, these functions provide an easy way to configure clocks: //! -//! - `ClockConfig::at_sys_frequency_mhz(200)` - Set system clock to a specific frequency with automatic voltage scaling +//! - `ClockConfig::system_freq(125_000_000)` - Set system clock to a specific frequency with automatic voltage scaling //! - `ClockConfig::crystal(12_000_000)` - Default configuration with 12MHz crystal giving 125MHz system clock //! //! ## Manual Configuration @@ -50,7 +50,7 @@ //! //! ### Overclock to 200MHz //! ```rust,ignore -//! let config = ClockConfig::crystal_freq(200_000_000); +//! let config = ClockConfig::system_freq(200_000_000); //! ``` //! //! ### Manual configuration for advanced scenarios @@ -90,6 +90,7 @@ struct Clocks { pll_usb: AtomicU32, usb: AtomicU32, adc: AtomicU32, + // See above re gpin handling being commented out // gpin0: AtomicU32, // gpin1: AtomicU32, rosc: AtomicU32, @@ -106,6 +107,7 @@ static CLOCKS: Clocks = Clocks { pll_usb: AtomicU32::new(0), usb: AtomicU32::new(0), adc: AtomicU32::new(0), + // See above re gpin handling being commented out // gpin0: AtomicU32::new(0), // gpin1: AtomicU32::new(0), rosc: AtomicU32::new(0), @@ -129,6 +131,7 @@ pub enum PeriClkSrc { Rosc = ClkPeriCtrlAuxsrc::ROSC_CLKSRC_PH as _, /// XOSC. Xosc = ClkPeriCtrlAuxsrc::XOSC_CLKSRC as _, + // See above re gpin handling being commented out // Gpin0 = ClkPeriCtrlAuxsrc::CLKSRC_GPIN0 as _ , // Gpin1 = ClkPeriCtrlAuxsrc::CLKSRC_GPIN1 as _ , } @@ -213,6 +216,7 @@ pub struct ClockConfig { /// If not set, defaults will be used based on voltage level. #[cfg(feature = "rp2040")] pub voltage_stabilization_delay_us: Option, + // See above re gpin handling being commented out // gpin0: Option<(u32, Gpin<'static, AnyPin>)>, // gpin1: Option<(u32, Gpin<'static, AnyPin>)>, } @@ -227,7 +231,7 @@ impl Default for ClockConfig { /// Most users should use one of the more specific configuration functions: /// - `ClockConfig::crystal()` - Standard configuration with external crystal /// - `ClockConfig::rosc()` - Configuration using only the internal oscillator - /// - `ClockConfig::at_sys_frequency_mhz()` - Configuration for a specific system frequency + /// - `ClockConfig::system_freq()` - Configuration for a specific system frequency fn default() -> Self { Self { rosc: None, @@ -250,6 +254,7 @@ impl Default for ClockConfig { core_voltage: CoreVoltage::V1_10, #[cfg(feature = "rp2040")] voltage_stabilization_delay_us: None, + // See above re gpin handling being commented out // gpin0: None, // gpin1: None, } @@ -322,6 +327,7 @@ impl ClockConfig { core_voltage: CoreVoltage::V1_10, // Use hardware default (1.10V) #[cfg(feature = "rp2040")] voltage_stabilization_delay_us: None, + // See above re gpin handling being commented out // gpin0: None, // gpin1: None, } @@ -366,6 +372,7 @@ impl ClockConfig { core_voltage: CoreVoltage::V1_10, // Use hardware default (1.10V) #[cfg(feature = "rp2040")] voltage_stabilization_delay_us: None, + // See above re gpin handling being commented out // gpin0: None, // gpin1: None, } @@ -393,19 +400,19 @@ impl ClockConfig { /// That way all other frequencies below 133MHz or above 200MHz are not explicitly documented and not covered here. /// In case You want to go below 133MHz or above 200MHz and want a different voltage, You will have to set that manually and with caution. #[cfg(feature = "rp2040")] - pub fn crystal_freq(sys_freq_hz: u32) -> Self { + pub fn system_freq(hz: u32) -> Self { // Start with the standard configuration from crystal() const DEFAULT_CRYSTAL_HZ: u32 = 12_000_000; let mut config = Self::crystal(DEFAULT_CRYSTAL_HZ); // No need to modify anything if target frequency is already 125MHz // (which is what crystal() configures by default) - if sys_freq_hz == 125_000_000 { + if hz == 125_000_000 { return config; } // Find optimal PLL parameters for the requested frequency - let sys_pll_params = find_pll_params(DEFAULT_CRYSTAL_HZ, sys_freq_hz) + let sys_pll_params = find_pll_params(DEFAULT_CRYSTAL_HZ, hz) .unwrap_or_else(|| panic!("Could not find valid PLL parameters for system clock")); // Replace the sys_pll configuration with our custom parameters @@ -417,7 +424,7 @@ impl ClockConfig { // Higher frequencies require higher voltage #[cfg(feature = "rp2040")] { - config.core_voltage = match sys_freq_hz { + config.core_voltage = match hz { freq if freq > 133_000_000 => CoreVoltage::V1_15, _ => CoreVoltage::V1_10, // Use default voltage (V1_10) }; @@ -631,6 +638,7 @@ pub enum RefClkSrc { Rosc, /// PLL USB. PllUsb, + // See above re gpin handling being commented out // Gpin0, // Gpin1, } @@ -649,6 +657,7 @@ pub enum SysClkSrc { Rosc, /// XOSC. Xosc, + // See above re gpin handling being commented out // Gpin0, // Gpin1, } @@ -684,6 +693,7 @@ pub enum UsbClkSrc { Rosc = ClkUsbCtrlAuxsrc::ROSC_CLKSRC_PH as _, /// XOSC. Xosc = ClkUsbCtrlAuxsrc::XOSC_CLKSRC as _, + // See above re gpin handling being commented out // Gpin0 = ClkUsbCtrlAuxsrc::CLKSRC_GPIN0 as _ , // Gpin1 = ClkUsbCtrlAuxsrc::CLKSRC_GPIN1 as _ , } @@ -711,6 +721,7 @@ pub enum AdcClkSrc { Rosc = ClkAdcCtrlAuxsrc::ROSC_CLKSRC_PH as _, /// XOSC. Xosc = ClkAdcCtrlAuxsrc::XOSC_CLKSRC as _, + // See above re gpin handling being commented out // Gpin0 = ClkAdcCtrlAuxsrc::CLKSRC_GPIN0 as _ , // Gpin1 = ClkAdcCtrlAuxsrc::CLKSRC_GPIN1 as _ , } @@ -739,6 +750,7 @@ pub enum RtcClkSrc { Rosc = ClkRtcCtrlAuxsrc::ROSC_CLKSRC_PH as _, /// XOSC. Xosc = ClkRtcCtrlAuxsrc::XOSC_CLKSRC as _, + // See above re gpin handling being commented out // Gpin0 = ClkRtcCtrlAuxsrc::CLKSRC_GPIN0 as _ , // Gpin1 = ClkRtcCtrlAuxsrc::CLKSRC_GPIN1 as _ , } @@ -895,6 +907,7 @@ pub(crate) unsafe fn init(config: ClockConfig) { reset::reset(peris); reset::unreset_wait(peris); + // See above re gpin handling being commented out // let gpin0_freq = config.gpin0.map_or(0, |p| { // core::mem::forget(p.1); // p.0 @@ -941,7 +954,7 @@ pub(crate) unsafe fn init(config: ClockConfig) { cortex_m::asm::delay(delay_cycles); } - // Only now set the BOD level. At htis point the voltage is considered stable. + // Only now set the BOD level. At this point the voltage is considered stable. vreg.bod().write(|w| { w.set_vsel(voltage.recommended_bod()); w.set_en(true); // Enable brownout detection @@ -952,8 +965,6 @@ pub(crate) unsafe fn init(config: ClockConfig) { let (xosc_freq, pll_sys_freq, pll_usb_freq) = match config.xosc { Some(config) => { // start XOSC - // datasheet mentions support for clock inputs into XIN, but doesn't go into - // how this is achieved. pico-sdk doesn't support this at all. start_xosc(config.hz, config.delay_multiplier); let pll_sys_freq = match config.sys_pll { @@ -988,6 +999,7 @@ pub(crate) unsafe fn init(config: ClockConfig) { RefClkSrc::Xosc => (Src::XOSC_CLKSRC, Aux::CLKSRC_PLL_USB, xosc_freq / div), RefClkSrc::Rosc => (Src::ROSC_CLKSRC_PH, Aux::CLKSRC_PLL_USB, rosc_freq / div), RefClkSrc::PllUsb => (Src::CLKSRC_CLK_REF_AUX, Aux::CLKSRC_PLL_USB, pll_usb_freq / div), + // See above re gpin handling being commented out // RefClkSrc::Gpin0 => (Src::CLKSRC_CLK_REF_AUX, Aux::CLKSRC_GPIN0, gpin0_freq / div), // RefClkSrc::Gpin1 => (Src::CLKSRC_CLK_REF_AUX, Aux::CLKSRC_GPIN1, gpin1_freq / div), } @@ -1032,6 +1044,7 @@ pub(crate) unsafe fn init(config: ClockConfig) { SysClkSrc::PllUsb => (Src::CLKSRC_CLK_SYS_AUX, Aux::CLKSRC_PLL_USB, pll_usb_freq), SysClkSrc::Rosc => (Src::CLKSRC_CLK_SYS_AUX, Aux::ROSC_CLKSRC, rosc_freq), SysClkSrc::Xosc => (Src::CLKSRC_CLK_SYS_AUX, Aux::XOSC_CLKSRC, xosc_freq), + // See above re gpin handling being commented out // SysClkSrc::Gpin0 => (Src::CLKSRC_CLK_SYS_AUX, Aux::CLKSRC_GPIN0, gpin0_freq), // SysClkSrc::Gpin1 => (Src::CLKSRC_CLK_SYS_AUX, Aux::CLKSRC_GPIN1, gpin1_freq), }; @@ -1075,6 +1088,7 @@ pub(crate) unsafe fn init(config: ClockConfig) { PeriClkSrc::PllUsb => pll_usb_freq, PeriClkSrc::Rosc => rosc_freq, PeriClkSrc::Xosc => xosc_freq, + // See above re gpin handling being commented out // PeriClkSrc::Gpin0 => gpin0_freq, // PeriClkSrc::Gpin1 => gpin1_freq, }; @@ -1100,6 +1114,7 @@ pub(crate) unsafe fn init(config: ClockConfig) { UsbClkSrc::PllSys => pll_sys_freq, UsbClkSrc::Rosc => rosc_freq, UsbClkSrc::Xosc => xosc_freq, + // See above re gpin handling being commented out // UsbClkSrc::Gpin0 => gpin0_freq, // UsbClkSrc::Gpin1 => gpin1_freq, }; @@ -1123,6 +1138,7 @@ pub(crate) unsafe fn init(config: ClockConfig) { AdcClkSrc::PllSys => pll_sys_freq, AdcClkSrc::Rosc => rosc_freq, AdcClkSrc::Xosc => xosc_freq, + // See above re gpin handling being commented out // AdcClkSrc::Gpin0 => gpin0_freq, // AdcClkSrc::Gpin1 => gpin1_freq, }; @@ -1151,6 +1167,7 @@ pub(crate) unsafe fn init(config: ClockConfig) { RtcClkSrc::PllSys => pll_sys_freq, RtcClkSrc::Rosc => rosc_freq, RtcClkSrc::Xosc => xosc_freq, + // See above re gpin handling being commented out // RtcClkSrc::Gpin0 => gpin0_freq, // RtcClkSrc::Gpin1 => gpin1_freq, }; @@ -1217,6 +1234,7 @@ pub fn xosc_freq() -> u32 { CLOCKS.xosc.load(Ordering::Relaxed) } +// See above re gpin handling being commented out // pub fn gpin0_freq() -> u32 { // CLOCKS.gpin0.load(Ordering::Relaxed) // } @@ -1452,6 +1470,7 @@ impl_gpoutpin!(PIN_25, 3); pub enum GpoutSrc { /// Sys PLL. PllSys = ClkGpoutCtrlAuxsrc::CLKSRC_PLL_SYS as _, + // See above re gpin handling being commented out // Gpin0 = ClkGpoutCtrlAuxsrc::CLKSRC_GPIN0 as _ , // Gpin1 = ClkGpoutCtrlAuxsrc::CLKSRC_GPIN1 as _ , /// USB PLL. @@ -1547,6 +1566,7 @@ impl<'d, T: GpoutPin> Gpout<'d, T> { let base = match src { ClkGpoutCtrlAuxsrc::CLKSRC_PLL_SYS => pll_sys_freq(), + // See above re gpin handling being commented out // ClkGpoutCtrlAuxsrc::CLKSRC_GPIN0 => gpin0_freq(), // ClkGpoutCtrlAuxsrc::CLKSRC_GPIN1 => gpin1_freq(), ClkGpoutCtrlAuxsrc::CLKSRC_PLL_USB => pll_usb_freq(), @@ -1555,7 +1575,6 @@ impl<'d, T: GpoutPin> Gpout<'d, T> { ClkGpoutCtrlAuxsrc::CLK_SYS => clk_sys_freq(), ClkGpoutCtrlAuxsrc::CLK_USB => clk_usb_freq(), ClkGpoutCtrlAuxsrc::CLK_ADC => clk_adc_freq(), - //ClkGpoutCtrlAuxsrc::CLK_RTC => clk_rtc_freq() as _, ClkGpoutCtrlAuxsrc::CLK_REF => clk_ref_freq(), _ => unreachable!(), }; @@ -1918,21 +1937,21 @@ mod tests { { // Test automatic voltage scaling based on frequency // Under 133 MHz should use default voltage (V1_10) - let config = ClockConfig::crystal_freq(125_000_000); + let config = ClockConfig::system_freq(125_000_000); assert_eq!(config.core_voltage, CoreVoltage::V1_10); // 133-200 MHz should use V1_15 - let config = ClockConfig::crystal_freq(150_000_000); + let config = ClockConfig::system_freq(150_000_000); assert_eq!(config.core_voltage, CoreVoltage::V1_15); - let config = ClockConfig::crystal_freq(200_000_000); + let config = ClockConfig::system_freq(200_000_000); assert_eq!(config.core_voltage, CoreVoltage::V1_15); // Above 200 MHz should use V1_25 - let config = ClockConfig::crystal_freq(250_000_000); + let config = ClockConfig::system_freq(250_000_000); assert_eq!(config.core_voltage, CoreVoltage::V1_15); // Below 125 MHz should use V1_10 - let config = ClockConfig::crystal_freq(100_000_000); + let config = ClockConfig::system_freq(100_000_000); assert_eq!(config.core_voltage, CoreVoltage::V1_10); } } diff --git a/examples/rp/src/bin/overclock.rs b/examples/rp/src/bin/overclock.rs index f9a8c94d0..9c78e0c9d 100644 --- a/examples/rp/src/bin/overclock.rs +++ b/examples/rp/src/bin/overclock.rs @@ -18,7 +18,7 @@ const COUNT_TO: i64 = 10_000_000; #[embassy_executor::main] async fn main(_spawner: Spawner) -> ! { // Set up for clock frequency of 200 MHz, setting all necessary defaults. - let config = Config::new(ClockConfig::crystal_freq(200_000_000)); + let config = Config::new(ClockConfig::system_freq(200_000_000)); // Show the voltage scale for verification info!("System core voltage: {}", Debug2Format(&config.clocks.core_voltage)); diff --git a/tests/rp/src/bin/overclock.rs b/tests/rp/src/bin/overclock.rs index 6c58a6b90..be8e85a3f 100644 --- a/tests/rp/src/bin/overclock.rs +++ b/tests/rp/src/bin/overclock.rs @@ -31,7 +31,7 @@ async fn main(_spawner: Spawner) { // Initialize with 200MHz clock configuration for RP2040, other chips will use default clock #[cfg(feature = "rp2040")] { - config.clocks = ClockConfig::crystal_freq(200_000_000); + config.clocks = ClockConfig::system_freq(200_000_000); let voltage = config.clocks.core_voltage; assert!(matches!(voltage, CoreVoltage::V1_15), "Expected voltage scale V1_15"); } From 297ff3d03229bedb2582c171be23b488ecc4e520 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 7 May 2025 12:56:58 -0700 Subject: [PATCH 1091/1217] clocks: remove defmt messages Whenever any of the defmt-timestamp-uptime* features is enabled, defmt will insert code that reads the timestamp in order to embed it into the format string. This means that we *must* have a functional time driver by the time the very first defmt message is printed. Because clocks.rs is the part of the code setting up clocks that may, indeed, be required by the chosen clock driver, it cannot contain any defmt messages, otherwise it will trigger a read to a function that does not yet exist. Signed-off-by: Felipe Balbi --- embassy-imxrt/src/clocks.rs | 42 +------------------------------------ 1 file changed, 1 insertion(+), 41 deletions(-) diff --git a/embassy-imxrt/src/clocks.rs b/embassy-imxrt/src/clocks.rs index 5be5f3925..39c3e6238 100644 --- a/embassy-imxrt/src/clocks.rs +++ b/embassy-imxrt/src/clocks.rs @@ -1,8 +1,6 @@ //! Clock configuration for the `RT6xx` use core::sync::atomic::{AtomicU32, AtomicU8, Ordering}; -#[cfg(feature = "defmt")] -use defmt; use paste::paste; use crate::pac; @@ -503,7 +501,6 @@ impl ConfigurableClock for LposcConfig { } } } else { - error!("failed to convert desired clock rate, {:#}, to LPOSC Freq", freq); Err(ClockError::InvalidFrequency) } } @@ -549,7 +546,6 @@ impl ConfigurableClock for FfroConfig { Ok(()) } fn get_clock_rate(&self) -> Result { - trace!("getting ffro clock rate"); Ok(self.freq.load(Ordering::Relaxed)) } fn set_clock_rate(&mut self, _div: u8, _mult: u8, freq: u32) -> Result<(), ClockError> { @@ -616,7 +612,6 @@ impl ConfigurableClock for SfroConfig { fn set_clock_rate(&mut self, _div: u8, _mult: u8, freq: u32) -> Result<(), ClockError> { if self.state == State::Enabled { if freq == SFRO_FREQ { - trace!("Sfro frequency is already set at 16MHz"); Ok(()) } else { Err(ClockError::InvalidFrequency) @@ -677,7 +672,6 @@ impl MultiSourceClock for MainPllClkConfig { } MainPllClkSrc::SFRO => { if !clock_src_config.is_enabled() { - error!("Can't set SFRO as source for MainPll as it's not enabled"); return Err(ClockError::ClockNotEnabled); } // check if desired frequency is a valid multiple of 16m SFRO clock @@ -703,7 +697,6 @@ impl ConfigurableClock for MainPllClkConfig { } fn disable(&self) -> Result<(), ClockError> { if self.is_enabled() { - error!("Attempting to reset the Main Pll Clock, should be resetting its source"); Err(ClockError::ClockNotSupported) } else { Err(ClockError::ClockNotEnabled) @@ -719,7 +712,6 @@ impl ConfigurableClock for MainPllClkConfig { } fn set_clock_rate(&mut self, div: u8, mult: u8, freq: u32) -> Result<(), ClockError> { if self.is_enabled() { - trace!("attempting to set main pll clock rate"); // SAFETY: unsafe needed to take pointers to Sysctl0 and Clkctl0 let clkctl0 = unsafe { crate::pac::Clkctl0::steal() }; let sysctl0 = unsafe { crate::pac::Sysctl0::steal() }; @@ -741,15 +733,12 @@ impl ConfigurableClock for MainPllClkConfig { base_rate = r; } MainPllClkSrc::FFRO => { - trace!("found FFRO as source, wait a bit"); delay_loop_clocks(1000, desired_freq); match clkctl0.ffroctl0().read().trim_range().is_ffro_48mhz() { true => base_rate = Into::into(FfroFreq::Ffro48m), false => base_rate = Into::into(FfroFreq::Ffro60m), } - trace!("found ffro rate to be: {:#}", base_rate); if div == 2 { - trace!("dividing FFRO rate by 2"); clkctl0.syspll0clksel().write(|w| w.sel().ffro_div_2()); delay_loop_clocks(150, desired_freq); base_rate /= 2; @@ -763,10 +752,8 @@ impl ConfigurableClock for MainPllClkConfig { } }; base_rate *= u32::from(mult); - trace!("calculated base rate at: {:#}", base_rate); if base_rate != freq { // make sure to power syspll back up before returning the error - error!("invalid frequency found, powering syspll back up before returning error. Check div and mult"); // Clear System PLL reset clkctl0.syspll0ctl0().write(|w| w.reset().normal()); // Power up SYSPLL @@ -775,13 +762,11 @@ impl ConfigurableClock for MainPllClkConfig { .write(|w| w.syspllana_pd().clr_pdruncfg0().syspllldo_pd().clr_pdruncfg0()); return Err(ClockError::InvalidFrequency); } - trace!("setting default num and denom"); // SAFETY: unsafe needed to write the bits for the num and demon fields clkctl0.syspll0num().write(|w| unsafe { w.num().bits(0b0) }); clkctl0.syspll0denom().write(|w| unsafe { w.denom().bits(0b1) }); delay_loop_clocks(30, desired_freq); self.mult.store(mult, Ordering::Relaxed); - trace!("setting self.mult as: {:#}", mult); match mult { 16 => { clkctl0.syspll0ctl0().modify(|_r, w| w.mult().div_16()); @@ -803,7 +788,6 @@ impl ConfigurableClock for MainPllClkConfig { } _ => return Err(ClockError::InvalidMult), } - trace!("clear syspll reset"); // Clear System PLL reset clkctl0.syspll0ctl0().modify(|_r, w| w.reset().normal()); // Power up SYSPLL @@ -819,7 +803,6 @@ impl ConfigurableClock for MainPllClkConfig { clkctl0.syspll0ctl0().modify(|_, w| w.holdringoff_ena().dsiable()); delay_loop_clocks(15, desired_freq); - trace!("setting new PFD0 bits"); // gate the output and clear bits. // SAFETY: unsafe needed to write the bits for pfd0 clkctl0 @@ -833,7 +816,6 @@ impl ConfigurableClock for MainPllClkConfig { .modify(|_r, w| unsafe { w.pfd0_clkgate().not_gated().pfd0().bits(0x12) }); // wait for ready bit to be set delay_loop_clocks(50, desired_freq); - trace!("waiting for mainpll clock to be ready"); while clkctl0.syspll0pfd().read().pfd0_clkrdy().bit_is_clear() {} // clear by writing a 1 clkctl0.syspll0pfd().modify(|_, w| w.pfd0_clkrdy().set_bit()); @@ -854,11 +836,9 @@ impl ConfigurableClock for MainPllClkConfig { impl MainPllClkConfig { /// Calculate the mult value of a desired frequency, return error if invalid pub(self) fn calc_mult(rate: u32, base_freq: u32) -> Result { - trace!("calculating mult for {:#} / {:#}", rate, base_freq); const VALIDMULTS: [u8; 6] = [16, 17, 20, 22, 27, 33]; if rate > base_freq && rate % base_freq == 0 { let mult = (rate / base_freq) as u8; - trace!("verifying that calculated mult {:#} is a valid one", mult); if VALIDMULTS.into_iter().any(|i| i == mult) { Ok(mult) } else { @@ -1112,7 +1092,6 @@ impl ConfigurableClock for MainClkConfig { Ok(()) } fn disable(&self) -> Result<(), ClockError> { - error!("Attempting to reset the main clock, should NOT happen during runtime"); Err(ClockError::ClockNotSupported) } fn get_clock_rate(&self) -> Result { @@ -1120,7 +1099,6 @@ impl ConfigurableClock for MainClkConfig { Ok(rate) } fn set_clock_rate(&mut self, _div: u8, _mult: u8, _freq: u32) -> Result<(), ClockError> { - error!("The multi-source set_clock_rate_and_source method should be used instead of set_clock_rate"); Err(ClockError::ClockNotSupported) } fn is_enabled(&self) -> bool { @@ -1145,7 +1123,6 @@ impl ConfigurableClock for ClkInConfig { } } fn set_clock_rate(&mut self, _div: u8, _mult: u8, freq: u32) -> Result<(), ClockError> { - trace!("Setting value of clk in config, this won't change the clock itself"); self.freq.as_ref().unwrap().store(freq, Ordering::Relaxed); Ok(()) } @@ -1188,7 +1165,6 @@ impl ConfigurableClock for RtcClkConfig { Ok(()) } fn disable(&self) -> Result<(), ClockError> { - error!("Resetting the RTC clock, this should NOT happen during runtime"); Err(ClockError::ClockNotSupported) } fn set_clock_rate(&mut self, _div: u8, _mult: u8, freq: u32) -> Result<(), ClockError> { @@ -1199,7 +1175,6 @@ impl ConfigurableClock for RtcClkConfig { match r { RtcFreq::Default1Hz => { if rtc.ctrl().read().rtc_en().is_enable() { - trace!("Attempting to enable an already enabled clock, RTC 1Hz"); } else { rtc.ctrl().modify(|_r, w| w.rtc_en().enable()); } @@ -1207,7 +1182,6 @@ impl ConfigurableClock for RtcClkConfig { } RtcFreq::HighResolution1khz => { if rtc.ctrl().read().rtc1khz_en().is_enable() { - trace!("Attempting to enable an already enabled clock, RTC 1Hz"); } else { rtc.ctrl().modify(|_r, w| w.rtc1khz_en().enable()); } @@ -1215,7 +1189,6 @@ impl ConfigurableClock for RtcClkConfig { } RtcFreq::SubSecond32kHz => { if rtc.ctrl().read().rtc_subsec_ena().is_enable() { - trace!("Attempting to enable an already enabled clock, RTC 1Hz"); } else { rtc.ctrl().modify(|_r, w| w.rtc_subsec_ena().enable()); } @@ -1245,18 +1218,12 @@ impl ConfigurableClock for RtcClkConfig { impl SysClkConfig { /// Updates the system core clock frequency, SW concept used for systick - fn update_sys_core_clock(&self) { - trace!( - "System core clock has been updated to {:?}, this involves no HW reg writes", - self.sysclkfreq.load(Ordering::Relaxed) - ); - } + fn update_sys_core_clock(&self) {} } impl ConfigurableClock for SysOscConfig { fn enable_and_reset(&self) -> Result<(), ClockError> { if self.state == State::Enabled { - trace!("SysOsc was already enabled"); return Ok(()); } @@ -1498,32 +1465,26 @@ impl ClockOutConfig { /// Using the config, enables all desired clocks to desired clock rates fn init_clock_hw(config: ClockConfig) -> Result<(), ClockError> { if let Err(e) = config.rtc.enable_and_reset() { - error!("couldn't Power on OSC for RTC, result: {:?}", e); return Err(e); } if let Err(e) = config.lposc.enable_and_reset() { - error!("couldn't Power on LPOSC, result: {:?}", e); return Err(e); } if let Err(e) = config.ffro.enable_and_reset() { - error!("couldn't Power on FFRO, result: {:?}", e); return Err(e); } if let Err(e) = config.sfro.enable_and_reset() { - error!("couldn't Power on SFRO, result: {:?}", e); return Err(e); } if let Err(e) = config.sys_osc.enable_and_reset() { - error!("Couldn't enable sys oscillator {:?}", e); return Err(e); } if let Err(e) = config.main_pll_clk.enable_and_reset() { - error!("Couldn't enable main pll clock {:?}", e); return Err(e); } @@ -1542,7 +1503,6 @@ fn init_clock_hw(config: ClockConfig) -> Result<(), ClockError> { init_syscpuahb_clk(); if let Err(e) = config.main_clk.enable_and_reset() { - error!("Couldn't enable main clock {:?}", e); return Err(e); } From 4621c8aa7a1ee1b55f2f0bf80fc48eddf76af320 Mon Sep 17 00:00:00 2001 From: 1-rafael-1 Date: Wed, 7 May 2025 22:16:29 +0200 Subject: [PATCH 1092/1217] Clarify comment for CoreVoltage enum regarding V1_20 --- embassy-rp/src/clocks.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs index 0c3988aac..6694aab66 100644 --- a/embassy-rp/src/clocks.rs +++ b/embassy-rp/src/clocks.rs @@ -160,7 +160,7 @@ pub enum CoreVoltage { V1_10 = 0b1011, /// 1.15V - Required for overclocking to 133-200MHz V1_15 = 0b1100, - /// 1.20V - Required for overclocking above 200MHz + /// 1.20V V1_20 = 0b1101, /// 1.25V V1_25 = 0b1110, From d46d3119cea14f6cd14c2fae7bf712faff4e6cfe Mon Sep 17 00:00:00 2001 From: Matt Rodgers Date: Wed, 7 May 2025 21:15:54 +0100 Subject: [PATCH 1093/1217] Implement embedded-io-async traits for USB CDC ACM --- embassy-usb-driver/Cargo.toml | 1 + embassy-usb-driver/src/lib.rs | 9 +++ embassy-usb/Cargo.toml | 1 + embassy-usb/src/class/cdc_acm.rs | 99 ++++++++++++++++++++++++++++++++ 4 files changed, 110 insertions(+) diff --git a/embassy-usb-driver/Cargo.toml b/embassy-usb-driver/Cargo.toml index 41493f00d..edb6551b0 100644 --- a/embassy-usb-driver/Cargo.toml +++ b/embassy-usb-driver/Cargo.toml @@ -20,3 +20,4 @@ features = ["defmt"] [dependencies] defmt = { version = "0.3", optional = true } +embedded-io-async = "0.6.1" diff --git a/embassy-usb-driver/src/lib.rs b/embassy-usb-driver/src/lib.rs index 3b705c8c4..d204e4d85 100644 --- a/embassy-usb-driver/src/lib.rs +++ b/embassy-usb-driver/src/lib.rs @@ -395,3 +395,12 @@ pub enum EndpointError { /// The endpoint is disabled. Disabled, } + +impl embedded_io_async::Error for EndpointError { + fn kind(&self) -> embedded_io_async::ErrorKind { + match self { + Self::BufferOverflow => embedded_io_async::ErrorKind::OutOfMemory, + Self::Disabled => embedded_io_async::ErrorKind::NotConnected, + } + } +} diff --git a/embassy-usb/Cargo.toml b/embassy-usb/Cargo.toml index 771190c89..4950fbe2a 100644 --- a/embassy-usb/Cargo.toml +++ b/embassy-usb/Cargo.toml @@ -52,6 +52,7 @@ embassy-sync = { version = "0.6.2", path = "../embassy-sync" } embassy-net-driver-channel = { version = "0.3.0", path = "../embassy-net-driver-channel" } defmt = { version = "0.3", optional = true } +embedded-io-async = "0.6.1" log = { version = "0.4.14", optional = true } heapless = "0.8" diff --git a/embassy-usb/src/class/cdc_acm.rs b/embassy-usb/src/class/cdc_acm.rs index ea9d9fb7b..732a433f8 100644 --- a/embassy-usb/src/class/cdc_acm.rs +++ b/embassy-usb/src/class/cdc_acm.rs @@ -410,6 +410,18 @@ impl<'d, D: Driver<'d>> Sender<'d, D> { } } +impl<'d, D: Driver<'d>> embedded_io_async::ErrorType for Sender<'d, D> { + type Error = EndpointError; +} + +impl<'d, D: Driver<'d>> embedded_io_async::Write for Sender<'d, D> { + async fn write(&mut self, buf: &[u8]) -> Result { + let len = core::cmp::min(buf.len(), self.max_packet_size() as usize); + self.write_packet(&buf[..len]).await?; + Ok(len) + } +} + /// CDC ACM class packet receiver. /// /// You can obtain a `Receiver` with [`CdcAcmClass::split`] @@ -451,6 +463,93 @@ impl<'d, D: Driver<'d>> Receiver<'d, D> { pub async fn wait_connection(&mut self) { self.read_ep.wait_enabled().await; } + + /// Turn the `Receiver` into a [`BufferedReceiver`]. + /// + /// The supplied buffer must be large enough to hold max_packet_size bytes. + pub fn into_buffered(self, buf: &'d mut [u8]) -> BufferedReceiver<'d, D> { + BufferedReceiver { + receiver: self, + buffer: buf, + start: 0, + end: 0, + } + } +} + +/// CDC ACM class buffered receiver. +/// +/// It is a requirement of the [`embedded_io_async::Read`] trait that arbitrarily small lengths of +/// data can be read from the stream. The [`Receiver`] can only read full packets at a time. The +/// `BufferedReceiver` instead buffers a single packet if the caller does not read all of the data, +/// so that the remaining data can be returned in subsequent calls. +/// +/// If you have no requirement to use the [`embedded_io_async::Read`] trait or to read a data length +/// less than the packet length, then it is more efficient to use the [`Receiver`] directly. +/// +/// You can obtain a `BufferedReceiver` with [`Receiver::into_buffered`]. +/// +/// [`embedded_io_async::Read`]: https://docs.rs/embedded-io-async/latest/embedded_io_async/trait.Read.html +pub struct BufferedReceiver<'d, D: Driver<'d>> { + receiver: Receiver<'d, D>, + buffer: &'d mut [u8], + start: usize, + end: usize, +} + +impl<'d, D: Driver<'d>> BufferedReceiver<'d, D> { + fn read_from_buffer(&mut self, buf: &mut [u8]) -> usize { + let available = &self.buffer[self.start..self.end]; + let len = core::cmp::min(available.len(), buf.len()); + buf[..len].copy_from_slice(&self.buffer[..len]); + self.start += len; + len + } + + /// Gets the current line coding. The line coding contains information that's mainly relevant + /// for USB to UART serial port emulators, and can be ignored if not relevant. + pub fn line_coding(&self) -> LineCoding { + self.receiver.line_coding() + } + + /// Gets the DTR (data terminal ready) state + pub fn dtr(&self) -> bool { + self.receiver.dtr() + } + + /// Gets the RTS (request to send) state + pub fn rts(&self) -> bool { + self.receiver.rts() + } + + /// Waits for the USB host to enable this interface + pub async fn wait_connection(&mut self) { + self.receiver.wait_connection().await; + } +} + +impl<'d, D: Driver<'d>> embedded_io_async::ErrorType for BufferedReceiver<'d, D> { + type Error = EndpointError; +} + +impl<'d, D: Driver<'d>> embedded_io_async::Read for BufferedReceiver<'d, D> { + async fn read(&mut self, buf: &mut [u8]) -> Result { + // If there is a buffered packet, return data from that first + if self.start != self.end { + return Ok(self.read_from_buffer(buf)); + } + + // If the caller's buffer is large enough to contain an entire packet, read directly into + // that instead of buffering the packet internally. + if buf.len() > self.receiver.max_packet_size() as usize { + return self.receiver.read_packet(buf).await; + } + + // Otherwise read a packet into the internal buffer, and return some of it to the caller + self.start = 0; + self.end = self.receiver.read_packet(&mut self.buffer).await?; + return Ok(self.read_from_buffer(buf)); + } } /// Number of stop bits for LineCoding From 42c62ba8999df08ad34d566f30f0a7199dbae083 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 7 May 2025 10:40:43 -0700 Subject: [PATCH 1094/1217] Add OS Event timer support Allow for the use of the OS Event timer as a time source. Signed-off-by: Felipe Balbi --- embassy-imxrt/Cargo.toml | 9 +- embassy-imxrt/src/lib.rs | 4 +- embassy-imxrt/src/time_driver.rs | 206 +++++++++++++++++++++++++++---- examples/mimxrt6/Cargo.toml | 4 +- 4 files changed, 189 insertions(+), 34 deletions(-) diff --git a/embassy-imxrt/Cargo.toml b/embassy-imxrt/Cargo.toml index d58de6353..f16002a8d 100644 --- a/embassy-imxrt/Cargo.toml +++ b/embassy-imxrt/Cargo.toml @@ -12,7 +12,7 @@ documentation = "https://docs.embassy.dev/embassy-imxrt" [package.metadata.embassy_docs] src_base = "https://github.com/embassy-rs/embassy/blob/embassy-imxrt-v$VERSION/embassy-imxrt/src/" src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-imxrt/src/" -features = ["defmt", "unstable-pac", "time", "time-driver"] +features = ["defmt", "unstable-pac", "time", "time-driver-os-timer"] flavors = [ { regex_feature = "mimxrt6.*", target = "thumbv8m.main-none-eabihf" } ] @@ -37,9 +37,12 @@ defmt = ["dep:defmt", "embassy-hal-internal/defmt", "embassy-sync/defmt", "mimxr time = ["dep:embassy-time", "embassy-embedded-hal/time"] ## Enable custom embassy time-driver implementation, using 32KHz RTC -time-driver-rtc = ["_time-driver"] +time-driver-rtc = ["_time-driver", "embassy-time-driver?/tick-hz-1_000"] -_time-driver = ["dep:embassy-time-driver", "embassy-time-driver?/tick-hz-1_000", "dep:embassy-time-queue-utils", "embassy-embedded-hal/time"] +## Enable custom embassy time-driver implementation, using 1MHz OS Timer +time-driver-os-timer = ["_time-driver", "embassy-time-driver?/tick-hz-1_000_000"] + +_time-driver = ["dep:embassy-time-driver", "dep:embassy-time-queue-utils", "embassy-embedded-hal/time"] ## Reexport the PAC for the currently enabled chip at `embassy_imxrt::pac` (unstable) unstable-pac = [] diff --git a/embassy-imxrt/src/lib.rs b/embassy-imxrt/src/lib.rs index fdf07b433..ad9f81e88 100644 --- a/embassy-imxrt/src/lib.rs +++ b/embassy-imxrt/src/lib.rs @@ -132,12 +132,10 @@ pub fn init(config: config::Config) -> Peripherals { error!("unable to initialize Clocks for reason: {:?}", e); // Panic here? } - gpio::init(); } - - // init RTC time driver #[cfg(feature = "_time-driver")] time_driver::init(config.time_interrupt_priority); + gpio::init(); peripherals } diff --git a/embassy-imxrt/src/time_driver.rs b/embassy-imxrt/src/time_driver.rs index 56a8f7397..c68679d3e 100644 --- a/embassy-imxrt/src/time_driver.rs +++ b/embassy-imxrt/src/time_driver.rs @@ -1,5 +1,6 @@ -//! RTC Time Driver. +//! Time Driver. use core::cell::{Cell, RefCell}; +#[cfg(feature = "time-driver-rtc")] use core::sync::atomic::{compiler_fence, AtomicU32, Ordering}; use critical_section::CriticalSection; @@ -8,27 +9,11 @@ use embassy_sync::blocking_mutex::Mutex; use embassy_time_driver::Driver; use embassy_time_queue_utils::Queue; +#[cfg(feature = "time-driver-os-timer")] +use crate::clocks::enable; use crate::interrupt::InterruptExt; use crate::{interrupt, pac}; -fn rtc() -> &'static pac::rtc::RegisterBlock { - unsafe { &*pac::Rtc::ptr() } -} - -/// Calculate the timestamp from the period count and the tick count. -/// -/// To get `now()`, `period` is read first, then `counter` is read. If the counter value matches -/// the expected range for the `period` parity, we're done. If it doesn't, this means that -/// a new period start has raced us between reading `period` and `counter`, so we assume the `counter` value -/// corresponds to the next period. -/// -/// the 1kHz RTC counter is 16 bits and RTC doesn't have separate compare channels, -/// so using a 32 bit GPREG0-2 as counter, compare, and int_en -/// `period` is a 32bit integer, gpreg 'counter' is 31 bits plus the parity bit for overflow detection -fn calc_now(period: u32, counter: u32) -> u64 { - ((period as u64) << 31) + ((counter ^ ((period & 1) << 31)) as u64) -} - struct AlarmState { timestamp: Cell, } @@ -43,6 +28,34 @@ impl AlarmState { } } +#[cfg(feature = "time-driver-rtc")] +fn rtc() -> &'static pac::rtc::RegisterBlock { + unsafe { &*pac::Rtc::ptr() } +} + +/// Calculate the timestamp from the period count and the tick count. +/// +/// To get `now()`, `period` is read first, then `counter` is read. If the counter value matches +/// the expected range for the `period` parity, we're done. If it doesn't, this means that +/// a new period start has raced us between reading `period` and `counter`, so we assume the `counter` value +/// corresponds to the next period. +/// +/// the 1kHz RTC counter is 16 bits and RTC doesn't have separate compare channels, +/// so using a 32 bit GPREG0-2 as counter, compare, and int_en +/// `period` is a 32bit integer, gpreg 'counter' is 31 bits plus the parity bit for overflow detection +#[cfg(feature = "time-driver-rtc")] +fn calc_now(period: u32, counter: u32) -> u64 { + ((period as u64) << 31) + ((counter ^ ((period & 1) << 31)) as u64) +} + +#[cfg(feature = "time-driver-rtc")] +embassy_time_driver::time_driver_impl!(static DRIVER: Rtc = Rtc { + period: AtomicU32::new(0), + alarms: Mutex::const_new(CriticalSectionRawMutex::new(), AlarmState::new()), + queue: Mutex::new(RefCell::new(Queue::new())), +}); + +#[cfg(feature = "time-driver-rtc")] struct Rtc { /// Number of 2^31 periods elapsed since boot. period: AtomicU32, @@ -51,12 +64,7 @@ struct Rtc { queue: Mutex>, } -embassy_time_driver::time_driver_impl!(static DRIVER: Rtc = Rtc { - period: AtomicU32::new(0), - alarms: Mutex::const_new(CriticalSectionRawMutex::new(), AlarmState::new()), - queue: Mutex::new(RefCell::new(Queue::new())), -}); - +#[cfg(feature = "time-driver-rtc")] impl Rtc { /// Access the GPREG0 register to use it as a 31-bit counter. #[inline] @@ -219,6 +227,7 @@ impl Rtc { } } +#[cfg(feature = "time-driver-rtc")] impl Driver for Rtc { fn now(&self) -> u64 { // `period` MUST be read before `counter`, see comment at the top for details. @@ -242,13 +251,158 @@ impl Driver for Rtc { } } -#[cfg(feature = "rt")] +#[cfg(all(feature = "rt", feature = "time-driver-rtc"))] #[allow(non_snake_case)] #[interrupt] fn RTC() { DRIVER.on_interrupt() } +#[cfg(feature = "time-driver-os-timer")] +fn os() -> &'static pac::ostimer0::RegisterBlock { + unsafe { &*pac::Ostimer0::ptr() } +} + +/// Convert gray to decimal +/// +/// Os Event provides a 64-bit timestamp gray-encoded. All we have to +/// do here is read both 32-bit halves of the register and convert +/// from gray to regular binary. +#[cfg(feature = "time-driver-os-timer")] +fn gray_to_dec(gray: u64) -> u64 { + let mut dec = gray; + + dec ^= dec >> 1; + dec ^= dec >> 2; + dec ^= dec >> 4; + dec ^= dec >> 8; + dec ^= dec >> 16; + dec ^= dec >> 32; + + dec +} + +/// Convert decimal to gray +/// +/// Before writing match value to the target register, we must convert +/// it back into gray code. +#[cfg(feature = "time-driver-os-timer")] +fn dec_to_gray(dec: u64) -> u64 { + let gray = dec; + gray ^ (gray >> 1) +} + +#[cfg(feature = "time-driver-os-timer")] +embassy_time_driver::time_driver_impl!(static DRIVER: OsTimer = OsTimer { + alarms: Mutex::const_new(CriticalSectionRawMutex::new(), AlarmState::new()), + queue: Mutex::new(RefCell::new(Queue::new())), +}); + +#[cfg(feature = "time-driver-os-timer")] +struct OsTimer { + /// Timestamp at which to fire alarm. u64::MAX if no alarm is scheduled. + alarms: Mutex, + queue: Mutex>, +} + +#[cfg(feature = "time-driver-os-timer")] +impl OsTimer { + fn init(&'static self, irq_prio: crate::interrupt::Priority) { + // init alarms + critical_section::with(|cs| { + let alarm = DRIVER.alarms.borrow(cs); + alarm.timestamp.set(u64::MAX); + }); + + // Enable clocks. Documentation advises AGAINST resetting this + // peripheral. + enable::(); + + interrupt::OS_EVENT.disable(); + + // Make sure interrupt is masked + os().osevent_ctrl().modify(|_, w| w.ostimer_intena().clear_bit()); + + // Default to the end of time + os().match_l().write(|w| unsafe { w.bits(0xffff_ffff) }); + os().match_h().write(|w| unsafe { w.bits(0xffff_ffff) }); + + interrupt::OS_EVENT.unpend(); + interrupt::OS_EVENT.set_priority(irq_prio); + unsafe { interrupt::OS_EVENT.enable() }; + } + + fn set_alarm(&self, cs: CriticalSection, timestamp: u64) -> bool { + let alarm = self.alarms.borrow(cs); + alarm.timestamp.set(timestamp); + + let t = self.now(); + if timestamp <= t { + os().osevent_ctrl().modify(|_, w| w.ostimer_intena().clear_bit()); + alarm.timestamp.set(u64::MAX); + return false; + } + + let gray_timestamp = dec_to_gray(timestamp); + + os().match_l() + .write(|w| unsafe { w.bits(gray_timestamp as u32 & 0xffff_ffff) }); + os().match_h() + .write(|w| unsafe { w.bits((gray_timestamp >> 32) as u32) }); + os().osevent_ctrl().modify(|_, w| w.ostimer_intena().set_bit()); + + true + } + + #[cfg(feature = "rt")] + fn trigger_alarm(&self, cs: CriticalSection) { + let mut next = self.queue.borrow(cs).borrow_mut().next_expiration(self.now()); + while !self.set_alarm(cs, next) { + next = self.queue.borrow(cs).borrow_mut().next_expiration(self.now()); + } + } + + #[cfg(feature = "rt")] + fn on_interrupt(&self) { + critical_section::with(|cs| { + if os().osevent_ctrl().read().ostimer_intrflag().bit_is_set() { + os().osevent_ctrl().modify(|_, w| w.ostimer_intena().clear_bit()); + self.trigger_alarm(cs); + } + }); + } +} + +#[cfg(feature = "time-driver-os-timer")] +impl Driver for OsTimer { + fn now(&self) -> u64 { + let mut t = os().evtimerh().read().bits() as u64; + t <<= 32; + t |= os().evtimerl().read().bits() as u64; + gray_to_dec(t) + } + + fn schedule_wake(&self, at: u64, waker: &core::task::Waker) { + critical_section::with(|cs| { + let mut queue = self.queue.borrow(cs).borrow_mut(); + + if queue.schedule_wake(at, waker) { + let mut next = queue.next_expiration(self.now()); + while !self.set_alarm(cs, next) { + next = queue.next_expiration(self.now()); + } + } + }) + } +} + +#[cfg(all(feature = "rt", feature = "time-driver-os-timer"))] +#[allow(non_snake_case)] +#[interrupt] +fn OS_EVENT() { + DRIVER.on_interrupt() +} + pub(crate) fn init(irq_prio: crate::interrupt::Priority) { DRIVER.init(irq_prio) } diff --git a/examples/mimxrt6/Cargo.toml b/examples/mimxrt6/Cargo.toml index 8fc510c47..b0c56f003 100644 --- a/examples/mimxrt6/Cargo.toml +++ b/examples/mimxrt6/Cargo.toml @@ -12,8 +12,8 @@ defmt-rtt = "1.0" embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-futures = { version = "0.1.1", path = "../../embassy-futures" } -embassy-imxrt = { version = "0.1.0", path = "../../embassy-imxrt", features = ["defmt", "mimxrt685s", "unstable-pac", "time", "time-driver-rtc"] } -embassy-time = { version = "0.4", path = "../../embassy-time" } +embassy-imxrt = { version = "0.1.0", path = "../../embassy-imxrt", features = ["defmt", "mimxrt685s", "unstable-pac", "time", "time-driver-os-timer"] } +embassy-time = { version = "0.4", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } embedded-hal-1 = { package = "embedded-hal", version = "1.0" } embedded-hal-async = "1.0.0" From d35df5cfbadb0142d4c8fd44b5dcbfa81ab7ac15 Mon Sep 17 00:00:00 2001 From: Matthew Tran <0e4ef622@gmail.com> Date: Thu, 8 May 2025 00:09:21 -0500 Subject: [PATCH 1095/1217] embassy-usb-dfu: Change return of reset to () Also adds &self to the Reset trait, which makes it easier to implement cleanup/delays before actually resetting. --- embassy-usb-dfu/src/application.rs | 10 ++++------ embassy-usb-dfu/src/dfu.rs | 14 ++++++-------- embassy-usb-dfu/src/lib.rs | 8 ++++---- examples/boot/application/stm32wb-dfu/src/main.rs | 4 ++-- examples/boot/bootloader/stm32wb-dfu/src/main.rs | 4 ++-- 5 files changed, 18 insertions(+), 22 deletions(-) diff --git a/embassy-usb-dfu/src/application.rs b/embassy-usb-dfu/src/application.rs index e93c241ad..3c1e8b2cc 100644 --- a/embassy-usb-dfu/src/application.rs +++ b/embassy-usb-dfu/src/application.rs @@ -1,5 +1,3 @@ -use core::marker::PhantomData; - use embassy_boot::BlockingFirmwareState; use embassy_time::{Duration, Instant}; use embassy_usb::control::{InResponse, OutResponse, Recipient, RequestType}; @@ -36,19 +34,19 @@ pub struct Control { state: State, timeout: Option, detach_start: Option, - _rst: PhantomData, + reset: RST, } impl Control { /// Create a new DFU instance to expose a DFU interface. - pub fn new(dfu_marker: MARK, attrs: DfuAttributes) -> Self { + pub fn new(dfu_marker: MARK, attrs: DfuAttributes, reset: RST) -> Self { Control { dfu_marker, attrs, state: State::AppIdle, detach_start: None, timeout: None, - _rst: PhantomData, + reset, } } } @@ -65,7 +63,7 @@ impl Handler for Control { ); if delta < timeout { self.dfu_marker.mark_dfu(); - RST::sys_reset() + self.reset.sys_reset() } } } diff --git a/embassy-usb-dfu/src/dfu.rs b/embassy-usb-dfu/src/dfu.rs index c23286cf5..a98d6ab40 100644 --- a/embassy-usb-dfu/src/dfu.rs +++ b/embassy-usb-dfu/src/dfu.rs @@ -1,5 +1,3 @@ -use core::marker::PhantomData; - use embassy_boot::{AlignedBuffer, BlockingFirmwareUpdater, FirmwareUpdaterError}; use embassy_usb::control::{InResponse, OutResponse, Recipient, RequestType}; use embassy_usb::driver::Driver; @@ -20,12 +18,12 @@ pub struct Control<'d, DFU: NorFlash, STATE: NorFlash, RST: Reset, const BLOCK_S status: Status, offset: usize, buf: AlignedBuffer, - _rst: PhantomData, + reset: RST, } impl<'d, DFU: NorFlash, STATE: NorFlash, RST: Reset, const BLOCK_SIZE: usize> Control<'d, DFU, STATE, RST, BLOCK_SIZE> { /// Create a new DFU instance to handle DFU transfers. - pub fn new(updater: BlockingFirmwareUpdater<'d, DFU, STATE>, attrs: DfuAttributes) -> Self { + pub fn new(updater: BlockingFirmwareUpdater<'d, DFU, STATE>, attrs: DfuAttributes, reset: RST) -> Self { Self { updater, attrs, @@ -33,7 +31,7 @@ impl<'d, DFU: NorFlash, STATE: NorFlash, RST: Reset, const BLOCK_SIZE: usize> Co status: Status::Ok, offset: 0, buf: AlignedBuffer([0; BLOCK_SIZE]), - _rst: PhantomData, + reset, } } @@ -155,14 +153,14 @@ impl<'d, DFU: NorFlash, STATE: NorFlash, RST: Reset, const BLOCK_SIZE: usize> Ha } match Request::try_from(req.request) { Ok(Request::GetStatus) => { - //TODO: Configurable poll timeout, ability to add string for Vendor error - buf[0..6].copy_from_slice(&[self.status as u8, 0x32, 0x00, 0x00, self.state as u8, 0x00]); match self.state { State::DlSync => self.state = State::Download, - State::ManifestSync => RST::sys_reset(), + State::ManifestSync => self.reset.sys_reset(), _ => {} } + //TODO: Configurable poll timeout, ability to add string for Vendor error + buf[0..6].copy_from_slice(&[self.status as u8, 0x32, 0x00, 0x00, self.state as u8, 0x00]); Some(InResponse::Accepted(&buf[0..6])) } Ok(Request::GetState) => { diff --git a/embassy-usb-dfu/src/lib.rs b/embassy-usb-dfu/src/lib.rs index eaa4b6e33..54ffa7276 100644 --- a/embassy-usb-dfu/src/lib.rs +++ b/embassy-usb-dfu/src/lib.rs @@ -26,10 +26,10 @@ compile_error!("usb-dfu must be compiled with exactly one of `dfu`, or `applicat /// This crate exposes `ResetImmediate` when compiled with cortex-m or esp32c3 support, which immediately issues a /// reset request without interfacing with any other peripherals. /// -/// If alternate behaviour is desired, a custom implementation of Reset can be provided as a type argument to the usb_dfu function. +/// If alternate behaviour is desired, a custom implementation of Reset can be provided as an argument to the usb_dfu function. pub trait Reset { /// Reset the device. - fn sys_reset() -> !; + fn sys_reset(&self); } /// Reset immediately. @@ -38,7 +38,7 @@ pub struct ResetImmediate; #[cfg(feature = "esp32c3-hal")] impl Reset for ResetImmediate { - fn sys_reset() -> ! { + fn sys_reset(&self) { esp32c3_hal::reset::software_reset(); loop {} } @@ -50,7 +50,7 @@ pub struct ResetImmediate; #[cfg(feature = "cortex-m")] impl Reset for ResetImmediate { - fn sys_reset() -> ! { + fn sys_reset(&self) { cortex_m::peripheral::SCB::sys_reset() } } diff --git a/examples/boot/application/stm32wb-dfu/src/main.rs b/examples/boot/application/stm32wb-dfu/src/main.rs index 0ab99ff90..dda2b795b 100644 --- a/examples/boot/application/stm32wb-dfu/src/main.rs +++ b/examples/boot/application/stm32wb-dfu/src/main.rs @@ -44,7 +44,7 @@ async fn main(_spawner: Spawner) { let mut config_descriptor = [0; 256]; let mut bos_descriptor = [0; 256]; let mut control_buf = [0; 64]; - let mut state = Control::new(firmware_state, DfuAttributes::CAN_DOWNLOAD); + let mut state = Control::new(firmware_state, DfuAttributes::CAN_DOWNLOAD, ResetImmediate); let mut builder = Builder::new( driver, config, @@ -54,7 +54,7 @@ async fn main(_spawner: Spawner) { &mut control_buf, ); - usb_dfu::<_, _, ResetImmediate>(&mut builder, &mut state, Duration::from_millis(2500)); + usb_dfu(&mut builder, &mut state, Duration::from_millis(2500)); let mut dev = builder.build(); dev.run().await diff --git a/examples/boot/bootloader/stm32wb-dfu/src/main.rs b/examples/boot/bootloader/stm32wb-dfu/src/main.rs index b09d53cf0..28216806e 100644 --- a/examples/boot/bootloader/stm32wb-dfu/src/main.rs +++ b/examples/boot/bootloader/stm32wb-dfu/src/main.rs @@ -55,7 +55,7 @@ fn main() -> ! { let mut config_descriptor = [0; 256]; let mut bos_descriptor = [0; 256]; let mut control_buf = [0; 4096]; - let mut state = Control::new(updater, DfuAttributes::CAN_DOWNLOAD); + let mut state = Control::new(updater, DfuAttributes::CAN_DOWNLOAD, ResetImmediate); let mut builder = Builder::new( driver, config, @@ -77,7 +77,7 @@ fn main() -> ! { msos::PropertyData::RegMultiSz(DEVICE_INTERFACE_GUIDS), )); - usb_dfu::<_, _, _, ResetImmediate, 4096>(&mut builder, &mut state); + usb_dfu::<_, _, _, _, 4096>(&mut builder, &mut state); let mut dev = builder.build(); embassy_futures::block_on(dev.run()); From 5c0a63a0ddbc8c8afc97dc2857c2d78093c48768 Mon Sep 17 00:00:00 2001 From: Matthew Tran <0e4ef622@gmail.com> Date: Thu, 8 May 2025 00:12:00 -0500 Subject: [PATCH 1096/1217] embassy-usb-dfu: Reset immediately if WILL_DETACH is set This is necessary to support the windows WinUSB driver which is not capable of generating the USB reset. --- embassy-usb-dfu/src/application.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/embassy-usb-dfu/src/application.rs b/embassy-usb-dfu/src/application.rs index 3c1e8b2cc..6ad07a78c 100644 --- a/embassy-usb-dfu/src/application.rs +++ b/embassy-usb-dfu/src/application.rs @@ -81,10 +81,15 @@ impl Handler for Control { match Request::try_from(req.request) { Ok(Request::Detach) => { - trace!("Received DETACH, awaiting USB reset"); self.detach_start = Some(Instant::now()); self.timeout = Some(Duration::from_millis(req.value as u64)); self.state = State::AppDetach; + if self.attrs.contains(DfuAttributes::WILL_DETACH) { + trace!("Received DETACH, performing reset"); + self.reset(); + } else { + trace!("Received DETACH, awaiting USB reset"); + } Some(OutResponse::Accepted) } _ => None, From 65bd86f19f8b2338c4593f35ac8e44a677a2b801 Mon Sep 17 00:00:00 2001 From: Dion Dokter Date: Thu, 8 May 2025 13:40:21 +0200 Subject: [PATCH 1097/1217] Stm32: Fix opamp copy pasta mistake --- embassy-stm32/src/opamp.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/src/opamp.rs b/embassy-stm32/src/opamp.rs index b368df6c3..2eb2e61c1 100644 --- a/embassy-stm32/src/opamp.rs +++ b/embassy-stm32/src/opamp.rs @@ -239,7 +239,7 @@ impl<'d, T: Instance> OpAmp<'d, T> { T::regs().csr().modify(|w| { w.set_vp_sel(VpSel::from_bits(pin.channel())); - w.set_vm_sel(VmSel::OUTPUT); + w.set_vm_sel(VmSel::PGA); w.set_pga_gain(pga_gain); w.set_opaintoen(true); w.set_opampen(true); From b3e13cc6de744a241521cff20725706a1e40ef25 Mon Sep 17 00:00:00 2001 From: Kat Perez Date: Thu, 8 May 2025 10:58:07 -0400 Subject: [PATCH 1098/1217] make tracing API functions internal --- embassy-executor/src/raw/trace.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-executor/src/raw/trace.rs b/embassy-executor/src/raw/trace.rs index c0599d2c7..503d806bd 100644 --- a/embassy-executor/src/raw/trace.rs +++ b/embassy-executor/src/raw/trace.rs @@ -239,7 +239,7 @@ pub(crate) fn executor_idle(executor: &SyncExecutor) { /// # Returns /// An iterator that yields `TaskRef` items for each task #[cfg(feature = "trace")] -pub fn get_all_active_tasks() -> impl Iterator + 'static { +fn get_all_active_tasks() -> impl Iterator + 'static { struct TaskIterator<'a> { tracker: &'a TaskTracker, current: *mut TaskHeader, @@ -285,7 +285,7 @@ pub fn count_active_tasks() -> usize { /// Perform an action on each active task #[cfg(feature = "trace")] -pub fn with_all_active_tasks(f: F) +fn with_all_active_tasks(f: F) where F: FnMut(TaskRef), { From 8f18810ec61ce235a4c895413936e0216ed22c4f Mon Sep 17 00:00:00 2001 From: Kat Perez Date: Thu, 8 May 2025 10:58:27 -0400 Subject: [PATCH 1099/1217] remove unused tracing API --- embassy-executor/src/raw/trace.rs | 29 ----------------------------- 1 file changed, 29 deletions(-) diff --git a/embassy-executor/src/raw/trace.rs b/embassy-executor/src/raw/trace.rs index 503d806bd..fec3a4834 100644 --- a/embassy-executor/src/raw/trace.rs +++ b/embassy-executor/src/raw/trace.rs @@ -266,23 +266,6 @@ fn get_all_active_tasks() -> impl Iterator + 'static { } } -/// Get all active tasks, filtered by a predicate function -#[cfg(feature = "trace")] -pub fn filter_active_tasks(predicate: F) -> impl Iterator + 'static -where - F: Fn(&TaskRef) -> bool + 'static, -{ - get_all_active_tasks().filter(move |task| predicate(task)) -} - -/// Count the number of active tasks -#[cfg(feature = "trace")] -pub fn count_active_tasks() -> usize { - let mut count = 0; - TASK_TRACKER.for_each(|_| count += 1); - count -} - /// Perform an action on each active task #[cfg(feature = "trace")] fn with_all_active_tasks(f: F) @@ -292,18 +275,6 @@ where TASK_TRACKER.for_each(f); } -/// Get tasks by name -#[cfg(feature = "trace")] -pub fn get_tasks_by_name(name: &'static str) -> impl Iterator + 'static { - filter_active_tasks(move |task| task.name() == Some(name)) -} - -/// Get tasks by ID -#[cfg(feature = "trace")] -pub fn get_task_by_id(id: u32) -> Option { - filter_active_tasks(move |task| task.id() == id).next() -} - #[cfg(feature = "rtos-trace")] impl rtos_trace::RtosTraceOSCallbacks for crate::raw::SyncExecutor { fn task_list() { From 56b5e35c60743d65aacee753d1db391c3cbeae16 Mon Sep 17 00:00:00 2001 From: Kat Perez Date: Thu, 8 May 2025 10:58:59 -0400 Subject: [PATCH 1100/1217] change rtos-trace feature flag on tracing API to trace feature flag --- embassy-executor/src/spawner.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-executor/src/spawner.rs b/embassy-executor/src/spawner.rs index 5e42f01bf..a0d246616 100644 --- a/embassy-executor/src/spawner.rs +++ b/embassy-executor/src/spawner.rs @@ -162,7 +162,7 @@ impl Spawner { /// /// # Returns /// Result indicating whether the spawn was successful - #[cfg(feature = "rtos-trace")] + #[cfg(feature = "trace")] pub fn spawn_named(&self, name: &'static str, token: SpawnToken) -> Result<(), SpawnError> { let task = token.raw_task; mem::forget(token); @@ -182,7 +182,7 @@ impl Spawner { /// When rtos-trace is disabled, spawn_named falls back to regular spawn. /// This maintains API compatibility while optimizing out the name parameter. - #[cfg(not(feature = "rtos-trace"))] + #[cfg(not(feature = "trace"))] pub fn spawn_named(&self, _name: &'static str, token: SpawnToken) -> Result<(), SpawnError> { self.spawn(token) } From 8a8deb704fdd58cecf463f033cd3c3d1cc3534c7 Mon Sep 17 00:00:00 2001 From: Kat Perez Date: Thu, 8 May 2025 11:20:22 -0400 Subject: [PATCH 1101/1217] move spawn_named into trace.rs through TraceExt trait --- embassy-executor/src/raw/trace.rs | 43 +++++++++++++++++++++++++++++++ embassy-executor/src/spawner.rs | 37 ++------------------------ 2 files changed, 45 insertions(+), 35 deletions(-) diff --git a/embassy-executor/src/raw/trace.rs b/embassy-executor/src/raw/trace.rs index fec3a4834..eb960f721 100644 --- a/embassy-executor/src/raw/trace.rs +++ b/embassy-executor/src/raw/trace.rs @@ -87,6 +87,49 @@ use core::sync::atomic::{AtomicUsize, Ordering}; use rtos_trace::TaskInfo; use crate::raw::{SyncExecutor, TaskHeader, TaskRef, TaskTracker}; +use crate::spawner::{SpawnError, SpawnToken, Spawner}; + +/// Extension trait adding tracing capabilities to the Spawner +pub trait TraceExt { + /// Spawns a new task with a specified name. + /// + /// # Arguments + /// * `name` - Static string name to associate with the task + /// * `token` - Token representing the task to spawn + /// + /// # Returns + /// Result indicating whether the spawn was successful + fn spawn_named(&self, name: &'static str, token: SpawnToken) -> Result<(), SpawnError>; +} + +#[cfg(feature = "trace")] +impl TraceExt for Spawner { + fn spawn_named(&self, name: &'static str, token: SpawnToken) -> Result<(), SpawnError> { + let task = token.raw_task; + core::mem::forget(token); + + match task { + Some(task) => { + task.set_name(Some(name)); + let task_id = task.as_ptr() as u32; + task.set_id(task_id); + + unsafe { self.executor.spawn(task) }; + Ok(()) + } + None => Err(SpawnError::Busy), + } + } +} + +/// When trace is disabled, spawn_named falls back to regular spawn. +/// This maintains API compatibility while optimizing out the name parameter. +#[cfg(not(feature = "trace"))] +impl TraceExt for Spawner { + fn spawn_named(&self, _name: &'static str, token: SpawnToken) -> Result<(), SpawnError> { + self.spawn(token) + } +} /// Global task tracker instance /// diff --git a/embassy-executor/src/spawner.rs b/embassy-executor/src/spawner.rs index a0d246616..6b8db4f8f 100644 --- a/embassy-executor/src/spawner.rs +++ b/embassy-executor/src/spawner.rs @@ -22,7 +22,7 @@ use super::raw; /// Once you've invoked a task function and obtained a SpawnToken, you *must* spawn it. #[must_use = "Calling a task function does nothing on its own. You must spawn the returned SpawnToken, typically with Spawner::spawn()"] pub struct SpawnToken { - raw_task: Option, + pub(crate) raw_task: Option, phantom: PhantomData<*mut S>, } @@ -103,7 +103,7 @@ impl core::error::Error for SpawnError {} /// If you want to spawn tasks from another thread, use [SendSpawner]. #[derive(Copy, Clone)] pub struct Spawner { - executor: &'static raw::Executor, + pub(crate) executor: &'static raw::Executor, not_send: PhantomData<*mut ()>, } @@ -154,39 +154,6 @@ impl Spawner { } } - /// Spawns a new task with a specified name. - /// - /// # Arguments - /// * `name` - Static string name to associate with the task - /// * `token` - Token representing the task to spawn - /// - /// # Returns - /// Result indicating whether the spawn was successful - #[cfg(feature = "trace")] - pub fn spawn_named(&self, name: &'static str, token: SpawnToken) -> Result<(), SpawnError> { - let task = token.raw_task; - mem::forget(token); - - match task { - Some(task) => { - task.set_name(Some(name)); - let task_id = task.as_ptr() as u32; - task.set_id(task_id); - - unsafe { self.executor.spawn(task) }; - Ok(()) - } - None => Err(SpawnError::Busy), - } - } - - /// When rtos-trace is disabled, spawn_named falls back to regular spawn. - /// This maintains API compatibility while optimizing out the name parameter. - #[cfg(not(feature = "trace"))] - pub fn spawn_named(&self, _name: &'static str, token: SpawnToken) -> Result<(), SpawnError> { - self.spawn(token) - } - // Used by the `embassy_executor_macros::main!` macro to throw an error when spawn // fails. This is here to allow conditional use of `defmt::unwrap!` // without introducing a `defmt` feature in the `embassy_executor_macros` package, From 462d04c6d5a0fc6072cf9bdb0faa60da74ff46d2 Mon Sep 17 00:00:00 2001 From: Kat Perez Date: Thu, 8 May 2025 13:34:32 -0400 Subject: [PATCH 1102/1217] move TaskTracker to trace --- embassy-executor/src/raw/mod.rs | 70 ----------------------------- embassy-executor/src/raw/trace.rs | 74 ++++++++++++++++++++++++++++++- 2 files changed, 72 insertions(+), 72 deletions(-) diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs index b4adfe01b..882e4605b 100644 --- a/embassy-executor/src/raw/mod.rs +++ b/embassy-executor/src/raw/mod.rs @@ -97,76 +97,6 @@ pub(crate) struct TaskHeader { all_tasks_next: AtomicPtr, } -/// A thread-safe tracker for all tasks in the system -/// -/// This struct uses an intrusive linked list approach to track all tasks -/// without additional memory allocations. It maintains a global list of -/// tasks that can be traversed to find all currently existing tasks. -#[cfg(feature = "trace")] -pub struct TaskTracker { - head: AtomicPtr, -} - -#[cfg(feature = "trace")] -impl TaskTracker { - /// Creates a new empty task tracker - /// - /// Initializes a tracker with no tasks in its list. - pub const fn new() -> Self { - Self { - head: AtomicPtr::new(core::ptr::null_mut()), - } - } - - /// Adds a task to the tracker - /// - /// This method inserts a task at the head of the intrusive linked list. - /// The operation is thread-safe and lock-free, using atomic operations - /// to ensure consistency even when called from different contexts. - /// - /// # Arguments - /// * `task` - The task reference to add to the tracker - pub fn add(&self, task: TaskRef) { - let task_ptr = task.as_ptr() as *mut TaskHeader; - - loop { - let current_head = self.head.load(Ordering::Acquire); - unsafe { - (*task_ptr).all_tasks_next.store(current_head, Ordering::Relaxed); - } - - if self - .head - .compare_exchange(current_head, task_ptr, Ordering::Release, Ordering::Relaxed) - .is_ok() - { - break; - } - } - } - - /// Performs an operation on each task in the tracker - /// - /// This method traverses the entire list of tasks and calls the provided - /// function for each task. This allows inspecting or processing all tasks - /// in the system without modifying the tracker's structure. - /// - /// # Arguments - /// * `f` - A function to call for each task in the tracker - pub fn for_each(&self, mut f: F) - where - F: FnMut(TaskRef), - { - let mut current = self.head.load(Ordering::Acquire); - while !current.is_null() { - let task = unsafe { TaskRef::from_ptr(current) }; - f(task); - - current = unsafe { (*current).all_tasks_next.load(Ordering::Acquire) }; - } - } -} - /// This is essentially a `&'static TaskStorage` where the type of the future has been erased. #[derive(Clone, Copy, PartialEq)] pub struct TaskRef { diff --git a/embassy-executor/src/raw/trace.rs b/embassy-executor/src/raw/trace.rs index eb960f721..b59da0526 100644 --- a/embassy-executor/src/raw/trace.rs +++ b/embassy-executor/src/raw/trace.rs @@ -82,11 +82,11 @@ #![allow(unused)] use core::cell::UnsafeCell; -use core::sync::atomic::{AtomicUsize, Ordering}; +use core::sync::atomic::{AtomicPtr, AtomicUsize, Ordering}; use rtos_trace::TaskInfo; -use crate::raw::{SyncExecutor, TaskHeader, TaskRef, TaskTracker}; +use crate::raw::{SyncExecutor, TaskHeader, TaskRef}; use crate::spawner::{SpawnError, SpawnToken, Spawner}; /// Extension trait adding tracing capabilities to the Spawner @@ -139,6 +139,76 @@ impl TraceExt for Spawner { #[cfg(feature = "trace")] pub static TASK_TRACKER: TaskTracker = TaskTracker::new(); +/// A thread-safe tracker for all tasks in the system +/// +/// This struct uses an intrusive linked list approach to track all tasks +/// without additional memory allocations. It maintains a global list of +/// tasks that can be traversed to find all currently existing tasks. +#[cfg(feature = "trace")] +pub struct TaskTracker { + head: AtomicPtr, +} + +#[cfg(feature = "trace")] +impl TaskTracker { + /// Creates a new empty task tracker + /// + /// Initializes a tracker with no tasks in its list. + pub const fn new() -> Self { + Self { + head: AtomicPtr::new(core::ptr::null_mut()), + } + } + + /// Adds a task to the tracker + /// + /// This method inserts a task at the head of the intrusive linked list. + /// The operation is thread-safe and lock-free, using atomic operations + /// to ensure consistency even when called from different contexts. + /// + /// # Arguments + /// * `task` - The task reference to add to the tracker + pub fn add(&self, task: TaskRef) { + let task_ptr = task.as_ptr() as *mut TaskHeader; + + loop { + let current_head = self.head.load(Ordering::Acquire); + unsafe { + (*task_ptr).all_tasks_next.store(current_head, Ordering::Relaxed); + } + + if self + .head + .compare_exchange(current_head, task_ptr, Ordering::Release, Ordering::Relaxed) + .is_ok() + { + break; + } + } + } + + /// Performs an operation on each task in the tracker + /// + /// This method traverses the entire list of tasks and calls the provided + /// function for each task. This allows inspecting or processing all tasks + /// in the system without modifying the tracker's structure. + /// + /// # Arguments + /// * `f` - A function to call for each task in the tracker + pub fn for_each(&self, mut f: F) + where + F: FnMut(TaskRef), + { + let mut current = self.head.load(Ordering::Acquire); + while !current.is_null() { + let task = unsafe { TaskRef::from_ptr(current) }; + f(task); + + current = unsafe { (*current).all_tasks_next.load(Ordering::Acquire) }; + } + } +} + #[cfg(not(feature = "rtos-trace"))] extern "Rust" { /// This callback is called when the executor begins polling. This will always From 3b873bb6bb51b9bdac9272b5ec629a6ac54a89f7 Mon Sep 17 00:00:00 2001 From: Kat Perez Date: Thu, 8 May 2025 13:40:32 -0400 Subject: [PATCH 1103/1217] implement TaskRefTrace for tracing-only fields in TaskRef --- embassy-executor/src/raw/mod.rs | 36 --------------------- embassy-executor/src/raw/trace.rs | 52 +++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 36 deletions(-) diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs index 882e4605b..e7a27035a 100644 --- a/embassy-executor/src/raw/mod.rs +++ b/embassy-executor/src/raw/mod.rs @@ -149,42 +149,6 @@ impl TaskRef { pub(crate) fn as_ptr(self) -> *const TaskHeader { self.ptr.as_ptr() } - - /// Get the ID for a task - #[cfg(feature = "trace")] - pub fn as_id(self) -> u32 { - self.ptr.as_ptr() as u32 - } - - /// Get the name for a task - #[cfg(feature = "trace")] - pub fn name(&self) -> Option<&'static str> { - self.header().name - } - - /// Set the name for a task - #[cfg(feature = "trace")] - pub fn set_name(&self, name: Option<&'static str>) { - unsafe { - let header_ptr = self.ptr.as_ptr() as *mut TaskHeader; - (*header_ptr).name = name; - } - } - - /// Get the ID for a task - #[cfg(feature = "trace")] - pub fn id(&self) -> u32 { - self.header().id - } - - /// Set the ID for a task - #[cfg(feature = "trace")] - pub fn set_id(&self, id: u32) { - unsafe { - let header_ptr = self.ptr.as_ptr() as *mut TaskHeader; - (*header_ptr).id = id; - } - } } /// Raw storage in which a task can be spawned. diff --git a/embassy-executor/src/raw/trace.rs b/embassy-executor/src/raw/trace.rs index b59da0526..b30f23468 100644 --- a/embassy-executor/src/raw/trace.rs +++ b/embassy-executor/src/raw/trace.rs @@ -209,6 +209,58 @@ impl TaskTracker { } } +/// Extension trait for `TaskRef` that provides tracing functionality. +/// +/// This trait is only available when the `trace` feature is enabled. +/// It extends `TaskRef` with methods for accessing and modifying task identifiers +/// and names, which are useful for debugging, logging, and performance analysis. +#[cfg(feature = "trace")] +pub trait TaskRefTrace { + /// Get the ID for a task + fn as_id(self) -> u32; + + /// Get the name for a task + fn name(&self) -> Option<&'static str>; + + /// Set the name for a task + fn set_name(&self, name: Option<&'static str>); + + /// Get the ID for a task + fn id(&self) -> u32; + + /// Set the ID for a task + fn set_id(&self, id: u32); +} + +#[cfg(feature = "trace")] +impl TaskRefTrace for TaskRef { + fn as_id(self) -> u32 { + self.ptr.as_ptr() as u32 + } + + fn name(&self) -> Option<&'static str> { + self.header().name + } + + fn set_name(&self, name: Option<&'static str>) { + unsafe { + let header_ptr = self.ptr.as_ptr() as *mut TaskHeader; + (*header_ptr).name = name; + } + } + + fn id(&self) -> u32 { + self.header().id + } + + fn set_id(&self, id: u32) { + unsafe { + let header_ptr = self.ptr.as_ptr() as *mut TaskHeader; + (*header_ptr).id = id; + } + } +} + #[cfg(not(feature = "rtos-trace"))] extern "Rust" { /// This callback is called when the executor begins polling. This will always From 194a3044acb5cd9691ced78596b9fd81e6884667 Mon Sep 17 00:00:00 2001 From: Kat Perez Date: Thu, 8 May 2025 13:41:23 -0400 Subject: [PATCH 1104/1217] remove unused task_id --- embassy-executor/src/raw/trace.rs | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/embassy-executor/src/raw/trace.rs b/embassy-executor/src/raw/trace.rs index b30f23468..04e9d234f 100644 --- a/embassy-executor/src/raw/trace.rs +++ b/embassy-executor/src/raw/trace.rs @@ -216,9 +216,6 @@ impl TaskTracker { /// and names, which are useful for debugging, logging, and performance analysis. #[cfg(feature = "trace")] pub trait TaskRefTrace { - /// Get the ID for a task - fn as_id(self) -> u32; - /// Get the name for a task fn name(&self) -> Option<&'static str>; @@ -234,10 +231,6 @@ pub trait TaskRefTrace { #[cfg(feature = "trace")] impl TaskRefTrace for TaskRef { - fn as_id(self) -> u32 { - self.ptr.as_ptr() as u32 - } - fn name(&self) -> Option<&'static str> { self.header().name } @@ -331,8 +324,6 @@ pub(crate) fn poll_start(executor: &SyncExecutor) { #[inline] pub(crate) fn task_new(executor: &SyncExecutor, task: &TaskRef) { - let task_id = task.as_ptr() as u32; - #[cfg(not(feature = "rtos-trace"))] unsafe { _embassy_trace_task_new(executor as *const _ as u32, task.as_ptr() as u32) @@ -347,8 +338,6 @@ pub(crate) fn task_new(executor: &SyncExecutor, task: &TaskRef) { #[inline] pub(crate) fn task_end(executor: *const SyncExecutor, task: &TaskRef) { - let task_id = task.as_ptr() as u32; - #[cfg(not(feature = "rtos-trace"))] unsafe { _embassy_trace_task_end(executor as u32, task.as_ptr() as u32) @@ -451,7 +440,7 @@ impl rtos_trace::RtosTraceOSCallbacks for crate::raw::SyncExecutor { stack_base: 0, stack_size: 0, }; - rtos_trace::trace::task_send_info(task.as_id(), info); + rtos_trace::trace::task_send_info(task.id(), info); }); } fn time() -> u64 { From e968c4763694d676cca6f1bd30949619dd12e962 Mon Sep 17 00:00:00 2001 From: Kat Perez Date: Thu, 8 May 2025 14:03:03 -0400 Subject: [PATCH 1105/1217] update TraceExt trait name for Spawner --- embassy-executor/src/raw/trace.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/embassy-executor/src/raw/trace.rs b/embassy-executor/src/raw/trace.rs index 04e9d234f..f55033530 100644 --- a/embassy-executor/src/raw/trace.rs +++ b/embassy-executor/src/raw/trace.rs @@ -90,7 +90,7 @@ use crate::raw::{SyncExecutor, TaskHeader, TaskRef}; use crate::spawner::{SpawnError, SpawnToken, Spawner}; /// Extension trait adding tracing capabilities to the Spawner -pub trait TraceExt { +pub trait SpawnerTraceExt { /// Spawns a new task with a specified name. /// /// # Arguments @@ -103,7 +103,7 @@ pub trait TraceExt { } #[cfg(feature = "trace")] -impl TraceExt for Spawner { +impl SpawnerTraceExt for Spawner { fn spawn_named(&self, name: &'static str, token: SpawnToken) -> Result<(), SpawnError> { let task = token.raw_task; core::mem::forget(token); @@ -125,7 +125,7 @@ impl TraceExt for Spawner { /// When trace is disabled, spawn_named falls back to regular spawn. /// This maintains API compatibility while optimizing out the name parameter. #[cfg(not(feature = "trace"))] -impl TraceExt for Spawner { +impl SpawnerTraceExt for Spawner { fn spawn_named(&self, _name: &'static str, token: SpawnToken) -> Result<(), SpawnError> { self.spawn(token) } From dfaab013ebaaa4a19c06f2eb00821712ff13cf7a Mon Sep 17 00:00:00 2001 From: Kat Perez Date: Thu, 8 May 2025 14:35:43 -0400 Subject: [PATCH 1106/1217] move SpawnerTraceExt back into Spawner --- embassy-executor/src/raw/trace.rs | 42 -------------------------- embassy-executor/src/spawner.rs | 50 +++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 42 deletions(-) diff --git a/embassy-executor/src/raw/trace.rs b/embassy-executor/src/raw/trace.rs index f55033530..593f7b0ba 100644 --- a/embassy-executor/src/raw/trace.rs +++ b/embassy-executor/src/raw/trace.rs @@ -89,48 +89,6 @@ use rtos_trace::TaskInfo; use crate::raw::{SyncExecutor, TaskHeader, TaskRef}; use crate::spawner::{SpawnError, SpawnToken, Spawner}; -/// Extension trait adding tracing capabilities to the Spawner -pub trait SpawnerTraceExt { - /// Spawns a new task with a specified name. - /// - /// # Arguments - /// * `name` - Static string name to associate with the task - /// * `token` - Token representing the task to spawn - /// - /// # Returns - /// Result indicating whether the spawn was successful - fn spawn_named(&self, name: &'static str, token: SpawnToken) -> Result<(), SpawnError>; -} - -#[cfg(feature = "trace")] -impl SpawnerTraceExt for Spawner { - fn spawn_named(&self, name: &'static str, token: SpawnToken) -> Result<(), SpawnError> { - let task = token.raw_task; - core::mem::forget(token); - - match task { - Some(task) => { - task.set_name(Some(name)); - let task_id = task.as_ptr() as u32; - task.set_id(task_id); - - unsafe { self.executor.spawn(task) }; - Ok(()) - } - None => Err(SpawnError::Busy), - } - } -} - -/// When trace is disabled, spawn_named falls back to regular spawn. -/// This maintains API compatibility while optimizing out the name parameter. -#[cfg(not(feature = "trace"))] -impl SpawnerTraceExt for Spawner { - fn spawn_named(&self, _name: &'static str, token: SpawnToken) -> Result<(), SpawnError> { - self.spawn(token) - } -} - /// Global task tracker instance /// /// This static provides access to the global task tracker which maintains diff --git a/embassy-executor/src/spawner.rs b/embassy-executor/src/spawner.rs index 6b8db4f8f..bfb32ebcc 100644 --- a/embassy-executor/src/spawner.rs +++ b/embassy-executor/src/spawner.rs @@ -6,6 +6,9 @@ use core::task::Poll; use super::raw; +#[cfg(feature = "trace")] +use crate::raw::trace::TaskRefTrace; + /// Token to spawn a newly-created task in an executor. /// /// When calling a task function (like `#[embassy_executor::task] async fn my_task() { ... }`), the returned @@ -180,6 +183,53 @@ impl Spawner { } } +/// Extension trait adding tracing capabilities to the Spawner +/// +/// This trait provides an additional method to spawn tasks with an associated name, +/// which can be useful for debugging and tracing purposes. +pub trait SpawnerTraceExt { + /// Spawns a new task with a specified name. + /// + /// # Arguments + /// * `name` - Static string name to associate with the task + /// * `token` - Token representing the task to spawn + /// + /// # Returns + /// Result indicating whether the spawn was successful + fn spawn_named(&self, name: &'static str, token: SpawnToken) -> Result<(), SpawnError>; +} + +/// Implementation of the SpawnerTraceExt trait for Spawner when trace is enabled +#[cfg(feature = "trace")] +impl SpawnerTraceExt for Spawner { + fn spawn_named(&self, name: &'static str, token: SpawnToken) -> Result<(), SpawnError> { + let task = token.raw_task; + core::mem::forget(token); + + match task { + Some(task) => { + // Set the name and ID when trace is enabled + task.set_name(Some(name)); + let task_id = task.as_ptr() as u32; + task.set_id(task_id); + + unsafe { self.executor.spawn(task) }; + Ok(()) + } + None => Err(SpawnError::Busy), + } + } +} + +/// Implementation of the SpawnerTraceExt trait for Spawner when trace is disabled +#[cfg(not(feature = "trace"))] +impl SpawnerTraceExt for Spawner { + fn spawn_named(&self, _name: &'static str, token: SpawnToken) -> Result<(), SpawnError> { + // When trace is disabled, just forward to regular spawn and ignore the name + self.spawn(token) + } +} + /// Handle to spawn tasks into an executor from any thread. /// /// This Spawner can be used from any thread (it is Send), but it can From 3ffa2e4f3f9ecbca8637ae1603194a63d55b4396 Mon Sep 17 00:00:00 2001 From: Kat Perez Date: Thu, 8 May 2025 16:30:06 -0400 Subject: [PATCH 1107/1217] remove unnecessary trace flags --- embassy-executor/src/raw/trace.rs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/embassy-executor/src/raw/trace.rs b/embassy-executor/src/raw/trace.rs index 593f7b0ba..6c9cfda25 100644 --- a/embassy-executor/src/raw/trace.rs +++ b/embassy-executor/src/raw/trace.rs @@ -94,7 +94,6 @@ use crate::spawner::{SpawnError, SpawnToken, Spawner}; /// This static provides access to the global task tracker which maintains /// a list of all tasks in the system. It's automatically updated by the /// task lifecycle hooks in the trace module. -#[cfg(feature = "trace")] pub static TASK_TRACKER: TaskTracker = TaskTracker::new(); /// A thread-safe tracker for all tasks in the system @@ -102,12 +101,10 @@ pub static TASK_TRACKER: TaskTracker = TaskTracker::new(); /// This struct uses an intrusive linked list approach to track all tasks /// without additional memory allocations. It maintains a global list of /// tasks that can be traversed to find all currently existing tasks. -#[cfg(feature = "trace")] pub struct TaskTracker { head: AtomicPtr, } -#[cfg(feature = "trace")] impl TaskTracker { /// Creates a new empty task tracker /// @@ -172,7 +169,6 @@ impl TaskTracker { /// This trait is only available when the `trace` feature is enabled. /// It extends `TaskRef` with methods for accessing and modifying task identifiers /// and names, which are useful for debugging, logging, and performance analysis. -#[cfg(feature = "trace")] pub trait TaskRefTrace { /// Get the name for a task fn name(&self) -> Option<&'static str>; @@ -187,7 +183,6 @@ pub trait TaskRefTrace { fn set_id(&self, id: u32); } -#[cfg(feature = "trace")] impl TaskRefTrace for TaskRef { fn name(&self) -> Option<&'static str> { self.header().name @@ -350,7 +345,6 @@ pub(crate) fn executor_idle(executor: &SyncExecutor) { /// /// # Returns /// An iterator that yields `TaskRef` items for each task -#[cfg(feature = "trace")] fn get_all_active_tasks() -> impl Iterator + 'static { struct TaskIterator<'a> { tracker: &'a TaskTracker, @@ -379,7 +373,6 @@ fn get_all_active_tasks() -> impl Iterator + 'static { } /// Perform an action on each active task -#[cfg(feature = "trace")] fn with_all_active_tasks(f: F) where F: FnMut(TaskRef), From ebb6132f5f9c55ad4ced2602134f8e2c69135c1e Mon Sep 17 00:00:00 2001 From: Kat Perez Date: Thu, 8 May 2025 16:31:47 -0400 Subject: [PATCH 1108/1217] rustfmt --- embassy-executor/src/spawner.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/embassy-executor/src/spawner.rs b/embassy-executor/src/spawner.rs index bfb32ebcc..522d97db3 100644 --- a/embassy-executor/src/spawner.rs +++ b/embassy-executor/src/spawner.rs @@ -5,7 +5,6 @@ use core::sync::atomic::Ordering; use core::task::Poll; use super::raw; - #[cfg(feature = "trace")] use crate::raw::trace::TaskRefTrace; From d4c378e059443dbaaaece02a0f5148db62bd4484 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 11 Apr 2025 14:28:59 -0700 Subject: [PATCH 1109/1217] Add embassy-imxrt CRC driver --- docs/pages/imxrt.adoc | 2 +- embassy-imxrt/src/crc.rs | 190 ++++++++++++++++++++++++++++++++ embassy-imxrt/src/lib.rs | 1 + examples/mimxrt6/src/bin/crc.rs | 175 +++++++++++++++++++++++++++++ 4 files changed, 367 insertions(+), 1 deletion(-) create mode 100644 embassy-imxrt/src/crc.rs create mode 100644 examples/mimxrt6/src/bin/crc.rs diff --git a/docs/pages/imxrt.adoc b/docs/pages/imxrt.adoc index adf5218e8..a84fbae03 100644 --- a/docs/pages/imxrt.adoc +++ b/docs/pages/imxrt.adoc @@ -9,5 +9,5 @@ The link: link:https://github.com/embassy-rs/embassy/tree/main/embassy-imxrt[Emb The following peripherals have a HAL implementation at present +* CRC * GPIO - diff --git a/embassy-imxrt/src/crc.rs b/embassy-imxrt/src/crc.rs new file mode 100644 index 000000000..24d6ba5bd --- /dev/null +++ b/embassy-imxrt/src/crc.rs @@ -0,0 +1,190 @@ +//! Cyclic Redundancy Check (CRC) + +use core::marker::PhantomData; + +use crate::clocks::{enable_and_reset, SysconPeripheral}; +pub use crate::pac::crc_engine::mode::CrcPolynomial as Polynomial; +use crate::{peripherals, Peri, PeripheralType}; + +/// CRC driver. +pub struct Crc<'d> { + info: Info, + _config: Config, + _lifetime: PhantomData<&'d ()>, +} + +/// CRC configuration +pub struct Config { + /// Polynomial to be used + pub polynomial: Polynomial, + + /// Reverse bit order of input? + pub reverse_in: bool, + + /// 1's complement input? + pub complement_in: bool, + + /// Reverse CRC bit order? + pub reverse_out: bool, + + /// 1's complement CRC? + pub complement_out: bool, + + /// CRC Seed + pub seed: u32, +} + +impl Config { + /// Create a new CRC config. + #[must_use] + pub fn new( + polynomial: Polynomial, + reverse_in: bool, + complement_in: bool, + reverse_out: bool, + complement_out: bool, + seed: u32, + ) -> Self { + Config { + polynomial, + reverse_in, + complement_in, + reverse_out, + complement_out, + seed, + } + } +} + +impl Default for Config { + fn default() -> Self { + Self { + polynomial: Polynomial::CrcCcitt, + reverse_in: false, + complement_in: false, + reverse_out: false, + complement_out: false, + seed: 0xffff, + } + } +} + +impl<'d> Crc<'d> { + /// Instantiates new CRC peripheral and initializes to default values. + pub fn new(_peripheral: Peri<'d, T>, config: Config) -> Self { + // enable CRC clock + enable_and_reset::(); + + let mut instance = Self { + info: T::info(), + _config: config, + _lifetime: PhantomData, + }; + + instance.reconfigure(); + instance + } + + /// Reconfigured the CRC peripheral. + fn reconfigure(&mut self) { + self.info.regs.mode().write(|w| { + w.crc_poly() + .variant(self._config.polynomial) + .bit_rvs_wr() + .variant(self._config.reverse_in) + .cmpl_wr() + .variant(self._config.complement_in) + .bit_rvs_sum() + .variant(self._config.reverse_out) + .cmpl_sum() + .variant(self._config.complement_out) + }); + + // Init CRC value + self.info + .regs + .seed() + .write(|w| unsafe { w.crc_seed().bits(self._config.seed) }); + } + + /// Feeds a byte into the CRC peripheral. Returns the computed checksum. + pub fn feed_byte(&mut self, byte: u8) -> u32 { + self.info.regs.wr_data8().write(|w| unsafe { w.bits(byte) }); + + self.info.regs.sum().read().bits() + } + + /// Feeds an slice of bytes into the CRC peripheral. Returns the computed checksum. + pub fn feed_bytes(&mut self, bytes: &[u8]) -> u32 { + let (prefix, data, suffix) = unsafe { bytes.align_to::() }; + + for b in prefix { + self.info.regs.wr_data8().write(|w| unsafe { w.bits(*b) }); + } + + for d in data { + self.info.regs.wr_data32().write(|w| unsafe { w.bits(*d) }); + } + + for b in suffix { + self.info.regs.wr_data8().write(|w| unsafe { w.bits(*b) }); + } + + self.info.regs.sum().read().bits() + } + + /// Feeds a halfword into the CRC peripheral. Returns the computed checksum. + pub fn feed_halfword(&mut self, halfword: u16) -> u32 { + self.info.regs.wr_data16().write(|w| unsafe { w.bits(halfword) }); + + self.info.regs.sum().read().bits() + } + + /// Feeds an slice of halfwords into the CRC peripheral. Returns the computed checksum. + pub fn feed_halfwords(&mut self, halfwords: &[u16]) -> u32 { + for halfword in halfwords { + self.info.regs.wr_data16().write(|w| unsafe { w.bits(*halfword) }); + } + + self.info.regs.sum().read().bits() + } + + /// Feeds a words into the CRC peripheral. Returns the computed checksum. + pub fn feed_word(&mut self, word: u32) -> u32 { + self.info.regs.wr_data32().write(|w| unsafe { w.bits(word) }); + + self.info.regs.sum().read().bits() + } + + /// Feeds an slice of words into the CRC peripheral. Returns the computed checksum. + pub fn feed_words(&mut self, words: &[u32]) -> u32 { + for word in words { + self.info.regs.wr_data32().write(|w| unsafe { w.bits(*word) }); + } + + self.info.regs.sum().read().bits() + } +} + +struct Info { + regs: crate::pac::CrcEngine, +} + +trait SealedInstance { + fn info() -> Info; +} + +/// CRC instance trait. +#[allow(private_bounds)] +pub trait Instance: SealedInstance + PeripheralType + SysconPeripheral + 'static + Send {} + +impl Instance for peripherals::CRC {} + +impl SealedInstance for peripherals::CRC { + fn info() -> Info { + // SAFETY: safe from single executor + Info { + regs: unsafe { crate::pac::CrcEngine::steal() }, + } + } +} diff --git a/embassy-imxrt/src/lib.rs b/embassy-imxrt/src/lib.rs index ad9f81e88..d8ce97f76 100644 --- a/embassy-imxrt/src/lib.rs +++ b/embassy-imxrt/src/lib.rs @@ -18,6 +18,7 @@ compile_error!( pub(crate) mod fmt; pub mod clocks; +pub mod crc; pub mod gpio; pub mod iopctl; diff --git a/examples/mimxrt6/src/bin/crc.rs b/examples/mimxrt6/src/bin/crc.rs new file mode 100644 index 000000000..005a250e5 --- /dev/null +++ b/examples/mimxrt6/src/bin/crc.rs @@ -0,0 +1,175 @@ +#![no_std] +#![no_main] + +extern crate embassy_imxrt_examples; + +use defmt::*; +use embassy_executor::Spawner; +use embassy_imxrt::crc::{Config, Crc, Polynomial}; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let mut p = embassy_imxrt::init(Default::default()); + let data = b"123456789"; + + info!("Initializing CRC"); + + // CRC-CCITT + let mut crc = Crc::new(p.CRC.reborrow(), Default::default()); + let output = crc.feed_bytes(data); + defmt::assert_eq!(output, 0x29b1); + + // CRC16-ARC + let mut crc = Crc::new( + p.CRC.reborrow(), + Config { + polynomial: Polynomial::Crc16, + reverse_in: true, + reverse_out: true, + complement_out: false, + seed: 0, + ..Default::default() + }, + ); + let output = crc.feed_bytes(data); + defmt::assert_eq!(output, 0xbb3d); + + // CRC16-CMS + let mut crc = Crc::new( + p.CRC.reborrow(), + Config { + polynomial: Polynomial::Crc16, + reverse_in: false, + reverse_out: false, + complement_out: false, + seed: 0xffff, + ..Default::default() + }, + ); + let output = crc.feed_bytes(data); + defmt::assert_eq!(output, 0xaee7); + + // CRC16-DDS-110 + let mut crc = Crc::new( + p.CRC.reborrow(), + Config { + polynomial: Polynomial::Crc16, + reverse_in: false, + reverse_out: false, + complement_out: false, + seed: 0x800d, + ..Default::default() + }, + ); + let output = crc.feed_bytes(data); + defmt::assert_eq!(output, 0x9ecf); + + // CRC16-MAXIM-DOW + let mut crc = Crc::new( + p.CRC.reborrow(), + Config { + polynomial: Polynomial::Crc16, + reverse_in: true, + reverse_out: true, + complement_out: true, + seed: 0, + ..Default::default() + }, + ); + let output = crc.feed_bytes(data); + defmt::assert_eq!(output, 0x44c2); + + // CRC16-MODBUS + let mut crc = Crc::new( + p.CRC.reborrow(), + Config { + polynomial: Polynomial::Crc16, + reverse_in: true, + reverse_out: true, + complement_out: false, + seed: 0xffff, + ..Default::default() + }, + ); + let output = crc.feed_bytes(data); + defmt::assert_eq!(output, 0x4b37); + + // CRC32-BZIP2 + let mut crc = Crc::new( + p.CRC.reborrow(), + Config { + polynomial: Polynomial::Crc32, + reverse_in: false, + reverse_out: false, + complement_out: true, + seed: 0xffff_ffff, + ..Default::default() + }, + ); + let output = crc.feed_bytes(data); + defmt::assert_eq!(output, 0xfc89_1918); + + // CRC32-CKSUM + let mut crc = Crc::new( + p.CRC.reborrow(), + Config { + polynomial: Polynomial::Crc32, + reverse_in: false, + reverse_out: false, + complement_out: true, + seed: 0, + ..Default::default() + }, + ); + let output = crc.feed_bytes(data); + defmt::assert_eq!(output, 0x765e_7680); + + // CRC32-ISO-HDLC + let mut crc = Crc::new( + p.CRC.reborrow(), + Config { + polynomial: Polynomial::Crc32, + reverse_in: true, + reverse_out: true, + complement_out: true, + seed: 0xffff_ffff, + ..Default::default() + }, + ); + let output = crc.feed_bytes(data); + defmt::assert_eq!(output, 0xcbf4_3926); + + // CRC32-JAMCRC + let mut crc = Crc::new( + p.CRC.reborrow(), + Config { + polynomial: Polynomial::Crc32, + reverse_in: true, + reverse_out: true, + complement_out: false, + seed: 0xffff_ffff, + ..Default::default() + }, + ); + let output = crc.feed_bytes(data); + defmt::assert_eq!(output, 0x340b_c6d9); + + // CRC32-MPEG-2 + let mut crc = Crc::new( + p.CRC.reborrow(), + Config { + polynomial: Polynomial::Crc32, + reverse_in: false, + reverse_out: false, + complement_out: false, + seed: 0xffff_ffff, + ..Default::default() + }, + ); + let output = crc.feed_bytes(data); + defmt::assert_eq!(output, 0x0376_e6e7); + + info!("end program"); + cortex_m::asm::bkpt(); +} From 8e7e4332b40707e8d36338ad8ec486320bb3538f Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 11 Apr 2025 15:03:53 -0700 Subject: [PATCH 1110/1217] Add embassy-imxrt RNG driver --- docs/pages/imxrt.adoc | 2 +- embassy-imxrt/src/lib.rs | 1 + embassy-imxrt/src/rng.rs | 257 ++++++++++++++++++++++++++++++++ examples/mimxrt6/src/bin/rng.rs | 40 +++++ 4 files changed, 299 insertions(+), 1 deletion(-) create mode 100644 embassy-imxrt/src/rng.rs create mode 100644 examples/mimxrt6/src/bin/rng.rs diff --git a/docs/pages/imxrt.adoc b/docs/pages/imxrt.adoc index adf5218e8..9fcb6725c 100644 --- a/docs/pages/imxrt.adoc +++ b/docs/pages/imxrt.adoc @@ -10,4 +10,4 @@ The link: link:https://github.com/embassy-rs/embassy/tree/main/embassy-imxrt[Emb The following peripherals have a HAL implementation at present * GPIO - +* RNG diff --git a/embassy-imxrt/src/lib.rs b/embassy-imxrt/src/lib.rs index ad9f81e88..f728ba060 100644 --- a/embassy-imxrt/src/lib.rs +++ b/embassy-imxrt/src/lib.rs @@ -20,6 +20,7 @@ pub(crate) mod fmt; pub mod clocks; pub mod gpio; pub mod iopctl; +pub mod rng; #[cfg(feature = "_time-driver")] pub mod time_driver; diff --git a/embassy-imxrt/src/rng.rs b/embassy-imxrt/src/rng.rs new file mode 100644 index 000000000..67e7ab65d --- /dev/null +++ b/embassy-imxrt/src/rng.rs @@ -0,0 +1,257 @@ +//! True Random Number Generator (TRNG) + +use core::future::poll_fn; +use core::marker::PhantomData; +use core::task::Poll; + +use embassy_futures::block_on; +use embassy_sync::waitqueue::AtomicWaker; +use rand_core::{CryptoRng, RngCore}; + +use crate::clocks::{enable_and_reset, SysconPeripheral}; +use crate::interrupt::typelevel::Interrupt; +use crate::{interrupt, peripherals, Peri, PeripheralType}; + +static RNG_WAKER: AtomicWaker = AtomicWaker::new(); + +/// RNG ;error +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum Error { + /// Seed error. + SeedError, + + /// HW Error. + HwError, + + /// Frequency Count Fail + FreqCountFail, +} + +/// RNG interrupt handler. +pub struct InterruptHandler { + _phantom: PhantomData, +} + +impl interrupt::typelevel::Handler for InterruptHandler { + unsafe fn on_interrupt() { + let regs = T::info().regs; + let int_status = regs.int_status().read(); + + if int_status.ent_val().bit_is_set() + || int_status.hw_err().bit_is_set() + || int_status.frq_ct_fail().bit_is_set() + { + regs.int_ctrl().modify(|_, w| { + w.ent_val() + .ent_val_0() + .hw_err() + .hw_err_0() + .frq_ct_fail() + .frq_ct_fail_0() + }); + RNG_WAKER.wake(); + } + } +} + +/// RNG driver. +pub struct Rng<'d> { + info: Info, + _lifetime: PhantomData<&'d ()>, +} + +impl<'d> Rng<'d> { + /// Create a new RNG driver. + pub fn new( + _inner: Peri<'d, T>, + _irq: impl interrupt::typelevel::Binding> + 'd, + ) -> Self { + enable_and_reset::(); + + let mut random = Self { + info: T::info(), + _lifetime: PhantomData, + }; + random.init(); + + T::Interrupt::unpend(); + unsafe { T::Interrupt::enable() }; + + random + } + + /// Reset the RNG. + pub fn reset(&mut self) { + self.info.regs.mctl().write(|w| w.rst_def().set_bit().prgm().set_bit()); + } + + /// Fill the given slice with random values. + pub async fn async_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + // We have a total of 16 words (512 bits) of entropy at our + // disposal. The idea here is to read all bits and copy the + // necessary bytes to the slice. + for chunk in dest.chunks_mut(64) { + self.async_fill_chunk(chunk).await?; + } + + Ok(()) + } + + async fn async_fill_chunk(&mut self, chunk: &mut [u8]) -> Result<(), Error> { + // wait for interrupt + let res = poll_fn(|cx| { + // Check if already ready. + // TODO: Is this necessary? Could we just check once after + // the waker has been registered? + if self.info.regs.int_status().read().ent_val().bit_is_set() { + return Poll::Ready(Ok(())); + } + + RNG_WAKER.register(cx.waker()); + + self.unmask_interrupts(); + + let mctl = self.info.regs.mctl().read(); + + // Check again if interrupt fired + if mctl.ent_val().bit_is_set() { + Poll::Ready(Ok(())) + } else if mctl.err().bit_is_set() { + Poll::Ready(Err(Error::HwError)) + } else if mctl.fct_fail().bit_is_set() { + Poll::Ready(Err(Error::FreqCountFail)) + } else { + Poll::Pending + } + }) + .await; + + let bits = self.info.regs.mctl().read(); + + if bits.ent_val().bit_is_set() { + let mut entropy = [0; 16]; + + for (i, item) in entropy.iter_mut().enumerate() { + *item = self.info.regs.ent(i).read().bits(); + } + + // Read MCTL after reading ENT15 + let _ = self.info.regs.mctl().read(); + + if entropy.iter().any(|e| *e == 0) { + return Err(Error::SeedError); + } + + // SAFETY: entropy is the same for input and output types in + // native endianness. + let entropy: [u8; 64] = unsafe { core::mem::transmute(entropy) }; + + // write bytes to chunk + chunk.copy_from_slice(&entropy[..chunk.len()]); + } + + res + } + + fn mask_interrupts(&mut self) { + self.info.regs.int_mask().write(|w| { + w.ent_val() + .ent_val_0() + .hw_err() + .hw_err_0() + .frq_ct_fail() + .frq_ct_fail_0() + }); + } + + fn unmask_interrupts(&mut self) { + self.info.regs.int_mask().modify(|_, w| { + w.ent_val() + .ent_val_1() + .hw_err() + .hw_err_1() + .frq_ct_fail() + .frq_ct_fail_1() + }); + } + + fn enable_interrupts(&mut self) { + self.info.regs.int_ctrl().write(|w| { + w.ent_val() + .ent_val_1() + .hw_err() + .hw_err_1() + .frq_ct_fail() + .frq_ct_fail_1() + }); + } + + fn init(&mut self) { + self.mask_interrupts(); + + // Switch TRNG to programming mode + self.info.regs.mctl().modify(|_, w| w.prgm().set_bit()); + + self.enable_interrupts(); + + // Switch TRNG to Run Mode + self.info + .regs + .mctl() + .modify(|_, w| w.trng_acc().set_bit().prgm().clear_bit()); + } +} + +impl RngCore for Rng<'_> { + fn next_u32(&mut self) -> u32 { + let mut bytes = [0u8; 4]; + block_on(self.async_fill_bytes(&mut bytes)).unwrap(); + u32::from_ne_bytes(bytes) + } + + fn next_u64(&mut self) -> u64 { + let mut bytes = [0u8; 8]; + block_on(self.async_fill_bytes(&mut bytes)).unwrap(); + u64::from_ne_bytes(bytes) + } + + fn fill_bytes(&mut self, dest: &mut [u8]) { + block_on(self.async_fill_bytes(dest)).unwrap(); + } + + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core::Error> { + self.fill_bytes(dest); + Ok(()) + } +} + +impl CryptoRng for Rng<'_> {} + +struct Info { + regs: crate::pac::Trng, +} + +trait SealedInstance { + fn info() -> Info; +} + +/// RNG instance trait. +#[allow(private_bounds)] +pub trait Instance: SealedInstance + PeripheralType + SysconPeripheral + 'static + Send { + /// Interrupt for this RNG instance. + type Interrupt: interrupt::typelevel::Interrupt; +} + +impl Instance for peripherals::RNG { + type Interrupt = crate::interrupt::typelevel::RNG; +} + +impl SealedInstance for peripherals::RNG { + fn info() -> Info { + // SAFETY: safe from single executor + Info { + regs: unsafe { crate::pac::Trng::steal() }, + } + } +} diff --git a/examples/mimxrt6/src/bin/rng.rs b/examples/mimxrt6/src/bin/rng.rs new file mode 100644 index 000000000..5f64cb96a --- /dev/null +++ b/examples/mimxrt6/src/bin/rng.rs @@ -0,0 +1,40 @@ +#![no_std] +#![no_main] + +extern crate embassy_imxrt_examples; + +use defmt::*; +use embassy_executor::Spawner; +use embassy_imxrt::rng::Rng; +use embassy_imxrt::{bind_interrupts, peripherals, rng}; +use rand::RngCore; +use {defmt_rtt as _, panic_probe as _}; + +bind_interrupts!(struct Irqs { + RNG => rng::InterruptHandler; +}); + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_imxrt::init(Default::default()); + + info!("Initializing RNG"); + let mut rng = Rng::new(p.RNG, Irqs); + let mut buf = [0u8; 65]; + + // Async interface + unwrap!(rng.async_fill_bytes(&mut buf).await); + info!("random bytes: {:02x}", buf); + + // RngCore interface + let mut random_bytes = [0; 16]; + + let random_u32 = rng.next_u32(); + let random_u64 = rng.next_u64(); + + rng.fill_bytes(&mut random_bytes); + + info!("random_u32 {}", random_u32); + info!("random_u64 {}", random_u64); + info!("random_bytes {}", random_bytes); +} From ee71dda6317ef8de66b09612a020416466aeb2d3 Mon Sep 17 00:00:00 2001 From: 9names <60134748+9names@users.noreply.github.com> Date: Sat, 10 May 2025 19:58:03 +1000 Subject: [PATCH 1111/1217] Clarify embassy-rp rt feature purpose --- embassy-rp/Cargo.toml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index b440591cf..8fb8a50fd 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml @@ -26,7 +26,10 @@ features = ["defmt", "unstable-pac", "time-driver", "rp2040"] [features] default = [ "rt" ] -## Enable the rt feature of [`rp-pac`](https://docs.rs/rp-pac). This brings in the [`cortex-m-rt`](https://docs.rs/cortex-m-rt) crate, which adds startup code and minimal runtime initialization. + +## Enable the `rt` feature of [`rp-pac`](https://docs.rs/rp-pac). +## With `rt` enabled the PAC provides interrupt vectors instead of letting [`cortex-m-rt`](https://docs.rs/cortex-m-rt) do that. +## See for more info. rt = [ "rp-pac/rt" ] ## Enable [defmt support](https://docs.rs/defmt) and enables `defmt` debug-log messages and formatting in embassy drivers. From 967a98fd4448a8e00c8cbfb509c1cc32e2bdcd29 Mon Sep 17 00:00:00 2001 From: Alessandro Gasbarroni Date: Tue, 17 Dec 2024 13:25:58 +0100 Subject: [PATCH 1112/1217] nrf: Add IPC peripheral for nRF5340 --- embassy-nrf/src/chips/nrf5340_app.rs | 5 + embassy-nrf/src/chips/nrf5340_net.rs | 5 + embassy-nrf/src/ipc.rs | 360 +++++++++++++++++++++++++++ embassy-nrf/src/lib.rs | 2 + 4 files changed, 372 insertions(+) create mode 100644 embassy-nrf/src/ipc.rs diff --git a/embassy-nrf/src/chips/nrf5340_app.rs b/embassy-nrf/src/chips/nrf5340_app.rs index 0103fa7ae..99cf29487 100644 --- a/embassy-nrf/src/chips/nrf5340_app.rs +++ b/embassy-nrf/src/chips/nrf5340_app.rs @@ -262,6 +262,9 @@ embassy_hal_internal::peripherals! { PPI_GROUP4, PPI_GROUP5, + // IPC + IPC, + // GPIO port 0 #[cfg(feature = "lfxo-pins-as-gpio")] P0_00, @@ -327,6 +330,8 @@ embassy_hal_internal::peripherals! { EGU5, } +impl_ipc!(IPC, IPC, IPC); + impl_usb!(USBD, USBD, USBD); impl_uarte!(SERIAL0, UARTE0, SERIAL0); diff --git a/embassy-nrf/src/chips/nrf5340_net.rs b/embassy-nrf/src/chips/nrf5340_net.rs index 22d33d080..c2932be31 100644 --- a/embassy-nrf/src/chips/nrf5340_net.rs +++ b/embassy-nrf/src/chips/nrf5340_net.rs @@ -141,6 +141,9 @@ embassy_hal_internal::peripherals! { PPI_GROUP4, PPI_GROUP5, + // IPC + IPC, + // GPIO port 0 P0_00, P0_01, @@ -200,6 +203,8 @@ embassy_hal_internal::peripherals! { EGU0, } +impl_ipc!(IPC, IPC, IPC); + impl_uarte!(SERIAL0, UARTE0, SERIAL0); impl_spim!(SERIAL0, SPIM0, SERIAL0); impl_spis!(SERIAL0, SPIS0, SERIAL0); diff --git a/embassy-nrf/src/ipc.rs b/embassy-nrf/src/ipc.rs new file mode 100644 index 000000000..410783ef4 --- /dev/null +++ b/embassy-nrf/src/ipc.rs @@ -0,0 +1,360 @@ +//! InterProcessor Communication (IPC) + +#![macro_use] + +use core::future::poll_fn; +use core::sync::atomic::{compiler_fence, Ordering}; +use core::task::Poll; + +use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; +use embassy_sync::waitqueue::AtomicWaker; + +use crate::peripherals::IPC; +use crate::{interrupt, pac}; + +/// IPC Event +#[derive(Debug, Clone, Copy)] +pub enum IpcEvent { + /// IPC Event 0 + Event0 = 0, + /// IPC Event 1 + Event1 = 1, + /// IPC Event 2 + Event2 = 2, + /// IPC Event 3 + Event3 = 3, + /// IPC Event 4 + Event4 = 4, + /// IPC Event 5 + Event5 = 5, + /// IPC Event 6 + Event6 = 6, + /// IPC Event 7 + Event7 = 7, + /// IPC Event 8 + Event8 = 8, + /// IPC Event 9 + Event9 = 9, + /// IPC Event 10 + Event10 = 10, + /// IPC Event 11 + Event11 = 11, + /// IPC Event 12 + Event12 = 12, + /// IPC Event 13 + Event13 = 13, + /// IPC Event 14 + Event14 = 14, + /// IPC Event 15 + Event15 = 15, +} + +const EVENTS: [IpcEvent; 16] = [ + IpcEvent::Event0, + IpcEvent::Event1, + IpcEvent::Event2, + IpcEvent::Event3, + IpcEvent::Event4, + IpcEvent::Event5, + IpcEvent::Event6, + IpcEvent::Event7, + IpcEvent::Event8, + IpcEvent::Event9, + IpcEvent::Event10, + IpcEvent::Event11, + IpcEvent::Event12, + IpcEvent::Event13, + IpcEvent::Event14, + IpcEvent::Event15, +]; + +/// IPC Channel +#[derive(Debug, Clone, Copy)] +pub enum IpcChannel { + /// IPC Channel 0 + Channel0, + /// IPC Channel 1 + Channel1, + /// IPC Channel 2 + Channel2, + /// IPC Channel 3 + Channel3, + /// IPC Channel 4 + Channel4, + /// IPC Channel 5 + Channel5, + /// IPC Channel 6 + Channel6, + /// IPC Channel 7 + Channel7, + /// IPC Channel 8 + Channel8, + /// IPC Channel 9 + Channel9, + /// IPC Channel 10 + Channel10, + /// IPC Channel 11 + Channel11, + /// IPC Channel 12 + Channel12, + /// IPC Channel 13 + Channel13, + /// IPC Channel 14 + Channel14, + /// IPC Channel 15 + Channel15, +} + +/// Interrupt Handler +pub struct InterruptHandler {} + +impl interrupt::typelevel::Handler for InterruptHandler { + unsafe fn on_interrupt() { + let regs = IPC::regs(); + + // Check if an event was generated, and if it was, trigger the corresponding waker + for event in EVENTS { + if regs.events_receive(event as usize).read() & 0x01 == 0x01 { + // Event is set. Reset and wake waker + regs.events_receive(event as usize).write_value(0); + IPC::state().waker_for(event); + } + + // Ensure the state is actually cleared + // Ref: nRF5340 PS v1.5 7.1.9.1 p.153 + compiler_fence(Ordering::SeqCst); + while regs.events_receive(event as usize).read() & 0x01 != 0x00 {} + } + } +} + +/// IPC driver +pub struct Ipc<'d, T: Instance> { + _peri: PeripheralRef<'d, T>, +} + +impl<'d, T: Instance> From> for Ipc<'d, T> { + fn from(value: PeripheralRef<'d, T>) -> Self { + Self { _peri: value } + } +} + +impl<'d, T: Instance> Ipc<'d, T> { + /// Create IPC driver + pub fn new(ipc: impl Peripheral

+ 'd) -> Self { + into_ref!(ipc); + + Self { _peri: ipc } + } + + /// Duplicates the peripheral singleton + /// + /// # Safety + /// + /// Ensure manually that only one peripheral is in use at one time + pub unsafe fn clone_unchecked(&self) -> Self { + Self { + _peri: self._peri.clone_unchecked(), + } + } + + /// Configures the sending of events + /// + /// Events can be configured to broadcast on one or multiple IPC channels. + pub fn configure_send_event>(&self, ev: IpcEvent, channels: I) { + let regs = T::regs(); + + regs.send_cnf(ev as usize).write(|w| { + for channel in channels { + match channel { + IpcChannel::Channel0 => w.set_chen0(true), + IpcChannel::Channel1 => w.set_chen1(true), + IpcChannel::Channel2 => w.set_chen2(true), + IpcChannel::Channel3 => w.set_chen3(true), + IpcChannel::Channel4 => w.set_chen4(true), + IpcChannel::Channel5 => w.set_chen5(true), + IpcChannel::Channel6 => w.set_chen6(true), + IpcChannel::Channel7 => w.set_chen7(true), + IpcChannel::Channel8 => w.set_chen8(true), + IpcChannel::Channel9 => w.set_chen9(true), + IpcChannel::Channel10 => w.set_chen10(true), + IpcChannel::Channel11 => w.set_chen11(true), + IpcChannel::Channel12 => w.set_chen12(true), + IpcChannel::Channel13 => w.set_chen13(true), + IpcChannel::Channel14 => w.set_chen14(true), + IpcChannel::Channel15 => w.set_chen15(true), + } + } + }) + } + + /// Configures the receiving of events + /// + /// Events can be configured to be received by one or multiple IPC channels. + pub fn configure_receive_event>(&self, ev: IpcEvent, channels: I) { + let regs = T::regs(); + + regs.receive_cnf(ev as usize).write(|w| { + for channel in channels { + match channel { + IpcChannel::Channel0 => w.set_chen0(true), + IpcChannel::Channel1 => w.set_chen1(true), + IpcChannel::Channel2 => w.set_chen2(true), + IpcChannel::Channel3 => w.set_chen3(true), + IpcChannel::Channel4 => w.set_chen4(true), + IpcChannel::Channel5 => w.set_chen5(true), + IpcChannel::Channel6 => w.set_chen6(true), + IpcChannel::Channel7 => w.set_chen7(true), + IpcChannel::Channel8 => w.set_chen8(true), + IpcChannel::Channel9 => w.set_chen9(true), + IpcChannel::Channel10 => w.set_chen10(true), + IpcChannel::Channel11 => w.set_chen11(true), + IpcChannel::Channel12 => w.set_chen12(true), + IpcChannel::Channel13 => w.set_chen13(true), + IpcChannel::Channel14 => w.set_chen14(true), + IpcChannel::Channel15 => w.set_chen15(true), + } + } + }); + } + + /// Triggers an event + pub fn trigger_event(&self, ev: IpcEvent) { + let regs = T::regs(); + + regs.tasks_send(ev as usize).write_value(0x01); + } + + /// Wait for event to be triggered + pub async fn wait_for_event(&self, ev: IpcEvent) { + let regs = T::regs(); + + // Enable interrupt + match ev { + IpcEvent::Event0 => { + regs.inten().modify(|m| m.set_receive0(true)); + } + IpcEvent::Event1 => { + regs.inten().modify(|m| m.set_receive1(true)); + } + IpcEvent::Event2 => { + regs.inten().modify(|m| m.set_receive2(true)); + } + IpcEvent::Event3 => { + regs.inten().modify(|m| m.set_receive3(true)); + } + IpcEvent::Event4 => { + regs.inten().modify(|m| m.set_receive4(true)); + } + IpcEvent::Event5 => { + regs.inten().modify(|m| m.set_receive5(true)); + } + IpcEvent::Event6 => { + regs.inten().modify(|m| m.set_receive6(true)); + } + IpcEvent::Event7 => { + regs.inten().modify(|m| m.set_receive7(true)); + } + IpcEvent::Event8 => { + regs.inten().modify(|m| m.set_receive8(true)); + } + IpcEvent::Event9 => { + regs.inten().modify(|m| m.set_receive9(true)); + } + IpcEvent::Event10 => { + regs.inten().modify(|m| m.set_receive10(true)); + } + IpcEvent::Event11 => { + regs.inten().modify(|m| m.set_receive11(true)); + } + IpcEvent::Event12 => { + regs.inten().modify(|m| m.set_receive12(true)); + } + IpcEvent::Event13 => { + regs.inten().modify(|m| m.set_receive13(true)); + } + IpcEvent::Event14 => { + regs.inten().modify(|m| m.set_receive14(true)); + } + IpcEvent::Event15 => { + regs.inten().modify(|m| m.set_receive15(true)); + } + }; + + poll_fn(|cx| { + IPC::state().waker_for(ev).register(cx.waker()); + + if regs.events_receive(ev as usize).read() & 0x01 == 0x01 { + regs.events_receive(ev as usize).write_value(0x00); + + Poll::Ready(()) + } else { + Poll::Pending + } + }) + .await; + } +} + +pub(crate) struct State { + wakers: [AtomicWaker; 16], +} + +impl State { + pub(crate) const fn new() -> Self { + const WAKER: AtomicWaker = AtomicWaker::new(); + + Self { wakers: [WAKER; 16] } + } + + const fn waker_for(&self, ev: IpcEvent) -> &AtomicWaker { + match ev { + IpcEvent::Event0 => &self.wakers[0], + IpcEvent::Event1 => &self.wakers[1], + IpcEvent::Event2 => &self.wakers[2], + IpcEvent::Event3 => &self.wakers[3], + IpcEvent::Event4 => &self.wakers[4], + IpcEvent::Event5 => &self.wakers[5], + IpcEvent::Event6 => &self.wakers[6], + IpcEvent::Event7 => &self.wakers[7], + IpcEvent::Event8 => &self.wakers[8], + IpcEvent::Event9 => &self.wakers[9], + IpcEvent::Event10 => &self.wakers[10], + IpcEvent::Event11 => &self.wakers[11], + IpcEvent::Event12 => &self.wakers[12], + IpcEvent::Event13 => &self.wakers[13], + IpcEvent::Event14 => &self.wakers[14], + IpcEvent::Event15 => &self.wakers[15], + } + } +} + +pub(crate) trait SealedInstance { + fn regs() -> pac::ipc::Ipc; + fn state() -> &'static State; +} + +/// IPC peripheral instance. +#[allow(private_bounds)] +pub trait Instance: Peripheral

+ SealedInstance + 'static + Send { + /// Interrupt for this peripheral. + type Interrupt: interrupt::typelevel::Interrupt; +} + +macro_rules! impl_ipc { + ($type:ident, $pac_type:ident, $irq:ident) => { + impl crate::ipc::SealedInstance for peripherals::$type { + fn regs() -> pac::ipc::Ipc { + pac::$pac_type + } + + fn state() -> &'static crate::ipc::State { + static STATE: crate::ipc::State = crate::ipc::State::new(); + &STATE + } + } + impl crate::ipc::Instance for peripherals::$type { + type Interrupt = crate::interrupt::typelevel::$irq; + } + }; +} diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index 07ba2f6d4..5bce65a98 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs @@ -88,6 +88,8 @@ pub mod gpiote; #[cfg(not(feature = "_nrf54l"))] // TODO #[cfg(any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840"))] pub mod i2s; +#[cfg(feature = "_nrf5340")] +pub mod ipc; #[cfg(not(feature = "_nrf54l"))] // TODO #[cfg(any( feature = "nrf52832", From 4567beda7b7773c8cb11f19f0f4f146c1243508d Mon Sep 17 00:00:00 2001 From: 1-rafael-1 Date: Sun, 11 May 2025 17:26:36 +0200 Subject: [PATCH 1113/1217] rp235x overclocking --- embassy-rp/src/clocks.rs | 329 +++++++++++++++++++++--- examples/rp/src/bin/overclock.rs | 8 +- examples/rp/src/bin/overclock_manual.rs | 10 +- examples/rp235x/src/bin/overclock.rs | 74 ++++++ tests/rp/src/bin/overclock.rs | 49 ++-- 5 files changed, 405 insertions(+), 65 deletions(-) create mode 100644 examples/rp235x/src/bin/overclock.rs diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs index 6694aab66..ea5e9362b 100644 --- a/embassy-rp/src/clocks.rs +++ b/embassy-rp/src/clocks.rs @@ -38,7 +38,7 @@ //! //! ## Examples //! -//! ### Standard 125MHz configuration +//! ### Standard 125MHz (rp2040) or 150Mhz (rp235x) configuration //! ```rust,ignore //! let config = ClockConfig::crystal(12_000_000); //! ``` @@ -136,43 +136,152 @@ pub enum PeriClkSrc { // Gpin1 = ClkPeriCtrlAuxsrc::CLKSRC_GPIN1 as _ , } -/// Core voltage regulator settings for RP2040. +/// Core voltage regulator settings. /// -/// The RP2040 voltage regulator can be configured for different output voltages. +/// The voltage regulator can be configured for different output voltages. /// Higher voltages allow for higher clock frequencies but increase power consumption and heat. -#[cfg(feature = "rp2040")] #[derive(Clone, Copy, Debug, PartialEq, Eq)] #[repr(u8)] pub enum CoreVoltage { - /// 0.80V - Suitable for lower frequencies + // RP2040 voltage levels + #[cfg(feature = "rp2040")] + /// RP2040: 0.80V V0_80 = 0b0000, - /// 0.85V + #[cfg(feature = "rp2040")] + /// RP2040: 0.85V V0_85 = 0b0110, - /// 0.90V + #[cfg(feature = "rp2040")] + /// RP2040: 0.90V V0_90 = 0b0111, - /// 0.95V + #[cfg(feature = "rp2040")] + /// RP2040: 0.95V V0_95 = 0b1000, - /// 1.00V + #[cfg(feature = "rp2040")] + /// RP2040: 1.00V V1_00 = 0b1001, - /// 1.05V + #[cfg(feature = "rp2040")] + /// RP2040: 1.05V V1_05 = 0b1010, - /// 1.10V - Default voltage level + #[cfg(feature = "rp2040")] + /// RP2040: 1.10V - Default voltage level V1_10 = 0b1011, - /// 1.15V - Required for overclocking to 133-200MHz + #[cfg(feature = "rp2040")] + /// RP2040: 1.15V - Required for overclocking to 133-200MHz V1_15 = 0b1100, - /// 1.20V + #[cfg(feature = "rp2040")] + /// RP2040: 1.20V V1_20 = 0b1101, - /// 1.25V + #[cfg(feature = "rp2040")] + /// RP2040: 1.25V V1_25 = 0b1110, - /// 1.30V + #[cfg(feature = "rp2040")] + /// RP2040: 1.30V V1_30 = 0b1111, + + // RP235x voltage levels + #[cfg(feature = "_rp235x")] + /// RP235x: 0.55V + V0_55 = 0b00000, + #[cfg(feature = "_rp235x")] + /// RP235x: 0.60V + V0_60 = 0b00001, + #[cfg(feature = "_rp235x")] + /// RP235x: 0.65V + V0_65 = 0b00010, + #[cfg(feature = "_rp235x")] + /// RP235x: 0.70V + V0_70 = 0b00011, + #[cfg(feature = "_rp235x")] + /// RP235x: 0.75V + V0_75 = 0b00100, + #[cfg(feature = "_rp235x")] + /// RP235x: 0.80V + V0_80 = 0b00101, + #[cfg(feature = "_rp235x")] + /// RP235x: 0.85V + V0_85 = 0b00110, + #[cfg(feature = "_rp235x")] + /// RP235x: 0.90V + V0_90 = 0b00111, + #[cfg(feature = "_rp235x")] + /// RP235x: 0.95V + V0_95 = 0b01000, + #[cfg(feature = "_rp235x")] + /// RP235x: 1.00V + V1_00 = 0b01001, + #[cfg(feature = "_rp235x")] + /// RP235x: 1.05V + V1_05 = 0b01010, + #[cfg(feature = "_rp235x")] + /// RP235x: 1.10V - Default voltage level + V1_10 = 0b01011, + #[cfg(feature = "_rp235x")] + /// RP235x: 1.15V + V1_15 = 0b01100, + #[cfg(feature = "_rp235x")] + /// RP235x: 1.20V + V1_20 = 0b01101, + #[cfg(feature = "_rp235x")] + /// RP235x: 1.25V + V1_25 = 0b01110, + #[cfg(feature = "_rp235x")] + /// RP235x: 1.30V + V1_30 = 0b01111, + #[cfg(feature = "_rp235x")] + /// RP235x: 1.35V + V1_35 = 0b10000, + #[cfg(feature = "_rp235x")] + /// RP235x: 1.40V + V1_40 = 0b10001, + #[cfg(feature = "_rp235x")] + /// RP235x: 1.50V + V1_50 = 0b10010, + #[cfg(feature = "_rp235x")] + /// RP235x: 1.60V + V1_60 = 0b10011, + #[cfg(feature = "_rp235x")] + /// RP235x: 1.65V + V1_65 = 0b10100, + #[cfg(feature = "_rp235x")] + /// RP235x: 1.70V + V1_70 = 0b10101, + #[cfg(feature = "_rp235x")] + /// RP235x: 1.80V + V1_80 = 0b10110, + #[cfg(feature = "_rp235x")] + /// RP235x: 1.90V + V1_90 = 0b10111, + #[cfg(feature = "_rp235x")] + /// RP235x: 2.00V + V2_00 = 0b11000, + #[cfg(feature = "_rp235x")] + /// RP235x: 2.35V + V2_35 = 0b11001, + #[cfg(feature = "_rp235x")] + /// RP235x: 2.50V + V2_50 = 0b11010, + #[cfg(feature = "_rp235x")] + /// RP235x: 2.65V + V2_65 = 0b11011, + #[cfg(feature = "_rp235x")] + /// RP235x: 2.80V + V2_80 = 0b11100, + #[cfg(feature = "_rp235x")] + /// RP235x: 3.00V + V3_00 = 0b11101, + #[cfg(feature = "_rp235x")] + /// RP235x: 3.15V + V3_15 = 0b11110, + #[cfg(feature = "_rp235x")] + /// RP235x: 3.30V + V3_30 = 0b11111, } -#[cfg(feature = "rp2040")] impl CoreVoltage { /// Get the recommended Brown-Out Detection (BOD) setting for this voltage. /// Sets the BOD threshold to approximately 80% of the core voltage. fn recommended_bod(self) -> u8 { + #[cfg(feature = "rp2040")] match self { CoreVoltage::V0_80 => 0b0100, // 0.645V (~81% of 0.80V) CoreVoltage::V0_85 => 0b0101, // 0.688V (~81% of 0.85V) @@ -180,12 +289,38 @@ impl CoreVoltage { CoreVoltage::V0_95 => 0b0111, // 0.774V (~81% of 0.95V) CoreVoltage::V1_00 => 0b1000, // 0.817V (~82% of 1.00V) CoreVoltage::V1_05 => 0b1000, // 0.817V (~78% of 1.05V) - CoreVoltage::V1_10 => 0b1001, // 0.860V (~78% of 1.10V) + CoreVoltage::V1_10 => 0b1001, // 0.860V (~78% of 1.10V), the default CoreVoltage::V1_15 => 0b1010, // 0.903V (~79% of 1.15V) CoreVoltage::V1_20 => 0b1011, // 0.946V (~79% of 1.20V) CoreVoltage::V1_25 => 0b1100, // 0.989V (~79% of 1.25V) CoreVoltage::V1_30 => 0b1101, // 1.032V (~79% of 1.30V) } + #[cfg(feature = "_rp235x")] + match self { + CoreVoltage::V0_55 => 0b00001, // 0.516V (~94% of 0.55V) + CoreVoltage::V0_60 => 0b00010, // 0.559V (~93% of 0.60V) + CoreVoltage::V0_65 => 0b00011, // 0.602V (~93% of 0.65V) + CoreVoltage::V0_70 => 0b00011, // 0.602V (~86% of 0.70V) + CoreVoltage::V0_75 => 0b00100, // 0.645V (~86% of 0.75V) + CoreVoltage::V0_80 => 0b00101, // 0.688V (~86% of 0.80V) + CoreVoltage::V0_85 => 0b00110, // 0.731V (~86% of 0.85V) + CoreVoltage::V0_90 => 0b00110, // 0.731V (~81% of 0.90V) + CoreVoltage::V0_95 => 0b00111, // 0.774V (~81% of 0.95V) + CoreVoltage::V1_00 => 0b01000, // 0.817V (~82% of 1.00V) + CoreVoltage::V1_05 => 0b01000, // 0.817V (~78% of 1.05V) + CoreVoltage::V1_10 => 0b01001, // 0.860V (~78% of 1.10V), the default + CoreVoltage::V1_15 => 0b01001, // 0.860V (~75% of 1.15V) + CoreVoltage::V1_20 => 0b01010, // 0.903V (~75% of 1.20V) + CoreVoltage::V1_25 => 0b01010, // 0.903V (~72% of 1.25V) + CoreVoltage::V1_30 => 0b01011, // 0.946V (~73% of 1.30V) + CoreVoltage::V1_35 => 0b01011, // 0.946V (~70% of 1.35V) + CoreVoltage::V1_40 => 0b01100, // 0.989V (~71% of 1.40V) + CoreVoltage::V1_50 => 0b01101, // 1.032V (~69% of 1.50V) + CoreVoltage::V1_60 => 0b01110, // 1.075V (~67% of 1.60V) + CoreVoltage::V1_65 => 0b01110, // 1.075V (~65% of 1.65V) + CoreVoltage::V1_70 => 0b01111, // 1.118V (~66% of 1.70V) + _ => 0b10000, // the rp2350 datasheet repeats this value for all other core voltages + } } } @@ -209,12 +344,10 @@ pub struct ClockConfig { /// RTC clock configuration. #[cfg(feature = "rp2040")] pub rtc_clk: Option, - /// Core voltage scaling (RP2040 only). Defaults to 1.10V. - #[cfg(feature = "rp2040")] + /// Core voltage scaling. Defaults to 1.10V. pub core_voltage: CoreVoltage, /// Voltage stabilization delay in microseconds. /// If not set, defaults will be used based on voltage level. - #[cfg(feature = "rp2040")] pub voltage_stabilization_delay_us: Option, // See above re gpin handling being commented out // gpin0: Option<(u32, Gpin<'static, AnyPin>)>, @@ -250,9 +383,7 @@ impl Default for ClockConfig { adc_clk: None, #[cfg(feature = "rp2040")] rtc_clk: None, - #[cfg(feature = "rp2040")] core_voltage: CoreVoltage::V1_10, - #[cfg(feature = "rp2040")] voltage_stabilization_delay_us: None, // See above re gpin handling being commented out // gpin0: None, @@ -323,9 +454,7 @@ impl ClockConfig { div_frac: 0, phase: 0, }), - #[cfg(feature = "rp2040")] core_voltage: CoreVoltage::V1_10, // Use hardware default (1.10V) - #[cfg(feature = "rp2040")] voltage_stabilization_delay_us: None, // See above re gpin handling being commented out // gpin0: None, @@ -368,9 +497,7 @@ impl ClockConfig { div_frac: 171, phase: 0, }), - #[cfg(feature = "rp2040")] core_voltage: CoreVoltage::V1_10, // Use hardware default (1.10V) - #[cfg(feature = "rp2040")] voltage_stabilization_delay_us: None, // See above re gpin handling being commented out // gpin0: None, @@ -394,12 +521,17 @@ impl ClockConfig { /// the usual 12Mhz crystal, or panic if no valid parameters can be found. /// /// # Note on core voltage: + /// + /// **For RP2040**: /// To date the only officially documented core voltages (see Datasheet section 2.15.3.1. Instances) are: /// - Up to 133MHz: V1_10 (default) /// - Above 133MHz: V1_15, but in the context of the datasheet covering reaching up to 200Mhz /// That way all other frequencies below 133MHz or above 200MHz are not explicitly documented and not covered here. /// In case You want to go below 133MHz or above 200MHz and want a different voltage, You will have to set that manually and with caution. - #[cfg(feature = "rp2040")] + /// + /// **For RP235x**: + /// At this point in time there is no official manufacturer endorsement for running the chip on other core voltages and/or other clock speeds than the defaults. + /// Using this function is experimental and may not work as expected or even damage the chip. pub fn system_freq(hz: u32) -> Self { // Start with the standard configuration from crystal() const DEFAULT_CRYSTAL_HZ: u32 = 12_000_000; @@ -407,9 +539,14 @@ impl ClockConfig { // No need to modify anything if target frequency is already 125MHz // (which is what crystal() configures by default) + #[cfg(feature = "rp2040")] if hz == 125_000_000 { return config; } + #[cfg(feature = "_rp235x")] + if hz == 150_000_000 { + return config; + } // Find optimal PLL parameters for the requested frequency let sys_pll_params = find_pll_params(DEFAULT_CRYSTAL_HZ, hz) @@ -429,6 +566,14 @@ impl ClockConfig { _ => CoreVoltage::V1_10, // Use default voltage (V1_10) }; } + #[cfg(feature = "_rp235x")] + { + config.core_voltage = match hz { + // There is no official support for running the chip on other core voltages and/or other clock speeds than the defaults. + // So for now we have not way of knowing what the voltage should be. Change this if the manufacturer provides more information. + _ => CoreVoltage::V1_10, // Use default voltage (V1_10) + }; + } config } @@ -791,7 +936,6 @@ pub struct RtcClkConfig { /// // Find parameters for 133MHz system clock from 12MHz crystal /// let pll_params = find_pll_params(12_000_000, 133_000_000).unwrap(); /// ``` -#[cfg(feature = "rp2040")] fn find_pll_params(input_hz: u32, target_hz: u32) -> Option { // Fixed reference divider for system PLL const PLL_SYS_REFDIV: u8 = 1; @@ -925,18 +1069,59 @@ pub(crate) unsafe fn init(config: ClockConfig) { }; CLOCKS.rosc.store(rosc_freq, Ordering::Relaxed); - // Set Core Voltage (RP2040 only), if we have config for it and we're not using the default - #[cfg(feature = "rp2040")] + // Set Core Voltage, if we have config for it and we're not using the default { let voltage = config.core_voltage; + + #[cfg(feature = "rp2040")] let vreg = pac::VREG_AND_CHIP_RESET; + #[cfg(feature = "_rp235x")] + let vreg = pac::POWMAN; + let current_vsel = vreg.vreg().read().vsel(); let target_vsel = voltage as u8; // If the target voltage is different from the current one, we need to change it if target_vsel != current_vsel { - // Use modify() to preserve the HIZ and EN bits - otherwise we will disable the regulator when changing voltage - vreg.vreg().modify(|w| w.set_vsel(target_vsel)); + #[cfg(feature = "rp2040")] + { + // Use modify() to preserve the HIZ and EN bits - otherwise we will disable the regulator when changing voltage + vreg.vreg().modify(|w| w.set_vsel(target_vsel)); + } + #[cfg(feature = "_rp235x")] + { + // The rp235x has a different way of controlling the voltage regulator + // Changes to the voltage regulator are protected by a password, see datasheet section 6.4 + // The password is "5AFE" (0x5AFE), it must be set in the top 16 bits of the register + + // The rp235x by default locks the voltage regulator control, so we need to unlock it first + // See datasheet section 6.3.2. Software Control + vreg.vreg_ctrl().modify(|w| { + // Add password to top 16 bits, preserving the rest, repeat below for other registers + w.0 = (w.0 & 0x0000FFFF) | (0x5AFE << 16); + w.set_unlock(true); + *w + }); + + // Set the voltage + vreg.vreg().modify(|w| { + w.0 = (w.0 & 0x0000FFFF) | (0x5AFE << 16); + w.set_vsel(target_vsel); + *w + }); + + // The rp235x has two more registers to set the voltage for low power mode + vreg.vreg_lp_entry().modify(|w| { + w.0 = (w.0 & 0x0000FFFF) | (0x5AFE << 16); + w.set_vsel(target_vsel); + *w + }); + vreg.vreg_lp_exit().modify(|w| { + w.0 = (w.0 & 0x0000FFFF) | (0x5AFE << 16); + w.set_vsel(target_vsel); + *w + }); + } // Wait for the voltage to stabilize. Use the provided delay or default based on voltage let settling_time_us = config.voltage_stabilization_delay_us.unwrap_or_else(|| { @@ -959,6 +1144,19 @@ pub(crate) unsafe fn init(config: ClockConfig) { w.set_vsel(voltage.recommended_bod()); w.set_en(true); // Enable brownout detection }); + + #[cfg(feature = "_rp235x")] + { + // The rp235x has a separate register for the BOD level in low power mode + vreg.bod_lp_entry().write(|w| { + w.set_vsel(voltage.recommended_bod()); + w.set_en(true); // Enable brownout detection + }); + vreg.bod_lp_exit().write(|w| { + w.set_vsel(voltage.recommended_bod()); + w.set_en(true); // Enable brownout detection + }); + } } } @@ -1283,6 +1481,73 @@ pub fn clk_rtc_freq() -> u16 { CLOCKS.rtc.load(Ordering::Relaxed) } +/// The core voltage of the chip. +/// +/// Returns the current core voltage or an error if the voltage register +/// contains an unknown value. +pub fn core_voltage() -> Result { + #[cfg(feature = "rp2040")] + { + let vreg = pac::VREG_AND_CHIP_RESET; + let vsel = vreg.vreg().read().vsel(); + match vsel { + 0b0000 => Ok(CoreVoltage::V0_80), + 0b0110 => Ok(CoreVoltage::V0_85), + 0b0111 => Ok(CoreVoltage::V0_90), + 0b1000 => Ok(CoreVoltage::V0_95), + 0b1001 => Ok(CoreVoltage::V1_00), + 0b1010 => Ok(CoreVoltage::V1_05), + 0b1011 => Ok(CoreVoltage::V1_10), + 0b1100 => Ok(CoreVoltage::V1_15), + 0b1101 => Ok(CoreVoltage::V1_20), + 0b1110 => Ok(CoreVoltage::V1_25), + 0b1111 => Ok(CoreVoltage::V1_30), + _ => Err("Unexpected value in register"), + } + } + + #[cfg(feature = "_rp235x")] + { + let vreg = pac::POWMAN; + let vsel = vreg.vreg().read().vsel(); + match vsel { + 0b00000 => Ok(CoreVoltage::V0_55), + 0b00001 => Ok(CoreVoltage::V0_60), + 0b00010 => Ok(CoreVoltage::V0_65), + 0b00011 => Ok(CoreVoltage::V0_70), + 0b00100 => Ok(CoreVoltage::V0_75), + 0b00101 => Ok(CoreVoltage::V0_80), + 0b00110 => Ok(CoreVoltage::V0_85), + 0b00111 => Ok(CoreVoltage::V0_90), + 0b01000 => Ok(CoreVoltage::V0_95), + 0b01001 => Ok(CoreVoltage::V1_00), + 0b01010 => Ok(CoreVoltage::V1_05), + 0b01011 => Ok(CoreVoltage::V1_10), + 0b01100 => Ok(CoreVoltage::V1_15), + 0b01101 => Ok(CoreVoltage::V1_20), + 0b01110 => Ok(CoreVoltage::V1_25), + 0b01111 => Ok(CoreVoltage::V1_30), + 0b10000 => Ok(CoreVoltage::V1_35), + 0b10001 => Ok(CoreVoltage::V1_40), + 0b10010 => Ok(CoreVoltage::V1_50), + 0b10011 => Ok(CoreVoltage::V1_60), + 0b10100 => Ok(CoreVoltage::V1_65), + 0b10101 => Ok(CoreVoltage::V1_70), + 0b10110 => Ok(CoreVoltage::V1_80), + 0b10111 => Ok(CoreVoltage::V1_90), + 0b11000 => Ok(CoreVoltage::V2_00), + 0b11001 => Ok(CoreVoltage::V2_35), + 0b11010 => Ok(CoreVoltage::V2_50), + 0b11011 => Ok(CoreVoltage::V2_65), + 0b11100 => Ok(CoreVoltage::V2_80), + 0b11101 => Ok(CoreVoltage::V3_00), + 0b11110 => Ok(CoreVoltage::V3_15), + 0b11111 => Ok(CoreVoltage::V3_30), + _ => Err("Unexpected value in register"), + } + } +} + fn start_xosc(crystal_hz: u32, delay_multiplier: u32) { let startup_delay = (((crystal_hz / 1000) * delay_multiplier) + 128) / 256; pac::XOSC.startup().write(|w| w.set_delay(startup_delay as u16)); diff --git a/examples/rp/src/bin/overclock.rs b/examples/rp/src/bin/overclock.rs index 9c78e0c9d..89147ba42 100644 --- a/examples/rp/src/bin/overclock.rs +++ b/examples/rp/src/bin/overclock.rs @@ -7,7 +7,7 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_rp::clocks::{clk_sys_freq, ClockConfig}; +use embassy_rp::clocks::{clk_sys_freq, core_voltage, ClockConfig}; use embassy_rp::config::Config; use embassy_rp::gpio::{Level, Output}; use embassy_time::{Duration, Instant, Timer}; @@ -20,15 +20,15 @@ async fn main(_spawner: Spawner) -> ! { // Set up for clock frequency of 200 MHz, setting all necessary defaults. let config = Config::new(ClockConfig::system_freq(200_000_000)); - // Show the voltage scale for verification - info!("System core voltage: {}", Debug2Format(&config.clocks.core_voltage)); - // Initialize the peripherals let p = embassy_rp::init(config); // Show CPU frequency for verification let sys_freq = clk_sys_freq(); info!("System clock frequency: {} MHz", sys_freq / 1_000_000); + // Show core voltage for verification + let core_voltage = core_voltage().unwrap(); + info!("Core voltage: {}", Debug2Format(&core_voltage)); // LED to indicate the system is running let mut led = Output::new(p.PIN_25, Level::Low); diff --git a/examples/rp/src/bin/overclock_manual.rs b/examples/rp/src/bin/overclock_manual.rs index 35160b250..88ef26a7a 100644 --- a/examples/rp/src/bin/overclock_manual.rs +++ b/examples/rp/src/bin/overclock_manual.rs @@ -7,8 +7,7 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_rp::clocks; -use embassy_rp::clocks::{ClockConfig, CoreVoltage, PllConfig}; +use embassy_rp::clocks::{clk_sys_freq, core_voltage, ClockConfig, CoreVoltage, PllConfig}; use embassy_rp::config::Config; use embassy_rp::gpio::{Level, Output}; use embassy_time::{Duration, Instant, Timer}; @@ -41,9 +40,12 @@ async fn main(_spawner: Spawner) -> ! { // Initialize with our manual overclock configuration let p = embassy_rp::init(configure_manual_overclock()); - // Verify the actual system clock frequency - let sys_freq = clocks::clk_sys_freq(); + // Show CPU frequency for verification + let sys_freq = clk_sys_freq(); info!("System clock frequency: {} MHz", sys_freq / 1_000_000); + // Show core voltage for verification + let core_voltage = core_voltage().unwrap(); + info!("Core voltage: {}", Debug2Format(&core_voltage)); // LED to indicate the system is running let mut led = Output::new(p.PIN_25, Level::Low); diff --git a/examples/rp235x/src/bin/overclock.rs b/examples/rp235x/src/bin/overclock.rs new file mode 100644 index 000000000..8713df688 --- /dev/null +++ b/examples/rp235x/src/bin/overclock.rs @@ -0,0 +1,74 @@ +//! # Overclocking the RP2350 to 200 MHz +//! +//! This example demonstrates how to configure the RP2350 to run at 200 MHz instead of the default 150 MHz. +//! +//! ## Note +//! +//! As of yet there is no official support for running the RP235x at higher clock frequencies and/or other core voltages than the default. +//! Doing so may cause unexpected behavior and/or damage the chip. + +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_rp::clocks::{clk_sys_freq, core_voltage, ClockConfig, CoreVoltage}; +use embassy_rp::config::Config; +use embassy_rp::gpio::{Level, Output}; +use embassy_time::{Duration, Instant, Timer}; +use {defmt_rtt as _, panic_probe as _}; + +const COUNT_TO: i64 = 10_000_000; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) -> ! { + // Set up for clock frequency of 200 MHz, setting all necessary defaults. + let mut config = Config::new(ClockConfig::system_freq(200_000_000)); + + // since for the rp235x there is no official support for higher clock frequencies, `system_freq()` will not set a voltage for us. + // We need to guess the core voltage, that is needed for the higher clock frequency. Going with a small increase from the default 1.1V here, based on + // what we know about the RP2040. This is not guaranteed to be correct. + config.clocks.core_voltage = CoreVoltage::V1_15; + + // Initialize the peripherals + let p = embassy_rp::init(config); + + // Show CPU frequency for verification + let sys_freq = clk_sys_freq(); + info!("System clock frequency: {} MHz", sys_freq / 1_000_000); + // Show core voltage for verification + let core_voltage = core_voltage().unwrap(); + info!("Core voltage: {}", Debug2Format(&core_voltage)); + + // LED to indicate the system is running + let mut led = Output::new(p.PIN_25, Level::Low); + + loop { + // Reset the counter at the start of measurement period + let mut counter = 0; + + // Turn LED on while counting + led.set_high(); + + let start = Instant::now(); + + // This is a busy loop that will take some time to complete + while counter < COUNT_TO { + counter += 1; + } + + let elapsed = Instant::now() - start; + + // Report the elapsed time + led.set_low(); + info!( + "At {}Mhz: Elapsed time to count to {}: {}ms", + sys_freq / 1_000_000, + counter, + elapsed.as_millis() + ); + + // Wait 2 seconds before starting the next measurement + Timer::after(Duration::from_secs(2)).await; + } +} diff --git a/tests/rp/src/bin/overclock.rs b/tests/rp/src/bin/overclock.rs index be8e85a3f..a568d7fed 100644 --- a/tests/rp/src/bin/overclock.rs +++ b/tests/rp/src/bin/overclock.rs @@ -7,14 +7,8 @@ teleprobe_meta::target!(b"rpi-pico"); teleprobe_meta::target!(b"pimoroni-pico-plus-2"); use defmt::info; -#[cfg(feature = "rp2040")] -use defmt::{assert, assert_eq}; use embassy_executor::Spawner; -use embassy_rp::clocks; -#[cfg(feature = "rp2040")] -use embassy_rp::clocks::ClockConfig; -#[cfg(feature = "rp2040")] -use embassy_rp::clocks::CoreVoltage; +use embassy_rp::clocks::{clk_sys_freq, core_voltage, ClockConfig, CoreVoltage}; use embassy_rp::config::Config; use embassy_time::Instant; use {defmt_rtt as _, panic_probe as _}; @@ -23,23 +17,26 @@ const COUNT_TO: i64 = 10_000_000; #[embassy_executor::main] async fn main(_spawner: Spawner) { - #[cfg(feature = "rp2040")] let mut config = Config::default(); - #[cfg(not(feature = "rp2040"))] - let config = Config::default(); - // Initialize with 200MHz clock configuration for RP2040, other chips will use default clock - #[cfg(feature = "rp2040")] + // Initialize with 200MHz clock configuration + config.clocks = ClockConfig::system_freq(200_000_000); + + // if we are rp235x, we need to manually set the core voltage. rp2040 should do this automatically + #[cfg(feature = "rp235xb")] { - config.clocks = ClockConfig::system_freq(200_000_000); - let voltage = config.clocks.core_voltage; - assert!(matches!(voltage, CoreVoltage::V1_15), "Expected voltage scale V1_15"); + config.clocks.core_voltage = CoreVoltage::V1_15; } let _p = embassy_rp::init(config); + // We should be at core voltage of 1.15V + assert_eq!(core_voltage().unwrap(), CoreVoltage::V1_15, "Core voltage is not 1.15V"); + // We should be at 200MHz + assert_eq!(clk_sys_freq(), 200_000_000, "System clock frequency is not 200MHz"); + // Test the system speed - let (time_elapsed, clk_sys_freq) = { + let time_elapsed = { let mut counter = 0; let start = Instant::now(); while counter < COUNT_TO { @@ -47,24 +44,26 @@ async fn main(_spawner: Spawner) { } let elapsed = Instant::now() - start; - (elapsed.as_millis(), clocks::clk_sys_freq()) + elapsed.as_millis() }; - // Report the elapsed time, so that the compiler doesn't optimize it away for chips other than RP2040 + // Tests will fail if unused variables are detected: + // Report the elapsed time, so that the compiler doesn't optimize it away for the chip not on test info!( "At {}Mhz: Elapsed time to count to {}: {}ms", - clk_sys_freq / 1_000_000, + clk_sys_freq() / 1_000_000, COUNT_TO, time_elapsed ); + // Check if the elapsed time is within expected limits + // for rp2040 we expect about 600ms #[cfg(feature = "rp2040")] - { - // we should be at 200MHz - assert_eq!(clk_sys_freq, 200_000_000, "System clock frequency is not 200MHz"); - // At 200MHz, the time to count to 10_000_000 should be at 600ms, testing with 1% margin - assert!(time_elapsed <= 606, "Elapsed time is too long"); - } + // allow 1% error + assert!(time_elapsed < 606, "Elapsed time is too long"); + // for rp235x we expect about 450ms + #[cfg(feature = "rp235xb")] + assert!(time_elapsed < 455, "Elapsed time is too long"); cortex_m::asm::bkpt(); } From a0a339d01ade57aa6e66835a27b1e6ea54333b54 Mon Sep 17 00:00:00 2001 From: Matthew Tran <0e4ef622@gmail.com> Date: Thu, 8 May 2025 23:26:10 -0500 Subject: [PATCH 1114/1217] nrf: Rework IPC module --- embassy-nrf/src/ipc.rs | 423 +++++++++++++++++++++-------------------- 1 file changed, 213 insertions(+), 210 deletions(-) diff --git a/embassy-nrf/src/ipc.rs b/embassy-nrf/src/ipc.rs index 410783ef4..a8a08c911 100644 --- a/embassy-nrf/src/ipc.rs +++ b/embassy-nrf/src/ipc.rs @@ -3,18 +3,20 @@ #![macro_use] use core::future::poll_fn; -use core::sync::atomic::{compiler_fence, Ordering}; +use core::marker::PhantomData; use core::task::Poll; -use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; +use embassy_hal_internal::{Peri, PeripheralType}; use embassy_sync::waitqueue::AtomicWaker; -use crate::peripherals::IPC; -use crate::{interrupt, pac}; +use crate::interrupt::typelevel::Interrupt; +use crate::{interrupt, pac, ppi}; + +const EVENT_COUNT: usize = 16; /// IPC Event -#[derive(Debug, Clone, Copy)] -pub enum IpcEvent { +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum EventNumber { /// IPC Event 0 Event0 = 0, /// IPC Event 1 @@ -49,27 +51,27 @@ pub enum IpcEvent { Event15 = 15, } -const EVENTS: [IpcEvent; 16] = [ - IpcEvent::Event0, - IpcEvent::Event1, - IpcEvent::Event2, - IpcEvent::Event3, - IpcEvent::Event4, - IpcEvent::Event5, - IpcEvent::Event6, - IpcEvent::Event7, - IpcEvent::Event8, - IpcEvent::Event9, - IpcEvent::Event10, - IpcEvent::Event11, - IpcEvent::Event12, - IpcEvent::Event13, - IpcEvent::Event14, - IpcEvent::Event15, +const EVENTS: [EventNumber; EVENT_COUNT] = [ + EventNumber::Event0, + EventNumber::Event1, + EventNumber::Event2, + EventNumber::Event3, + EventNumber::Event4, + EventNumber::Event5, + EventNumber::Event6, + EventNumber::Event7, + EventNumber::Event8, + EventNumber::Event9, + EventNumber::Event10, + EventNumber::Event11, + EventNumber::Event12, + EventNumber::Event13, + EventNumber::Event14, + EventNumber::Event15, ]; /// IPC Channel -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum IpcChannel { /// IPC Channel 0 Channel0, @@ -105,188 +107,124 @@ pub enum IpcChannel { Channel15, } -/// Interrupt Handler -pub struct InterruptHandler {} +impl IpcChannel { + fn mask(self) -> u32 { + 1 << (self as u32) + } +} -impl interrupt::typelevel::Handler for InterruptHandler { +/// Interrupt Handler +pub struct InterruptHandler { + _phantom: PhantomData, +} + +impl interrupt::typelevel::Handler for InterruptHandler { unsafe fn on_interrupt() { - let regs = IPC::regs(); + let regs = T::regs(); // Check if an event was generated, and if it was, trigger the corresponding waker for event in EVENTS { if regs.events_receive(event as usize).read() & 0x01 == 0x01 { - // Event is set. Reset and wake waker - regs.events_receive(event as usize).write_value(0); - IPC::state().waker_for(event); + regs.intenclr().write(|w| w.0 = 0x01 << event as u32); + T::state().wakers[event as usize].wake(); } - - // Ensure the state is actually cleared - // Ref: nRF5340 PS v1.5 7.1.9.1 p.153 - compiler_fence(Ordering::SeqCst); - while regs.events_receive(event as usize).read() & 0x01 != 0x00 {} } } } /// IPC driver +#[non_exhaustive] pub struct Ipc<'d, T: Instance> { - _peri: PeripheralRef<'d, T>, -} - -impl<'d, T: Instance> From> for Ipc<'d, T> { - fn from(value: PeripheralRef<'d, T>) -> Self { - Self { _peri: value } - } + /// Event 0 + pub event0: Event<'d, T>, + /// Event 1 + pub event1: Event<'d, T>, + /// Event 2 + pub event2: Event<'d, T>, + /// Event 3 + pub event3: Event<'d, T>, + /// Event 4 + pub event4: Event<'d, T>, + /// Event 5 + pub event5: Event<'d, T>, + /// Event 6 + pub event6: Event<'d, T>, + /// Event 7 + pub event7: Event<'d, T>, + /// Event 8 + pub event8: Event<'d, T>, + /// Event 9 + pub event9: Event<'d, T>, + /// Event 10 + pub event10: Event<'d, T>, + /// Event 11 + pub event11: Event<'d, T>, + /// Event 12 + pub event12: Event<'d, T>, + /// Event 13 + pub event13: Event<'d, T>, + /// Event 14 + pub event14: Event<'d, T>, + /// Event 15 + pub event15: Event<'d, T>, } impl<'d, T: Instance> Ipc<'d, T> { - /// Create IPC driver - pub fn new(ipc: impl Peripheral

+ 'd) -> Self { - into_ref!(ipc); + /// Create a new IPC driver. + pub fn new( + _p: Peri<'d, T>, + _irq: impl interrupt::typelevel::Binding> + 'd, + ) -> Self { + T::Interrupt::unpend(); + unsafe { T::Interrupt::enable() }; - Self { _peri: ipc } - } - - /// Duplicates the peripheral singleton - /// - /// # Safety - /// - /// Ensure manually that only one peripheral is in use at one time - pub unsafe fn clone_unchecked(&self) -> Self { - Self { - _peri: self._peri.clone_unchecked(), - } - } - - /// Configures the sending of events - /// - /// Events can be configured to broadcast on one or multiple IPC channels. - pub fn configure_send_event>(&self, ev: IpcEvent, channels: I) { - let regs = T::regs(); - - regs.send_cnf(ev as usize).write(|w| { - for channel in channels { - match channel { - IpcChannel::Channel0 => w.set_chen0(true), - IpcChannel::Channel1 => w.set_chen1(true), - IpcChannel::Channel2 => w.set_chen2(true), - IpcChannel::Channel3 => w.set_chen3(true), - IpcChannel::Channel4 => w.set_chen4(true), - IpcChannel::Channel5 => w.set_chen5(true), - IpcChannel::Channel6 => w.set_chen6(true), - IpcChannel::Channel7 => w.set_chen7(true), - IpcChannel::Channel8 => w.set_chen8(true), - IpcChannel::Channel9 => w.set_chen9(true), - IpcChannel::Channel10 => w.set_chen10(true), - IpcChannel::Channel11 => w.set_chen11(true), - IpcChannel::Channel12 => w.set_chen12(true), - IpcChannel::Channel13 => w.set_chen13(true), - IpcChannel::Channel14 => w.set_chen14(true), - IpcChannel::Channel15 => w.set_chen15(true), - } - } - }) - } - - /// Configures the receiving of events - /// - /// Events can be configured to be received by one or multiple IPC channels. - pub fn configure_receive_event>(&self, ev: IpcEvent, channels: I) { - let regs = T::regs(); - - regs.receive_cnf(ev as usize).write(|w| { - for channel in channels { - match channel { - IpcChannel::Channel0 => w.set_chen0(true), - IpcChannel::Channel1 => w.set_chen1(true), - IpcChannel::Channel2 => w.set_chen2(true), - IpcChannel::Channel3 => w.set_chen3(true), - IpcChannel::Channel4 => w.set_chen4(true), - IpcChannel::Channel5 => w.set_chen5(true), - IpcChannel::Channel6 => w.set_chen6(true), - IpcChannel::Channel7 => w.set_chen7(true), - IpcChannel::Channel8 => w.set_chen8(true), - IpcChannel::Channel9 => w.set_chen9(true), - IpcChannel::Channel10 => w.set_chen10(true), - IpcChannel::Channel11 => w.set_chen11(true), - IpcChannel::Channel12 => w.set_chen12(true), - IpcChannel::Channel13 => w.set_chen13(true), - IpcChannel::Channel14 => w.set_chen14(true), - IpcChannel::Channel15 => w.set_chen15(true), - } - } - }); - } - - /// Triggers an event - pub fn trigger_event(&self, ev: IpcEvent) { - let regs = T::regs(); - - regs.tasks_send(ev as usize).write_value(0x01); - } - - /// Wait for event to be triggered - pub async fn wait_for_event(&self, ev: IpcEvent) { - let regs = T::regs(); - - // Enable interrupt - match ev { - IpcEvent::Event0 => { - regs.inten().modify(|m| m.set_receive0(true)); - } - IpcEvent::Event1 => { - regs.inten().modify(|m| m.set_receive1(true)); - } - IpcEvent::Event2 => { - regs.inten().modify(|m| m.set_receive2(true)); - } - IpcEvent::Event3 => { - regs.inten().modify(|m| m.set_receive3(true)); - } - IpcEvent::Event4 => { - regs.inten().modify(|m| m.set_receive4(true)); - } - IpcEvent::Event5 => { - regs.inten().modify(|m| m.set_receive5(true)); - } - IpcEvent::Event6 => { - regs.inten().modify(|m| m.set_receive6(true)); - } - IpcEvent::Event7 => { - regs.inten().modify(|m| m.set_receive7(true)); - } - IpcEvent::Event8 => { - regs.inten().modify(|m| m.set_receive8(true)); - } - IpcEvent::Event9 => { - regs.inten().modify(|m| m.set_receive9(true)); - } - IpcEvent::Event10 => { - regs.inten().modify(|m| m.set_receive10(true)); - } - IpcEvent::Event11 => { - regs.inten().modify(|m| m.set_receive11(true)); - } - IpcEvent::Event12 => { - regs.inten().modify(|m| m.set_receive12(true)); - } - IpcEvent::Event13 => { - regs.inten().modify(|m| m.set_receive13(true)); - } - IpcEvent::Event14 => { - regs.inten().modify(|m| m.set_receive14(true)); - } - IpcEvent::Event15 => { - regs.inten().modify(|m| m.set_receive15(true)); - } + let _phantom = PhantomData; + #[rustfmt::skip] + let r = Self { // attributes on expressions are experimental + event0: Event { number: EventNumber::Event0, _phantom }, + event1: Event { number: EventNumber::Event1, _phantom }, + event2: Event { number: EventNumber::Event2, _phantom }, + event3: Event { number: EventNumber::Event3, _phantom }, + event4: Event { number: EventNumber::Event4, _phantom }, + event5: Event { number: EventNumber::Event5, _phantom }, + event6: Event { number: EventNumber::Event6, _phantom }, + event7: Event { number: EventNumber::Event7, _phantom }, + event8: Event { number: EventNumber::Event8, _phantom }, + event9: Event { number: EventNumber::Event9, _phantom }, + event10: Event { number: EventNumber::Event10, _phantom }, + event11: Event { number: EventNumber::Event11, _phantom }, + event12: Event { number: EventNumber::Event12, _phantom }, + event13: Event { number: EventNumber::Event13, _phantom }, + event14: Event { number: EventNumber::Event14, _phantom }, + event15: Event { number: EventNumber::Event15, _phantom }, }; + r + } +} +/// IPC event +pub struct Event<'d, T: Instance> { + number: EventNumber, + _phantom: PhantomData<&'d T>, +} + +impl<'d, T: Instance> Event<'d, T> { + /// Trigger the event. + pub fn trigger(&self) { + let nr = self.number; + T::regs().tasks_send(nr as usize).write_value(1); + } + + /// Wait for the event to be triggered. + pub async fn wait(&mut self) { + let regs = T::regs(); + let nr = self.number as usize; + regs.intenset().write(|w| w.0 = 1 << nr); poll_fn(|cx| { - IPC::state().waker_for(ev).register(cx.waker()); - - if regs.events_receive(ev as usize).read() & 0x01 == 0x01 { - regs.events_receive(ev as usize).write_value(0x00); + T::state().wakers[nr].register(cx.waker()); + if regs.events_receive(nr).read() == 1 { + regs.events_receive(nr).write_value(0x00); Poll::Ready(()) } else { Poll::Pending @@ -294,37 +232,102 @@ impl<'d, T: Instance> Ipc<'d, T> { }) .await; } + + /// Returns the [`EventNumber`] of the event. + pub fn number(&self) -> EventNumber { + self.number + } + + /// Create a handle that can trigger the event. + pub fn trigger_handle(&self) -> EventTrigger<'d, T> { + EventTrigger { + number: self.number, + _phantom: PhantomData, + } + } + + /// Configure the channels the event will broadcast to + pub fn configure_trigger>(&mut self, channels: I) { + T::regs().send_cnf(self.number as usize).write(|w| { + for channel in channels { + w.0 |= channel.mask(); + } + }) + } + + /// Configure the channels the event will listen on + pub fn configure_wait>(&mut self, channels: I) { + T::regs().receive_cnf(self.number as usize).write(|w| { + for channel in channels { + w.0 |= channel.mask(); + } + }); + } + + /// Get the task for the IPC event to use with PPI. + pub fn task(&self) -> ppi::Task<'d> { + let nr = self.number as usize; + let regs = T::regs(); + ppi::Task::from_reg(regs.tasks_send(nr)) + } + + /// Get the event for the IPC event to use with PPI. + pub fn event(&self) -> ppi::Event<'d> { + let nr = self.number as usize; + let regs = T::regs(); + ppi::Event::from_reg(regs.events_receive(nr)) + } + + /// Reborrow into a "child" Event. + /// + /// `self` will stay borrowed until the child Event is dropped. + pub fn reborrow(&mut self) -> Event<'_, T> { + Self { ..*self } + } + + /// Steal an IPC event by number. + /// + /// # Safety + /// + /// The event number must not be in use by another [`Event`]. + pub unsafe fn steal(number: EventNumber) -> Self { + Self { + number, + _phantom: PhantomData, + } + } +} + +/// A handle that can trigger an IPC event. +/// +/// This `struct` is returned by [`Event::trigger_handle`]. +#[derive(Debug, Copy, Clone)] +pub struct EventTrigger<'d, T: Instance> { + number: EventNumber, + _phantom: PhantomData<&'d T>, +} + +impl EventTrigger<'_, T> { + /// Trigger the event. + pub fn trigger(&self) { + let nr = self.number; + T::regs().tasks_send(nr as usize).write_value(1); + } + + /// Returns the [`EventNumber`] of the event. + pub fn number(&self) -> EventNumber { + self.number + } } pub(crate) struct State { - wakers: [AtomicWaker; 16], + wakers: [AtomicWaker; EVENT_COUNT], } impl State { pub(crate) const fn new() -> Self { - const WAKER: AtomicWaker = AtomicWaker::new(); - - Self { wakers: [WAKER; 16] } - } - - const fn waker_for(&self, ev: IpcEvent) -> &AtomicWaker { - match ev { - IpcEvent::Event0 => &self.wakers[0], - IpcEvent::Event1 => &self.wakers[1], - IpcEvent::Event2 => &self.wakers[2], - IpcEvent::Event3 => &self.wakers[3], - IpcEvent::Event4 => &self.wakers[4], - IpcEvent::Event5 => &self.wakers[5], - IpcEvent::Event6 => &self.wakers[6], - IpcEvent::Event7 => &self.wakers[7], - IpcEvent::Event8 => &self.wakers[8], - IpcEvent::Event9 => &self.wakers[9], - IpcEvent::Event10 => &self.wakers[10], - IpcEvent::Event11 => &self.wakers[11], - IpcEvent::Event12 => &self.wakers[12], - IpcEvent::Event13 => &self.wakers[13], - IpcEvent::Event14 => &self.wakers[14], - IpcEvent::Event15 => &self.wakers[15], + Self { + wakers: [const { AtomicWaker::new() }; EVENT_COUNT], } } } @@ -336,7 +339,7 @@ pub(crate) trait SealedInstance { /// IPC peripheral instance. #[allow(private_bounds)] -pub trait Instance: Peripheral

+ SealedInstance + 'static + Send { +pub trait Instance: PeripheralType + SealedInstance + 'static + Send { /// Interrupt for this peripheral. type Interrupt: interrupt::typelevel::Interrupt; } From 133500167ca53cfbc5e9268356753bc0e3f8c209 Mon Sep 17 00:00:00 2001 From: 1-rafael-1 Date: Mon, 12 May 2025 09:45:05 +0200 Subject: [PATCH 1115/1217] limit CoreVoltage eum to values up to 1.30V, because we do not support unlocking higher voltages --- embassy-rp/src/clocks.rs | 141 ++++++--------------------------------- 1 file changed, 21 insertions(+), 120 deletions(-) diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs index ea5e9362b..bcd08c204 100644 --- a/embassy-rp/src/clocks.rs +++ b/embassy-rp/src/clocks.rs @@ -140,6 +140,10 @@ pub enum PeriClkSrc { /// /// The voltage regulator can be configured for different output voltages. /// Higher voltages allow for higher clock frequencies but increase power consumption and heat. +/// +/// **Note**: For RP235x the maximum voltage is 1.30V, unless unlocked by setting unless the voltage limit +/// is disabled using the disable_voltage_limit field in the vreg_ctrl register. For lack of practical use at this +/// point in time, this is not implemented here. So the maximum voltage in this enum is 1.30V for now. #[derive(Clone, Copy, Debug, PartialEq, Eq)] #[repr(u8)] pub enum CoreVoltage { @@ -227,54 +231,6 @@ pub enum CoreVoltage { #[cfg(feature = "_rp235x")] /// RP235x: 1.30V V1_30 = 0b01111, - #[cfg(feature = "_rp235x")] - /// RP235x: 1.35V - V1_35 = 0b10000, - #[cfg(feature = "_rp235x")] - /// RP235x: 1.40V - V1_40 = 0b10001, - #[cfg(feature = "_rp235x")] - /// RP235x: 1.50V - V1_50 = 0b10010, - #[cfg(feature = "_rp235x")] - /// RP235x: 1.60V - V1_60 = 0b10011, - #[cfg(feature = "_rp235x")] - /// RP235x: 1.65V - V1_65 = 0b10100, - #[cfg(feature = "_rp235x")] - /// RP235x: 1.70V - V1_70 = 0b10101, - #[cfg(feature = "_rp235x")] - /// RP235x: 1.80V - V1_80 = 0b10110, - #[cfg(feature = "_rp235x")] - /// RP235x: 1.90V - V1_90 = 0b10111, - #[cfg(feature = "_rp235x")] - /// RP235x: 2.00V - V2_00 = 0b11000, - #[cfg(feature = "_rp235x")] - /// RP235x: 2.35V - V2_35 = 0b11001, - #[cfg(feature = "_rp235x")] - /// RP235x: 2.50V - V2_50 = 0b11010, - #[cfg(feature = "_rp235x")] - /// RP235x: 2.65V - V2_65 = 0b11011, - #[cfg(feature = "_rp235x")] - /// RP235x: 2.80V - V2_80 = 0b11100, - #[cfg(feature = "_rp235x")] - /// RP235x: 3.00V - V3_00 = 0b11101, - #[cfg(feature = "_rp235x")] - /// RP235x: 3.15V - V3_15 = 0b11110, - #[cfg(feature = "_rp235x")] - /// RP235x: 3.30V - V3_30 = 0b11111, } impl CoreVoltage { @@ -313,13 +269,7 @@ impl CoreVoltage { CoreVoltage::V1_20 => 0b01010, // 0.903V (~75% of 1.20V) CoreVoltage::V1_25 => 0b01010, // 0.903V (~72% of 1.25V) CoreVoltage::V1_30 => 0b01011, // 0.946V (~73% of 1.30V) - CoreVoltage::V1_35 => 0b01011, // 0.946V (~70% of 1.35V) - CoreVoltage::V1_40 => 0b01100, // 0.989V (~71% of 1.40V) - CoreVoltage::V1_50 => 0b01101, // 1.032V (~69% of 1.50V) - CoreVoltage::V1_60 => 0b01110, // 1.075V (~67% of 1.60V) - CoreVoltage::V1_65 => 0b01110, // 1.075V (~65% of 1.65V) - CoreVoltage::V1_70 => 0b01111, // 1.118V (~66% of 1.70V) - _ => 0b10000, // the rp2350 datasheet repeats this value for all other core voltages + // all others: 0.946V (see CoreVoltage: we do not support setting Voltages higher than 1.30V at this point) } } } @@ -1083,45 +1033,17 @@ pub(crate) unsafe fn init(config: ClockConfig) { // If the target voltage is different from the current one, we need to change it if target_vsel != current_vsel { + // Set the voltage regulator to the target voltage #[cfg(feature = "rp2040")] - { - // Use modify() to preserve the HIZ and EN bits - otherwise we will disable the regulator when changing voltage - vreg.vreg().modify(|w| w.set_vsel(target_vsel)); - } + vreg.vreg().modify(|w| w.set_vsel(target_vsel)); #[cfg(feature = "_rp235x")] - { - // The rp235x has a different way of controlling the voltage regulator - // Changes to the voltage regulator are protected by a password, see datasheet section 6.4 - // The password is "5AFE" (0x5AFE), it must be set in the top 16 bits of the register - - // The rp235x by default locks the voltage regulator control, so we need to unlock it first - // See datasheet section 6.3.2. Software Control - vreg.vreg_ctrl().modify(|w| { - // Add password to top 16 bits, preserving the rest, repeat below for other registers - w.0 = (w.0 & 0x0000FFFF) | (0x5AFE << 16); - w.set_unlock(true); - *w - }); - - // Set the voltage - vreg.vreg().modify(|w| { - w.0 = (w.0 & 0x0000FFFF) | (0x5AFE << 16); - w.set_vsel(target_vsel); - *w - }); - - // The rp235x has two more registers to set the voltage for low power mode - vreg.vreg_lp_entry().modify(|w| { - w.0 = (w.0 & 0x0000FFFF) | (0x5AFE << 16); - w.set_vsel(target_vsel); - *w - }); - vreg.vreg_lp_exit().modify(|w| { - w.0 = (w.0 & 0x0000FFFF) | (0x5AFE << 16); - w.set_vsel(target_vsel); - *w - }); - } + // For rp235x changes to the voltage regulator are protected by a password, see datasheet section 6.4 Power Management (POWMAN) Registers + // The password is "5AFE" (0x5AFE), it must be set in the top 16 bits of the register + vreg.vreg().modify(|w| { + w.0 = (w.0 & 0x0000FFFF) | (0x5AFE << 16); // Set the password + w.set_vsel(target_vsel); + *w + }); // Wait for the voltage to stabilize. Use the provided delay or default based on voltage let settling_time_us = config.voltage_stabilization_delay_us.unwrap_or_else(|| { @@ -1140,23 +1062,17 @@ pub(crate) unsafe fn init(config: ClockConfig) { } // Only now set the BOD level. At this point the voltage is considered stable. + #[cfg(feature = "rp2040")] vreg.bod().write(|w| { w.set_vsel(voltage.recommended_bod()); w.set_en(true); // Enable brownout detection }); - #[cfg(feature = "_rp235x")] - { - // The rp235x has a separate register for the BOD level in low power mode - vreg.bod_lp_entry().write(|w| { - w.set_vsel(voltage.recommended_bod()); - w.set_en(true); // Enable brownout detection - }); - vreg.bod_lp_exit().write(|w| { - w.set_vsel(voltage.recommended_bod()); - w.set_en(true); // Enable brownout detection - }); - } + vreg.bod().write(|w| { + w.0 = (w.0 & 0x0000FFFF) | (0x5AFE << 16); // Set the password + w.set_vsel(voltage.recommended_bod()); + w.set_en(true); // Enable brownout detection + }); } } @@ -1527,23 +1443,8 @@ pub fn core_voltage() -> Result { 0b01101 => Ok(CoreVoltage::V1_20), 0b01110 => Ok(CoreVoltage::V1_25), 0b01111 => Ok(CoreVoltage::V1_30), - 0b10000 => Ok(CoreVoltage::V1_35), - 0b10001 => Ok(CoreVoltage::V1_40), - 0b10010 => Ok(CoreVoltage::V1_50), - 0b10011 => Ok(CoreVoltage::V1_60), - 0b10100 => Ok(CoreVoltage::V1_65), - 0b10101 => Ok(CoreVoltage::V1_70), - 0b10110 => Ok(CoreVoltage::V1_80), - 0b10111 => Ok(CoreVoltage::V1_90), - 0b11000 => Ok(CoreVoltage::V2_00), - 0b11001 => Ok(CoreVoltage::V2_35), - 0b11010 => Ok(CoreVoltage::V2_50), - 0b11011 => Ok(CoreVoltage::V2_65), - 0b11100 => Ok(CoreVoltage::V2_80), - 0b11101 => Ok(CoreVoltage::V3_00), - 0b11110 => Ok(CoreVoltage::V3_15), - 0b11111 => Ok(CoreVoltage::V3_30), _ => Err("Unexpected value in register"), + // see CoreVoltage: we do not support setting Voltages higher than 1.30V at this point } } } From 3c73b497909ce5bacd16d23e54928a7f66544e09 Mon Sep 17 00:00:00 2001 From: Gerhard de Clercq <11624490+Gerharddc@users.noreply.github.com> Date: Mon, 12 May 2025 15:51:19 +0200 Subject: [PATCH 1116/1217] [embassy-usb-dfu] support function level WinUSB GUIDs This commit makes it possible to provide function level msos GUIDs to usb_dfu. This helps to ensure that composite DFU devices automatically get assigned the WinUSB driver on Windows. --- embassy-usb-dfu/src/application.rs | 16 +++++++++++- embassy-usb-dfu/src/dfu.rs | 16 +++++++++++- .../boot/application/stm32wb-dfu/src/main.rs | 26 +++++++++++++++++-- .../boot/bootloader/stm32wb-dfu/src/main.rs | 15 ++++++++--- 4 files changed, 65 insertions(+), 8 deletions(-) diff --git a/embassy-usb-dfu/src/application.rs b/embassy-usb-dfu/src/application.rs index 6ad07a78c..52a7ca951 100644 --- a/embassy-usb-dfu/src/application.rs +++ b/embassy-usb-dfu/src/application.rs @@ -2,7 +2,7 @@ use embassy_boot::BlockingFirmwareState; use embassy_time::{Duration, Instant}; use embassy_usb::control::{InResponse, OutResponse, Recipient, RequestType}; use embassy_usb::driver::Driver; -use embassy_usb::{Builder, Handler}; +use embassy_usb::{msos, Builder, Handler}; use embedded_storage::nor_flash::NorFlash; use crate::consts::{ @@ -130,8 +130,22 @@ pub fn usb_dfu<'d, D: Driver<'d>, MARK: DfuMarker, RST: Reset>( builder: &mut Builder<'d, D>, handler: &'d mut Control, timeout: Duration, + winusb_guids: Option<&'d [&str]>, ) { let mut func = builder.function(0x00, 0x00, 0x00); + if let Some(winusb_guids) = winusb_guids { + // We add MSOS headers so that the device automatically gets assigned the WinUSB driver on Windows. + // Otherwise users need to do this manually using a tool like Zadig. + // + // Adding them here on the function level appears to only work for compositive devices though. + // For non-composite devices they should be placed on the device level instead. + func.msos_feature(msos::CompatibleIdFeatureDescriptor::new("WINUSB", "")); + func.msos_feature(msos::RegistryPropertyFeatureDescriptor::new( + "DeviceInterfaceGUIDs", + msos::PropertyData::RegMultiSz(winusb_guids), + )); + } + let mut iface = func.interface(); let mut alt = iface.alt_setting(USB_CLASS_APPN_SPEC, APPN_SPEC_SUBCLASS_DFU, DFU_PROTOCOL_RT, None); let timeout = timeout.as_millis() as u16; diff --git a/embassy-usb-dfu/src/dfu.rs b/embassy-usb-dfu/src/dfu.rs index a98d6ab40..83feacaf8 100644 --- a/embassy-usb-dfu/src/dfu.rs +++ b/embassy-usb-dfu/src/dfu.rs @@ -1,7 +1,7 @@ use embassy_boot::{AlignedBuffer, BlockingFirmwareUpdater, FirmwareUpdaterError}; use embassy_usb::control::{InResponse, OutResponse, Recipient, RequestType}; use embassy_usb::driver::Driver; -use embassy_usb::{Builder, Handler}; +use embassy_usb::{msos, Builder, Handler}; use embedded_storage::nor_flash::{NorFlash, NorFlashErrorKind}; use crate::consts::{ @@ -186,8 +186,22 @@ impl<'d, DFU: NorFlash, STATE: NorFlash, RST: Reset, const BLOCK_SIZE: usize> Ha pub fn usb_dfu<'d, D: Driver<'d>, DFU: NorFlash, STATE: NorFlash, RST: Reset, const BLOCK_SIZE: usize>( builder: &mut Builder<'d, D>, handler: &'d mut Control<'d, DFU, STATE, RST, BLOCK_SIZE>, + winusb_guids: Option<&'d [&str]>, ) { let mut func = builder.function(USB_CLASS_APPN_SPEC, APPN_SPEC_SUBCLASS_DFU, DFU_PROTOCOL_DFU); + if let Some(winusb_guids) = winusb_guids { + // We add MSOS headers so that the device automatically gets assigned the WinUSB driver on Windows. + // Otherwise users need to do this manually using a tool like Zadig. + // + // Adding them here on the function level appears to only work for compositive devices though. + // For non-composite devices they should be placed on the device level instead. + func.msos_feature(msos::CompatibleIdFeatureDescriptor::new("WINUSB", "")); + func.msos_feature(msos::RegistryPropertyFeatureDescriptor::new( + "DeviceInterfaceGUIDs", + msos::PropertyData::RegMultiSz(winusb_guids), + )); + } + let mut iface = func.interface(); let mut alt = iface.alt_setting(USB_CLASS_APPN_SPEC, APPN_SPEC_SUBCLASS_DFU, DFU_PROTOCOL_DFU, None); alt.descriptor( diff --git a/examples/boot/application/stm32wb-dfu/src/main.rs b/examples/boot/application/stm32wb-dfu/src/main.rs index dda2b795b..68e9bc3f6 100644 --- a/examples/boot/application/stm32wb-dfu/src/main.rs +++ b/examples/boot/application/stm32wb-dfu/src/main.rs @@ -13,7 +13,7 @@ use embassy_stm32::usb::{self, Driver}; use embassy_stm32::{bind_interrupts, peripherals}; use embassy_sync::blocking_mutex::Mutex; use embassy_time::Duration; -use embassy_usb::Builder; +use embassy_usb::{msos, Builder}; use embassy_usb_dfu::consts::DfuAttributes; use embassy_usb_dfu::{usb_dfu, Control, ResetImmediate}; use panic_reset as _; @@ -22,6 +22,9 @@ bind_interrupts!(struct Irqs { USB_LP => usb::InterruptHandler; }); +// This is a randomly generated GUID to allow clients on Windows to find our device +const DEVICE_INTERFACE_GUIDS: &[&str] = &["{EAA9A5DC-30BA-44BC-9232-606CDC875321}"]; + #[embassy_executor::main] async fn main(_spawner: Spawner) { let mut config = embassy_stm32::Config::default(); @@ -54,7 +57,26 @@ async fn main(_spawner: Spawner) { &mut control_buf, ); - usb_dfu(&mut builder, &mut state, Duration::from_millis(2500)); + // We add MSOS headers so that the device automatically gets assigned the WinUSB driver on Windows. + // Otherwise users need to do this manually using a tool like Zadig. + builder.msos_descriptor(msos::windows_version::WIN8_1, 2); + + // In the case of non-composite devices, it seems that feature headers need to be on the device level. + // (As is implemented here) + // + // For composite devices however, they should be on the function level instead. + // (This is achieved by passing a GUID to the "usb_dfu" function) + builder.msos_feature(msos::CompatibleIdFeatureDescriptor::new("WINUSB", "")); + builder.msos_feature(msos::RegistryPropertyFeatureDescriptor::new( + "DeviceInterfaceGUIDs", + msos::PropertyData::RegMultiSz(DEVICE_INTERFACE_GUIDS), + )); + + // For non-composite devices: + usb_dfu(&mut builder, &mut state, Duration::from_millis(2500), None); + + // Or for composite devices: + // usb_dfu(&mut builder, &mut state, Duration::from_millis(2500), Some(DEVICE_INTERFACE_GUIDS)); let mut dev = builder.build(); dev.run().await diff --git a/examples/boot/bootloader/stm32wb-dfu/src/main.rs b/examples/boot/bootloader/stm32wb-dfu/src/main.rs index 28216806e..2cd7f859d 100644 --- a/examples/boot/bootloader/stm32wb-dfu/src/main.rs +++ b/examples/boot/bootloader/stm32wb-dfu/src/main.rs @@ -67,17 +67,24 @@ fn main() -> ! { // We add MSOS headers so that the device automatically gets assigned the WinUSB driver on Windows. // Otherwise users need to do this manually using a tool like Zadig. - // - // It seems it is important for the DFU class that these headers be on the Device level. - // builder.msos_descriptor(msos::windows_version::WIN8_1, 2); + + // In the case of non-composite devices, it seems that feature headers need to be on the device level. + // (As is implemented here) + // + // For composite devices however, they should be on the function level instead. + // (This is achieved by passing a GUID to the "usb_dfu" function) builder.msos_feature(msos::CompatibleIdFeatureDescriptor::new("WINUSB", "")); builder.msos_feature(msos::RegistryPropertyFeatureDescriptor::new( "DeviceInterfaceGUIDs", msos::PropertyData::RegMultiSz(DEVICE_INTERFACE_GUIDS), )); - usb_dfu::<_, _, _, _, 4096>(&mut builder, &mut state); + // For non-composite devices: + usb_dfu::<_, _, _, _, 4096>(&mut builder, &mut state, None); + + // Or for composite devices: + // usb_dfu::<_, _, _, _, 4096>(&mut builder, &mut state, Some(DEVICE_INTERFACE_GUIDS)); let mut dev = builder.build(); embassy_futures::block_on(dev.run()); From 79e452922a6b467f2e8547a6b28698ed5f409705 Mon Sep 17 00:00:00 2001 From: 1-rafael-1 Date: Mon, 12 May 2025 21:33:47 +0200 Subject: [PATCH 1117/1217] Add ClockError enum and update system_freq to return Result for error handling --- embassy-rp/src/clocks.rs | 66 ++++++++++++++++++++-------- examples/rp/src/bin/overclock.rs | 2 +- examples/rp235x/src/bin/overclock.rs | 2 +- tests/rp/src/bin/overclock.rs | 2 +- 4 files changed, 50 insertions(+), 22 deletions(-) diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs index bcd08c204..5872ef789 100644 --- a/embassy-rp/src/clocks.rs +++ b/embassy-rp/src/clocks.rs @@ -82,6 +82,18 @@ use crate::{pac, reset, Peri}; // be very useful until we have runtime clock reconfiguration. once this // happens we can resurrect the commented-out gpin bits. +/// Clock error types. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum ClockError { + /// PLL failed to lock within the timeout period. + PllLockTimedOut, + /// Could not find valid PLL parameters for system clock. + InvalidPllParameters, + /// Reading the core voltage failed due to an unexpected value in the register. + UnexpectedCoreVoltageRead, +} + struct Clocks { xosc: AtomicU32, sys: AtomicU32, @@ -144,8 +156,9 @@ pub enum PeriClkSrc { /// **Note**: For RP235x the maximum voltage is 1.30V, unless unlocked by setting unless the voltage limit /// is disabled using the disable_voltage_limit field in the vreg_ctrl register. For lack of practical use at this /// point in time, this is not implemented here. So the maximum voltage in this enum is 1.30V for now. -#[derive(Clone, Copy, Debug, PartialEq, Eq)] #[repr(u8)] +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum CoreVoltage { // RP2040 voltage levels #[cfg(feature = "rp2040")] @@ -468,7 +481,7 @@ impl ClockConfig { /// # Returns /// /// A ClockConfig configured to achieve the requested system frequency using the - /// the usual 12Mhz crystal, or panic if no valid parameters can be found. + /// the usual 12Mhz crystal, or an error if no valid parameters can be found. /// /// # Note on core voltage: /// @@ -482,7 +495,11 @@ impl ClockConfig { /// **For RP235x**: /// At this point in time there is no official manufacturer endorsement for running the chip on other core voltages and/or other clock speeds than the defaults. /// Using this function is experimental and may not work as expected or even damage the chip. - pub fn system_freq(hz: u32) -> Self { + /// + /// # Returns + /// + /// A Result containing either the configured ClockConfig or a ClockError. + pub fn system_freq(hz: u32) -> Result { // Start with the standard configuration from crystal() const DEFAULT_CRYSTAL_HZ: u32 = 12_000_000; let mut config = Self::crystal(DEFAULT_CRYSTAL_HZ); @@ -491,16 +508,15 @@ impl ClockConfig { // (which is what crystal() configures by default) #[cfg(feature = "rp2040")] if hz == 125_000_000 { - return config; + return Ok(config); } #[cfg(feature = "_rp235x")] if hz == 150_000_000 { - return config; + return Ok(config); } // Find optimal PLL parameters for the requested frequency - let sys_pll_params = find_pll_params(DEFAULT_CRYSTAL_HZ, hz) - .unwrap_or_else(|| panic!("Could not find valid PLL parameters for system clock")); + let sys_pll_params = find_pll_params(DEFAULT_CRYSTAL_HZ, hz).ok_or(ClockError::InvalidPllParameters)?; // Replace the sys_pll configuration with our custom parameters if let Some(xosc) = &mut config.xosc { @@ -525,7 +541,7 @@ impl ClockConfig { }; } - config + Ok(config) } /// Configure with manual PLL settings for full control over system clock @@ -620,6 +636,7 @@ impl ClockConfig { #[repr(u16)] #[non_exhaustive] #[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum RoscRange { /// Low range. Low = pac::rosc::vals::FreqRange::LOW.0, @@ -726,6 +743,7 @@ pub struct RefClkConfig { /// Reference clock source. #[non_exhaustive] #[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum RefClkSrc { /// XOSC. Xosc, @@ -741,6 +759,7 @@ pub enum RefClkSrc { /// SYS clock source. #[non_exhaustive] #[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum SysClkSrc { /// REF. Ref, @@ -779,6 +798,7 @@ pub struct SysClkConfig { #[repr(u8)] #[non_exhaustive] #[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum UsbClkSrc { /// PLL USB. PllUsb = ClkUsbCtrlAuxsrc::CLKSRC_PLL_USB as _, @@ -807,6 +827,7 @@ pub struct UsbClkConfig { #[repr(u8)] #[non_exhaustive] #[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum AdcClkSrc { /// PLL USB. PllUsb = ClkAdcCtrlAuxsrc::CLKSRC_PLL_USB as _, @@ -835,6 +856,7 @@ pub struct AdcClkConfig { #[repr(u8)] #[non_exhaustive] #[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg(feature = "rp2040")] pub enum RtcClkSrc { /// PLL USB. @@ -1084,14 +1106,20 @@ pub(crate) unsafe fn init(config: ClockConfig) { let pll_sys_freq = match config.sys_pll { Some(sys_pll_config) => match configure_pll(pac::PLL_SYS, config.hz, sys_pll_config) { Ok(freq) => freq, + #[cfg(feature = "defmt")] Err(e) => panic!("Failed to configure PLL_SYS: {}", e), + #[cfg(not(feature = "defmt"))] + Err(_e) => panic!("Failed to configure PLL_SYS"), }, None => 0, }; let pll_usb_freq = match config.usb_pll { Some(usb_pll_config) => match configure_pll(pac::PLL_USB, config.hz, usb_pll_config) { Ok(freq) => freq, + #[cfg(feature = "defmt")] Err(e) => panic!("Failed to configure PLL_USB: {}", e), + #[cfg(not(feature = "defmt"))] + Err(_e) => panic!("Failed to configure PLL_USB"), }, None => 0, }; @@ -1401,7 +1429,7 @@ pub fn clk_rtc_freq() -> u16 { /// /// Returns the current core voltage or an error if the voltage register /// contains an unknown value. -pub fn core_voltage() -> Result { +pub fn core_voltage() -> Result { #[cfg(feature = "rp2040")] { let vreg = pac::VREG_AND_CHIP_RESET; @@ -1418,7 +1446,7 @@ pub fn core_voltage() -> Result { 0b1101 => Ok(CoreVoltage::V1_20), 0b1110 => Ok(CoreVoltage::V1_25), 0b1111 => Ok(CoreVoltage::V1_30), - _ => Err("Unexpected value in register"), + _ => Err(ClockError::UnexpectedCoreVoltageRead), } } @@ -1443,7 +1471,7 @@ pub fn core_voltage() -> Result { 0b01101 => Ok(CoreVoltage::V1_20), 0b01110 => Ok(CoreVoltage::V1_25), 0b01111 => Ok(CoreVoltage::V1_30), - _ => Err("Unexpected value in register"), + _ => Err(ClockError::UnexpectedCoreVoltageRead), // see CoreVoltage: we do not support setting Voltages higher than 1.30V at this point } } @@ -1461,7 +1489,7 @@ fn start_xosc(crystal_hz: u32, delay_multiplier: u32) { /// PLL (Phase-Locked Loop) configuration #[inline(always)] -fn configure_pll(p: pac::pll::Pll, input_freq: u32, config: PllConfig) -> Result { +fn configure_pll(p: pac::pll::Pll, input_freq: u32, config: PllConfig) -> Result { // Calculate reference frequency let ref_freq = input_freq / config.refdiv as u32; @@ -1532,7 +1560,7 @@ fn configure_pll(p: pac::pll::Pll, input_freq: u32, config: PllConfig) -> Result timeout -= 1; if timeout == 0 { // PLL failed to lock, return 0 to indicate failure - return Err("PLL failed to lock"); + return Err(ClockError::PllLockTimedOut); } } @@ -2103,21 +2131,21 @@ mod tests { { // Test automatic voltage scaling based on frequency // Under 133 MHz should use default voltage (V1_10) - let config = ClockConfig::system_freq(125_000_000); + let config = ClockConfig::system_freq(125_000_000).unwrap(); assert_eq!(config.core_voltage, CoreVoltage::V1_10); // 133-200 MHz should use V1_15 - let config = ClockConfig::system_freq(150_000_000); + let config = ClockConfig::system_freq(150_000_000).unwrap(); assert_eq!(config.core_voltage, CoreVoltage::V1_15); - let config = ClockConfig::system_freq(200_000_000); + let config = ClockConfig::system_freq(200_000_000).unwrap(); assert_eq!(config.core_voltage, CoreVoltage::V1_15); - // Above 200 MHz should use V1_25 - let config = ClockConfig::system_freq(250_000_000); + // Above 200 MHz should use V1_15 + let config = ClockConfig::system_freq(250_000_000).unwrap(); assert_eq!(config.core_voltage, CoreVoltage::V1_15); // Below 125 MHz should use V1_10 - let config = ClockConfig::system_freq(100_000_000); + let config = ClockConfig::system_freq(100_000_000).unwrap(); assert_eq!(config.core_voltage, CoreVoltage::V1_10); } } diff --git a/examples/rp/src/bin/overclock.rs b/examples/rp/src/bin/overclock.rs index 89147ba42..2706399af 100644 --- a/examples/rp/src/bin/overclock.rs +++ b/examples/rp/src/bin/overclock.rs @@ -18,7 +18,7 @@ const COUNT_TO: i64 = 10_000_000; #[embassy_executor::main] async fn main(_spawner: Spawner) -> ! { // Set up for clock frequency of 200 MHz, setting all necessary defaults. - let config = Config::new(ClockConfig::system_freq(200_000_000)); + let config = Config::new(ClockConfig::system_freq(200_000_000).unwrap()); // Initialize the peripherals let p = embassy_rp::init(config); diff --git a/examples/rp235x/src/bin/overclock.rs b/examples/rp235x/src/bin/overclock.rs index 8713df688..178fd62ca 100644 --- a/examples/rp235x/src/bin/overclock.rs +++ b/examples/rp235x/src/bin/overclock.rs @@ -23,7 +23,7 @@ const COUNT_TO: i64 = 10_000_000; #[embassy_executor::main] async fn main(_spawner: Spawner) -> ! { // Set up for clock frequency of 200 MHz, setting all necessary defaults. - let mut config = Config::new(ClockConfig::system_freq(200_000_000)); + let mut config = Config::new(ClockConfig::system_freq(200_000_000).unwrap()); // since for the rp235x there is no official support for higher clock frequencies, `system_freq()` will not set a voltage for us. // We need to guess the core voltage, that is needed for the higher clock frequency. Going with a small increase from the default 1.1V here, based on diff --git a/tests/rp/src/bin/overclock.rs b/tests/rp/src/bin/overclock.rs index a568d7fed..167a26eb2 100644 --- a/tests/rp/src/bin/overclock.rs +++ b/tests/rp/src/bin/overclock.rs @@ -20,7 +20,7 @@ async fn main(_spawner: Spawner) { let mut config = Config::default(); // Initialize with 200MHz clock configuration - config.clocks = ClockConfig::system_freq(200_000_000); + config.clocks = ClockConfig::system_freq(200_000_000).unwrap(); // if we are rp235x, we need to manually set the core voltage. rp2040 should do this automatically #[cfg(feature = "rp235xb")] From be1b679d48b5d781f888fb97c1fed7479235019b Mon Sep 17 00:00:00 2001 From: 1-rafael-1 Date: Mon, 12 May 2025 21:42:03 +0200 Subject: [PATCH 1118/1217] Refactor CoreVoltage enum, separate for rp2040 and rp235x --- embassy-rp/src/clocks.rs | 98 +++++++++++++++++----------------------- 1 file changed, 42 insertions(+), 56 deletions(-) diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs index 5872ef789..3975e7e79 100644 --- a/embassy-rp/src/clocks.rs +++ b/embassy-rp/src/clocks.rs @@ -156,93 +156,79 @@ pub enum PeriClkSrc { /// **Note**: For RP235x the maximum voltage is 1.30V, unless unlocked by setting unless the voltage limit /// is disabled using the disable_voltage_limit field in the vreg_ctrl register. For lack of practical use at this /// point in time, this is not implemented here. So the maximum voltage in this enum is 1.30V for now. +#[cfg(feature = "rp2040")] #[repr(u8)] #[derive(Clone, Copy, Debug, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum CoreVoltage { - // RP2040 voltage levels - #[cfg(feature = "rp2040")] - /// RP2040: 0.80V + /// 0.80V V0_80 = 0b0000, - #[cfg(feature = "rp2040")] - /// RP2040: 0.85V + /// 0.85V V0_85 = 0b0110, - #[cfg(feature = "rp2040")] - /// RP2040: 0.90V + /// 0.90V V0_90 = 0b0111, - #[cfg(feature = "rp2040")] - /// RP2040: 0.95V + /// 0.95V V0_95 = 0b1000, - #[cfg(feature = "rp2040")] - /// RP2040: 1.00V + /// 1.00V V1_00 = 0b1001, - #[cfg(feature = "rp2040")] - /// RP2040: 1.05V + /// 1.05V V1_05 = 0b1010, - #[cfg(feature = "rp2040")] - /// RP2040: 1.10V - Default voltage level + /// 1.10V - Default voltage level V1_10 = 0b1011, - #[cfg(feature = "rp2040")] - /// RP2040: 1.15V - Required for overclocking to 133-200MHz + /// 1.15V - Required for overclocking to 133-200MHz V1_15 = 0b1100, - #[cfg(feature = "rp2040")] - /// RP2040: 1.20V + /// 1.20V V1_20 = 0b1101, - #[cfg(feature = "rp2040")] - /// RP2040: 1.25V + /// 1.25V V1_25 = 0b1110, - #[cfg(feature = "rp2040")] - /// RP2040: 1.30V + /// 1.30V V1_30 = 0b1111, +} - // RP235x voltage levels - #[cfg(feature = "_rp235x")] - /// RP235x: 0.55V +/// Core voltage regulator settings. +/// +/// The voltage regulator can be configured for different output voltages. +/// Higher voltages allow for higher clock frequencies but increase power consumption and heat. +/// +/// **Note**: For RP235x the maximum voltage is 1.30V, unless unlocked by setting unless the voltage limit +/// is disabled using the disable_voltage_limit field in the vreg_ctrl register. For lack of practical use at this +/// point in time, this is not implemented here. So the maximum voltage in this enum is 1.30V for now. +#[cfg(feature = "_rp235x")] +#[repr(u8)] +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum CoreVoltage { + /// 0.55V V0_55 = 0b00000, - #[cfg(feature = "_rp235x")] - /// RP235x: 0.60V + /// 0.60V V0_60 = 0b00001, - #[cfg(feature = "_rp235x")] - /// RP235x: 0.65V + /// 0.65V V0_65 = 0b00010, - #[cfg(feature = "_rp235x")] - /// RP235x: 0.70V + /// 0.70V V0_70 = 0b00011, - #[cfg(feature = "_rp235x")] - /// RP235x: 0.75V + /// 0.75V V0_75 = 0b00100, - #[cfg(feature = "_rp235x")] - /// RP235x: 0.80V + /// 0.80V V0_80 = 0b00101, - #[cfg(feature = "_rp235x")] - /// RP235x: 0.85V + /// 0.85V V0_85 = 0b00110, - #[cfg(feature = "_rp235x")] - /// RP235x: 0.90V + /// 0.90V V0_90 = 0b00111, - #[cfg(feature = "_rp235x")] - /// RP235x: 0.95V + /// 0.95V V0_95 = 0b01000, - #[cfg(feature = "_rp235x")] - /// RP235x: 1.00V + /// 1.00V V1_00 = 0b01001, - #[cfg(feature = "_rp235x")] - /// RP235x: 1.05V + /// 1.05V V1_05 = 0b01010, - #[cfg(feature = "_rp235x")] - /// RP235x: 1.10V - Default voltage level + /// 1.10V - Default voltage level V1_10 = 0b01011, - #[cfg(feature = "_rp235x")] - /// RP235x: 1.15V + /// 1.15V V1_15 = 0b01100, - #[cfg(feature = "_rp235x")] - /// RP235x: 1.20V + /// 1.20V V1_20 = 0b01101, - #[cfg(feature = "_rp235x")] - /// RP235x: 1.25V + /// 1.25V V1_25 = 0b01110, - #[cfg(feature = "_rp235x")] - /// RP235x: 1.30V + /// 1.30V V1_30 = 0b01111, } From abafbed0d5fba70ab5d0096b9d381577d2f880c8 Mon Sep 17 00:00:00 2001 From: 1-rafael-1 Date: Mon, 12 May 2025 21:43:17 +0200 Subject: [PATCH 1119/1217] remove Debug2Fmt from examples --- examples/rp/src/bin/overclock.rs | 2 +- examples/rp/src/bin/overclock_manual.rs | 2 +- examples/rp235x/src/bin/overclock.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/rp/src/bin/overclock.rs b/examples/rp/src/bin/overclock.rs index 2706399af..83b17308b 100644 --- a/examples/rp/src/bin/overclock.rs +++ b/examples/rp/src/bin/overclock.rs @@ -28,7 +28,7 @@ async fn main(_spawner: Spawner) -> ! { info!("System clock frequency: {} MHz", sys_freq / 1_000_000); // Show core voltage for verification let core_voltage = core_voltage().unwrap(); - info!("Core voltage: {}", Debug2Format(&core_voltage)); + info!("Core voltage: {}", core_voltage); // LED to indicate the system is running let mut led = Output::new(p.PIN_25, Level::Low); diff --git a/examples/rp/src/bin/overclock_manual.rs b/examples/rp/src/bin/overclock_manual.rs index 88ef26a7a..dea5cfb3c 100644 --- a/examples/rp/src/bin/overclock_manual.rs +++ b/examples/rp/src/bin/overclock_manual.rs @@ -45,7 +45,7 @@ async fn main(_spawner: Spawner) -> ! { info!("System clock frequency: {} MHz", sys_freq / 1_000_000); // Show core voltage for verification let core_voltage = core_voltage().unwrap(); - info!("Core voltage: {}", Debug2Format(&core_voltage)); + info!("Core voltage: {}", core_voltage); // LED to indicate the system is running let mut led = Output::new(p.PIN_25, Level::Low); diff --git a/examples/rp235x/src/bin/overclock.rs b/examples/rp235x/src/bin/overclock.rs index 178fd62ca..5fd97ef97 100644 --- a/examples/rp235x/src/bin/overclock.rs +++ b/examples/rp235x/src/bin/overclock.rs @@ -38,7 +38,7 @@ async fn main(_spawner: Spawner) -> ! { info!("System clock frequency: {} MHz", sys_freq / 1_000_000); // Show core voltage for verification let core_voltage = core_voltage().unwrap(); - info!("Core voltage: {}", Debug2Format(&core_voltage)); + info!("Core voltage: {}", core_voltage); // LED to indicate the system is running let mut led = Output::new(p.PIN_25, Level::Low); From 1314808b3a39d856d33655504db00d799914c440 Mon Sep 17 00:00:00 2001 From: 1-rafael-1 Date: Tue, 13 May 2025 10:49:23 +0200 Subject: [PATCH 1120/1217] Changes after review: copypasted doc comment fixed and no cfg gates to panic on failing pll config in init() --- embassy-rp/src/clocks.rs | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs index 3975e7e79..47e71c448 100644 --- a/embassy-rp/src/clocks.rs +++ b/embassy-rp/src/clocks.rs @@ -152,11 +152,6 @@ pub enum PeriClkSrc { /// /// The voltage regulator can be configured for different output voltages. /// Higher voltages allow for higher clock frequencies but increase power consumption and heat. -/// -/// **Note**: For RP235x the maximum voltage is 1.30V, unless unlocked by setting unless the voltage limit -/// is disabled using the disable_voltage_limit field in the vreg_ctrl register. For lack of practical use at this -/// point in time, this is not implemented here. So the maximum voltage in this enum is 1.30V for now. -#[cfg(feature = "rp2040")] #[repr(u8)] #[derive(Clone, Copy, Debug, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -190,7 +185,7 @@ pub enum CoreVoltage { /// The voltage regulator can be configured for different output voltages. /// Higher voltages allow for higher clock frequencies but increase power consumption and heat. /// -/// **Note**: For RP235x the maximum voltage is 1.30V, unless unlocked by setting unless the voltage limit +/// **Note**: The maximum voltage is 1.30V, unless unlocked by setting unless the voltage limit /// is disabled using the disable_voltage_limit field in the vreg_ctrl register. For lack of practical use at this /// point in time, this is not implemented here. So the maximum voltage in this enum is 1.30V for now. #[cfg(feature = "_rp235x")] @@ -1092,20 +1087,14 @@ pub(crate) unsafe fn init(config: ClockConfig) { let pll_sys_freq = match config.sys_pll { Some(sys_pll_config) => match configure_pll(pac::PLL_SYS, config.hz, sys_pll_config) { Ok(freq) => freq, - #[cfg(feature = "defmt")] - Err(e) => panic!("Failed to configure PLL_SYS: {}", e), - #[cfg(not(feature = "defmt"))] - Err(_e) => panic!("Failed to configure PLL_SYS"), + Err(e) => panic!("Failed to configure PLL_SYS: {:?}", e), }, None => 0, }; let pll_usb_freq = match config.usb_pll { Some(usb_pll_config) => match configure_pll(pac::PLL_USB, config.hz, usb_pll_config) { Ok(freq) => freq, - #[cfg(feature = "defmt")] - Err(e) => panic!("Failed to configure PLL_USB: {}", e), - #[cfg(not(feature = "defmt"))] - Err(_e) => panic!("Failed to configure PLL_USB"), + Err(e) => panic!("Failed to configure PLL_USB: {:?}", e), }, None => 0, }; From 981ef20f83ec88601818d8c55f69a1037d57b0cb Mon Sep 17 00:00:00 2001 From: 1-rafael-1 Date: Tue, 13 May 2025 10:59:11 +0200 Subject: [PATCH 1121/1217] removed one line too many --- embassy-rp/src/clocks.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs index 47e71c448..857877680 100644 --- a/embassy-rp/src/clocks.rs +++ b/embassy-rp/src/clocks.rs @@ -152,6 +152,7 @@ pub enum PeriClkSrc { /// /// The voltage regulator can be configured for different output voltages. /// Higher voltages allow for higher clock frequencies but increase power consumption and heat. +#[cfg(feature = "rp2040")] #[repr(u8)] #[derive(Clone, Copy, Debug, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] From 46e25cbc5ff62e24f86574d7ae5d872aa0c2595d Mon Sep 17 00:00:00 2001 From: Gerhard de Clercq <11624490+Gerharddc@users.noreply.github.com> Date: Tue, 13 May 2025 15:09:53 +0200 Subject: [PATCH 1122/1217] [embassy-usb-dfu] correct comment about composite devices --- embassy-usb-dfu/src/application.rs | 5 +++-- embassy-usb-dfu/src/dfu.rs | 5 +++-- examples/boot/application/stm32wb-dfu/src/main.rs | 10 ++++------ examples/boot/bootloader/stm32wb-dfu/src/main.rs | 10 ++++------ 4 files changed, 14 insertions(+), 16 deletions(-) diff --git a/embassy-usb-dfu/src/application.rs b/embassy-usb-dfu/src/application.rs index 52a7ca951..2646d100d 100644 --- a/embassy-usb-dfu/src/application.rs +++ b/embassy-usb-dfu/src/application.rs @@ -137,8 +137,9 @@ pub fn usb_dfu<'d, D: Driver<'d>, MARK: DfuMarker, RST: Reset>( // We add MSOS headers so that the device automatically gets assigned the WinUSB driver on Windows. // Otherwise users need to do this manually using a tool like Zadig. // - // Adding them here on the function level appears to only work for compositive devices though. - // For non-composite devices they should be placed on the device level instead. + // Adding them here on the function level appears to only be needed for compositive devices. + // In addition to being on the function level, they should also be added to the device level. + // func.msos_feature(msos::CompatibleIdFeatureDescriptor::new("WINUSB", "")); func.msos_feature(msos::RegistryPropertyFeatureDescriptor::new( "DeviceInterfaceGUIDs", diff --git a/embassy-usb-dfu/src/dfu.rs b/embassy-usb-dfu/src/dfu.rs index 83feacaf8..43a35637d 100644 --- a/embassy-usb-dfu/src/dfu.rs +++ b/embassy-usb-dfu/src/dfu.rs @@ -193,8 +193,9 @@ pub fn usb_dfu<'d, D: Driver<'d>, DFU: NorFlash, STATE: NorFlash, RST: Reset, co // We add MSOS headers so that the device automatically gets assigned the WinUSB driver on Windows. // Otherwise users need to do this manually using a tool like Zadig. // - // Adding them here on the function level appears to only work for compositive devices though. - // For non-composite devices they should be placed on the device level instead. + // Adding them here on the function level appears to only be needed for compositive devices. + // In addition to being on the function level, they should also be added to the device level. + // func.msos_feature(msos::CompatibleIdFeatureDescriptor::new("WINUSB", "")); func.msos_feature(msos::RegistryPropertyFeatureDescriptor::new( "DeviceInterfaceGUIDs", diff --git a/examples/boot/application/stm32wb-dfu/src/main.rs b/examples/boot/application/stm32wb-dfu/src/main.rs index 68e9bc3f6..6236dfe52 100644 --- a/examples/boot/application/stm32wb-dfu/src/main.rs +++ b/examples/boot/application/stm32wb-dfu/src/main.rs @@ -59,13 +59,11 @@ async fn main(_spawner: Spawner) { // We add MSOS headers so that the device automatically gets assigned the WinUSB driver on Windows. // Otherwise users need to do this manually using a tool like Zadig. - builder.msos_descriptor(msos::windows_version::WIN8_1, 2); - - // In the case of non-composite devices, it seems that feature headers need to be on the device level. - // (As is implemented here) // - // For composite devices however, they should be on the function level instead. - // (This is achieved by passing a GUID to the "usb_dfu" function) + // It seems these always need to be at added at the device level for this to work and for + // composite devices they also need to be added on the function level (as shown later). + // + builder.msos_descriptor(msos::windows_version::WIN8_1, 2); builder.msos_feature(msos::CompatibleIdFeatureDescriptor::new("WINUSB", "")); builder.msos_feature(msos::RegistryPropertyFeatureDescriptor::new( "DeviceInterfaceGUIDs", diff --git a/examples/boot/bootloader/stm32wb-dfu/src/main.rs b/examples/boot/bootloader/stm32wb-dfu/src/main.rs index 2cd7f859d..8cfd4daa7 100644 --- a/examples/boot/bootloader/stm32wb-dfu/src/main.rs +++ b/examples/boot/bootloader/stm32wb-dfu/src/main.rs @@ -67,13 +67,11 @@ fn main() -> ! { // We add MSOS headers so that the device automatically gets assigned the WinUSB driver on Windows. // Otherwise users need to do this manually using a tool like Zadig. - builder.msos_descriptor(msos::windows_version::WIN8_1, 2); - - // In the case of non-composite devices, it seems that feature headers need to be on the device level. - // (As is implemented here) // - // For composite devices however, they should be on the function level instead. - // (This is achieved by passing a GUID to the "usb_dfu" function) + // It seems these always need to be at added at the device level for this to work and for + // composite devices they also need to be added on the function level (as shown later). + // + builder.msos_descriptor(msos::windows_version::WIN8_1, 2); builder.msos_feature(msos::CompatibleIdFeatureDescriptor::new("WINUSB", "")); builder.msos_feature(msos::RegistryPropertyFeatureDescriptor::new( "DeviceInterfaceGUIDs", From edcbfeb15257e93557a73b9aac3a8ee92a273e32 Mon Sep 17 00:00:00 2001 From: Marvin Gudel Date: Tue, 13 May 2025 22:36:28 +0200 Subject: [PATCH 1123/1217] Make bit-depth of I2S PIO program configurable Also the channel argument is removed, since only 2 channels are supported. --- embassy-rp/src/pio_programs/i2s.rs | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/embassy-rp/src/pio_programs/i2s.rs b/embassy-rp/src/pio_programs/i2s.rs index b967f0160..7ceed3fa6 100644 --- a/embassy-rp/src/pio_programs/i2s.rs +++ b/embassy-rp/src/pio_programs/i2s.rs @@ -9,6 +9,10 @@ use crate::pio::{ use crate::Peri; /// This struct represents an i2s output driver program +/// +/// The sample bit-depth is set through scratch register `Y`. +/// `Y` has to be set to sample bit-depth - 2. +/// (14 = 16bit, 22 = 24bit, 30 = 32bit) pub struct PioI2sOutProgram<'d, PIO: Instance> { prg: LoadedProgram<'d, PIO>, } @@ -17,13 +21,13 @@ impl<'d, PIO: Instance> PioI2sOutProgram<'d, PIO> { /// Load the program into the given pio pub fn new(common: &mut Common<'d, PIO>) -> Self { let prg = pio::pio_asm!( - ".side_set 2", - " set x, 14 side 0b01", // side 0bWB - W = Word Clock, B = Bit Clock + ".side_set 2", // side 0bWB - W = Word Clock, B = Bit Clock + " mov x, y side 0b01", // y stores sample depth - 2 (14 = 16bit, 22 = 24bit, 30 = 32bit) "left_data:", " out pins, 1 side 0b00", " jmp x-- left_data side 0b01", " out pins 1 side 0b10", - " set x, 14 side 0b11", + " mov x, y side 0b11", "right_data:", " out pins 1 side 0b10", " jmp x-- right_data side 0b11", @@ -53,7 +57,6 @@ impl<'d, P: Instance, const S: usize> PioI2sOut<'d, P, S> { lr_clock_pin: Peri<'d, impl PioPin>, sample_rate: u32, bit_depth: u32, - channels: u32, program: &PioI2sOutProgram<'d, P>, ) -> Self { let data_pin = common.make_pio_pin(data_pin); @@ -64,7 +67,7 @@ impl<'d, P: Instance, const S: usize> PioI2sOut<'d, P, S> { let mut cfg = Config::default(); cfg.use_program(&program.prg, &[&bit_clock_pin, &left_right_clock_pin]); cfg.set_out_pins(&[&data_pin]); - let clock_frequency = sample_rate * bit_depth * channels; + let clock_frequency = sample_rate * bit_depth * 2; cfg.clock_divider = (crate::clocks::clk_sys_freq() as f64 / clock_frequency as f64 / 2.).to_fixed(); cfg.shift_out = ShiftConfig { threshold: 32, @@ -78,6 +81,11 @@ impl<'d, P: Instance, const S: usize> PioI2sOut<'d, P, S> { sm.set_config(&cfg); sm.set_pin_dirs(Direction::Out, &[&data_pin, &left_right_clock_pin, &bit_clock_pin]); + // Set the `y` register up to configure the sample depth + // The SM counts down to 0 and uses one clock cycle to set up the counter, + // which results in bit_depth - 2 as register value. + unsafe { sm.set_y(bit_depth - 2) }; + sm.set_enable(true); Self { dma: dma.into(), sm } From fd9ed3924c5a7c4ef4f9bc4b8a4f934ad2bcc486 Mon Sep 17 00:00:00 2001 From: Marvin Gudel Date: Tue, 13 May 2025 22:49:35 +0200 Subject: [PATCH 1124/1217] Fix example --- examples/rp/src/bin/pio_i2s.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/examples/rp/src/bin/pio_i2s.rs b/examples/rp/src/bin/pio_i2s.rs index 192c8f854..695a74cc3 100644 --- a/examples/rp/src/bin/pio_i2s.rs +++ b/examples/rp/src/bin/pio_i2s.rs @@ -27,7 +27,6 @@ bind_interrupts!(struct Irqs { const SAMPLE_RATE: u32 = 48_000; const BIT_DEPTH: u32 = 16; -const CHANNELS: u32 = 2; #[embassy_executor::main] async fn main(_spawner: Spawner) { @@ -50,7 +49,6 @@ async fn main(_spawner: Spawner) { left_right_clock_pin, SAMPLE_RATE, BIT_DEPTH, - CHANNELS, &program, ); From 58383465d52b45016f88aa6af081f60d67d2b123 Mon Sep 17 00:00:00 2001 From: Marvin Gudel Date: Tue, 13 May 2025 23:30:55 +0200 Subject: [PATCH 1125/1217] Fix example for rp235x --- examples/rp235x/src/bin/pio_i2s.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/examples/rp235x/src/bin/pio_i2s.rs b/examples/rp235x/src/bin/pio_i2s.rs index 5a4bcfcac..cfcb0221d 100644 --- a/examples/rp235x/src/bin/pio_i2s.rs +++ b/examples/rp235x/src/bin/pio_i2s.rs @@ -27,7 +27,6 @@ bind_interrupts!(struct Irqs { const SAMPLE_RATE: u32 = 48_000; const BIT_DEPTH: u32 = 16; -const CHANNELS: u32 = 2; #[embassy_executor::main] async fn main(_spawner: Spawner) { @@ -50,7 +49,6 @@ async fn main(_spawner: Spawner) { left_right_clock_pin, SAMPLE_RATE, BIT_DEPTH, - CHANNELS, &program, ); From f41e8c45f68ca31819ea1b1eae5fbd019bf8f318 Mon Sep 17 00:00:00 2001 From: i509VCB Date: Tue, 13 May 2025 21:55:50 -0500 Subject: [PATCH 1126/1217] mspm0: generate feature per chip + package --- ci.sh | 10 +- embassy-mspm0/Cargo.toml | 140 +++++++++++++++++++++++++-- embassy-mspm0/README.md | 28 ++++++ embassy-mspm0/build.rs | 87 +++++++++++++++-- embassy-mspm0/src/gpio.rs | 4 +- embassy-mspm0/src/int_group/g150x.rs | 51 ++++++++++ embassy-mspm0/src/lib.rs | 17 ++-- examples/mspm0c1104/Cargo.toml | 2 +- examples/mspm0c1104/README.md | 4 +- examples/mspm0g3507/Cargo.toml | 2 +- examples/mspm0g3507/README.md | 4 +- examples/mspm0g3519/Cargo.toml | 2 +- examples/mspm0g3519/README.md | 4 +- examples/mspm0l1306/Cargo.toml | 2 +- examples/mspm0l1306/README.md | 4 +- examples/mspm0l2228/Cargo.toml | 2 +- examples/mspm0l2228/README.md | 4 +- tests/mspm0/Cargo.toml | 2 +- 18 files changed, 326 insertions(+), 43 deletions(-) create mode 100644 embassy-mspm0/README.md create mode 100644 embassy-mspm0/src/int_group/g150x.rs diff --git a/ci.sh b/ci.sh index 6e320e4d1..4e48778da 100755 --- a/ci.sh +++ b/ci.sh @@ -174,11 +174,11 @@ cargo batch \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32u073mb,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32u083rc,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-nxp/Cargo.toml --target thumbv8m.main-none-eabihf \ - --- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0c110x,defmt,time-driver-any \ - --- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0g350x,defmt,time-driver-any \ - --- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0g351x,defmt,time-driver-any \ - --- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0l130x,defmt,time-driver-any \ - --- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0l222x,defmt,time-driver-any \ + --- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0c1104dgs20,defmt,time-driver-any \ + --- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0g3507pm,defmt,time-driver-any \ + --- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0g3519pz,defmt,time-driver-any \ + --- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0l1306rhb,defmt,time-driver-any \ + --- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0l2228pn,defmt,time-driver-any \ --- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features ''\ --- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'log' \ --- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'defmt' \ diff --git a/embassy-mspm0/Cargo.toml b/embassy-mspm0/Cargo.toml index df996ff4b..79feee0c2 100644 --- a/embassy-mspm0/Cargo.toml +++ b/embassy-mspm0/Cargo.toml @@ -46,14 +46,14 @@ cortex-m = "0.7.6" critical-section = "1.2.0" # mspm0-metapac = { version = "" } -mspm0-metapac = { git = "https://github.com/mspm0-rs/mspm0-data-generated/", tag = "mspm0-data-119240dd23ef5748d2a7bef219ca298d37ba604a" } +mspm0-metapac = { git = "https://github.com/mspm0-rs/mspm0-data-generated/", tag = "mspm0-data-66a55c7bf38a2201ff48c299843e741f2d537f0b" } [build-dependencies] proc-macro2 = "1.0.94" quote = "1.0.40" # mspm0-metapac = { version = "", default-features = false, features = ["metadata"] } -mspm0-metapac = { git = "https://github.com/mspm0-rs/mspm0-data-generated/", tag = "mspm0-data-119240dd23ef5748d2a7bef219ca298d37ba604a", default-features = false, features = ["metadata"] } +mspm0-metapac = { git = "https://github.com/mspm0-rs/mspm0-data-generated/", tag = "mspm0-data-66a55c7bf38a2201ff48c299843e741f2d537f0b", default-features = false, features = ["metadata"] } [features] default = ["rt"] @@ -120,14 +120,138 @@ time-driver-tima0 = ["_time-driver"] time-driver-tima1 = ["_time-driver"] #! ## Chip-selection features -#! Select your chip by specifying the model as a feature, e.g. `mspm0g350x`. +#! Select your chip by specifying the model as a feature, e.g. `mspm0g3507pm`. #! Check the `Cargo.toml` for the latest list of supported chips. #! #! **Important:** Do not forget to adapt the target chip in your toolchain, #! e.g. in `.cargo/config.toml`. -mspm0c110x = [ "mspm0-metapac/mspm0c110x" ] -mspm0g350x = [ "mspm0-metapac/mspm0g350x" ] -mspm0g351x = [ "mspm0-metapac/mspm0g351x" ] -mspm0l130x = [ "mspm0-metapac/mspm0l130x" ] -mspm0l222x = [ "mspm0-metapac/mspm0l222x" ] +mspm0c1103dgs20 = ["mspm0-metapac/mspm0c1103dgs20"] +mspm0c1103dsg = ["mspm0-metapac/mspm0c1103dsg"] +mspm0c1103dyy = ["mspm0-metapac/mspm0c1103dyy"] +mspm0c1103ruk = ["mspm0-metapac/mspm0c1103ruk"] +mspm0c1104dgs20 = ["mspm0-metapac/mspm0c1104dgs20"] +mspm0c1104dsg = ["mspm0-metapac/mspm0c1104dsg"] +mspm0c1104dyy = ["mspm0-metapac/mspm0c1104dyy"] +mspm0c1104ruk = ["mspm0-metapac/mspm0c1104ruk"] +mspm0c1104ycj = ["mspm0-metapac/mspm0c1104ycj"] +mspm0g1105dgs28 = ["mspm0-metapac/mspm0g1105dgs28"] +mspm0g1105pm = ["mspm0-metapac/mspm0g1105pm"] +mspm0g1105pt = ["mspm0-metapac/mspm0g1105pt"] +mspm0g1105rge = ["mspm0-metapac/mspm0g1105rge"] +mspm0g1105rgz = ["mspm0-metapac/mspm0g1105rgz"] +mspm0g1105rhb = ["mspm0-metapac/mspm0g1105rhb"] +mspm0g1106dgs28 = ["mspm0-metapac/mspm0g1106dgs28"] +mspm0g1106pm = ["mspm0-metapac/mspm0g1106pm"] +mspm0g1106pt = ["mspm0-metapac/mspm0g1106pt"] +mspm0g1106rge = ["mspm0-metapac/mspm0g1106rge"] +mspm0g1106rgz = ["mspm0-metapac/mspm0g1106rgz"] +mspm0g1106rhb = ["mspm0-metapac/mspm0g1106rhb"] +mspm0g1107dgs28 = ["mspm0-metapac/mspm0g1107dgs28"] +mspm0g1107pm = ["mspm0-metapac/mspm0g1107pm"] +mspm0g1107pt = ["mspm0-metapac/mspm0g1107pt"] +mspm0g1107rge = ["mspm0-metapac/mspm0g1107rge"] +mspm0g1107rgz = ["mspm0-metapac/mspm0g1107rgz"] +mspm0g1107rhb = ["mspm0-metapac/mspm0g1107rhb"] +mspm0g1107ycj = ["mspm0-metapac/mspm0g1107ycj"] +mspm0g1505pm = ["mspm0-metapac/mspm0g1505pm"] +mspm0g1505pt = ["mspm0-metapac/mspm0g1505pt"] +mspm0g1505rge = ["mspm0-metapac/mspm0g1505rge"] +mspm0g1505rgz = ["mspm0-metapac/mspm0g1505rgz"] +mspm0g1505rhb = ["mspm0-metapac/mspm0g1505rhb"] +mspm0g1506pm = ["mspm0-metapac/mspm0g1506pm"] +mspm0g1506pt = ["mspm0-metapac/mspm0g1506pt"] +mspm0g1506rge = ["mspm0-metapac/mspm0g1506rge"] +mspm0g1506rgz = ["mspm0-metapac/mspm0g1506rgz"] +mspm0g1506rhb = ["mspm0-metapac/mspm0g1506rhb"] +mspm0g1507pm = ["mspm0-metapac/mspm0g1507pm"] +mspm0g1507pt = ["mspm0-metapac/mspm0g1507pt"] +mspm0g1507rge = ["mspm0-metapac/mspm0g1507rge"] +mspm0g1507rgz = ["mspm0-metapac/mspm0g1507rgz"] +mspm0g1507rhb = ["mspm0-metapac/mspm0g1507rhb"] +mspm0g1507ycj = ["mspm0-metapac/mspm0g1507ycj"] +mspm0g1519rgz = ["mspm0-metapac/mspm0g1519rgz"] +mspm0g1519rhb = ["mspm0-metapac/mspm0g1519rhb"] +mspm0g3105dgs20 = ["mspm0-metapac/mspm0g3105dgs20"] +mspm0g3105dgs28 = ["mspm0-metapac/mspm0g3105dgs28"] +mspm0g3105rhb = ["mspm0-metapac/mspm0g3105rhb"] +mspm0g3106dgs20 = ["mspm0-metapac/mspm0g3106dgs20"] +mspm0g3106dgs28 = ["mspm0-metapac/mspm0g3106dgs28"] +mspm0g3106rhb = ["mspm0-metapac/mspm0g3106rhb"] +mspm0g3107dgs20 = ["mspm0-metapac/mspm0g3107dgs20"] +mspm0g3107dgs28 = ["mspm0-metapac/mspm0g3107dgs28"] +mspm0g3107rhb = ["mspm0-metapac/mspm0g3107rhb"] +mspm0g3505dgs28 = ["mspm0-metapac/mspm0g3505dgs28"] +mspm0g3505pm = ["mspm0-metapac/mspm0g3505pm"] +mspm0g3505pt = ["mspm0-metapac/mspm0g3505pt"] +mspm0g3505rgz = ["mspm0-metapac/mspm0g3505rgz"] +mspm0g3505rhb = ["mspm0-metapac/mspm0g3505rhb"] +mspm0g3506dgs28 = ["mspm0-metapac/mspm0g3506dgs28"] +mspm0g3506pm = ["mspm0-metapac/mspm0g3506pm"] +mspm0g3506pt = ["mspm0-metapac/mspm0g3506pt"] +mspm0g3506rgz = ["mspm0-metapac/mspm0g3506rgz"] +mspm0g3506rhb = ["mspm0-metapac/mspm0g3506rhb"] +mspm0g3507dgs28 = ["mspm0-metapac/mspm0g3507dgs28"] +mspm0g3507pm = ["mspm0-metapac/mspm0g3507pm"] +mspm0g3507pt = ["mspm0-metapac/mspm0g3507pt"] +mspm0g3507rgz = ["mspm0-metapac/mspm0g3507rgz"] +mspm0g3507rhb = ["mspm0-metapac/mspm0g3507rhb"] +mspm0g3519pm = ["mspm0-metapac/mspm0g3519pm"] +mspm0g3519pn = ["mspm0-metapac/mspm0g3519pn"] +mspm0g3519pz = ["mspm0-metapac/mspm0g3519pz"] +mspm0g3519rgz = ["mspm0-metapac/mspm0g3519rgz"] +mspm0g3519rhb = ["mspm0-metapac/mspm0g3519rhb"] +mspm0l1105dgs20 = ["mspm0-metapac/mspm0l1105dgs20"] +mspm0l1105dgs28 = ["mspm0-metapac/mspm0l1105dgs28"] +mspm0l1105dyy = ["mspm0-metapac/mspm0l1105dyy"] +mspm0l1105rge = ["mspm0-metapac/mspm0l1105rge"] +mspm0l1105rtr = ["mspm0-metapac/mspm0l1105rtr"] +mspm0l1106dgs20 = ["mspm0-metapac/mspm0l1106dgs20"] +mspm0l1106dgs28 = ["mspm0-metapac/mspm0l1106dgs28"] +mspm0l1106dyy = ["mspm0-metapac/mspm0l1106dyy"] +mspm0l1106rge = ["mspm0-metapac/mspm0l1106rge"] +mspm0l1106rhb = ["mspm0-metapac/mspm0l1106rhb"] +mspm0l1106rtr = ["mspm0-metapac/mspm0l1106rtr"] +mspm0l1227pm = ["mspm0-metapac/mspm0l1227pm"] +mspm0l1227pn = ["mspm0-metapac/mspm0l1227pn"] +mspm0l1227pt = ["mspm0-metapac/mspm0l1227pt"] +mspm0l1227rge = ["mspm0-metapac/mspm0l1227rge"] +mspm0l1227rgz = ["mspm0-metapac/mspm0l1227rgz"] +mspm0l1227rhb = ["mspm0-metapac/mspm0l1227rhb"] +mspm0l1228pm = ["mspm0-metapac/mspm0l1228pm"] +mspm0l1228pn = ["mspm0-metapac/mspm0l1228pn"] +mspm0l1228pt = ["mspm0-metapac/mspm0l1228pt"] +mspm0l1228rge = ["mspm0-metapac/mspm0l1228rge"] +mspm0l1228rgz = ["mspm0-metapac/mspm0l1228rgz"] +mspm0l1228rhb = ["mspm0-metapac/mspm0l1228rhb"] +mspm0l1303rge = ["mspm0-metapac/mspm0l1303rge"] +mspm0l1304dgs20 = ["mspm0-metapac/mspm0l1304dgs20"] +mspm0l1304dgs28 = ["mspm0-metapac/mspm0l1304dgs28"] +mspm0l1304dyy = ["mspm0-metapac/mspm0l1304dyy"] +mspm0l1304rge = ["mspm0-metapac/mspm0l1304rge"] +mspm0l1304rhb = ["mspm0-metapac/mspm0l1304rhb"] +mspm0l1304rtr = ["mspm0-metapac/mspm0l1304rtr"] +mspm0l1305dgs20 = ["mspm0-metapac/mspm0l1305dgs20"] +mspm0l1305dgs28 = ["mspm0-metapac/mspm0l1305dgs28"] +mspm0l1305dyy = ["mspm0-metapac/mspm0l1305dyy"] +mspm0l1305rge = ["mspm0-metapac/mspm0l1305rge"] +mspm0l1305rtr = ["mspm0-metapac/mspm0l1305rtr"] +mspm0l1306dgs20 = ["mspm0-metapac/mspm0l1306dgs20"] +mspm0l1306dgs28 = ["mspm0-metapac/mspm0l1306dgs28"] +mspm0l1306dyy = ["mspm0-metapac/mspm0l1306dyy"] +mspm0l1306rge = ["mspm0-metapac/mspm0l1306rge"] +mspm0l1306rhb = ["mspm0-metapac/mspm0l1306rhb"] +mspm0l1343dgs20 = ["mspm0-metapac/mspm0l1343dgs20"] +mspm0l1344dgs20 = ["mspm0-metapac/mspm0l1344dgs20"] +mspm0l1345dgs28 = ["mspm0-metapac/mspm0l1345dgs28"] +mspm0l1346dgs28 = ["mspm0-metapac/mspm0l1346dgs28"] +mspm0l2227pm = ["mspm0-metapac/mspm0l2227pm"] +mspm0l2227pn = ["mspm0-metapac/mspm0l2227pn"] +mspm0l2227pt = ["mspm0-metapac/mspm0l2227pt"] +mspm0l2227rgz = ["mspm0-metapac/mspm0l2227rgz"] +mspm0l2228pm = ["mspm0-metapac/mspm0l2228pm"] +mspm0l2228pn = ["mspm0-metapac/mspm0l2228pn"] +mspm0l2228pt = ["mspm0-metapac/mspm0l2228pt"] +mspm0l2228rgz = ["mspm0-metapac/mspm0l2228rgz"] +msps003f3pw20 = ["mspm0-metapac/msps003f3pw20"] +msps003f4pw20 = ["mspm0-metapac/msps003f4pw20"] diff --git a/embassy-mspm0/README.md b/embassy-mspm0/README.md new file mode 100644 index 000000000..b2b8934aa --- /dev/null +++ b/embassy-mspm0/README.md @@ -0,0 +1,28 @@ +# Embassy MSPM0 HAL + +The embassy-mspm0 HAL aims to provide a safe, idiomatic hardware abstraction layer for all MSPM0 and MSPS003 chips. + +* [Documentation](https://docs.embassy.dev/embassy-mspm0/) (**Important:** use docs.embassy.dev rather than docs.rs to see the specific docs for the chip you’re using!) +* [Source](https://github.com/embassy-rs/embassy/tree/main/embassy-mspm0) +* [Examples](https://github.com/embassy-rs/embassy/tree/main/examples) + +## Embedded-hal + +The `embassy-mspm0` HAL implements the traits from [embedded-hal](https://crates.io/crates/embedded-hal) (1.0) and [embedded-hal-async](https://crates.io/crates/embedded-hal-async), as well as [embedded-io](https://crates.io/crates/embedded-io) and [embedded-io-async](https://crates.io/crates/embedded-io-async). + +## A note on feature flag names + +Feature flag names for chips do not include temperature rating or distribution format. + +Usually chapter 10 of your device's datasheet will explain the device nomenclature and how to decode it. Feature names in embassy-mspm0 only use the following from device nomenclature: +- MCU platform +- Product family +- Device subfamily +- Flash memory +- Package type + +This means for a part such as `MSPM0G3507SPMR`, the feature name is `mspm0g3507pm`. This also means that `MSPM0G3507QPMRQ1` uses the feature `mspm0g3507pm`, since the Q1 parts are just qualified variants of the base G3507 with a PM (QFP-64) package. + +## Interoperability + +This crate can run on any executor. diff --git a/embassy-mspm0/build.rs b/embassy-mspm0/build.rs index 08209df2a..409ce0621 100644 --- a/embassy-mspm0/build.rs +++ b/embassy-mspm0/build.rs @@ -7,7 +7,7 @@ use std::sync::LazyLock; use std::{env, fs}; use common::CfgSet; -use mspm0_metapac::metadata::METADATA; +use mspm0_metapac::metadata::{ALL_CHIPS, METADATA}; use proc_macro2::{Ident, Literal, Span, TokenStream}; use quote::{format_ident, quote}; @@ -24,6 +24,27 @@ fn generate_code() { cfgs.declare_all(&["gpio_pb", "gpio_pc", "int_group1"]); + let chip_name = match env::vars() + .map(|(a, _)| a) + .filter(|x| x.starts_with("CARGO_FEATURE_MSPM0") || x.starts_with("CARGO_FEATURE_MSPS")) + .get_one() + { + Ok(x) => x, + Err(GetOneError::None) => panic!("No mspm0xx/mspsxx Cargo feature enabled"), + Err(GetOneError::Multiple) => panic!("Multiple mspm0xx/mspsxx Cargo features enabled"), + } + .strip_prefix("CARGO_FEATURE_") + .unwrap() + .to_ascii_lowercase() + .replace('_', "-"); + + eprintln!("chip: {chip_name}"); + + cfgs.enable_all(&get_chip_cfgs(&chip_name)); + for chip in ALL_CHIPS { + cfgs.declare_all(&get_chip_cfgs(&chip)); + } + let mut singletons = get_singletons(&mut cfgs); time_driver(&mut singletons, &mut cfgs); @@ -44,6 +65,60 @@ fn generate_code() { rustfmt(&out_file); } +fn get_chip_cfgs(chip_name: &str) -> Vec { + let mut cfgs = Vec::new(); + + // GPIO on C110x is special as it does not belong to an interrupt group. + if chip_name.starts_with("mspm0c110") || chip_name.starts_with("msps003f") { + cfgs.push("mspm0c110x".to_string()); + } + + // Family ranges (temporary until int groups are generated) + // + // TODO: Remove this once int group stuff is generated. + if chip_name.starts_with("mspm0g110") { + cfgs.push("mspm0g110x".to_string()); + } + + if chip_name.starts_with("mspm0g150") { + cfgs.push("mspm0g150x".to_string()); + } + + if chip_name.starts_with("mspm0g310") { + cfgs.push("mspm0g310x".to_string()); + } + + if chip_name.starts_with("mspm0g350") { + cfgs.push("mspm0g350x".to_string()); + } + + if chip_name.starts_with("mspm0g351") { + cfgs.push("mspm0g351x".to_string()); + } + + if chip_name.starts_with("mspm0l110") { + cfgs.push("mspm0l110x".to_string()); + } + + if chip_name.starts_with("mspm0l122") { + cfgs.push("mspm0l122x".to_string()); + } + + if chip_name.starts_with("mspm0l130") { + cfgs.push("mspm0l130x".to_string()); + } + + if chip_name.starts_with("mspm0l134") { + cfgs.push("mspm0l134x".to_string()); + } + + if chip_name.starts_with("mspm0l222") { + cfgs.push("mspm0l222x".to_string()); + } + + cfgs +} + #[derive(Debug, Clone)] struct Singleton { name: String, @@ -146,7 +221,7 @@ fn make_valid_identifier(s: &str) -> Singleton { } fn generate_pincm_mapping() -> TokenStream { - let pincms = METADATA.pincm_mappings.iter().map(|mapping| { + let pincms = METADATA.pins.iter().map(|mapping| { let port_letter = mapping.pin.strip_prefix("P").unwrap(); let port_base = (port_letter.chars().next().unwrap() as u8 - b'A') * 32; // This assumes all ports are single letter length. @@ -174,11 +249,11 @@ fn generate_pincm_mapping() -> TokenStream { } fn generate_pin() -> TokenStream { - let pin_impls = METADATA.pincm_mappings.iter().map(|pincm_mapping| { - let name = Ident::new(&pincm_mapping.pin, Span::call_site()); - let port_letter = pincm_mapping.pin.strip_prefix("P").unwrap(); + let pin_impls = METADATA.pins.iter().map(|pin| { + let name = Ident::new(&pin.pin, Span::call_site()); + let port_letter = pin.pin.strip_prefix("P").unwrap(); let port_letter = port_letter.chars().next().unwrap(); - let pin_number = Literal::u8_unsuffixed(pincm_mapping.pin[2..].parse::().unwrap()); + let pin_number = Literal::u8_unsuffixed(pin.pin[2..].parse::().unwrap()); let port = Ident::new(&format!("Port{}", port_letter), Span::call_site()); diff --git a/embassy-mspm0/src/gpio.rs b/embassy-mspm0/src/gpio.rs index 3f895d962..3c824b0e6 100644 --- a/embassy-mspm0/src/gpio.rs +++ b/embassy-mspm0/src/gpio.rs @@ -10,7 +10,7 @@ use embassy_sync::waitqueue::AtomicWaker; use crate::pac::gpio::vals::*; use crate::pac::gpio::{self}; -#[cfg(all(feature = "rt", feature = "mspm0c110x"))] +#[cfg(all(feature = "rt", mspm0c110x))] use crate::pac::interrupt; use crate::pac::{self}; @@ -1120,7 +1120,7 @@ impl Iterator for BitIter { } // C110x has a dedicated interrupt just for GPIOA, as it does not have a GROUP1 interrupt. -#[cfg(all(feature = "rt", feature = "mspm0c110x"))] +#[cfg(all(feature = "rt", mspm0c110x))] #[interrupt] fn GPIOA() { gpioa_interrupt(); diff --git a/embassy-mspm0/src/int_group/g150x.rs b/embassy-mspm0/src/int_group/g150x.rs new file mode 100644 index 000000000..706ba2078 --- /dev/null +++ b/embassy-mspm0/src/int_group/g150x.rs @@ -0,0 +1,51 @@ +use crate::pac; +use crate::pac::interrupt; + +#[cfg(feature = "rt")] +#[interrupt] +fn GROUP0() { + use mspm0_metapac::Group0; + + let group = pac::CPUSS.int_group(0); + + // Must subtract by 1 since NO_INTR is value 0 + let iidx = group.iidx().read().stat().to_bits() - 1; + + let Ok(group) = pac::Group0::try_from(iidx as u8) else { + debug!("Invalid IIDX for group 0: {}", iidx); + return; + }; + + match group { + Group0::WWDT0 => todo!("implement WWDT0"), + Group0::WWDT1 => todo!("implement WWDT1"), + Group0::DEBUGSS => todo!("implement DEBUGSS"), + Group0::FLASHCTL => todo!("implement FLASHCTL"), + Group0::SYSCTL => todo!("implement SYSCTL"), + } +} + +#[cfg(feature = "rt")] +#[interrupt] +fn GROUP1() { + use mspm0_metapac::Group1; + + let group = pac::CPUSS.int_group(1); + + // Must subtract by 1 since NO_INTR is value 0 + let iidx = group.iidx().read().stat().to_bits() - 1; + + let Ok(group) = pac::Group1::try_from(iidx as u8) else { + debug!("Invalid IIDX for group 1: {}", iidx); + return; + }; + + match group { + Group1::GPIOA => crate::gpio::gpioa_interrupt(), + Group1::GPIOB => crate::gpio::gpiob_interrupt(), + Group1::COMP0 => todo!("implement COMP0"), + Group1::COMP1 => todo!("implement COMP1"), + Group1::COMP2 => todo!("implement COMP2"), + Group1::TRNG => todo!("implement TRNG"), + } +} diff --git a/embassy-mspm0/src/lib.rs b/embassy-mspm0/src/lib.rs index e8f5971d5..df2d83cc0 100644 --- a/embassy-mspm0/src/lib.rs +++ b/embassy-mspm0/src/lib.rs @@ -1,6 +1,11 @@ #![no_std] // Doc feature labels can be tested locally by running RUSTDOCFLAGS="--cfg=docsrs" cargo +nightly doc #![cfg_attr(docsrs, feature(doc_auto_cfg, doc_cfg_hide), doc(cfg_hide(doc, docsrs)))] +#![cfg_attr( + docsrs, + doc = "

You might want to browse the `embassy-mspm0` documentation on the Embassy website instead.

The documentation here on `docs.rs` is built for a single chip only, while on the Embassy website you can pick your exact chip from the top menu. Available peripherals and their APIs change depending on the chip.

\n\n" +)] +#![doc = include_str!("../README.md")] // This mod MUST go first, so that the others see its macros. pub(crate) mod fmt; @@ -35,11 +40,11 @@ pub mod mode { mod time_driver; // Interrupt group handlers. -#[cfg_attr(feature = "mspm0c110x", path = "int_group/c110x.rs")] -#[cfg_attr(feature = "mspm0g350x", path = "int_group/g350x.rs")] -#[cfg_attr(feature = "mspm0g351x", path = "int_group/g351x.rs")] -#[cfg_attr(feature = "mspm0l130x", path = "int_group/l130x.rs")] -#[cfg_attr(feature = "mspm0l222x", path = "int_group/l222x.rs")] +#[cfg_attr(mspm0c110x, path = "int_group/c110x.rs")] +#[cfg_attr(mspm0g350x, path = "int_group/g350x.rs")] +#[cfg_attr(mspm0g351x, path = "int_group/g351x.rs")] +#[cfg_attr(mspm0l130x, path = "int_group/l130x.rs")] +#[cfg_attr(mspm0l222x, path = "int_group/l222x.rs")] mod int_group; pub(crate) mod _generated { @@ -109,7 +114,7 @@ pub fn init(_config: Config) -> Peripherals { _generated::enable_group_interrupts(cs); - #[cfg(feature = "mspm0c110x")] + #[cfg(mspm0c110x)] unsafe { use crate::_generated::interrupt::typelevel::Interrupt; crate::interrupt::typelevel::GPIOA::enable(); diff --git a/examples/mspm0c1104/Cargo.toml b/examples/mspm0c1104/Cargo.toml index ba64a578d..67b0372ab 100644 --- a/examples/mspm0c1104/Cargo.toml +++ b/examples/mspm0c1104/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-mspm0 = { version = "0.1.0", path = "../../embassy-mspm0", features = ["mspm0c110x", "defmt", "rt", "time-driver-any"] } +embassy-mspm0 = { version = "0.1.0", path = "../../embassy-mspm0", features = ["mspm0c1104dgs20", "defmt", "rt", "time-driver-any"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt"] } embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt"] } diff --git a/examples/mspm0c1104/README.md b/examples/mspm0c1104/README.md index e5c9f961d..86b6c3918 100644 --- a/examples/mspm0c1104/README.md +++ b/examples/mspm0c1104/README.md @@ -1,4 +1,4 @@ -# Examples for MSPM0C110x family +# Examples for MSPM0C1104 Run individual examples with ``` @@ -15,7 +15,7 @@ A large number of the examples are written for the [LP-MSPM0C1104](https://www.t You might need to adjust `.cargo/config.toml`, `Cargo.toml` and possibly update pin numbers or peripherals to match the specific MCU or board you are using. * [ ] Update .cargo/config.toml with the correct probe-rs command to use your specific MCU. For example for C1104 it should be `probe-rs run --chip MSPM0C1104`. (use `probe-rs chip list` to find your chip) -* [ ] Update Cargo.toml to have the correct `embassy-mspm0` feature. For example for C1104 it should be `mspm0c1104`. Look in the `Cargo.toml` file of the `embassy-mspm0` project to find the correct feature flag for your chip. +* [ ] Update Cargo.toml to have the correct `embassy-mspm0` feature. For the LP-MSPM0C1104 it should be `mspm0c1104dgs20`. Look in the `Cargo.toml` file of the `embassy-mspm0` project to find the correct feature flag for your chip. * [ ] If your board has a special clock or power configuration, make sure that it is set up appropriately. * [ ] If your board has different pin mapping, update any pin numbers or peripherals in the given example code to match your schematic diff --git a/examples/mspm0g3507/Cargo.toml b/examples/mspm0g3507/Cargo.toml index f6fed091d..49baeabdf 100644 --- a/examples/mspm0g3507/Cargo.toml +++ b/examples/mspm0g3507/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-mspm0 = { version = "0.1.0", path = "../../embassy-mspm0", features = ["mspm0g350x", "defmt", "rt", "time-driver-any"] } +embassy-mspm0 = { version = "0.1.0", path = "../../embassy-mspm0", features = ["mspm0g3507pm", "defmt", "rt", "time-driver-any"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt"] } embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt"] } diff --git a/examples/mspm0g3507/README.md b/examples/mspm0g3507/README.md index 5e8a83212..be91dc5a0 100644 --- a/examples/mspm0g3507/README.md +++ b/examples/mspm0g3507/README.md @@ -1,4 +1,4 @@ -# Examples for MSPM0C350x family +# Examples for MSPM0M3507 Run individual examples with ``` @@ -15,7 +15,7 @@ A large number of the examples are written for the [LP-MSPM0G3507](https://www.t You might need to adjust `.cargo/config.toml`, `Cargo.toml` and possibly update pin numbers or peripherals to match the specific MCU or board you are using. * [ ] Update .cargo/config.toml with the correct probe-rs command to use your specific MCU. For example for G3507 it should be `probe-rs run --chip MSPM0G3507`. (use `probe-rs chip list` to find your chip) -* [ ] Update Cargo.toml to have the correct `embassy-mspm0` feature. For example for G3507 it should be `mspm0g3507`. Look in the `Cargo.toml` file of the `embassy-mspm0` project to find the correct feature flag for your chip. +* [ ] Update Cargo.toml to have the correct `embassy-mspm0` feature. For the LP-MSPM0G3507 it should be `mspm0g3507pm`. Look in the `Cargo.toml` file of the `embassy-mspm0` project to find the correct feature flag for your chip. * [ ] If your board has a special clock or power configuration, make sure that it is set up appropriately. * [ ] If your board has different pin mapping, update any pin numbers or peripherals in the given example code to match your schematic diff --git a/examples/mspm0g3519/Cargo.toml b/examples/mspm0g3519/Cargo.toml index 1662e1f8d..dfe365daf 100644 --- a/examples/mspm0g3519/Cargo.toml +++ b/examples/mspm0g3519/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-mspm0 = { version = "0.1.0", path = "../../embassy-mspm0", features = ["mspm0g351x", "defmt", "rt", "time-driver-any"] } +embassy-mspm0 = { version = "0.1.0", path = "../../embassy-mspm0", features = ["mspm0g3519pz", "defmt", "rt", "time-driver-any"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt"] } embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt"] } diff --git a/examples/mspm0g3519/README.md b/examples/mspm0g3519/README.md index 5034b1913..c392c9e25 100644 --- a/examples/mspm0g3519/README.md +++ b/examples/mspm0g3519/README.md @@ -1,4 +1,4 @@ -# Examples for MSPM0G351x family +# Examples for MSPM0G3519 Run individual examples with ``` @@ -15,7 +15,7 @@ A large number of the examples are written for the [LP-MSPM0G3519](https://www.t You might need to adjust `.cargo/config.toml`, `Cargo.toml` and possibly update pin numbers or peripherals to match the specific MCU or board you are using. * [ ] Update .cargo/config.toml with the correct probe-rs command to use your specific MCU. For example for G3519 it should be `probe-rs run --chip MSPM0G3519`. (use `probe-rs chip list` to find your chip) -* [ ] Update Cargo.toml to have the correct `embassy-mspm0` feature. For example for G3519 it should be `mspm0g3519`. Look in the `Cargo.toml` file of the `embassy-mspm0` project to find the correct feature flag for your chip. +* [ ] Update Cargo.toml to have the correct `embassy-mspm0` feature. For the LP-MSPM0G3519 it should be `mspm0g3519pz`. Look in the `Cargo.toml` file of the `embassy-mspm0` project to find the correct feature flag for your chip. * [ ] If your board has a special clock or power configuration, make sure that it is set up appropriately. * [ ] If your board has different pin mapping, update any pin numbers or peripherals in the given example code to match your schematic diff --git a/examples/mspm0l1306/Cargo.toml b/examples/mspm0l1306/Cargo.toml index 609b3f205..b0c370bb5 100644 --- a/examples/mspm0l1306/Cargo.toml +++ b/examples/mspm0l1306/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-mspm0 = { version = "0.1.0", path = "../../embassy-mspm0", features = ["mspm0l130x", "defmt", "rt", "time-driver-any"] } +embassy-mspm0 = { version = "0.1.0", path = "../../embassy-mspm0", features = ["mspm0l1306rhb", "defmt", "rt", "time-driver-any"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt"] } embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt"] } diff --git a/examples/mspm0l1306/README.md b/examples/mspm0l1306/README.md index 5a55d721e..4d698e0fa 100644 --- a/examples/mspm0l1306/README.md +++ b/examples/mspm0l1306/README.md @@ -1,4 +1,4 @@ -# Examples for MSPM0L130x family +# Examples for MSPM0L1306 Run individual examples with ``` @@ -15,7 +15,7 @@ A large number of the examples are written for the [LP-MSPM0L1306](https://www.t You might need to adjust `.cargo/config.toml`, `Cargo.toml` and possibly update pin numbers or peripherals to match the specific MCU or board you are using. * [ ] Update .cargo/config.toml with the correct probe-rs command to use your specific MCU. For example for L1306 it should be `probe-rs run --chip MSPM0L1306`. (use `probe-rs chip list` to find your chip) -* [ ] Update Cargo.toml to have the correct `embassy-mspm0` feature. For example for L1306 it should be `mspm0l1306`. Look in the `Cargo.toml` file of the `embassy-mspm0` project to find the correct feature flag for your chip. +* [ ] Update Cargo.toml to have the correct `embassy-mspm0` feature. For the LP-MSPM0L1306 it should be `mspm0l1306rhb`. Look in the `Cargo.toml` file of the `embassy-mspm0` project to find the correct feature flag for your chip. * [ ] If your board has a special clock or power configuration, make sure that it is set up appropriately. * [ ] If your board has different pin mapping, update any pin numbers or peripherals in the given example code to match your schematic diff --git a/examples/mspm0l2228/Cargo.toml b/examples/mspm0l2228/Cargo.toml index bbca011a1..d55b9e6a8 100644 --- a/examples/mspm0l2228/Cargo.toml +++ b/examples/mspm0l2228/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-mspm0 = { version = "0.1.0", path = "../../embassy-mspm0", features = ["mspm0l222x", "defmt", "rt", "time-driver-any"] } +embassy-mspm0 = { version = "0.1.0", path = "../../embassy-mspm0", features = ["mspm0l2228pn", "defmt", "rt", "time-driver-any"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt"] } embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt"] } diff --git a/examples/mspm0l2228/README.md b/examples/mspm0l2228/README.md index c73fa13b6..191022258 100644 --- a/examples/mspm0l2228/README.md +++ b/examples/mspm0l2228/README.md @@ -1,4 +1,4 @@ -# Examples for MSPM0L222x family +# Examples for MSPM0L2228 Run individual examples with ``` @@ -15,7 +15,7 @@ A large number of the examples are written for the [LP-MSPM0L2228](https://www.t You might need to adjust `.cargo/config.toml`, `Cargo.toml` and possibly update pin numbers or peripherals to match the specific MCU or board you are using. * [ ] Update .cargo/config.toml with the correct probe-rs command to use your specific MCU. For example for L2228 it should be `probe-rs run --chip MSPM0L2228`. (use `probe-rs chip list` to find your chip) -* [ ] Update Cargo.toml to have the correct `embassy-mspm0` feature. For example for L2228 it should be `mspm0l2228`. Look in the `Cargo.toml` file of the `embassy-mspm0` project to find the correct feature flag for your chip. +* [ ] Update Cargo.toml to have the correct `embassy-mspm0` feature. For example for LP-MSPM0L2228 it should be `mspm0l2228pn`. Look in the `Cargo.toml` file of the `embassy-mspm0` project to find the correct feature flag for your chip. * [ ] If your board has a special clock or power configuration, make sure that it is set up appropriately. * [ ] If your board has different pin mapping, update any pin numbers or peripherals in the given example code to match your schematic diff --git a/tests/mspm0/Cargo.toml b/tests/mspm0/Cargo.toml index 0566807d7..d76aaff73 100644 --- a/tests/mspm0/Cargo.toml +++ b/tests/mspm0/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [features] -mspm0g3507 = [ "embassy-mspm0/mspm0g350x" ] +mspm0g3507 = [ "embassy-mspm0/mspm0g3507pm" ] [dependencies] teleprobe-meta = "1.1" From 8bb25a551abbf3677a440d6f73401b88cf4de57f Mon Sep 17 00:00:00 2001 From: i509VCB Date: Tue, 13 May 2025 22:53:16 -0500 Subject: [PATCH 1127/1217] ci: build std examples on aarch64-unknown-linux-gnu --- ci.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci.sh b/ci.sh index 6e320e4d1..f2d461c1a 100755 --- a/ci.sh +++ b/ci.sh @@ -19,7 +19,7 @@ fi TARGET=$(rustc -vV | sed -n 's|host: ||p') BUILD_EXTRA="" -if [ $TARGET = "x86_64-unknown-linux-gnu" ]; then +if [ $TARGET = "x86_64-unknown-linux-gnu" ] || [ $TARGET = "aarch64-unknown-linux-gnu" ]; then BUILD_EXTRA="--- build --release --manifest-path examples/std/Cargo.toml --target $TARGET --artifact-dir out/examples/std" fi From d4d10bad0bc2f2bbfbad116fb07e27eea4ac5af2 Mon Sep 17 00:00:00 2001 From: Gerhard de Clercq <11624490+Gerharddc@users.noreply.github.com> Date: Wed, 14 May 2025 09:52:46 +0200 Subject: [PATCH 1128/1217] [embassy-usb-dfu] accept closure to customise DFU function This provides a more generic interface for users to customise the DFU function instead of restricting customisation to DFU headers. --- embassy-usb-dfu/src/application.rs | 21 ++++++------------- embassy-usb-dfu/src/dfu.rs | 21 ++++++------------- .../boot/application/stm32wb-dfu/src/main.rs | 14 ++++++++----- .../boot/bootloader/stm32wb-dfu/src/main.rs | 14 ++++++++----- 4 files changed, 30 insertions(+), 40 deletions(-) diff --git a/embassy-usb-dfu/src/application.rs b/embassy-usb-dfu/src/application.rs index 2646d100d..4b7b72073 100644 --- a/embassy-usb-dfu/src/application.rs +++ b/embassy-usb-dfu/src/application.rs @@ -2,7 +2,7 @@ use embassy_boot::BlockingFirmwareState; use embassy_time::{Duration, Instant}; use embassy_usb::control::{InResponse, OutResponse, Recipient, RequestType}; use embassy_usb::driver::Driver; -use embassy_usb::{msos, Builder, Handler}; +use embassy_usb::{Builder, FunctionBuilder, Handler}; use embedded_storage::nor_flash::NorFlash; use crate::consts::{ @@ -130,22 +130,13 @@ pub fn usb_dfu<'d, D: Driver<'d>, MARK: DfuMarker, RST: Reset>( builder: &mut Builder<'d, D>, handler: &'d mut Control, timeout: Duration, - winusb_guids: Option<&'d [&str]>, + func_modifier: impl Fn(&mut FunctionBuilder<'_, 'd, D>), ) { let mut func = builder.function(0x00, 0x00, 0x00); - if let Some(winusb_guids) = winusb_guids { - // We add MSOS headers so that the device automatically gets assigned the WinUSB driver on Windows. - // Otherwise users need to do this manually using a tool like Zadig. - // - // Adding them here on the function level appears to only be needed for compositive devices. - // In addition to being on the function level, they should also be added to the device level. - // - func.msos_feature(msos::CompatibleIdFeatureDescriptor::new("WINUSB", "")); - func.msos_feature(msos::RegistryPropertyFeatureDescriptor::new( - "DeviceInterfaceGUIDs", - msos::PropertyData::RegMultiSz(winusb_guids), - )); - } + + // Here we give users the opportunity to add their own function level MSOS headers for instance. + // This is useful when DFU functionality is part of a composite USB device. + func_modifier(&mut func); let mut iface = func.interface(); let mut alt = iface.alt_setting(USB_CLASS_APPN_SPEC, APPN_SPEC_SUBCLASS_DFU, DFU_PROTOCOL_RT, None); diff --git a/embassy-usb-dfu/src/dfu.rs b/embassy-usb-dfu/src/dfu.rs index 43a35637d..0f39d906b 100644 --- a/embassy-usb-dfu/src/dfu.rs +++ b/embassy-usb-dfu/src/dfu.rs @@ -1,7 +1,7 @@ use embassy_boot::{AlignedBuffer, BlockingFirmwareUpdater, FirmwareUpdaterError}; use embassy_usb::control::{InResponse, OutResponse, Recipient, RequestType}; use embassy_usb::driver::Driver; -use embassy_usb::{msos, Builder, Handler}; +use embassy_usb::{Builder, FunctionBuilder, Handler}; use embedded_storage::nor_flash::{NorFlash, NorFlashErrorKind}; use crate::consts::{ @@ -186,22 +186,13 @@ impl<'d, DFU: NorFlash, STATE: NorFlash, RST: Reset, const BLOCK_SIZE: usize> Ha pub fn usb_dfu<'d, D: Driver<'d>, DFU: NorFlash, STATE: NorFlash, RST: Reset, const BLOCK_SIZE: usize>( builder: &mut Builder<'d, D>, handler: &'d mut Control<'d, DFU, STATE, RST, BLOCK_SIZE>, - winusb_guids: Option<&'d [&str]>, + func_modifier: impl Fn(&mut FunctionBuilder<'_, 'd, D>), ) { let mut func = builder.function(USB_CLASS_APPN_SPEC, APPN_SPEC_SUBCLASS_DFU, DFU_PROTOCOL_DFU); - if let Some(winusb_guids) = winusb_guids { - // We add MSOS headers so that the device automatically gets assigned the WinUSB driver on Windows. - // Otherwise users need to do this manually using a tool like Zadig. - // - // Adding them here on the function level appears to only be needed for compositive devices. - // In addition to being on the function level, they should also be added to the device level. - // - func.msos_feature(msos::CompatibleIdFeatureDescriptor::new("WINUSB", "")); - func.msos_feature(msos::RegistryPropertyFeatureDescriptor::new( - "DeviceInterfaceGUIDs", - msos::PropertyData::RegMultiSz(winusb_guids), - )); - } + + // Here we give users the opportunity to add their own function level MSOS headers for instance. + // This is useful when DFU functionality is part of a composite USB device. + func_modifier(&mut func); let mut iface = func.interface(); let mut alt = iface.alt_setting(USB_CLASS_APPN_SPEC, APPN_SPEC_SUBCLASS_DFU, DFU_PROTOCOL_DFU, None); diff --git a/examples/boot/application/stm32wb-dfu/src/main.rs b/examples/boot/application/stm32wb-dfu/src/main.rs index 6236dfe52..4d6556597 100644 --- a/examples/boot/application/stm32wb-dfu/src/main.rs +++ b/examples/boot/application/stm32wb-dfu/src/main.rs @@ -70,11 +70,15 @@ async fn main(_spawner: Spawner) { msos::PropertyData::RegMultiSz(DEVICE_INTERFACE_GUIDS), )); - // For non-composite devices: - usb_dfu(&mut builder, &mut state, Duration::from_millis(2500), None); - - // Or for composite devices: - // usb_dfu(&mut builder, &mut state, Duration::from_millis(2500), Some(DEVICE_INTERFACE_GUIDS)); + usb_dfu(&mut builder, &mut state, Duration::from_millis(2500), |func| { + // You likely don't have to add these function level headers if your USB device is not composite + // (i.e. if your device does not expose another interface in addition to DFU) + func.msos_feature(msos::CompatibleIdFeatureDescriptor::new("WINUSB", "")); + func.msos_feature(msos::RegistryPropertyFeatureDescriptor::new( + "DeviceInterfaceGUIDs", + msos::PropertyData::RegMultiSz(DEVICE_INTERFACE_GUIDS), + )); + }); let mut dev = builder.build(); dev.run().await diff --git a/examples/boot/bootloader/stm32wb-dfu/src/main.rs b/examples/boot/bootloader/stm32wb-dfu/src/main.rs index 8cfd4daa7..fea6f4a0d 100644 --- a/examples/boot/bootloader/stm32wb-dfu/src/main.rs +++ b/examples/boot/bootloader/stm32wb-dfu/src/main.rs @@ -78,11 +78,15 @@ fn main() -> ! { msos::PropertyData::RegMultiSz(DEVICE_INTERFACE_GUIDS), )); - // For non-composite devices: - usb_dfu::<_, _, _, _, 4096>(&mut builder, &mut state, None); - - // Or for composite devices: - // usb_dfu::<_, _, _, _, 4096>(&mut builder, &mut state, Some(DEVICE_INTERFACE_GUIDS)); + usb_dfu::<_, _, _, _, 4096>(&mut builder, &mut state, |func| { + // You likely don't have to add these function level headers if your USB device is not composite + // (i.e. if your device does not expose another interface in addition to DFU) + func.msos_feature(msos::CompatibleIdFeatureDescriptor::new("WINUSB", "")); + func.msos_feature(msos::RegistryPropertyFeatureDescriptor::new( + "DeviceInterfaceGUIDs", + msos::PropertyData::RegMultiSz(DEVICE_INTERFACE_GUIDS), + )); + }); let mut dev = builder.build(); embassy_futures::block_on(dev.run()); From 2bbc2045a4a6cb1e489295d258ac0cdb6338f90a Mon Sep 17 00:00:00 2001 From: Gerhard de Clercq <11624490+Gerharddc@users.noreply.github.com> Date: Wed, 14 May 2025 09:56:28 +0200 Subject: [PATCH 1129/1217] [usb-dfu examples] Alert users to customise their WinUSB GUIDs --- examples/boot/application/stm32wb-dfu/src/main.rs | 4 +++- examples/boot/bootloader/stm32wb-dfu/src/main.rs | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/examples/boot/application/stm32wb-dfu/src/main.rs b/examples/boot/application/stm32wb-dfu/src/main.rs index 4d6556597..5e7b71f5a 100644 --- a/examples/boot/application/stm32wb-dfu/src/main.rs +++ b/examples/boot/application/stm32wb-dfu/src/main.rs @@ -22,7 +22,9 @@ bind_interrupts!(struct Irqs { USB_LP => usb::InterruptHandler; }); -// This is a randomly generated GUID to allow clients on Windows to find our device +// This is a randomly generated GUID to allow clients on Windows to find your device. +// +// N.B. update to a custom GUID for your own device! const DEVICE_INTERFACE_GUIDS: &[&str] = &["{EAA9A5DC-30BA-44BC-9232-606CDC875321}"]; #[embassy_executor::main] diff --git a/examples/boot/bootloader/stm32wb-dfu/src/main.rs b/examples/boot/bootloader/stm32wb-dfu/src/main.rs index fea6f4a0d..0b643079f 100644 --- a/examples/boot/bootloader/stm32wb-dfu/src/main.rs +++ b/examples/boot/bootloader/stm32wb-dfu/src/main.rs @@ -20,7 +20,9 @@ bind_interrupts!(struct Irqs { USB_LP => usb::InterruptHandler; }); -// This is a randomly generated GUID to allow clients on Windows to find our device +// This is a randomly generated GUID to allow clients on Windows to find your device. +// +// N.B. update to a custom GUID for your own device! const DEVICE_INTERFACE_GUIDS: &[&str] = &["{EAA9A5DC-30BA-44BC-9232-606CDC875321}"]; #[entry] From be20c708fa7b099507c2027a8c5666b54f1e5723 Mon Sep 17 00:00:00 2001 From: jake-taf <149392739+jake-taf@users.noreply.github.com> Date: Wed, 14 May 2025 09:45:20 -0400 Subject: [PATCH 1130/1217] Interrupt Doc Comments Support adding doc comments to interrupts --- embassy-stm32/src/lib.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 3e84d3386..f8d09413d 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -173,8 +173,9 @@ pub use crate::_generated::interrupt; // developer note: this macro can't be in `embassy-hal-internal` due to the use of `$crate`. #[macro_export] macro_rules! bind_interrupts { - ($vis:vis struct $name:ident { + ($(#[$outer:meta])* $vis:vis struct $name:ident { $( + $(#[$inner:meta])* $(#[cfg($cond_irq:meta)])? $irq:ident => $( $(#[cfg($cond_handler:meta)])? @@ -183,12 +184,14 @@ macro_rules! bind_interrupts { )* }) => { #[derive(Copy, Clone)] + $(#[$outer])* $vis struct $name; $( #[allow(non_snake_case)] #[no_mangle] $(#[cfg($cond_irq)])? + $(#[$inner])* unsafe extern "C" fn $irq() { $( $(#[cfg($cond_handler)])? From a71642ca01190d1a8f8bd652bd41d8a9539fe2ee Mon Sep 17 00:00:00 2001 From: Jakob Date: Wed, 14 May 2025 18:57:00 +0200 Subject: [PATCH 1131/1217] Fix compile error in adc_read doc comment code --- embassy-stm32/src/adc/g4.rs | 4 ++-- embassy-stm32/src/adc/v3.rs | 4 ++-- embassy-stm32/src/adc/v4.rs | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/embassy-stm32/src/adc/g4.rs b/embassy-stm32/src/adc/g4.rs index 8ed102c1b..1fce3085a 100644 --- a/embassy-stm32/src/adc/g4.rs +++ b/embassy-stm32/src/adc/g4.rs @@ -371,8 +371,8 @@ impl<'d, T: Instance> Adc<'d, T> { /// let mut adc_pin1 = p.PA1.into(); /// let mut measurements = [0u16; 2]; /// - /// adc.read_async( - /// p.DMA1_CH2, + /// adc.read( + /// p.DMA1_CH2.reborrow(), /// [ /// (&mut *adc_pin0, SampleTime::CYCLES160_5), /// (&mut *adc_pin1, SampleTime::CYCLES160_5), diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs index 1c5ad16e9..313244e19 100644 --- a/embassy-stm32/src/adc/v3.rs +++ b/embassy-stm32/src/adc/v3.rs @@ -272,8 +272,8 @@ impl<'d, T: Instance> Adc<'d, T> { /// let mut adc_pin1 = p.PA1.degrade_adc(); /// let mut measurements = [0u16; 2]; /// - /// adc.read_async( - /// p.DMA1_CH2, + /// adc.read( + /// p.DMA1_CH2.reborrow(), /// [ /// (&mut *adc_pin0, SampleTime::CYCLES160_5), /// (&mut *adc_pin1, SampleTime::CYCLES160_5), diff --git a/embassy-stm32/src/adc/v4.rs b/embassy-stm32/src/adc/v4.rs index e455b275c..39e0d51b9 100644 --- a/embassy-stm32/src/adc/v4.rs +++ b/embassy-stm32/src/adc/v4.rs @@ -347,8 +347,8 @@ impl<'d, T: Instance> Adc<'d, T> { /// let mut adc_pin2 = p.PA2.into(); /// let mut measurements = [0u16; 2]; /// - /// adc.read_async( - /// p.DMA2_CH0, + /// adc.read( + /// p.DMA2_CH0.reborrow(), /// [ /// (&mut *adc_pin0, SampleTime::CYCLES112), /// (&mut *adc_pin2, SampleTime::CYCLES112), From ad091324a7da4d6b4326f6d1f8dc29e7a9844be0 Mon Sep 17 00:00:00 2001 From: Matthew Tran <0e4ef622@gmail.com> Date: Wed, 14 May 2025 22:26:55 -0500 Subject: [PATCH 1132/1217] nrf: _3v3 -> _3V3 --- embassy-nrf/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index 5bce65a98..7d86e1218 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs @@ -339,7 +339,7 @@ pub mod config { /// 3.0 V _3V0 = 4, /// 3.3 V - _3v3 = 5, + _3V3 = 5, //ERASED = 7, means 1.8V } @@ -371,7 +371,7 @@ pub mod config { /// 3.0 V _3V0 = 4, /// 3.3 V - _3v3 = 5, + _3V3 = 5, //ERASED = 7, means 1.8V } From d64ae225b30bc3a0f7a9b1277188b6e60fc97484 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 10 Apr 2025 10:39:54 -0700 Subject: [PATCH 1133/1217] Add UART and DMA drivers Both blocking and async versions are supported. Add separate examples for each mode. --- docs/pages/imxrt.adoc | 2 + embassy-imxrt/src/dma.rs | 418 ++++++++ embassy-imxrt/src/flexcomm/mod.rs | 252 +++++ embassy-imxrt/src/flexcomm/uart.rs | 1230 ++++++++++++++++++++++++ embassy-imxrt/src/gpio.rs | 20 +- embassy-imxrt/src/lib.rs | 26 +- examples/mimxrt6/src/bin/uart-async.rs | 87 ++ examples/mimxrt6/src/bin/uart.rs | 55 ++ 8 files changed, 2069 insertions(+), 21 deletions(-) create mode 100644 embassy-imxrt/src/dma.rs create mode 100644 embassy-imxrt/src/flexcomm/mod.rs create mode 100644 embassy-imxrt/src/flexcomm/uart.rs create mode 100644 examples/mimxrt6/src/bin/uart-async.rs create mode 100644 examples/mimxrt6/src/bin/uart.rs diff --git a/docs/pages/imxrt.adoc b/docs/pages/imxrt.adoc index bbd65e494..87867e1e0 100644 --- a/docs/pages/imxrt.adoc +++ b/docs/pages/imxrt.adoc @@ -10,5 +10,7 @@ The link: link:https://github.com/embassy-rs/embassy/tree/main/embassy-imxrt[Emb The following peripherals have a HAL implementation at present * CRC +* DMA * GPIO * RNG +* UART diff --git a/embassy-imxrt/src/dma.rs b/embassy-imxrt/src/dma.rs new file mode 100644 index 000000000..e141447f3 --- /dev/null +++ b/embassy-imxrt/src/dma.rs @@ -0,0 +1,418 @@ +//! DMA driver. + +use core::future::Future; +use core::pin::Pin; +use core::sync::atomic::{compiler_fence, Ordering}; +use core::task::{Context, Poll}; + +use embassy_hal_internal::{impl_peripheral, Peri, PeripheralType}; +use embassy_sync::waitqueue::AtomicWaker; +use pac::dma0::channel::cfg::Periphreqen; +use pac::dma0::channel::xfercfg::{Dstinc, Srcinc, Width}; + +use crate::clocks::enable_and_reset; +use crate::interrupt::InterruptExt; +use crate::peripherals::DMA0; +use crate::sealed::Sealed; +use crate::{interrupt, pac, peripherals, BitIter}; + +#[cfg(feature = "rt")] +#[interrupt] +fn DMA0() { + let reg = unsafe { crate::pac::Dma0::steal() }; + + if reg.intstat().read().activeerrint().bit() { + let err = reg.errint0().read().bits(); + + for channel in BitIter(err) { + error!("DMA error interrupt on channel {}!", channel); + reg.errint0().write(|w| unsafe { w.err().bits(1 << channel) }); + CHANNEL_WAKERS[channel as usize].wake(); + } + } + + if reg.intstat().read().activeint().bit() { + let ia = reg.inta0().read().bits(); + + for channel in BitIter(ia) { + reg.inta0().write(|w| unsafe { w.ia().bits(1 << channel) }); + CHANNEL_WAKERS[channel as usize].wake(); + } + } +} + +/// Initialize DMA controllers (DMA0 only, for now) +pub(crate) unsafe fn init() { + let sysctl0 = crate::pac::Sysctl0::steal(); + let dmactl0 = crate::pac::Dma0::steal(); + + enable_and_reset::(); + + interrupt::DMA0.disable(); + interrupt::DMA0.set_priority(interrupt::Priority::P3); + + dmactl0.ctrl().modify(|_, w| w.enable().set_bit()); + + // Set channel descriptor SRAM base address + // Descriptor base must be 1K aligned + let descriptor_base = core::ptr::addr_of!(DESCRIPTORS.descs) as u32; + dmactl0.srambase().write(|w| w.bits(descriptor_base)); + + // Ensure AHB priority it highest (M4 == DMAC0) + sysctl0.ahbmatrixprior().modify(|_, w| w.m4().bits(0)); + + interrupt::DMA0.unpend(); + interrupt::DMA0.enable(); +} + +/// DMA read. +/// +/// SAFETY: Slice must point to a valid location reachable by DMA. +pub unsafe fn read<'a, C: Channel, W: Word>(ch: Peri<'a, C>, from: *const W, to: *mut [W]) -> Transfer<'a, C> { + let count = ((to.len() / W::size() as usize) - 1) as isize; + + copy_inner( + ch, + from as *const u32, + (to as *mut u32).byte_offset(count * W::size()), + W::width(), + count, + false, + true, + true, + ) +} + +/// DMA write. +/// +/// SAFETY: Slice must point to a valid location reachable by DMA. +pub unsafe fn write<'a, C: Channel, W: Word>(ch: Peri<'a, C>, from: *const [W], to: *mut W) -> Transfer<'a, C> { + let count = ((from.len() / W::size() as usize) - 1) as isize; + + copy_inner( + ch, + (from as *const u32).byte_offset(count * W::size()), + to as *mut u32, + W::width(), + count, + true, + false, + true, + ) +} + +/// DMA copy between slices. +/// +/// SAFETY: Slices must point to locations reachable by DMA. +pub unsafe fn copy<'a, C: Channel, W: Word>(ch: Peri<'a, C>, from: &[W], to: &mut [W]) -> Transfer<'a, C> { + let from_len = from.len(); + let to_len = to.len(); + assert_eq!(from_len, to_len); + + let count = ((from_len / W::size() as usize) - 1) as isize; + + copy_inner( + ch, + from.as_ptr().byte_offset(count * W::size()) as *const u32, + to.as_mut_ptr().byte_offset(count * W::size()) as *mut u32, + W::width(), + count, + true, + true, + false, + ) +} + +fn copy_inner<'a, C: Channel>( + ch: Peri<'a, C>, + from: *const u32, + to: *mut u32, + width: Width, + count: isize, + incr_read: bool, + incr_write: bool, + periph: bool, +) -> Transfer<'a, C> { + let p = ch.regs(); + + unsafe { + DESCRIPTORS.descs[ch.number() as usize].src = from as u32; + DESCRIPTORS.descs[ch.number() as usize].dest = to as u32; + } + + compiler_fence(Ordering::SeqCst); + + p.errint0().write(|w| unsafe { w.err().bits(1 << ch.number()) }); + p.inta0().write(|w| unsafe { w.ia().bits(1 << ch.number()) }); + + p.channel(ch.number().into()).cfg().write(|w| { + unsafe { w.chpriority().bits(0) } + .periphreqen() + .variant(match periph { + false => Periphreqen::Disabled, + true => Periphreqen::Enabled, + }) + .hwtrigen() + .clear_bit() + }); + + p.intenset0().write(|w| unsafe { w.inten().bits(1 << ch.number()) }); + + p.channel(ch.number().into()).xfercfg().write(|w| { + unsafe { w.xfercount().bits(count as u16) } + .cfgvalid() + .set_bit() + .clrtrig() + .set_bit() + .reload() + .clear_bit() + .setinta() + .set_bit() + .width() + .variant(width) + .srcinc() + .variant(match incr_read { + false => Srcinc::NoIncrement, + true => Srcinc::WidthX1, + // REVISIT: what about WidthX2 and WidthX4? + }) + .dstinc() + .variant(match incr_write { + false => Dstinc::NoIncrement, + true => Dstinc::WidthX1, + // REVISIT: what about WidthX2 and WidthX4? + }) + }); + + p.enableset0().write(|w| unsafe { w.ena().bits(1 << ch.number()) }); + + p.channel(ch.number().into()) + .xfercfg() + .modify(|_, w| w.swtrig().set_bit()); + + compiler_fence(Ordering::SeqCst); + + Transfer::new(ch) +} + +/// DMA transfer driver. +#[must_use = "futures do nothing unless you `.await` or poll them"] +pub struct Transfer<'a, C: Channel> { + channel: Peri<'a, C>, +} + +impl<'a, C: Channel> Transfer<'a, C> { + pub(crate) fn new(channel: Peri<'a, C>) -> Self { + Self { channel } + } + + pub(crate) fn abort(&mut self) -> usize { + let p = self.channel.regs(); + + p.abort0().write(|w| w.channel(self.channel.number()).set_bit()); + while p.busy0().read().bsy().bits() & (1 << self.channel.number()) != 0 {} + + p.enableclr0() + .write(|w| unsafe { w.clr().bits(1 << self.channel.number()) }); + + let width: u8 = p + .channel(self.channel.number().into()) + .xfercfg() + .read() + .width() + .variant() + .unwrap() + .into(); + + let count = p + .channel(self.channel.number().into()) + .xfercfg() + .read() + .xfercount() + .bits() + + 1; + + usize::from(count) * usize::from(width) + } +} + +impl<'a, C: Channel> Drop for Transfer<'a, C> { + fn drop(&mut self) { + self.abort(); + } +} + +impl<'a, C: Channel> Unpin for Transfer<'a, C> {} +impl<'a, C: Channel> Future for Transfer<'a, C> { + type Output = (); + + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + // Re-register the waker on each call to poll() because any calls to + // wake will deregister the waker. + CHANNEL_WAKERS[self.channel.number() as usize].register(cx.waker()); + + if self.channel.regs().active0().read().act().bits() & (1 << self.channel.number()) == 0 { + Poll::Ready(()) + } else { + Poll::Pending + } + } +} + +/// DMA channel descriptor +#[derive(Copy, Clone)] +#[repr(C)] +struct Descriptor { + reserved: u32, + src: u32, + dest: u32, + link: u32, +} + +impl Descriptor { + const fn new() -> Self { + Self { + reserved: 0, + src: 0, + dest: 0, + link: 0, + } + } +} + +#[repr(align(1024))] +struct Descriptors { + descs: [Descriptor; CHANNEL_COUNT], +} + +impl Descriptors { + const fn new() -> Self { + Self { + descs: [const { Descriptor::new() }; CHANNEL_COUNT], + } + } +} + +static mut DESCRIPTORS: Descriptors = Descriptors::new(); +static CHANNEL_WAKERS: [AtomicWaker; CHANNEL_COUNT] = [const { AtomicWaker::new() }; CHANNEL_COUNT]; +pub(crate) const CHANNEL_COUNT: usize = 33; + +/// DMA channel interface. +#[allow(private_bounds)] +pub trait Channel: PeripheralType + Sealed + Into + Sized + 'static { + /// Channel number. + fn number(&self) -> u8; + + /// Channel registry block. + fn regs(&self) -> &'static pac::dma0::RegisterBlock { + unsafe { &*crate::pac::Dma0::ptr() } + } +} + +/// DMA word. +#[allow(private_bounds)] +pub trait Word: Sealed { + /// Transfer width. + fn width() -> Width; + + /// Size in bytes for the width. + fn size() -> isize; +} + +impl Sealed for u8 {} +impl Word for u8 { + fn width() -> Width { + Width::Bit8 + } + + fn size() -> isize { + 1 + } +} + +impl Sealed for u16 {} +impl Word for u16 { + fn width() -> Width { + Width::Bit16 + } + + fn size() -> isize { + 2 + } +} + +impl Sealed for u32 {} +impl Word for u32 { + fn width() -> Width { + Width::Bit32 + } + + fn size() -> isize { + 4 + } +} + +/// Type erased DMA channel. +pub struct AnyChannel { + number: u8, +} + +impl_peripheral!(AnyChannel); + +impl Sealed for AnyChannel {} +impl Channel for AnyChannel { + fn number(&self) -> u8 { + self.number + } +} + +macro_rules! channel { + ($name:ident, $num:expr) => { + impl Sealed for peripherals::$name {} + impl Channel for peripherals::$name { + fn number(&self) -> u8 { + $num + } + } + + impl From for crate::dma::AnyChannel { + fn from(val: peripherals::$name) -> Self { + Self { number: val.number() } + } + } + }; +} + +channel!(DMA0_CH0, 0); +channel!(DMA0_CH1, 1); +channel!(DMA0_CH2, 2); +channel!(DMA0_CH3, 3); +channel!(DMA0_CH4, 4); +channel!(DMA0_CH5, 5); +channel!(DMA0_CH6, 6); +channel!(DMA0_CH7, 7); +channel!(DMA0_CH8, 8); +channel!(DMA0_CH9, 9); +channel!(DMA0_CH10, 10); +channel!(DMA0_CH11, 11); +channel!(DMA0_CH12, 12); +channel!(DMA0_CH13, 13); +channel!(DMA0_CH14, 14); +channel!(DMA0_CH15, 15); +channel!(DMA0_CH16, 16); +channel!(DMA0_CH17, 17); +channel!(DMA0_CH18, 18); +channel!(DMA0_CH19, 19); +channel!(DMA0_CH20, 20); +channel!(DMA0_CH21, 21); +channel!(DMA0_CH22, 22); +channel!(DMA0_CH23, 23); +channel!(DMA0_CH24, 24); +channel!(DMA0_CH25, 25); +channel!(DMA0_CH26, 26); +channel!(DMA0_CH27, 27); +channel!(DMA0_CH28, 28); +channel!(DMA0_CH29, 29); +channel!(DMA0_CH30, 30); +channel!(DMA0_CH31, 31); +channel!(DMA0_CH32, 32); diff --git a/embassy-imxrt/src/flexcomm/mod.rs b/embassy-imxrt/src/flexcomm/mod.rs new file mode 100644 index 000000000..4473c9a77 --- /dev/null +++ b/embassy-imxrt/src/flexcomm/mod.rs @@ -0,0 +1,252 @@ +//! Implements Flexcomm interface wrapper for easier usage across modules + +pub mod uart; + +use paste::paste; + +use crate::clocks::{enable_and_reset, SysconPeripheral}; +use crate::peripherals::{ + FLEXCOMM0, FLEXCOMM1, FLEXCOMM14, FLEXCOMM15, FLEXCOMM2, FLEXCOMM3, FLEXCOMM4, FLEXCOMM5, FLEXCOMM6, FLEXCOMM7, +}; +use crate::{pac, PeripheralType}; + +/// clock selection option +#[derive(Copy, Clone, Debug)] +pub enum Clock { + /// SFRO + Sfro, + + /// FFRO + Ffro, + + /// `AUDIO_PLL` + AudioPll, + + /// MASTER + Master, + + /// FCn_FRG with Main clock source + FcnFrgMain, + + /// FCn_FRG with Pll clock source + FcnFrgPll, + + /// FCn_FRG with Sfro clock source + FcnFrgSfro, + + /// FCn_FRG with Ffro clock source + FcnFrgFfro, + + /// disabled + None, +} + +/// do not allow implementation of trait outside this mod +mod sealed { + /// trait does not get re-exported outside flexcomm mod, allowing us to safely expose only desired APIs + pub trait Sealed {} +} + +/// primary low-level flexcomm interface +pub(crate) trait FlexcommLowLevel: sealed::Sealed + PeripheralType + SysconPeripheral + 'static + Send { + // fetch the flexcomm register block for direct manipulation + fn reg() -> &'static pac::flexcomm0::RegisterBlock; + + // set the clock select for this flexcomm instance and remove from reset + fn enable(clk: Clock); +} + +macro_rules! impl_flexcomm { + ($($idx:expr),*) => { + $( + paste!{ + impl sealed::Sealed for crate::peripherals::[] {} + + impl FlexcommLowLevel for crate::peripherals::[] { + fn reg() -> &'static crate::pac::flexcomm0::RegisterBlock { + // SAFETY: safe from single executor, enforce + // via peripheral reference lifetime tracking + unsafe { + &*crate::pac::[]::ptr() + } + } + + fn enable(clk: Clock) { + // SAFETY: safe from single executor + let clkctl1 = unsafe { crate::pac::Clkctl1::steal() }; + + clkctl1.flexcomm($idx).fcfclksel().write(|w| match clk { + Clock::Sfro => w.sel().sfro_clk(), + Clock::Ffro => w.sel().ffro_clk(), + Clock::AudioPll => w.sel().audio_pll_clk(), + Clock::Master => w.sel().master_clk(), + Clock::FcnFrgMain => w.sel().fcn_frg_clk(), + Clock::FcnFrgPll => w.sel().fcn_frg_clk(), + Clock::FcnFrgSfro => w.sel().fcn_frg_clk(), + Clock::FcnFrgFfro => w.sel().fcn_frg_clk(), + Clock::None => w.sel().none(), // no clock? throw an error? + }); + + clkctl1.flexcomm($idx).frgclksel().write(|w| match clk { + Clock::FcnFrgMain => w.sel().main_clk(), + Clock::FcnFrgPll => w.sel().frg_pll_clk(), + Clock::FcnFrgSfro => w.sel().sfro_clk(), + Clock::FcnFrgFfro => w.sel().ffro_clk(), + _ => w.sel().none(), // not using frg ... + }); + + // todo: add support for frg div/mult + clkctl1 + .flexcomm($idx) + .frgctl() + .write(|w| + // SAFETY: unsafe only used for .bits() call + unsafe { w.mult().bits(0) }); + + enable_and_reset::<[]>(); + } + } + } + )* + } +} + +impl_flexcomm!(0, 1, 2, 3, 4, 5, 6, 7); + +// TODO: FLEXCOMM 14 is untested. Enable SPI support on FLEXCOMM14 +// Add special case FLEXCOMM14 +impl sealed::Sealed for crate::peripherals::FLEXCOMM14 {} + +impl FlexcommLowLevel for crate::peripherals::FLEXCOMM14 { + fn reg() -> &'static crate::pac::flexcomm0::RegisterBlock { + // SAFETY: safe from single executor, enforce + // via peripheral reference lifetime tracking + unsafe { &*crate::pac::Flexcomm14::ptr() } + } + + fn enable(clk: Clock) { + // SAFETY: safe from single executor + let clkctl1 = unsafe { crate::pac::Clkctl1::steal() }; + + clkctl1.fc14fclksel().write(|w| match clk { + Clock::Sfro => w.sel().sfro_clk(), + Clock::Ffro => w.sel().ffro_clk(), + Clock::AudioPll => w.sel().audio_pll_clk(), + Clock::Master => w.sel().master_clk(), + Clock::FcnFrgMain => w.sel().fcn_frg_clk(), + Clock::FcnFrgPll => w.sel().fcn_frg_clk(), + Clock::FcnFrgSfro => w.sel().fcn_frg_clk(), + Clock::FcnFrgFfro => w.sel().fcn_frg_clk(), + Clock::None => w.sel().none(), // no clock? throw an error? + }); + + clkctl1.frg14clksel().write(|w| match clk { + Clock::FcnFrgMain => w.sel().main_clk(), + Clock::FcnFrgPll => w.sel().frg_pll_clk(), + Clock::FcnFrgSfro => w.sel().sfro_clk(), + Clock::FcnFrgFfro => w.sel().ffro_clk(), + _ => w.sel().none(), // not using frg ... + }); + + // todo: add support for frg div/mult + clkctl1.frg14ctl().write(|w| + // SAFETY: unsafe only used for .bits() call + unsafe { w.mult().bits(0) }); + + enable_and_reset::(); + } +} + +// Add special case FLEXCOMM15 +impl sealed::Sealed for crate::peripherals::FLEXCOMM15 {} + +impl FlexcommLowLevel for crate::peripherals::FLEXCOMM15 { + fn reg() -> &'static crate::pac::flexcomm0::RegisterBlock { + // SAFETY: safe from single executor, enforce + // via peripheral reference lifetime tracking + unsafe { &*crate::pac::Flexcomm15::ptr() } + } + + fn enable(clk: Clock) { + // SAFETY: safe from single executor + let clkctl1 = unsafe { crate::pac::Clkctl1::steal() }; + + clkctl1.fc15fclksel().write(|w| match clk { + Clock::Sfro => w.sel().sfro_clk(), + Clock::Ffro => w.sel().ffro_clk(), + Clock::AudioPll => w.sel().audio_pll_clk(), + Clock::Master => w.sel().master_clk(), + Clock::FcnFrgMain => w.sel().fcn_frg_clk(), + Clock::FcnFrgPll => w.sel().fcn_frg_clk(), + Clock::FcnFrgSfro => w.sel().fcn_frg_clk(), + Clock::FcnFrgFfro => w.sel().fcn_frg_clk(), + Clock::None => w.sel().none(), // no clock? throw an error? + }); + clkctl1.frg15clksel().write(|w| match clk { + Clock::FcnFrgMain => w.sel().main_clk(), + Clock::FcnFrgPll => w.sel().frg_pll_clk(), + Clock::FcnFrgSfro => w.sel().sfro_clk(), + Clock::FcnFrgFfro => w.sel().ffro_clk(), + _ => w.sel().none(), // not using frg ... + }); + // todo: add support for frg div/mult + clkctl1.frg15ctl().write(|w| + // SAFETY: unsafe only used for .bits() call + unsafe { w.mult().bits(0) }); + + enable_and_reset::(); + } +} + +macro_rules! into_mode { + ($mode:ident, $($fc:ident),*) => { + paste! { + /// Sealed Mode trait + trait []: FlexcommLowLevel {} + + /// Select mode of operation + #[allow(private_bounds)] + pub trait []: [] { + /// Set mode of operation + fn []() { + Self::reg().pselid().write(|w| w.persel().[<$mode>]()); + } + } + } + + $( + paste!{ + impl [] for crate::peripherals::$fc {} + impl [] for crate::peripherals::$fc {} + } + )* + } +} + +into_mode!(usart, FLEXCOMM0, FLEXCOMM1, FLEXCOMM2, FLEXCOMM3, FLEXCOMM4, FLEXCOMM5, FLEXCOMM6, FLEXCOMM7); +into_mode!(spi, FLEXCOMM0, FLEXCOMM1, FLEXCOMM2, FLEXCOMM3, FLEXCOMM4, FLEXCOMM5, FLEXCOMM6, FLEXCOMM7, FLEXCOMM14); +into_mode!(i2c, FLEXCOMM0, FLEXCOMM1, FLEXCOMM2, FLEXCOMM3, FLEXCOMM4, FLEXCOMM5, FLEXCOMM6, FLEXCOMM7, FLEXCOMM15); + +into_mode!( + i2s_transmit, + FLEXCOMM0, + FLEXCOMM1, + FLEXCOMM2, + FLEXCOMM3, + FLEXCOMM4, + FLEXCOMM5, + FLEXCOMM6, + FLEXCOMM7 +); + +into_mode!( + i2s_receive, + FLEXCOMM0, + FLEXCOMM1, + FLEXCOMM2, + FLEXCOMM3, + FLEXCOMM4, + FLEXCOMM5, + FLEXCOMM6, + FLEXCOMM7 +); diff --git a/embassy-imxrt/src/flexcomm/uart.rs b/embassy-imxrt/src/flexcomm/uart.rs new file mode 100644 index 000000000..230b30d43 --- /dev/null +++ b/embassy-imxrt/src/flexcomm/uart.rs @@ -0,0 +1,1230 @@ +//! Universal Asynchronous Receiver Transmitter (UART) driver. + +use core::future::poll_fn; +use core::marker::PhantomData; +use core::sync::atomic::{compiler_fence, AtomicU8, Ordering}; +use core::task::Poll; + +use embassy_futures::select::{select, Either}; +use embassy_hal_internal::drop::OnDrop; +use embassy_hal_internal::{Peri, PeripheralType}; +use embassy_sync::waitqueue::AtomicWaker; +use paste::paste; + +use crate::dma::AnyChannel; +use crate::flexcomm::Clock; +use crate::gpio::{AnyPin, GpioPin as Pin}; +use crate::interrupt::typelevel::Interrupt; +use crate::iopctl::{DriveMode, DriveStrength, Inverter, IopctlPin, Pull, SlewRate}; +use crate::pac::usart0::cfg::{Clkpol, Datalen, Loop, Paritysel as Parity, Stoplen, Syncen, Syncmst}; +use crate::pac::usart0::ctl::Cc; +use crate::sealed::Sealed; +use crate::{dma, interrupt}; + +/// Driver move trait. +#[allow(private_bounds)] +pub trait Mode: Sealed {} + +/// Blocking mode. +pub struct Blocking; +impl Sealed for Blocking {} +impl Mode for Blocking {} + +/// Async mode. +pub struct Async; +impl Sealed for Async {} +impl Mode for Async {} + +/// Uart driver. +pub struct Uart<'a, M: Mode> { + tx: UartTx<'a, M>, + rx: UartRx<'a, M>, +} + +/// Uart TX driver. +pub struct UartTx<'a, M: Mode> { + info: Info, + tx_dma: Option>, + _phantom: PhantomData<(&'a (), M)>, +} + +/// Uart RX driver. +pub struct UartRx<'a, M: Mode> { + info: Info, + rx_dma: Option>, + _phantom: PhantomData<(&'a (), M)>, +} + +/// UART config +#[derive(Clone, Copy)] +pub struct Config { + /// Baudrate of the Uart + pub baudrate: u32, + /// data length + pub data_bits: Datalen, + /// Parity + pub parity: Parity, + /// Stop bits + pub stop_bits: Stoplen, + /// Polarity of the clock + pub clock_polarity: Clkpol, + /// Sync/ Async operation selection + pub operation: Syncen, + /// Sync master/slave mode selection (only applicable in sync mode) + pub sync_mode_master_select: Syncmst, + /// USART continuous Clock generation enable in synchronous master mode. + pub continuous_clock: Cc, + /// Normal/ loopback mode + pub loopback_mode: Loop, + /// Clock type + pub clock: Clock, +} + +impl Default for Config { + /// Default configuration for single channel sampling. + fn default() -> Self { + Self { + baudrate: 115_200, + data_bits: Datalen::Bit8, + parity: Parity::NoParity, + stop_bits: Stoplen::Bit1, + clock_polarity: Clkpol::FallingEdge, + operation: Syncen::AsynchronousMode, + sync_mode_master_select: Syncmst::Slave, + continuous_clock: Cc::ClockOnCharacter, + loopback_mode: Loop::Normal, + clock: crate::flexcomm::Clock::Sfro, + } + } +} + +/// Uart Errors +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum Error { + /// Read error + Read, + + /// Buffer overflow + Overrun, + + /// Noise error + Noise, + + /// Framing error + Framing, + + /// Parity error + Parity, + + /// Failure + Fail, + + /// Invalid argument + InvalidArgument, + + /// Uart baud rate cannot be supported with the given clock + UnsupportedBaudrate, + + /// RX FIFO Empty + RxFifoEmpty, + + /// TX FIFO Full + TxFifoFull, + + /// TX Busy + TxBusy, +} +/// shorthand for -> `Result` +pub type Result = core::result::Result; + +impl<'a, M: Mode> UartTx<'a, M> { + fn new_inner(tx_dma: Option>) -> Self { + let uarttx = Self { + info: T::info(), + tx_dma, + _phantom: PhantomData, + }; + uarttx.info.refcnt.fetch_add(1, Ordering::Relaxed); + uarttx + } +} + +impl<'a, M: Mode> Drop for UartTx<'a, M> { + fn drop(&mut self) { + if self.info.refcnt.fetch_sub(1, Ordering::Relaxed) == 1 { + while self.info.regs.stat().read().txidle().bit_is_clear() {} + + self.info.regs.fifointenclr().modify(|_, w| { + w.txerr() + .set_bit() + .rxerr() + .set_bit() + .txlvl() + .set_bit() + .rxlvl() + .set_bit() + }); + + self.info + .regs + .fifocfg() + .modify(|_, w| w.dmatx().clear_bit().dmarx().clear_bit()); + + self.info.regs.cfg().modify(|_, w| w.enable().disabled()); + } + } +} + +impl<'a> UartTx<'a, Blocking> { + /// Create a new UART which can only send data + /// Unidirectional Uart - Tx only + pub fn new_blocking(_inner: Peri<'a, T>, tx: Peri<'a, impl TxPin>, config: Config) -> Result { + tx.as_tx(); + + let _tx = tx.into(); + Uart::::init::(Some(_tx), None, None, None, config)?; + + Ok(Self::new_inner::(None)) + } + + fn write_byte_internal(&mut self, byte: u8) -> Result<()> { + // SAFETY: unsafe only used for .bits() + self.info + .regs + .fifowr() + .write(|w| unsafe { w.txdata().bits(u16::from(byte)) }); + + Ok(()) + } + + fn blocking_write_byte(&mut self, byte: u8) -> Result<()> { + while self.info.regs.fifostat().read().txnotfull().bit_is_clear() {} + + // Prevent the compiler from reordering write_byte_internal() + // before the loop above. + compiler_fence(Ordering::Release); + + self.write_byte_internal(byte) + } + + fn write_byte(&mut self, byte: u8) -> Result<()> { + if self.info.regs.fifostat().read().txnotfull().bit_is_clear() { + Err(Error::TxFifoFull) + } else { + self.write_byte_internal(byte) + } + } + + /// Transmit the provided buffer blocking execution until done. + pub fn blocking_write(&mut self, buf: &[u8]) -> Result<()> { + for x in buf { + self.blocking_write_byte(*x)?; + } + + Ok(()) + } + + /// Transmit the provided buffer. Non-blocking version, bails out + /// if it would block. + pub fn write(&mut self, buf: &[u8]) -> Result<()> { + for x in buf { + self.write_byte(*x)?; + } + + Ok(()) + } + + /// Flush UART TX blocking execution until done. + pub fn blocking_flush(&mut self) -> Result<()> { + while self.info.regs.stat().read().txidle().bit_is_clear() {} + Ok(()) + } + + /// Flush UART TX. + pub fn flush(&mut self) -> Result<()> { + if self.info.regs.stat().read().txidle().bit_is_clear() { + Err(Error::TxBusy) + } else { + Ok(()) + } + } +} + +impl<'a, M: Mode> UartRx<'a, M> { + fn new_inner(rx_dma: Option>) -> Self { + let uartrx = Self { + info: T::info(), + rx_dma, + _phantom: PhantomData, + }; + uartrx.info.refcnt.fetch_add(1, Ordering::Relaxed); + uartrx + } +} + +impl<'a, M: Mode> Drop for UartRx<'a, M> { + fn drop(&mut self) { + if self.info.refcnt.fetch_sub(1, Ordering::Relaxed) == 1 { + while self.info.regs.stat().read().rxidle().bit_is_clear() {} + + self.info.regs.fifointenclr().modify(|_, w| { + w.txerr() + .set_bit() + .rxerr() + .set_bit() + .txlvl() + .set_bit() + .rxlvl() + .set_bit() + }); + + self.info + .regs + .fifocfg() + .modify(|_, w| w.dmatx().clear_bit().dmarx().clear_bit()); + + self.info.regs.cfg().modify(|_, w| w.enable().disabled()); + } + } +} + +impl<'a> UartRx<'a, Blocking> { + /// Create a new blocking UART which can only receive data + pub fn new_blocking(_inner: Peri<'a, T>, rx: Peri<'a, impl RxPin>, config: Config) -> Result { + rx.as_rx(); + + let _rx = rx.into(); + Uart::::init::(None, Some(_rx), None, None, config)?; + + Ok(Self::new_inner::(None)) + } +} + +impl UartRx<'_, Blocking> { + fn read_byte_internal(&mut self) -> Result { + if self.info.regs.fifostat().read().rxerr().bit_is_set() { + self.info.regs.fifocfg().modify(|_, w| w.emptyrx().set_bit()); + self.info.regs.fifostat().modify(|_, w| w.rxerr().set_bit()); + Err(Error::Read) + } else if self.info.regs.stat().read().parityerrint().bit_is_set() { + self.info.regs.stat().modify(|_, w| w.parityerrint().clear_bit_by_one()); + Err(Error::Parity) + } else if self.info.regs.stat().read().framerrint().bit_is_set() { + self.info.regs.stat().modify(|_, w| w.framerrint().clear_bit_by_one()); + Err(Error::Framing) + } else if self.info.regs.stat().read().rxnoiseint().bit_is_set() { + self.info.regs.stat().modify(|_, w| w.rxnoiseint().clear_bit_by_one()); + Err(Error::Noise) + } else { + let byte = self.info.regs.fiford().read().rxdata().bits() as u8; + Ok(byte) + } + } + + fn read_byte(&mut self) -> Result { + if self.info.regs.fifostat().read().rxnotempty().bit_is_clear() { + Err(Error::RxFifoEmpty) + } else { + self.read_byte_internal() + } + } + + fn blocking_read_byte(&mut self) -> Result { + while self.info.regs.fifostat().read().rxnotempty().bit_is_clear() {} + + // Prevent the compiler from reordering read_byte_internal() + // before the loop above. + compiler_fence(Ordering::Acquire); + + self.read_byte_internal() + } + + /// Read from UART RX. Non-blocking version, bails out if it would + /// block. + pub fn read(&mut self, buf: &mut [u8]) -> Result<()> { + for b in buf.iter_mut() { + *b = self.read_byte()?; + } + + Ok(()) + } + + /// Read from UART RX blocking execution until done. + pub fn blocking_read(&mut self, buf: &mut [u8]) -> Result<()> { + for b in buf.iter_mut() { + *b = self.blocking_read_byte()?; + } + + Ok(()) + } +} + +impl<'a, M: Mode> Uart<'a, M> { + fn init( + tx: Option>, + rx: Option>, + rts: Option>, + cts: Option>, + config: Config, + ) -> Result<()> { + T::enable(config.clock); + T::into_usart(); + + let regs = T::info().regs; + + if tx.is_some() { + regs.fifocfg().modify(|_, w| w.emptytx().set_bit().enabletx().enabled()); + + // clear FIFO error + regs.fifostat().write(|w| w.txerr().set_bit()); + } + + if rx.is_some() { + regs.fifocfg().modify(|_, w| w.emptyrx().set_bit().enablerx().enabled()); + + // clear FIFO error + regs.fifostat().write(|w| w.rxerr().set_bit()); + } + + if rts.is_some() && cts.is_some() { + regs.cfg().modify(|_, w| w.ctsen().enabled()); + } + + Self::set_baudrate_inner::(config.baudrate, config.clock)?; + Self::set_uart_config::(config); + + Ok(()) + } + + fn get_fc_freq(clock: Clock) -> Result { + match clock { + Clock::Sfro => Ok(16_000_000), + Clock::Ffro => Ok(48_000_000), + // We only support Sfro and Ffro now. + _ => Err(Error::InvalidArgument), + } + } + + fn set_baudrate_inner(baudrate: u32, clock: Clock) -> Result<()> { + // Get source clock frequency according to clock type. + let source_clock_hz = Self::get_fc_freq(clock)?; + + if baudrate == 0 { + return Err(Error::InvalidArgument); + } + + let regs = T::info().regs; + + // If synchronous master mode is enabled, only configure the BRG value. + if regs.cfg().read().syncen().is_synchronous_mode() { + // Master + if regs.cfg().read().syncmst().is_master() { + // Calculate the BRG value + let brgval = (source_clock_hz / baudrate) - 1; + + // SAFETY: unsafe only used for .bits() + regs.brg().write(|w| unsafe { w.brgval().bits(brgval as u16) }); + } + } else { + // Smaller values of OSR can make the sampling position within a + // data bit less accurate and may potentially cause more noise + // errors or incorrect data. + let (_, osr, brg) = (8..16).rev().fold( + (u32::MAX, u32::MAX, u32::MAX), + |(best_diff, best_osr, best_brg), osrval| { + // Compare source_clock_hz agaist with ((osrval + 1) * baudrate) to make sure + // (source_clock_hz / ((osrval + 1) * baudrate)) is not less than 0. + if source_clock_hz < ((osrval + 1) * baudrate) { + (best_diff, best_osr, best_brg) + } else { + let brgval = (source_clock_hz / ((osrval + 1) * baudrate)) - 1; + // We know brgval will not be less than 0 now, it should have already been a valid u32 value, + // then compare it agaist with 65535. + if brgval > 65535 { + (best_diff, best_osr, best_brg) + } else { + // Calculate the baud rate based on the BRG value + let candidate = source_clock_hz / ((osrval + 1) * (brgval + 1)); + + // Calculate the difference between the + // current baud rate and the desired baud rate + let diff = (candidate as i32 - baudrate as i32).unsigned_abs(); + + // Check if the current calculated difference is the best so far + if diff < best_diff { + (diff, osrval, brgval) + } else { + (best_diff, best_osr, best_brg) + } + } + } + }, + ); + + // Value over range + if brg > 65535 { + return Err(Error::UnsupportedBaudrate); + } + + // SAFETY: unsafe only used for .bits() + regs.osr().write(|w| unsafe { w.osrval().bits(osr as u8) }); + + // SAFETY: unsafe only used for .bits() + regs.brg().write(|w| unsafe { w.brgval().bits(brg as u16) }); + } + + Ok(()) + } + + fn set_uart_config(config: Config) { + let regs = T::info().regs; + + regs.cfg().modify(|_, w| w.enable().disabled()); + + regs.cfg().modify(|_, w| { + w.datalen() + .variant(config.data_bits) + .stoplen() + .variant(config.stop_bits) + .paritysel() + .variant(config.parity) + .loop_() + .variant(config.loopback_mode) + .syncen() + .variant(config.operation) + .clkpol() + .variant(config.clock_polarity) + }); + + regs.cfg().modify(|_, w| w.enable().enabled()); + } + + /// Split the Uart into a transmitter and receiver, which is particularly + /// useful when having two tasks correlating to transmitting and receiving. + pub fn split(self) -> (UartTx<'a, M>, UartRx<'a, M>) { + (self.tx, self.rx) + } + + /// Split the Uart into a transmitter and receiver by mutable reference, + /// which is particularly useful when having two tasks correlating to + /// transmitting and receiving. + pub fn split_ref(&mut self) -> (&mut UartTx<'a, M>, &mut UartRx<'a, M>) { + (&mut self.tx, &mut self.rx) + } +} + +impl<'a> Uart<'a, Blocking> { + /// Create a new blocking UART + pub fn new_blocking( + _inner: Peri<'a, T>, + tx: Peri<'a, impl TxPin>, + rx: Peri<'a, impl RxPin>, + config: Config, + ) -> Result { + tx.as_tx(); + rx.as_rx(); + + let tx = tx.into(); + let rx = rx.into(); + + Self::init::(Some(tx), Some(rx), None, None, config)?; + + Ok(Self { + tx: UartTx::new_inner::(None), + rx: UartRx::new_inner::(None), + }) + } + + /// Read from UART RX blocking execution until done. + pub fn blocking_read(&mut self, buf: &mut [u8]) -> Result<()> { + self.rx.blocking_read(buf) + } + + /// Read from UART RX. Non-blocking version, bails out if it would + /// block. + pub fn read(&mut self, buf: &mut [u8]) -> Result<()> { + self.rx.read(buf) + } + + /// Transmit the provided buffer blocking execution until done. + pub fn blocking_write(&mut self, buf: &[u8]) -> Result<()> { + self.tx.blocking_write(buf) + } + + /// Transmit the provided buffer. Non-blocking version, bails out + /// if it would block. + pub fn write(&mut self, buf: &[u8]) -> Result<()> { + self.tx.write(buf) + } + + /// Flush UART TX blocking execution until done. + pub fn blocking_flush(&mut self) -> Result<()> { + self.tx.blocking_flush() + } + + /// Flush UART TX. + pub fn flush(&mut self) -> Result<()> { + self.tx.flush() + } +} + +impl<'a> UartTx<'a, Async> { + /// Create a new DMA enabled UART which can only send data + pub fn new_async( + _inner: Peri<'a, T>, + tx: Peri<'a, impl TxPin>, + _irq: impl interrupt::typelevel::Binding> + 'a, + tx_dma: Peri<'a, impl TxDma>, + config: Config, + ) -> Result { + tx.as_tx(); + + let _tx = tx.into(); + Uart::::init::(Some(_tx), None, None, None, config)?; + + T::Interrupt::unpend(); + unsafe { T::Interrupt::enable() }; + + Ok(Self::new_inner::(Some(tx_dma.into()))) + } + + /// Transmit the provided buffer asynchronously. + pub async fn write(&mut self, buf: &[u8]) -> Result<()> { + let regs = self.info.regs; + + // Disable DMA on completion/cancellation + let _dma_guard = OnDrop::new(|| { + regs.fifocfg().modify(|_, w| w.dmatx().disabled()); + }); + + for chunk in buf.chunks(1024) { + regs.fifocfg().modify(|_, w| w.dmatx().enabled()); + + let ch = self.tx_dma.as_mut().unwrap().reborrow(); + let transfer = unsafe { dma::write(ch, chunk, regs.fifowr().as_ptr() as *mut u8) }; + + let res = select( + transfer, + poll_fn(|cx| { + UART_WAKERS[self.info.index].register(cx.waker()); + + self.info.regs.intenset().write(|w| { + w.framerren() + .set_bit() + .parityerren() + .set_bit() + .rxnoiseen() + .set_bit() + .aberren() + .set_bit() + }); + + let stat = self.info.regs.stat().read(); + + self.info.regs.stat().write(|w| { + w.framerrint() + .clear_bit_by_one() + .parityerrint() + .clear_bit_by_one() + .rxnoiseint() + .clear_bit_by_one() + .aberr() + .clear_bit_by_one() + }); + + if stat.framerrint().bit_is_set() { + Poll::Ready(Err(Error::Framing)) + } else if stat.parityerrint().bit_is_set() { + Poll::Ready(Err(Error::Parity)) + } else if stat.rxnoiseint().bit_is_set() { + Poll::Ready(Err(Error::Noise)) + } else if stat.aberr().bit_is_set() { + Poll::Ready(Err(Error::Fail)) + } else { + Poll::Pending + } + }), + ) + .await; + + match res { + Either::First(()) | Either::Second(Ok(())) => (), + Either::Second(e) => return e, + } + } + + Ok(()) + } + + /// Flush UART TX asynchronously. + pub async fn flush(&mut self) -> Result<()> { + self.wait_on( + |me| { + if me.info.regs.stat().read().txidle().bit_is_set() { + Poll::Ready(Ok(())) + } else { + Poll::Pending + } + }, + |me| { + me.info.regs.intenset().write(|w| w.txidleen().set_bit()); + }, + ) + .await + } + + /// Calls `f` to check if we are ready or not. + /// If not, `g` is called once the waker is set (to eg enable the required interrupts). + async fn wait_on(&mut self, mut f: F, mut g: G) -> U + where + F: FnMut(&mut Self) -> Poll, + G: FnMut(&mut Self), + { + poll_fn(|cx| { + // Register waker before checking condition, to ensure that wakes/interrupts + // aren't lost between f() and g() + UART_WAKERS[self.info.index].register(cx.waker()); + let r = f(self); + + if r.is_pending() { + g(self); + } + + r + }) + .await + } +} + +impl<'a> UartRx<'a, Async> { + /// Create a new DMA enabled UART which can only receive data + pub fn new_async( + _inner: Peri<'a, T>, + rx: Peri<'a, impl RxPin>, + _irq: impl interrupt::typelevel::Binding> + 'a, + rx_dma: Peri<'a, impl RxDma>, + config: Config, + ) -> Result { + rx.as_rx(); + + let _rx = rx.into(); + Uart::::init::(None, Some(_rx), None, None, config)?; + + T::Interrupt::unpend(); + unsafe { T::Interrupt::enable() }; + + Ok(Self::new_inner::(Some(rx_dma.into()))) + } + + /// Read from UART RX asynchronously. + pub async fn read(&mut self, buf: &mut [u8]) -> Result<()> { + let regs = self.info.regs; + + // Disable DMA on completion/cancellation + let _dma_guard = OnDrop::new(|| { + regs.fifocfg().modify(|_, w| w.dmarx().disabled()); + }); + + for chunk in buf.chunks_mut(1024) { + regs.fifocfg().modify(|_, w| w.dmarx().enabled()); + + let ch = self.rx_dma.as_mut().unwrap().reborrow(); + let transfer = unsafe { dma::read(ch, regs.fiford().as_ptr() as *const u8, chunk) }; + + let res = select( + transfer, + poll_fn(|cx| { + UART_WAKERS[self.info.index].register(cx.waker()); + + self.info.regs.intenset().write(|w| { + w.framerren() + .set_bit() + .parityerren() + .set_bit() + .rxnoiseen() + .set_bit() + .aberren() + .set_bit() + }); + + let stat = self.info.regs.stat().read(); + + self.info.regs.stat().write(|w| { + w.framerrint() + .clear_bit_by_one() + .parityerrint() + .clear_bit_by_one() + .rxnoiseint() + .clear_bit_by_one() + .aberr() + .clear_bit_by_one() + }); + + if stat.framerrint().bit_is_set() { + Poll::Ready(Err(Error::Framing)) + } else if stat.parityerrint().bit_is_set() { + Poll::Ready(Err(Error::Parity)) + } else if stat.rxnoiseint().bit_is_set() { + Poll::Ready(Err(Error::Noise)) + } else if stat.aberr().bit_is_set() { + Poll::Ready(Err(Error::Fail)) + } else { + Poll::Pending + } + }), + ) + .await; + + match res { + Either::First(()) | Either::Second(Ok(())) => (), + Either::Second(e) => return e, + } + } + + Ok(()) + } +} + +impl<'a> Uart<'a, Async> { + /// Create a new DMA enabled UART + pub fn new_async( + _inner: Peri<'a, T>, + tx: Peri<'a, impl TxPin>, + rx: Peri<'a, impl RxPin>, + _irq: impl interrupt::typelevel::Binding> + 'a, + tx_dma: Peri<'a, impl TxDma>, + rx_dma: Peri<'a, impl RxDma>, + config: Config, + ) -> Result { + tx.as_tx(); + rx.as_rx(); + + let tx = tx.into(); + let rx = rx.into(); + + T::Interrupt::unpend(); + unsafe { T::Interrupt::enable() }; + + Self::init::(Some(tx), Some(rx), None, None, config)?; + + Ok(Self { + tx: UartTx::new_inner::(Some(tx_dma.into())), + rx: UartRx::new_inner::(Some(rx_dma.into())), + }) + } + + /// Create a new DMA enabled UART with hardware flow control (RTS/CTS) + pub fn new_with_rtscts( + _inner: Peri<'a, T>, + tx: Peri<'a, impl TxPin>, + rx: Peri<'a, impl RxPin>, + rts: Peri<'a, impl RtsPin>, + cts: Peri<'a, impl CtsPin>, + _irq: impl interrupt::typelevel::Binding> + 'a, + tx_dma: Peri<'a, impl TxDma>, + rx_dma: Peri<'a, impl RxDma>, + config: Config, + ) -> Result { + tx.as_tx(); + rx.as_rx(); + rts.as_rts(); + cts.as_cts(); + + let tx = tx.into(); + let rx = rx.into(); + let rts = rts.into(); + let cts = cts.into(); + + Self::init::(Some(tx), Some(rx), Some(rts), Some(cts), config)?; + + Ok(Self { + tx: UartTx::new_inner::(Some(tx_dma.into())), + rx: UartRx::new_inner::(Some(rx_dma.into())), + }) + } + + /// Read from UART RX. + pub async fn read(&mut self, buf: &mut [u8]) -> Result<()> { + self.rx.read(buf).await + } + + /// Transmit the provided buffer. + pub async fn write(&mut self, buf: &[u8]) -> Result<()> { + self.tx.write(buf).await + } + + /// Flush UART TX. + pub async fn flush(&mut self) -> Result<()> { + self.tx.flush().await + } +} + +impl embedded_hal_02::serial::Read for UartRx<'_, Blocking> { + type Error = Error; + + fn read(&mut self) -> core::result::Result> { + let mut buf = [0; 1]; + + match self.read(&mut buf) { + Ok(_) => Ok(buf[0]), + Err(Error::RxFifoEmpty) => Err(nb::Error::WouldBlock), + Err(e) => Err(nb::Error::Other(e)), + } + } +} + +impl embedded_hal_02::serial::Write for UartTx<'_, Blocking> { + type Error = Error; + + fn write(&mut self, word: u8) -> core::result::Result<(), nb::Error> { + match self.write(&[word]) { + Ok(_) => Ok(()), + Err(Error::TxFifoFull) => Err(nb::Error::WouldBlock), + Err(e) => Err(nb::Error::Other(e)), + } + } + + fn flush(&mut self) -> core::result::Result<(), nb::Error> { + match self.flush() { + Ok(_) => Ok(()), + Err(Error::TxBusy) => Err(nb::Error::WouldBlock), + Err(e) => Err(nb::Error::Other(e)), + } + } +} + +impl embedded_hal_02::blocking::serial::Write for UartTx<'_, Blocking> { + type Error = Error; + + fn bwrite_all(&mut self, buffer: &[u8]) -> core::result::Result<(), Self::Error> { + self.blocking_write(buffer) + } + + fn bflush(&mut self) -> core::result::Result<(), Self::Error> { + self.blocking_flush() + } +} + +impl embedded_hal_02::serial::Read for Uart<'_, Blocking> { + type Error = Error; + + fn read(&mut self) -> core::result::Result> { + embedded_hal_02::serial::Read::read(&mut self.rx) + } +} + +impl embedded_hal_02::serial::Write for Uart<'_, Blocking> { + type Error = Error; + + fn write(&mut self, word: u8) -> core::result::Result<(), nb::Error> { + embedded_hal_02::serial::Write::write(&mut self.tx, word) + } + + fn flush(&mut self) -> core::result::Result<(), nb::Error> { + embedded_hal_02::serial::Write::flush(&mut self.tx) + } +} + +impl embedded_hal_02::blocking::serial::Write for Uart<'_, Blocking> { + type Error = Error; + + fn bwrite_all(&mut self, buffer: &[u8]) -> core::result::Result<(), Self::Error> { + self.blocking_write(buffer) + } + + fn bflush(&mut self) -> core::result::Result<(), Self::Error> { + self.blocking_flush() + } +} + +impl embedded_hal_nb::serial::Error for Error { + fn kind(&self) -> embedded_hal_nb::serial::ErrorKind { + match *self { + Self::Framing => embedded_hal_nb::serial::ErrorKind::FrameFormat, + Self::Overrun => embedded_hal_nb::serial::ErrorKind::Overrun, + Self::Parity => embedded_hal_nb::serial::ErrorKind::Parity, + Self::Noise => embedded_hal_nb::serial::ErrorKind::Noise, + _ => embedded_hal_nb::serial::ErrorKind::Other, + } + } +} + +impl embedded_hal_nb::serial::ErrorType for UartRx<'_, Blocking> { + type Error = Error; +} + +impl embedded_hal_nb::serial::ErrorType for UartTx<'_, Blocking> { + type Error = Error; +} + +impl embedded_hal_nb::serial::ErrorType for Uart<'_, Blocking> { + type Error = Error; +} + +impl embedded_hal_nb::serial::Read for UartRx<'_, Blocking> { + fn read(&mut self) -> nb::Result { + let mut buf = [0; 1]; + + match self.read(&mut buf) { + Ok(_) => Ok(buf[0]), + Err(Error::RxFifoEmpty) => Err(nb::Error::WouldBlock), + Err(e) => Err(nb::Error::Other(e)), + } + } +} + +impl embedded_hal_nb::serial::Write for UartTx<'_, Blocking> { + fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> { + match self.write(&[word]) { + Ok(_) => Ok(()), + Err(Error::TxFifoFull) => Err(nb::Error::WouldBlock), + Err(e) => Err(nb::Error::Other(e)), + } + } + + fn flush(&mut self) -> nb::Result<(), Self::Error> { + match self.flush() { + Ok(_) => Ok(()), + Err(Error::TxBusy) => Err(nb::Error::WouldBlock), + Err(e) => Err(nb::Error::Other(e)), + } + } +} + +impl embedded_hal_nb::serial::Read for Uart<'_, Blocking> { + fn read(&mut self) -> core::result::Result> { + embedded_hal_02::serial::Read::read(&mut self.rx) + } +} + +impl embedded_hal_nb::serial::Write for Uart<'_, Blocking> { + fn write(&mut self, char: u8) -> nb::Result<(), Self::Error> { + self.blocking_write(&[char]).map_err(nb::Error::Other) + } + + fn flush(&mut self) -> nb::Result<(), Self::Error> { + self.blocking_flush().map_err(nb::Error::Other) + } +} + +struct Info { + regs: &'static crate::pac::usart0::RegisterBlock, + index: usize, + refcnt: AtomicU8, +} + +trait SealedInstance { + fn info() -> Info; + fn index() -> usize; +} + +/// UART interrupt handler. +pub struct InterruptHandler { + _phantom: PhantomData, +} + +const UART_COUNT: usize = 8; +static UART_WAKERS: [AtomicWaker; UART_COUNT] = [const { AtomicWaker::new() }; UART_COUNT]; + +impl interrupt::typelevel::Handler for InterruptHandler { + unsafe fn on_interrupt() { + let waker = &UART_WAKERS[T::index()]; + let regs = T::info().regs; + let stat = regs.intstat().read(); + + if stat.txidle().bit_is_set() + || stat.framerrint().bit_is_set() + || stat.parityerrint().bit_is_set() + || stat.rxnoiseint().bit_is_set() + || stat.aberrint().bit_is_set() + { + regs.intenclr().write(|w| { + w.txidleclr() + .set_bit() + .framerrclr() + .set_bit() + .parityerrclr() + .set_bit() + .rxnoiseclr() + .set_bit() + .aberrclr() + .set_bit() + }); + } + + waker.wake(); + } +} + +/// UART instance trait. +#[allow(private_bounds)] +pub trait Instance: crate::flexcomm::IntoUsart + SealedInstance + PeripheralType + 'static + Send { + /// Interrupt for this UART instance. + type Interrupt: interrupt::typelevel::Interrupt; +} + +macro_rules! impl_instance { + ($($n:expr),*) => { + $( + paste!{ + impl SealedInstance for crate::peripherals::[] { + fn info() -> Info { + Info { + regs: unsafe { &*crate::pac::[]::ptr() }, + index: $n, + refcnt: AtomicU8::new(0), + } + } + + #[inline] + fn index() -> usize { + $n + } + } + + impl Instance for crate::peripherals::[] { + type Interrupt = crate::interrupt::typelevel::[]; + } + } + )* + }; +} + +impl_instance!(0, 1, 2, 3, 4, 5, 6, 7); + +impl Sealed for T {} + +/// io configuration trait for Uart Tx configuration +pub trait TxPin: Pin + Sealed + PeripheralType { + /// convert the pin to appropriate function for Uart Tx usage + fn as_tx(&self); +} + +/// io configuration trait for Uart Rx configuration +pub trait RxPin: Pin + Sealed + PeripheralType { + /// convert the pin to appropriate function for Uart Rx usage + fn as_rx(&self); +} + +/// io configuration trait for Uart Cts +pub trait CtsPin: Pin + Sealed + PeripheralType { + /// convert the pin to appropriate function for Uart Cts usage + fn as_cts(&self); +} + +/// io configuration trait for Uart Rts +pub trait RtsPin: Pin + Sealed + PeripheralType { + /// convert the pin to appropriate function for Uart Rts usage + fn as_rts(&self); +} + +macro_rules! impl_pin_trait { + ($fcn:ident, $mode:ident, $($pin:ident, $fn:ident),*) => { + paste! { + $( + impl [<$mode:camel Pin>] for crate::peripherals::$pin { + fn [](&self) { + // UM11147 table 507 pg 495 + self.set_function(crate::iopctl::Function::$fn) + .set_pull(Pull::None) + .enable_input_buffer() + .set_slew_rate(SlewRate::Standard) + .set_drive_strength(DriveStrength::Normal) + .disable_analog_multiplex() + .set_drive_mode(DriveMode::PushPull) + .set_input_inverter(Inverter::Disabled); + } + } + )* + } + }; +} + +// FLEXCOMM0 +impl_pin_trait!(FLEXCOMM0, tx, PIO0_1, F1, PIO3_1, F5); +impl_pin_trait!(FLEXCOMM0, rx, PIO0_2, F1, PIO3_2, F5); +impl_pin_trait!(FLEXCOMM0, cts, PIO0_3, F1, PIO3_3, F5); +impl_pin_trait!(FLEXCOMM0, rts, PIO0_4, F1, PIO3_4, F5); + +// FLEXCOMM1 +impl_pin_trait!(FLEXCOMM1, tx, PIO0_8, F1, PIO7_26, F1); +impl_pin_trait!(FLEXCOMM1, rx, PIO0_9, F1, PIO7_27, F1); +impl_pin_trait!(FLEXCOMM1, cts, PIO0_10, F1, PIO7_28, F1); +impl_pin_trait!(FLEXCOMM1, rts, PIO0_11, F1, PIO7_29, F1); + +// FLEXCOMM2 +impl_pin_trait!(FLEXCOMM2, tx, PIO0_15, F1, PIO7_30, F5); +impl_pin_trait!(FLEXCOMM2, rx, PIO0_16, F1, PIO7_31, F5); +impl_pin_trait!(FLEXCOMM2, cts, PIO0_17, F1, PIO4_8, F5); +impl_pin_trait!(FLEXCOMM2, rts, PIO0_18, F1); + +// FLEXCOMM3 +impl_pin_trait!(FLEXCOMM3, tx, PIO0_22, F1); +impl_pin_trait!(FLEXCOMM3, rx, PIO0_23, F1); +impl_pin_trait!(FLEXCOMM3, cts, PIO0_24, F1); +impl_pin_trait!(FLEXCOMM3, rts, PIO0_25, F1); + +// FLEXCOMM4 +impl_pin_trait!(FLEXCOMM4, tx, PIO0_29, F1); +impl_pin_trait!(FLEXCOMM4, rx, PIO0_30, F1); +impl_pin_trait!(FLEXCOMM4, cts, PIO0_31, F1); +impl_pin_trait!(FLEXCOMM4, rts, PIO1_0, F1); + +// FLEXCOMM5 +impl_pin_trait!(FLEXCOMM5, tx, PIO1_4, F1, PIO3_16, F5); +impl_pin_trait!(FLEXCOMM5, rx, PIO1_5, F1, PIO3_17, F5); +impl_pin_trait!(FLEXCOMM5, cts, PIO1_6, F1, PIO3_18, F5); +impl_pin_trait!(FLEXCOMM5, rts, PIO1_7, F1, PIO3_23, F5); + +// FLEXCOMM6 +impl_pin_trait!(FLEXCOMM6, tx, PIO3_26, F1); +impl_pin_trait!(FLEXCOMM6, rx, PIO3_27, F1); +impl_pin_trait!(FLEXCOMM6, cts, PIO3_28, F1); +impl_pin_trait!(FLEXCOMM6, rts, PIO3_29, F1); + +// FLEXCOMM7 +impl_pin_trait!(FLEXCOMM7, tx, PIO4_1, F1); +impl_pin_trait!(FLEXCOMM7, rx, PIO4_2, F1); +impl_pin_trait!(FLEXCOMM7, cts, PIO4_3, F1); +impl_pin_trait!(FLEXCOMM7, rts, PIO4_4, F1); + +/// UART Tx DMA trait. +#[allow(private_bounds)] +pub trait TxDma: crate::dma::Channel {} + +/// UART Rx DMA trait. +#[allow(private_bounds)] +pub trait RxDma: crate::dma::Channel {} + +macro_rules! impl_dma { + ($fcn:ident, $mode:ident, $dma:ident) => { + paste! { + impl [<$mode Dma>] for crate::peripherals::$dma {} + } + }; +} + +impl_dma!(FLEXCOMM0, Rx, DMA0_CH0); +impl_dma!(FLEXCOMM0, Tx, DMA0_CH1); + +impl_dma!(FLEXCOMM1, Rx, DMA0_CH2); +impl_dma!(FLEXCOMM1, Tx, DMA0_CH3); + +impl_dma!(FLEXCOMM2, Rx, DMA0_CH4); +impl_dma!(FLEXCOMM2, Tx, DMA0_CH5); + +impl_dma!(FLEXCOMM3, Rx, DMA0_CH6); +impl_dma!(FLEXCOMM3, Tx, DMA0_CH7); + +impl_dma!(FLEXCOMM4, Rx, DMA0_CH8); +impl_dma!(FLEXCOMM4, Tx, DMA0_CH9); + +impl_dma!(FLEXCOMM5, Rx, DMA0_CH10); +impl_dma!(FLEXCOMM5, Tx, DMA0_CH11); + +impl_dma!(FLEXCOMM6, Rx, DMA0_CH12); +impl_dma!(FLEXCOMM6, Tx, DMA0_CH13); + +impl_dma!(FLEXCOMM7, Rx, DMA0_CH14); +impl_dma!(FLEXCOMM7, Tx, DMA0_CH15); diff --git a/embassy-imxrt/src/gpio.rs b/embassy-imxrt/src/gpio.rs index 6883c4ee0..e62fde8b1 100644 --- a/embassy-imxrt/src/gpio.rs +++ b/embassy-imxrt/src/gpio.rs @@ -13,7 +13,7 @@ use crate::clocks::enable_and_reset; use crate::iopctl::IopctlPin; pub use crate::iopctl::{AnyPin, DriveMode, DriveStrength, Function, Inverter, Pull, SlewRate}; use crate::sealed::Sealed; -use crate::{interrupt, peripherals, Peri, PeripheralType}; +use crate::{interrupt, peripherals, BitIter, Peri, PeripheralType}; // This should be unique per IMXRT package const PORT_COUNT: usize = 8; @@ -63,24 +63,6 @@ fn GPIO_INTA() { irq_handler(&GPIO_WAKERS); } -#[cfg(feature = "rt")] -struct BitIter(u32); - -#[cfg(feature = "rt")] -impl Iterator for BitIter { - type Item = u32; - - fn next(&mut self) -> Option { - match self.0.trailing_zeros() { - 32 => None, - b => { - self.0 &= !(1 << b); - Some(b) - } - } - } -} - #[cfg(feature = "rt")] fn irq_handler(port_wakers: &[Option<&PortWaker>]) { let reg = unsafe { crate::pac::Gpio::steal() }; diff --git a/embassy-imxrt/src/lib.rs b/embassy-imxrt/src/lib.rs index b1183d8fc..ad0d9e21c 100644 --- a/embassy-imxrt/src/lib.rs +++ b/embassy-imxrt/src/lib.rs @@ -19,6 +19,8 @@ pub(crate) mod fmt; pub mod clocks; pub mod crc; +pub mod dma; +pub mod flexcomm; pub mod gpio; pub mod iopctl; pub mod rng; @@ -129,14 +131,16 @@ pub fn init(config: config::Config) -> Peripherals { // before doing anything important. let peripherals = Peripherals::take(); + #[cfg(feature = "_time-driver")] + time_driver::init(config.time_interrupt_priority); + unsafe { if let Err(e) = clocks::init(config.clocks) { error!("unable to initialize Clocks for reason: {:?}", e); // Panic here? } + dma::init(); } - #[cfg(feature = "_time-driver")] - time_driver::init(config.time_interrupt_priority); gpio::init(); peripherals @@ -145,3 +149,21 @@ pub fn init(config: config::Config) -> Peripherals { pub(crate) mod sealed { pub trait Sealed {} } + +#[cfg(feature = "rt")] +struct BitIter(u32); + +#[cfg(feature = "rt")] +impl Iterator for BitIter { + type Item = u32; + + fn next(&mut self) -> Option { + match self.0.trailing_zeros() { + 32 => None, + b => { + self.0 &= !(1 << b); + Some(b) + } + } + } +} diff --git a/examples/mimxrt6/src/bin/uart-async.rs b/examples/mimxrt6/src/bin/uart-async.rs new file mode 100644 index 000000000..58e31f379 --- /dev/null +++ b/examples/mimxrt6/src/bin/uart-async.rs @@ -0,0 +1,87 @@ +#![no_std] +#![no_main] + +extern crate embassy_imxrt_examples; + +use defmt::info; +use embassy_executor::Spawner; +use embassy_imxrt::flexcomm::uart::{self, Async, Uart}; +use embassy_imxrt::{bind_interrupts, peripherals}; +use embassy_time::Timer; +use {defmt_rtt as _, panic_probe as _}; + +bind_interrupts!(struct Irqs { + FLEXCOMM2 => uart::InterruptHandler; + FLEXCOMM4 => uart::InterruptHandler; +}); + +const BUFLEN: usize = 16; + +#[embassy_executor::task] +async fn usart4_task(mut uart: Uart<'static, Async>) { + info!("RX Task"); + + loop { + let mut rx_buf = [0; BUFLEN]; + uart.read(&mut rx_buf).await.unwrap(); + info!("usart4: rx_buf {:02x}", rx_buf); + + Timer::after_millis(10).await; + + let tx_buf = [0xaa; BUFLEN]; + uart.write(&tx_buf).await.unwrap(); + info!("usart4: tx_buf {:02x}", tx_buf); + } +} + +#[embassy_executor::task] +async fn usart2_task(mut uart: Uart<'static, Async>) { + info!("TX Task"); + + loop { + let tx_buf = [0x55; BUFLEN]; + uart.write(&tx_buf).await.unwrap(); + info!("usart2: tx_buf {:02x}", tx_buf); + + Timer::after_millis(10).await; + + let mut rx_buf = [0x00; BUFLEN]; + uart.read(&mut rx_buf).await.unwrap(); + info!("usart2: rx_buf {:02x}", rx_buf); + } +} + +#[embassy_executor::main] +async fn main(spawner: Spawner) { + let p = embassy_imxrt::init(Default::default()); + + info!("UART test start"); + + let usart4 = Uart::new_with_rtscts( + p.FLEXCOMM4, + p.PIO0_29, + p.PIO0_30, + p.PIO1_0, + p.PIO0_31, + Irqs, + p.DMA0_CH9, + p.DMA0_CH8, + Default::default(), + ) + .unwrap(); + spawner.must_spawn(usart4_task(usart4)); + + let usart2 = Uart::new_with_rtscts( + p.FLEXCOMM2, + p.PIO0_15, + p.PIO0_16, + p.PIO0_18, + p.PIO0_17, + Irqs, + p.DMA0_CH5, + p.DMA0_CH4, + Default::default(), + ) + .unwrap(); + spawner.must_spawn(usart2_task(usart2)); +} diff --git a/examples/mimxrt6/src/bin/uart.rs b/examples/mimxrt6/src/bin/uart.rs new file mode 100644 index 000000000..d6a75f85d --- /dev/null +++ b/examples/mimxrt6/src/bin/uart.rs @@ -0,0 +1,55 @@ +#![no_std] +#![no_main] + +extern crate embassy_imxrt_examples; + +use defmt::info; +use embassy_executor::Spawner; +use embassy_imxrt::flexcomm::uart::{Blocking, Uart, UartRx, UartTx}; +use embassy_time::Timer; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::task] +async fn usart4_task(mut uart: UartRx<'static, Blocking>) { + info!("RX Task"); + + loop { + let mut buf = [0; 8]; + + Timer::after_millis(10).await; + + uart.blocking_read(&mut buf).unwrap(); + + let s = core::str::from_utf8(&buf).unwrap(); + + info!("Received '{}'", s); + } +} + +#[embassy_executor::task] +async fn usart2_task(mut uart: UartTx<'static, Blocking>) { + info!("TX Task"); + + loop { + let buf = "Testing\0".as_bytes(); + + uart.blocking_write(buf).unwrap(); + + Timer::after_millis(10).await; + } +} + +#[embassy_executor::main] +async fn main(spawner: Spawner) { + let p = embassy_imxrt::init(Default::default()); + + info!("UART test start"); + + let usart4 = Uart::new_blocking(p.FLEXCOMM4, p.PIO0_29, p.PIO0_30, Default::default()).unwrap(); + + let (_, usart4) = usart4.split(); + spawner.must_spawn(usart4_task(usart4)); + + let usart2 = UartTx::new_blocking(p.FLEXCOMM2, p.PIO0_15, Default::default()).unwrap(); + spawner.must_spawn(usart2_task(usart2)); +} From 117eb45fa0829239da9152b9cf54c3cf706dc76d Mon Sep 17 00:00:00 2001 From: Ralph Ursprung Date: Thu, 15 May 2025 17:53:31 +0200 Subject: [PATCH 1134/1217] add the possibility to document `bind_interrupts` `struct`s the `bind_interrupts` macro creates a `struct` for the interrupts. it was so far not possible to document those (except for STM32) and there was no generic documentation being generated/added either, thus the `missing_docs` lint was triggered for consumers which enabled it. with this change it is now possible to manually add a comment on the `struct` being defined in the macro invocation. to show that this works one RP example has been modified accordingly. --- embassy-imxrt/src/lib.rs | 12 ++++++++---- embassy-nrf/src/lib.rs | 12 ++++++++---- embassy-rp/src/lib.rs | 12 ++++++++---- embassy-stm32/src/lib.rs | 13 ++++++++----- examples/rp/src/bin/adc.rs | 9 ++++++--- 5 files changed, 38 insertions(+), 20 deletions(-) diff --git a/embassy-imxrt/src/lib.rs b/embassy-imxrt/src/lib.rs index b1183d8fc..5b7341fbd 100644 --- a/embassy-imxrt/src/lib.rs +++ b/embassy-imxrt/src/lib.rs @@ -54,16 +54,20 @@ pub use crate::pac::NVIC_PRIO_BITS; /// ```rust,ignore /// use embassy_imxrt::{bind_interrupts, flexspi, peripherals}; /// -/// bind_interrupts!(struct Irqs { -/// FLEXSPI_IRQ => flexspi::InterruptHandler; -/// }); +/// bind_interrupts!( +/// /// Binds the FLEXSPI interrupt. +/// struct Irqs { +/// FLEXSPI_IRQ => flexspi::InterruptHandler; +/// } +/// ); /// ``` /// // developer note: this macro can't be in `embassy-hal-internal` due to the use of `$crate`. #[macro_export] macro_rules! bind_interrupts { - ($vis:vis struct $name:ident { $($irq:ident => $($handler:ty),*;)* }) => { + ($(#[$attr:meta])* $vis:vis struct $name:ident { $($irq:ident => $($handler:ty),*;)* }) => { #[derive(Copy, Clone)] + $(#[$attr])* $vis struct $name; $( diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index 7d86e1218..0c5dd059d 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs @@ -200,9 +200,12 @@ mod chip; /// ```rust,ignore /// use embassy_nrf::{bind_interrupts, spim, peripherals}; /// -/// bind_interrupts!(struct Irqs { -/// SPIM3 => spim::InterruptHandler; -/// }); +/// bind_interrupts!( +/// /// Binds the SPIM3 interrupt. +/// struct Irqs { +/// SPIM3 => spim::InterruptHandler; +/// } +/// ); /// ``` /// /// Example of how to bind multiple interrupts in a single macro invocation: @@ -219,7 +222,7 @@ mod chip; // developer note: this macro can't be in `embassy-hal-internal` due to the use of `$crate`. #[macro_export] macro_rules! bind_interrupts { - ($vis:vis struct $name:ident { + ($(#[$attr:meta])* $vis:vis struct $name:ident { $( $(#[cfg($cond_irq:meta)])? $irq:ident => $( @@ -229,6 +232,7 @@ macro_rules! bind_interrupts { )* }) => { #[derive(Copy, Clone)] + $(#[$attr])* $vis struct $name; $( diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs index f549446bc..f3c5a35bb 100644 --- a/embassy-rp/src/lib.rs +++ b/embassy-rp/src/lib.rs @@ -160,15 +160,18 @@ embassy_hal_internal::interrupt_mod!( /// ```rust,ignore /// use embassy_rp::{bind_interrupts, usb, peripherals}; /// -/// bind_interrupts!(struct Irqs { -/// USBCTRL_IRQ => usb::InterruptHandler; -/// }); +/// bind_interrupts!( +/// /// Binds the USB Interrupts. +/// struct Irqs { +/// USBCTRL_IRQ => usb::InterruptHandler; +/// } +/// ); /// ``` /// // developer note: this macro can't be in `embassy-hal-internal` due to the use of `$crate`. #[macro_export] macro_rules! bind_interrupts { - ($vis:vis struct $name:ident { + ($(#[$attr:meta])* $vis:vis struct $name:ident { $( $(#[cfg($cond_irq:meta)])? $irq:ident => $( @@ -178,6 +181,7 @@ macro_rules! bind_interrupts { )* }) => { #[derive(Copy, Clone)] + $(#[$attr])* $vis struct $name; $( diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index f8d09413d..973acc9bb 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -163,11 +163,14 @@ pub use crate::_generated::interrupt; /// ```rust,ignore /// use embassy_stm32::{bind_interrupts, i2c, peripherals}; /// -/// bind_interrupts!(struct Irqs { -/// I2C1 => i2c::EventInterruptHandler, i2c::ErrorInterruptHandler; -/// I2C2_3 => i2c::EventInterruptHandler, i2c::ErrorInterruptHandler, -/// i2c::EventInterruptHandler, i2c::ErrorInterruptHandler; -/// }); +/// bind_interrupts!( +/// /// Binds the I2C interrupts. +/// struct Irqs { +/// I2C1 => i2c::EventInterruptHandler, i2c::ErrorInterruptHandler; +/// I2C2_3 => i2c::EventInterruptHandler, i2c::ErrorInterruptHandler, +/// i2c::EventInterruptHandler, i2c::ErrorInterruptHandler; +/// } +/// ); /// ``` // developer note: this macro can't be in `embassy-hal-internal` due to the use of `$crate`. diff --git a/examples/rp/src/bin/adc.rs b/examples/rp/src/bin/adc.rs index 1bb7c2249..015915586 100644 --- a/examples/rp/src/bin/adc.rs +++ b/examples/rp/src/bin/adc.rs @@ -12,9 +12,12 @@ use embassy_rp::gpio::Pull; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; -bind_interrupts!(struct Irqs { - ADC_IRQ_FIFO => InterruptHandler; -}); +bind_interrupts!( + /// Binds the ADC interrupts. + struct Irqs { + ADC_IRQ_FIFO => InterruptHandler; + } +); #[embassy_executor::main] async fn main(_spawner: Spawner) { From 05bfbacee55207f8065b6e9bbbc0d5454e77668f Mon Sep 17 00:00:00 2001 From: Ralph Ursprung Date: Thu, 15 May 2025 18:36:51 +0200 Subject: [PATCH 1135/1217] `embassy-nxp`: make `defmt` optional also enable it on all dependencies (where available). this is needed because in a next commit we'll add code to `embassy-hal-internal` which uses the feature in a macro, as it expects `defmt` to be optional in all embassy HALs. this was the only HAL where that wasn't the case. note that this is a breaking change for consumers! if you wish to use `defmt` in `embassy-nxp` you now need to enable the feature. --- embassy-nxp/Cargo.toml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/embassy-nxp/Cargo.toml b/embassy-nxp/Cargo.toml index cf36a67ec..031cd4aba 100644 --- a/embassy-nxp/Cargo.toml +++ b/embassy-nxp/Cargo.toml @@ -10,8 +10,11 @@ critical-section = "1.1.2" embassy-hal-internal = { version = "0.2.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-2"] } embassy-sync = { version = "0.6.2", path = "../embassy-sync" } lpc55-pac = "0.5.0" -defmt = "0.3.8" +defmt = { version = "0.3.8", optional = true } [features] default = ["rt"] -rt = ["lpc55-pac/rt"] \ No newline at end of file +rt = ["lpc55-pac/rt"] + +## Enable [defmt support](https://docs.rs/defmt) and enables `defmt` debug-log messages and formatting in embassy drivers. +defmt = ["dep:defmt", "embassy-hal-internal/defmt", "embassy-sync/defmt"] From 4a089fe2455f22f956455548816fcd96735e38d8 Mon Sep 17 00:00:00 2001 From: Ralph Ursprung Date: Thu, 15 May 2025 17:29:23 +0200 Subject: [PATCH 1136/1217] rp: add missing `Debug` and `defmt::Format` `derive`s for ADC this doesn't cover every `struct` & co. in `embassy-rp`, but at least it adds those needed for `Adc` and `adc::Channel`. --- embassy-hal-internal/src/macros.rs | 2 ++ embassy-hal-internal/src/peripheral.rs | 2 ++ embassy-rp/src/adc.rs | 2 ++ embassy-rp/src/gpio.rs | 2 ++ 4 files changed, 8 insertions(+) diff --git a/embassy-hal-internal/src/macros.rs b/embassy-hal-internal/src/macros.rs index cd2bc3cab..ce72ded5c 100644 --- a/embassy-hal-internal/src/macros.rs +++ b/embassy-hal-internal/src/macros.rs @@ -8,6 +8,8 @@ macro_rules! peripherals_definition { $(#[$cfg])? #[allow(non_camel_case_types)] #[doc = concat!(stringify!($name), " peripheral")] + #[derive(Debug)] + #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct $name { _private: () } $(#[$cfg])? diff --git a/embassy-hal-internal/src/peripheral.rs b/embassy-hal-internal/src/peripheral.rs index 803259bb8..b1868caf6 100644 --- a/embassy-hal-internal/src/peripheral.rs +++ b/embassy-hal-internal/src/peripheral.rs @@ -14,6 +14,8 @@ use core::ops::Deref; /// the driver code would be monomorphized two times. With Peri, the driver is generic /// over a lifetime only. `SPI4` becomes `Peri<'static, SPI4>`, and `&mut SPI4` becomes /// `Peri<'a, SPI4>`. Lifetimes don't cause monomorphization. +#[derive(Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct Peri<'a, T: PeripheralType> { inner: T, _lifetime: PhantomData<&'a mut T>, diff --git a/embassy-rp/src/adc.rs b/embassy-rp/src/adc.rs index ec0c8c46c..2db8e63d7 100644 --- a/embassy-rp/src/adc.rs +++ b/embassy-rp/src/adc.rs @@ -21,6 +21,8 @@ static WAKER: AtomicWaker = AtomicWaker::new(); #[derive(Default)] pub struct Config {} +#[derive(Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] enum Source<'p> { Pin(Peri<'p, AnyPin>), TempSensor(Peri<'p, ADC_TEMP_SENSOR>), diff --git a/embassy-rp/src/gpio.rs b/embassy-rp/src/gpio.rs index af0837f6a..2fb2d65c2 100644 --- a/embassy-rp/src/gpio.rs +++ b/embassy-rp/src/gpio.rs @@ -932,6 +932,8 @@ pub trait Pin: PeripheralType + Into + SealedPin + Sized + 'static { } /// Type-erased GPIO pin +#[derive(Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct AnyPin { pin_bank: u8, } From 466e1ee9eff2a40f562b0f970e3afcdeac017cfb Mon Sep 17 00:00:00 2001 From: Tobias Naumann Date: Fri, 16 May 2025 13:05:35 +0200 Subject: [PATCH 1137/1217] Impl Drop for stm32 Rng --- embassy-stm32/src/rng.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/embassy-stm32/src/rng.rs b/embassy-stm32/src/rng.rs index 250a08a39..8fa1b3a9d 100644 --- a/embassy-stm32/src/rng.rs +++ b/embassy-stm32/src/rng.rs @@ -186,6 +186,15 @@ impl<'d, T: Instance> Rng<'d, T> { } } +impl<'d, T: Instance> Drop for Rng<'d, T> { + fn drop(&mut self) { + T::regs().cr().modify(|reg| { + reg.set_rngen(false); + }); + rcc::disable::(); + } +} + impl<'d, T: Instance> RngCore for Rng<'d, T> { fn next_u32(&mut self) -> u32 { loop { From 1eb76eb59170f3953c390385fc572cf36536f652 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Fri, 16 May 2025 09:45:02 +0200 Subject: [PATCH 1138/1217] fix: add bank configuration doc build features --- embassy-stm32/Cargo.toml | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 972307bec..873c9b6ae 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -19,16 +19,22 @@ flavors = [ { regex_feature = "stm32f1.*", target = "thumbv7m-none-eabi" }, { regex_feature = "stm32f2.*", target = "thumbv7m-none-eabi" }, { regex_feature = "stm32f3.*", target = "thumbv7em-none-eabi" }, - { regex_feature = "stm32f4.*", target = "thumbv7em-none-eabi", features = ["low-power"] }, + { regex_feature = "stm32f4[2367]..[ig]", target = "thumbv7em-none-eabi", features = ["low-power", "dual-bank"] }, + { regex_feature = "stm32f4.*", target = "thumbv7em-none-eabi", features = ["low-power", "single-bank"] }, + { regex_feature = "stm32f7[67]..[ig]", target = "thumbv7em-none-eabi", features = ["dual-bank"] }, { regex_feature = "stm32f7.*", target = "thumbv7em-none-eabi" }, { regex_feature = "stm32c0.*", target = "thumbv6m-none-eabi" }, + { regex_feature = "stm32g0...c", target = "thumbv6m-none-eabi", features = ["dual-bank"] }, { regex_feature = "stm32g0.*", target = "thumbv6m-none-eabi" }, + { regex_feature = "stm32g4[78].*", target = "thumbv7em-none-eabi", features = ["low-power", "dual-bank"] }, { regex_feature = "stm32g4.*", target = "thumbv7em-none-eabi", features = ["low-power"] }, { regex_feature = "stm32h5.*", target = "thumbv8m.main-none-eabihf", features = ["low-power"] }, { regex_feature = "stm32h7.*", target = "thumbv7em-none-eabi" }, { regex_feature = "stm32l0.*", target = "thumbv6m-none-eabi", features = ["low-power"] }, { regex_feature = "stm32l1.*", target = "thumbv7m-none-eabi" }, + { regex_feature = "stm32l4[pqrs].*", target = "thumbv7em-none-eabi", features = ["dual-bank"] }, { regex_feature = "stm32l4.*", target = "thumbv7em-none-eabi" }, + { regex_feature = "stm32l5...e", target = "thumbv8m.main-none-eabihf", features = ["low-power", "dual-bank"] }, { regex_feature = "stm32l5.*", target = "thumbv8m.main-none-eabihf", features = ["low-power"] }, { regex_feature = "stm32u0.*", target = "thumbv6m-none-eabi" }, { regex_feature = "stm32u5.*", target = "thumbv8m.main-none-eabihf" }, @@ -38,7 +44,7 @@ flavors = [ ] [package.metadata.docs.rs] -features = ["defmt", "unstable-pac", "exti", "time-driver-any", "time", "stm32h755zi-cm7"] +features = ["defmt", "unstable-pac", "exti", "time-driver-any", "time", "stm32h755zi-cm7", "single-bank"] rustdoc-args = ["--cfg", "docsrs"] [dependencies] From e2d053e5a85bc0206b6d088f2b794211d0a46e96 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 16 May 2025 14:48:18 +0200 Subject: [PATCH 1139/1217] Fix a minor formatting issue in `README.md` --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 669fa469b..68d8460d3 100644 --- a/README.md +++ b/README.md @@ -12,8 +12,8 @@ Rust's [async/await](https://rust-lang.github.io/async-book/) allows for unprece ## Batteries included -- **Hardware Abstraction Layers - ** - HALs implement safe, idiomatic Rust APIs to use the hardware capabilities, so raw register manipulation is not needed. The Embassy project maintains HALs for select hardware, but you can still use HALs from other projects with Embassy. +- **Hardware Abstraction Layers** + - HALs implement safe, idiomatic Rust APIs to use the hardware capabilities, so raw register manipulation is not needed. The Embassy project maintains HALs for select hardware, but you can still use HALs from other projects with Embassy. - [embassy-stm32](https://docs.embassy.dev/embassy-stm32/), for all STM32 microcontroller families. - [embassy-nrf](https://docs.embassy.dev/embassy-nrf/), for the Nordic Semiconductor nRF52, nRF53, nRF54 and nRF91 series. - [embassy-rp](https://docs.embassy.dev/embassy-rp/), for the Raspberry Pi RP2040 and RP23xx microcontrollers. From e4fc48764491f8981e4a145a72e9b6e72df8c546 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sun, 18 May 2025 20:32:48 +0200 Subject: [PATCH 1140/1217] Add rand-core v0.9 support. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Aurélien Jacobs --- embassy-imxrt/Cargo.toml | 4 +- embassy-imxrt/src/rng.rs | 48 ++++++++++--- embassy-nrf/Cargo.toml | 4 +- embassy-nrf/src/rng.rs | 47 ++++++++---- embassy-rp/Cargo.toml | 4 +- embassy-rp/src/clocks.rs | 59 +++++++++++---- embassy-rp/src/trng.rs | 25 +++++-- embassy-stm32/Cargo.toml | 4 +- embassy-stm32/src/rng.rs | 72 +++++++++++++------ examples/mimxrt6/Cargo.toml | 1 - examples/mimxrt6/src/bin/rng.rs | 7 +- examples/nrf-rtos-trace/Cargo.toml | 1 - examples/nrf52840/Cargo.toml | 2 +- examples/nrf52840/src/bin/rng.rs | 2 +- examples/nrf5340/Cargo.toml | 1 - examples/rp/Cargo.toml | 3 +- examples/rp/src/bin/ethernet_w5500_icmp.rs | 1 - .../rp/src/bin/ethernet_w5500_icmp_ping.rs | 1 - .../rp/src/bin/ethernet_w5500_multisocket.rs | 1 - .../rp/src/bin/ethernet_w5500_tcp_client.rs | 1 - .../rp/src/bin/ethernet_w5500_tcp_server.rs | 1 - examples/rp/src/bin/ethernet_w5500_udp.rs | 1 - examples/rp/src/bin/orchestrate_tasks.rs | 1 - examples/rp/src/bin/sharing.rs | 1 - examples/rp/src/bin/spi_gc9a01.rs | 1 - examples/rp/src/bin/usb_ethernet.rs | 1 - examples/rp/src/bin/usb_hid_mouse.rs | 4 +- examples/rp/src/bin/wifi_ap_tcp_server.rs | 1 - examples/rp/src/bin/wifi_tcp_server.rs | 1 - examples/rp/src/bin/wifi_webrequest.rs | 1 - examples/rp235x/Cargo.toml | 1 - examples/rp235x/src/bin/sharing.rs | 1 - examples/rp235x/src/bin/trng.rs | 5 +- examples/std/Cargo.toml | 2 +- examples/std/src/bin/net.rs | 4 +- examples/std/src/bin/net_dns.rs | 4 +- examples/std/src/bin/net_ppp.rs | 4 +- examples/std/src/bin/net_udp.rs | 4 +- examples/std/src/bin/tcp_accept.rs | 4 +- examples/stm32f7/Cargo.toml | 1 - examples/stm32f7/src/bin/eth.rs | 1 - examples/stm32h5/Cargo.toml | 1 - examples/stm32h5/src/bin/eth.rs | 1 - examples/stm32h7/Cargo.toml | 1 - examples/stm32h7/src/bin/eth.rs | 1 - examples/stm32h7/src/bin/eth_client.rs | 1 - examples/stm32h7/src/bin/eth_client_mii.rs | 1 - examples/stm32h723/Cargo.toml | 1 - examples/stm32h742/Cargo.toml | 1 - examples/stm32h755cm4/Cargo.toml | 1 - examples/stm32h755cm7/Cargo.toml | 1 - examples/stm32h7b0/Cargo.toml | 1 - examples/stm32h7rs/Cargo.toml | 1 - examples/stm32h7rs/src/bin/eth.rs | 1 - examples/stm32l4/Cargo.toml | 1 - .../src/bin/spe_adin1110_http_server.rs | 1 - examples/stm32l5/Cargo.toml | 1 - examples/stm32l5/src/bin/usb_ethernet.rs | 1 - tests/rp/Cargo.toml | 1 - tests/rp/src/bin/ethernet_w5100s_perf.rs | 1 - tests/stm32/Cargo.toml | 4 +- tests/stm32/src/bin/eth.rs | 1 - tests/utils/Cargo.toml | 2 +- 63 files changed, 227 insertions(+), 131 deletions(-) mode change 100644 => 100755 examples/nrf52840/src/bin/rng.rs mode change 100644 => 100755 examples/rp/src/bin/usb_hid_mouse.rs diff --git a/embassy-imxrt/Cargo.toml b/embassy-imxrt/Cargo.toml index f16002a8d..d8cf3aaba 100644 --- a/embassy-imxrt/Cargo.toml +++ b/embassy-imxrt/Cargo.toml @@ -80,9 +80,11 @@ cortex-m = "0.7.6" critical-section = "1.1" embedded-io = { version = "0.6.1" } embedded-io-async = { version = "0.6.1" } -rand_core = "0.6.4" fixed = "1.23.1" +rand-core-06 = { package = "rand_core", version = "0.6" } +rand-core-09 = { package = "rand_core", version = "0.9" } + embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = [ "unproven", ] } diff --git a/embassy-imxrt/src/rng.rs b/embassy-imxrt/src/rng.rs index 67e7ab65d..75f243df9 100644 --- a/embassy-imxrt/src/rng.rs +++ b/embassy-imxrt/src/rng.rs @@ -6,7 +6,6 @@ use core::task::Poll; use embassy_futures::block_on; use embassy_sync::waitqueue::AtomicWaker; -use rand_core::{CryptoRng, RngCore}; use crate::clocks::{enable_and_reset, SysconPeripheral}; use crate::interrupt::typelevel::Interrupt; @@ -201,32 +200,63 @@ impl<'d> Rng<'d> { .mctl() .modify(|_, w| w.trng_acc().set_bit().prgm().clear_bit()); } -} -impl RngCore for Rng<'_> { - fn next_u32(&mut self) -> u32 { + /// Generate a random u32 + pub fn blocking_next_u32(&mut self) -> u32 { let mut bytes = [0u8; 4]; block_on(self.async_fill_bytes(&mut bytes)).unwrap(); u32::from_ne_bytes(bytes) } - fn next_u64(&mut self) -> u64 { + /// Generate a random u64 + pub fn blocking_next_u64(&mut self) -> u64 { let mut bytes = [0u8; 8]; block_on(self.async_fill_bytes(&mut bytes)).unwrap(); u64::from_ne_bytes(bytes) } - fn fill_bytes(&mut self, dest: &mut [u8]) { + /// Fill a slice with random bytes. + pub fn blocking_fill_bytes(&mut self, dest: &mut [u8]) { block_on(self.async_fill_bytes(dest)).unwrap(); } +} - fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core::Error> { - self.fill_bytes(dest); +impl<'d> rand_core_06::RngCore for Rng<'d> { + fn next_u32(&mut self) -> u32 { + self.blocking_next_u32() + } + + fn next_u64(&mut self) -> u64 { + self.blocking_next_u64() + } + + fn fill_bytes(&mut self, dest: &mut [u8]) { + self.blocking_fill_bytes(dest); + } + + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core_06::Error> { + self.blocking_fill_bytes(dest); Ok(()) } } -impl CryptoRng for Rng<'_> {} +impl<'d> rand_core_06::CryptoRng for Rng<'d> {} + +impl<'d> rand_core_09::RngCore for Rng<'d> { + fn next_u32(&mut self) -> u32 { + self.blocking_next_u32() + } + + fn next_u64(&mut self) -> u64 { + self.blocking_next_u64() + } + + fn fill_bytes(&mut self, dest: &mut [u8]) { + self.blocking_fill_bytes(dest); + } +} + +impl<'d> rand_core_09::CryptoRng for Rng<'d> {} struct Info { regs: crate::pac::Trng, diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml index 6ca099599..e4e143c65 100644 --- a/embassy-nrf/Cargo.toml +++ b/embassy-nrf/Cargo.toml @@ -154,6 +154,9 @@ embedded-hal-async = { version = "1.0" } embedded-io = { version = "0.6.0" } embedded-io-async = { version = "0.6.1" } +rand-core-06 = { package = "rand_core", version = "0.6" } +rand-core-09 = { package = "rand_core", version = "0.9" } + nrf-pac = "0.1.0" defmt = { version = "0.3", optional = true } @@ -162,7 +165,6 @@ log = { version = "0.4.14", optional = true } cortex-m-rt = ">=0.6.15,<0.8" cortex-m = "0.7.6" critical-section = "1.1" -rand_core = "0.6.3" fixed = "1.10.0" embedded-storage = "0.3.1" embedded-storage-async = "0.4.1" diff --git a/embassy-nrf/src/rng.rs b/embassy-nrf/src/rng.rs index e75ffda00..7e42dc938 100644 --- a/embassy-nrf/src/rng.rs +++ b/embassy-nrf/src/rng.rs @@ -167,6 +167,21 @@ impl<'d, T: Instance> Rng<'d, T> { self.stop(); } + + /// Generate a random u32 + pub fn blocking_next_u32(&mut self) -> u32 { + let mut bytes = [0; 4]; + self.blocking_fill_bytes(&mut bytes); + // We don't care about the endianness, so just use the native one. + u32::from_ne_bytes(bytes) + } + + /// Generate a random u64 + pub fn blocking_next_u64(&mut self) -> u64 { + let mut bytes = [0; 8]; + self.blocking_fill_bytes(&mut bytes); + u64::from_ne_bytes(bytes) + } } impl<'d, T: Instance> Drop for Rng<'d, T> { @@ -180,31 +195,37 @@ impl<'d, T: Instance> Drop for Rng<'d, T> { } } -impl<'d, T: Instance> rand_core::RngCore for Rng<'d, T> { +impl<'d, T: Instance> rand_core_06::RngCore for Rng<'d, T> { fn fill_bytes(&mut self, dest: &mut [u8]) { self.blocking_fill_bytes(dest); } - fn next_u32(&mut self) -> u32 { - let mut bytes = [0; 4]; - self.blocking_fill_bytes(&mut bytes); - // We don't care about the endianness, so just use the native one. - u32::from_ne_bytes(bytes) + self.blocking_next_u32() } - fn next_u64(&mut self) -> u64 { - let mut bytes = [0; 8]; - self.blocking_fill_bytes(&mut bytes); - u64::from_ne_bytes(bytes) + self.blocking_next_u64() } - - fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core::Error> { + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core_06::Error> { self.blocking_fill_bytes(dest); Ok(()) } } -impl<'d, T: Instance> rand_core::CryptoRng for Rng<'d, T> {} +impl<'d, T: Instance> rand_core_06::CryptoRng for Rng<'d, T> {} + +impl<'d, T: Instance> rand_core_09::RngCore for Rng<'d, T> { + fn fill_bytes(&mut self, dest: &mut [u8]) { + self.blocking_fill_bytes(dest); + } + fn next_u32(&mut self) -> u32 { + self.blocking_next_u32() + } + fn next_u64(&mut self) -> u64 { + self.blocking_next_u64() + } +} + +impl<'d, T: Instance> rand_core_09::CryptoRng for Rng<'d, T> {} /// Peripheral static state pub(crate) struct State { diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index 8fb8a50fd..849cb549a 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml @@ -157,7 +157,6 @@ embedded-io = { version = "0.6.1" } embedded-io-async = { version = "0.6.1" } embedded-storage = { version = "0.3" } embedded-storage-async = { version = "0.4.1" } -rand_core = "0.6.4" fixed = "1.28.0" rp-pac = { version = "7.0.0" } @@ -167,6 +166,9 @@ embedded-hal-1 = { package = "embedded-hal", version = "1.0" } embedded-hal-async = { version = "1.0" } embedded-hal-nb = { version = "1.0" } +rand-core-06 = { package = "rand_core", version = "0.6" } +rand-core-09 = { package = "rand_core", version = "0.9" } + pio = { version = "0.3" } rp2040-boot2 = "0.3" document-features = "0.2.10" diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs index 857877680..d79bffab3 100644 --- a/embassy-rp/src/clocks.rs +++ b/embassy-rp/src/clocks.rs @@ -1776,7 +1776,8 @@ impl<'d, T: GpoutPin> Drop for Gpout<'d, T> { pub struct RoscRng; impl RoscRng { - fn next_u8() -> u8 { + /// Get a random u8 + pub fn next_u8() -> u8 { let random_reg = pac::ROSC.randombit(); let mut acc = 0; for _ in 0..u8::BITS { @@ -1785,26 +1786,60 @@ impl RoscRng { } acc } -} -impl rand_core::RngCore for RoscRng { - fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core::Error> { - Ok(self.fill_bytes(dest)) + /// Get a random u32 + pub fn next_u32(&mut self) -> u32 { + rand_core_09::impls::next_u32_via_fill(self) } - fn next_u32(&mut self) -> u32 { - rand_core::impls::next_u32_via_fill(self) + /// Get a random u64 + pub fn next_u64(&mut self) -> u64 { + rand_core_09::impls::next_u64_via_fill(self) } - fn next_u64(&mut self) -> u64 { - rand_core::impls::next_u64_via_fill(self) - } - - fn fill_bytes(&mut self, dest: &mut [u8]) { + /// Fill a slice with random bytes + pub fn fill_bytes(&mut self, dest: &mut [u8]) { dest.fill_with(Self::next_u8) } } +impl rand_core_06::RngCore for RoscRng { + fn next_u32(&mut self) -> u32 { + self.next_u32() + } + + fn next_u64(&mut self) -> u64 { + self.next_u64() + } + + fn fill_bytes(&mut self, dest: &mut [u8]) { + self.fill_bytes(dest); + } + + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core_06::Error> { + self.fill_bytes(dest); + Ok(()) + } +} + +impl rand_core_06::CryptoRng for RoscRng {} + +impl rand_core_09::RngCore for RoscRng { + fn next_u32(&mut self) -> u32 { + self.next_u32() + } + + fn next_u64(&mut self) -> u64 { + self.next_u64() + } + + fn fill_bytes(&mut self, dest: &mut [u8]) { + self.fill_bytes(dest); + } +} + +impl rand_core_09::CryptoRng for RoscRng {} + /// Enter the `DORMANT` sleep state. This will stop *all* internal clocks /// and can only be exited through resets, dormant-wake GPIO interrupts, /// and RTC interrupts. If RTC is clocked from an internal clock source diff --git a/embassy-rp/src/trng.rs b/embassy-rp/src/trng.rs index a8a0172be..a3f23c1f2 100644 --- a/embassy-rp/src/trng.rs +++ b/embassy-rp/src/trng.rs @@ -7,7 +7,6 @@ use core::task::Poll; use embassy_hal_internal::{Peri, PeripheralType}; use embassy_sync::waitqueue::AtomicWaker; -use rand_core::Error; use crate::interrupt::typelevel::{Binding, Interrupt}; use crate::peripherals::TRNG; @@ -369,7 +368,7 @@ impl<'d, T: Instance> Trng<'d, T> { } } -impl<'d, T: Instance> rand_core::RngCore for Trng<'d, T> { +impl<'d, T: Instance> rand_core_06::RngCore for Trng<'d, T> { fn next_u32(&mut self) -> u32 { self.blocking_next_u32() } @@ -379,16 +378,32 @@ impl<'d, T: Instance> rand_core::RngCore for Trng<'d, T> { } fn fill_bytes(&mut self, dest: &mut [u8]) { - self.blocking_fill_bytes(dest) + self.blocking_fill_bytes(dest); } - fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core_06::Error> { self.blocking_fill_bytes(dest); Ok(()) } } -impl<'d, T: Instance> rand_core::CryptoRng for Trng<'d, T> {} +impl<'d, T: Instance> rand_core_06::CryptoRng for Trng<'d, T> {} + +impl<'d, T: Instance> rand_core_09::RngCore for Trng<'d, T> { + fn next_u32(&mut self) -> u32 { + self.blocking_next_u32() + } + + fn next_u64(&mut self) -> u64 { + self.blocking_next_u64() + } + + fn fill_bytes(&mut self, dest: &mut [u8]) { + self.blocking_fill_bytes(dest); + } +} + +impl<'d, T: Instance> rand_core_09::CryptoRng for Trng<'d, T> {} /// TRNG interrupt handler. pub struct InterruptHandler { diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 972307bec..35c1291fd 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -63,13 +63,15 @@ embedded-can = "0.4" embedded-storage = "0.3.1" embedded-storage-async = { version = "0.4.1" } +rand-core-06 = { package = "rand_core", version = "0.6" } +rand-core-09 = { package = "rand_core", version = "0.9" } + defmt = { version = "0.3", optional = true } log = { version = "0.4.14", optional = true } cortex-m-rt = ">=0.6.15,<0.8" cortex-m = "0.7.6" futures-util = { version = "0.3.30", default-features = false } -rand_core = "0.6.3" sdio-host = "0.9.0" critical-section = "1.1" #stm32-metapac = { version = "16" } diff --git a/embassy-stm32/src/rng.rs b/embassy-stm32/src/rng.rs index 8fa1b3a9d..312f343b9 100644 --- a/embassy-stm32/src/rng.rs +++ b/embassy-stm32/src/rng.rs @@ -7,7 +7,6 @@ use core::task::Poll; use embassy_hal_internal::PeripheralType; use embassy_sync::waitqueue::AtomicWaker; -use rand_core::{CryptoRng, RngCore}; use crate::interrupt::typelevel::Interrupt; use crate::{interrupt, pac, peripherals, rcc, Peri}; @@ -184,6 +183,35 @@ impl<'d, T: Instance> Rng<'d, T> { Ok(()) } + + /// Get a random u32 + pub fn next_u32(&mut self) -> u32 { + loop { + let sr = T::regs().sr().read(); + if sr.seis() | sr.ceis() { + self.reset(); + } else if sr.drdy() { + return T::regs().dr().read(); + } + } + } + + /// Get a random u64 + pub fn next_u64(&mut self) -> u64 { + let mut rand = self.next_u32() as u64; + rand |= (self.next_u32() as u64) << 32; + rand + } + + /// Fill a slice with random bytes + pub fn fill_bytes(&mut self, dest: &mut [u8]) { + for chunk in dest.chunks_mut(4) { + let rand = self.next_u32(); + for (slot, num) in chunk.iter_mut().zip(rand.to_ne_bytes().iter()) { + *slot = *num + } + } + } } impl<'d, T: Instance> Drop for Rng<'d, T> { @@ -195,40 +223,42 @@ impl<'d, T: Instance> Drop for Rng<'d, T> { } } -impl<'d, T: Instance> RngCore for Rng<'d, T> { +impl<'d, T: Instance> rand_core_06::RngCore for Rng<'d, T> { fn next_u32(&mut self) -> u32 { - loop { - let sr = T::regs().sr().read(); - if sr.seis() | sr.ceis() { - self.reset(); - } else if sr.drdy() { - return T::regs().dr().read(); - } - } + self.next_u32() } fn next_u64(&mut self) -> u64 { - let mut rand = self.next_u32() as u64; - rand |= (self.next_u32() as u64) << 32; - rand + self.next_u64() } fn fill_bytes(&mut self, dest: &mut [u8]) { - for chunk in dest.chunks_mut(4) { - let rand = self.next_u32(); - for (slot, num) in chunk.iter_mut().zip(rand.to_ne_bytes().iter()) { - *slot = *num - } - } + self.fill_bytes(dest); } - fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core::Error> { + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core_06::Error> { self.fill_bytes(dest); Ok(()) } } -impl<'d, T: Instance> CryptoRng for Rng<'d, T> {} +impl<'d, T: Instance> rand_core_06::CryptoRng for Rng<'d, T> {} + +impl<'d, T: Instance> rand_core_09::RngCore for Rng<'d, T> { + fn next_u32(&mut self) -> u32 { + self.next_u32() + } + + fn next_u64(&mut self) -> u64 { + self.next_u64() + } + + fn fill_bytes(&mut self, dest: &mut [u8]) { + self.fill_bytes(dest); + } +} + +impl<'d, T: Instance> rand_core_09::CryptoRng for Rng<'d, T> {} trait SealedInstance { fn regs() -> pac::rng::Rng; diff --git a/examples/mimxrt6/Cargo.toml b/examples/mimxrt6/Cargo.toml index b0c56f003..27c3a27dc 100644 --- a/examples/mimxrt6/Cargo.toml +++ b/examples/mimxrt6/Cargo.toml @@ -20,7 +20,6 @@ embedded-hal-async = "1.0.0" mimxrt600-fcb = "0.2.2" panic-probe = { version = "0.3", features = ["print-defmt"] } -rand = { version = "0.8.5", default-features = false } # cargo build/run [profile.dev] diff --git a/examples/mimxrt6/src/bin/rng.rs b/examples/mimxrt6/src/bin/rng.rs index 5f64cb96a..9468dd109 100644 --- a/examples/mimxrt6/src/bin/rng.rs +++ b/examples/mimxrt6/src/bin/rng.rs @@ -7,7 +7,6 @@ use defmt::*; use embassy_executor::Spawner; use embassy_imxrt::rng::Rng; use embassy_imxrt::{bind_interrupts, peripherals, rng}; -use rand::RngCore; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { @@ -29,10 +28,10 @@ async fn main(_spawner: Spawner) { // RngCore interface let mut random_bytes = [0; 16]; - let random_u32 = rng.next_u32(); - let random_u64 = rng.next_u64(); + let random_u32 = rng.blocking_next_u32(); + let random_u64 = rng.blocking_next_u64(); - rng.fill_bytes(&mut random_bytes); + rng.blocking_fill_bytes(&mut random_bytes); info!("random_u32 {}", random_u32); info!("random_u64 {}", random_u64); diff --git a/examples/nrf-rtos-trace/Cargo.toml b/examples/nrf-rtos-trace/Cargo.toml index af12212cd..ba609d889 100644 --- a/examples/nrf-rtos-trace/Cargo.toml +++ b/examples/nrf-rtos-trace/Cargo.toml @@ -23,7 +23,6 @@ embassy-nrf = { version = "0.3.1", path = "../../embassy-nrf", features = ["nrf5 cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } cortex-m-rt = "0.7.0" panic-probe = { version = "0.3" } -rand = { version = "0.8.4", default-features = false } serde = { version = "1.0.136", default-features = false } rtos-trace = "0.1.3" systemview-target = { version = "0.1.2", features = ["callbacks-app", "callbacks-os", "log", "cortex-m"] } diff --git a/examples/nrf52840/Cargo.toml b/examples/nrf52840/Cargo.toml index 902193f3a..ff40a34af 100644 --- a/examples/nrf52840/Cargo.toml +++ b/examples/nrf52840/Cargo.toml @@ -25,7 +25,7 @@ static_cell = { version = "2" } cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } cortex-m-rt = "0.7.0" panic-probe = { version = "0.3", features = ["print-defmt"] } -rand = { version = "0.8.4", default-features = false } +rand = { version = "0.9.0", default-features = false } embedded-storage = "0.3.1" usbd-hid = "0.8.1" serde = { version = "1.0.136", default-features = false } diff --git a/examples/nrf52840/src/bin/rng.rs b/examples/nrf52840/src/bin/rng.rs old mode 100644 new mode 100755 index 326054c9a..f32d17cd9 --- a/examples/nrf52840/src/bin/rng.rs +++ b/examples/nrf52840/src/bin/rng.rs @@ -22,7 +22,7 @@ async fn main(_spawner: Spawner) { defmt::info!("Some random bytes: {:?}", bytes); // Sync API with `rand` - defmt::info!("A random number from 1 to 10: {:?}", rng.gen_range(1..=10)); + defmt::info!("A random number from 1 to 10: {:?}", rng.random_range(1..=10)); let mut bytes = [0; 1024]; rng.fill_bytes(&mut bytes).await; diff --git a/examples/nrf5340/Cargo.toml b/examples/nrf5340/Cargo.toml index 459c43221..5c226695f 100644 --- a/examples/nrf5340/Cargo.toml +++ b/examples/nrf5340/Cargo.toml @@ -21,7 +21,6 @@ static_cell = "2" cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } cortex-m-rt = "0.7.0" panic-probe = { version = "0.3", features = ["print-defmt"] } -rand = { version = "0.8.4", default-features = false } embedded-storage = "0.3.1" usbd-hid = "0.8.1" serde = { version = "1.0.136", default-features = false } diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index 45ca30e4c..aacf9846a 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml @@ -45,7 +45,6 @@ byte-slice-cast = { version = "1.2.0", default-features = false } smart-leds = "0.4.0" heapless = "0.8" usbd-hid = "0.8.1" -rand_core = "0.6.4" embedded-hal-1 = { package = "embedded-hal", version = "1.0" } embedded-hal-async = "1.0" @@ -55,7 +54,7 @@ embedded-storage = { version = "0.3" } static_cell = "2.1" portable-atomic = { version = "1.5", features = ["critical-section"] } log = "0.4" -rand = { version = "0.8.5", default-features = false } +rand = { version = "0.9.0", default-features = false } embedded-sdmmc = "0.7.0" [profile.release] diff --git a/examples/rp/src/bin/ethernet_w5500_icmp.rs b/examples/rp/src/bin/ethernet_w5500_icmp.rs index 5c42b2dde..e434b3bbc 100644 --- a/examples/rp/src/bin/ethernet_w5500_icmp.rs +++ b/examples/rp/src/bin/ethernet_w5500_icmp.rs @@ -21,7 +21,6 @@ use embassy_rp::peripherals::SPI0; use embassy_rp::spi::{Async, Config as SpiConfig, Spi}; use embassy_time::{Delay, Instant, Timer}; use embedded_hal_bus::spi::ExclusiveDevice; -use rand::RngCore; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/rp/src/bin/ethernet_w5500_icmp_ping.rs b/examples/rp/src/bin/ethernet_w5500_icmp_ping.rs index 0724311f9..0ec594fd5 100644 --- a/examples/rp/src/bin/ethernet_w5500_icmp_ping.rs +++ b/examples/rp/src/bin/ethernet_w5500_icmp_ping.rs @@ -23,7 +23,6 @@ use embassy_rp::peripherals::SPI0; use embassy_rp::spi::{Async, Config as SpiConfig, Spi}; use embassy_time::{Delay, Duration}; use embedded_hal_bus::spi::ExclusiveDevice; -use rand::RngCore; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/rp/src/bin/ethernet_w5500_multisocket.rs b/examples/rp/src/bin/ethernet_w5500_multisocket.rs index 2bea9fc9d..27e2f3c30 100644 --- a/examples/rp/src/bin/ethernet_w5500_multisocket.rs +++ b/examples/rp/src/bin/ethernet_w5500_multisocket.rs @@ -18,7 +18,6 @@ use embassy_rp::spi::{Async, Config as SpiConfig, Spi}; use embassy_time::{Delay, Duration}; use embedded_hal_bus::spi::ExclusiveDevice; use embedded_io_async::Write; -use rand::RngCore; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/rp/src/bin/ethernet_w5500_tcp_client.rs b/examples/rp/src/bin/ethernet_w5500_tcp_client.rs index 78d1b0b83..ba82f2a60 100644 --- a/examples/rp/src/bin/ethernet_w5500_tcp_client.rs +++ b/examples/rp/src/bin/ethernet_w5500_tcp_client.rs @@ -20,7 +20,6 @@ use embassy_rp::spi::{Async, Config as SpiConfig, Spi}; use embassy_time::{Delay, Duration, Timer}; use embedded_hal_bus::spi::ExclusiveDevice; use embedded_io_async::Write; -use rand::RngCore; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/rp/src/bin/ethernet_w5500_tcp_server.rs b/examples/rp/src/bin/ethernet_w5500_tcp_server.rs index 25a38c714..5c56dcafa 100644 --- a/examples/rp/src/bin/ethernet_w5500_tcp_server.rs +++ b/examples/rp/src/bin/ethernet_w5500_tcp_server.rs @@ -19,7 +19,6 @@ use embassy_rp::spi::{Async, Config as SpiConfig, Spi}; use embassy_time::{Delay, Duration}; use embedded_hal_bus::spi::ExclusiveDevice; use embedded_io_async::Write; -use rand::RngCore; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/rp/src/bin/ethernet_w5500_udp.rs b/examples/rp/src/bin/ethernet_w5500_udp.rs index 683e29222..c5fc8de1d 100644 --- a/examples/rp/src/bin/ethernet_w5500_udp.rs +++ b/examples/rp/src/bin/ethernet_w5500_udp.rs @@ -18,7 +18,6 @@ use embassy_rp::peripherals::SPI0; use embassy_rp::spi::{Async, Config as SpiConfig, Spi}; use embassy_time::Delay; use embedded_hal_bus::spi::ExclusiveDevice; -use rand::RngCore; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/rp/src/bin/orchestrate_tasks.rs b/examples/rp/src/bin/orchestrate_tasks.rs index 5e2775793..c35679251 100644 --- a/examples/rp/src/bin/orchestrate_tasks.rs +++ b/examples/rp/src/bin/orchestrate_tasks.rs @@ -29,7 +29,6 @@ use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::mutex::Mutex; use embassy_sync::{channel, signal}; use embassy_time::{Duration, Timer}; -use rand::RngCore; use {defmt_rtt as _, panic_probe as _}; // Hardware resource assignment. See other examples for different ways of doing this. diff --git a/examples/rp/src/bin/sharing.rs b/examples/rp/src/bin/sharing.rs index 497c4f845..856be6ace 100644 --- a/examples/rp/src/bin/sharing.rs +++ b/examples/rp/src/bin/sharing.rs @@ -27,7 +27,6 @@ use embassy_rp::{bind_interrupts, interrupt}; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::{blocking_mutex, mutex}; use embassy_time::{Duration, Ticker}; -use rand::RngCore; use static_cell::{ConstStaticCell, StaticCell}; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/rp/src/bin/spi_gc9a01.rs b/examples/rp/src/bin/spi_gc9a01.rs index 30afc253d..fdef09d4b 100644 --- a/examples/rp/src/bin/spi_gc9a01.rs +++ b/examples/rp/src/bin/spi_gc9a01.rs @@ -26,7 +26,6 @@ use embedded_graphics::primitives::{PrimitiveStyleBuilder, Rectangle}; use mipidsi::models::GC9A01; use mipidsi::options::{ColorInversion, ColorOrder}; use mipidsi::Builder; -use rand_core::RngCore; use {defmt_rtt as _, panic_probe as _}; const DISPLAY_FREQ: u32 = 64_000_000; diff --git a/examples/rp/src/bin/usb_ethernet.rs b/examples/rp/src/bin/usb_ethernet.rs index 2add20bc6..171f21a75 100644 --- a/examples/rp/src/bin/usb_ethernet.rs +++ b/examples/rp/src/bin/usb_ethernet.rs @@ -17,7 +17,6 @@ use embassy_usb::class::cdc_ncm::embassy_net::{Device, Runner, State as NetState use embassy_usb::class::cdc_ncm::{CdcNcmClass, State}; use embassy_usb::{Builder, Config, UsbDevice}; use embedded_io_async::Write; -use rand::RngCore; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/rp/src/bin/usb_hid_mouse.rs b/examples/rp/src/bin/usb_hid_mouse.rs old mode 100644 new mode 100755 index 5ee650910..4454c593c --- a/examples/rp/src/bin/usb_hid_mouse.rs +++ b/examples/rp/src/bin/usb_hid_mouse.rs @@ -85,8 +85,8 @@ async fn main(_spawner: Spawner) { _ = Timer::after_secs(1).await; let report = MouseReport { buttons: 0, - x: rng.gen_range(-100..100), // random small x movement - y: rng.gen_range(-100..100), // random small y movement + x: rng.random_range(-100..100), // random small x movement + y: rng.random_range(-100..100), // random small y movement wheel: 0, pan: 0, }; diff --git a/examples/rp/src/bin/wifi_ap_tcp_server.rs b/examples/rp/src/bin/wifi_ap_tcp_server.rs index e97ddb4c1..856838a8c 100644 --- a/examples/rp/src/bin/wifi_ap_tcp_server.rs +++ b/examples/rp/src/bin/wifi_ap_tcp_server.rs @@ -19,7 +19,6 @@ use embassy_rp::peripherals::{DMA_CH0, PIO0}; use embassy_rp::pio::{InterruptHandler, Pio}; use embassy_time::Duration; use embedded_io_async::Write; -use rand::RngCore; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/rp/src/bin/wifi_tcp_server.rs b/examples/rp/src/bin/wifi_tcp_server.rs index 7e3c663fe..fbc957e0e 100644 --- a/examples/rp/src/bin/wifi_tcp_server.rs +++ b/examples/rp/src/bin/wifi_tcp_server.rs @@ -20,7 +20,6 @@ use embassy_rp::peripherals::{DMA_CH0, PIO0}; use embassy_rp::pio::{InterruptHandler, Pio}; use embassy_time::{Duration, Timer}; use embedded_io_async::Write; -use rand::RngCore; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/rp/src/bin/wifi_webrequest.rs b/examples/rp/src/bin/wifi_webrequest.rs index f1b398b65..1efd1cd28 100644 --- a/examples/rp/src/bin/wifi_webrequest.rs +++ b/examples/rp/src/bin/wifi_webrequest.rs @@ -20,7 +20,6 @@ use embassy_rp::gpio::{Level, Output}; use embassy_rp::peripherals::{DMA_CH0, PIO0}; use embassy_rp::pio::{InterruptHandler, Pio}; use embassy_time::{Duration, Timer}; -use rand::RngCore; use reqwless::client::{HttpClient, TlsConfig, TlsVerify}; use reqwless::request::Method; use serde::Deserialize; diff --git a/examples/rp235x/Cargo.toml b/examples/rp235x/Cargo.toml index 345a915af..a247bc619 100644 --- a/examples/rp235x/Cargo.toml +++ b/examples/rp235x/Cargo.toml @@ -55,7 +55,6 @@ embedded-storage = { version = "0.3" } static_cell = "2.1" portable-atomic = { version = "1.5", features = ["critical-section"] } log = "0.4" -rand = { version = "0.8.5", default-features = false } embedded-sdmmc = "0.7.0" [profile.release] diff --git a/examples/rp235x/src/bin/sharing.rs b/examples/rp235x/src/bin/sharing.rs index 497c4f845..856be6ace 100644 --- a/examples/rp235x/src/bin/sharing.rs +++ b/examples/rp235x/src/bin/sharing.rs @@ -27,7 +27,6 @@ use embassy_rp::{bind_interrupts, interrupt}; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::{blocking_mutex, mutex}; use embassy_time::{Duration, Ticker}; -use rand::RngCore; use static_cell::{ConstStaticCell, StaticCell}; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/rp235x/src/bin/trng.rs b/examples/rp235x/src/bin/trng.rs index ad19aef3e..100d6b104 100644 --- a/examples/rp235x/src/bin/trng.rs +++ b/examples/rp235x/src/bin/trng.rs @@ -10,7 +10,6 @@ use embassy_rp::gpio::{Level, Output}; use embassy_rp::peripherals::TRNG; use embassy_rp::trng::Trng; use embassy_time::Timer; -use rand::RngCore; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { @@ -33,8 +32,8 @@ async fn main(_spawner: Spawner) { info!("Random bytes async {}", &randomness); trng.blocking_fill_bytes(&mut randomness); info!("Random bytes blocking {}", &randomness); - let random_u32 = trng.next_u32(); - let random_u64 = trng.next_u64(); + let random_u32 = trng.blocking_next_u32(); + let random_u64 = trng.blocking_next_u64(); info!("Random u32 {} u64 {}", random_u32, random_u64); // Random number of blinks between 0 and 31 let blinks = random_u32 % 32; diff --git a/examples/std/Cargo.toml b/examples/std/Cargo.toml index f00953167..ff4b2fbbd 100644 --- a/examples/std/Cargo.toml +++ b/examples/std/Cargo.toml @@ -21,7 +21,7 @@ futures = { version = "0.3.17" } log = "0.4.14" nix = "0.26.2" clap = { version = "3.0.0-beta.5", features = ["derive"] } -rand_core = { version = "0.6.3", features = ["std"] } +rand_core = { version = "0.9.1", features = ["std", "os_rng"] } heapless = { version = "0.8", default-features = false } static_cell = "2" diff --git a/examples/std/src/bin/net.rs b/examples/std/src/bin/net.rs index 6e50b1a01..232cf494b 100644 --- a/examples/std/src/bin/net.rs +++ b/examples/std/src/bin/net.rs @@ -9,7 +9,7 @@ use embassy_time::Duration; use embedded_io_async::Write; use heapless::Vec; use log::*; -use rand_core::{OsRng, RngCore}; +use rand_core::{OsRng, TryRngCore}; use static_cell::StaticCell; #[derive(Parser)] @@ -48,7 +48,7 @@ async fn main_task(spawner: Spawner) { // Generate random seed let mut seed = [0; 8]; - OsRng.fill_bytes(&mut seed); + OsRng.try_fill_bytes(&mut seed).unwrap(); let seed = u64::from_le_bytes(seed); // Init network stack diff --git a/examples/std/src/bin/net_dns.rs b/examples/std/src/bin/net_dns.rs index a42c5dbb7..cf90731dd 100644 --- a/examples/std/src/bin/net_dns.rs +++ b/examples/std/src/bin/net_dns.rs @@ -5,7 +5,7 @@ use embassy_net::{Config, Ipv4Address, Ipv4Cidr, StackResources}; use embassy_net_tuntap::TunTapDevice; use heapless::Vec; use log::*; -use rand_core::{OsRng, RngCore}; +use rand_core::{OsRng, TryRngCore}; use static_cell::StaticCell; #[derive(Parser)] @@ -45,7 +45,7 @@ async fn main_task(spawner: Spawner) { // Generate random seed let mut seed = [0; 8]; - OsRng.fill_bytes(&mut seed); + OsRng.try_fill_bytes(&mut seed).unwrap(); let seed = u64::from_le_bytes(seed); // Init network stack diff --git a/examples/std/src/bin/net_ppp.rs b/examples/std/src/bin/net_ppp.rs index f667e8d4c..ac3aea6ff 100644 --- a/examples/std/src/bin/net_ppp.rs +++ b/examples/std/src/bin/net_ppp.rs @@ -23,7 +23,7 @@ use futures::io::BufReader; use heapless::Vec; use log::*; use nix::sys::termios; -use rand_core::{OsRng, RngCore}; +use rand_core::{OsRng, TryRngCore}; use static_cell::StaticCell; use crate::serial_port::SerialPort; @@ -89,7 +89,7 @@ async fn main_task(spawner: Spawner) { // Generate random seed let mut seed = [0; 8]; - OsRng.fill_bytes(&mut seed); + OsRng.try_fill_bytes(&mut seed).unwrap(); let seed = u64::from_le_bytes(seed); // Init network stack diff --git a/examples/std/src/bin/net_udp.rs b/examples/std/src/bin/net_udp.rs index 02d4d3efb..53632a5b4 100644 --- a/examples/std/src/bin/net_udp.rs +++ b/examples/std/src/bin/net_udp.rs @@ -5,7 +5,7 @@ use embassy_net::{Config, Ipv4Address, Ipv4Cidr, StackResources}; use embassy_net_tuntap::TunTapDevice; use heapless::Vec; use log::*; -use rand_core::{OsRng, RngCore}; +use rand_core::{OsRng, TryRngCore}; use static_cell::StaticCell; #[derive(Parser)] @@ -44,7 +44,7 @@ async fn main_task(spawner: Spawner) { // Generate random seed let mut seed = [0; 8]; - OsRng.fill_bytes(&mut seed); + OsRng.try_fill_bytes(&mut seed).unwrap(); let seed = u64::from_le_bytes(seed); // Init network stack diff --git a/examples/std/src/bin/tcp_accept.rs b/examples/std/src/bin/tcp_accept.rs index 18646a083..961c20e2d 100644 --- a/examples/std/src/bin/tcp_accept.rs +++ b/examples/std/src/bin/tcp_accept.rs @@ -7,7 +7,7 @@ use embassy_time::{Duration, Timer}; use embedded_io_async::Write as _; use heapless::Vec; use log::*; -use rand_core::{OsRng, RngCore}; +use rand_core::{OsRng, TryRngCore}; use static_cell::StaticCell; #[derive(Parser)] @@ -46,7 +46,7 @@ async fn main_task(spawner: Spawner) { // Generate random seed let mut seed = [0; 8]; - OsRng.fill_bytes(&mut seed); + OsRng.try_fill_bytes(&mut seed).unwrap(); let seed = u64::from_le_bytes(seed); // Init network stack diff --git a/examples/stm32f7/Cargo.toml b/examples/stm32f7/Cargo.toml index 1a46931d9..94e0a80eb 100644 --- a/examples/stm32f7/Cargo.toml +++ b/examples/stm32f7/Cargo.toml @@ -24,7 +24,6 @@ embedded-hal = "0.2.6" panic-probe = { version = "0.3", features = ["print-defmt"] } heapless = { version = "0.8", default-features = false } nb = "1.0.0" -rand_core = "0.6.3" critical-section = "1.1" embedded-storage = "0.3.1" static_cell = "2" diff --git a/examples/stm32f7/src/bin/eth.rs b/examples/stm32f7/src/bin/eth.rs index 17ab7fc00..67a2b34bb 100644 --- a/examples/stm32f7/src/bin/eth.rs +++ b/examples/stm32f7/src/bin/eth.rs @@ -12,7 +12,6 @@ use embassy_stm32::time::Hertz; use embassy_stm32::{bind_interrupts, eth, peripherals, rng, Config}; use embassy_time::Timer; use embedded_io_async::Write; -use rand_core::RngCore; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32h5/Cargo.toml b/examples/stm32h5/Cargo.toml index 5631ff746..6fb14f422 100644 --- a/examples/stm32h5/Cargo.toml +++ b/examples/stm32h5/Cargo.toml @@ -26,7 +26,6 @@ embedded-io-async = { version = "0.6.1" } embedded-nal-async = "0.8.0" panic-probe = { version = "0.3", features = ["print-defmt"] } heapless = { version = "0.8", default-features = false } -rand_core = "0.6.3" critical-section = "1.1" micromath = "2.0.0" stm32-fmc = "0.3.0" diff --git a/examples/stm32h5/src/bin/eth.rs b/examples/stm32h5/src/bin/eth.rs index 4034b552c..1d85cc1e7 100644 --- a/examples/stm32h5/src/bin/eth.rs +++ b/examples/stm32h5/src/bin/eth.rs @@ -15,7 +15,6 @@ use embassy_stm32::time::Hertz; use embassy_stm32::{bind_interrupts, eth, peripherals, rng, Config}; use embassy_time::Timer; use embedded_io_async::Write; -use rand_core::RngCore; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32h7/Cargo.toml b/examples/stm32h7/Cargo.toml index 2f98542bb..5035dacae 100644 --- a/examples/stm32h7/Cargo.toml +++ b/examples/stm32h7/Cargo.toml @@ -27,7 +27,6 @@ embedded-nal-async = "0.8.0" embedded-io-async = { version = "0.6.1" } panic-probe = { version = "0.3", features = ["print-defmt"] } heapless = { version = "0.8", default-features = false } -rand_core = "0.6.3" critical-section = "1.1" micromath = "2.0.0" stm32-fmc = "0.3.0" diff --git a/examples/stm32h7/src/bin/eth.rs b/examples/stm32h7/src/bin/eth.rs index da7aa4af5..fc14c1a70 100644 --- a/examples/stm32h7/src/bin/eth.rs +++ b/examples/stm32h7/src/bin/eth.rs @@ -11,7 +11,6 @@ use embassy_stm32::rng::Rng; use embassy_stm32::{bind_interrupts, eth, peripherals, rng, Config}; use embassy_time::Timer; use embedded_io_async::Write; -use rand_core::RngCore; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32h7/src/bin/eth_client.rs b/examples/stm32h7/src/bin/eth_client.rs index 10485109a..46301a478 100644 --- a/examples/stm32h7/src/bin/eth_client.rs +++ b/examples/stm32h7/src/bin/eth_client.rs @@ -14,7 +14,6 @@ use embassy_stm32::{bind_interrupts, eth, peripherals, rng, Config}; use embassy_time::Timer; use embedded_io_async::Write; use embedded_nal_async::TcpConnect; -use rand_core::RngCore; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32h7/src/bin/eth_client_mii.rs b/examples/stm32h7/src/bin/eth_client_mii.rs index 849173615..99cd1a158 100644 --- a/examples/stm32h7/src/bin/eth_client_mii.rs +++ b/examples/stm32h7/src/bin/eth_client_mii.rs @@ -14,7 +14,6 @@ use embassy_stm32::{bind_interrupts, eth, peripherals, rng, Config}; use embassy_time::Timer; use embedded_io_async::Write; use embedded_nal_async::TcpConnect; -use rand_core::RngCore; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32h723/Cargo.toml b/examples/stm32h723/Cargo.toml index 749fd78ae..f07d360b3 100644 --- a/examples/stm32h723/Cargo.toml +++ b/examples/stm32h723/Cargo.toml @@ -24,7 +24,6 @@ embedded-nal-async = "0.8.0" embedded-io-async = { version = "0.6.1" } panic-probe = { version = "0.3", features = ["print-defmt"] } heapless = { version = "0.8", default-features = false } -rand_core = "0.6.3" critical-section = "1.1" static_cell = "2" chrono = { version = "^0.4", default-features = false } diff --git a/examples/stm32h742/Cargo.toml b/examples/stm32h742/Cargo.toml index e2e0094b8..3f936193c 100644 --- a/examples/stm32h742/Cargo.toml +++ b/examples/stm32h742/Cargo.toml @@ -51,7 +51,6 @@ embedded-hal = "0.2.6" panic-probe = { version = "0.3", features = ["print-defmt"] } heapless = { version = "0.8", default-features = false } nb = "1.0.0" -rand_core = "0.6.3" critical-section = "1.1" embedded-storage = "0.3.1" static_cell = "2" diff --git a/examples/stm32h755cm4/Cargo.toml b/examples/stm32h755cm4/Cargo.toml index 7c17bc766..c186ef19f 100644 --- a/examples/stm32h755cm4/Cargo.toml +++ b/examples/stm32h755cm4/Cargo.toml @@ -27,7 +27,6 @@ embedded-nal-async = "0.8.0" embedded-io-async = { version = "0.6.1" } panic-probe = { version = "0.3", features = ["print-defmt"] } heapless = { version = "0.8", default-features = false } -rand_core = "0.6.3" critical-section = "1.1" micromath = "2.0.0" stm32-fmc = "0.3.0" diff --git a/examples/stm32h755cm7/Cargo.toml b/examples/stm32h755cm7/Cargo.toml index 3186929a8..d37978e44 100644 --- a/examples/stm32h755cm7/Cargo.toml +++ b/examples/stm32h755cm7/Cargo.toml @@ -27,7 +27,6 @@ embedded-nal-async = "0.8.0" embedded-io-async = { version = "0.6.1" } panic-probe = { version = "0.3", features = ["print-defmt"] } heapless = { version = "0.8", default-features = false } -rand_core = "0.6.3" critical-section = "1.1" micromath = "2.0.0" stm32-fmc = "0.3.0" diff --git a/examples/stm32h7b0/Cargo.toml b/examples/stm32h7b0/Cargo.toml index e5f2dfe86..dc8ecc684 100644 --- a/examples/stm32h7b0/Cargo.toml +++ b/examples/stm32h7b0/Cargo.toml @@ -26,7 +26,6 @@ embedded-nal-async = "0.8.0" embedded-io-async = { version = "0.6.1" } panic-probe = { version = "0.3", features = ["print-defmt"] } heapless = { version = "0.8", default-features = false } -rand_core = "0.6.3" critical-section = "1.1" micromath = "2.0.0" stm32-fmc = "0.3.0" diff --git a/examples/stm32h7rs/Cargo.toml b/examples/stm32h7rs/Cargo.toml index 22d59be04..aee2703a1 100644 --- a/examples/stm32h7rs/Cargo.toml +++ b/examples/stm32h7rs/Cargo.toml @@ -26,7 +26,6 @@ embedded-nal-async = "0.8.0" embedded-io-async = { version = "0.6.1" } panic-probe = { version = "0.3", features = ["print-defmt"] } heapless = { version = "0.8", default-features = false } -rand_core = "0.6.3" critical-section = "1.1" micromath = "2.0.0" stm32-fmc = "0.3.0" diff --git a/examples/stm32h7rs/src/bin/eth.rs b/examples/stm32h7rs/src/bin/eth.rs index f2bd9575e..6d246bb09 100644 --- a/examples/stm32h7rs/src/bin/eth.rs +++ b/examples/stm32h7rs/src/bin/eth.rs @@ -11,7 +11,6 @@ use embassy_stm32::rng::Rng; use embassy_stm32::{bind_interrupts, eth, peripherals, rng, Config}; use embassy_time::Timer; use heapless::Vec; -use rand_core::RngCore; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32l4/Cargo.toml b/examples/stm32l4/Cargo.toml index 239bfcd79..cceec86dd 100644 --- a/examples/stm32l4/Cargo.toml +++ b/examples/stm32l4/Cargo.toml @@ -30,7 +30,6 @@ embedded-hal-bus = { version = "0.1", features = ["async"] } panic-probe = { version = "0.3", features = ["print-defmt"] } heapless = { version = "0.8", default-features = false } chrono = { version = "^0.4", default-features = false } -rand = { version = "0.8.5", default-features = false } static_cell = "2" micromath = "2.0.0" diff --git a/examples/stm32l4/src/bin/spe_adin1110_http_server.rs b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs index 4a7c01f9f..354ac90b2 100644 --- a/examples/stm32l4/src/bin/spe_adin1110_http_server.rs +++ b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs @@ -38,7 +38,6 @@ use embedded_io::Write as bWrite; use embedded_io_async::Write; use heapless::Vec; use panic_probe as _; -use rand::RngCore; use static_cell::StaticCell; bind_interrupts!(struct Irqs { diff --git a/examples/stm32l5/Cargo.toml b/examples/stm32l5/Cargo.toml index 4c372a554..6962db7ea 100644 --- a/examples/stm32l5/Cargo.toml +++ b/examples/stm32l5/Cargo.toml @@ -23,7 +23,6 @@ cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-sing cortex-m-rt = "0.7.0" embedded-hal = "0.2.6" heapless = { version = "0.8", default-features = false } -rand_core = { version = "0.6.3", default-features = false } embedded-io-async = { version = "0.6.1" } static_cell = "2" diff --git a/examples/stm32l5/src/bin/usb_ethernet.rs b/examples/stm32l5/src/bin/usb_ethernet.rs index 809ec6ab1..6c72132c6 100644 --- a/examples/stm32l5/src/bin/usb_ethernet.rs +++ b/examples/stm32l5/src/bin/usb_ethernet.rs @@ -12,7 +12,6 @@ use embassy_usb::class::cdc_ncm::embassy_net::{Device, Runner, State as NetState use embassy_usb::class::cdc_ncm::{CdcNcmClass, State}; use embassy_usb::{Builder, UsbDevice}; use embedded_io_async::Write; -use rand_core::RngCore; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; diff --git a/tests/rp/Cargo.toml b/tests/rp/Cargo.toml index 1335aa84b..46dc820ab 100644 --- a/tests/rp/Cargo.toml +++ b/tests/rp/Cargo.toml @@ -38,7 +38,6 @@ embedded-io-async = { version = "0.6.1" } embedded-storage = { version = "0.3" } static_cell = "2" portable-atomic = { version = "1.5", features = ["critical-section"] } -rand = { version = "0.8.5", default-features = false } # bootsel not currently supported on 2350 [[bin]] diff --git a/tests/rp/src/bin/ethernet_w5100s_perf.rs b/tests/rp/src/bin/ethernet_w5100s_perf.rs index ae2adfa55..89e0ad32e 100644 --- a/tests/rp/src/bin/ethernet_w5100s_perf.rs +++ b/tests/rp/src/bin/ethernet_w5100s_perf.rs @@ -14,7 +14,6 @@ use embassy_rp::peripherals::SPI0; use embassy_rp::spi::{Async, Config as SpiConfig, Spi}; use embassy_time::Delay; use embedded_hal_bus::spi::ExclusiveDevice; -use rand::RngCore; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml index 3a347e279..b230e619e 100644 --- a/tests/stm32/Cargo.toml +++ b/tests/stm32/Cargo.toml @@ -81,8 +81,8 @@ embedded-hal-async = { version = "1.0" } embedded-can = { version = "0.4" } micromath = "2.0.0" panic-probe = { version = "0.3.0", features = ["print-defmt"] } -rand_core = { version = "0.6", default-features = false } -rand_chacha = { version = "0.3", default-features = false } +rand_core = { version = "0.9.1", default-features = false } +rand_chacha = { version = "0.9.0", default-features = false } static_cell = "2" portable-atomic = { version = "1.5", features = [] } diff --git a/tests/stm32/src/bin/eth.rs b/tests/stm32/src/bin/eth.rs index a7e76fd8e..bcb362b42 100644 --- a/tests/stm32/src/bin/eth.rs +++ b/tests/stm32/src/bin/eth.rs @@ -11,7 +11,6 @@ use embassy_stm32::eth::{Ethernet, GenericPhy, PacketQueue}; use embassy_stm32::peripherals::ETH; use embassy_stm32::rng::Rng; use embassy_stm32::{bind_interrupts, eth, peripherals, rng}; -use rand_core::RngCore; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; diff --git a/tests/utils/Cargo.toml b/tests/utils/Cargo.toml index 7b54a4f52..bda55ad32 100644 --- a/tests/utils/Cargo.toml +++ b/tests/utils/Cargo.toml @@ -4,5 +4,5 @@ version = "0.1.0" edition = "2021" [dependencies] -rand = "0.8" +rand = "0.9" serial = "0.4" From ef0f29f0ede245671ffd82fcf384a9105f174c24 Mon Sep 17 00:00:00 2001 From: Yuri Astrakhan Date: Sun, 18 May 2025 20:51:15 +0200 Subject: [PATCH 1141/1217] Update defmt dependencies --- cyw43-pio/Cargo.toml | 2 +- cyw43/Cargo.toml | 2 +- docs/examples/basic/Cargo.toml | 6 +++--- docs/examples/layer-by-layer/blinky-async/Cargo.toml | 6 +++--- docs/examples/layer-by-layer/blinky-hal/Cargo.toml | 6 +++--- docs/examples/layer-by-layer/blinky-irq/Cargo.toml | 6 +++--- docs/examples/layer-by-layer/blinky-pac/Cargo.toml | 6 +++--- embassy-boot-nrf/Cargo.toml | 2 +- embassy-boot-rp/Cargo.toml | 2 +- embassy-boot-stm32/Cargo.toml | 2 +- embassy-boot/Cargo.toml | 2 +- embassy-embedded-hal/Cargo.toml | 2 +- embassy-executor/Cargo.toml | 2 +- embassy-futures/Cargo.toml | 2 +- embassy-hal-internal/Cargo.toml | 2 +- embassy-imxrt/Cargo.toml | 2 +- embassy-mspm0/Cargo.toml | 2 +- embassy-net-adin1110/Cargo.toml | 4 ++-- embassy-net-driver-channel/Cargo.toml | 2 +- embassy-net-driver/Cargo.toml | 2 +- embassy-net-enc28j60/Cargo.toml | 2 +- embassy-net-esp-hosted/Cargo.toml | 6 +++--- embassy-net-nrf91/Cargo.toml | 12 ++++++------ embassy-net-ppp/Cargo.toml | 2 +- embassy-net-wiznet/Cargo.toml | 2 +- embassy-net/Cargo.toml | 2 +- embassy-nrf/Cargo.toml | 2 +- embassy-nxp/Cargo.toml | 2 +- embassy-rp/Cargo.toml | 2 +- embassy-stm32-wpan/Cargo.toml | 2 +- embassy-stm32/Cargo.toml | 2 +- embassy-sync/Cargo.toml | 2 +- embassy-time/Cargo.toml | 2 +- embassy-usb-dfu/Cargo.toml | 2 +- embassy-usb-driver/Cargo.toml | 2 +- embassy-usb-synopsys-otg/Cargo.toml | 2 +- embassy-usb/Cargo.toml | 4 ++-- examples/boot/application/nrf/Cargo.toml | 4 ++-- examples/boot/application/rp/Cargo.toml | 6 +++--- examples/boot/application/stm32f3/Cargo.toml | 4 ++-- examples/boot/application/stm32f7/Cargo.toml | 4 ++-- examples/boot/application/stm32h7/Cargo.toml | 4 ++-- examples/boot/application/stm32l0/Cargo.toml | 4 ++-- examples/boot/application/stm32l1/Cargo.toml | 4 ++-- examples/boot/application/stm32l4/Cargo.toml | 4 ++-- examples/boot/application/stm32wb-dfu/Cargo.toml | 4 ++-- examples/boot/application/stm32wl/Cargo.toml | 4 ++-- examples/boot/bootloader/nrf/Cargo.toml | 4 ++-- examples/boot/bootloader/rp/Cargo.toml | 4 ++-- examples/boot/bootloader/stm32-dual-bank/Cargo.toml | 4 ++-- examples/boot/bootloader/stm32/Cargo.toml | 4 ++-- examples/boot/bootloader/stm32wb-dfu/Cargo.toml | 4 ++-- examples/lpc55s69/Cargo.toml | 8 ++++---- examples/mimxrt6/Cargo.toml | 6 +++--- examples/mspm0c1104/Cargo.toml | 8 ++++---- examples/mspm0g3507/Cargo.toml | 8 ++++---- examples/mspm0g3519/Cargo.toml | 8 ++++---- examples/mspm0l1306/Cargo.toml | 8 ++++---- examples/mspm0l2228/Cargo.toml | 8 ++++---- examples/nrf-rtos-trace/Cargo.toml | 2 +- examples/nrf51/Cargo.toml | 6 +++--- examples/nrf52810/Cargo.toml | 6 +++--- examples/nrf52840-rtic/Cargo.toml | 6 +++--- examples/nrf52840/Cargo.toml | 6 +++--- examples/nrf5340/Cargo.toml | 6 +++--- examples/nrf54l15/Cargo.toml | 6 +++--- examples/nrf9151/ns/Cargo.toml | 6 +++--- examples/nrf9151/s/Cargo.toml | 6 +++--- examples/nrf9160/Cargo.toml | 6 +++--- examples/rp/Cargo.toml | 6 +++--- examples/rp235x/Cargo.toml | 6 +++--- examples/stm32c0/Cargo.toml | 6 +++--- examples/stm32f0/Cargo.toml | 6 +++--- examples/stm32f1/Cargo.toml | 6 +++--- examples/stm32f2/Cargo.toml | 6 +++--- examples/stm32f3/Cargo.toml | 6 +++--- examples/stm32f334/Cargo.toml | 6 +++--- examples/stm32f4/Cargo.toml | 6 +++--- examples/stm32f469/Cargo.toml | 6 +++--- examples/stm32f7/Cargo.toml | 6 +++--- examples/stm32g0/Cargo.toml | 6 +++--- examples/stm32g4/Cargo.toml | 6 +++--- examples/stm32h5/Cargo.toml | 6 +++--- examples/stm32h7/Cargo.toml | 6 +++--- examples/stm32h723/Cargo.toml | 6 +++--- examples/stm32h735/Cargo.toml | 6 +++--- examples/stm32h742/Cargo.toml | 6 +++--- examples/stm32h755cm4/Cargo.toml | 6 +++--- examples/stm32h755cm7/Cargo.toml | 6 +++--- examples/stm32h7b0/Cargo.toml | 6 +++--- examples/stm32h7rs/Cargo.toml | 6 +++--- examples/stm32l0/Cargo.toml | 6 +++--- examples/stm32l1/Cargo.toml | 6 +++--- examples/stm32l4/Cargo.toml | 6 +++--- examples/stm32l432/Cargo.toml | 6 +++--- examples/stm32l5/Cargo.toml | 6 +++--- examples/stm32u0/Cargo.toml | 6 +++--- examples/stm32u5/Cargo.toml | 6 +++--- examples/stm32wb/Cargo.toml | 10 +++++----- examples/stm32wba/Cargo.toml | 10 +++++----- examples/stm32wl/Cargo.toml | 6 +++--- rustfmt.toml | 2 +- tests/mspm0/Cargo.toml | 2 +- tests/nrf/Cargo.toml | 6 +++--- tests/perf-client/Cargo.toml | 2 +- tests/rp/Cargo.toml | 6 +++--- tests/stm32/Cargo.toml | 6 +++--- 107 files changed, 254 insertions(+), 254 deletions(-) diff --git a/cyw43-pio/Cargo.toml b/cyw43-pio/Cargo.toml index 600caf5ed..93a2e7089 100644 --- a/cyw43-pio/Cargo.toml +++ b/cyw43-pio/Cargo.toml @@ -13,7 +13,7 @@ documentation = "https://docs.embassy.dev/cyw43-pio" cyw43 = { version = "0.3.0", path = "../cyw43" } embassy-rp = { version = "0.4.0", path = "../embassy-rp" } fixed = "1.23.1" -defmt = { version = "0.3", optional = true } +defmt = { version = "1.0.1", optional = true } [package.metadata.embassy_docs] src_base = "https://github.com/embassy-rs/embassy/blob/cyw43-pio-v$VERSION/cyw43-pio/src/" diff --git a/cyw43/Cargo.toml b/cyw43/Cargo.toml index 88d1fe506..4b58ee9c9 100644 --- a/cyw43/Cargo.toml +++ b/cyw43/Cargo.toml @@ -23,7 +23,7 @@ embassy-sync = { version = "0.6.2", path = "../embassy-sync"} embassy-futures = { version = "0.1.0", path = "../embassy-futures"} embassy-net-driver-channel = { version = "0.3.0", path = "../embassy-net-driver-channel"} -defmt = { version = "0.3", optional = true } +defmt = { version = "1.0.1", optional = true } log = { version = "0.4.17", optional = true } cortex-m = "0.7.6" diff --git a/docs/examples/basic/Cargo.toml b/docs/examples/basic/Cargo.toml index 705c334a7..f5cf2b231 100644 --- a/docs/examples/basic/Cargo.toml +++ b/docs/examples/basic/Cargo.toml @@ -10,9 +10,9 @@ embassy-executor = { version = "0.7.0", path = "../../../embassy-executor", feat embassy-time = { version = "0.4.0", path = "../../../embassy-time", features = ["defmt"] } embassy-nrf = { version = "0.3.1", path = "../../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote"] } -defmt = "0.3" -defmt-rtt = "0.3" +defmt = "1.0.1" +defmt-rtt = "1.0.0" cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } cortex-m-rt = "0.7.0" -panic-probe = { version = "0.3", features = ["print-defmt"] } +panic-probe = { version = "1.0.0", features = ["print-defmt"] } diff --git a/docs/examples/layer-by-layer/blinky-async/Cargo.toml b/docs/examples/layer-by-layer/blinky-async/Cargo.toml index 541eb6edf..2a6741b33 100644 --- a/docs/examples/layer-by-layer/blinky-async/Cargo.toml +++ b/docs/examples/layer-by-layer/blinky-async/Cargo.toml @@ -10,6 +10,6 @@ cortex-m-rt = "0.7" embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32l475vg", "memory-x", "exti"] } embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread"] } -defmt = "0.3" -defmt-rtt = "0.4" -panic-probe = { version = "0.3.0", features = ["print-defmt"] } +defmt = "1.0.1" +defmt-rtt = "1.0.0" +panic-probe = { version = "1.0.0", features = ["print-defmt"] } diff --git a/docs/examples/layer-by-layer/blinky-hal/Cargo.toml b/docs/examples/layer-by-layer/blinky-hal/Cargo.toml index dd574c3e7..9a261f804 100644 --- a/docs/examples/layer-by-layer/blinky-hal/Cargo.toml +++ b/docs/examples/layer-by-layer/blinky-hal/Cargo.toml @@ -9,6 +9,6 @@ cortex-m-rt = "0.7" cortex-m = { version = "0.7", features = ["critical-section-single-core"] } embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32l475vg", "memory-x"] } -defmt = "0.3" -defmt-rtt = "0.4" -panic-probe = { version = "0.3.0", features = ["print-defmt"] } +defmt = "1.0.1" +defmt-rtt = "1.0.0" +panic-probe = { version = "1.0.0", features = ["print-defmt"] } diff --git a/docs/examples/layer-by-layer/blinky-irq/Cargo.toml b/docs/examples/layer-by-layer/blinky-irq/Cargo.toml index 8733ee894..c3ec9ad1a 100644 --- a/docs/examples/layer-by-layer/blinky-irq/Cargo.toml +++ b/docs/examples/layer-by-layer/blinky-irq/Cargo.toml @@ -11,6 +11,6 @@ cortex-m = { version = "0.7", features = ["critical-section-single-core"] } cortex-m-rt = { version = "0.7" } embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32l475vg", "memory-x", "unstable-pac"] } -defmt = "0.3" -defmt-rtt = "0.4" -panic-probe = { version = "0.3.0", features = ["print-defmt"] } +defmt = "1.0.1" +defmt-rtt = "1.0.0" +panic-probe = { version = "1.0.0", features = ["print-defmt"] } diff --git a/docs/examples/layer-by-layer/blinky-pac/Cargo.toml b/docs/examples/layer-by-layer/blinky-pac/Cargo.toml index 155c41ec6..4e7e2f2ff 100644 --- a/docs/examples/layer-by-layer/blinky-pac/Cargo.toml +++ b/docs/examples/layer-by-layer/blinky-pac/Cargo.toml @@ -9,6 +9,6 @@ cortex-m = { version = "0.7", features = ["critical-section-single-core"] } cortex-m-rt = "0.7" stm32-metapac = { version = "16", features = ["stm32l475vg"] } -defmt = "0.3" -defmt-rtt = "0.4" -panic-probe = { version = "0.3.0", features = ["print-defmt"] } +defmt = "1.0.1" +defmt-rtt = "1.0.0" +panic-probe = { version = "1.0.0", features = ["print-defmt"] } diff --git a/embassy-boot-nrf/Cargo.toml b/embassy-boot-nrf/Cargo.toml index c3e0cb5ec..7d3e04419 100644 --- a/embassy-boot-nrf/Cargo.toml +++ b/embassy-boot-nrf/Cargo.toml @@ -21,7 +21,7 @@ target = "thumbv7em-none-eabi" [lib] [dependencies] -defmt = { version = "0.3", optional = true } +defmt = { version = "1.0.1", optional = true } log = { version = "0.4.17", optional = true } embassy-sync = { version = "0.6.2", path = "../embassy-sync" } diff --git a/embassy-boot-rp/Cargo.toml b/embassy-boot-rp/Cargo.toml index 284ac654c..10eec774f 100644 --- a/embassy-boot-rp/Cargo.toml +++ b/embassy-boot-rp/Cargo.toml @@ -21,7 +21,7 @@ features = ["embassy-rp/rp2040"] [lib] [dependencies] -defmt = { version = "0.3", optional = true } +defmt = { version = "1.0.1", optional = true } log = { version = "0.4", optional = true } embassy-sync = { version = "0.6.2", path = "../embassy-sync" } diff --git a/embassy-boot-stm32/Cargo.toml b/embassy-boot-stm32/Cargo.toml index 7dbe7e22b..2b741cc95 100644 --- a/embassy-boot-stm32/Cargo.toml +++ b/embassy-boot-stm32/Cargo.toml @@ -21,7 +21,7 @@ target = "thumbv7em-none-eabi" [lib] [dependencies] -defmt = { version = "0.3", optional = true } +defmt = { version = "1.0.1", optional = true } log = { version = "0.4", optional = true } embassy-sync = { version = "0.6.2", path = "../embassy-sync" } diff --git a/embassy-boot/Cargo.toml b/embassy-boot/Cargo.toml index 4906da0ea..8889f1a20 100644 --- a/embassy-boot/Cargo.toml +++ b/embassy-boot/Cargo.toml @@ -24,7 +24,7 @@ features = ["defmt"] [lib] [dependencies] -defmt = { version = "0.3", optional = true } +defmt = { version = "1.0.1", optional = true } digest = "0.10" log = { version = "0.4", optional = true } ed25519-dalek = { version = "2", default-features = false, features = ["digest"], optional = true } diff --git a/embassy-embedded-hal/Cargo.toml b/embassy-embedded-hal/Cargo.toml index f385963f1..f7a973a8d 100644 --- a/embassy-embedded-hal/Cargo.toml +++ b/embassy-embedded-hal/Cargo.toml @@ -35,7 +35,7 @@ embedded-storage = "0.3.1" embedded-storage-async = { version = "0.4.1" } nb = "1.0.0" -defmt = { version = "0.3", optional = true } +defmt = { version = "1.0.1", optional = true } [dev-dependencies] critical-section = { version = "1.1.1", features = ["std"] } diff --git a/embassy-executor/Cargo.toml b/embassy-executor/Cargo.toml index 0f69d3c8a..9f9eaa600 100644 --- a/embassy-executor/Cargo.toml +++ b/embassy-executor/Cargo.toml @@ -29,7 +29,7 @@ targets = ["thumbv7em-none-eabi"] features = ["defmt", "arch-cortex-m", "executor-thread", "executor-interrupt"] [dependencies] -defmt = { version = "0.3", optional = true } +defmt = { version = "1.0.1", optional = true } log = { version = "0.4.14", optional = true } rtos-trace = { version = "0.1.3", optional = true } diff --git a/embassy-futures/Cargo.toml b/embassy-futures/Cargo.toml index 47cefa56f..0deab0165 100644 --- a/embassy-futures/Cargo.toml +++ b/embassy-futures/Cargo.toml @@ -24,5 +24,5 @@ target = "thumbv7em-none-eabi" features = ["defmt"] [dependencies] -defmt = { version = "0.3", optional = true } +defmt = { version = "1.0.1", optional = true } log = { version = "0.4.14", optional = true } diff --git a/embassy-hal-internal/Cargo.toml b/embassy-hal-internal/Cargo.toml index d5ca95ac2..cc360682e 100644 --- a/embassy-hal-internal/Cargo.toml +++ b/embassy-hal-internal/Cargo.toml @@ -28,7 +28,7 @@ prio-bits-8 = [] cortex-m = ["dep:cortex-m", "dep:critical-section"] [dependencies] -defmt = { version = "0.3", optional = true } +defmt = { version = "1.0.1", optional = true } log = { version = "0.4.14", optional = true } num-traits = { version = "0.2.14", default-features = false } diff --git a/embassy-imxrt/Cargo.toml b/embassy-imxrt/Cargo.toml index d8cf3aaba..231a80251 100644 --- a/embassy-imxrt/Cargo.toml +++ b/embassy-imxrt/Cargo.toml @@ -71,7 +71,7 @@ embassy-hal-internal = { version = "0.2.0", path = "../embassy-hal-internal", fe embassy-embedded-hal = { version = "0.3.0", path = "../embassy-embedded-hal", default-features = false } embassy-futures = { version = "0.1.1", path = "../embassy-futures" } -defmt = { version = "1.0", optional = true } +defmt = { version = "1.0.1", optional = true } log = { version = "0.4.14", optional = true } nb = "1.0.0" cfg-if = "1.0.0" diff --git a/embassy-mspm0/Cargo.toml b/embassy-mspm0/Cargo.toml index df996ff4b..877d1ae18 100644 --- a/embassy-mspm0/Cargo.toml +++ b/embassy-mspm0/Cargo.toml @@ -38,7 +38,7 @@ embassy-executor = { version = "0.7.0", path = "../embassy-executor", optional = embedded-hal = { version = "1.0" } embedded-hal-async = { version = "1.0" } -defmt = { version = "0.3", optional = true } +defmt = { version = "1.0.1", optional = true } fixed = "1.29" log = { version = "0.4.14", optional = true } cortex-m-rt = ">=0.6.15,<0.8" diff --git a/embassy-net-adin1110/Cargo.toml b/embassy-net-adin1110/Cargo.toml index 22d494b84..a620928cb 100644 --- a/embassy-net-adin1110/Cargo.toml +++ b/embassy-net-adin1110/Cargo.toml @@ -11,7 +11,7 @@ documentation = "https://docs.embassy.dev/embassy-net-adin1110" [dependencies] heapless = "0.8" -defmt = { version = "0.3", optional = true } +defmt = { version = "1.0.1", optional = true } log = { version = "0.4", default-features = false, optional = true } embedded-hal-1 = { package = "embedded-hal", version = "1.0" } embedded-hal-async = { version = "1.0" } @@ -29,7 +29,7 @@ critical-section = { version = "1.1.2", features = ["std"] } futures-test = "0.3.28" [features] -defmt = [ "dep:defmt", "embedded-hal-1/defmt-03" ] +defmt = ["dep:defmt", "embedded-hal-1/defmt-03"] log = ["dep:log"] [package.metadata.embassy_docs] diff --git a/embassy-net-driver-channel/Cargo.toml b/embassy-net-driver-channel/Cargo.toml index 5165621b7..beadbf3c9 100644 --- a/embassy-net-driver-channel/Cargo.toml +++ b/embassy-net-driver-channel/Cargo.toml @@ -22,7 +22,7 @@ target = "thumbv7em-none-eabi" features = ["defmt"] [dependencies] -defmt = { version = "0.3", optional = true } +defmt = { version = "1.0.1", optional = true } log = { version = "0.4.14", optional = true } embassy-sync = { version = "0.6.2", path = "../embassy-sync" } diff --git a/embassy-net-driver/Cargo.toml b/embassy-net-driver/Cargo.toml index 97e8a0db3..34bc6c91a 100644 --- a/embassy-net-driver/Cargo.toml +++ b/embassy-net-driver/Cargo.toml @@ -22,4 +22,4 @@ target = "thumbv7em-none-eabi" features = ["defmt"] [dependencies] -defmt = { version = "0.3", optional = true } +defmt = { version = "1.0.1", optional = true } diff --git a/embassy-net-enc28j60/Cargo.toml b/embassy-net-enc28j60/Cargo.toml index 74f94816a..b26be1420 100644 --- a/embassy-net-enc28j60/Cargo.toml +++ b/embassy-net-enc28j60/Cargo.toml @@ -16,7 +16,7 @@ embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver" } embassy-time = { version = "0.4.0", path = "../embassy-time" } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } -defmt = { version = "0.3", optional = true } +defmt = { version = "1.0.1", optional = true } log = { version = "0.4.14", optional = true } [package.metadata.embassy_docs] diff --git a/embassy-net-esp-hosted/Cargo.toml b/embassy-net-esp-hosted/Cargo.toml index bab0e6d7c..0cb99e67e 100644 --- a/embassy-net-esp-hosted/Cargo.toml +++ b/embassy-net-esp-hosted/Cargo.toml @@ -10,11 +10,11 @@ repository = "https://github.com/embassy-rs/embassy" documentation = "https://docs.embassy.dev/embassy-net-esp-hosted" [features] -defmt = [ "dep:defmt", "heapless/defmt-03" ] -log = [ "dep:log" ] +defmt = ["dep:defmt", "heapless/defmt-03"] +log = ["dep:log"] [dependencies] -defmt = { version = "0.3", optional = true } +defmt = { version = "1.0.1", optional = true } log = { version = "0.4.14", optional = true } embassy-time = { version = "0.4.0", path = "../embassy-time" } diff --git a/embassy-net-nrf91/Cargo.toml b/embassy-net-nrf91/Cargo.toml index 99ec5a318..de12ac36f 100644 --- a/embassy-net-nrf91/Cargo.toml +++ b/embassy-net-nrf91/Cargo.toml @@ -10,20 +10,20 @@ repository = "https://github.com/embassy-rs/embassy" documentation = "https://docs.embassy.dev/embassy-net-nrf91" [features] -defmt = [ "dep:defmt", "heapless/defmt-03" ] -log = [ "dep:log" ] +defmt = ["dep:defmt", "heapless/defmt-03"] +log = ["dep:log"] [dependencies] -defmt = { version = "0.3", optional = true } +defmt = { version = "1.0.1", optional = true } log = { version = "0.4.14", optional = true } nrf-pac = "0.1.0" cortex-m = "0.7.7" embassy-time = { version = "0.4.0", path = "../embassy-time" } -embassy-sync = { version = "0.6.2", path = "../embassy-sync"} -embassy-futures = { version = "0.1.0", path = "../embassy-futures"} -embassy-net-driver-channel = { version = "0.3.0", path = "../embassy-net-driver-channel"} +embassy-sync = { version = "0.6.2", path = "../embassy-sync" } +embassy-futures = { version = "0.1.0", path = "../embassy-futures" } +embassy-net-driver-channel = { version = "0.3.0", path = "../embassy-net-driver-channel" } heapless = "0.8" embedded-io = "0.6.1" diff --git a/embassy-net-ppp/Cargo.toml b/embassy-net-ppp/Cargo.toml index 2d82e2ad0..ab713fed8 100644 --- a/embassy-net-ppp/Cargo.toml +++ b/embassy-net-ppp/Cargo.toml @@ -14,7 +14,7 @@ defmt = ["dep:defmt", "ppproto/defmt"] log = ["dep:log", "ppproto/log"] [dependencies] -defmt = { version = "0.3", optional = true } +defmt = { version = "1.0.1", optional = true } log = { version = "0.4.14", optional = true } embedded-io-async = { version = "0.6.1" } diff --git a/embassy-net-wiznet/Cargo.toml b/embassy-net-wiznet/Cargo.toml index 2ad5a6f48..a06a09302 100644 --- a/embassy-net-wiznet/Cargo.toml +++ b/embassy-net-wiznet/Cargo.toml @@ -15,7 +15,7 @@ embedded-hal-async = { version = "1.0" } embassy-net-driver-channel = { version = "0.3.0", path = "../embassy-net-driver-channel" } embassy-time = { version = "0.4.0", path = "../embassy-time" } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } -defmt = { version = "0.3", optional = true } +defmt = { version = "1.0.1", optional = true } [package.metadata.embassy_docs] src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-wiznet-v$VERSION/embassy-net-wiznet/src/" diff --git a/embassy-net/Cargo.toml b/embassy-net/Cargo.toml index c3bf1acbc..d96481f98 100644 --- a/embassy-net/Cargo.toml +++ b/embassy-net/Cargo.toml @@ -68,7 +68,7 @@ alloc = ["smoltcp/alloc"] [dependencies] -defmt = { version = "0.3.8", optional = true } +defmt = { version = "1.0.1", optional = true } log = { version = "0.4.14", optional = true } smoltcp = { version = "0.12.0", default-features = false, features = [ diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml index e4e143c65..e4f40630e 100644 --- a/embassy-nrf/Cargo.toml +++ b/embassy-nrf/Cargo.toml @@ -159,7 +159,7 @@ rand-core-09 = { package = "rand_core", version = "0.9" } nrf-pac = "0.1.0" -defmt = { version = "0.3", optional = true } +defmt = { version = "1.0.1", optional = true } bitflags = "2.4.2" log = { version = "0.4.14", optional = true } cortex-m-rt = ">=0.6.15,<0.8" diff --git a/embassy-nxp/Cargo.toml b/embassy-nxp/Cargo.toml index 031cd4aba..86a989aa7 100644 --- a/embassy-nxp/Cargo.toml +++ b/embassy-nxp/Cargo.toml @@ -10,7 +10,7 @@ critical-section = "1.1.2" embassy-hal-internal = { version = "0.2.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-2"] } embassy-sync = { version = "0.6.2", path = "../embassy-sync" } lpc55-pac = "0.5.0" -defmt = { version = "0.3.8", optional = true } +defmt = { version = "1", optional = true } [features] default = ["rt"] diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index 849cb549a..3c18a8f77 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml @@ -145,7 +145,7 @@ embassy-hal-internal = { version = "0.2.0", path = "../embassy-hal-internal", fe embassy-embedded-hal = { version = "0.3.0", path = "../embassy-embedded-hal" } embassy-usb-driver = { version = "0.1.0", path = "../embassy-usb-driver" } atomic-polyfill = "1.0.1" -defmt = { version = "0.3", optional = true } +defmt = { version = "1.0.1", optional = true } log = { version = "0.4.14", optional = true } nb = "1.1.0" cfg-if = "1.0.0" diff --git a/embassy-stm32-wpan/Cargo.toml b/embassy-stm32-wpan/Cargo.toml index 3bcfd11a9..81af6aedd 100644 --- a/embassy-stm32-wpan/Cargo.toml +++ b/embassy-stm32-wpan/Cargo.toml @@ -27,7 +27,7 @@ embassy-hal-internal = { version = "0.2.0", path = "../embassy-hal-internal" } embassy-embedded-hal = { version = "0.3.0", path = "../embassy-embedded-hal" } embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver", optional=true } -defmt = { version = "0.3", optional = true } +defmt = { version = "1.0.1", optional = true } log = { version = "0.4.17", optional = true } cortex-m = "0.7.6" diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 35c1291fd..d898f7ff3 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -67,7 +67,7 @@ rand-core-06 = { package = "rand_core", version = "0.6" } rand-core-09 = { package = "rand_core", version = "0.9" } -defmt = { version = "0.3", optional = true } +defmt = { version = "1.0.1", optional = true } log = { version = "0.4.14", optional = true } cortex-m-rt = ">=0.6.15,<0.8" cortex-m = "0.7.6" diff --git a/embassy-sync/Cargo.toml b/embassy-sync/Cargo.toml index 92ee38ed9..65cade317 100644 --- a/embassy-sync/Cargo.toml +++ b/embassy-sync/Cargo.toml @@ -24,7 +24,7 @@ std = [] turbowakers = [] [dependencies] -defmt = { version = "0.3", optional = true } +defmt = { version = "1.0.1", optional = true } log = { version = "0.4.14", optional = true } futures-sink = { version = "0.3", default-features = false, features = [] } diff --git a/embassy-time/Cargo.toml b/embassy-time/Cargo.toml index dc144ec3c..76983d880 100644 --- a/embassy-time/Cargo.toml +++ b/embassy-time/Cargo.toml @@ -420,7 +420,7 @@ tick-hz-5_242_880_000 = ["embassy-time-driver/tick-hz-5_242_880_000"] embassy-time-driver = { version = "0.2", path = "../embassy-time-driver" } embassy-time-queue-utils = { version = "0.1", path = "../embassy-time-queue-utils", optional = true} -defmt = { version = "0.3", optional = true } +defmt = { version = "1.0.1", optional = true } log = { version = "0.4.14", optional = true } embedded-hal-02 = { package = "embedded-hal", version = "0.2.6" } diff --git a/embassy-usb-dfu/Cargo.toml b/embassy-usb-dfu/Cargo.toml index eba902c74..ccf8a16eb 100644 --- a/embassy-usb-dfu/Cargo.toml +++ b/embassy-usb-dfu/Cargo.toml @@ -26,7 +26,7 @@ flavors = [ features = ["defmt", "cortex-m", "dfu"] [dependencies] -defmt = { version = "0.3.5", optional = true } +defmt = { version = "1.0.1", optional = true } log = { version = "0.4.17", optional = true } bitflags = "2.4.1" diff --git a/embassy-usb-driver/Cargo.toml b/embassy-usb-driver/Cargo.toml index edb6551b0..e40421649 100644 --- a/embassy-usb-driver/Cargo.toml +++ b/embassy-usb-driver/Cargo.toml @@ -19,5 +19,5 @@ target = "thumbv7em-none-eabi" features = ["defmt"] [dependencies] -defmt = { version = "0.3", optional = true } embedded-io-async = "0.6.1" +defmt = { version = "1", optional = true } diff --git a/embassy-usb-synopsys-otg/Cargo.toml b/embassy-usb-synopsys-otg/Cargo.toml index f9703a54a..98fc044ce 100644 --- a/embassy-usb-synopsys-otg/Cargo.toml +++ b/embassy-usb-synopsys-otg/Cargo.toml @@ -21,5 +21,5 @@ critical-section = "1.1" embassy-sync = { version = "0.6.2", path = "../embassy-sync" } embassy-usb-driver = { version = "0.1.0", path = "../embassy-usb-driver" } -defmt = { version = "0.3", optional = true } +defmt = { version = "1.0.1", optional = true } log = { version = "0.4.14", optional = true } diff --git a/embassy-usb/Cargo.toml b/embassy-usb/Cargo.toml index 4950fbe2a..e52f4602d 100644 --- a/embassy-usb/Cargo.toml +++ b/embassy-usb/Cargo.toml @@ -51,10 +51,10 @@ embassy-usb-driver = { version = "0.1.0", path = "../embassy-usb-driver" } embassy-sync = { version = "0.6.2", path = "../embassy-sync" } embassy-net-driver-channel = { version = "0.3.0", path = "../embassy-net-driver-channel" } -defmt = { version = "0.3", optional = true } -embedded-io-async = "0.6.1" +defmt = { version = "1", optional = true } log = { version = "0.4.14", optional = true } heapless = "0.8" +embedded-io-async = "0.6.1" # for HID usbd-hid = { version = "0.8.1", optional = true } diff --git a/examples/boot/application/nrf/Cargo.toml b/examples/boot/application/nrf/Cargo.toml index 4ae0e6a77..244ce9591 100644 --- a/examples/boot/application/nrf/Cargo.toml +++ b/examples/boot/application/nrf/Cargo.toml @@ -13,8 +13,8 @@ embassy-boot = { version = "0.4.0", path = "../../../../embassy-boot", features embassy-boot-nrf = { version = "0.4.0", path = "../../../../embassy-boot-nrf", features = [] } embassy-embedded-hal = { version = "0.3.0", path = "../../../../embassy-embedded-hal" } -defmt = { version = "0.3", optional = true } -defmt-rtt = { version = "0.4", optional = true } +defmt = { version = "1.0.1", optional = true } +defmt-rtt = { version = "1.0.0", optional = true } panic-reset = { version = "0.1.1" } embedded-hal = { version = "0.2.6" } diff --git a/examples/boot/application/rp/Cargo.toml b/examples/boot/application/rp/Cargo.toml index 3c0d207d1..24f4218f1 100644 --- a/examples/boot/application/rp/Cargo.toml +++ b/examples/boot/application/rp/Cargo.toml @@ -12,9 +12,9 @@ embassy-rp = { version = "0.4.0", path = "../../../../embassy-rp", features = [" embassy-boot-rp = { version = "0.5.0", path = "../../../../embassy-boot-rp", features = [] } embassy-embedded-hal = { version = "0.3.0", path = "../../../../embassy-embedded-hal" } -defmt = "0.3" -defmt-rtt = "0.4" -panic-probe = { version = "0.3", features = ["print-defmt"], optional = true } +defmt = "1.0.1" +defmt-rtt = "1.0.0" +panic-probe = { version = "1.0.0", features = ["print-defmt"], optional = true } panic-reset = { version = "0.1.1", optional = true } embedded-hal = { version = "0.2.6" } diff --git a/examples/boot/application/stm32f3/Cargo.toml b/examples/boot/application/stm32f3/Cargo.toml index f32727ea8..1e209eb9c 100644 --- a/examples/boot/application/stm32f3/Cargo.toml +++ b/examples/boot/application/stm32f3/Cargo.toml @@ -12,8 +12,8 @@ embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", feature embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32" } embassy-embedded-hal = { version = "0.3.0", path = "../../../../embassy-embedded-hal" } -defmt = { version = "0.3", optional = true } -defmt-rtt = { version = "0.4", optional = true } +defmt = { version = "1.0.1", optional = true } +defmt-rtt = { version = "1.0.0", optional = true } panic-reset = { version = "0.1.1" } embedded-hal = { version = "0.2.6" } diff --git a/examples/boot/application/stm32f7/Cargo.toml b/examples/boot/application/stm32f7/Cargo.toml index d62c67742..877e239fa 100644 --- a/examples/boot/application/stm32f7/Cargo.toml +++ b/examples/boot/application/stm32f7/Cargo.toml @@ -12,8 +12,8 @@ embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", feature embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } embassy-embedded-hal = { version = "0.3.0", path = "../../../../embassy-embedded-hal" } -defmt = { version = "0.3", optional = true } -defmt-rtt = { version = "0.4", optional = true } +defmt = { version = "1.0.1", optional = true } +defmt-rtt = { version = "1.0.0", optional = true } panic-reset = { version = "0.1.1" } embedded-hal = { version = "0.2.6" } embedded-storage = "0.3.1" diff --git a/examples/boot/application/stm32h7/Cargo.toml b/examples/boot/application/stm32h7/Cargo.toml index dd3a32e45..f28723835 100644 --- a/examples/boot/application/stm32h7/Cargo.toml +++ b/examples/boot/application/stm32h7/Cargo.toml @@ -12,8 +12,8 @@ embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", feature embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } embassy-embedded-hal = { version = "0.3.0", path = "../../../../embassy-embedded-hal" } -defmt = { version = "0.3", optional = true } -defmt-rtt = { version = "0.4", optional = true } +defmt = { version = "1.0.1", optional = true } +defmt-rtt = { version = "1.0.0", optional = true } panic-reset = { version = "0.1.1" } embedded-hal = { version = "0.2.6" } embedded-storage = "0.3.1" diff --git a/examples/boot/application/stm32l0/Cargo.toml b/examples/boot/application/stm32l0/Cargo.toml index 0b9e9b96a..f1cb55223 100644 --- a/examples/boot/application/stm32l0/Cargo.toml +++ b/examples/boot/application/stm32l0/Cargo.toml @@ -12,8 +12,8 @@ embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", feature embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } embassy-embedded-hal = { version = "0.3.0", path = "../../../../embassy-embedded-hal" } -defmt = { version = "0.3", optional = true } -defmt-rtt = { version = "0.4", optional = true } +defmt = { version = "1.0.1", optional = true } +defmt-rtt = { version = "1.0.0", optional = true } panic-reset = { version = "0.1.1" } embedded-hal = { version = "0.2.6" } diff --git a/examples/boot/application/stm32l1/Cargo.toml b/examples/boot/application/stm32l1/Cargo.toml index 490541a2e..7c53e011d 100644 --- a/examples/boot/application/stm32l1/Cargo.toml +++ b/examples/boot/application/stm32l1/Cargo.toml @@ -12,8 +12,8 @@ embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", feature embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } embassy-embedded-hal = { version = "0.3.0", path = "../../../../embassy-embedded-hal" } -defmt = { version = "0.3", optional = true } -defmt-rtt = { version = "0.4", optional = true } +defmt = { version = "1.0.1", optional = true } +defmt-rtt = { version = "1.0.0", optional = true } panic-reset = { version = "0.1.1" } embedded-hal = { version = "0.2.6" } diff --git a/examples/boot/application/stm32l4/Cargo.toml b/examples/boot/application/stm32l4/Cargo.toml index c3aa31161..9f5060802 100644 --- a/examples/boot/application/stm32l4/Cargo.toml +++ b/examples/boot/application/stm32l4/Cargo.toml @@ -12,8 +12,8 @@ embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", feature embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } embassy-embedded-hal = { version = "0.3.0", path = "../../../../embassy-embedded-hal" } -defmt = { version = "0.3", optional = true } -defmt-rtt = { version = "0.4", optional = true } +defmt = { version = "1.0.1", optional = true } +defmt-rtt = { version = "1.0.0", optional = true } panic-reset = { version = "0.1.1" } embedded-hal = { version = "0.2.6" } diff --git a/examples/boot/application/stm32wb-dfu/Cargo.toml b/examples/boot/application/stm32wb-dfu/Cargo.toml index a89e2bb6e..d1cea8520 100644 --- a/examples/boot/application/stm32wb-dfu/Cargo.toml +++ b/examples/boot/application/stm32wb-dfu/Cargo.toml @@ -14,8 +14,8 @@ embassy-embedded-hal = { version = "0.3.0", path = "../../../../embassy-embedded embassy-usb = { version = "0.4.0", path = "../../../../embassy-usb" } embassy-usb-dfu = { version = "0.1.0", path = "../../../../embassy-usb-dfu", features = ["application", "cortex-m"] } -defmt = { version = "0.3", optional = true } -defmt-rtt = { version = "0.4", optional = true } +defmt = { version = "1.0.1", optional = true } +defmt-rtt = { version = "1.0.0", optional = true } panic-reset = { version = "0.1.1" } embedded-hal = { version = "0.2.6" } diff --git a/examples/boot/application/stm32wl/Cargo.toml b/examples/boot/application/stm32wl/Cargo.toml index f4d7ae712..54331dd69 100644 --- a/examples/boot/application/stm32wl/Cargo.toml +++ b/examples/boot/application/stm32wl/Cargo.toml @@ -12,8 +12,8 @@ embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", feature embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } embassy-embedded-hal = { version = "0.3.0", path = "../../../../embassy-embedded-hal" } -defmt = { version = "0.3", optional = true } -defmt-rtt = { version = "0.4", optional = true } +defmt = { version = "1.0.1", optional = true } +defmt-rtt = { version = "1.0.0", optional = true } panic-reset = { version = "0.1.1" } embedded-hal = { version = "0.2.6" } diff --git a/examples/boot/bootloader/nrf/Cargo.toml b/examples/boot/bootloader/nrf/Cargo.toml index 34a0553e3..4c2712718 100644 --- a/examples/boot/bootloader/nrf/Cargo.toml +++ b/examples/boot/bootloader/nrf/Cargo.toml @@ -6,8 +6,8 @@ description = "Bootloader for nRF chips" license = "MIT OR Apache-2.0" [dependencies] -defmt = { version = "0.3", optional = true } -defmt-rtt = { version = "0.4", optional = true } +defmt = { version = "1.0.1", optional = true } +defmt-rtt = { version = "1.0.0", optional = true } embassy-nrf = { path = "../../../../embassy-nrf", features = [] } embassy-boot-nrf = { path = "../../../../embassy-boot-nrf" } diff --git a/examples/boot/bootloader/rp/Cargo.toml b/examples/boot/bootloader/rp/Cargo.toml index 7c9c3c779..c57b90793 100644 --- a/examples/boot/bootloader/rp/Cargo.toml +++ b/examples/boot/bootloader/rp/Cargo.toml @@ -6,8 +6,8 @@ description = "Example bootloader for RP2040 chips" license = "MIT OR Apache-2.0" [dependencies] -defmt = { version = "0.3", optional = true } -defmt-rtt = { version = "0.4", optional = true } +defmt = { version = "1.0.1", optional = true } +defmt-rtt = { version = "1.0.0", optional = true } embassy-rp = { path = "../../../../embassy-rp", features = ["rp2040"] } embassy-boot-rp = { path = "../../../../embassy-boot-rp" } diff --git a/examples/boot/bootloader/stm32-dual-bank/Cargo.toml b/examples/boot/bootloader/stm32-dual-bank/Cargo.toml index 4beb9c61c..a3ca96aec 100644 --- a/examples/boot/bootloader/stm32-dual-bank/Cargo.toml +++ b/examples/boot/bootloader/stm32-dual-bank/Cargo.toml @@ -6,8 +6,8 @@ description = "Example bootloader for dual-bank flash STM32 chips" license = "MIT OR Apache-2.0" [dependencies] -defmt = { version = "0.3", optional = true } -defmt-rtt = { version = "0.4", optional = true } +defmt = { version = "1.0.1", optional = true } +defmt-rtt = { version = "1.0.0", optional = true } embassy-stm32 = { path = "../../../../embassy-stm32", features = [] } embassy-boot-stm32 = { path = "../../../../embassy-boot-stm32" } diff --git a/examples/boot/bootloader/stm32/Cargo.toml b/examples/boot/bootloader/stm32/Cargo.toml index 9abad8636..bdefa2cb5 100644 --- a/examples/boot/bootloader/stm32/Cargo.toml +++ b/examples/boot/bootloader/stm32/Cargo.toml @@ -6,8 +6,8 @@ description = "Example bootloader for STM32 chips" license = "MIT OR Apache-2.0" [dependencies] -defmt = { version = "0.3", optional = true } -defmt-rtt = { version = "0.4", optional = true } +defmt = { version = "1.0.1", optional = true } +defmt-rtt = { version = "1.0.0", optional = true } embassy-stm32 = { path = "../../../../embassy-stm32", features = [] } embassy-boot-stm32 = { path = "../../../../embassy-boot-stm32" } diff --git a/examples/boot/bootloader/stm32wb-dfu/Cargo.toml b/examples/boot/bootloader/stm32wb-dfu/Cargo.toml index 01343b86b..389f43641 100644 --- a/examples/boot/bootloader/stm32wb-dfu/Cargo.toml +++ b/examples/boot/bootloader/stm32wb-dfu/Cargo.toml @@ -6,8 +6,8 @@ description = "Example USB DFUbootloader for the STM32WB series of chips" license = "MIT OR Apache-2.0" [dependencies] -defmt = { version = "0.3", optional = true } -defmt-rtt = { version = "0.4", optional = true } +defmt = { version = "1.0.1", optional = true } +defmt-rtt = { version = "1.0.0", optional = true } embassy-stm32 = { path = "../../../../embassy-stm32", features = [] } embassy-boot-stm32 = { path = "../../../../embassy-boot-stm32" } diff --git a/examples/lpc55s69/Cargo.toml b/examples/lpc55s69/Cargo.toml index f5a6e6995..30ce0b799 100644 --- a/examples/lpc55s69/Cargo.toml +++ b/examples/lpc55s69/Cargo.toml @@ -10,12 +10,12 @@ embassy-nxp = { version = "0.1.0", path = "../../embassy-nxp", features = ["rt"] embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt"] } embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt"] } -panic-halt = "0.2.0" +panic-halt = "1.0.0" cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } cortex-m-rt = { version = "0.7.0"} -defmt = "0.3" -defmt-rtt = "0.4" -panic-probe = { version = "0.3.2", features = ["print-defmt"] } +defmt = "1.0.1" +defmt-rtt = "1.0.0" +panic-probe = { version = "1.0.0", features = ["print-defmt"] } panic-semihosting = "0.6.0" [profile.release] diff --git a/examples/mimxrt6/Cargo.toml b/examples/mimxrt6/Cargo.toml index 27c3a27dc..40cc0fb44 100644 --- a/examples/mimxrt6/Cargo.toml +++ b/examples/mimxrt6/Cargo.toml @@ -7,8 +7,8 @@ license = "MIT or Apache-2.0" [dependencies] cortex-m = { version = "0.7.7", features = ["inline-asm", "critical-section-single-core"] } cortex-m-rt = "0.7.3" -defmt = "1.0" -defmt-rtt = "1.0" +defmt = "1.0.1" +defmt-rtt = "1.0.0" embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-futures = { version = "0.1.1", path = "../../embassy-futures" } @@ -19,7 +19,7 @@ embedded-hal-1 = { package = "embedded-hal", version = "1.0" } embedded-hal-async = "1.0.0" mimxrt600-fcb = "0.2.2" -panic-probe = { version = "0.3", features = ["print-defmt"] } +panic-probe = { version = "1.0.0", features = ["print-defmt"] } # cargo build/run [profile.dev] diff --git a/examples/mspm0c1104/Cargo.toml b/examples/mspm0c1104/Cargo.toml index ba64a578d..1498b599d 100644 --- a/examples/mspm0c1104/Cargo.toml +++ b/examples/mspm0c1104/Cargo.toml @@ -9,12 +9,12 @@ embassy-mspm0 = { version = "0.1.0", path = "../../embassy-mspm0", features = [" embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt"] } embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt"] } -panic-halt = "0.2.0" +panic-halt = "1.0.0" cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } cortex-m-rt = { version = "0.7.0"} -defmt = "0.3" -defmt-rtt = "0.4" -panic-probe = { version = "0.3.2", features = ["print-defmt"] } +defmt = "1.0.1" +defmt-rtt = "1.0.0" +panic-probe = { version = "1.0.0", features = ["print-defmt"] } panic-semihosting = "0.6.0" # The chip only has 1KB of ram, so we must optimize binaries regardless diff --git a/examples/mspm0g3507/Cargo.toml b/examples/mspm0g3507/Cargo.toml index f6fed091d..78c4b3f5a 100644 --- a/examples/mspm0g3507/Cargo.toml +++ b/examples/mspm0g3507/Cargo.toml @@ -9,12 +9,12 @@ embassy-mspm0 = { version = "0.1.0", path = "../../embassy-mspm0", features = [" embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt"] } embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt"] } -panic-halt = "0.2.0" +panic-halt = "1.0.0" cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } cortex-m-rt = { version = "0.7.0"} -defmt = "0.3" -defmt-rtt = "0.4" -panic-probe = { version = "0.3.2", features = ["print-defmt"] } +defmt = "1.0.1" +defmt-rtt = "1.0.0" +panic-probe = { version = "1.0.0", features = ["print-defmt"] } panic-semihosting = "0.6.0" [profile.release] diff --git a/examples/mspm0g3519/Cargo.toml b/examples/mspm0g3519/Cargo.toml index 1662e1f8d..1d191b2da 100644 --- a/examples/mspm0g3519/Cargo.toml +++ b/examples/mspm0g3519/Cargo.toml @@ -9,12 +9,12 @@ embassy-mspm0 = { version = "0.1.0", path = "../../embassy-mspm0", features = [" embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt"] } embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt"] } -panic-halt = "0.2.0" +panic-halt = "1.0.0" cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } cortex-m-rt = { version = "0.7.0"} -defmt = "0.3" -defmt-rtt = "0.4" -panic-probe = { version = "0.3.2", features = ["print-defmt"] } +defmt = "1.0.1" +defmt-rtt = "1.0.0" +panic-probe = { version = "1.0.0", features = ["print-defmt"] } panic-semihosting = "0.6.0" [profile.release] diff --git a/examples/mspm0l1306/Cargo.toml b/examples/mspm0l1306/Cargo.toml index 609b3f205..e427971fe 100644 --- a/examples/mspm0l1306/Cargo.toml +++ b/examples/mspm0l1306/Cargo.toml @@ -9,12 +9,12 @@ embassy-mspm0 = { version = "0.1.0", path = "../../embassy-mspm0", features = [" embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt"] } embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt"] } -panic-halt = "0.2.0" +panic-halt = "1.0.0" cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } cortex-m-rt = { version = "0.7.0"} -defmt = "0.3" -defmt-rtt = "0.4" -panic-probe = { version = "0.3.2", features = ["print-defmt"] } +defmt = "1.0.1" +defmt-rtt = "1.0.0" +panic-probe = { version = "1.0.0", features = ["print-defmt"] } panic-semihosting = "0.6.0" [profile.release] diff --git a/examples/mspm0l2228/Cargo.toml b/examples/mspm0l2228/Cargo.toml index bbca011a1..39e0e1a0c 100644 --- a/examples/mspm0l2228/Cargo.toml +++ b/examples/mspm0l2228/Cargo.toml @@ -9,12 +9,12 @@ embassy-mspm0 = { version = "0.1.0", path = "../../embassy-mspm0", features = [" embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt"] } embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt"] } -panic-halt = "0.2.0" +panic-halt = "1.0.0" cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } cortex-m-rt = { version = "0.7.0"} -defmt = "0.3" -defmt-rtt = "0.4" -panic-probe = { version = "0.3.2", features = ["print-defmt"] } +defmt = "1.0.1" +defmt-rtt = "1.0.0" +panic-probe = { version = "1.0.0", features = ["print-defmt"] } panic-semihosting = "0.6.0" [profile.release] diff --git a/examples/nrf-rtos-trace/Cargo.toml b/examples/nrf-rtos-trace/Cargo.toml index ba609d889..dcbaf87f8 100644 --- a/examples/nrf-rtos-trace/Cargo.toml +++ b/examples/nrf-rtos-trace/Cargo.toml @@ -22,7 +22,7 @@ embassy-nrf = { version = "0.3.1", path = "../../embassy-nrf", features = ["nrf5 cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } cortex-m-rt = "0.7.0" -panic-probe = { version = "0.3" } +panic-probe = "1.0.0" serde = { version = "1.0.136", default-features = false } rtos-trace = "0.1.3" systemview-target = { version = "0.1.2", features = ["callbacks-app", "callbacks-os", "log", "cortex-m"] } diff --git a/examples/nrf51/Cargo.toml b/examples/nrf51/Cargo.toml index 97b5b924a..91f78737f 100644 --- a/examples/nrf51/Cargo.toml +++ b/examples/nrf51/Cargo.toml @@ -9,12 +9,12 @@ embassy-executor = { version = "0.7.0", path = "../../embassy-executor", feature embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.3.1", path = "../../embassy-nrf", features = ["defmt", "nrf51", "gpiote", "time-driver-rtc1", "unstable-pac", "time", "rt"] } -defmt = "0.3" -defmt-rtt = "0.4" +defmt = "1.0.1" +defmt-rtt = "1.0.0" cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } cortex-m-rt = "0.7" -panic-probe = { version = "0.3", features = ["print-defmt"] } +panic-probe = { version = "1.0.0", features = ["print-defmt"] } [profile.release] debug = 2 diff --git a/examples/nrf52810/Cargo.toml b/examples/nrf52810/Cargo.toml index cd59b86c3..5373278c1 100644 --- a/examples/nrf52810/Cargo.toml +++ b/examples/nrf52810/Cargo.toml @@ -11,14 +11,14 @@ embassy-executor = { version = "0.7.0", path = "../../embassy-executor", feature embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.3.1", path = "../../embassy-nrf", features = ["defmt", "nrf52810", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } -defmt = "0.3" -defmt-rtt = "0.4" +defmt = "1.0.1" +defmt-rtt = "1.0.0" fixed = "1.10.0" static_cell = { version = "2" } cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } cortex-m-rt = "0.7.0" -panic-probe = { version = "0.3", features = ["print-defmt"] } +panic-probe = { version = "1.0.0", features = ["print-defmt"] } [profile.release] debug = 2 diff --git a/examples/nrf52840-rtic/Cargo.toml b/examples/nrf52840-rtic/Cargo.toml index ac3d2006c..2eef012b7 100644 --- a/examples/nrf52840-rtic/Cargo.toml +++ b/examples/nrf52840-rtic/Cargo.toml @@ -13,12 +13,12 @@ embassy-time = { version = "0.4.0", path = "../../embassy-time", features = [ "d embassy-time-queue-utils = { version = "0.1", path = "../../embassy-time-queue-utils", features = ["generic-queue-8"] } embassy-nrf = { version = "0.3.1", path = "../../embassy-nrf", features = [ "defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } -defmt = "0.3" -defmt-rtt = "0.4" +defmt = "1.0.1" +defmt-rtt = "1.0.0" cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } cortex-m-rt = "0.7.0" -panic-probe = { version = "0.3", features = ["print-defmt"] } +panic-probe = { version = "1.0.0", features = ["print-defmt"] } [profile.release] debug = 2 diff --git a/examples/nrf52840/Cargo.toml b/examples/nrf52840/Cargo.toml index ff40a34af..92127a8b0 100644 --- a/examples/nrf52840/Cargo.toml +++ b/examples/nrf52840/Cargo.toml @@ -17,14 +17,14 @@ embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } embassy-net-esp-hosted = { version = "0.2.0", path = "../../embassy-net-esp-hosted", features = ["defmt"] } embassy-net-enc28j60 = { version = "0.2.0", path = "../../embassy-net-enc28j60", features = ["defmt"] } -defmt = "0.3" -defmt-rtt = "0.4" +defmt = "1.0.1" +defmt-rtt = "1.0.0" fixed = "1.10.0" static_cell = { version = "2" } cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } cortex-m-rt = "0.7.0" -panic-probe = { version = "0.3", features = ["print-defmt"] } +panic-probe = { version = "1.0.0", features = ["print-defmt"] } rand = { version = "0.9.0", default-features = false } embedded-storage = "0.3.1" usbd-hid = "0.8.1" diff --git a/examples/nrf5340/Cargo.toml b/examples/nrf5340/Cargo.toml index 5c226695f..42d7766b7 100644 --- a/examples/nrf5340/Cargo.toml +++ b/examples/nrf5340/Cargo.toml @@ -14,13 +14,13 @@ embassy-net = { version = "0.7.0", path = "../../embassy-net", features = ["defm embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defmt"] } embedded-io-async = { version = "0.6.1" } -defmt = "0.3" -defmt-rtt = "0.4" +defmt = "1.0.1" +defmt-rtt = "1.0.0" static_cell = "2" cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } cortex-m-rt = "0.7.0" -panic-probe = { version = "0.3", features = ["print-defmt"] } +panic-probe = { version = "1.0.0", features = ["print-defmt"] } embedded-storage = "0.3.1" usbd-hid = "0.8.1" serde = { version = "1.0.136", default-features = false } diff --git a/examples/nrf54l15/Cargo.toml b/examples/nrf54l15/Cargo.toml index 8848065d8..4b229d06d 100644 --- a/examples/nrf54l15/Cargo.toml +++ b/examples/nrf54l15/Cargo.toml @@ -9,9 +9,9 @@ embassy-executor = { version = "0.7.0", path = "../../embassy-executor", feature embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.3.1", path = "../../embassy-nrf", features = ["defmt", "nrf54l15-app-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } -defmt = "0.3" -defmt-rtt = "0.4" -panic-probe = { version = "0.3", features = ["print-defmt"] } +defmt = "1.0.1" +defmt-rtt = "1.0.0" +panic-probe = { version = "1.0.0", features = ["print-defmt"] } cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } cortex-m-rt = "0.7.0" diff --git a/examples/nrf9151/ns/Cargo.toml b/examples/nrf9151/ns/Cargo.toml index 03f38fd63..a083aa5e7 100644 --- a/examples/nrf9151/ns/Cargo.toml +++ b/examples/nrf9151/ns/Cargo.toml @@ -9,12 +9,12 @@ embassy-executor = { version = "0.7.0", path = "../../../embassy-executor", feat embassy-time = { version = "0.4.0", path = "../../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.3.1", path = "../../../embassy-nrf", features = ["defmt", "nrf9120-ns", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } -defmt = "0.3" -defmt-rtt = "0.4" +defmt = "1.0.1" +defmt-rtt = "1.0.0" cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } cortex-m-rt = "0.7.0" -panic-probe = { version = "0.3", features = ["print-defmt"] } +panic-probe = { version = "1.0.0", features = ["print-defmt"] } [profile.release] debug = 2 diff --git a/examples/nrf9151/s/Cargo.toml b/examples/nrf9151/s/Cargo.toml index ba88f6da3..ae98631ef 100644 --- a/examples/nrf9151/s/Cargo.toml +++ b/examples/nrf9151/s/Cargo.toml @@ -9,12 +9,12 @@ embassy-executor = { version = "0.7.0", path = "../../../embassy-executor", feat embassy-time = { version = "0.4.0", path = "../../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.3.1", path = "../../../embassy-nrf", features = ["defmt", "nrf9120-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } -defmt = "0.3" -defmt-rtt = "0.4" +defmt = "1.0.1" +defmt-rtt = "1.0.0" cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } cortex-m-rt = "0.7.0" -panic-probe = { version = "0.3", features = ["print-defmt"] } +panic-probe = { version = "1.0.0", features = ["print-defmt"] } [profile.release] debug = 2 diff --git a/examples/nrf9160/Cargo.toml b/examples/nrf9160/Cargo.toml index a720f2d61..25aedf624 100644 --- a/examples/nrf9160/Cargo.toml +++ b/examples/nrf9160/Cargo.toml @@ -11,13 +11,13 @@ embassy-nrf = { version = "0.3.1", path = "../../embassy-nrf", features = ["defm embassy-net-nrf91 = { version = "0.1.0", path = "../../embassy-net-nrf91", features = ["defmt"] } embassy-net = { version = "0.7.0", path = "../../embassy-net", features = ["defmt", "tcp", "proto-ipv4", "medium-ip"] } -defmt = "0.3" -defmt-rtt = "0.4" +defmt = "1.0.1" +defmt-rtt = "1.0.0" heapless = "0.8" cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } cortex-m-rt = "0.7.0" -panic-probe = { version = "0.3", features = ["print-defmt"] } +panic-probe = { version = "1.0.0", features = ["print-defmt"] } static_cell = { version = "2" } embedded-io = "0.6.1" embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index aacf9846a..d19dd9dc7 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml @@ -19,8 +19,8 @@ embassy-usb-logger = { version = "0.4.0", path = "../../embassy-usb-logger" } cyw43 = { version = "0.3.0", path = "../../cyw43", features = ["defmt", "firmware-logs"] } cyw43-pio = { version = "0.4.0", path = "../../cyw43-pio", features = ["defmt"] } -defmt = "0.3" -defmt-rtt = "0.4" +defmt = "1.0.1" +defmt-rtt = "1.0.0" fixed = "1.23.1" fixed-macro = "1.2" @@ -36,7 +36,7 @@ assign-resources = { git = "https://github.com/adamgreig/assign-resources", rev cortex-m = { version = "0.7.6", features = ["inline-asm"] } cortex-m-rt = "0.7.0" critical-section = "1.1" -panic-probe = { version = "0.3", features = ["print-defmt"] } +panic-probe = { version = "1.0.0", features = ["print-defmt"] } display-interface-spi = "0.5.0" embedded-graphics = "0.8.1" mipidsi = "0.8.0" diff --git a/examples/rp235x/Cargo.toml b/examples/rp235x/Cargo.toml index a247bc619..ae64489ae 100644 --- a/examples/rp235x/Cargo.toml +++ b/examples/rp235x/Cargo.toml @@ -19,8 +19,8 @@ embassy-usb-logger = { version = "0.4.0", path = "../../embassy-usb-logger" } cyw43 = { version = "0.3.0", path = "../../cyw43", features = ["defmt", "firmware-logs"] } cyw43-pio = { version = "0.4.0", path = "../../cyw43-pio", features = ["defmt"] } -defmt = "0.3" -defmt-rtt = "0.4" +defmt = "1.0.1" +defmt-rtt = "1.0.0" fixed = "1.23.1" fixed-macro = "1.2" @@ -37,7 +37,7 @@ tb6612fng = "1.0.0" cortex-m = { version = "0.7.6", features = ["inline-asm"] } cortex-m-rt = "0.7.0" critical-section = "1.1" -panic-probe = { version = "0.3", features = ["print-defmt"] } +panic-probe = { version = "1.0.0", features = ["print-defmt"] } display-interface-spi = "0.5.0" embedded-graphics = "0.8.1" mipidsi = "0.8.0" diff --git a/examples/stm32c0/Cargo.toml b/examples/stm32c0/Cargo.toml index 767b742f7..71f1cfda1 100644 --- a/examples/stm32c0/Cargo.toml +++ b/examples/stm32c0/Cargo.toml @@ -11,13 +11,13 @@ embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["de embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } -defmt = "0.3" -defmt-rtt = "0.4" +defmt = "1.0.1" +defmt-rtt = "1.0.0" cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } cortex-m-rt = "0.7.0" embedded-hal = "0.2.6" -panic-probe = { version = "0.3", features = ["print-defmt"] } +panic-probe = { version = "1.0.0", features = ["print-defmt"] } heapless = { version = "0.8", default-features = false } [profile.release] diff --git a/examples/stm32f0/Cargo.toml b/examples/stm32f0/Cargo.toml index 932a97dc8..534e8c33d 100644 --- a/examples/stm32f0/Cargo.toml +++ b/examples/stm32f0/Cargo.toml @@ -9,9 +9,9 @@ license = "MIT OR Apache-2.0" embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [ "defmt", "memory-x", "stm32f091rc", "time-driver-tim2", "exti", "unstable-pac"] } cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } cortex-m-rt = "0.7.0" -defmt = "0.3" -defmt-rtt = "0.4" -panic-probe = { version = "0.3", features = ["print-defmt"] } +defmt = "1.0.1" +defmt-rtt = "1.0.0" +panic-probe = { version = "1.0.0", features = ["print-defmt"] } embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } diff --git a/examples/stm32f1/Cargo.toml b/examples/stm32f1/Cargo.toml index fe800bc80..f856d2620 100644 --- a/examples/stm32f1/Cargo.toml +++ b/examples/stm32f1/Cargo.toml @@ -13,13 +13,13 @@ embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["de embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } -defmt = "0.3" -defmt-rtt = "0.4" +defmt = "1.0.1" +defmt-rtt = "1.0.0" cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } cortex-m-rt = "0.7.0" embedded-hal = "0.2.6" -panic-probe = { version = "0.3", features = ["print-defmt"] } +panic-probe = { version = "1.0.0", features = ["print-defmt"] } heapless = { version = "0.8", default-features = false } nb = "1.0.0" static_cell = "2.0.0" diff --git a/examples/stm32f2/Cargo.toml b/examples/stm32f2/Cargo.toml index 26be3f485..f26cbfadc 100644 --- a/examples/stm32f2/Cargo.toml +++ b/examples/stm32f2/Cargo.toml @@ -11,13 +11,13 @@ embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["de embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } -defmt = "0.3" -defmt-rtt = "0.4" +defmt = "1.0.1" +defmt-rtt = "1.0.0" cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } cortex-m-rt = "0.7.0" embedded-hal = "0.2.6" -panic-probe = { version = "0.3", features = ["print-defmt"] } +panic-probe = { version = "1.0.0", features = ["print-defmt"] } heapless = { version = "0.8", default-features = false } nb = "1.0.0" diff --git a/examples/stm32f3/Cargo.toml b/examples/stm32f3/Cargo.toml index 31bf040b0..4c1dd881f 100644 --- a/examples/stm32f3/Cargo.toml +++ b/examples/stm32f3/Cargo.toml @@ -13,13 +13,13 @@ embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["de embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } -defmt = "0.3" -defmt-rtt = "0.4" +defmt = "1.0.1" +defmt-rtt = "1.0.0" cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } cortex-m-rt = "0.7.0" embedded-hal = "0.2.6" -panic-probe = { version = "0.3", features = ["print-defmt"] } +panic-probe = { version = "1.0.0", features = ["print-defmt"] } heapless = { version = "0.8", default-features = false } nb = "1.0.0" embedded-storage = "0.3.1" diff --git a/examples/stm32f334/Cargo.toml b/examples/stm32f334/Cargo.toml index 5fb6d60c5..c28855b3a 100644 --- a/examples/stm32f334/Cargo.toml +++ b/examples/stm32f334/Cargo.toml @@ -12,13 +12,13 @@ embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [ embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } -defmt = "0.3" -defmt-rtt = "0.4" +defmt = "1.0.1" +defmt-rtt = "1.0.0" cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } cortex-m-rt = "0.7.0" embedded-hal = "0.2.6" -panic-probe = { version = "0.3", features = ["print-defmt"] } +panic-probe = { version = "1.0.0", features = ["print-defmt"] } heapless = { version = "0.8", default-features = false } nb = "1.0.0" embedded-storage = "0.3.1" diff --git a/examples/stm32f4/Cargo.toml b/examples/stm32f4/Cargo.toml index 7aa4354ca..7374f8813 100644 --- a/examples/stm32f4/Cargo.toml +++ b/examples/stm32f4/Cargo.toml @@ -15,8 +15,8 @@ embassy-net = { version = "0.7.0", path = "../../embassy-net", features = ["defm embassy-net-wiznet = { version = "0.2.0", path = "../../embassy-net-wiznet", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } -defmt = "0.3" -defmt-rtt = "0.4" +defmt = "1.0.1" +defmt-rtt = "1.0.0" cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } cortex-m-rt = "0.7.0" @@ -24,7 +24,7 @@ embedded-hal = "0.2.6" embedded-hal-bus = { version = "0.2", features = ["async"] } embedded-io = { version = "0.6.0" } embedded-io-async = { version = "0.6.1" } -panic-probe = { version = "0.3", features = ["print-defmt"] } +panic-probe = { version = "1.0.0", features = ["print-defmt"] } futures-util = { version = "0.3.30", default-features = false } heapless = { version = "0.8", default-features = false } critical-section = "1.1" diff --git a/examples/stm32f469/Cargo.toml b/examples/stm32f469/Cargo.toml index 4d403bae8..87a3b8f75 100644 --- a/examples/stm32f469/Cargo.toml +++ b/examples/stm32f469/Cargo.toml @@ -10,13 +10,13 @@ embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [" embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } -defmt = "0.3" -defmt-rtt = "0.4" +defmt = "1.0.1" +defmt-rtt = "1.0.0" cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } cortex-m-rt = "0.7.0" embedded-hal = "1.0.0" -panic-probe = { version = "0.3", features = ["print-defmt"] } +panic-probe = { version = "1.0.0", features = ["print-defmt"] } [profile.release] debug = 2 diff --git a/examples/stm32f7/Cargo.toml b/examples/stm32f7/Cargo.toml index 94e0a80eb..bce521f30 100644 --- a/examples/stm32f7/Cargo.toml +++ b/examples/stm32f7/Cargo.toml @@ -15,13 +15,13 @@ embedded-io-async = { version = "0.6.1" } embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } -defmt = "0.3" -defmt-rtt = "0.4" +defmt = "1.0.1" +defmt-rtt = "1.0.0" cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } cortex-m-rt = "0.7.0" embedded-hal = "0.2.6" -panic-probe = { version = "0.3", features = ["print-defmt"] } +panic-probe = { version = "1.0.0", features = ["print-defmt"] } heapless = { version = "0.8", default-features = false } nb = "1.0.0" critical-section = "1.1" diff --git a/examples/stm32g0/Cargo.toml b/examples/stm32g0/Cargo.toml index 319d84179..5e09b237e 100644 --- a/examples/stm32g0/Cargo.toml +++ b/examples/stm32g0/Cargo.toml @@ -13,13 +13,13 @@ embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["de embassy-usb = { version = "0.4.0", path = "../../embassy-usb", default-features = false, features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } -defmt = "0.3" -defmt-rtt = "0.4" +defmt = "1.0.1" +defmt-rtt = "1.0.0" cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } cortex-m-rt = "0.7.0" embedded-hal = "0.2.6" -panic-probe = { version = "0.3", features = ["print-defmt"] } +panic-probe = { version = "1.0.0", features = ["print-defmt"] } heapless = { version = "0.8", default-features = false } portable-atomic = { version = "1.5", features = ["unsafe-assume-single-core"] } diff --git a/examples/stm32g4/Cargo.toml b/examples/stm32g4/Cargo.toml index aa01d84e2..582553a29 100644 --- a/examples/stm32g4/Cargo.toml +++ b/examples/stm32g4/Cargo.toml @@ -14,14 +14,14 @@ embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defm embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } usbd-hid = "0.8.1" -defmt = "0.3" -defmt-rtt = "0.4" +defmt = "1.0.1" +defmt-rtt = "1.0.0" cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } cortex-m-rt = "0.7.0" embedded-hal = "0.2.6" embedded-can = { version = "0.4" } -panic-probe = { version = "0.3", features = ["print-defmt"] } +panic-probe = { version = "1.0.0", features = ["print-defmt"] } heapless = { version = "0.8", default-features = false } static_cell = "2.0.0" diff --git a/examples/stm32h5/Cargo.toml b/examples/stm32h5/Cargo.toml index 6fb14f422..3e022e4e5 100644 --- a/examples/stm32h5/Cargo.toml +++ b/examples/stm32h5/Cargo.toml @@ -14,8 +14,8 @@ embassy-net = { version = "0.7.0", path = "../../embassy-net", features = ["defm embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } -defmt = "0.3" -defmt-rtt = "0.4" +defmt = "1.0.1" +defmt-rtt = "1.0.0" cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } cortex-m-rt = "0.7.0" @@ -24,7 +24,7 @@ embedded-hal-1 = { package = "embedded-hal", version = "1.0" } embedded-hal-async = { version = "1.0" } embedded-io-async = { version = "0.6.1" } embedded-nal-async = "0.8.0" -panic-probe = { version = "0.3", features = ["print-defmt"] } +panic-probe = { version = "1.0.0", features = ["print-defmt"] } heapless = { version = "0.8", default-features = false } critical-section = "1.1" micromath = "2.0.0" diff --git a/examples/stm32h7/Cargo.toml b/examples/stm32h7/Cargo.toml index 5035dacae..520d0c8e6 100644 --- a/examples/stm32h7/Cargo.toml +++ b/examples/stm32h7/Cargo.toml @@ -15,8 +15,8 @@ embassy-net = { version = "0.7.0", path = "../../embassy-net", features = ["defm embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } -defmt = "0.3" -defmt-rtt = "0.4" +defmt = "1.0.1" +defmt-rtt = "1.0.0" cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } cortex-m-rt = "0.7.0" @@ -25,7 +25,7 @@ embedded-hal-1 = { package = "embedded-hal", version = "1.0" } embedded-hal-async = { version = "1.0" } embedded-nal-async = "0.8.0" embedded-io-async = { version = "0.6.1" } -panic-probe = { version = "0.3", features = ["print-defmt"] } +panic-probe = { version = "1.0.0", features = ["print-defmt"] } heapless = { version = "0.8", default-features = false } critical-section = "1.1" micromath = "2.0.0" diff --git a/examples/stm32h723/Cargo.toml b/examples/stm32h723/Cargo.toml index f07d360b3..1eb706b4d 100644 --- a/examples/stm32h723/Cargo.toml +++ b/examples/stm32h723/Cargo.toml @@ -12,8 +12,8 @@ embassy-executor = { version = "0.7.0", path = "../../embassy-executor", feature embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } -defmt = "0.3" -defmt-rtt = "0.4" +defmt = "1.0.1" +defmt-rtt = "1.0.0" cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } cortex-m-rt = "0.7.0" @@ -22,7 +22,7 @@ embedded-hal-1 = { package = "embedded-hal", version = "1.0" } embedded-hal-async = { version = "1.0" } embedded-nal-async = "0.8.0" embedded-io-async = { version = "0.6.1" } -panic-probe = { version = "0.3", features = ["print-defmt"] } +panic-probe = { version = "1.0.0", features = ["print-defmt"] } heapless = { version = "0.8", default-features = false } critical-section = "1.1" static_cell = "2" diff --git a/examples/stm32h735/Cargo.toml b/examples/stm32h735/Cargo.toml index 4d31dedf1..2ce989e6f 100644 --- a/examples/stm32h735/Cargo.toml +++ b/examples/stm32h735/Cargo.toml @@ -12,12 +12,12 @@ embassy-executor = { version = "0.7.0", path = "../../embassy-executor", feature embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } -defmt = "0.3" -defmt-rtt = "0.4" +defmt = "1.0.1" +defmt-rtt = "1.0.0" cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } cortex-m-rt = "0.7.0" -panic-probe = { version = "0.3", features = ["print-defmt"] } +panic-probe = { version = "1.0.0", features = ["print-defmt"] } heapless = { version = "0.8", default-features = false } embedded-graphics = { version = "0.8.1" } tinybmp = { version = "0.5" } diff --git a/examples/stm32h742/Cargo.toml b/examples/stm32h742/Cargo.toml index 3f936193c..c3bf39e13 100644 --- a/examples/stm32h742/Cargo.toml +++ b/examples/stm32h742/Cargo.toml @@ -39,8 +39,8 @@ embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = [ ] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } -defmt = "0.3" -defmt-rtt = "0.4" +defmt = "1.0.1" +defmt-rtt = "1.0.0" cortex-m = { version = "0.7.6", features = [ "inline-asm", @@ -48,7 +48,7 @@ cortex-m = { version = "0.7.6", features = [ ] } cortex-m-rt = "0.7.0" embedded-hal = "0.2.6" -panic-probe = { version = "0.3", features = ["print-defmt"] } +panic-probe = { version = "1.0.0", features = ["print-defmt"] } heapless = { version = "0.8", default-features = false } nb = "1.0.0" critical-section = "1.1" diff --git a/examples/stm32h755cm4/Cargo.toml b/examples/stm32h755cm4/Cargo.toml index c186ef19f..c97ac447e 100644 --- a/examples/stm32h755cm4/Cargo.toml +++ b/examples/stm32h755cm4/Cargo.toml @@ -15,8 +15,8 @@ embassy-net = { version = "0.7.0", path = "../../embassy-net", features = ["defm embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } -defmt = "0.3" -defmt-rtt = "0.4" +defmt = "1.0.1" +defmt-rtt = "1.0.0" cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } cortex-m-rt = "0.7.0" @@ -25,7 +25,7 @@ embedded-hal-1 = { package = "embedded-hal", version = "1.0" } embedded-hal-async = { version = "1.0" } embedded-nal-async = "0.8.0" embedded-io-async = { version = "0.6.1" } -panic-probe = { version = "0.3", features = ["print-defmt"] } +panic-probe = { version = "1.0.0", features = ["print-defmt"] } heapless = { version = "0.8", default-features = false } critical-section = "1.1" micromath = "2.0.0" diff --git a/examples/stm32h755cm7/Cargo.toml b/examples/stm32h755cm7/Cargo.toml index d37978e44..3843d5d43 100644 --- a/examples/stm32h755cm7/Cargo.toml +++ b/examples/stm32h755cm7/Cargo.toml @@ -15,8 +15,8 @@ embassy-net = { version = "0.7.0", path = "../../embassy-net", features = ["defm embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } -defmt = "0.3" -defmt-rtt = "0.4" +defmt = "1.0.1" +defmt-rtt = "1.0.0" cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } cortex-m-rt = "0.7.0" @@ -25,7 +25,7 @@ embedded-hal-1 = { package = "embedded-hal", version = "1.0" } embedded-hal-async = { version = "1.0" } embedded-nal-async = "0.8.0" embedded-io-async = { version = "0.6.1" } -panic-probe = { version = "0.3", features = ["print-defmt"] } +panic-probe = { version = "1.0.0", features = ["print-defmt"] } heapless = { version = "0.8", default-features = false } critical-section = "1.1" micromath = "2.0.0" diff --git a/examples/stm32h7b0/Cargo.toml b/examples/stm32h7b0/Cargo.toml index dc8ecc684..e4f1080ac 100644 --- a/examples/stm32h7b0/Cargo.toml +++ b/examples/stm32h7b0/Cargo.toml @@ -14,8 +14,8 @@ embassy-net = { version = "0.7.0", path = "../../embassy-net", features = ["defm embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } -defmt = "0.3" -defmt-rtt = "0.4" +defmt = "1.0.1" +defmt-rtt = "1.0.0" cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } cortex-m-rt = "0.7.0" @@ -24,7 +24,7 @@ embedded-hal-1 = { package = "embedded-hal", version = "1.0" } embedded-hal-async = { version = "1.0" } embedded-nal-async = "0.8.0" embedded-io-async = { version = "0.6.1" } -panic-probe = { version = "0.3", features = ["print-defmt"] } +panic-probe = { version = "1.0.0", features = ["print-defmt"] } heapless = { version = "0.8", default-features = false } critical-section = "1.1" micromath = "2.0.0" diff --git a/examples/stm32h7rs/Cargo.toml b/examples/stm32h7rs/Cargo.toml index aee2703a1..58f8b1274 100644 --- a/examples/stm32h7rs/Cargo.toml +++ b/examples/stm32h7rs/Cargo.toml @@ -14,8 +14,8 @@ embassy-net = { version = "0.7.0", path = "../../embassy-net", features = ["defm embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } -defmt = "0.3" -defmt-rtt = "0.4" +defmt = "1.0.1" +defmt-rtt = "1.0.0" cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } cortex-m-rt = "0.7.0" @@ -24,7 +24,7 @@ embedded-hal-1 = { package = "embedded-hal", version = "1.0" } embedded-hal-async = { version = "1.0" } embedded-nal-async = "0.8.0" embedded-io-async = { version = "0.6.1" } -panic-probe = { version = "0.3", features = ["print-defmt"] } +panic-probe = { version = "1.0.0", features = ["print-defmt"] } heapless = { version = "0.8", default-features = false } critical-section = "1.1" micromath = "2.0.0" diff --git a/examples/stm32l0/Cargo.toml b/examples/stm32l0/Cargo.toml index 189b0e8d4..ce54ad9fb 100644 --- a/examples/stm32l0/Cargo.toml +++ b/examples/stm32l0/Cargo.toml @@ -11,8 +11,8 @@ embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["de embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } -defmt = "0.3" -defmt-rtt = "0.4" +defmt = "1.0.1" +defmt-rtt = "1.0.0" embedded-storage = "0.3.1" embedded-io = { version = "0.6.0" } @@ -20,7 +20,7 @@ embedded-io-async = { version = "0.6.1" } cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } cortex-m-rt = "0.7.0" -panic-probe = { version = "0.3", features = ["print-defmt"] } +panic-probe = { version = "1.0.0", features = ["print-defmt"] } heapless = { version = "0.8", default-features = false } embedded-hal = "0.2.6" static_cell = { version = "2" } diff --git a/examples/stm32l1/Cargo.toml b/examples/stm32l1/Cargo.toml index 6066b6dc7..a780f9290 100644 --- a/examples/stm32l1/Cargo.toml +++ b/examples/stm32l1/Cargo.toml @@ -12,13 +12,13 @@ embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [ embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } -defmt = "0.3" -defmt-rtt = "0.4" +defmt = "1.0.1" +defmt-rtt = "1.0.0" cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } cortex-m-rt = "0.7.0" embedded-hal = "0.2.6" -panic-probe = { version = "0.3", features = ["print-defmt"] } +panic-probe = { version = "1.0.0", features = ["print-defmt"] } heapless = { version = "0.8", default-features = false } embedded-storage = "0.3.1" diff --git a/examples/stm32l4/Cargo.toml b/examples/stm32l4/Cargo.toml index cceec86dd..5c4dce482 100644 --- a/examples/stm32l4/Cargo.toml +++ b/examples/stm32l4/Cargo.toml @@ -18,8 +18,8 @@ embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } embedded-io = { version = "0.6.0", features = ["defmt-03"] } -defmt = "0.3" -defmt-rtt = "0.4" +defmt = "1.0.1" +defmt-rtt = "1.0.0" cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } cortex-m-rt = "0.7.0" @@ -27,7 +27,7 @@ embedded-hal = "0.2.6" embedded-hal-1 = { package = "embedded-hal", version = "1.0" } embedded-hal-async = { version = "1.0" } embedded-hal-bus = { version = "0.1", features = ["async"] } -panic-probe = { version = "0.3", features = ["print-defmt"] } +panic-probe = { version = "1.0.0", features = ["print-defmt"] } heapless = { version = "0.8", default-features = false } chrono = { version = "^0.4", default-features = false } static_cell = "2" diff --git a/examples/stm32l432/Cargo.toml b/examples/stm32l432/Cargo.toml index e155b3e66..ac7e507de 100644 --- a/examples/stm32l432/Cargo.toml +++ b/examples/stm32l432/Cargo.toml @@ -10,8 +10,8 @@ embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [ embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = [ "defmt" ] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = [ "arch-cortex-m", "executor-thread", "defmt" ] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = [ "defmt", "defmt-timestamp-uptime", "tick-hz-32_768" ] } -defmt = "0.3" -defmt-rtt = "0.4" +defmt = "1.0.1" +defmt-rtt = "1.0.0" cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } cortex-m-rt = "0.7.0" @@ -19,7 +19,7 @@ embedded-hal = "0.2.6" embedded-hal-1 = { package = "embedded-hal", version = "1.0" } embedded-hal-async = { version = "1.0" } embedded-hal-bus = { version = "0.1", features = ["async"] } -panic-probe = { version = "0.3", features = ["print-defmt"] } +panic-probe = { version = "1.0.0", features = ["print-defmt"] } [profile.release] debug = 2 diff --git a/examples/stm32l5/Cargo.toml b/examples/stm32l5/Cargo.toml index 6962db7ea..138276b7f 100644 --- a/examples/stm32l5/Cargo.toml +++ b/examples/stm32l5/Cargo.toml @@ -15,9 +15,9 @@ embassy-net = { version = "0.7.0", path = "../../embassy-net", features = ["defm embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } usbd-hid = "0.8.1" -defmt = "0.3" -defmt-rtt = "0.4" -panic-probe = { version = "0.3", features = ["print-defmt"] } +defmt = "1.0.1" +defmt-rtt = "1.0.0" +panic-probe = { version = "1.0.0", features = ["print-defmt"] } cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } cortex-m-rt = "0.7.0" diff --git a/examples/stm32u0/Cargo.toml b/examples/stm32u0/Cargo.toml index efcb9bf4d..86cff2321 100644 --- a/examples/stm32u0/Cargo.toml +++ b/examples/stm32u0/Cargo.toml @@ -13,13 +13,13 @@ embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["de embassy-usb = { version = "0.4.0", path = "../../embassy-usb", default-features = false, features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } -defmt = "0.3" -defmt-rtt = "0.4" +defmt = "1.0.1" +defmt-rtt = "1.0.0" cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } cortex-m-rt = "0.7.0" embedded-hal = "0.2.6" -panic-probe = { version = "0.3", features = ["print-defmt"] } +panic-probe = { version = "1.0.0", features = ["print-defmt"] } heapless = { version = "0.8", default-features = false } micromath = "2.0.0" diff --git a/examples/stm32u5/Cargo.toml b/examples/stm32u5/Cargo.toml index 886c5cb2e..94f77ce2f 100644 --- a/examples/stm32u5/Cargo.toml +++ b/examples/stm32u5/Cargo.toml @@ -13,13 +13,13 @@ embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["de embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } -defmt = "0.3" -defmt-rtt = "0.4" +defmt = "1.0.1" +defmt-rtt = "1.0.0" cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } cortex-m-rt = "0.7.0" embedded-hal = "0.2.6" -panic-probe = { version = "0.3", features = ["print-defmt"] } +panic-probe = { version = "1.0.0", features = ["print-defmt"] } heapless = { version = "0.8", default-features = false } embedded-graphics = { version = "0.8.1" } tinybmp = { version = "0.6.0" } diff --git a/examples/stm32wb/Cargo.toml b/examples/stm32wb/Cargo.toml index 96f66f3af..a83871d4d 100644 --- a/examples/stm32wb/Cargo.toml +++ b/examples/stm32wb/Cargo.toml @@ -11,15 +11,15 @@ embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", fea embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } -embassy-net = { version = "0.7.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", ], optional=true } +embassy-net = { version = "0.7.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", ], optional = true } -defmt = "0.3" -defmt-rtt = "0.4" +defmt = "1.0.1" +defmt-rtt = "1.0.0" cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } cortex-m-rt = "0.7.0" -embedded-hal = "0.2.6" -panic-probe = { version = "0.3", features = ["print-defmt"] } +embedded-hal = "1.0.0" +panic-probe = { version = "1.0.0", features = ["print-defmt"] } heapless = { version = "0.8", default-features = false } static_cell = "2" diff --git a/examples/stm32wba/Cargo.toml b/examples/stm32wba/Cargo.toml index 60b09adb4..b87ca88bf 100644 --- a/examples/stm32wba/Cargo.toml +++ b/examples/stm32wba/Cargo.toml @@ -9,15 +9,15 @@ embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [ embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } -embassy-net = { version = "0.7.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", ], optional=true } +embassy-net = { version = "0.7.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", ], optional = true } -defmt = "0.3" -defmt-rtt = "0.4" +defmt = "1.0.1" +defmt-rtt = "1.0.0" cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } cortex-m-rt = "0.7.0" -embedded-hal = "0.2.6" -panic-probe = { version = "0.3", features = ["print-defmt"] } +embedded-hal = "1.0.0" +panic-probe = { version = "1.0.0", features = ["print-defmt"] } heapless = { version = "0.8", default-features = false } static_cell = "2" diff --git a/examples/stm32wl/Cargo.toml b/examples/stm32wl/Cargo.toml index 6b677914e..1b6a23bed 100644 --- a/examples/stm32wl/Cargo.toml +++ b/examples/stm32wl/Cargo.toml @@ -12,14 +12,14 @@ embassy-executor = { version = "0.7.0", path = "../../embassy-executor", feature embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-embedded-hal = { version = "0.3.0", path = "../../embassy-embedded-hal" } -defmt = "0.3" -defmt-rtt = "0.4" +defmt = "1.0.1" +defmt-rtt = "1.0.0" cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } cortex-m-rt = "0.7.0" embedded-hal = "0.2.6" embedded-storage = "0.3.1" -panic-probe = { version = "0.3", features = ["print-defmt"] } +panic-probe = { version = "1.0.0", features = ["print-defmt"] } heapless = { version = "0.8", default-features = false } chrono = { version = "^0.4", default-features = false } diff --git a/rustfmt.toml b/rustfmt.toml index 592ad27ff..2561562fd 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -1,4 +1,4 @@ group_imports = "StdExternalCrate" imports_granularity = "Module" edition = "2021" -max_width=120 +max_width = 120 diff --git a/tests/mspm0/Cargo.toml b/tests/mspm0/Cargo.toml index 0566807d7..b77747e5d 100644 --- a/tests/mspm0/Cargo.toml +++ b/tests/mspm0/Cargo.toml @@ -23,7 +23,7 @@ cortex-m = { version = "0.7.6", features = [ "inline-asm", "critical-section-sin cortex-m-rt = "0.7.0" embedded-hal = { package = "embedded-hal", version = "1.0" } embedded-hal-async = { version = "1.0" } -panic-probe = { version = "0.3.0", features = ["print-defmt"] } +panic-probe = { version = "1.0.0", features = ["print-defmt"] } static_cell = "2" portable-atomic = { version = "1.5", features = ["critical-section"] } diff --git a/tests/nrf/Cargo.toml b/tests/nrf/Cargo.toml index 410d62bdd..32087940e 100644 --- a/tests/nrf/Cargo.toml +++ b/tests/nrf/Cargo.toml @@ -21,12 +21,12 @@ embedded-hal-bus = { version = "0.1", features = ["async"] } static_cell = "2" perf-client = { path = "../perf-client" } -defmt = "0.3" -defmt-rtt = "0.4" +defmt = "1.0.1" +defmt-rtt = "1.0.0" cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } cortex-m-rt = "0.7.0" -panic-probe = { version = "0.3", features = ["print-defmt"] } +panic-probe = { version = "1.0.0", features = ["print-defmt"] } portable-atomic = { version = "1.6.0" } [features] diff --git a/tests/perf-client/Cargo.toml b/tests/perf-client/Cargo.toml index 9620972c3..e31d6361b 100644 --- a/tests/perf-client/Cargo.toml +++ b/tests/perf-client/Cargo.toml @@ -7,4 +7,4 @@ edition = "2021" embassy-net = { version = "0.7.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", ] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } -defmt = "0.3" +defmt = "1.0.1" diff --git a/tests/rp/Cargo.toml b/tests/rp/Cargo.toml index 46dc820ab..2c2ed73cc 100644 --- a/tests/rp/Cargo.toml +++ b/tests/rp/Cargo.toml @@ -24,8 +24,8 @@ cyw43 = { path = "../../cyw43", features = ["defmt", "firmware-logs"] } cyw43-pio = { path = "../../cyw43-pio", features = ["defmt"] } perf-client = { path = "../perf-client" } -defmt = "0.3" -defmt-rtt = "0.4" +defmt = "1.0.1" +defmt-rtt = "1.0.0" cortex-m = { version = "0.7.6" } cortex-m-rt = "0.7.0" @@ -33,7 +33,7 @@ embedded-hal = "0.2.6" embedded-hal-1 = { package = "embedded-hal", version = "1.0" } embedded-hal-async = { version = "1.0" } embedded-hal-bus = { version = "0.1", features = ["async"] } -panic-probe = { version = "0.3.0", features = ["print-defmt"] } +panic-probe = { version = "1.0.0", features = ["print-defmt"] } embedded-io-async = { version = "0.6.1" } embedded-storage = { version = "0.3" } static_cell = "2" diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml index b230e619e..6036a5a97 100644 --- a/tests/stm32/Cargo.toml +++ b/tests/stm32/Cargo.toml @@ -70,8 +70,8 @@ embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", opt embassy-net = { version = "0.7.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "dhcpv4", "medium-ethernet"] } perf-client = { path = "../perf-client" } -defmt = "0.3" -defmt-rtt = "0.4" +defmt = "1.0.1" +defmt-rtt = "1.0.0" cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } cortex-m-rt = "0.7.0" @@ -80,7 +80,7 @@ embedded-hal-1 = { package = "embedded-hal", version = "1.0" } embedded-hal-async = { version = "1.0" } embedded-can = { version = "0.4" } micromath = "2.0.0" -panic-probe = { version = "0.3.0", features = ["print-defmt"] } +panic-probe = { version = "1.0.0", features = ["print-defmt"] } rand_core = { version = "0.9.1", default-features = false } rand_chacha = { version = "0.9.0", default-features = false } static_cell = "2" From e0c5e93e78d48a2077578ac01d532066a638115a Mon Sep 17 00:00:00 2001 From: Tobias Naumann Date: Sun, 18 May 2025 22:09:00 +0200 Subject: [PATCH 1142/1217] Count all users of a given CAN instance and cleanup pins and RCC when the last user gets dropped --- embassy-stm32/src/can/fdcan.rs | 71 +++++++++++++++++++++++++++++----- 1 file changed, 62 insertions(+), 9 deletions(-) diff --git a/embassy-stm32/src/can/fdcan.rs b/embassy-stm32/src/can/fdcan.rs index 5467a40f1..a7815f79b 100644 --- a/embassy-stm32/src/can/fdcan.rs +++ b/embassy-stm32/src/can/fdcan.rs @@ -10,7 +10,7 @@ use embassy_sync::channel::Channel; use embassy_sync::waitqueue::AtomicWaker; use crate::can::fd::peripheral::Registers; -use crate::gpio::{AfType, OutputType, Pull, Speed}; +use crate::gpio::{AfType, OutputType, Pull, SealedPin as _, Speed}; use crate::interrupt::typelevel::Interrupt; use crate::rcc::{self, RccPeripheral}; use crate::{interrupt, peripherals, Peri}; @@ -187,13 +187,17 @@ impl<'d> CanConfigurator<'d> { rcc::enable_and_reset::(); + let info = T::info(); + let state = unsafe { T::mut_state() }; + state.tx_pin_port = Some(tx.pin_port()); + state.rx_pin_port = Some(rx.pin_port()); + (info.internal_operation)(InternalOperation::NotifySenderCreated); + (info.internal_operation)(InternalOperation::NotifyReceiverCreated); + let mut config = crate::can::fd::config::FdCanConfig::default(); config.timestamp_source = TimestampSource::Prescaler(TimestampPrescaler::_1); T::registers().into_config_mode(config); - rx.set_as_af(rx.af_num(), AfType::input(Pull::None)); - tx.set_as_af(tx.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh)); - unsafe { T::IT0Interrupt::unpend(); // Not unsafe T::IT0Interrupt::enable(); @@ -204,8 +208,8 @@ impl<'d> CanConfigurator<'d> { Self { _phantom: PhantomData, config, - info: T::info(), - state: T::state(), + info, + state, properties: Properties::new(T::info()), periph_clock: T::frequency(), } @@ -265,6 +269,8 @@ impl<'d> CanConfigurator<'d> { } }); self.info.regs.into_mode(self.config, mode); + (self.info.internal_operation)(InternalOperation::NotifySenderCreated); + (self.info.internal_operation)(InternalOperation::NotifyReceiverCreated); Can { _phantom: PhantomData, config: self.config, @@ -291,6 +297,13 @@ impl<'d> CanConfigurator<'d> { } } +impl<'d> Drop for CanConfigurator<'d> { + fn drop(&mut self) { + (self.info.internal_operation)(InternalOperation::NotifySenderDestroyed); + (self.info.internal_operation)(InternalOperation::NotifyReceiverDestroyed); + } +} + /// FDCAN Instance pub struct Can<'d> { _phantom: PhantomData<&'d ()>, @@ -353,6 +366,8 @@ impl<'d> Can<'d> { /// Split instance into separate portions: Tx(write), Rx(read), common properties pub fn split(self) -> (CanTx<'d>, CanRx<'d>, Properties) { + (self.info.internal_operation)(InternalOperation::NotifySenderCreated); + (self.info.internal_operation)(InternalOperation::NotifyReceiverCreated); ( CanTx { _phantom: PhantomData, @@ -367,11 +382,15 @@ impl<'d> Can<'d> { state: self.state, _mode: self._mode, }, - self.properties, + Properties { + info: self.properties.info, + }, ) } /// Join split rx and tx portions back together pub fn join(tx: CanTx<'d>, rx: CanRx<'d>) -> Self { + (tx.info.internal_operation)(InternalOperation::NotifySenderCreated); + (tx.info.internal_operation)(InternalOperation::NotifyReceiverCreated); Can { _phantom: PhantomData, config: tx.config, @@ -401,6 +420,13 @@ impl<'d> Can<'d> { } } +impl<'d> Drop for Can<'d> { + fn drop(&mut self) { + (self.info.internal_operation)(InternalOperation::NotifySenderDestroyed); + (self.info.internal_operation)(InternalOperation::NotifyReceiverDestroyed); + } +} + /// User supplied buffer for RX Buffering pub type RxBuf = Channel, BUF_SIZE>; @@ -426,6 +452,8 @@ impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCan<'d, tx_buf: &'static TxBuf, rx_buf: &'static RxBuf, ) -> Self { + (info.internal_operation)(InternalOperation::NotifySenderCreated); + (info.internal_operation)(InternalOperation::NotifyReceiverCreated); BufferedCan { _phantom: PhantomData, info, @@ -532,6 +560,8 @@ impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCanFd<' tx_buf: &'static TxFdBuf, rx_buf: &'static RxFdBuf, ) -> Self { + (info.internal_operation)(InternalOperation::NotifySenderCreated); + (info.internal_operation)(InternalOperation::NotifyReceiverCreated); BufferedCanFd { _phantom: PhantomData, info, @@ -627,6 +657,12 @@ impl<'d> CanRx<'d> { } } +impl<'d> Drop for CanRx<'d> { + fn drop(&mut self) { + (self.info.internal_operation)(InternalOperation::NotifyReceiverDestroyed); + } +} + /// FDCAN Tx only Instance pub struct CanTx<'d> { _phantom: PhantomData<&'d ()>, @@ -654,6 +690,12 @@ impl<'c, 'd> CanTx<'d> { } } +impl<'d> Drop for CanTx<'d> { + fn drop(&mut self) { + (self.info.internal_operation)(InternalOperation::NotifySenderDestroyed); + } +} + enum RxMode { NonBuffered(AtomicWaker), ClassicBuffered(super::common::ClassicBufferedRxInner), @@ -898,6 +940,8 @@ struct State { pub ns_per_timer_tick: u64, receiver_instance_count: usize, sender_instance_count: usize, + tx_pin_port: Option, + rx_pin_port: Option, pub err_waker: AtomicWaker, } @@ -909,8 +953,10 @@ impl State { tx_mode: TxMode::NonBuffered(AtomicWaker::new()), ns_per_timer_tick: 0, err_waker: AtomicWaker::new(), - receiver_instance_count: 1, - sender_instance_count: 1, + receiver_instance_count: 0, + sender_instance_count: 0, + tx_pin_port: None, + rx_pin_port: None, } } } @@ -998,6 +1044,13 @@ macro_rules! impl_fdcan { } } } + if mut_state.sender_instance_count == 0 && mut_state.receiver_instance_count == 0 { + let tx_pin = crate::gpio::AnyPin::steal(mut_state.tx_pin_port.unwrap()); + tx_pin.set_as_disconnected(); + let rx_pin = crate::gpio::AnyPin::steal(mut_state.rx_pin_port.unwrap()); + rx_pin.set_as_disconnected(); + rcc::disable::(); + } } }); } From ef32187ed7349f3883d997b6f1590e11dbc8db81 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 19 May 2025 18:15:05 +0200 Subject: [PATCH 1143/1217] mspm0: fix build for int groups. --- ci.sh | 7 +++ embassy-mspm0/build.rs | 4 ++ embassy-mspm0/src/int_group/g110x.rs | 47 +++++++++++++++++ embassy-mspm0/src/int_group/g151x.rs | 52 +++++++++++++++++++ embassy-mspm0/src/int_group/g310x.rs | 48 +++++++++++++++++ embassy-mspm0/src/int_group/l11xx.rs | 25 +++++++++ embassy-mspm0/src/int_group/l12xx.rs | 49 +++++++++++++++++ .../src/int_group/{l130x.rs => l13xx.rs} | 0 embassy-mspm0/src/lib.rs | 8 ++- 9 files changed, 239 insertions(+), 1 deletion(-) create mode 100644 embassy-mspm0/src/int_group/g110x.rs create mode 100644 embassy-mspm0/src/int_group/g151x.rs create mode 100644 embassy-mspm0/src/int_group/g310x.rs create mode 100644 embassy-mspm0/src/int_group/l11xx.rs create mode 100644 embassy-mspm0/src/int_group/l12xx.rs rename embassy-mspm0/src/int_group/{l130x.rs => l13xx.rs} (100%) diff --git a/ci.sh b/ci.sh index 2f4164998..2be84ef6b 100755 --- a/ci.sh +++ b/ci.sh @@ -179,6 +179,13 @@ cargo batch \ --- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0g3519pz,defmt,time-driver-any \ --- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0l1306rhb,defmt,time-driver-any \ --- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0l2228pn,defmt,time-driver-any \ + --- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0l1345dgs28,defmt,time-driver-any \ + --- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0l1106dgs28,defmt,time-driver-any \ + --- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0l1228pm,defmt,time-driver-any \ + --- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0g1107ycj,defmt,time-driver-any \ + --- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0g3105rhb,defmt,time-driver-any \ + --- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0g1505pt,defmt,time-driver-any \ + --- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0g1519rhb,defmt,time-driver-any \ --- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features ''\ --- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'log' \ --- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'defmt' \ diff --git a/embassy-mspm0/build.rs b/embassy-mspm0/build.rs index 409ce0621..094769992 100644 --- a/embassy-mspm0/build.rs +++ b/embassy-mspm0/build.rs @@ -84,6 +84,10 @@ fn get_chip_cfgs(chip_name: &str) -> Vec { cfgs.push("mspm0g150x".to_string()); } + if chip_name.starts_with("mspm0g151") { + cfgs.push("mspm0g151x".to_string()); + } + if chip_name.starts_with("mspm0g310") { cfgs.push("mspm0g310x".to_string()); } diff --git a/embassy-mspm0/src/int_group/g110x.rs b/embassy-mspm0/src/int_group/g110x.rs new file mode 100644 index 000000000..9f8ac4d7b --- /dev/null +++ b/embassy-mspm0/src/int_group/g110x.rs @@ -0,0 +1,47 @@ +use crate::pac; +use crate::pac::interrupt; + +#[cfg(feature = "rt")] +#[interrupt] +fn GROUP0() { + use mspm0_metapac::Group0; + + let group = pac::CPUSS.int_group(0); + + // Must subtract by 1 since NO_INTR is value 0 + let iidx = group.iidx().read().stat().to_bits() - 1; + + let Ok(group) = pac::Group0::try_from(iidx as u8) else { + debug!("Invalid IIDX for group 0: {}", iidx); + return; + }; + + match group { + Group0::WWDT0 => todo!("implement WWDT0"), + Group0::WWDT1 => todo!("implement WWDT1"), + Group0::DEBUGSS => todo!("implement DEBUGSS"), + Group0::FLASHCTL => todo!("implement FLASHCTL"), + Group0::SYSCTL => todo!("implement SYSCTL"), + } +} + +#[cfg(feature = "rt")] +#[interrupt] +fn GROUP1() { + use mspm0_metapac::Group1; + + let group = pac::CPUSS.int_group(1); + + // Must subtract by 1 since NO_INTR is value 0 + let iidx = group.iidx().read().stat().to_bits() - 1; + + let Ok(group) = pac::Group1::try_from(iidx as u8) else { + debug!("Invalid IIDX for group 1: {}", iidx); + return; + }; + + match group { + Group1::GPIOA => crate::gpio::gpioa_interrupt(), + Group1::GPIOB => crate::gpio::gpiob_interrupt(), + } +} diff --git a/embassy-mspm0/src/int_group/g151x.rs b/embassy-mspm0/src/int_group/g151x.rs new file mode 100644 index 000000000..e785018a7 --- /dev/null +++ b/embassy-mspm0/src/int_group/g151x.rs @@ -0,0 +1,52 @@ +use crate::pac; +use crate::pac::interrupt; + +#[cfg(feature = "rt")] +#[interrupt] +fn GROUP0() { + use mspm0_metapac::Group0; + + let group = pac::CPUSS.int_group(0); + + // Must subtract by 1 since NO_INTR is value 0 + let iidx = group.iidx().read().stat().to_bits() - 1; + + let Ok(group) = pac::Group0::try_from(iidx as u8) else { + debug!("Invalid IIDX for group 0: {}", iidx); + return; + }; + + match group { + Group0::WWDT0 => todo!("implement WWDT0"), + Group0::WWDT1 => todo!("implement WWDT1"), + Group0::DEBUGSS => todo!("implement DEBUGSS"), + Group0::FLASHCTL => todo!("implement FLASHCTL"), + Group0::SYSCTL => todo!("implement SYSCTL"), + } +} + +#[cfg(feature = "rt")] +#[interrupt] +fn GROUP1() { + use mspm0_metapac::Group1; + + let group = pac::CPUSS.int_group(1); + + // Must subtract by 1 since NO_INTR is value 0 + let iidx = group.iidx().read().stat().to_bits() - 1; + + let Ok(group) = pac::Group1::try_from(iidx as u8) else { + debug!("Invalid IIDX for group 1: {}", iidx); + return; + }; + + match group { + Group1::GPIOA => crate::gpio::gpioa_interrupt(), + Group1::GPIOB => crate::gpio::gpiob_interrupt(), + Group1::COMP0 => todo!("implement COMP0"), + Group1::COMP1 => todo!("implement COMP1"), + Group1::COMP2 => todo!("implement COMP2"), + Group1::TRNG => todo!("implement TRNG"), + Group1::GPIOC => crate::gpio::gpioc_interrupt(), + } +} diff --git a/embassy-mspm0/src/int_group/g310x.rs b/embassy-mspm0/src/int_group/g310x.rs new file mode 100644 index 000000000..ad508d3a2 --- /dev/null +++ b/embassy-mspm0/src/int_group/g310x.rs @@ -0,0 +1,48 @@ +use crate::pac; +use crate::pac::interrupt; + +#[cfg(feature = "rt")] +#[interrupt] +fn GROUP0() { + use mspm0_metapac::Group0; + + let group = pac::CPUSS.int_group(0); + + // Must subtract by 1 since NO_INTR is value 0 + let iidx = group.iidx().read().stat().to_bits() - 1; + + let Ok(group) = pac::Group0::try_from(iidx as u8) else { + debug!("Invalid IIDX for group 0: {}", iidx); + return; + }; + + match group { + Group0::WWDT0 => todo!("implement WWDT0"), + Group0::WWDT1 => todo!("implement WWDT1"), + Group0::DEBUGSS => todo!("implement DEBUGSS"), + Group0::FLASHCTL => todo!("implement FLASHCTL"), + Group0::SYSCTL => todo!("implement SYSCTL"), + } +} + +#[cfg(feature = "rt")] +#[interrupt] +fn GROUP1() { + use mspm0_metapac::Group1; + + let group = pac::CPUSS.int_group(1); + + // Must subtract by 1 since NO_INTR is value 0 + let iidx = group.iidx().read().stat().to_bits() - 1; + + let Ok(group) = pac::Group1::try_from(iidx as u8) else { + debug!("Invalid IIDX for group 1: {}", iidx); + return; + }; + + match group { + Group1::GPIOA => crate::gpio::gpioa_interrupt(), + Group1::GPIOB => crate::gpio::gpiob_interrupt(), + Group1::TRNG => todo!("implement TRNG"), + } +} diff --git a/embassy-mspm0/src/int_group/l11xx.rs b/embassy-mspm0/src/int_group/l11xx.rs new file mode 100644 index 000000000..426a80c13 --- /dev/null +++ b/embassy-mspm0/src/int_group/l11xx.rs @@ -0,0 +1,25 @@ +use crate::pac; +use crate::pac::interrupt; + +#[cfg(feature = "rt")] +#[interrupt] +fn GROUP0() { + use mspm0_metapac::Group0; + + let group = pac::CPUSS.int_group(0); + + // Must subtract by 1 since NO_INTR is value 0 + let iidx = group.iidx().read().stat().to_bits() - 1; + + let Ok(group) = pac::Group0::try_from(iidx as u8) else { + debug!("Invalid IIDX for group 0: {}", iidx); + return; + }; + + match group { + Group0::WWDT0 => todo!("implement WWDT0"), + Group0::DEBUGSS => todo!("implement DEBUGSS"), + Group0::FLASHCTL => todo!("implement FLASHCTL"), + Group0::SYSCTL => todo!("implement SYSCTL"), + } +} diff --git a/embassy-mspm0/src/int_group/l12xx.rs b/embassy-mspm0/src/int_group/l12xx.rs new file mode 100644 index 000000000..833771eea --- /dev/null +++ b/embassy-mspm0/src/int_group/l12xx.rs @@ -0,0 +1,49 @@ +use crate::pac; +use crate::pac::interrupt; + +#[cfg(feature = "rt")] +#[interrupt] +fn GROUP0() { + use mspm0_metapac::Group0; + + let group = pac::CPUSS.int_group(0); + + // Must subtract by 1 since NO_INTR is value 0 + let iidx = group.iidx().read().stat().to_bits() - 1; + + let Ok(group) = pac::Group0::try_from(iidx as u8) else { + debug!("Invalid IIDX for group 0: {}", iidx); + return; + }; + + match group { + Group0::WWDT0 => todo!("implement WWDT0"), + Group0::DEBUGSS => todo!("implement DEBUGSS"), + Group0::FLASHCTL => todo!("implement FLASHCTL"), + Group0::SYSCTL => todo!("implement SYSCTL"), + } +} + +#[cfg(feature = "rt")] +#[interrupt] +fn GROUP1() { + use mspm0_metapac::Group1; + + let group = pac::CPUSS.int_group(1); + + // Must subtract by 1 since NO_INTR is value 0 + let iidx = group.iidx().read().stat().to_bits() - 1; + + let Ok(group) = pac::Group1::try_from(iidx as u8) else { + debug!("Invalid IIDX for group 1: {}", iidx); + return; + }; + + match group { + Group1::GPIOA => crate::gpio::gpioa_interrupt(), + Group1::GPIOB => todo!("implement GPIOB"), + Group1::COMP0 => todo!("implement COMP0"), + Group1::TRNG => todo!("implement TRNG"), + Group1::GPIOC => todo!("implement GPIOC"), + } +} diff --git a/embassy-mspm0/src/int_group/l130x.rs b/embassy-mspm0/src/int_group/l13xx.rs similarity index 100% rename from embassy-mspm0/src/int_group/l130x.rs rename to embassy-mspm0/src/int_group/l13xx.rs diff --git a/embassy-mspm0/src/lib.rs b/embassy-mspm0/src/lib.rs index df2d83cc0..f129e221b 100644 --- a/embassy-mspm0/src/lib.rs +++ b/embassy-mspm0/src/lib.rs @@ -41,9 +41,15 @@ mod time_driver; // Interrupt group handlers. #[cfg_attr(mspm0c110x, path = "int_group/c110x.rs")] +#[cfg_attr(mspm0g110x, path = "int_group/g110x.rs")] +#[cfg_attr(mspm0g150x, path = "int_group/g150x.rs")] #[cfg_attr(mspm0g350x, path = "int_group/g350x.rs")] +#[cfg_attr(mspm0g151x, path = "int_group/g151x.rs")] #[cfg_attr(mspm0g351x, path = "int_group/g351x.rs")] -#[cfg_attr(mspm0l130x, path = "int_group/l130x.rs")] +#[cfg_attr(mspm0g310x, path = "int_group/g310x.rs")] +#[cfg_attr(mspm0l110x, path = "int_group/l11xx.rs")] +#[cfg_attr(mspm0l122x, path = "int_group/l12xx.rs")] +#[cfg_attr(any(mspm0l130x, mspm0l134x), path = "int_group/l13xx.rs")] #[cfg_attr(mspm0l222x, path = "int_group/l222x.rs")] mod int_group; From ab5e0150d46b8b97d5ffe430b3e7a1caaae0438c Mon Sep 17 00:00:00 2001 From: okhsunrog Date: Tue, 20 May 2025 18:48:44 +0300 Subject: [PATCH 1144/1217] update stm32-metapac --- embassy-stm32/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 413c92cce..2ab4f9960 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -81,7 +81,7 @@ futures-util = { version = "0.3.30", default-features = false } sdio-host = "0.9.0" critical-section = "1.1" #stm32-metapac = { version = "16" } -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-7251801e3273011ce28a89e8f2e45eec2e419e26" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-27ef8fba3483187e852eaf3796d827259f61e8ec" } vcell = "0.1.3" nb = "1.0.0" @@ -110,7 +110,7 @@ proc-macro2 = "1.0.36" quote = "1.0.15" #stm32-metapac = { version = "16", default-features = false, features = ["metadata"]} -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-7251801e3273011ce28a89e8f2e45eec2e419e26", default-features = false, features = ["metadata"] } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-27ef8fba3483187e852eaf3796d827259f61e8ec", default-features = false, features = ["metadata"] } [features] default = ["rt"] From 44dce8206124359459facbb373887ca51c33c60b Mon Sep 17 00:00:00 2001 From: i509VCB Date: Tue, 20 May 2025 12:27:28 -0500 Subject: [PATCH 1145/1217] mspm0: add gpio handlers to l122x --- embassy-mspm0/src/int_group/l12xx.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-mspm0/src/int_group/l12xx.rs b/embassy-mspm0/src/int_group/l12xx.rs index 833771eea..eeb2ce70d 100644 --- a/embassy-mspm0/src/int_group/l12xx.rs +++ b/embassy-mspm0/src/int_group/l12xx.rs @@ -41,9 +41,9 @@ fn GROUP1() { match group { Group1::GPIOA => crate::gpio::gpioa_interrupt(), - Group1::GPIOB => todo!("implement GPIOB"), + Group1::GPIOB => crate::gpio::gpiob_interrupt(), Group1::COMP0 => todo!("implement COMP0"), Group1::TRNG => todo!("implement TRNG"), - Group1::GPIOC => todo!("implement GPIOC"), + Group1::GPIOC => crate::gpio::gpioc_interrupt(), } } From 156bf00009495bbdffefd67f920919b4cd35c418 Mon Sep 17 00:00:00 2001 From: i509VCB Date: Tue, 20 May 2025 12:35:17 -0500 Subject: [PATCH 1146/1217] mspm0: L110x has no group1 --- embassy-mspm0/src/gpio.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-mspm0/src/gpio.rs b/embassy-mspm0/src/gpio.rs index 3c824b0e6..19a6230b6 100644 --- a/embassy-mspm0/src/gpio.rs +++ b/embassy-mspm0/src/gpio.rs @@ -10,7 +10,7 @@ use embassy_sync::waitqueue::AtomicWaker; use crate::pac::gpio::vals::*; use crate::pac::gpio::{self}; -#[cfg(all(feature = "rt", mspm0c110x))] +#[cfg(all(feature = "rt", any(mspm0c110x, mspm0l110x)))] use crate::pac::interrupt; use crate::pac::{self}; @@ -1120,7 +1120,7 @@ impl Iterator for BitIter { } // C110x has a dedicated interrupt just for GPIOA, as it does not have a GROUP1 interrupt. -#[cfg(all(feature = "rt", mspm0c110x))] +#[cfg(all(feature = "rt", any(mspm0c110x, mspm0l110x)))] #[interrupt] fn GPIOA() { gpioa_interrupt(); From e93ae32546b754ee9b54405aca81d936087ea8c7 Mon Sep 17 00:00:00 2001 From: okhsunrog Date: Tue, 20 May 2025 21:31:32 +0300 Subject: [PATCH 1147/1217] adding eeprom constants to _generated.rs --- embassy-stm32/build.rs | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index b00b6a7ac..b91934af3 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -1922,6 +1922,47 @@ fn main() { pub const WRITE_SIZE: usize = #write_size; )); + // ======== + // Generate EEPROM constants + + let eeprom_memory_regions: Vec<&MemoryRegion> = + memory.iter().filter(|x| x.kind == MemoryRegionKind::Eeprom).collect(); + + if !eeprom_memory_regions.is_empty() { + cfgs.enable("eeprom"); + cfgs.declare("eeprom"); + + let mut sorted_eeprom_regions = eeprom_memory_regions.clone(); + sorted_eeprom_regions.sort_by_key(|r| r.address); + + let first_eeprom_address = sorted_eeprom_regions[0].address; + let mut total_eeprom_size = 0; + let mut current_expected_address = first_eeprom_address; + + for region in sorted_eeprom_regions.iter() { + if region.address != current_expected_address { + // For STM32L0 and STM32L1, EEPROM regions (if multiple) are expected to be contiguous. + // If they are not, this indicates an issue with the chip metadata or an unsupported configuration. + panic!( + "EEPROM regions for chip {} are not contiguous, which is unexpected for L0/L1 series. \ + First region: '{}' at {:#X}. Found next non-contiguous region: '{}' at {:#X}. \ + Please verify chip metadata. Embassy currently assumes contiguous EEPROM for these series.", + chip_name, sorted_eeprom_regions[0].name, first_eeprom_address, region.name, region.address + ); + } + total_eeprom_size += region.size; + current_expected_address += region.size; + } + + let eeprom_base_usize = first_eeprom_address as usize; + let total_eeprom_size_usize = total_eeprom_size as usize; + + g.extend(quote! { + pub const EEPROM_BASE: usize = #eeprom_base_usize; + pub const EEPROM_SIZE: usize = #total_eeprom_size_usize; + }); + } + // ======== // Generate macro-tables From c9f0afa494636533c838473bcb5d27ff8f011fb7 Mon Sep 17 00:00:00 2001 From: okhsunrog Date: Wed, 21 May 2025 00:37:46 +0300 Subject: [PATCH 1148/1217] import and re-export EEPROM_BASE and EEPROM_SIZE in flash module --- embassy-stm32/src/flash/mod.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/embassy-stm32/src/flash/mod.rs b/embassy-stm32/src/flash/mod.rs index adc45db9c..ab956664b 100644 --- a/embassy-stm32/src/flash/mod.rs +++ b/embassy-stm32/src/flash/mod.rs @@ -13,6 +13,8 @@ pub use common::*; pub use crate::_generated::flash_regions::*; pub use crate::_generated::{FLASH_BASE, FLASH_SIZE, MAX_ERASE_SIZE, WRITE_SIZE}; +#[cfg(eeprom)] +pub use crate::_generated::{EEPROM_BASE, EEPROM_SIZE}; /// Get all flash regions. pub fn get_flash_regions() -> &'static [&'static FlashRegion] { From d335e309012020b5eab6f0d04ee63053365140ea Mon Sep 17 00:00:00 2001 From: okhsunrog Date: Wed, 21 May 2025 00:44:24 +0300 Subject: [PATCH 1149/1217] only support eeprom for l0 and l1 --- embassy-stm32/src/flash/mod.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/flash/mod.rs b/embassy-stm32/src/flash/mod.rs index ab956664b..26f357370 100644 --- a/embassy-stm32/src/flash/mod.rs +++ b/embassy-stm32/src/flash/mod.rs @@ -12,9 +12,9 @@ pub use asynch::InterruptHandler; pub use common::*; pub use crate::_generated::flash_regions::*; -pub use crate::_generated::{FLASH_BASE, FLASH_SIZE, MAX_ERASE_SIZE, WRITE_SIZE}; #[cfg(eeprom)] pub use crate::_generated::{EEPROM_BASE, EEPROM_SIZE}; +pub use crate::_generated::{FLASH_BASE, FLASH_SIZE, MAX_ERASE_SIZE, WRITE_SIZE}; /// Get all flash regions. pub fn get_flash_regions() -> &'static [&'static FlashRegion] { @@ -85,7 +85,8 @@ pub enum FlashBank { /// OTP region, Otp, } - +#[cfg(all(eeprom, not(any(flash_l0, flash_l1))))] +compile_error!("The 'eeprom' cfg is enabled for a non-L0/L1 chip family. This is an unsupported configuration."); #[cfg_attr(any(flash_l0, flash_l1, flash_l4, flash_l5, flash_wl, flash_wb), path = "l.rs")] #[cfg_attr(flash_f0, path = "f0.rs")] #[cfg_attr(any(flash_f1, flash_f3), path = "f1f3.rs")] From d23c71ea290828cbdf12b0ce64e9cd420e9038ab Mon Sep 17 00:00:00 2001 From: i509VCB Date: Tue, 20 May 2025 17:17:03 -0500 Subject: [PATCH 1150/1217] mspm0: generate interrupt group handlers --- embassy-mspm0/Cargo.toml | 4 +- embassy-mspm0/build.rs | 88 +++++++++++++++++++++++++++- embassy-mspm0/src/gpio.rs | 24 ++++++-- embassy-mspm0/src/int_group/c110x.rs | 25 -------- embassy-mspm0/src/int_group/g110x.rs | 47 --------------- embassy-mspm0/src/int_group/g150x.rs | 51 ---------------- embassy-mspm0/src/int_group/g151x.rs | 52 ---------------- embassy-mspm0/src/int_group/g310x.rs | 48 --------------- embassy-mspm0/src/int_group/g350x.rs | 51 ---------------- embassy-mspm0/src/int_group/g351x.rs | 52 ---------------- embassy-mspm0/src/int_group/l11xx.rs | 25 -------- embassy-mspm0/src/int_group/l12xx.rs | 49 ---------------- embassy-mspm0/src/int_group/l13xx.rs | 46 --------------- embassy-mspm0/src/int_group/l222x.rs | 49 ---------------- embassy-mspm0/src/lib.rs | 14 ----- examples/mspm0c1104/build.rs | 2 + examples/mspm0g3507/build.rs | 2 + examples/mspm0g3519/build.rs | 2 + examples/mspm0l1306/build.rs | 2 + examples/mspm0l2228/build.rs | 2 + 20 files changed, 117 insertions(+), 518 deletions(-) delete mode 100644 embassy-mspm0/src/int_group/c110x.rs delete mode 100644 embassy-mspm0/src/int_group/g110x.rs delete mode 100644 embassy-mspm0/src/int_group/g150x.rs delete mode 100644 embassy-mspm0/src/int_group/g151x.rs delete mode 100644 embassy-mspm0/src/int_group/g310x.rs delete mode 100644 embassy-mspm0/src/int_group/g350x.rs delete mode 100644 embassy-mspm0/src/int_group/g351x.rs delete mode 100644 embassy-mspm0/src/int_group/l11xx.rs delete mode 100644 embassy-mspm0/src/int_group/l12xx.rs delete mode 100644 embassy-mspm0/src/int_group/l13xx.rs delete mode 100644 embassy-mspm0/src/int_group/l222x.rs diff --git a/embassy-mspm0/Cargo.toml b/embassy-mspm0/Cargo.toml index 1b189e05a..6f767a3c0 100644 --- a/embassy-mspm0/Cargo.toml +++ b/embassy-mspm0/Cargo.toml @@ -46,14 +46,14 @@ cortex-m = "0.7.6" critical-section = "1.2.0" # mspm0-metapac = { version = "" } -mspm0-metapac = { git = "https://github.com/mspm0-rs/mspm0-data-generated/", tag = "mspm0-data-66a55c7bf38a2201ff48c299843e741f2d537f0b" } +mspm0-metapac = { git = "https://github.com/mspm0-rs/mspm0-data-generated/", tag = "mspm0-data-26a6f681eda4ef120e8cb614a1631727c848590f" } [build-dependencies] proc-macro2 = "1.0.94" quote = "1.0.40" # mspm0-metapac = { version = "", default-features = false, features = ["metadata"] } -mspm0-metapac = { git = "https://github.com/mspm0-rs/mspm0-data-generated/", tag = "mspm0-data-66a55c7bf38a2201ff48c299843e741f2d537f0b", default-features = false, features = ["metadata"] } +mspm0-metapac = { git = "https://github.com/mspm0-rs/mspm0-data-generated/", tag = "mspm0-data-26a6f681eda4ef120e8cb614a1631727c848590f", default-features = false, features = ["metadata"] } [features] default = ["rt"] diff --git a/embassy-mspm0/build.rs b/embassy-mspm0/build.rs index 094769992..6cd62895b 100644 --- a/embassy-mspm0/build.rs +++ b/embassy-mspm0/build.rs @@ -1,6 +1,7 @@ use std::cmp::Ordering; use std::collections::{BTreeSet, HashMap}; -use std::io::Write; +use std::fmt::Write; +use std::io::Write as _; use std::path::{Path, PathBuf}; use std::process::Command; use std::sync::LazyLock; @@ -16,12 +17,19 @@ mod common; fn main() { generate_code(); + interrupt_group_linker_magic(); } fn generate_code() { let mut cfgs = common::CfgSet::new(); common::set_target_cfgs(&mut cfgs); + #[cfg(any(feature = "rt"))] + println!( + "cargo:rustc-link-search={}", + PathBuf::from(env::var_os("OUT_DIR").unwrap()).display(), + ); + cfgs.declare_all(&["gpio_pb", "gpio_pc", "int_group1"]); let chip_name = match env::vars() @@ -58,6 +66,7 @@ fn generate_code() { g.extend(generate_interrupts()); g.extend(generate_peripheral_instances()); g.extend(generate_pin_trait_impls()); + g.extend(generate_groups()); let out_dir = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); let out_file = out_dir.join("_generated.rs").to_string_lossy().to_string(); @@ -123,6 +132,83 @@ fn get_chip_cfgs(chip_name: &str) -> Vec { cfgs } +/// Interrupt groups use a weakly linked symbols and #[linkage = "extern_weak"] is nightly we need to +/// do some linker magic to create weak linkage. +fn interrupt_group_linker_magic() { + let mut file = String::new(); + + for group in METADATA.interrupt_groups { + for interrupt in group.interrupts.iter() { + let name = interrupt.name; + + writeln!(&mut file, "PROVIDE({name} = DefaultHandler);").unwrap(); + } + } + + let out_dir = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); + let out_file = out_dir.join("interrupt_group.x"); + fs::write(&out_file, file).unwrap(); +} + +fn generate_groups() -> TokenStream { + let group_vectors = METADATA.interrupt_groups.iter().map(|group| { + let vectors = group.interrupts.iter().map(|interrupt| { + let fn_name = Ident::new(interrupt.name, Span::call_site()); + + quote! { + pub(crate) fn #fn_name(); + } + }); + + quote! { #(#vectors)* } + }); + + let groups = METADATA.interrupt_groups.iter().map(|group| { + let interrupt_group_name = Ident::new(group.name, Span::call_site()); + let group_enum = Ident::new(&format!("Group{}", &group.name[5..]), Span::call_site()); + let group_number = Literal::u32_unsuffixed(group.number); + + let matches = group.interrupts.iter().map(|interrupt| { + let variant = Ident::new(&interrupt.name, Span::call_site()); + + quote! { + #group_enum::#variant => unsafe { group_vectors::#variant() }, + } + }); + + quote! { + #[cfg(feature = "rt")] + #[crate::pac::interrupt] + fn #interrupt_group_name() { + use crate::pac::#group_enum; + + let group = crate::pac::CPUSS.int_group(#group_number); + // MUST subtract by 1 since 0 is NO_INTR + let iidx = group.iidx().read().stat().to_bits() - 1; + + let Ok(group) = #group_enum::try_from(iidx as u8) else { + return; + }; + + match group { + #(#matches)* + } + } + } + }); + + quote! { + #(#groups)* + + #[cfg(feature = "rt")] + mod group_vectors { + extern "Rust" { + #(#group_vectors)* + } + } + } +} + #[derive(Debug, Clone)] struct Singleton { name: String, diff --git a/embassy-mspm0/src/gpio.rs b/embassy-mspm0/src/gpio.rs index 19a6230b6..738d51928 100644 --- a/embassy-mspm0/src/gpio.rs +++ b/embassy-mspm0/src/gpio.rs @@ -1119,24 +1119,36 @@ impl Iterator for BitIter { } } -// C110x has a dedicated interrupt just for GPIOA, as it does not have a GROUP1 interrupt. +// C110x and L110x have a dedicated interrupts just for GPIOA. +// +// These chips do not have a GROUP1 interrupt. #[cfg(all(feature = "rt", any(mspm0c110x, mspm0l110x)))] #[interrupt] fn GPIOA() { - gpioa_interrupt(); + irq_handler(pac::GPIOA, &PORTA_WAKERS); } -#[cfg(feature = "rt")] -pub(crate) fn gpioa_interrupt() { +// These symbols are weakly defined as DefaultHandler and are called by the interrupt group implementation. +// +// Defining these as no_mangle is required so that the linker will pick these over the default handler. + +#[cfg(all(feature = "rt", not(any(mspm0c110x, mspm0l110x))))] +#[no_mangle] +#[allow(non_snake_case)] +fn GPIOA() { irq_handler(pac::GPIOA, &PORTA_WAKERS); } #[cfg(all(feature = "rt", gpio_pb))] -pub(crate) fn gpiob_interrupt() { +#[no_mangle] +#[allow(non_snake_case)] +fn GPIOB() { irq_handler(pac::GPIOB, &PORTB_WAKERS); } #[cfg(all(feature = "rt", gpio_pc))] -pub(crate) fn gpioc_interrupt() { +#[allow(non_snake_case)] +#[no_mangle] +fn GPIOC() { irq_handler(pac::GPIOC, &PORTC_WAKERS); } diff --git a/embassy-mspm0/src/int_group/c110x.rs b/embassy-mspm0/src/int_group/c110x.rs deleted file mode 100644 index e6a9ddb99..000000000 --- a/embassy-mspm0/src/int_group/c110x.rs +++ /dev/null @@ -1,25 +0,0 @@ -use crate::pac; -use crate::pac::interrupt; - -#[cfg(feature = "rt")] -#[interrupt] -fn GROUP0() { - use mspm0_metapac::Group0; - - let group = pac::CPUSS.int_group(0); - - // TODO: Decompose to direct u8 - let iidx = group.iidx().read().stat().to_bits(); - - let Ok(group) = pac::Group0::try_from(iidx as u8) else { - debug!("Invalid IIDX for group 0: {}", iidx); - return; - }; - - match group { - Group0::WWDT0 => todo!("implement WWDT0"), - Group0::DEBUGSS => todo!("implement DEBUGSS"), - Group0::FLASHCTL => todo!("implement FLASHCTL"), - Group0::SYSCTL => todo!("implement SYSCTL"), - } -} diff --git a/embassy-mspm0/src/int_group/g110x.rs b/embassy-mspm0/src/int_group/g110x.rs deleted file mode 100644 index 9f8ac4d7b..000000000 --- a/embassy-mspm0/src/int_group/g110x.rs +++ /dev/null @@ -1,47 +0,0 @@ -use crate::pac; -use crate::pac::interrupt; - -#[cfg(feature = "rt")] -#[interrupt] -fn GROUP0() { - use mspm0_metapac::Group0; - - let group = pac::CPUSS.int_group(0); - - // Must subtract by 1 since NO_INTR is value 0 - let iidx = group.iidx().read().stat().to_bits() - 1; - - let Ok(group) = pac::Group0::try_from(iidx as u8) else { - debug!("Invalid IIDX for group 0: {}", iidx); - return; - }; - - match group { - Group0::WWDT0 => todo!("implement WWDT0"), - Group0::WWDT1 => todo!("implement WWDT1"), - Group0::DEBUGSS => todo!("implement DEBUGSS"), - Group0::FLASHCTL => todo!("implement FLASHCTL"), - Group0::SYSCTL => todo!("implement SYSCTL"), - } -} - -#[cfg(feature = "rt")] -#[interrupt] -fn GROUP1() { - use mspm0_metapac::Group1; - - let group = pac::CPUSS.int_group(1); - - // Must subtract by 1 since NO_INTR is value 0 - let iidx = group.iidx().read().stat().to_bits() - 1; - - let Ok(group) = pac::Group1::try_from(iidx as u8) else { - debug!("Invalid IIDX for group 1: {}", iidx); - return; - }; - - match group { - Group1::GPIOA => crate::gpio::gpioa_interrupt(), - Group1::GPIOB => crate::gpio::gpiob_interrupt(), - } -} diff --git a/embassy-mspm0/src/int_group/g150x.rs b/embassy-mspm0/src/int_group/g150x.rs deleted file mode 100644 index 706ba2078..000000000 --- a/embassy-mspm0/src/int_group/g150x.rs +++ /dev/null @@ -1,51 +0,0 @@ -use crate::pac; -use crate::pac::interrupt; - -#[cfg(feature = "rt")] -#[interrupt] -fn GROUP0() { - use mspm0_metapac::Group0; - - let group = pac::CPUSS.int_group(0); - - // Must subtract by 1 since NO_INTR is value 0 - let iidx = group.iidx().read().stat().to_bits() - 1; - - let Ok(group) = pac::Group0::try_from(iidx as u8) else { - debug!("Invalid IIDX for group 0: {}", iidx); - return; - }; - - match group { - Group0::WWDT0 => todo!("implement WWDT0"), - Group0::WWDT1 => todo!("implement WWDT1"), - Group0::DEBUGSS => todo!("implement DEBUGSS"), - Group0::FLASHCTL => todo!("implement FLASHCTL"), - Group0::SYSCTL => todo!("implement SYSCTL"), - } -} - -#[cfg(feature = "rt")] -#[interrupt] -fn GROUP1() { - use mspm0_metapac::Group1; - - let group = pac::CPUSS.int_group(1); - - // Must subtract by 1 since NO_INTR is value 0 - let iidx = group.iidx().read().stat().to_bits() - 1; - - let Ok(group) = pac::Group1::try_from(iidx as u8) else { - debug!("Invalid IIDX for group 1: {}", iidx); - return; - }; - - match group { - Group1::GPIOA => crate::gpio::gpioa_interrupt(), - Group1::GPIOB => crate::gpio::gpiob_interrupt(), - Group1::COMP0 => todo!("implement COMP0"), - Group1::COMP1 => todo!("implement COMP1"), - Group1::COMP2 => todo!("implement COMP2"), - Group1::TRNG => todo!("implement TRNG"), - } -} diff --git a/embassy-mspm0/src/int_group/g151x.rs b/embassy-mspm0/src/int_group/g151x.rs deleted file mode 100644 index e785018a7..000000000 --- a/embassy-mspm0/src/int_group/g151x.rs +++ /dev/null @@ -1,52 +0,0 @@ -use crate::pac; -use crate::pac::interrupt; - -#[cfg(feature = "rt")] -#[interrupt] -fn GROUP0() { - use mspm0_metapac::Group0; - - let group = pac::CPUSS.int_group(0); - - // Must subtract by 1 since NO_INTR is value 0 - let iidx = group.iidx().read().stat().to_bits() - 1; - - let Ok(group) = pac::Group0::try_from(iidx as u8) else { - debug!("Invalid IIDX for group 0: {}", iidx); - return; - }; - - match group { - Group0::WWDT0 => todo!("implement WWDT0"), - Group0::WWDT1 => todo!("implement WWDT1"), - Group0::DEBUGSS => todo!("implement DEBUGSS"), - Group0::FLASHCTL => todo!("implement FLASHCTL"), - Group0::SYSCTL => todo!("implement SYSCTL"), - } -} - -#[cfg(feature = "rt")] -#[interrupt] -fn GROUP1() { - use mspm0_metapac::Group1; - - let group = pac::CPUSS.int_group(1); - - // Must subtract by 1 since NO_INTR is value 0 - let iidx = group.iidx().read().stat().to_bits() - 1; - - let Ok(group) = pac::Group1::try_from(iidx as u8) else { - debug!("Invalid IIDX for group 1: {}", iidx); - return; - }; - - match group { - Group1::GPIOA => crate::gpio::gpioa_interrupt(), - Group1::GPIOB => crate::gpio::gpiob_interrupt(), - Group1::COMP0 => todo!("implement COMP0"), - Group1::COMP1 => todo!("implement COMP1"), - Group1::COMP2 => todo!("implement COMP2"), - Group1::TRNG => todo!("implement TRNG"), - Group1::GPIOC => crate::gpio::gpioc_interrupt(), - } -} diff --git a/embassy-mspm0/src/int_group/g310x.rs b/embassy-mspm0/src/int_group/g310x.rs deleted file mode 100644 index ad508d3a2..000000000 --- a/embassy-mspm0/src/int_group/g310x.rs +++ /dev/null @@ -1,48 +0,0 @@ -use crate::pac; -use crate::pac::interrupt; - -#[cfg(feature = "rt")] -#[interrupt] -fn GROUP0() { - use mspm0_metapac::Group0; - - let group = pac::CPUSS.int_group(0); - - // Must subtract by 1 since NO_INTR is value 0 - let iidx = group.iidx().read().stat().to_bits() - 1; - - let Ok(group) = pac::Group0::try_from(iidx as u8) else { - debug!("Invalid IIDX for group 0: {}", iidx); - return; - }; - - match group { - Group0::WWDT0 => todo!("implement WWDT0"), - Group0::WWDT1 => todo!("implement WWDT1"), - Group0::DEBUGSS => todo!("implement DEBUGSS"), - Group0::FLASHCTL => todo!("implement FLASHCTL"), - Group0::SYSCTL => todo!("implement SYSCTL"), - } -} - -#[cfg(feature = "rt")] -#[interrupt] -fn GROUP1() { - use mspm0_metapac::Group1; - - let group = pac::CPUSS.int_group(1); - - // Must subtract by 1 since NO_INTR is value 0 - let iidx = group.iidx().read().stat().to_bits() - 1; - - let Ok(group) = pac::Group1::try_from(iidx as u8) else { - debug!("Invalid IIDX for group 1: {}", iidx); - return; - }; - - match group { - Group1::GPIOA => crate::gpio::gpioa_interrupt(), - Group1::GPIOB => crate::gpio::gpiob_interrupt(), - Group1::TRNG => todo!("implement TRNG"), - } -} diff --git a/embassy-mspm0/src/int_group/g350x.rs b/embassy-mspm0/src/int_group/g350x.rs deleted file mode 100644 index 706ba2078..000000000 --- a/embassy-mspm0/src/int_group/g350x.rs +++ /dev/null @@ -1,51 +0,0 @@ -use crate::pac; -use crate::pac::interrupt; - -#[cfg(feature = "rt")] -#[interrupt] -fn GROUP0() { - use mspm0_metapac::Group0; - - let group = pac::CPUSS.int_group(0); - - // Must subtract by 1 since NO_INTR is value 0 - let iidx = group.iidx().read().stat().to_bits() - 1; - - let Ok(group) = pac::Group0::try_from(iidx as u8) else { - debug!("Invalid IIDX for group 0: {}", iidx); - return; - }; - - match group { - Group0::WWDT0 => todo!("implement WWDT0"), - Group0::WWDT1 => todo!("implement WWDT1"), - Group0::DEBUGSS => todo!("implement DEBUGSS"), - Group0::FLASHCTL => todo!("implement FLASHCTL"), - Group0::SYSCTL => todo!("implement SYSCTL"), - } -} - -#[cfg(feature = "rt")] -#[interrupt] -fn GROUP1() { - use mspm0_metapac::Group1; - - let group = pac::CPUSS.int_group(1); - - // Must subtract by 1 since NO_INTR is value 0 - let iidx = group.iidx().read().stat().to_bits() - 1; - - let Ok(group) = pac::Group1::try_from(iidx as u8) else { - debug!("Invalid IIDX for group 1: {}", iidx); - return; - }; - - match group { - Group1::GPIOA => crate::gpio::gpioa_interrupt(), - Group1::GPIOB => crate::gpio::gpiob_interrupt(), - Group1::COMP0 => todo!("implement COMP0"), - Group1::COMP1 => todo!("implement COMP1"), - Group1::COMP2 => todo!("implement COMP2"), - Group1::TRNG => todo!("implement TRNG"), - } -} diff --git a/embassy-mspm0/src/int_group/g351x.rs b/embassy-mspm0/src/int_group/g351x.rs deleted file mode 100644 index e785018a7..000000000 --- a/embassy-mspm0/src/int_group/g351x.rs +++ /dev/null @@ -1,52 +0,0 @@ -use crate::pac; -use crate::pac::interrupt; - -#[cfg(feature = "rt")] -#[interrupt] -fn GROUP0() { - use mspm0_metapac::Group0; - - let group = pac::CPUSS.int_group(0); - - // Must subtract by 1 since NO_INTR is value 0 - let iidx = group.iidx().read().stat().to_bits() - 1; - - let Ok(group) = pac::Group0::try_from(iidx as u8) else { - debug!("Invalid IIDX for group 0: {}", iidx); - return; - }; - - match group { - Group0::WWDT0 => todo!("implement WWDT0"), - Group0::WWDT1 => todo!("implement WWDT1"), - Group0::DEBUGSS => todo!("implement DEBUGSS"), - Group0::FLASHCTL => todo!("implement FLASHCTL"), - Group0::SYSCTL => todo!("implement SYSCTL"), - } -} - -#[cfg(feature = "rt")] -#[interrupt] -fn GROUP1() { - use mspm0_metapac::Group1; - - let group = pac::CPUSS.int_group(1); - - // Must subtract by 1 since NO_INTR is value 0 - let iidx = group.iidx().read().stat().to_bits() - 1; - - let Ok(group) = pac::Group1::try_from(iidx as u8) else { - debug!("Invalid IIDX for group 1: {}", iidx); - return; - }; - - match group { - Group1::GPIOA => crate::gpio::gpioa_interrupt(), - Group1::GPIOB => crate::gpio::gpiob_interrupt(), - Group1::COMP0 => todo!("implement COMP0"), - Group1::COMP1 => todo!("implement COMP1"), - Group1::COMP2 => todo!("implement COMP2"), - Group1::TRNG => todo!("implement TRNG"), - Group1::GPIOC => crate::gpio::gpioc_interrupt(), - } -} diff --git a/embassy-mspm0/src/int_group/l11xx.rs b/embassy-mspm0/src/int_group/l11xx.rs deleted file mode 100644 index 426a80c13..000000000 --- a/embassy-mspm0/src/int_group/l11xx.rs +++ /dev/null @@ -1,25 +0,0 @@ -use crate::pac; -use crate::pac::interrupt; - -#[cfg(feature = "rt")] -#[interrupt] -fn GROUP0() { - use mspm0_metapac::Group0; - - let group = pac::CPUSS.int_group(0); - - // Must subtract by 1 since NO_INTR is value 0 - let iidx = group.iidx().read().stat().to_bits() - 1; - - let Ok(group) = pac::Group0::try_from(iidx as u8) else { - debug!("Invalid IIDX for group 0: {}", iidx); - return; - }; - - match group { - Group0::WWDT0 => todo!("implement WWDT0"), - Group0::DEBUGSS => todo!("implement DEBUGSS"), - Group0::FLASHCTL => todo!("implement FLASHCTL"), - Group0::SYSCTL => todo!("implement SYSCTL"), - } -} diff --git a/embassy-mspm0/src/int_group/l12xx.rs b/embassy-mspm0/src/int_group/l12xx.rs deleted file mode 100644 index eeb2ce70d..000000000 --- a/embassy-mspm0/src/int_group/l12xx.rs +++ /dev/null @@ -1,49 +0,0 @@ -use crate::pac; -use crate::pac::interrupt; - -#[cfg(feature = "rt")] -#[interrupt] -fn GROUP0() { - use mspm0_metapac::Group0; - - let group = pac::CPUSS.int_group(0); - - // Must subtract by 1 since NO_INTR is value 0 - let iidx = group.iidx().read().stat().to_bits() - 1; - - let Ok(group) = pac::Group0::try_from(iidx as u8) else { - debug!("Invalid IIDX for group 0: {}", iidx); - return; - }; - - match group { - Group0::WWDT0 => todo!("implement WWDT0"), - Group0::DEBUGSS => todo!("implement DEBUGSS"), - Group0::FLASHCTL => todo!("implement FLASHCTL"), - Group0::SYSCTL => todo!("implement SYSCTL"), - } -} - -#[cfg(feature = "rt")] -#[interrupt] -fn GROUP1() { - use mspm0_metapac::Group1; - - let group = pac::CPUSS.int_group(1); - - // Must subtract by 1 since NO_INTR is value 0 - let iidx = group.iidx().read().stat().to_bits() - 1; - - let Ok(group) = pac::Group1::try_from(iidx as u8) else { - debug!("Invalid IIDX for group 1: {}", iidx); - return; - }; - - match group { - Group1::GPIOA => crate::gpio::gpioa_interrupt(), - Group1::GPIOB => crate::gpio::gpiob_interrupt(), - Group1::COMP0 => todo!("implement COMP0"), - Group1::TRNG => todo!("implement TRNG"), - Group1::GPIOC => crate::gpio::gpioc_interrupt(), - } -} diff --git a/embassy-mspm0/src/int_group/l13xx.rs b/embassy-mspm0/src/int_group/l13xx.rs deleted file mode 100644 index 8be5adcad..000000000 --- a/embassy-mspm0/src/int_group/l13xx.rs +++ /dev/null @@ -1,46 +0,0 @@ -use crate::pac; -use crate::pac::interrupt; - -#[cfg(feature = "rt")] -#[interrupt] -fn GROUP0() { - use mspm0_metapac::Group0; - - let group = pac::CPUSS.int_group(0); - - // Must subtract by 1 since NO_INTR is value 0 - let iidx = group.iidx().read().stat().to_bits() - 1; - - let Ok(group) = pac::Group0::try_from(iidx as u8) else { - debug!("Invalid IIDX for group 0: {}", iidx); - return; - }; - - match group { - Group0::WWDT0 => todo!("implement WWDT0"), - Group0::DEBUGSS => todo!("implement DEBUGSS"), - Group0::FLASHCTL => todo!("implement FLASHCTL"), - Group0::SYSCTL => todo!("implement SYSCTL"), - } -} - -#[cfg(feature = "rt")] -#[interrupt] -fn GROUP1() { - use mspm0_metapac::Group1; - - let group = pac::CPUSS.int_group(1); - - // Must subtract by 1 since NO_INTR is value 0 - let iidx = group.iidx().read().stat().to_bits() - 1; - - let Ok(group) = pac::Group1::try_from(iidx as u8) else { - debug!("Invalid IIDX for group 1: {}", iidx); - return; - }; - - match group { - Group1::GPIOA => crate::gpio::gpioa_interrupt(), - Group1::COMP0 => todo!("implement COMP0"), - } -} diff --git a/embassy-mspm0/src/int_group/l222x.rs b/embassy-mspm0/src/int_group/l222x.rs deleted file mode 100644 index eeb2ce70d..000000000 --- a/embassy-mspm0/src/int_group/l222x.rs +++ /dev/null @@ -1,49 +0,0 @@ -use crate::pac; -use crate::pac::interrupt; - -#[cfg(feature = "rt")] -#[interrupt] -fn GROUP0() { - use mspm0_metapac::Group0; - - let group = pac::CPUSS.int_group(0); - - // Must subtract by 1 since NO_INTR is value 0 - let iidx = group.iidx().read().stat().to_bits() - 1; - - let Ok(group) = pac::Group0::try_from(iidx as u8) else { - debug!("Invalid IIDX for group 0: {}", iidx); - return; - }; - - match group { - Group0::WWDT0 => todo!("implement WWDT0"), - Group0::DEBUGSS => todo!("implement DEBUGSS"), - Group0::FLASHCTL => todo!("implement FLASHCTL"), - Group0::SYSCTL => todo!("implement SYSCTL"), - } -} - -#[cfg(feature = "rt")] -#[interrupt] -fn GROUP1() { - use mspm0_metapac::Group1; - - let group = pac::CPUSS.int_group(1); - - // Must subtract by 1 since NO_INTR is value 0 - let iidx = group.iidx().read().stat().to_bits() - 1; - - let Ok(group) = pac::Group1::try_from(iidx as u8) else { - debug!("Invalid IIDX for group 1: {}", iidx); - return; - }; - - match group { - Group1::GPIOA => crate::gpio::gpioa_interrupt(), - Group1::GPIOB => crate::gpio::gpiob_interrupt(), - Group1::COMP0 => todo!("implement COMP0"), - Group1::TRNG => todo!("implement TRNG"), - Group1::GPIOC => crate::gpio::gpioc_interrupt(), - } -} diff --git a/embassy-mspm0/src/lib.rs b/embassy-mspm0/src/lib.rs index f129e221b..7ff60e946 100644 --- a/embassy-mspm0/src/lib.rs +++ b/embassy-mspm0/src/lib.rs @@ -39,20 +39,6 @@ pub mod mode { #[cfg(feature = "_time-driver")] mod time_driver; -// Interrupt group handlers. -#[cfg_attr(mspm0c110x, path = "int_group/c110x.rs")] -#[cfg_attr(mspm0g110x, path = "int_group/g110x.rs")] -#[cfg_attr(mspm0g150x, path = "int_group/g150x.rs")] -#[cfg_attr(mspm0g350x, path = "int_group/g350x.rs")] -#[cfg_attr(mspm0g151x, path = "int_group/g151x.rs")] -#[cfg_attr(mspm0g351x, path = "int_group/g351x.rs")] -#[cfg_attr(mspm0g310x, path = "int_group/g310x.rs")] -#[cfg_attr(mspm0l110x, path = "int_group/l11xx.rs")] -#[cfg_attr(mspm0l122x, path = "int_group/l12xx.rs")] -#[cfg_attr(any(mspm0l130x, mspm0l134x), path = "int_group/l13xx.rs")] -#[cfg_attr(mspm0l222x, path = "int_group/l222x.rs")] -mod int_group; - pub(crate) mod _generated { #![allow(dead_code)] #![allow(unused_imports)] diff --git a/examples/mspm0c1104/build.rs b/examples/mspm0c1104/build.rs index 30691aa97..2d777c2d3 100644 --- a/examples/mspm0c1104/build.rs +++ b/examples/mspm0c1104/build.rs @@ -32,4 +32,6 @@ fn main() { println!("cargo:rustc-link-arg-bins=--nmagic"); println!("cargo:rustc-link-arg-bins=-Tlink.x"); println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); + // You must tell cargo to link interrupt groups if the rt feature is enabled. + println!("cargo:rustc-link-arg-bins=-Tinterrupt_group.x"); } diff --git a/examples/mspm0g3507/build.rs b/examples/mspm0g3507/build.rs index 30691aa97..2d777c2d3 100644 --- a/examples/mspm0g3507/build.rs +++ b/examples/mspm0g3507/build.rs @@ -32,4 +32,6 @@ fn main() { println!("cargo:rustc-link-arg-bins=--nmagic"); println!("cargo:rustc-link-arg-bins=-Tlink.x"); println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); + // You must tell cargo to link interrupt groups if the rt feature is enabled. + println!("cargo:rustc-link-arg-bins=-Tinterrupt_group.x"); } diff --git a/examples/mspm0g3519/build.rs b/examples/mspm0g3519/build.rs index 30691aa97..2d777c2d3 100644 --- a/examples/mspm0g3519/build.rs +++ b/examples/mspm0g3519/build.rs @@ -32,4 +32,6 @@ fn main() { println!("cargo:rustc-link-arg-bins=--nmagic"); println!("cargo:rustc-link-arg-bins=-Tlink.x"); println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); + // You must tell cargo to link interrupt groups if the rt feature is enabled. + println!("cargo:rustc-link-arg-bins=-Tinterrupt_group.x"); } diff --git a/examples/mspm0l1306/build.rs b/examples/mspm0l1306/build.rs index 30691aa97..2d777c2d3 100644 --- a/examples/mspm0l1306/build.rs +++ b/examples/mspm0l1306/build.rs @@ -32,4 +32,6 @@ fn main() { println!("cargo:rustc-link-arg-bins=--nmagic"); println!("cargo:rustc-link-arg-bins=-Tlink.x"); println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); + // You must tell cargo to link interrupt groups if the rt feature is enabled. + println!("cargo:rustc-link-arg-bins=-Tinterrupt_group.x"); } diff --git a/examples/mspm0l2228/build.rs b/examples/mspm0l2228/build.rs index 30691aa97..2d777c2d3 100644 --- a/examples/mspm0l2228/build.rs +++ b/examples/mspm0l2228/build.rs @@ -32,4 +32,6 @@ fn main() { println!("cargo:rustc-link-arg-bins=--nmagic"); println!("cargo:rustc-link-arg-bins=-Tlink.x"); println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); + // You must tell cargo to link interrupt groups if the rt feature is enabled. + println!("cargo:rustc-link-arg-bins=-Tinterrupt_group.x"); } From 7be84f137c4f56842b6ebd6de3538b0081d42a09 Mon Sep 17 00:00:00 2001 From: okhsunrog Date: Wed, 21 May 2025 01:21:43 +0300 Subject: [PATCH 1151/1217] eeprom support --- embassy-stm32/src/flash/common.rs | 97 +++++++++++++++++++++++++++++++ embassy-stm32/src/flash/l.rs | 2 +- 2 files changed, 98 insertions(+), 1 deletion(-) diff --git a/embassy-stm32/src/flash/common.rs b/embassy-stm32/src/flash/common.rs index 10023e637..81d8966e9 100644 --- a/embassy-stm32/src/flash/common.rs +++ b/embassy-stm32/src/flash/common.rs @@ -11,6 +11,9 @@ use crate::Peri; use crate::_generated::FLASH_BASE; use crate::peripherals::FLASH; +#[cfg(eeprom)] +use crate::_generated::{EEPROM_BASE, EEPROM_SIZE}; + /// Internal flash memory driver. pub struct Flash<'d, MODE = Async> { pub(crate) inner: Peri<'d, FLASH>, @@ -72,6 +75,100 @@ impl<'d, MODE> Flash<'d, MODE> { } } +#[cfg(eeprom)] +impl<'d> Flash<'d, Blocking> { + fn eeprom_base(&self) -> u32 { + EEPROM_BASE as u32 + } + + fn eeprom_size(&self) -> u32 { + EEPROM_SIZE as u32 + } + + fn check_eeprom_offset(&self, offset: u32, size: u32) -> Result<(), Error> { + if offset + size > self.eeprom_size() { + Err(Error::Size) + } else { + Ok(()) + } + } + + /// Read a byte (u8) from EEPROM at the given offset. + pub fn eeprom_read_u8(&self, offset: u32) -> Result { + self.check_eeprom_offset(offset, 1)?; + let addr = self.eeprom_base() + offset; + Ok(unsafe { core::ptr::read_volatile(addr as *const u8) }) + } + + /// Read a half-word (u16) from EEPROM at the given offset. + pub fn eeprom_read_u16(&self, offset: u32) -> Result { + if offset % 2 != 0 { + return Err(Error::Unaligned); + } + self.check_eeprom_offset(offset, 2)?; + let addr = self.eeprom_base() + offset; + Ok(unsafe { core::ptr::read_volatile(addr as *const u16) }) + } + + /// Read a word (u32) from EEPROM at the given offset. + pub fn eeprom_read_u32(&self, offset: u32) -> Result { + if offset % 4 != 0 { + return Err(Error::Unaligned); + } + self.check_eeprom_offset(offset, 4)?; + let addr = self.eeprom_base() + offset; + Ok(unsafe { core::ptr::read_volatile(addr as *const u32) }) + } + + /// Write a byte (u8) to EEPROM at the given offset. + pub fn eeprom_write_u8(&mut self, offset: u32, value: u8) -> Result<(), Error> { + self.check_eeprom_offset(offset, 1)?; + let addr = self.eeprom_base() + offset; + unsafe { + family::unlock(); + core::ptr::write_volatile(addr as *mut u8, value); + family::wait_ready_blocking()?; + family::clear_all_err(); + family::lock(); + } + Ok(()) + } + + /// Write a half-word (u16) to EEPROM at the given offset. + pub fn eeprom_write_u16(&mut self, offset: u32, value: u16) -> Result<(), Error> { + if offset % 2 != 0 { + return Err(Error::Unaligned); + } + self.check_eeprom_offset(offset, 2)?; + let addr = self.eeprom_base() + offset; + unsafe { + family::unlock(); + core::ptr::write_volatile(addr as *mut u16, value); + family::wait_ready_blocking()?; + family::clear_all_err(); + family::lock(); + } + Ok(()) + } + + /// Write a word (u32) to EEPROM at the given offset. + pub fn eeprom_write_u32(&mut self, offset: u32, value: u32) -> Result<(), Error> { + if offset % 4 != 0 { + return Err(Error::Unaligned); + } + self.check_eeprom_offset(offset, 4)?; + let addr = self.eeprom_base() + offset; + unsafe { + family::unlock(); + core::ptr::write_volatile(addr as *mut u32, value); + family::wait_ready_blocking()?; + family::clear_all_err(); + family::lock(); + } + Ok(()) + } +} + pub(super) fn blocking_read(base: u32, size: u32, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { if offset + bytes.len() as u32 > size { return Err(Error::Size); diff --git a/embassy-stm32/src/flash/l.rs b/embassy-stm32/src/flash/l.rs index 65cea005c..1b82704ec 100644 --- a/embassy-stm32/src/flash/l.rs +++ b/embassy-stm32/src/flash/l.rs @@ -162,7 +162,7 @@ pub(crate) unsafe fn clear_all_err() { pac::FLASH.nssr().modify(|_| {}); } -unsafe fn wait_ready_blocking() -> Result<(), Error> { +pub(crate) unsafe fn wait_ready_blocking() -> Result<(), Error> { loop { #[cfg(not(flash_l5))] { From 8b65f9cf0f4095080297bf5c3e09334296da8076 Mon Sep 17 00:00:00 2001 From: i509VCB Date: Tue, 20 May 2025 17:29:28 -0500 Subject: [PATCH 1152/1217] mspm0: link interrupt groups in tests --- tests/mspm0/build.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/mspm0/build.rs b/tests/mspm0/build.rs index 57b592abf..0b58fb9e9 100644 --- a/tests/mspm0/build.rs +++ b/tests/mspm0/build.rs @@ -19,6 +19,8 @@ fn main() -> Result<(), Box> { println!("cargo:rustc-link-arg-bins=-Tlink_ram.x"); println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); println!("cargo:rustc-link-arg-bins=-Tteleprobe.x"); + // You must tell cargo to link interrupt groups if the rt feature is enabled. + println!("cargo:rustc-link-arg-bins=-Tinterrupt_group.x"); Ok(()) } From 6d19f2fd4cd073359f543776475c6ef6c5fddd00 Mon Sep 17 00:00:00 2001 From: okhsunrog Date: Wed, 21 May 2025 02:43:41 +0300 Subject: [PATCH 1153/1217] nightly fmt --- embassy-stm32/src/flash/common.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/embassy-stm32/src/flash/common.rs b/embassy-stm32/src/flash/common.rs index 81d8966e9..fb899b813 100644 --- a/embassy-stm32/src/flash/common.rs +++ b/embassy-stm32/src/flash/common.rs @@ -9,10 +9,9 @@ use super::{ }; use crate::Peri; use crate::_generated::FLASH_BASE; -use crate::peripherals::FLASH; - #[cfg(eeprom)] use crate::_generated::{EEPROM_BASE, EEPROM_SIZE}; +use crate::peripherals::FLASH; /// Internal flash memory driver. pub struct Flash<'d, MODE = Async> { From 21004fce0dae25a5f27b627861fad8912e7256f5 Mon Sep 17 00:00:00 2001 From: okhsunrog Date: Wed, 21 May 2025 02:50:36 +0300 Subject: [PATCH 1154/1217] always declare eeprom --- embassy-stm32/build.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index b91934af3..bb5ef53d7 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -1925,12 +1925,13 @@ fn main() { // ======== // Generate EEPROM constants + cfgs.declare("eeprom"); + let eeprom_memory_regions: Vec<&MemoryRegion> = memory.iter().filter(|x| x.kind == MemoryRegionKind::Eeprom).collect(); if !eeprom_memory_regions.is_empty() { cfgs.enable("eeprom"); - cfgs.declare("eeprom"); let mut sorted_eeprom_regions = eeprom_memory_regions.clone(); sorted_eeprom_regions.sort_by_key(|r| r.address); From 1accd560054f4203e193c6e77baca1c448fbf1c9 Mon Sep 17 00:00:00 2001 From: okhsunrog Date: Wed, 21 May 2025 08:30:38 +0300 Subject: [PATCH 1155/1217] new API --- embassy-stm32/src/flash/common.rs | 96 ------------- embassy-stm32/src/flash/eeprom.rs | 224 ++++++++++++++++++++++++++++++ embassy-stm32/src/flash/mod.rs | 5 + 3 files changed, 229 insertions(+), 96 deletions(-) create mode 100644 embassy-stm32/src/flash/eeprom.rs diff --git a/embassy-stm32/src/flash/common.rs b/embassy-stm32/src/flash/common.rs index fb899b813..10023e637 100644 --- a/embassy-stm32/src/flash/common.rs +++ b/embassy-stm32/src/flash/common.rs @@ -9,8 +9,6 @@ use super::{ }; use crate::Peri; use crate::_generated::FLASH_BASE; -#[cfg(eeprom)] -use crate::_generated::{EEPROM_BASE, EEPROM_SIZE}; use crate::peripherals::FLASH; /// Internal flash memory driver. @@ -74,100 +72,6 @@ impl<'d, MODE> Flash<'d, MODE> { } } -#[cfg(eeprom)] -impl<'d> Flash<'d, Blocking> { - fn eeprom_base(&self) -> u32 { - EEPROM_BASE as u32 - } - - fn eeprom_size(&self) -> u32 { - EEPROM_SIZE as u32 - } - - fn check_eeprom_offset(&self, offset: u32, size: u32) -> Result<(), Error> { - if offset + size > self.eeprom_size() { - Err(Error::Size) - } else { - Ok(()) - } - } - - /// Read a byte (u8) from EEPROM at the given offset. - pub fn eeprom_read_u8(&self, offset: u32) -> Result { - self.check_eeprom_offset(offset, 1)?; - let addr = self.eeprom_base() + offset; - Ok(unsafe { core::ptr::read_volatile(addr as *const u8) }) - } - - /// Read a half-word (u16) from EEPROM at the given offset. - pub fn eeprom_read_u16(&self, offset: u32) -> Result { - if offset % 2 != 0 { - return Err(Error::Unaligned); - } - self.check_eeprom_offset(offset, 2)?; - let addr = self.eeprom_base() + offset; - Ok(unsafe { core::ptr::read_volatile(addr as *const u16) }) - } - - /// Read a word (u32) from EEPROM at the given offset. - pub fn eeprom_read_u32(&self, offset: u32) -> Result { - if offset % 4 != 0 { - return Err(Error::Unaligned); - } - self.check_eeprom_offset(offset, 4)?; - let addr = self.eeprom_base() + offset; - Ok(unsafe { core::ptr::read_volatile(addr as *const u32) }) - } - - /// Write a byte (u8) to EEPROM at the given offset. - pub fn eeprom_write_u8(&mut self, offset: u32, value: u8) -> Result<(), Error> { - self.check_eeprom_offset(offset, 1)?; - let addr = self.eeprom_base() + offset; - unsafe { - family::unlock(); - core::ptr::write_volatile(addr as *mut u8, value); - family::wait_ready_blocking()?; - family::clear_all_err(); - family::lock(); - } - Ok(()) - } - - /// Write a half-word (u16) to EEPROM at the given offset. - pub fn eeprom_write_u16(&mut self, offset: u32, value: u16) -> Result<(), Error> { - if offset % 2 != 0 { - return Err(Error::Unaligned); - } - self.check_eeprom_offset(offset, 2)?; - let addr = self.eeprom_base() + offset; - unsafe { - family::unlock(); - core::ptr::write_volatile(addr as *mut u16, value); - family::wait_ready_blocking()?; - family::clear_all_err(); - family::lock(); - } - Ok(()) - } - - /// Write a word (u32) to EEPROM at the given offset. - pub fn eeprom_write_u32(&mut self, offset: u32, value: u32) -> Result<(), Error> { - if offset % 4 != 0 { - return Err(Error::Unaligned); - } - self.check_eeprom_offset(offset, 4)?; - let addr = self.eeprom_base() + offset; - unsafe { - family::unlock(); - core::ptr::write_volatile(addr as *mut u32, value); - family::wait_ready_blocking()?; - family::clear_all_err(); - family::lock(); - } - Ok(()) - } -} - pub(super) fn blocking_read(base: u32, size: u32, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { if offset + bytes.len() as u32 > size { return Err(Error::Size); diff --git a/embassy-stm32/src/flash/eeprom.rs b/embassy-stm32/src/flash/eeprom.rs new file mode 100644 index 000000000..74aedb7c0 --- /dev/null +++ b/embassy-stm32/src/flash/eeprom.rs @@ -0,0 +1,224 @@ +use super::{family, Blocking, Error, Flash, EEPROM_BASE, EEPROM_SIZE}; + +#[cfg(eeprom)] +impl<'d> Flash<'d, Blocking> { + // --- Internal helpers --- + + fn check_eeprom_offset(&self, offset: u32, size: u32) -> Result<(), Error> { + if offset + .checked_add(size) + .filter(|&end| end <= EEPROM_SIZE as u32) + .is_some() + { + Ok(()) + } else { + Err(Error::Size) + } + } + + // --- Unlocked (unsafe, internal) functions --- + + unsafe fn eeprom_write_u8_slice_unlocked(&self, offset: u32, data: &[u8]) -> Result<(), Error> { + for (i, &byte) in data.iter().enumerate() { + let addr = EEPROM_BASE as u32 + offset + i as u32; + core::ptr::write_volatile(addr as *mut u8, byte); + family::wait_ready_blocking()?; + family::clear_all_err(); + } + Ok(()) + } + + unsafe fn eeprom_write_u16_slice_unlocked(&self, offset: u32, data: &[u16]) -> Result<(), Error> { + for (i, &value) in data.iter().enumerate() { + let addr = EEPROM_BASE as u32 + offset + i as u32 * 2; + core::ptr::write_volatile(addr as *mut u16, value); + family::wait_ready_blocking()?; + family::clear_all_err(); + } + Ok(()) + } + + unsafe fn eeprom_write_u32_slice_unlocked(&self, offset: u32, data: &[u32]) -> Result<(), Error> { + for (i, &value) in data.iter().enumerate() { + let addr = EEPROM_BASE as u32 + offset + i as u32 * 4; + core::ptr::write_volatile(addr as *mut u32, value); + family::wait_ready_blocking()?; + family::clear_all_err(); + } + Ok(()) + } + + // --- Public, safe API --- + + pub fn eeprom_write_u8(&mut self, offset: u32, value: u8) -> Result<(), Error> { + self.check_eeprom_offset(offset, 1)?; + unsafe { + family::unlock(); + } + unsafe { + self.eeprom_write_u8_slice_unlocked(offset, core::slice::from_ref(&value))?; + } + unsafe { + family::lock(); + } + Ok(()) + } + + pub fn eeprom_write_u16(&mut self, offset: u32, value: u16) -> Result<(), Error> { + if offset % 2 != 0 { + return Err(Error::Unaligned); + } + self.check_eeprom_offset(offset, 2)?; + unsafe { + family::unlock(); + } + unsafe { + self.eeprom_write_u16_slice_unlocked(offset, core::slice::from_ref(&value))?; + } + unsafe { + family::lock(); + } + Ok(()) + } + + pub fn eeprom_write_u32(&mut self, offset: u32, value: u32) -> Result<(), Error> { + if offset % 4 != 0 { + return Err(Error::Unaligned); + } + self.check_eeprom_offset(offset, 4)?; + unsafe { + family::unlock(); + } + unsafe { + self.eeprom_write_u32_slice_unlocked(offset, core::slice::from_ref(&value))?; + } + unsafe { + family::lock(); + } + Ok(()) + } + + pub fn eeprom_write_u8_slice(&mut self, offset: u32, data: &[u8]) -> Result<(), Error> { + self.check_eeprom_offset(offset, data.len() as u32)?; + unsafe { + family::unlock(); + } + unsafe { + self.eeprom_write_u8_slice_unlocked(offset, data)?; + } + unsafe { + family::lock(); + } + Ok(()) + } + + pub fn eeprom_write_u16_slice(&mut self, offset: u32, data: &[u16]) -> Result<(), Error> { + if offset % 2 != 0 { + return Err(Error::Unaligned); + } + self.check_eeprom_offset(offset, data.len() as u32 * 2)?; + unsafe { + family::unlock(); + } + unsafe { + self.eeprom_write_u16_slice_unlocked(offset, data)?; + } + unsafe { + family::lock(); + } + Ok(()) + } + + pub fn eeprom_write_u32_slice(&mut self, offset: u32, data: &[u32]) -> Result<(), Error> { + if offset % 4 != 0 { + return Err(Error::Unaligned); + } + self.check_eeprom_offset(offset, data.len() as u32 * 4)?; + unsafe { + family::unlock(); + } + unsafe { + self.eeprom_write_u32_slice_unlocked(offset, data)?; + } + unsafe { + family::lock(); + } + Ok(()) + } + + pub fn eeprom_write(&mut self, offset: u32, data: &[u8]) -> Result<(), Error> { + let start = offset; + let end = offset.checked_add(data.len() as u32).ok_or(Error::Size)?; + if end > EEPROM_SIZE as u32 { + return Err(Error::Size); + } + + let misalign = (start % 4) as usize; + let prefix_len = if misalign == 0 { + 0 + } else { + (4 - misalign).min(data.len()) + }; + let (prefix, rest) = data.split_at(prefix_len); + let aligned_len = (rest.len() / 4) * 4; + let (aligned, suffix) = rest.split_at(aligned_len); + + unsafe { + family::unlock(); + } + if !prefix.is_empty() { + unsafe { + self.eeprom_write_u8_slice_unlocked(start, prefix)?; + } + } + if !aligned.is_empty() { + let aligned_offset = start + prefix_len as u32; + let u32_data = unsafe { core::slice::from_raw_parts(aligned.as_ptr() as *const u32, aligned.len() / 4) }; + unsafe { + self.eeprom_write_u32_slice_unlocked(aligned_offset, u32_data)?; + } + } + if !suffix.is_empty() { + let suffix_offset = start + (prefix_len + aligned_len) as u32; + unsafe { + self.eeprom_write_u8_slice_unlocked(suffix_offset, suffix)?; + } + } + unsafe { + family::lock(); + } + Ok(()) + } + + pub fn eeprom_read_u8(&self, offset: u32) -> Result { + self.check_eeprom_offset(offset, 1)?; + let addr = EEPROM_BASE as u32 + offset; + Ok(unsafe { core::ptr::read_volatile(addr as *const u8) }) + } + + pub fn eeprom_read_u16(&self, offset: u32) -> Result { + if offset % 2 != 0 { + return Err(Error::Unaligned); + } + self.check_eeprom_offset(offset, 2)?; + let addr = EEPROM_BASE as u32 + offset; + Ok(unsafe { core::ptr::read_volatile(addr as *const u16) }) + } + + pub fn eeprom_read_u32(&self, offset: u32) -> Result { + if offset % 4 != 0 { + return Err(Error::Unaligned); + } + self.check_eeprom_offset(offset, 4)?; + let addr = EEPROM_BASE as u32 + offset; + Ok(unsafe { core::ptr::read_volatile(addr as *const u32) }) + } + + pub fn eeprom_read_slice(&self, offset: u32, buf: &mut [u8]) -> Result<(), Error> { + self.check_eeprom_offset(offset, buf.len() as u32)?; + let addr = EEPROM_BASE as u32 + offset; + let src = unsafe { core::slice::from_raw_parts(addr as *const u8, buf.len()) }; + buf.copy_from_slice(src); + Ok(()) + } +} diff --git a/embassy-stm32/src/flash/mod.rs b/embassy-stm32/src/flash/mod.rs index 26f357370..a3f9e00f7 100644 --- a/embassy-stm32/src/flash/mod.rs +++ b/embassy-stm32/src/flash/mod.rs @@ -5,11 +5,16 @@ use embedded_storage::nor_flash::{NorFlashError, NorFlashErrorKind}; mod asynch; #[cfg(flash)] mod common; +#[cfg(eeprom)] +mod eeprom; #[cfg(flash_f4)] pub use asynch::InterruptHandler; #[cfg(flash)] pub use common::*; +#[cfg(eeprom)] +#[allow(unused_imports)] +pub use eeprom::*; pub use crate::_generated::flash_regions::*; #[cfg(eeprom)] From bc265b98b7597ffb90fe4e951beee5d65c6c481f Mon Sep 17 00:00:00 2001 From: okhsunrog Date: Wed, 21 May 2025 08:41:04 +0300 Subject: [PATCH 1156/1217] adding docs --- embassy-stm32/src/flash/eeprom.rs | 88 ++++++++++++++++--------------- 1 file changed, 45 insertions(+), 43 deletions(-) diff --git a/embassy-stm32/src/flash/eeprom.rs b/embassy-stm32/src/flash/eeprom.rs index 74aedb7c0..99c6b9c10 100644 --- a/embassy-stm32/src/flash/eeprom.rs +++ b/embassy-stm32/src/flash/eeprom.rs @@ -4,6 +4,7 @@ use super::{family, Blocking, Error, Flash, EEPROM_BASE, EEPROM_SIZE}; impl<'d> Flash<'d, Blocking> { // --- Internal helpers --- + /// Checks if the given offset and size are within the EEPROM bounds. fn check_eeprom_offset(&self, offset: u32, size: u32) -> Result<(), Error> { if offset .checked_add(size) @@ -18,6 +19,10 @@ impl<'d> Flash<'d, Blocking> { // --- Unlocked (unsafe, internal) functions --- + /// Writes a slice of bytes to EEPROM at the given offset without locking. + /// + /// # Safety + /// Caller must ensure EEPROM is unlocked and offset is valid. unsafe fn eeprom_write_u8_slice_unlocked(&self, offset: u32, data: &[u8]) -> Result<(), Error> { for (i, &byte) in data.iter().enumerate() { let addr = EEPROM_BASE as u32 + offset + i as u32; @@ -28,6 +33,10 @@ impl<'d> Flash<'d, Blocking> { Ok(()) } + /// Writes a slice of u16 values to EEPROM at the given offset without locking. + /// + /// # Safety + /// Caller must ensure EEPROM is unlocked and offset is valid and aligned. unsafe fn eeprom_write_u16_slice_unlocked(&self, offset: u32, data: &[u16]) -> Result<(), Error> { for (i, &value) in data.iter().enumerate() { let addr = EEPROM_BASE as u32 + offset + i as u32 * 2; @@ -38,6 +47,10 @@ impl<'d> Flash<'d, Blocking> { Ok(()) } + /// Writes a slice of u32 values to EEPROM at the given offset without locking. + /// + /// # Safety + /// Caller must ensure EEPROM is unlocked and offset is valid and aligned. unsafe fn eeprom_write_u32_slice_unlocked(&self, offset: u32, data: &[u32]) -> Result<(), Error> { for (i, &value) in data.iter().enumerate() { let addr = EEPROM_BASE as u32 + offset + i as u32 * 4; @@ -50,20 +63,20 @@ impl<'d> Flash<'d, Blocking> { // --- Public, safe API --- + /// Writes a single byte to EEPROM at the given offset. pub fn eeprom_write_u8(&mut self, offset: u32, value: u8) -> Result<(), Error> { self.check_eeprom_offset(offset, 1)?; unsafe { family::unlock(); - } - unsafe { self.eeprom_write_u8_slice_unlocked(offset, core::slice::from_ref(&value))?; - } - unsafe { family::lock(); } Ok(()) } + /// Writes a single 16-bit value to EEPROM at the given offset. + /// + /// Returns an error if the offset is not 2-byte aligned. pub fn eeprom_write_u16(&mut self, offset: u32, value: u16) -> Result<(), Error> { if offset % 2 != 0 { return Err(Error::Unaligned); @@ -71,16 +84,15 @@ impl<'d> Flash<'d, Blocking> { self.check_eeprom_offset(offset, 2)?; unsafe { family::unlock(); - } - unsafe { self.eeprom_write_u16_slice_unlocked(offset, core::slice::from_ref(&value))?; - } - unsafe { family::lock(); } Ok(()) } + /// Writes a single 32-bit value to EEPROM at the given offset. + /// + /// Returns an error if the offset is not 4-byte aligned. pub fn eeprom_write_u32(&mut self, offset: u32, value: u32) -> Result<(), Error> { if offset % 4 != 0 { return Err(Error::Unaligned); @@ -88,30 +100,26 @@ impl<'d> Flash<'d, Blocking> { self.check_eeprom_offset(offset, 4)?; unsafe { family::unlock(); - } - unsafe { self.eeprom_write_u32_slice_unlocked(offset, core::slice::from_ref(&value))?; - } - unsafe { family::lock(); } Ok(()) } + /// Writes a slice of bytes to EEPROM at the given offset. pub fn eeprom_write_u8_slice(&mut self, offset: u32, data: &[u8]) -> Result<(), Error> { self.check_eeprom_offset(offset, data.len() as u32)?; unsafe { family::unlock(); - } - unsafe { self.eeprom_write_u8_slice_unlocked(offset, data)?; - } - unsafe { family::lock(); } Ok(()) } + /// Writes a slice of 16-bit values to EEPROM at the given offset. + /// + /// Returns an error if the offset is not 2-byte aligned. pub fn eeprom_write_u16_slice(&mut self, offset: u32, data: &[u16]) -> Result<(), Error> { if offset % 2 != 0 { return Err(Error::Unaligned); @@ -119,16 +127,15 @@ impl<'d> Flash<'d, Blocking> { self.check_eeprom_offset(offset, data.len() as u32 * 2)?; unsafe { family::unlock(); - } - unsafe { self.eeprom_write_u16_slice_unlocked(offset, data)?; - } - unsafe { family::lock(); } Ok(()) } + /// Writes a slice of 32-bit values to EEPROM at the given offset. + /// + /// Returns an error if the offset is not 4-byte aligned. pub fn eeprom_write_u32_slice(&mut self, offset: u32, data: &[u32]) -> Result<(), Error> { if offset % 4 != 0 { return Err(Error::Unaligned); @@ -136,23 +143,18 @@ impl<'d> Flash<'d, Blocking> { self.check_eeprom_offset(offset, data.len() as u32 * 4)?; unsafe { family::unlock(); - } - unsafe { self.eeprom_write_u32_slice_unlocked(offset, data)?; - } - unsafe { family::lock(); } Ok(()) } + /// Writes a byte slice to EEPROM at the given offset, handling alignment. + /// + /// This method will write unaligned prefix and suffix as bytes, and aligned middle as u32. pub fn eeprom_write(&mut self, offset: u32, data: &[u8]) -> Result<(), Error> { + self.check_eeprom_offset(offset, data.len() as u32)?; let start = offset; - let end = offset.checked_add(data.len() as u32).ok_or(Error::Size)?; - if end > EEPROM_SIZE as u32 { - return Err(Error::Size); - } - let misalign = (start % 4) as usize; let prefix_len = if misalign == 0 { 0 @@ -165,37 +167,33 @@ impl<'d> Flash<'d, Blocking> { unsafe { family::unlock(); - } - if !prefix.is_empty() { - unsafe { + if !prefix.is_empty() { self.eeprom_write_u8_slice_unlocked(start, prefix)?; } - } - if !aligned.is_empty() { - let aligned_offset = start + prefix_len as u32; - let u32_data = unsafe { core::slice::from_raw_parts(aligned.as_ptr() as *const u32, aligned.len() / 4) }; - unsafe { + if !aligned.is_empty() { + let aligned_offset = start + prefix_len as u32; + let u32_data = core::slice::from_raw_parts(aligned.as_ptr() as *const u32, aligned.len() / 4); self.eeprom_write_u32_slice_unlocked(aligned_offset, u32_data)?; } - } - if !suffix.is_empty() { - let suffix_offset = start + (prefix_len + aligned_len) as u32; - unsafe { + if !suffix.is_empty() { + let suffix_offset = start + (prefix_len + aligned_len) as u32; self.eeprom_write_u8_slice_unlocked(suffix_offset, suffix)?; } - } - unsafe { family::lock(); } Ok(()) } + /// Reads a single byte from EEPROM at the given offset. pub fn eeprom_read_u8(&self, offset: u32) -> Result { self.check_eeprom_offset(offset, 1)?; let addr = EEPROM_BASE as u32 + offset; Ok(unsafe { core::ptr::read_volatile(addr as *const u8) }) } + /// Reads a single 16-bit value from EEPROM at the given offset. + /// + /// Returns an error if the offset is not 2-byte aligned. pub fn eeprom_read_u16(&self, offset: u32) -> Result { if offset % 2 != 0 { return Err(Error::Unaligned); @@ -205,6 +203,9 @@ impl<'d> Flash<'d, Blocking> { Ok(unsafe { core::ptr::read_volatile(addr as *const u16) }) } + /// Reads a single 32-bit value from EEPROM at the given offset. + /// + /// Returns an error if the offset is not 4-byte aligned. pub fn eeprom_read_u32(&self, offset: u32) -> Result { if offset % 4 != 0 { return Err(Error::Unaligned); @@ -214,6 +215,7 @@ impl<'d> Flash<'d, Blocking> { Ok(unsafe { core::ptr::read_volatile(addr as *const u32) }) } + /// Reads a slice of bytes from EEPROM at the given offset into the provided buffer. pub fn eeprom_read_slice(&self, offset: u32, buf: &mut [u8]) -> Result<(), Error> { self.check_eeprom_offset(offset, buf.len() as u32)?; let addr = EEPROM_BASE as u32 + offset; From 437e45df2b468caf13475ffaf3d55cc4f01e2d6b Mon Sep 17 00:00:00 2001 From: okhsunrog Date: Wed, 21 May 2025 09:44:28 +0300 Subject: [PATCH 1157/1217] make API more consistent --- embassy-stm32/src/flash/eeprom.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/src/flash/eeprom.rs b/embassy-stm32/src/flash/eeprom.rs index 99c6b9c10..5bccb2ecc 100644 --- a/embassy-stm32/src/flash/eeprom.rs +++ b/embassy-stm32/src/flash/eeprom.rs @@ -152,7 +152,7 @@ impl<'d> Flash<'d, Blocking> { /// Writes a byte slice to EEPROM at the given offset, handling alignment. /// /// This method will write unaligned prefix and suffix as bytes, and aligned middle as u32. - pub fn eeprom_write(&mut self, offset: u32, data: &[u8]) -> Result<(), Error> { + pub fn eeprom_write_slice(&mut self, offset: u32, data: &[u8]) -> Result<(), Error> { self.check_eeprom_offset(offset, data.len() as u32)?; let start = offset; let misalign = (start % 4) as usize; From 27ca627fc83974d926630b4a1bfc9783c3c86bb9 Mon Sep 17 00:00:00 2001 From: okhsunrog Date: Wed, 21 May 2025 09:54:19 +0300 Subject: [PATCH 1158/1217] added examples --- examples/stm32l0/src/bin/eeprom.rs | 32 ++++++++++++++++++++++++++++++ examples/stm32l1/src/bin/eeprom.rs | 32 ++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) create mode 100644 examples/stm32l0/src/bin/eeprom.rs create mode 100644 examples/stm32l1/src/bin/eeprom.rs diff --git a/examples/stm32l0/src/bin/eeprom.rs b/examples/stm32l0/src/bin/eeprom.rs new file mode 100644 index 000000000..370246644 --- /dev/null +++ b/examples/stm32l0/src/bin/eeprom.rs @@ -0,0 +1,32 @@ +#![no_std] +#![no_main] + +use defmt::{info, unwrap}; +use embassy_executor::Spawner; +use embassy_stm32::flash::{Flash, EEPROM_BASE, EEPROM_SIZE}; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_stm32::init(Default::default()); + + info!("Hello Eeprom! Start: {}, Size: {}", EEPROM_BASE, EEPROM_SIZE); + + const ADDR: u32 = 0x0; + + let mut f = Flash::new_blocking(p.FLASH); + + info!("Reading..."); + let mut buf = [0u8; 8]; + unwrap!(f.eeprom_read_slice(ADDR, &mut buf)); + info!("Read: {=[u8]:x}", buf); + + info!("Writing..."); + unwrap!(f.eeprom_write_slice(ADDR, &[1, 2, 3, 4, 5, 6, 7, 8])); + + info!("Reading..."); + let mut buf = [0u8; 8]; + unwrap!(f.eeprom_read_slice(ADDR, &mut buf)); + info!("Read: {=[u8]:x}", buf); + assert_eq!(&buf[..], &[1, 2, 3, 4, 5, 6, 7, 8]); +} diff --git a/examples/stm32l1/src/bin/eeprom.rs b/examples/stm32l1/src/bin/eeprom.rs new file mode 100644 index 000000000..370246644 --- /dev/null +++ b/examples/stm32l1/src/bin/eeprom.rs @@ -0,0 +1,32 @@ +#![no_std] +#![no_main] + +use defmt::{info, unwrap}; +use embassy_executor::Spawner; +use embassy_stm32::flash::{Flash, EEPROM_BASE, EEPROM_SIZE}; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_stm32::init(Default::default()); + + info!("Hello Eeprom! Start: {}, Size: {}", EEPROM_BASE, EEPROM_SIZE); + + const ADDR: u32 = 0x0; + + let mut f = Flash::new_blocking(p.FLASH); + + info!("Reading..."); + let mut buf = [0u8; 8]; + unwrap!(f.eeprom_read_slice(ADDR, &mut buf)); + info!("Read: {=[u8]:x}", buf); + + info!("Writing..."); + unwrap!(f.eeprom_write_slice(ADDR, &[1, 2, 3, 4, 5, 6, 7, 8])); + + info!("Reading..."); + let mut buf = [0u8; 8]; + unwrap!(f.eeprom_read_slice(ADDR, &mut buf)); + info!("Read: {=[u8]:x}", buf); + assert_eq!(&buf[..], &[1, 2, 3, 4, 5, 6, 7, 8]); +} From 05c511355638c3a55ab509ef9b2e30f5564b6282 Mon Sep 17 00:00:00 2001 From: RaulIQ Date: Wed, 21 May 2025 12:27:25 +0300 Subject: [PATCH 1159/1217] add waveform_up_multichannel using DMAR/DCR --- embassy-stm32/src/timer/simple_pwm.rs | 68 +++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs index 8fd7e8df4..c6fd169fc 100644 --- a/embassy-stm32/src/timer/simple_pwm.rs +++ b/embassy-stm32/src/timer/simple_pwm.rs @@ -381,6 +381,74 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> { self.inner.enable_update_dma(false); } } + + /// Generate a multichannel sequence of PWM waveforms using DMA triggered by timer update events. + /// + /// This method utilizes the timer's DMA burst transfer capability to update multiple CCRx registers + /// in sequence on each update event (UEV). The data is written via the DMAR register using the + /// DMA base address (DBA) and burst length (DBL) configured in the DCR register. + /// + /// Note: + /// you will need to provide corresponding TIMx_UP DMA channel to use this method. + pub async fn waveform_up_multichannel( + &mut self, + dma: Peri<'_, impl super::UpDma>, + starting_channel: Channel, + ending_channel: Channel, + duty: &[u16], + ) { + let cr1_addr = self.inner.regs_gp16().cr1().as_ptr() as u32; + let start_ch_index = starting_channel.index(); + let end_ch_index = ending_channel.index(); + + assert!(start_ch_index <= end_ch_index); + + let ccrx_addr = self.inner.regs_gp16().ccr(start_ch_index).as_ptr() as u32; + self.inner + .regs_gp16() + .dcr() + .modify(|w| w.set_dba(((ccrx_addr - cr1_addr) / 4) as u8)); + self.inner + .regs_gp16() + .dcr() + .modify(|w| w.set_dbl((end_ch_index - start_ch_index) as u8)); + + #[allow(clippy::let_unit_value)] // eg. stm32f334 + let req = dma.request(); + + let original_update_dma_state = self.inner.get_update_dma_state(); + if !original_update_dma_state { + self.inner.enable_update_dma(true); + } + + unsafe { + #[cfg(not(any(bdma, gpdma)))] + use crate::dma::{Burst, FifoThreshold}; + use crate::dma::{Transfer, TransferOptions}; + + let dma_transfer_option = TransferOptions { + #[cfg(not(any(bdma, gpdma)))] + fifo_threshold: Some(FifoThreshold::Full), + #[cfg(not(any(bdma, gpdma)))] + mburst: Burst::Incr4, + ..Default::default() + }; + + Transfer::new_write( + dma, + req, + duty, + self.inner.regs_gp16().dmar().as_ptr() as *mut u16, + dma_transfer_option, + ) + .await + }; + + if !original_update_dma_state { + self.inner.enable_update_dma(false); + } + } + } macro_rules! impl_waveform_chx { From 0e47478f01335c735f8f27fa3a935776736e9afa Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 19 May 2025 16:38:34 +0200 Subject: [PATCH 1160/1217] nrf/rng: add Blocking/Async Mode param. This allows avoiding creating the irq handler if you're only going to use it in blocking mode. --- embassy-nrf/src/lib.rs | 24 +++++++++++++ embassy-nrf/src/rng.rs | 78 ++++++++++++++++++++++++++++-------------- 2 files changed, 76 insertions(+), 26 deletions(-) diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index 0c5dd059d..398bfed48 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs @@ -1039,3 +1039,27 @@ pub fn init(config: config::Config) -> Peripherals { peripherals } + +/// Operating modes for peripherals. +pub mod mode { + trait SealedMode {} + + /// Operating mode for a peripheral. + #[allow(private_bounds)] + pub trait Mode: SealedMode {} + + macro_rules! impl_mode { + ($name:ident) => { + impl SealedMode for $name {} + impl Mode for $name {} + }; + } + + /// Blocking mode. + pub struct Blocking; + /// Async mode. + pub struct Async; + + impl_mode!(Blocking); + impl_mode!(Async); +} diff --git a/embassy-nrf/src/rng.rs b/embassy-nrf/src/rng.rs index 7e42dc938..9d3130e6e 100644 --- a/embassy-nrf/src/rng.rs +++ b/embassy-nrf/src/rng.rs @@ -14,6 +14,7 @@ use embassy_hal_internal::{Peri, PeripheralType}; use embassy_sync::waitqueue::WakerRegistration; use crate::interrupt::typelevel::Interrupt; +use crate::mode::{Async, Blocking, Mode}; use crate::{interrupt, pac}; /// Interrupt handler. @@ -55,11 +56,31 @@ impl interrupt::typelevel::Handler for InterruptHandl /// A wrapper around an nRF RNG peripheral. /// /// It has a non-blocking API, and a blocking api through `rand`. -pub struct Rng<'d, T: Instance> { +pub struct Rng<'d, T: Instance, M: Mode> { _peri: Peri<'d, T>, + _phantom: PhantomData, } -impl<'d, T: Instance> Rng<'d, T> { +impl<'d, T: Instance> Rng<'d, T, Blocking> { + /// Creates a new RNG driver from the `RNG` peripheral and interrupt. + /// + /// SAFETY: The future returned from `fill_bytes` must not have its lifetime end without running its destructor, + /// e.g. using `mem::forget`. + /// + /// The synchronous API is safe. + pub fn new_blocking(rng: Peri<'d, T>) -> Self { + let this = Self { + _peri: rng, + _phantom: PhantomData, + }; + + this.stop(); + + this + } +} + +impl<'d, T: Instance> Rng<'d, T, Async> { /// Creates a new RNG driver from the `RNG` peripheral and interrupt. /// /// SAFETY: The future returned from `fill_bytes` must not have its lifetime end without running its destructor, @@ -70,7 +91,10 @@ impl<'d, T: Instance> Rng<'d, T> { rng: Peri<'d, T>, _irq: impl interrupt::typelevel::Binding> + 'd, ) -> Self { - let this = Self { _peri: rng }; + let this = Self { + _peri: rng, + _phantom: PhantomData, + }; this.stop(); this.disable_irq(); @@ -81,14 +105,6 @@ impl<'d, T: Instance> Rng<'d, T> { this } - fn stop(&self) { - T::regs().tasks_stop().write_value(1) - } - - fn start(&self) { - T::regs().tasks_start().write_value(1) - } - fn enable_irq(&self) { T::regs().intenset().write(|w| w.set_valrdy(true)); } @@ -97,16 +113,6 @@ impl<'d, T: Instance> Rng<'d, T> { T::regs().intenclr().write(|w| w.set_valrdy(true)); } - /// Enable or disable the RNG's bias correction. - /// - /// Bias correction removes any bias towards a '1' or a '0' in the bits generated. - /// However, this makes the generation of numbers slower. - /// - /// Defaults to disabled. - pub fn set_bias_correction(&self, enable: bool) { - T::regs().config().write(|w| w.set_dercen(enable)) - } - /// Fill the buffer with random bytes. pub async fn fill_bytes(&mut self, dest: &mut [u8]) { if dest.is_empty() { @@ -153,6 +159,26 @@ impl<'d, T: Instance> Rng<'d, T> { // Trigger the teardown drop(on_drop); } +} + +impl<'d, T: Instance, M: Mode> Rng<'d, T, M> { + fn stop(&self) { + T::regs().tasks_stop().write_value(1) + } + + fn start(&self) { + T::regs().tasks_start().write_value(1) + } + + /// Enable or disable the RNG's bias correction. + /// + /// Bias correction removes any bias towards a '1' or a '0' in the bits generated. + /// However, this makes the generation of numbers slower. + /// + /// Defaults to disabled. + pub fn set_bias_correction(&self, enable: bool) { + T::regs().config().write(|w| w.set_dercen(enable)) + } /// Fill the buffer with random bytes, blocking version. pub fn blocking_fill_bytes(&mut self, dest: &mut [u8]) { @@ -184,7 +210,7 @@ impl<'d, T: Instance> Rng<'d, T> { } } -impl<'d, T: Instance> Drop for Rng<'d, T> { +impl<'d, T: Instance, M: Mode> Drop for Rng<'d, T, M> { fn drop(&mut self) { self.stop(); critical_section::with(|cs| { @@ -195,7 +221,7 @@ impl<'d, T: Instance> Drop for Rng<'d, T> { } } -impl<'d, T: Instance> rand_core_06::RngCore for Rng<'d, T> { +impl<'d, T: Instance, M: Mode> rand_core_06::RngCore for Rng<'d, T, M> { fn fill_bytes(&mut self, dest: &mut [u8]) { self.blocking_fill_bytes(dest); } @@ -211,9 +237,9 @@ impl<'d, T: Instance> rand_core_06::RngCore for Rng<'d, T> { } } -impl<'d, T: Instance> rand_core_06::CryptoRng for Rng<'d, T> {} +impl<'d, T: Instance, M: Mode> rand_core_06::CryptoRng for Rng<'d, T, M> {} -impl<'d, T: Instance> rand_core_09::RngCore for Rng<'d, T> { +impl<'d, T: Instance, M: Mode> rand_core_09::RngCore for Rng<'d, T, M> { fn fill_bytes(&mut self, dest: &mut [u8]) { self.blocking_fill_bytes(dest); } @@ -225,7 +251,7 @@ impl<'d, T: Instance> rand_core_09::RngCore for Rng<'d, T> { } } -impl<'d, T: Instance> rand_core_09::CryptoRng for Rng<'d, T> {} +impl<'d, T: Instance, M: Mode> rand_core_09::CryptoRng for Rng<'d, T, M> {} /// Peripheral static state pub(crate) struct State { From 0bbde1f65964acccb52ca8913da0f99511d29336 Mon Sep 17 00:00:00 2001 From: Adam Morgan Date: Mon, 19 May 2025 16:02:20 -0600 Subject: [PATCH 1161/1217] Add support for rtc_v3h7rs --- embassy-stm32/src/rtc/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs index b16c6fdca..49f423f37 100644 --- a/embassy-stm32/src/rtc/mod.rs +++ b/embassy-stm32/src/rtc/mod.rs @@ -25,7 +25,7 @@ use crate::time::Hertz; ), path = "v2.rs" )] -#[cfg_attr(any(rtc_v3, rtc_v3u5, rtc_v3l5), path = "v3.rs")] +#[cfg_attr(any(rtc_v3, rtc_v3u5, rtc_v3l5, rtc_v3h7rs), path = "v3.rs")] mod _version; #[allow(unused_imports)] pub use _version::*; From 3c025ff3772f6c20d53151a25b8cca9598bfcb2c Mon Sep 17 00:00:00 2001 From: Adam Morgan Date: Tue, 20 May 2025 09:17:38 -0600 Subject: [PATCH 1162/1217] Update stm32-metapac tag --- embassy-stm32/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 413c92cce..2ab4f9960 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -81,7 +81,7 @@ futures-util = { version = "0.3.30", default-features = false } sdio-host = "0.9.0" critical-section = "1.1" #stm32-metapac = { version = "16" } -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-7251801e3273011ce28a89e8f2e45eec2e419e26" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-27ef8fba3483187e852eaf3796d827259f61e8ec" } vcell = "0.1.3" nb = "1.0.0" @@ -110,7 +110,7 @@ proc-macro2 = "1.0.36" quote = "1.0.15" #stm32-metapac = { version = "16", default-features = false, features = ["metadata"]} -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-7251801e3273011ce28a89e8f2e45eec2e419e26", default-features = false, features = ["metadata"] } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-27ef8fba3483187e852eaf3796d827259f61e8ec", default-features = false, features = ["metadata"] } [features] default = ["rt"] From 65a22439d587746f6311ed05af740fd0cd455644 Mon Sep 17 00:00:00 2001 From: ROMemories <152802150+ROMemories@users.noreply.github.com> Date: Wed, 21 May 2025 11:17:59 +0200 Subject: [PATCH 1163/1217] feat(stm32-l): provide a `const` constructor on `rcc::Config` --- embassy-stm32/src/rcc/bd.rs | 18 +++++++++++------- embassy-stm32/src/rcc/hsi48.rs | 8 +++++++- embassy-stm32/src/rcc/l.rs | 17 ++++++++++++----- 3 files changed, 30 insertions(+), 13 deletions(-) diff --git a/embassy-stm32/src/rcc/bd.rs b/embassy-stm32/src/rcc/bd.rs index 57aaba1c7..939c05907 100644 --- a/embassy-stm32/src/rcc/bd.rs +++ b/embassy-stm32/src/rcc/bd.rs @@ -92,6 +92,16 @@ pub struct LsConfig { } impl LsConfig { + pub const fn new() -> Self { + // on L5, just the fact that LSI is enabled makes things crash. + // TODO: investigate. + + #[cfg(not(stm32l5))] + return Self::default_lsi(); + #[cfg(stm32l5)] + return Self::off(); + } + pub const fn default_lse() -> Self { Self { rtc: RtcClockSource::LSE, @@ -124,13 +134,7 @@ impl LsConfig { impl Default for LsConfig { fn default() -> Self { - // on L5, just the fact that LSI is enabled makes things crash. - // TODO: investigate. - - #[cfg(not(stm32l5))] - return Self::default_lsi(); - #[cfg(stm32l5)] - return Self::off(); + Self::new() } } diff --git a/embassy-stm32/src/rcc/hsi48.rs b/embassy-stm32/src/rcc/hsi48.rs index efabd059f..3ea5c96c9 100644 --- a/embassy-stm32/src/rcc/hsi48.rs +++ b/embassy-stm32/src/rcc/hsi48.rs @@ -18,9 +18,15 @@ pub struct Hsi48Config { pub sync_from_usb: bool, } +impl Hsi48Config { + pub const fn new() -> Self { + Self { sync_from_usb: false } + } +} + impl Default for Hsi48Config { fn default() -> Self { - Self { sync_from_usb: false } + Self::new() } } diff --git a/embassy-stm32/src/rcc/l.rs b/embassy-stm32/src/rcc/l.rs index 863942f1a..91e6ae07e 100644 --- a/embassy-stm32/src/rcc/l.rs +++ b/embassy-stm32/src/rcc/l.rs @@ -68,9 +68,9 @@ pub struct Config { pub mux: super::mux::ClockMux, } -impl Default for Config { +impl Config { #[inline] - fn default() -> Config { + pub const fn new() -> Self { Config { hse: None, hsi: false, @@ -90,15 +90,22 @@ impl Default for Config { #[cfg(any(stm32l47x, stm32l48x, stm32l49x, stm32l4ax, rcc_l4plus, stm32l5))] pllsai2: None, #[cfg(crs)] - hsi48: Some(Default::default()), - ls: Default::default(), + hsi48: Some(crate::rcc::Hsi48Config::new()), + ls: crate::rcc::LsConfig::new(), #[cfg(any(stm32l0, stm32l1))] voltage_scale: VoltageScale::RANGE1, - mux: Default::default(), + mux: super::mux::ClockMux::default(), } } } +impl Default for Config { + #[inline] + fn default() -> Config { + Self::new() + } +} + #[cfg(stm32wb)] pub const WPAN_DEFAULT: Config = Config { hse: Some(Hse { From 79b24bd35d452d162867480327e7b77296aad8c5 Mon Sep 17 00:00:00 2001 From: ROMemories <152802150+ROMemories@users.noreply.github.com> Date: Wed, 21 May 2025 11:36:55 +0200 Subject: [PATCH 1164/1217] feat(stm32-c0): provide a `const` constructor on `rcc::Config` --- embassy-stm32/src/rcc/c0.rs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/embassy-stm32/src/rcc/c0.rs b/embassy-stm32/src/rcc/c0.rs index 0b749bcff..68f67af01 100644 --- a/embassy-stm32/src/rcc/c0.rs +++ b/embassy-stm32/src/rcc/c0.rs @@ -59,9 +59,9 @@ pub struct Config { pub mux: super::mux::ClockMux, } -impl Default for Config { +impl Config { #[inline] - fn default() -> Config { + pub const fn new() -> Self { Config { hsi: Some(Hsi { sys_div: HsiSysDiv::DIV4, @@ -71,12 +71,19 @@ impl Default for Config { sys: Sysclk::HSISYS, ahb_pre: AHBPrescaler::DIV1, apb1_pre: APBPrescaler::DIV1, - ls: Default::default(), - mux: Default::default(), + ls: crate::rcc::LsConfig::new(), + mux: super::mux::ClockMux::default(), } } } +impl Default for Config { + #[inline] + fn default() -> Config { + Self::new() + } +} + pub(crate) unsafe fn init(config: Config) { // Turn on the HSI match config.hsi { From 4e6df1704703d69162fe91416fba6daa12eec0f4 Mon Sep 17 00:00:00 2001 From: ROMemories <152802150+ROMemories@users.noreply.github.com> Date: Wed, 21 May 2025 11:36:55 +0200 Subject: [PATCH 1165/1217] feat(stm32-f013): provide a `const` constructor on `rcc::Config` --- embassy-stm32/src/rcc/f013.rs | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/embassy-stm32/src/rcc/f013.rs b/embassy-stm32/src/rcc/f013.rs index cfa223d1f..1155b6acd 100644 --- a/embassy-stm32/src/rcc/f013.rs +++ b/embassy-stm32/src/rcc/f013.rs @@ -126,13 +126,13 @@ pub struct Config { pub ls: super::LsConfig, } -impl Default for Config { - fn default() -> Self { +impl Config { + pub const fn new() -> Self { Self { hsi: true, hse: None, #[cfg(crs)] - hsi48: Some(Default::default()), + hsi48: Some(crate::rcc::Hsi48Config::new()), sys: Sysclk::HSI, pll: None, @@ -147,7 +147,7 @@ impl Default for Config { apb1_pre: APBPrescaler::DIV1, #[cfg(not(stm32f0))] apb2_pre: APBPrescaler::DIV1, - ls: Default::default(), + ls: crate::rcc::LsConfig::new(), #[cfg(stm32f1)] // ensure ADC is not out of range by default even if APB2 is maxxed out (36mhz) @@ -163,11 +163,17 @@ impl Default for Config { #[cfg(stm32f107)] i2s3_src: I2s2src::SYS, - mux: Default::default(), + mux: super::mux::ClockMux::default(), } } } +impl Default for Config { + fn default() -> Self { + Self::new() + } +} + /// Initialize and Set the clock frequencies pub(crate) unsafe fn init(config: Config) { // Turn on the HSI From 3fcfec7b943c3ac26668c1c168e549fe3009547e Mon Sep 17 00:00:00 2001 From: ROMemories <152802150+ROMemories@users.noreply.github.com> Date: Wed, 21 May 2025 11:36:55 +0200 Subject: [PATCH 1166/1217] feat(stm32-f247): provide a `const` constructor on `rcc::Config` --- embassy-stm32/src/rcc/f247.rs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/embassy-stm32/src/rcc/f247.rs b/embassy-stm32/src/rcc/f247.rs index ee67f1cc0..8f2e8db5f 100644 --- a/embassy-stm32/src/rcc/f247.rs +++ b/embassy-stm32/src/rcc/f247.rs @@ -108,8 +108,8 @@ pub struct Config { pub voltage: VoltageScale, } -impl Default for Config { - fn default() -> Self { +impl Config { + pub const fn new() -> Self { Self { hsi: true, hse: None, @@ -127,15 +127,21 @@ impl Default for Config { apb1_pre: APBPrescaler::DIV1, apb2_pre: APBPrescaler::DIV1, - ls: Default::default(), + ls: crate::rcc::LsConfig::new(), #[cfg(stm32f2)] voltage: VoltageScale::Range3, - mux: Default::default(), + mux: super::mux::ClockMux::default(), } } } +impl Default for Config { + fn default() -> Self { + Self::new() + } +} + pub(crate) unsafe fn init(config: Config) { // set VOS to SCALE1, if use PLL // TODO: check real clock speed before set VOS From 26fb6eb9f65e7bf03302c26727ef7d6d940cf648 Mon Sep 17 00:00:00 2001 From: ROMemories <152802150+ROMemories@users.noreply.github.com> Date: Wed, 21 May 2025 11:36:55 +0200 Subject: [PATCH 1167/1217] feat(stm32-g0): provide a `const` constructor on `rcc::Config` --- embassy-stm32/src/rcc/g0.rs | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/embassy-stm32/src/rcc/g0.rs b/embassy-stm32/src/rcc/g0.rs index e391b1210..c03cbf9a8 100644 --- a/embassy-stm32/src/rcc/g0.rs +++ b/embassy-stm32/src/rcc/g0.rs @@ -97,9 +97,9 @@ pub struct Config { pub mux: super::mux::ClockMux, } -impl Default for Config { +impl Config { #[inline] - fn default() -> Config { + pub const fn new() -> Self { Config { hsi: Some(Hsi { sys_div: HsiSysDiv::DIV1, @@ -107,18 +107,25 @@ impl Default for Config { hse: None, sys: Sysclk::HSI, #[cfg(crs)] - hsi48: Some(Default::default()), + hsi48: Some(crate::rcc::Hsi48Config::new()), pll: None, ahb_pre: AHBPrescaler::DIV1, apb1_pre: APBPrescaler::DIV1, low_power_run: false, - ls: Default::default(), + ls: crate::rcc::LsConfig::new(), voltage_range: VoltageRange::RANGE1, - mux: Default::default(), + mux: super::mux::ClockMux::default(), } } } +impl Default for Config { + #[inline] + fn default() -> Config { + Self::new() + } +} + #[derive(Default)] pub struct PllFreq { pub pll_p: Option, From ea243761f727fb4fe2e2a55e85d3f0ac80e6387d Mon Sep 17 00:00:00 2001 From: ROMemories <152802150+ROMemories@users.noreply.github.com> Date: Wed, 21 May 2025 11:36:55 +0200 Subject: [PATCH 1168/1217] feat(stm32-g4): provide a `const` constructor on `rcc::Config` --- embassy-stm32/src/rcc/g4.rs | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/embassy-stm32/src/rcc/g4.rs b/embassy-stm32/src/rcc/g4.rs index d7d5c7388..e4b216450 100644 --- a/embassy-stm32/src/rcc/g4.rs +++ b/embassy-stm32/src/rcc/g4.rs @@ -91,26 +91,33 @@ pub struct Config { pub mux: super::mux::ClockMux, } -impl Default for Config { +impl Config { #[inline] - fn default() -> Config { + pub const fn new() -> Self { Config { hsi: true, hse: None, sys: Sysclk::HSI, - hsi48: Some(Default::default()), + hsi48: Some(crate::rcc::Hsi48Config::new()), pll: None, ahb_pre: AHBPrescaler::DIV1, apb1_pre: APBPrescaler::DIV1, apb2_pre: APBPrescaler::DIV1, low_power_run: false, - ls: Default::default(), + ls: crate::rcc::LsConfig::new(), boost: false, - mux: Default::default(), + mux: super::mux::ClockMux::default(), } } } +impl Default for Config { + #[inline] + fn default() -> Config { + Self::new() + } +} + #[derive(Default)] pub struct PllFreq { pub pll_p: Option, From 48b36adafd0e001e5d277f480359396759a0509e Mon Sep 17 00:00:00 2001 From: ROMemories <152802150+ROMemories@users.noreply.github.com> Date: Wed, 21 May 2025 11:36:55 +0200 Subject: [PATCH 1169/1217] feat(stm32-h): provide a `const` constructor on `rcc::Config` --- embassy-stm32/src/rcc/h.rs | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/embassy-stm32/src/rcc/h.rs b/embassy-stm32/src/rcc/h.rs index eaba8cefb..383f48874 100644 --- a/embassy-stm32/src/rcc/h.rs +++ b/embassy-stm32/src/rcc/h.rs @@ -218,13 +218,13 @@ pub struct Config { pub mux: super::mux::ClockMux, } -impl Default for Config { - fn default() -> Self { +impl Config { + pub const fn new() -> Self { Self { hsi: Some(HSIPrescaler::DIV1), hse: None, csi: false, - hsi48: Some(Default::default()), + hsi48: Some(crate::rcc::Hsi48Config::new()), sys: Sysclk::HSI, pll1: None, pll2: None, @@ -248,16 +248,22 @@ impl Default for Config { voltage_scale: VoltageScale::Scale0, #[cfg(rcc_h7rs)] voltage_scale: VoltageScale::HIGH, - ls: Default::default(), + ls: crate::rcc::LsConfig::new(), #[cfg(any(pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468, pwr_h7rs))] supply_config: SupplyConfig::LDO, - mux: Default::default(), + mux: super::mux::ClockMux::default(), } } } +impl Default for Config { + fn default() -> Self { + Self::new() + } +} + pub(crate) unsafe fn init(config: Config) { #[cfg(any(stm32h7))] let pwr_reg = PWR.cr3(); From da86052586b38768bdc2f709fda299ab06260cdb Mon Sep 17 00:00:00 2001 From: ROMemories <152802150+ROMemories@users.noreply.github.com> Date: Wed, 21 May 2025 11:36:55 +0200 Subject: [PATCH 1170/1217] feat(stm32-u5): provide a `const` constructor on `rcc::Config` --- embassy-stm32/src/rcc/u5.rs | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/embassy-stm32/src/rcc/u5.rs b/embassy-stm32/src/rcc/u5.rs index 93a327be7..ff70466b9 100644 --- a/embassy-stm32/src/rcc/u5.rs +++ b/embassy-stm32/src/rcc/u5.rs @@ -97,14 +97,14 @@ pub struct Config { pub mux: super::mux::ClockMux, } -impl Default for Config { - fn default() -> Self { +impl Config { + pub const fn new() -> Self { Self { msis: Some(Msirange::RANGE_4MHZ), msik: Some(Msirange::RANGE_4MHZ), hse: None, hsi: false, - hsi48: Some(Default::default()), + hsi48: Some(crate::rcc::Hsi48Config::new()), pll1: None, pll2: None, pll3: None, @@ -114,12 +114,18 @@ impl Default for Config { apb2_pre: APBPrescaler::DIV1, apb3_pre: APBPrescaler::DIV1, voltage_range: VoltageScale::RANGE1, - ls: Default::default(), - mux: Default::default(), + ls: crate::rcc::LsConfig::new(), + mux: super::mux::ClockMux::default(), } } } +impl Default for Config { + fn default() -> Self { + Self::new() + } +} + pub(crate) unsafe fn init(config: Config) { // Set the requested power mode PWR.vosr().modify(|w| w.set_vos(config.voltage_range)); From 576241fe2a455fff58527d9a593583fdab2d51bb Mon Sep 17 00:00:00 2001 From: ROMemories <152802150+ROMemories@users.noreply.github.com> Date: Wed, 21 May 2025 11:36:55 +0200 Subject: [PATCH 1171/1217] feat(stm32-wba): provide a `const` constructor on `rcc::Config` --- embassy-stm32/src/rcc/wba.rs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/embassy-stm32/src/rcc/wba.rs b/embassy-stm32/src/rcc/wba.rs index 1fee648d4..98d2dcf0e 100644 --- a/embassy-stm32/src/rcc/wba.rs +++ b/embassy-stm32/src/rcc/wba.rs @@ -37,9 +37,9 @@ pub struct Config { pub mux: super::mux::ClockMux, } -impl Default for Config { +impl Config { #[inline] - fn default() -> Config { + pub const fn new() -> Self { Config { hse: None, hsi: true, @@ -48,13 +48,20 @@ impl Default for Config { apb1_pre: APBPrescaler::DIV1, apb2_pre: APBPrescaler::DIV1, apb7_pre: APBPrescaler::DIV1, - ls: Default::default(), + ls: crate::rcc::LsConfig::new(), voltage_scale: VoltageScale::RANGE2, - mux: Default::default(), + mux: super::mux::ClockMux::default(), } } } +impl Default for Config { + #[inline] + fn default() -> Config { + Self::new() + } +} + fn hsi_enable() { RCC.cr().modify(|w| w.set_hsion(true)); while !RCC.cr().read().hsirdy() {} From 62ffc995f179de25d3fc41b420dd0194c94df737 Mon Sep 17 00:00:00 2001 From: RaulIQ Date: Wed, 21 May 2025 16:39:41 +0300 Subject: [PATCH 1172/1217] improve waveform_up_multi_channel documentation --- embassy-stm32/src/timer/simple_pwm.rs | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs index c6fd169fc..972a3852c 100644 --- a/embassy-stm32/src/timer/simple_pwm.rs +++ b/embassy-stm32/src/timer/simple_pwm.rs @@ -388,9 +388,27 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> { /// in sequence on each update event (UEV). The data is written via the DMAR register using the /// DMA base address (DBA) and burst length (DBL) configured in the DCR register. /// + /// The `duty` buffer must be structured as a flattened 2D array in row-major order, where each row + /// represents a single update event and each column corresponds to a specific timer channel (starting + /// from `starting_channel` up to and including `ending_channel`). + /// + /// For example, if using channels 1 through 4, a buffer of 4 update steps might look like: + /// + /// ```rust + /// let dma_buf: [u16; 16] = [ + /// ch1_duty_1, ch2_duty_1, ch3_duty_1, ch4_duty_1, // update 1 + /// ch1_duty_2, ch2_duty_2, ch3_duty_2, ch4_duty_2, // update 2 + /// ch1_duty_3, ch2_duty_3, ch3_duty_3, ch4_duty_3, // update 3 + /// ch1_duty_4, ch2_duty_4, ch3_duty_4, ch4_duty_4, // update 4 + /// ]; + /// ``` + /// + /// Each group of N values (where N = number of channels) is transferred on one update event, + /// updating the duty cycles of all selected channels simultaneously. + /// /// Note: /// you will need to provide corresponding TIMx_UP DMA channel to use this method. - pub async fn waveform_up_multichannel( + pub async fn waveform_up_multi_channel( &mut self, dma: Peri<'_, impl super::UpDma>, starting_channel: Channel, From 8e93ae88995d4f6663b2ba7ce2d4987d907c0339 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Tue, 20 May 2025 10:11:30 -0700 Subject: [PATCH 1173/1217] imxrt: add button example --- examples/mimxrt6/src/bin/button.rs | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 examples/mimxrt6/src/bin/button.rs diff --git a/examples/mimxrt6/src/bin/button.rs b/examples/mimxrt6/src/bin/button.rs new file mode 100644 index 000000000..efb7f14af --- /dev/null +++ b/examples/mimxrt6/src/bin/button.rs @@ -0,0 +1,29 @@ +#![no_std] +#![no_main] + +use defmt::info; +use embassy_executor::Spawner; +use embassy_futures::select::{select, Either}; +use embassy_imxrt::gpio; +use {defmt_rtt as _, embassy_imxrt_examples as _, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_imxrt::init(Default::default()); + + let mut user1 = gpio::Input::new(p.PIO1_1, gpio::Pull::None, gpio::Inverter::Disabled); + let mut user2 = gpio::Input::new(p.PIO0_10, gpio::Pull::None, gpio::Inverter::Disabled); + + loop { + let res = select(user1.wait_for_falling_edge(), user2.wait_for_falling_edge()).await; + + match res { + Either::First(()) => { + info!("Button `USER1' pressed"); + } + Either::Second(()) => { + info!("Button `USER2' pressed"); + } + } + } +} From 7a600fe9256a4c7c25501320da1de1fce8e1b39e Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Tue, 20 May 2025 08:49:34 -0700 Subject: [PATCH 1174/1217] timer: ostimer: wait for match write ready Before writing to MATCH_L/MATCH_H registers, wait for permission to do so by pollinmg MATCH_WR_RDY bit in CTRL register. --- embassy-imxrt/src/time_driver.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/embassy-imxrt/src/time_driver.rs b/embassy-imxrt/src/time_driver.rs index c68679d3e..f127609c8 100644 --- a/embassy-imxrt/src/time_driver.rs +++ b/embassy-imxrt/src/time_driver.rs @@ -336,6 +336,10 @@ impl OsTimer { let alarm = self.alarms.borrow(cs); alarm.timestamp.set(timestamp); + // Wait until we're allowed to write to MATCH_L/MATCH_H + // registers + while os().osevent_ctrl().read().match_wr_rdy().bit_is_set() {} + let t = self.now(); if timestamp <= t { os().osevent_ctrl().modify(|_, w| w.ostimer_intena().clear_bit()); @@ -366,7 +370,8 @@ impl OsTimer { fn on_interrupt(&self) { critical_section::with(|cs| { if os().osevent_ctrl().read().ostimer_intrflag().bit_is_set() { - os().osevent_ctrl().modify(|_, w| w.ostimer_intena().clear_bit()); + os().osevent_ctrl() + .modify(|_, w| w.ostimer_intena().clear_bit().ostimer_intrflag().set_bit()); self.trigger_alarm(cs); } }); From 966186064ebf36634e9930dd4b2d83ed675f6eb0 Mon Sep 17 00:00:00 2001 From: okhsunrog Date: Wed, 21 May 2025 20:59:49 +0300 Subject: [PATCH 1175/1217] fix UB --- embassy-stm32/src/flash/eeprom.rs | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/embassy-stm32/src/flash/eeprom.rs b/embassy-stm32/src/flash/eeprom.rs index 5bccb2ecc..68bcc6c15 100644 --- a/embassy-stm32/src/flash/eeprom.rs +++ b/embassy-stm32/src/flash/eeprom.rs @@ -154,6 +154,7 @@ impl<'d> Flash<'d, Blocking> { /// This method will write unaligned prefix and suffix as bytes, and aligned middle as u32. pub fn eeprom_write_slice(&mut self, offset: u32, data: &[u8]) -> Result<(), Error> { self.check_eeprom_offset(offset, data.len() as u32)?; + let start = offset; let misalign = (start % 4) as usize; let prefix_len = if misalign == 0 { @@ -163,17 +164,24 @@ impl<'d> Flash<'d, Blocking> { }; let (prefix, rest) = data.split_at(prefix_len); let aligned_len = (rest.len() / 4) * 4; - let (aligned, suffix) = rest.split_at(aligned_len); + let (bytes_for_u32_write, suffix) = rest.split_at(aligned_len); unsafe { family::unlock(); if !prefix.is_empty() { self.eeprom_write_u8_slice_unlocked(start, prefix)?; } - if !aligned.is_empty() { - let aligned_offset = start + prefix_len as u32; - let u32_data = core::slice::from_raw_parts(aligned.as_ptr() as *const u32, aligned.len() / 4); - self.eeprom_write_u32_slice_unlocked(aligned_offset, u32_data)?; + if !bytes_for_u32_write.is_empty() { + let aligned_eeprom_offset = start + prefix_len as u32; + let base_eeprom_addr = EEPROM_BASE as u32 + aligned_eeprom_offset; + for (i, chunk) in bytes_for_u32_write.chunks_exact(4).enumerate() { + // Safely read a u32 from a potentially unaligned pointer into the chunk. + let value = (chunk.as_ptr() as *const u32).read_unaligned(); + let current_eeprom_addr = base_eeprom_addr + (i * 4) as u32; + core::ptr::write_volatile(current_eeprom_addr as *mut u32, value); + family::wait_ready_blocking()?; + family::clear_all_err(); + } } if !suffix.is_empty() { let suffix_offset = start + (prefix_len + aligned_len) as u32; From e4a6d7aeddd686e47e1a26cd129e7bb646dcb0be Mon Sep 17 00:00:00 2001 From: okhsunrog Date: Wed, 21 May 2025 21:30:23 +0300 Subject: [PATCH 1176/1217] fix: lock on early return --- embassy-stm32/src/flash/eeprom.rs | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/embassy-stm32/src/flash/eeprom.rs b/embassy-stm32/src/flash/eeprom.rs index 68bcc6c15..cc3529eb9 100644 --- a/embassy-stm32/src/flash/eeprom.rs +++ b/embassy-stm32/src/flash/eeprom.rs @@ -1,3 +1,5 @@ +use embassy_hal_internal::drop::OnDrop; + use super::{family, Blocking, Error, Flash, EEPROM_BASE, EEPROM_SIZE}; #[cfg(eeprom)] @@ -68,8 +70,8 @@ impl<'d> Flash<'d, Blocking> { self.check_eeprom_offset(offset, 1)?; unsafe { family::unlock(); + let _on_drop = OnDrop::new(|| family::lock()); self.eeprom_write_u8_slice_unlocked(offset, core::slice::from_ref(&value))?; - family::lock(); } Ok(()) } @@ -84,8 +86,8 @@ impl<'d> Flash<'d, Blocking> { self.check_eeprom_offset(offset, 2)?; unsafe { family::unlock(); + let _on_drop = OnDrop::new(|| family::lock()); self.eeprom_write_u16_slice_unlocked(offset, core::slice::from_ref(&value))?; - family::lock(); } Ok(()) } @@ -100,8 +102,8 @@ impl<'d> Flash<'d, Blocking> { self.check_eeprom_offset(offset, 4)?; unsafe { family::unlock(); + let _on_drop = OnDrop::new(|| family::lock()); self.eeprom_write_u32_slice_unlocked(offset, core::slice::from_ref(&value))?; - family::lock(); } Ok(()) } @@ -111,8 +113,8 @@ impl<'d> Flash<'d, Blocking> { self.check_eeprom_offset(offset, data.len() as u32)?; unsafe { family::unlock(); + let _on_drop = OnDrop::new(|| family::lock()); self.eeprom_write_u8_slice_unlocked(offset, data)?; - family::lock(); } Ok(()) } @@ -127,8 +129,8 @@ impl<'d> Flash<'d, Blocking> { self.check_eeprom_offset(offset, data.len() as u32 * 2)?; unsafe { family::unlock(); + let _on_drop = OnDrop::new(|| family::lock()); self.eeprom_write_u16_slice_unlocked(offset, data)?; - family::lock(); } Ok(()) } @@ -143,8 +145,8 @@ impl<'d> Flash<'d, Blocking> { self.check_eeprom_offset(offset, data.len() as u32 * 4)?; unsafe { family::unlock(); + let _on_drop = OnDrop::new(|| family::lock()); self.eeprom_write_u32_slice_unlocked(offset, data)?; - family::lock(); } Ok(()) } @@ -154,7 +156,6 @@ impl<'d> Flash<'d, Blocking> { /// This method will write unaligned prefix and suffix as bytes, and aligned middle as u32. pub fn eeprom_write_slice(&mut self, offset: u32, data: &[u8]) -> Result<(), Error> { self.check_eeprom_offset(offset, data.len() as u32)?; - let start = offset; let misalign = (start % 4) as usize; let prefix_len = if misalign == 0 { @@ -168,6 +169,8 @@ impl<'d> Flash<'d, Blocking> { unsafe { family::unlock(); + let _on_drop = OnDrop::new(|| family::lock()); + if !prefix.is_empty() { self.eeprom_write_u8_slice_unlocked(start, prefix)?; } @@ -187,7 +190,6 @@ impl<'d> Flash<'d, Blocking> { let suffix_offset = start + (prefix_len + aligned_len) as u32; self.eeprom_write_u8_slice_unlocked(suffix_offset, suffix)?; } - family::lock(); } Ok(()) } From c88bc972316634da586589adcefa49bb02a2cf0f Mon Sep 17 00:00:00 2001 From: okhsunrog Date: Wed, 21 May 2025 22:33:44 +0300 Subject: [PATCH 1177/1217] added eeprom to tests --- tests/stm32/Cargo.toml | 10 ++++++++-- tests/stm32/src/bin/eeprom.rs | 30 ++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 2 deletions(-) create mode 100644 tests/stm32/src/bin/eeprom.rs diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml index 6036a5a97..5a483849c 100644 --- a/tests/stm32/Cargo.toml +++ b/tests/stm32/Cargo.toml @@ -19,8 +19,8 @@ stm32h563zi = ["embassy-stm32/stm32h563zi", "spi-v345", "chrono", "eth", "rng", stm32h753zi = ["embassy-stm32/stm32h753zi", "spi-v345", "chrono", "not-gpdma", "eth", "rng", "fdcan", "hash", "cryp"] stm32h755zi = ["embassy-stm32/stm32h755zi-cm7", "spi-v345", "chrono", "not-gpdma", "eth", "dac", "rng", "fdcan", "hash", "cryp"] stm32h7a3zi = ["embassy-stm32/stm32h7a3zi", "spi-v345", "not-gpdma", "rng", "fdcan"] -stm32l073rz = ["embassy-stm32/stm32l073rz", "cm0", "not-gpdma", "rng"] -stm32l152re = ["embassy-stm32/stm32l152re", "spi-v1", "chrono", "not-gpdma"] +stm32l073rz = ["embassy-stm32/stm32l073rz", "cm0", "not-gpdma", "rng", "eeprom"] +stm32l152re = ["embassy-stm32/stm32l152re", "spi-v1", "chrono", "not-gpdma", "eeprom"] stm32l496zg = ["embassy-stm32/stm32l496zg", "not-gpdma", "rng"] stm32l4a6zg = ["embassy-stm32/stm32l4a6zg", "chrono", "not-gpdma", "rng", "hash"] stm32l4r5zi = ["embassy-stm32/stm32l4r5zi", "chrono", "not-gpdma", "rng", "dual-bank"] @@ -55,6 +55,7 @@ ucpd = [] cordic = ["dep:num-traits"] dual-bank = ["embassy-stm32/dual-bank"] single-bank = ["embassy-stm32/single-bank"] +eeprom = [] cm0 = ["portable-atomic/unsafe-assume-single-core"] @@ -119,6 +120,11 @@ name = "dac_l1" path = "src/bin/dac_l1.rs" required-features = [ "stm32l152re",] +[[bin]] +name = "eeprom" +path = "src/bin/eeprom.rs" +required-features = [ "eeprom",] + [[bin]] name = "eth" path = "src/bin/eth.rs" diff --git a/tests/stm32/src/bin/eeprom.rs b/tests/stm32/src/bin/eeprom.rs new file mode 100644 index 000000000..61d249fd7 --- /dev/null +++ b/tests/stm32/src/bin/eeprom.rs @@ -0,0 +1,30 @@ +#![no_std] +#![no_main] + +// required-features: eeprom + +#[path = "../common.rs"] +mod common; + +use common::*; +use defmt::assert_eq; +use embassy_executor::Spawner; +use embassy_stm32::flash::Flash; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + // Initialize the board and obtain a Peripherals instance + let p: embassy_stm32::Peripherals = init(); + + let mut f = Flash::new_blocking(p.FLASH); + const ADDR: u32 = 0x0; + + unwrap!(f.eeprom_write_slice(ADDR, &[1, 2, 3, 4, 5, 6, 7, 8])); + let mut buf = [0u8; 8]; + unwrap!(f.eeprom_read_slice(ADDR, &mut buf)); + assert_eq!(&buf[..], &[1, 2, 3, 4, 5, 6, 7, 8]); + + info!("Test OK"); + cortex_m::asm::bkpt(); +} From 2f8a8e817c64dfa8d63b4a3ad43e650785698a5e Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Thu, 22 May 2025 11:41:25 +0800 Subject: [PATCH 1178/1217] embassy-sync: Update changelog --- embassy-sync/CHANGELOG.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/embassy-sync/CHANGELOG.md b/embassy-sync/CHANGELOG.md index 2049e0f11..aacb0d6c4 100644 --- a/embassy-sync/CHANGELOG.md +++ b/embassy-sync/CHANGELOG.md @@ -7,6 +7,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +- Add `remove_if` to `priority_channel::{Receiver, PriorityChannel}`. +- impl `Stream` for `channel::{Receiver, Channel}`. +- Fix channels to wake senders on `clear()`. + For `Channel`, `PriorityChannel`, `PubSub`, `zerocopy_channel::Channel`. +- Allow `zerocopy_channel::Channel` to auto-implement `Sync`/`Send`. +- Add `must_use` to `MutexGuard`. +- Add a `RwLock`. +- Add `lock_mut` to `blocking_mutex::Mutex`. +- Don't select a critical-section implementation when `std` feature is enabled. +- Improve waker documentation. +- Improve `Signal` and `Watch` documentation. +- Update to defmt 1.0. This remains compatible with latest defmt 0.3. + ## 0.6.2 - 2025-01-15 - Add dynamic dispatch variant of `Pipe`. From 5e49985ed678659e199c58c8100e3ed18d2f6227 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Thu, 22 May 2025 11:42:15 +0800 Subject: [PATCH 1179/1217] embassy-sync: bump to 0.7.0 --- cyw43/Cargo.toml | 2 +- embassy-boot-nrf/Cargo.toml | 2 +- embassy-boot-rp/Cargo.toml | 2 +- embassy-boot-stm32/Cargo.toml | 2 +- embassy-boot/Cargo.toml | 2 +- embassy-embedded-hal/Cargo.toml | 2 +- embassy-imxrt/Cargo.toml | 2 +- embassy-mspm0/Cargo.toml | 2 +- embassy-net-driver-channel/Cargo.toml | 2 +- embassy-net-esp-hosted/Cargo.toml | 2 +- embassy-net-nrf91/Cargo.toml | 2 +- embassy-net-ppp/Cargo.toml | 2 +- embassy-net/Cargo.toml | 2 +- embassy-nrf/Cargo.toml | 2 +- embassy-nxp/Cargo.toml | 2 +- embassy-rp/Cargo.toml | 2 +- embassy-stm32-wpan/Cargo.toml | 2 +- embassy-stm32/Cargo.toml | 2 +- embassy-sync/CHANGELOG.md | 2 ++ embassy-sync/Cargo.toml | 2 +- embassy-usb-dfu/Cargo.toml | 2 +- embassy-usb-logger/Cargo.toml | 2 +- embassy-usb-synopsys-otg/Cargo.toml | 2 +- embassy-usb/Cargo.toml | 2 +- examples/boot/application/nrf/Cargo.toml | 2 +- examples/boot/application/rp/Cargo.toml | 2 +- examples/boot/application/stm32f3/Cargo.toml | 2 +- examples/boot/application/stm32f7/Cargo.toml | 2 +- examples/boot/application/stm32h7/Cargo.toml | 2 +- examples/boot/application/stm32l0/Cargo.toml | 2 +- examples/boot/application/stm32l1/Cargo.toml | 2 +- examples/boot/application/stm32l4/Cargo.toml | 2 +- examples/boot/application/stm32wb-dfu/Cargo.toml | 2 +- examples/boot/application/stm32wl/Cargo.toml | 2 +- examples/boot/bootloader/nrf/Cargo.toml | 2 +- examples/boot/bootloader/rp/Cargo.toml | 2 +- examples/boot/bootloader/stm32-dual-bank/Cargo.toml | 2 +- examples/boot/bootloader/stm32/Cargo.toml | 2 +- examples/boot/bootloader/stm32wb-dfu/Cargo.toml | 2 +- examples/lpc55s69/Cargo.toml | 2 +- examples/mimxrt6/Cargo.toml | 2 +- examples/mspm0c1104/Cargo.toml | 2 +- examples/mspm0g3507/Cargo.toml | 2 +- examples/mspm0g3519/Cargo.toml | 2 +- examples/mspm0l1306/Cargo.toml | 2 +- examples/mspm0l2228/Cargo.toml | 2 +- examples/nrf-rtos-trace/Cargo.toml | 2 +- examples/nrf52810/Cargo.toml | 2 +- examples/nrf52840-rtic/Cargo.toml | 2 +- examples/nrf52840/Cargo.toml | 2 +- examples/nrf5340/Cargo.toml | 2 +- examples/rp/Cargo.toml | 2 +- examples/rp235x/Cargo.toml | 2 +- examples/std/Cargo.toml | 2 +- examples/stm32c0/Cargo.toml | 2 +- examples/stm32f0/Cargo.toml | 2 +- examples/stm32f1/Cargo.toml | 2 +- examples/stm32f2/Cargo.toml | 2 +- examples/stm32f3/Cargo.toml | 2 +- examples/stm32f334/Cargo.toml | 2 +- examples/stm32f4/Cargo.toml | 2 +- examples/stm32f7/Cargo.toml | 2 +- examples/stm32g0/Cargo.toml | 2 +- examples/stm32g4/Cargo.toml | 2 +- examples/stm32h5/Cargo.toml | 2 +- examples/stm32h7/Cargo.toml | 2 +- examples/stm32h723/Cargo.toml | 2 +- examples/stm32h735/Cargo.toml | 2 +- examples/stm32h742/Cargo.toml | 2 +- examples/stm32h755cm4/Cargo.toml | 2 +- examples/stm32h755cm7/Cargo.toml | 2 +- examples/stm32h7b0/Cargo.toml | 2 +- examples/stm32h7rs/Cargo.toml | 2 +- examples/stm32l0/Cargo.toml | 2 +- examples/stm32l1/Cargo.toml | 2 +- examples/stm32l4/Cargo.toml | 2 +- examples/stm32l432/Cargo.toml | 2 +- examples/stm32l5/Cargo.toml | 2 +- examples/stm32u0/Cargo.toml | 2 +- examples/stm32u5/Cargo.toml | 2 +- examples/stm32wb/Cargo.toml | 2 +- examples/stm32wba/Cargo.toml | 2 +- examples/stm32wl/Cargo.toml | 2 +- examples/wasm/Cargo.toml | 2 +- tests/mspm0/Cargo.toml | 2 +- tests/nrf/Cargo.toml | 2 +- tests/riscv32/Cargo.toml | 2 +- tests/rp/Cargo.toml | 2 +- tests/stm32/Cargo.toml | 2 +- 89 files changed, 90 insertions(+), 88 deletions(-) diff --git a/cyw43/Cargo.toml b/cyw43/Cargo.toml index 4b58ee9c9..c52a653bd 100644 --- a/cyw43/Cargo.toml +++ b/cyw43/Cargo.toml @@ -19,7 +19,7 @@ firmware-logs = [] [dependencies] embassy-time = { version = "0.4.0", path = "../embassy-time"} -embassy-sync = { version = "0.6.2", path = "../embassy-sync"} +embassy-sync = { version = "0.7.0", path = "../embassy-sync"} embassy-futures = { version = "0.1.0", path = "../embassy-futures"} embassy-net-driver-channel = { version = "0.3.0", path = "../embassy-net-driver-channel"} diff --git a/embassy-boot-nrf/Cargo.toml b/embassy-boot-nrf/Cargo.toml index 7d3e04419..3cfaa5a80 100644 --- a/embassy-boot-nrf/Cargo.toml +++ b/embassy-boot-nrf/Cargo.toml @@ -24,7 +24,7 @@ target = "thumbv7em-none-eabi" defmt = { version = "1.0.1", optional = true } log = { version = "0.4.17", optional = true } -embassy-sync = { version = "0.6.2", path = "../embassy-sync" } +embassy-sync = { version = "0.7.0", path = "../embassy-sync" } embassy-nrf = { version = "0.3.1", path = "../embassy-nrf", default-features = false } embassy-boot = { version = "0.4.0", path = "../embassy-boot" } cortex-m = { version = "0.7.6" } diff --git a/embassy-boot-rp/Cargo.toml b/embassy-boot-rp/Cargo.toml index 10eec774f..afe5d6691 100644 --- a/embassy-boot-rp/Cargo.toml +++ b/embassy-boot-rp/Cargo.toml @@ -24,7 +24,7 @@ features = ["embassy-rp/rp2040"] defmt = { version = "1.0.1", optional = true } log = { version = "0.4", optional = true } -embassy-sync = { version = "0.6.2", path = "../embassy-sync" } +embassy-sync = { version = "0.7.0", path = "../embassy-sync" } embassy-rp = { version = "0.4.0", path = "../embassy-rp", default-features = false } embassy-boot = { version = "0.4.0", path = "../embassy-boot" } embassy-time = { version = "0.4.0", path = "../embassy-time" } diff --git a/embassy-boot-stm32/Cargo.toml b/embassy-boot-stm32/Cargo.toml index 2b741cc95..a24921291 100644 --- a/embassy-boot-stm32/Cargo.toml +++ b/embassy-boot-stm32/Cargo.toml @@ -24,7 +24,7 @@ target = "thumbv7em-none-eabi" defmt = { version = "1.0.1", optional = true } log = { version = "0.4", optional = true } -embassy-sync = { version = "0.6.2", path = "../embassy-sync" } +embassy-sync = { version = "0.7.0", path = "../embassy-sync" } embassy-stm32 = { version = "0.2.0", path = "../embassy-stm32", default-features = false } embassy-boot = { version = "0.4.0", path = "../embassy-boot" } cortex-m = { version = "0.7.6" } diff --git a/embassy-boot/Cargo.toml b/embassy-boot/Cargo.toml index 8889f1a20..f12e8e304 100644 --- a/embassy-boot/Cargo.toml +++ b/embassy-boot/Cargo.toml @@ -29,7 +29,7 @@ digest = "0.10" log = { version = "0.4", optional = true } ed25519-dalek = { version = "2", default-features = false, features = ["digest"], optional = true } embassy-embedded-hal = { version = "0.3.0", path = "../embassy-embedded-hal" } -embassy-sync = { version = "0.6.2", path = "../embassy-sync" } +embassy-sync = { version = "0.7.0", path = "../embassy-sync" } embedded-storage = "0.3.1" embedded-storage-async = { version = "0.4.1" } salty = { version = "0.3", optional = true } diff --git a/embassy-embedded-hal/Cargo.toml b/embassy-embedded-hal/Cargo.toml index f7a973a8d..efc3173d4 100644 --- a/embassy-embedded-hal/Cargo.toml +++ b/embassy-embedded-hal/Cargo.toml @@ -24,7 +24,7 @@ default = ["time"] [dependencies] embassy-hal-internal = { version = "0.2.0", path = "../embassy-hal-internal" } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } -embassy-sync = { version = "0.6.2", path = "../embassy-sync" } +embassy-sync = { version = "0.7.0", path = "../embassy-sync" } embassy-time = { version = "0.4.0", path = "../embassy-time", optional = true } embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = [ "unproven", diff --git a/embassy-imxrt/Cargo.toml b/embassy-imxrt/Cargo.toml index 231a80251..49dc8089c 100644 --- a/embassy-imxrt/Cargo.toml +++ b/embassy-imxrt/Cargo.toml @@ -63,7 +63,7 @@ mimxrt685s = ["mimxrt685s-pac", "_mimxrt685s"] mimxrt633s = ["mimxrt633s-pac", "_mimxrt633s"] [dependencies] -embassy-sync = { version = "0.6.2", path = "../embassy-sync" } +embassy-sync = { version = "0.7.0", path = "../embassy-sync" } embassy-time-driver = { version = "0.2", path = "../embassy-time-driver", optional = true } embassy-time-queue-utils = { version = "0.1", path = "../embassy-time-queue-utils", optional = true } embassy-time = { version = "0.4", path = "../embassy-time", optional = true } diff --git a/embassy-mspm0/Cargo.toml b/embassy-mspm0/Cargo.toml index 6f767a3c0..456d302af 100644 --- a/embassy-mspm0/Cargo.toml +++ b/embassy-mspm0/Cargo.toml @@ -25,7 +25,7 @@ features = ["defmt", "unstable-pac", "time-driver-any", "time", "mspm0g3507"] rustdoc-args = ["--cfg", "docsrs"] [dependencies] -embassy-sync = { version = "0.6.2", path = "../embassy-sync" } +embassy-sync = { version = "0.7.0", path = "../embassy-sync" } embassy-time = { version = "0.4.0", path = "../embassy-time", optional = true } # TODO: Support other tick rates embassy-time-driver = { version = "0.2", path = "../embassy-time-driver", optional = true, features = ["tick-hz-32_768"] } diff --git a/embassy-net-driver-channel/Cargo.toml b/embassy-net-driver-channel/Cargo.toml index beadbf3c9..c16c4be74 100644 --- a/embassy-net-driver-channel/Cargo.toml +++ b/embassy-net-driver-channel/Cargo.toml @@ -25,6 +25,6 @@ features = ["defmt"] defmt = { version = "1.0.1", optional = true } log = { version = "0.4.14", optional = true } -embassy-sync = { version = "0.6.2", path = "../embassy-sync" } +embassy-sync = { version = "0.7.0", path = "../embassy-sync" } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver" } diff --git a/embassy-net-esp-hosted/Cargo.toml b/embassy-net-esp-hosted/Cargo.toml index 0cb99e67e..dea74ed65 100644 --- a/embassy-net-esp-hosted/Cargo.toml +++ b/embassy-net-esp-hosted/Cargo.toml @@ -18,7 +18,7 @@ defmt = { version = "1.0.1", optional = true } log = { version = "0.4.14", optional = true } embassy-time = { version = "0.4.0", path = "../embassy-time" } -embassy-sync = { version = "0.6.2", path = "../embassy-sync"} +embassy-sync = { version = "0.7.0", path = "../embassy-sync"} embassy-futures = { version = "0.1.0", path = "../embassy-futures"} embassy-net-driver-channel = { version = "0.3.0", path = "../embassy-net-driver-channel"} diff --git a/embassy-net-nrf91/Cargo.toml b/embassy-net-nrf91/Cargo.toml index de12ac36f..62813e546 100644 --- a/embassy-net-nrf91/Cargo.toml +++ b/embassy-net-nrf91/Cargo.toml @@ -21,7 +21,7 @@ nrf-pac = "0.1.0" cortex-m = "0.7.7" embassy-time = { version = "0.4.0", path = "../embassy-time" } -embassy-sync = { version = "0.6.2", path = "../embassy-sync" } +embassy-sync = { version = "0.7.0", path = "../embassy-sync" } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } embassy-net-driver-channel = { version = "0.3.0", path = "../embassy-net-driver-channel" } diff --git a/embassy-net-ppp/Cargo.toml b/embassy-net-ppp/Cargo.toml index ab713fed8..0936626eb 100644 --- a/embassy-net-ppp/Cargo.toml +++ b/embassy-net-ppp/Cargo.toml @@ -21,7 +21,7 @@ embedded-io-async = { version = "0.6.1" } embassy-net-driver-channel = { version = "0.3.0", path = "../embassy-net-driver-channel" } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } ppproto = { version = "0.2.1"} -embassy-sync = { version = "0.6.2", path = "../embassy-sync" } +embassy-sync = { version = "0.7.0", path = "../embassy-sync" } [package.metadata.embassy_docs] src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-ppp-v$VERSION/embassy-net-ppp/src/" diff --git a/embassy-net/Cargo.toml b/embassy-net/Cargo.toml index d96481f98..526c8a4b3 100644 --- a/embassy-net/Cargo.toml +++ b/embassy-net/Cargo.toml @@ -78,7 +78,7 @@ smoltcp = { version = "0.12.0", default-features = false, features = [ embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver" } embassy-time = { version = "0.4.0", path = "../embassy-time" } -embassy-sync = { version = "0.6.2", path = "../embassy-sync" } +embassy-sync = { version = "0.7.0", path = "../embassy-sync" } embedded-io-async = { version = "0.6.1" } managed = { version = "0.8.0", default-features = false, features = [ "map" ] } diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml index e4f40630e..47eb92697 100644 --- a/embassy-nrf/Cargo.toml +++ b/embassy-nrf/Cargo.toml @@ -143,7 +143,7 @@ _multi_wdt = [] embassy-time-driver = { version = "0.2", path = "../embassy-time-driver", optional = true } embassy-time-queue-utils = { version = "0.1", path = "../embassy-time-queue-utils", optional = true } embassy-time = { version = "0.4.0", path = "../embassy-time", optional = true } -embassy-sync = { version = "0.6.2", path = "../embassy-sync" } +embassy-sync = { version = "0.7.0", path = "../embassy-sync" } embassy-hal-internal = { version = "0.2.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-3"] } embassy-embedded-hal = { version = "0.3.0", path = "../embassy-embedded-hal", default-features = false } embassy-usb-driver = { version = "0.1.0", path = "../embassy-usb-driver" } diff --git a/embassy-nxp/Cargo.toml b/embassy-nxp/Cargo.toml index 86a989aa7..426af06a0 100644 --- a/embassy-nxp/Cargo.toml +++ b/embassy-nxp/Cargo.toml @@ -8,7 +8,7 @@ cortex-m = "0.7.7" cortex-m-rt = "0.7.0" critical-section = "1.1.2" embassy-hal-internal = { version = "0.2.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-2"] } -embassy-sync = { version = "0.6.2", path = "../embassy-sync" } +embassy-sync = { version = "0.7.0", path = "../embassy-sync" } lpc55-pac = "0.5.0" defmt = { version = "1", optional = true } diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index 3c18a8f77..5df9e154c 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml @@ -136,7 +136,7 @@ _test = [] binary-info = ["rt", "dep:rp-binary-info", "rp-binary-info?/binary-info"] [dependencies] -embassy-sync = { version = "0.6.2", path = "../embassy-sync" } +embassy-sync = { version = "0.7.0", path = "../embassy-sync" } embassy-time-driver = { version = "0.2", path = "../embassy-time-driver", optional = true } embassy-time-queue-utils = { version = "0.1", path = "../embassy-time-queue-utils", optional = true } embassy-time = { version = "0.4.0", path = "../embassy-time" } diff --git a/embassy-stm32-wpan/Cargo.toml b/embassy-stm32-wpan/Cargo.toml index 81af6aedd..b749625aa 100644 --- a/embassy-stm32-wpan/Cargo.toml +++ b/embassy-stm32-wpan/Cargo.toml @@ -20,7 +20,7 @@ features = ["stm32wb55rg", "ble", "mac"] [dependencies] embassy-stm32 = { version = "0.2.0", path = "../embassy-stm32" } -embassy-sync = { version = "0.6.2", path = "../embassy-sync" } +embassy-sync = { version = "0.7.0", path = "../embassy-sync" } embassy-time = { version = "0.4.0", path = "../embassy-time", optional = true } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } embassy-hal-internal = { version = "0.2.0", path = "../embassy-hal-internal" } diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 2ab4f9960..034f51df9 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -48,7 +48,7 @@ features = ["defmt", "unstable-pac", "exti", "time-driver-any", "time", "stm32h7 rustdoc-args = ["--cfg", "docsrs"] [dependencies] -embassy-sync = { version = "0.6.2", path = "../embassy-sync" } +embassy-sync = { version = "0.7.0", path = "../embassy-sync" } embassy-time = { version = "0.4.0", path = "../embassy-time", optional = true } embassy-time-driver = { version = "0.2", path = "../embassy-time-driver", optional = true } embassy-time-queue-utils = { version = "0.1", path = "../embassy-time-queue-utils", optional = true } diff --git a/embassy-sync/CHANGELOG.md b/embassy-sync/CHANGELOG.md index aacb0d6c4..1770bef44 100644 --- a/embassy-sync/CHANGELOG.md +++ b/embassy-sync/CHANGELOG.md @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +## 0.7.0 - 2025-05-22 + - Add `remove_if` to `priority_channel::{Receiver, PriorityChannel}`. - impl `Stream` for `channel::{Receiver, Channel}`. - Fix channels to wake senders on `clear()`. diff --git a/embassy-sync/Cargo.toml b/embassy-sync/Cargo.toml index 65cade317..99962f9f6 100644 --- a/embassy-sync/Cargo.toml +++ b/embassy-sync/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "embassy-sync" -version = "0.6.2" +version = "0.7.0" edition = "2021" description = "no-std, no-alloc synchronization primitives with async support" repository = "https://github.com/embassy-rs/embassy" diff --git a/embassy-usb-dfu/Cargo.toml b/embassy-usb-dfu/Cargo.toml index ccf8a16eb..ca108c1a2 100644 --- a/embassy-usb-dfu/Cargo.toml +++ b/embassy-usb-dfu/Cargo.toml @@ -33,7 +33,7 @@ bitflags = "2.4.1" cortex-m = { version = "0.7.7", features = ["inline-asm"], optional = true } embassy-boot = { version = "0.4.0", path = "../embassy-boot" } embassy-futures = { version = "0.1.1", path = "../embassy-futures" } -embassy-sync = { version = "0.6.2", path = "../embassy-sync" } +embassy-sync = { version = "0.7.0", path = "../embassy-sync" } embassy-time = { version = "0.4.0", path = "../embassy-time" } embassy-usb = { version = "0.4.0", path = "../embassy-usb", default-features = false } embedded-storage = { version = "0.3.1" } diff --git a/embassy-usb-logger/Cargo.toml b/embassy-usb-logger/Cargo.toml index c670b41b6..6b8e9af47 100644 --- a/embassy-usb-logger/Cargo.toml +++ b/embassy-usb-logger/Cargo.toml @@ -16,6 +16,6 @@ target = "thumbv7em-none-eabi" [dependencies] embassy-usb = { version = "0.4.0", path = "../embassy-usb" } -embassy-sync = { version = "0.6.2", path = "../embassy-sync" } +embassy-sync = { version = "0.7.0", path = "../embassy-sync" } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } log = "0.4" diff --git a/embassy-usb-synopsys-otg/Cargo.toml b/embassy-usb-synopsys-otg/Cargo.toml index 98fc044ce..6252feaef 100644 --- a/embassy-usb-synopsys-otg/Cargo.toml +++ b/embassy-usb-synopsys-otg/Cargo.toml @@ -18,7 +18,7 @@ target = "thumbv7em-none-eabi" [dependencies] critical-section = "1.1" -embassy-sync = { version = "0.6.2", path = "../embassy-sync" } +embassy-sync = { version = "0.7.0", path = "../embassy-sync" } embassy-usb-driver = { version = "0.1.0", path = "../embassy-usb-driver" } defmt = { version = "1.0.1", optional = true } diff --git a/embassy-usb/Cargo.toml b/embassy-usb/Cargo.toml index e52f4602d..31fd1c1e0 100644 --- a/embassy-usb/Cargo.toml +++ b/embassy-usb/Cargo.toml @@ -48,7 +48,7 @@ max-handler-count-8 = [] [dependencies] embassy-futures = { version = "0.1.0", path = "../embassy-futures" } embassy-usb-driver = { version = "0.1.0", path = "../embassy-usb-driver" } -embassy-sync = { version = "0.6.2", path = "../embassy-sync" } +embassy-sync = { version = "0.7.0", path = "../embassy-sync" } embassy-net-driver-channel = { version = "0.3.0", path = "../embassy-net-driver-channel" } defmt = { version = "1", optional = true } diff --git a/examples/boot/application/nrf/Cargo.toml b/examples/boot/application/nrf/Cargo.toml index 244ce9591..4d633e8a8 100644 --- a/examples/boot/application/nrf/Cargo.toml +++ b/examples/boot/application/nrf/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-sync = { version = "0.6.2", path = "../../../../embassy-sync" } +embassy-sync = { version = "0.7.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [] } embassy-nrf = { version = "0.3.1", path = "../../../../embassy-nrf", features = ["time-driver-rtc1", "gpiote", ] } diff --git a/examples/boot/application/rp/Cargo.toml b/examples/boot/application/rp/Cargo.toml index 24f4218f1..be283fb27 100644 --- a/examples/boot/application/rp/Cargo.toml +++ b/examples/boot/application/rp/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-sync = { version = "0.6.2", path = "../../../../embassy-sync" } +embassy-sync = { version = "0.7.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [] } embassy-rp = { version = "0.4.0", path = "../../../../embassy-rp", features = ["time-driver", "rp2040"] } diff --git a/examples/boot/application/stm32f3/Cargo.toml b/examples/boot/application/stm32f3/Cargo.toml index 1e209eb9c..87f97071b 100644 --- a/examples/boot/application/stm32f3/Cargo.toml +++ b/examples/boot/application/stm32f3/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-sync = { version = "0.6.2", path = "../../../../embassy-sync" } +embassy-sync = { version = "0.7.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32f303re", "time-driver-any", "exti"] } diff --git a/examples/boot/application/stm32f7/Cargo.toml b/examples/boot/application/stm32f7/Cargo.toml index 877e239fa..d593a568e 100644 --- a/examples/boot/application/stm32f7/Cargo.toml +++ b/examples/boot/application/stm32f7/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-sync = { version = "0.6.2", path = "../../../../embassy-sync" } +embassy-sync = { version = "0.7.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32f767zi", "time-driver-any", "exti", "single-bank"] } diff --git a/examples/boot/application/stm32h7/Cargo.toml b/examples/boot/application/stm32h7/Cargo.toml index f28723835..7653d82ed 100644 --- a/examples/boot/application/stm32h7/Cargo.toml +++ b/examples/boot/application/stm32h7/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-sync = { version = "0.6.2", path = "../../../../embassy-sync" } +embassy-sync = { version = "0.7.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32h743zi", "time-driver-any", "exti"] } diff --git a/examples/boot/application/stm32l0/Cargo.toml b/examples/boot/application/stm32l0/Cargo.toml index f1cb55223..d1cace246 100644 --- a/examples/boot/application/stm32l0/Cargo.toml +++ b/examples/boot/application/stm32l0/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-sync = { version = "0.6.2", path = "../../../../embassy-sync" } +embassy-sync = { version = "0.7.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32l072cz", "time-driver-any", "exti", "memory-x"] } diff --git a/examples/boot/application/stm32l1/Cargo.toml b/examples/boot/application/stm32l1/Cargo.toml index 7c53e011d..034bf39af 100644 --- a/examples/boot/application/stm32l1/Cargo.toml +++ b/examples/boot/application/stm32l1/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-sync = { version = "0.6.2", path = "../../../../embassy-sync" } +embassy-sync = { version = "0.7.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32l151cb-a", "time-driver-any", "exti"] } diff --git a/examples/boot/application/stm32l4/Cargo.toml b/examples/boot/application/stm32l4/Cargo.toml index 9f5060802..d32cbca97 100644 --- a/examples/boot/application/stm32l4/Cargo.toml +++ b/examples/boot/application/stm32l4/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-sync = { version = "0.6.2", path = "../../../../embassy-sync" } +embassy-sync = { version = "0.7.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32l475vg", "time-driver-any", "exti"] } diff --git a/examples/boot/application/stm32wb-dfu/Cargo.toml b/examples/boot/application/stm32wb-dfu/Cargo.toml index d1cea8520..49b35f681 100644 --- a/examples/boot/application/stm32wb-dfu/Cargo.toml +++ b/examples/boot/application/stm32wb-dfu/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-sync = { version = "0.6.2", path = "../../../../embassy-sync" } +embassy-sync = { version = "0.7.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32wb55rg", "time-driver-any", "exti"] } diff --git a/examples/boot/application/stm32wl/Cargo.toml b/examples/boot/application/stm32wl/Cargo.toml index 54331dd69..e44d9859a 100644 --- a/examples/boot/application/stm32wl/Cargo.toml +++ b/examples/boot/application/stm32wl/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-sync = { version = "0.6.2", path = "../../../../embassy-sync" } +embassy-sync = { version = "0.7.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32wl55jc-cm4", "time-driver-any", "exti"] } diff --git a/examples/boot/bootloader/nrf/Cargo.toml b/examples/boot/bootloader/nrf/Cargo.toml index 4c2712718..897890ca4 100644 --- a/examples/boot/bootloader/nrf/Cargo.toml +++ b/examples/boot/bootloader/nrf/Cargo.toml @@ -12,7 +12,7 @@ defmt-rtt = { version = "1.0.0", optional = true } embassy-nrf = { path = "../../../../embassy-nrf", features = [] } embassy-boot-nrf = { path = "../../../../embassy-boot-nrf" } cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } -embassy-sync = { version = "0.6.2", path = "../../../../embassy-sync" } +embassy-sync = { version = "0.7.0", path = "../../../../embassy-sync" } cortex-m-rt = { version = "0.7" } cfg-if = "1.0.0" diff --git a/examples/boot/bootloader/rp/Cargo.toml b/examples/boot/bootloader/rp/Cargo.toml index c57b90793..090a581d4 100644 --- a/examples/boot/bootloader/rp/Cargo.toml +++ b/examples/boot/bootloader/rp/Cargo.toml @@ -11,7 +11,7 @@ defmt-rtt = { version = "1.0.0", optional = true } embassy-rp = { path = "../../../../embassy-rp", features = ["rp2040"] } embassy-boot-rp = { path = "../../../../embassy-boot-rp" } -embassy-sync = { version = "0.6.2", path = "../../../../embassy-sync" } +embassy-sync = { version = "0.7.0", path = "../../../../embassy-sync" } embassy-time = { path = "../../../../embassy-time", features = [] } cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } diff --git a/examples/boot/bootloader/stm32-dual-bank/Cargo.toml b/examples/boot/bootloader/stm32-dual-bank/Cargo.toml index a3ca96aec..67edc6a6c 100644 --- a/examples/boot/bootloader/stm32-dual-bank/Cargo.toml +++ b/examples/boot/bootloader/stm32-dual-bank/Cargo.toml @@ -15,7 +15,7 @@ cortex-m = { version = "0.7.6", features = [ "inline-asm", "critical-section-single-core", ] } -embassy-sync = { version = "0.6.2", path = "../../../../embassy-sync" } +embassy-sync = { version = "0.7.0", path = "../../../../embassy-sync" } cortex-m-rt = { version = "0.7" } embedded-storage = "0.3.1" embedded-storage-async = "0.4.0" diff --git a/examples/boot/bootloader/stm32/Cargo.toml b/examples/boot/bootloader/stm32/Cargo.toml index bdefa2cb5..fe81b5151 100644 --- a/examples/boot/bootloader/stm32/Cargo.toml +++ b/examples/boot/bootloader/stm32/Cargo.toml @@ -12,7 +12,7 @@ defmt-rtt = { version = "1.0.0", optional = true } embassy-stm32 = { path = "../../../../embassy-stm32", features = [] } embassy-boot-stm32 = { path = "../../../../embassy-boot-stm32" } cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } -embassy-sync = { version = "0.6.2", path = "../../../../embassy-sync" } +embassy-sync = { version = "0.7.0", path = "../../../../embassy-sync" } cortex-m-rt = { version = "0.7" } embedded-storage = "0.3.1" embedded-storage-async = "0.4.0" diff --git a/examples/boot/bootloader/stm32wb-dfu/Cargo.toml b/examples/boot/bootloader/stm32wb-dfu/Cargo.toml index 389f43641..738afb6ec 100644 --- a/examples/boot/bootloader/stm32wb-dfu/Cargo.toml +++ b/examples/boot/bootloader/stm32wb-dfu/Cargo.toml @@ -12,7 +12,7 @@ defmt-rtt = { version = "1.0.0", optional = true } embassy-stm32 = { path = "../../../../embassy-stm32", features = [] } embassy-boot-stm32 = { path = "../../../../embassy-boot-stm32" } cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } -embassy-sync = { version = "0.6.2", path = "../../../../embassy-sync" } +embassy-sync = { version = "0.7.0", path = "../../../../embassy-sync" } cortex-m-rt = { version = "0.7" } embedded-storage = "0.3.1" embedded-storage-async = "0.4.0" diff --git a/examples/lpc55s69/Cargo.toml b/examples/lpc55s69/Cargo.toml index 30ce0b799..7f81e9c7f 100644 --- a/examples/lpc55s69/Cargo.toml +++ b/examples/lpc55s69/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-nxp = { version = "0.1.0", path = "../../embassy-nxp", features = ["rt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt"] } -embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt"] } panic-halt = "1.0.0" cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } diff --git a/examples/mimxrt6/Cargo.toml b/examples/mimxrt6/Cargo.toml index 40cc0fb44..65cb9e3ca 100644 --- a/examples/mimxrt6/Cargo.toml +++ b/examples/mimxrt6/Cargo.toml @@ -14,7 +14,7 @@ embassy-executor = { version = "0.7.0", path = "../../embassy-executor", feature embassy-futures = { version = "0.1.1", path = "../../embassy-futures" } embassy-imxrt = { version = "0.1.0", path = "../../embassy-imxrt", features = ["defmt", "mimxrt685s", "unstable-pac", "time", "time-driver-os-timer"] } embassy-time = { version = "0.4", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } -embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["defmt"] } embedded-hal-1 = { package = "embedded-hal", version = "1.0" } embedded-hal-async = "1.0.0" diff --git a/examples/mspm0c1104/Cargo.toml b/examples/mspm0c1104/Cargo.toml index 7d419af51..79f9c0959 100644 --- a/examples/mspm0c1104/Cargo.toml +++ b/examples/mspm0c1104/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-mspm0 = { version = "0.1.0", path = "../../embassy-mspm0", features = ["mspm0c1104dgs20", "defmt", "rt", "time-driver-any"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt"] } -embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt"] } panic-halt = "1.0.0" cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } diff --git a/examples/mspm0g3507/Cargo.toml b/examples/mspm0g3507/Cargo.toml index 5a02b7249..b6621c9c5 100644 --- a/examples/mspm0g3507/Cargo.toml +++ b/examples/mspm0g3507/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-mspm0 = { version = "0.1.0", path = "../../embassy-mspm0", features = ["mspm0g3507pm", "defmt", "rt", "time-driver-any"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt"] } -embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt"] } panic-halt = "1.0.0" cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } diff --git a/examples/mspm0g3519/Cargo.toml b/examples/mspm0g3519/Cargo.toml index fc647a4ce..fd0e97c01 100644 --- a/examples/mspm0g3519/Cargo.toml +++ b/examples/mspm0g3519/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-mspm0 = { version = "0.1.0", path = "../../embassy-mspm0", features = ["mspm0g3519pz", "defmt", "rt", "time-driver-any"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt"] } -embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt"] } panic-halt = "1.0.0" cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } diff --git a/examples/mspm0l1306/Cargo.toml b/examples/mspm0l1306/Cargo.toml index 6f2f33b1e..6b1125810 100644 --- a/examples/mspm0l1306/Cargo.toml +++ b/examples/mspm0l1306/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-mspm0 = { version = "0.1.0", path = "../../embassy-mspm0", features = ["mspm0l1306rhb", "defmt", "rt", "time-driver-any"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt"] } -embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt"] } panic-halt = "1.0.0" cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } diff --git a/examples/mspm0l2228/Cargo.toml b/examples/mspm0l2228/Cargo.toml index a68b5bfe9..08dfd5ff6 100644 --- a/examples/mspm0l2228/Cargo.toml +++ b/examples/mspm0l2228/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-mspm0 = { version = "0.1.0", path = "../../embassy-mspm0", features = ["mspm0l2228pn", "defmt", "rt", "time-driver-any"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt"] } -embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt"] } panic-halt = "1.0.0" cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } diff --git a/examples/nrf-rtos-trace/Cargo.toml b/examples/nrf-rtos-trace/Cargo.toml index dcbaf87f8..d9e8ca2f9 100644 --- a/examples/nrf-rtos-trace/Cargo.toml +++ b/examples/nrf-rtos-trace/Cargo.toml @@ -15,7 +15,7 @@ log = [ ] [dependencies] -embassy-sync = { version = "0.6.2", path = "../../embassy-sync" } +embassy-sync = { version = "0.7.0", path = "../../embassy-sync" } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "rtos-trace"] } embassy-time = { version = "0.4.0", path = "../../embassy-time" } embassy-nrf = { version = "0.3.1", path = "../../embassy-nrf", features = ["nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] } diff --git a/examples/nrf52810/Cargo.toml b/examples/nrf52810/Cargo.toml index 5373278c1..87da89efe 100644 --- a/examples/nrf52810/Cargo.toml +++ b/examples/nrf52810/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } -embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.3.1", path = "../../embassy-nrf", features = ["defmt", "nrf52810", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } diff --git a/examples/nrf52840-rtic/Cargo.toml b/examples/nrf52840-rtic/Cargo.toml index 2eef012b7..afd269f72 100644 --- a/examples/nrf52840-rtic/Cargo.toml +++ b/examples/nrf52840-rtic/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" rtic = { version = "2", features = ["thumbv7-backend"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } -embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = [ "defmt", "defmt-timestamp-uptime"] } embassy-time-queue-utils = { version = "0.1", path = "../../embassy-time-queue-utils", features = ["generic-queue-8"] } embassy-nrf = { version = "0.3.1", path = "../../embassy-nrf", features = [ "defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } diff --git a/examples/nrf52840/Cargo.toml b/examples/nrf52840/Cargo.toml index 92127a8b0..4140e49d2 100644 --- a/examples/nrf52840/Cargo.toml +++ b/examples/nrf52840/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } -embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.3.1", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } diff --git a/examples/nrf5340/Cargo.toml b/examples/nrf5340/Cargo.toml index 42d7766b7..dc4fba4fd 100644 --- a/examples/nrf5340/Cargo.toml +++ b/examples/nrf5340/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } -embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.3.1", path = "../../embassy-nrf", features = ["defmt", "nrf5340-app-s", "time-driver-rtc1", "gpiote", "unstable-pac"] } diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index d19dd9dc7..c8a132a5e 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-embedded-hal = { version = "0.3.0", path = "../../embassy-embedded-hal", features = ["defmt"] } -embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-rp = { version = "0.4.0", path = "../../embassy-rp", features = ["defmt", "unstable-pac", "time-driver", "critical-section-impl", "rp2040"] } diff --git a/examples/rp235x/Cargo.toml b/examples/rp235x/Cargo.toml index ae64489ae..c81b79ae1 100644 --- a/examples/rp235x/Cargo.toml +++ b/examples/rp235x/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-embedded-hal = { version = "0.3.0", path = "../../embassy-embedded-hal", features = ["defmt"] } -embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-rp = { version = "0.4.0", path = "../../embassy-rp", features = ["defmt", "unstable-pac", "time-driver", "critical-section-impl", "rp235xa", "binary-info"] } diff --git a/examples/std/Cargo.toml b/examples/std/Cargo.toml index ff4b2fbbd..63740963d 100644 --- a/examples/std/Cargo.toml +++ b/examples/std/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["log"] } +embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["log"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-std", "executor-thread", "log"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["log", "std", ] } embassy-net = { version = "0.7.0", path = "../../embassy-net", features=[ "log", "medium-ethernet", "medium-ip", "tcp", "udp", "dns", "dhcpv4", "proto-ipv6"] } diff --git a/examples/stm32c0/Cargo.toml b/examples/stm32c0/Cargo.toml index 71f1cfda1..4cf07cef4 100644 --- a/examples/stm32c0/Cargo.toml +++ b/examples/stm32c0/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32c031c6 to your chip name, if necessary. embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32c031c6", "memory-x", "unstable-pac", "exti"] } -embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } diff --git a/examples/stm32f0/Cargo.toml b/examples/stm32f0/Cargo.toml index 534e8c33d..400e6b94c 100644 --- a/examples/stm32f0/Cargo.toml +++ b/examples/stm32f0/Cargo.toml @@ -12,7 +12,7 @@ cortex-m-rt = "0.7.0" defmt = "1.0.1" defmt-rtt = "1.0.0" panic-probe = { version = "1.0.0", features = ["print-defmt"] } -embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } static_cell = "2" diff --git a/examples/stm32f1/Cargo.toml b/examples/stm32f1/Cargo.toml index f856d2620..261733305 100644 --- a/examples/stm32f1/Cargo.toml +++ b/examples/stm32f1/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32f103c8 to your chip name, if necessary. embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f103c8", "unstable-pac", "memory-x", "time-driver-any" ] } -embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/stm32f2/Cargo.toml b/examples/stm32f2/Cargo.toml index f26cbfadc..905cffff0 100644 --- a/examples/stm32f2/Cargo.toml +++ b/examples/stm32f2/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32f207zg to your chip name, if necessary. embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f207zg", "unstable-pac", "memory-x", "time-driver-any", "exti"] } -embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } diff --git a/examples/stm32f3/Cargo.toml b/examples/stm32f3/Cargo.toml index 4c1dd881f..f675b0be1 100644 --- a/examples/stm32f3/Cargo.toml +++ b/examples/stm32f3/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32f303ze to your chip name, if necessary. embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f303ze", "unstable-pac", "memory-x", "time-driver-tim2", "exti"] } -embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/stm32f334/Cargo.toml b/examples/stm32f334/Cargo.toml index c28855b3a..b47a81e1b 100644 --- a/examples/stm32f334/Cargo.toml +++ b/examples/stm32f334/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f334r8", "unstable-pac", "memory-x", "time-driver-any", "exti"] } diff --git a/examples/stm32f4/Cargo.toml b/examples/stm32f4/Cargo.toml index 7374f8813..edab9ea00 100644 --- a/examples/stm32f4/Cargo.toml +++ b/examples/stm32f4/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32f429zi to your chip name, if necessary. embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = ["defmt", "stm32f429zi", "unstable-pac", "memory-x", "time-driver-tim4", "exti", "chrono"] } -embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defmt" ] } diff --git a/examples/stm32f7/Cargo.toml b/examples/stm32f7/Cargo.toml index bce521f30..c5801ea90 100644 --- a/examples/stm32f7/Cargo.toml +++ b/examples/stm32f7/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32f777zi to your chip name, if necessary. embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = ["defmt", "stm32f777zi", "memory-x", "unstable-pac", "time-driver-any", "exti", "single-bank"] } -embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.7.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } diff --git a/examples/stm32g0/Cargo.toml b/examples/stm32g0/Cargo.toml index 5e09b237e..bf1e7250e 100644 --- a/examples/stm32g0/Cargo.toml +++ b/examples/stm32g0/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32g0b1re to your chip name, if necessary. embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32g0b1re", "memory-x", "unstable-pac", "exti"] } -embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.4.0", path = "../../embassy-usb", default-features = false, features = ["defmt"] } diff --git a/examples/stm32g4/Cargo.toml b/examples/stm32g4/Cargo.toml index 582553a29..3d2c2aa7d 100644 --- a/examples/stm32g4/Cargo.toml +++ b/examples/stm32g4/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32g491re to your chip name, if necessary. embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32g491re", "memory-x", "unstable-pac", "exti"] } -embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/stm32h5/Cargo.toml b/examples/stm32h5/Cargo.toml index 3e022e4e5..f3fda7ff3 100644 --- a/examples/stm32h5/Cargo.toml +++ b/examples/stm32h5/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32h563zi to your chip name, if necessary. embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = ["defmt", "stm32h563zi", "memory-x", "time-driver-any", "exti", "unstable-pac", "low-power"] } -embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.7.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6"] } diff --git a/examples/stm32h7/Cargo.toml b/examples/stm32h7/Cargo.toml index 520d0c8e6..27c59d980 100644 --- a/examples/stm32h7/Cargo.toml +++ b/examples/stm32h7/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32h743bi to your chip name, if necessary. embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = ["defmt", "stm32h743bi", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } -embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["defmt"] } embassy-embedded-hal = { version = "0.3.0", path = "../../embassy-embedded-hal" } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } diff --git a/examples/stm32h723/Cargo.toml b/examples/stm32h723/Cargo.toml index 1eb706b4d..fb219733f 100644 --- a/examples/stm32h723/Cargo.toml +++ b/examples/stm32h723/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32h723zg to your chip name, if necessary. embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = ["defmt", "stm32h723zg", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } -embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32h735/Cargo.toml b/examples/stm32h735/Cargo.toml index 2ce989e6f..8d23c346a 100644 --- a/examples/stm32h735/Cargo.toml +++ b/examples/stm32h735/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = ["defmt", "stm32h735ig", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } -embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["defmt"] } embassy-embedded-hal = { version = "0.3.0", path = "../../embassy-embedded-hal" } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } diff --git a/examples/stm32h742/Cargo.toml b/examples/stm32h742/Cargo.toml index c3bf39e13..31eff4379 100644 --- a/examples/stm32h742/Cargo.toml +++ b/examples/stm32h742/Cargo.toml @@ -14,7 +14,7 @@ embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [ "time-driver-any", "exti", ] } -embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = [ +embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = [ "defmt", ] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = [ diff --git a/examples/stm32h755cm4/Cargo.toml b/examples/stm32h755cm4/Cargo.toml index c97ac447e..71bd50d60 100644 --- a/examples/stm32h755cm4/Cargo.toml +++ b/examples/stm32h755cm4/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32h755zi-cm4 to your chip name, if necessary. embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = ["defmt", "stm32h755zi-cm4", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } -embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["defmt"] } embassy-embedded-hal = { version = "0.3.0", path = "../../embassy-embedded-hal" } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } diff --git a/examples/stm32h755cm7/Cargo.toml b/examples/stm32h755cm7/Cargo.toml index 3843d5d43..8e960932a 100644 --- a/examples/stm32h755cm7/Cargo.toml +++ b/examples/stm32h755cm7/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32h743bi to your chip name, if necessary. embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = ["defmt", "stm32h755zi-cm7", "time-driver-tim3", "exti", "memory-x", "unstable-pac", "chrono"] } -embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["defmt"] } embassy-embedded-hal = { version = "0.3.0", path = "../../embassy-embedded-hal" } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } diff --git a/examples/stm32h7b0/Cargo.toml b/examples/stm32h7b0/Cargo.toml index e4f1080ac..72f86e0cf 100644 --- a/examples/stm32h7b0/Cargo.toml +++ b/examples/stm32h7b0/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = ["defmt", "stm32h7b0vb", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } -embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["defmt"] } embassy-embedded-hal = { version = "0.3.0", path = "../../embassy-embedded-hal" } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } diff --git a/examples/stm32h7rs/Cargo.toml b/examples/stm32h7rs/Cargo.toml index 58f8b1274..5f1ce8dfc 100644 --- a/examples/stm32h7rs/Cargo.toml +++ b/examples/stm32h7rs/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32h743bi to your chip name, if necessary. embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = ["defmt", "stm32h7s3l8", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } -embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.7.0", path = "../../embassy-net", features = ["defmt", "udp", "medium-ethernet", "medium-ip", "proto-ipv4"] } diff --git a/examples/stm32l0/Cargo.toml b/examples/stm32l0/Cargo.toml index ce54ad9fb..3101cf7ce 100644 --- a/examples/stm32l0/Cargo.toml +++ b/examples/stm32l0/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32l072cz to your chip name, if necessary. embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = ["defmt", "stm32l073rz", "unstable-pac", "time-driver-any", "exti", "memory-x"] } -embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } diff --git a/examples/stm32l1/Cargo.toml b/examples/stm32l1/Cargo.toml index a780f9290..a0a7916a7 100644 --- a/examples/stm32l1/Cargo.toml +++ b/examples/stm32l1/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.0" license = "MIT OR Apache-2.0" [dependencies] -embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [ "defmt", "stm32l151cb-a", "time-driver-any", "memory-x"] } diff --git a/examples/stm32l4/Cargo.toml b/examples/stm32l4/Cargo.toml index 5c4dce482..7da09e5b0 100644 --- a/examples/stm32l4/Cargo.toml +++ b/examples/stm32l4/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32l4s5vi to your chip name, if necessary. embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32l4r5zi", "memory-x", "time-driver-any", "exti", "chrono", "dual-bank"] } -embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768", ] } embassy-embedded-hal = { version = "0.3.0", path = "../../embassy-embedded-hal" } diff --git a/examples/stm32l432/Cargo.toml b/examples/stm32l432/Cargo.toml index ac7e507de..c38462355 100644 --- a/examples/stm32l432/Cargo.toml +++ b/examples/stm32l432/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32l4s5vi to your chip name, if necessary. embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32l432kc", "memory-x", "time-driver-any", "exti", "chrono"] } -embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = [ "defmt" ] } +embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = [ "defmt" ] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = [ "arch-cortex-m", "executor-thread", "defmt" ] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = [ "defmt", "defmt-timestamp-uptime", "tick-hz-32_768" ] } defmt = "1.0.1" diff --git a/examples/stm32l5/Cargo.toml b/examples/stm32l5/Cargo.toml index 138276b7f..3ea3bcd5c 100644 --- a/examples/stm32l5/Cargo.toml +++ b/examples/stm32l5/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32l552ze to your chip name, if necessary. embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32l552ze", "time-driver-any", "exti", "memory-x", "low-power", "dual-bank"] } -embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/stm32u0/Cargo.toml b/examples/stm32u0/Cargo.toml index 86cff2321..3aa45dc79 100644 --- a/examples/stm32u0/Cargo.toml +++ b/examples/stm32u0/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32u083rc to your chip name, if necessary. embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32u083rc", "memory-x", "unstable-pac", "exti", "chrono"] } -embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.4.0", path = "../../embassy-usb", default-features = false, features = ["defmt"] } diff --git a/examples/stm32u5/Cargo.toml b/examples/stm32u5/Cargo.toml index 94f77ce2f..777d3ed4c 100644 --- a/examples/stm32u5/Cargo.toml +++ b/examples/stm32u5/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32u5g9zj to your chip name, if necessary. embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = ["defmt", "unstable-pac", "stm32u5g9zj", "time-driver-any", "memory-x" ] } -embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.4.0", path = "../../embassy-usb", features = ["defmt"] } diff --git a/examples/stm32wb/Cargo.toml b/examples/stm32wb/Cargo.toml index a83871d4d..dbe9660e2 100644 --- a/examples/stm32wb/Cargo.toml +++ b/examples/stm32wb/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" # Change stm32wb55rg to your chip name in both dependencies, if necessary. embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [ "defmt", "stm32wb55rg", "time-driver-any", "memory-x", "exti"] } embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", features = ["defmt", "stm32wb55rg"] } -embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.7.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", ], optional = true } diff --git a/examples/stm32wba/Cargo.toml b/examples/stm32wba/Cargo.toml index b87ca88bf..2c638f9f4 100644 --- a/examples/stm32wba/Cargo.toml +++ b/examples/stm32wba/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [ "defmt", "stm32wba55cg", "time-driver-any", "memory-x", "exti"] } -embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.7.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", ], optional = true } diff --git a/examples/stm32wl/Cargo.toml b/examples/stm32wl/Cargo.toml index 1b6a23bed..5ecd77443 100644 --- a/examples/stm32wl/Cargo.toml +++ b/examples/stm32wl/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] # Change stm32wl55jc-cm4 to your chip name, if necessary. embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = ["defmt", "stm32wl55jc-cm4", "time-driver-any", "memory-x", "unstable-pac", "exti", "chrono"] } -embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-embedded-hal = { version = "0.3.0", path = "../../embassy-embedded-hal" } diff --git a/examples/wasm/Cargo.toml b/examples/wasm/Cargo.toml index 3a27f913c..9e553f52b 100644 --- a/examples/wasm/Cargo.toml +++ b/examples/wasm/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" crate-type = ["cdylib"] [dependencies] -embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["log"] } +embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["log"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-wasm", "executor-thread", "log"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["log", "wasm", ] } diff --git a/tests/mspm0/Cargo.toml b/tests/mspm0/Cargo.toml index 386536bee..298522d09 100644 --- a/tests/mspm0/Cargo.toml +++ b/tests/mspm0/Cargo.toml @@ -10,7 +10,7 @@ mspm0g3507 = [ "embassy-mspm0/mspm0g3507pm" ] [dependencies] teleprobe-meta = "1.1" -embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = [ "defmt" ] } +embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = [ "defmt" ] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = [ "arch-cortex-m", "executor-thread", "defmt" ] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = [ "defmt" ] } embassy-mspm0 = { version = "0.1.0", path = "../../embassy-mspm0", features = [ "rt", "defmt", "unstable-pac", "time-driver-any" ] } diff --git a/tests/nrf/Cargo.toml b/tests/nrf/Cargo.toml index 32087940e..30c4223b7 100644 --- a/tests/nrf/Cargo.toml +++ b/tests/nrf/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" teleprobe-meta = "1" embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } -embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt", ] } +embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["defmt", ] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.3.1", path = "../../embassy-nrf", features = ["defmt", "time-driver-rtc1", "gpiote", "unstable-pac"] } diff --git a/tests/riscv32/Cargo.toml b/tests/riscv32/Cargo.toml index 446326d8a..c5f6a1194 100644 --- a/tests/riscv32/Cargo.toml +++ b/tests/riscv32/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] critical-section = { version = "1.1.1", features = ["restore-state-bool"] } -embassy-sync = { version = "0.6.2", path = "../../embassy-sync" } +embassy-sync = { version = "0.7.0", path = "../../embassy-sync" } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-riscv32", "executor-thread"] } embassy-time = { version = "0.4.0", path = "../../embassy-time" } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/tests/rp/Cargo.toml b/tests/rp/Cargo.toml index 2c2ed73cc..2be37f525 100644 --- a/tests/rp/Cargo.toml +++ b/tests/rp/Cargo.toml @@ -12,7 +12,7 @@ rp235xb = ["embassy-rp/rp235xb"] [dependencies] teleprobe-meta = "1.1" -embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", ] } embassy-rp = { version = "0.4.0", path = "../../embassy-rp", features = [ "defmt", "unstable-pac", "time-driver", "critical-section-impl", "intrinsics", "rom-v2-intrinsics", "run-from-ram"] } diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml index 6036a5a97..e78520e40 100644 --- a/tests/stm32/Cargo.toml +++ b/tests/stm32/Cargo.toml @@ -61,7 +61,7 @@ cm0 = ["portable-atomic/unsafe-assume-single-core"] [dependencies] teleprobe-meta = "1" -embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } +embassy-sync = { version = "0.7.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "tick-hz-131_072", "defmt-timestamp-uptime"] } embassy-stm32 = { version = "0.2.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "memory-x", "time-driver-any"] } From 43ff562b5a0327d575d2c02f299ad6d15680384e Mon Sep 17 00:00:00 2001 From: jubeormk1 Date: Thu, 22 May 2025 15:41:43 +1000 Subject: [PATCH 1180/1217] Adjustments for std examples I extended the README.md file to extend instructions for the rest of network examples I modified the tap.sh script to give ownership to the user running it and avoiding running the examples with sudo. This would help someone using a debuger. --- examples/std/README.md | 115 +++++++++++++++++++++++++++++++++++++++-- examples/std/tap.sh | 2 +- 2 files changed, 112 insertions(+), 5 deletions(-) diff --git a/examples/std/README.md b/examples/std/README.md index dcc152fc2..5d7c384ae 100644 --- a/examples/std/README.md +++ b/examples/std/README.md @@ -1,19 +1,126 @@ ## Running the `embassy-net` examples -First, create the tap99 interface. (The number was chosen to +To run `net`, `tcp_accept`, `net_udp` examples you will need a tap interface. Before running any example, create the tap99 interface. (The number was chosen to hopefully not collide with anything.) You only need to do -this once. +this once every time you reboot your computer. ```sh sudo sh tap.sh ``` -Second, have something listening there. For example `nc -lp 8000` +### `net` example + +For this example, you need to have something listening in the correct port. For example `nc -lp 8000`. Then run the example located in the `examples` folder: ```sh cd $EMBASSY_ROOT/examples/std/ -sudo cargo run --bin net -- --tap tap99 --static-ip +cargo run --bin net -- --tap tap99 --static-ip +``` +### `tcp_accept` example + +This example listen for a tcp connection. + +First run the example located in the `examples` folder: + +```sh +cd $EMBASSY_ROOT/examples/std/ +cargo run --bin tcp_accept -- --tap tap99 --static-ip +``` + +Then open a connection to the port. For example `nc 192.168.69.2 9999`. + +### `net_udp` example + +This example listen for a udp connection. + +First run the example located in the `examples` folder: + +```sh +cd $EMBASSY_ROOT/examples/std/ +cargo run --bin net_udp -- --tap tap99 --static-ip +``` + +Then open a connection to the port. For example `nc -u 192.168.69.2 9400`. + +### `net_dns` example + +This example queries a `DNS` for the IP address of `www.example.com`. + +In order to achieve this, the `tap99` interface requires configuring tap99 as a gateway device temporarily. + +For example, in Ubuntu you can do this by: + +1. Identifying your default route device. In the next example `eth0` + +```sh +ip r | grep "default" +default via 192.168.2.1 dev eth0 proto kernel metric 35 +``` + +2. Enabling temporarily IP Forwarding: + +```sh +sudo sysctl -w net.ipv4.ip_forward=1 +``` + +3. Configuring NAT to mascarade traffic from `tap99` to `eth0` + +```sh +sudo iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE +sudo iptables -A FORWARD -i tap99 -j ACCEPT +sudo iptables -A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT +``` + +4. Then you can run the example located in the `examples` folder: + +```sh +cd $EMBASSY_ROOT/examples/std/ +cargo run --bin net_dns -- --tap tap99 --static-ip +``` + +### `net_ppp` example + +This example establish a Point-to-Point Protocol (PPP) connection that can be used, for example, for connecting to internet through a 4G modem via a serial channel. + +The example creates a PPP bridge over a virtual serial channel between `pty1` and `pty2` for the example code and a PPP server running on the same computer. + +To run this example you will need: +- ppp (pppd server) +- socat (socket CAT) + +To run the examples you may follow the next steps: + +1. Save the PPP server configuration: +```sh +sudo sh -c 'echo "myuser $(hostname) mypass 192.168.7.10" >> /etc/ppp/pap-secrets' +``` + +2. Create a files `pty1` and `pty2` and link them +```sh +cd $EMBASSY_ROOT/examples/std/ +socat -v -x PTY,link=pty1,rawer PTY,link=pty2,rawer +``` + +3. open a second terminal and start the PPP server: +```sh +cd $EMBASSY_ROOT/examples/std/ +sudo pppd $PWD/pty1 115200 192.168.7.1: ms-dns 8.8.4.4 ms-dns 8.8.8.8 nodetach debug local persist silent +``` + +4. Open a third terminal and run the example +```sh +cd $EMBASSY_ROOT/examples/std/ +RUST_LOG=trace cargo run --bin net_ppp -- --device pty2 +``` +5. Observe the output in the second and third terminal +6. Open one last terminal to interact with `net_ppp` example through the PPP connection +```sh +# ping the net_ppp client +ping 192.168.7.10 +# open an tcp connection +nc 192.168.7.10 1234 +# Type anything and observe the output in the different terminals ``` diff --git a/examples/std/tap.sh b/examples/std/tap.sh index 39d92a099..fb89d2381 100644 --- a/examples/std/tap.sh +++ b/examples/std/tap.sh @@ -1,4 +1,4 @@ -ip tuntap add name tap99 mode tap user $USER +ip tuntap add name tap99 mode tap user $SUDO_USER ip link set tap99 up ip addr add 192.168.69.100/24 dev tap99 ip -6 addr add fe80::100/64 dev tap99 From bc80903d0affb0cff6f97b8da64d2ddb6549a5fb Mon Sep 17 00:00:00 2001 From: jubeormk1 Date: Thu, 22 May 2025 15:47:11 +1000 Subject: [PATCH 1181/1217] Added some notes for net_ppp example --- examples/std/README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/examples/std/README.md b/examples/std/README.md index 5d7c384ae..ac2c2a1a6 100644 --- a/examples/std/README.md +++ b/examples/std/README.md @@ -1,14 +1,16 @@ ## Running the `embassy-net` examples -To run `net`, `tcp_accept`, `net_udp` examples you will need a tap interface. Before running any example, create the tap99 interface. (The number was chosen to -hopefully not collide with anything.) You only need to do -this once every time you reboot your computer. +To run `net`, `tcp_accept`, `net_udp` and `net_dns` examples you will need a tap interface. Before running these examples, create the tap99 interface. (The number was chosen to +hopefully not collide with anything.) You only need to do this once every time you reboot your computer. ```sh +cd $EMBASSY_ROOT/examples/std/ sudo sh tap.sh ``` +The example `net_ppp` requires different steps that are detailed in its section. + ### `net` example For this example, you need to have something listening in the correct port. For example `nc -lp 8000`. From 3c3c7877cd31b84fb5dcf976e05d4eab66ddeaee Mon Sep 17 00:00:00 2001 From: RaulIQ Date: Thu, 22 May 2025 10:44:38 +0300 Subject: [PATCH 1182/1217] format simple_pwm.rs with rustfmt --- embassy-stm32/src/timer/simple_pwm.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs index 972a3852c..d356bb4b4 100644 --- a/embassy-stm32/src/timer/simple_pwm.rs +++ b/embassy-stm32/src/timer/simple_pwm.rs @@ -383,11 +383,11 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> { } /// Generate a multichannel sequence of PWM waveforms using DMA triggered by timer update events. - /// + /// /// This method utilizes the timer's DMA burst transfer capability to update multiple CCRx registers /// in sequence on each update event (UEV). The data is written via the DMAR register using the /// DMA base address (DBA) and burst length (DBL) configured in the DCR register. - /// + /// /// The `duty` buffer must be structured as a flattened 2D array in row-major order, where each row /// represents a single update event and each column corresponds to a specific timer channel (starting /// from `starting_channel` up to and including `ending_channel`). @@ -405,7 +405,7 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> { /// /// Each group of N values (where N = number of channels) is transferred on one update event, /// updating the duty cycles of all selected channels simultaneously. - /// + /// /// Note: /// you will need to provide corresponding TIMx_UP DMA channel to use this method. pub async fn waveform_up_multi_channel( @@ -466,7 +466,6 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> { self.inner.enable_update_dma(false); } } - } macro_rules! impl_waveform_chx { From 967ae161a0dfe996635866b7c7139d02bc5882b9 Mon Sep 17 00:00:00 2001 From: RaulIQ Date: Thu, 22 May 2025 10:56:48 +0300 Subject: [PATCH 1183/1217] doc: update documentation to pass test --- embassy-stm32/src/timer/simple_pwm.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs index d356bb4b4..f7f433154 100644 --- a/embassy-stm32/src/timer/simple_pwm.rs +++ b/embassy-stm32/src/timer/simple_pwm.rs @@ -394,14 +394,12 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> { /// /// For example, if using channels 1 through 4, a buffer of 4 update steps might look like: /// - /// ```rust /// let dma_buf: [u16; 16] = [ /// ch1_duty_1, ch2_duty_1, ch3_duty_1, ch4_duty_1, // update 1 /// ch1_duty_2, ch2_duty_2, ch3_duty_2, ch4_duty_2, // update 2 /// ch1_duty_3, ch2_duty_3, ch3_duty_3, ch4_duty_3, // update 3 /// ch1_duty_4, ch2_duty_4, ch3_duty_4, ch4_duty_4, // update 4 /// ]; - /// ``` /// /// Each group of N values (where N = number of channels) is transferred on one update event, /// updating the duty cycles of all selected channels simultaneously. From 9baf5fc5eb8b317c7ac86ddd7bdc7434fbe7c26c Mon Sep 17 00:00:00 2001 From: MatrixSenpai Date: Thu, 22 May 2025 10:54:24 -0500 Subject: [PATCH 1184/1217] adding compatibility with ws2812 leds that have 4 addressable lights --- embassy-rp/src/pio_programs/ws2812.rs | 71 +++++++++++++++++++++++++-- 1 file changed, 67 insertions(+), 4 deletions(-) diff --git a/embassy-rp/src/pio_programs/ws2812.rs b/embassy-rp/src/pio_programs/ws2812.rs index 578937e11..f257bfcdc 100644 --- a/embassy-rp/src/pio_programs/ws2812.rs +++ b/embassy-rp/src/pio_programs/ws2812.rs @@ -2,7 +2,7 @@ use embassy_time::Timer; use fixed::types::U24F8; -use smart_leds::RGB8; +use smart_leds::{RGB8, RGBW}; use crate::clocks::clk_sys_freq; use crate::dma::{AnyChannel, Channel}; @@ -50,14 +50,14 @@ impl<'a, PIO: Instance> PioWs2812Program<'a, PIO> { } } -/// Pio backed ws2812 driver +/// Pio backed RGB ws2812 driver /// Const N is the number of ws2812 leds attached to this pin -pub struct PioWs2812<'d, P: Instance, const S: usize, const N: usize> { +pub struct RgbPioWs2812<'d, P: Instance, const S: usize, const N: usize> { dma: Peri<'d, AnyChannel>, sm: StateMachine<'d, P, S>, } -impl<'d, P: Instance, const S: usize, const N: usize> PioWs2812<'d, P, S, N> { +impl<'d, P: Instance, const S: usize, const N: usize> RgbPioWs2812<'d, P, S, N> { /// Configure a pio state machine to use the loaded ws2812 program. pub fn new( pio: &mut Common<'d, P>, @@ -111,3 +111,66 @@ impl<'d, P: Instance, const S: usize, const N: usize> PioWs2812<'d, P, S, N> { Timer::after_micros(55).await; } } + +/// Pio backed RGBW ws2812 driver +/// This version is intended for ws2812 leds with 4 addressable lights +/// Const N is the number of ws2812 leds attached to this pin +pub struct RgbwPioWs2812<'d, P: Instance, const S: usize, const N: usize> { + dma: Peri<'d, AnyChannel>, + sm: StateMachine<'d, P, S>, +} + +impl<'d, P: Instance, const S: usize, const N: usize> RgbwPioWs2812<'d, P, S, N> { + /// Configure a pio state machine to use the loaded ws2812 program. + pub fn new( + pio: &mut Common<'d, P>, + mut sm: StateMachine<'d, P, S>, + dma: Peri<'d, impl Channel>, + pin: Peri<'d, impl PioPin>, + program: &PioWs2812Program<'d, P>, + ) -> Self { + // Setup sm0 + let mut cfg = Config::default(); + + // Pin config + let out_pin = pio.make_pio_pin(pin); + cfg.set_out_pins(&[&out_pin]); + cfg.set_set_pins(&[&out_pin]); + + cfg.use_program(&program.prg, &[&out_pin]); + + // Clock config, measured in kHz to avoid overflows + let clock_freq = U24F8::from_num(clk_sys_freq() / 1000); + let ws2812_freq = U24F8::from_num(800); + let bit_freq = ws2812_freq * CYCLES_PER_BIT; + cfg.clock_divider = clock_freq / bit_freq; + + // FIFO config + cfg.fifo_join = FifoJoin::TxOnly; + cfg.shift_out = ShiftConfig { + auto_fill: true, + threshold: 32, + direction: ShiftDirection::Left, + }; + + sm.set_config(&cfg); + sm.set_enable(true); + + Self { dma: dma.into(), sm } + } + + /// Write a buffer of [smart_leds::RGBW] to the ws2812 string + pub async fn write(&mut self, colors: &[RGBW; N]) { + // Precompute the word bytes from the colors + let mut words = [0u32; N]; + for i in 0..N { + let word = (u32::from(colors[i].g) << 24) | (u32::from(colors[i].r) << 16) | (u32::from(colors[i].b) << 8) | u32::from(colors[i].a.0); + words[i] = word; + } + + // DMA transfer + self.sm.tx().dma_push(self.dma.reborrow(), &words, false).await; + + Timer::after_micros(55).await; + } +} From 7eaea84fb769f739f884bc0a474b518b65c126e4 Mon Sep 17 00:00:00 2001 From: MatrixSenpai Date: Thu, 22 May 2025 11:04:30 -0500 Subject: [PATCH 1185/1217] rustfmt --- embassy-rp/src/pio_programs/ws2812.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/embassy-rp/src/pio_programs/ws2812.rs b/embassy-rp/src/pio_programs/ws2812.rs index f257bfcdc..37dd1c4e0 100644 --- a/embassy-rp/src/pio_programs/ws2812.rs +++ b/embassy-rp/src/pio_programs/ws2812.rs @@ -52,12 +52,12 @@ impl<'a, PIO: Instance> PioWs2812Program<'a, PIO> { /// Pio backed RGB ws2812 driver /// Const N is the number of ws2812 leds attached to this pin -pub struct RgbPioWs2812<'d, P: Instance, const S: usize, const N: usize> { +pub struct PioWs2812<'d, P: Instance, const S: usize, const N: usize> { dma: Peri<'d, AnyChannel>, sm: StateMachine<'d, P, S>, } -impl<'d, P: Instance, const S: usize, const N: usize> RgbPioWs2812<'d, P, S, N> { +impl<'d, P: Instance, const S: usize, const N: usize> PioWs2812<'d, P, S, N> { /// Configure a pio state machine to use the loaded ws2812 program. pub fn new( pio: &mut Common<'d, P>, @@ -164,7 +164,10 @@ impl<'d, P: Instance, const S: usize, const N: usize> RgbwPioWs2812<'d, P, S, N> // Precompute the word bytes from the colors let mut words = [0u32; N]; for i in 0..N { - let word = (u32::from(colors[i].g) << 24) | (u32::from(colors[i].r) << 16) | (u32::from(colors[i].b) << 8) | u32::from(colors[i].a.0); + let word = (u32::from(colors[i].g) << 24) + | (u32::from(colors[i].r) << 16) + | (u32::from(colors[i].b) << 8) + | u32::from(colors[i].a.0); words[i] = word; } From ea36d121db8dc71ebd205040cdd4b99fe5c2086c Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 22 May 2025 14:01:40 -0700 Subject: [PATCH 1186/1217] embassy-rp: implement input/output inversion RP2040/RP23xx support inversion in HW of the inputs and outputs. Implement minimal support for that. --- embassy-rp/src/gpio.rs | 38 ++++++++++++++++++++++++++++++++++++++ tests/rp/src/bin/gpio.rs | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+) diff --git a/embassy-rp/src/gpio.rs b/embassy-rp/src/gpio.rs index 2fb2d65c2..9b5faac15 100644 --- a/embassy-rp/src/gpio.rs +++ b/embassy-rp/src/gpio.rs @@ -146,6 +146,12 @@ impl<'d> Input<'d> { self.pin.get_level() } + /// Configure the input logic inversion of this pin. + #[inline] + pub fn set_inversion(&mut self, invert: bool) { + self.pin.set_input_inversion(invert) + } + /// Wait until the pin is high. If it is already high, return immediately. #[inline] pub async fn wait_for_high(&mut self) { @@ -382,6 +388,12 @@ impl<'d> Output<'d> { self.pin.set_slew_rate(slew_rate) } + /// Configure the output logic inversion of this pin. + #[inline] + pub fn set_inversion(&mut self, invert: bool) { + self.pin.set_output_inversion(invert) + } + /// Set the output as high. #[inline] pub fn set_high(&mut self) { @@ -685,6 +697,30 @@ impl<'d> Flex<'d> { self.pin.sio_oe().value_xor().write_value(self.bit()) } + /// Configure the input logic inversion of this pin. + #[inline] + pub fn set_input_inversion(&mut self, invert: bool) { + self.pin.gpio().ctrl().modify(|w| { + w.set_inover(if invert { + pac::io::vals::Inover::INVERT + } else { + pac::io::vals::Inover::NORMAL + }) + }); + } + + /// Configure the output logic inversion of this pin. + #[inline] + pub fn set_output_inversion(&mut self, invert: bool) { + self.pin.gpio().ctrl().modify(|w| { + w.set_outover(if invert { + pac::io::vals::Outover::INVERT + } else { + pac::io::vals::Outover::NORMAL + }) + }); + } + /// Get whether the pin input level is high. #[inline] pub fn is_high(&self) -> bool { @@ -815,6 +851,8 @@ impl<'d> Drop for Flex<'d> { self.pin.pad_ctrl().write(|_| {}); self.pin.gpio().ctrl().write(|w| { w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::NULL as _); + w.set_inover(pac::io::vals::Inover::NORMAL); + w.set_outover(pac::io::vals::Outover::NORMAL); }); self.pin.io().int_dormant_wake().inte(idx / 8).write_clear(|w| { w.set_edge_high(idx % 8, true); diff --git a/tests/rp/src/bin/gpio.rs b/tests/rp/src/bin/gpio.rs index 614b6317a..8bd0df8d8 100644 --- a/tests/rp/src/bin/gpio.rs +++ b/tests/rp/src/bin/gpio.rs @@ -67,6 +67,40 @@ async fn main(_spawner: Spawner) { } } + // Test input inversion + { + let mut b = Input::new(b.reborrow(), Pull::None); + b.set_inversion(true); + // no pull, the status is undefined + + let mut a = Output::new(a.reborrow(), Level::Low); + delay(); + assert!(b.is_high()); + a.set_high(); + delay(); + assert!(b.is_low()); + + b.set_inversion(false); + a.set_inversion(true); + + a.set_low(); + delay(); + assert!(b.is_high()); + + a.set_high(); + delay(); + assert!(b.is_low()); + + b.set_inversion(true); + a.set_high(); + delay(); + assert!(b.is_high()); + + a.set_high(); + delay(); + assert!(b.is_high()); + } + // Test input no pull { let b = Input::new(b.reborrow(), Pull::None); From 2d1652c53268ef1ac36b8d7ea6be9bf31dd79586 Mon Sep 17 00:00:00 2001 From: Matthew Tran <0e4ef622@gmail.com> Date: Thu, 22 May 2025 23:53:18 -0500 Subject: [PATCH 1187/1217] nrf: Enable TEMP driver for nrf5340-net --- embassy-nrf/src/chips/nrf5340_net.rs | 3 +++ embassy-nrf/src/lib.rs | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/embassy-nrf/src/chips/nrf5340_net.rs b/embassy-nrf/src/chips/nrf5340_net.rs index c2932be31..d4c3e5353 100644 --- a/embassy-nrf/src/chips/nrf5340_net.rs +++ b/embassy-nrf/src/chips/nrf5340_net.rs @@ -201,6 +201,9 @@ embassy_hal_internal::peripherals! { // EGU EGU0, + + // TEMP + TEMP, } impl_ipc!(IPC, IPC, IPC); diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index 398bfed48..9d44ae7e6 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs @@ -149,7 +149,7 @@ pub mod spim; #[cfg(not(feature = "_nrf51"))] pub mod spis; #[cfg(not(feature = "_nrf54l"))] // TODO -#[cfg(not(any(feature = "_nrf5340", feature = "_nrf91")))] +#[cfg(not(any(feature = "_nrf5340-app", feature = "_nrf91")))] pub mod temp; #[cfg(not(feature = "_nrf54l"))] // TODO pub mod timer; From 68a45490fc1675f2171131ccbf01f690c4123f01 Mon Sep 17 00:00:00 2001 From: Gerhard de Clercq <11624490+Gerharddc@users.noreply.github.com> Date: Tue, 15 Apr 2025 20:16:09 +0200 Subject: [PATCH 1188/1217] [embassy-usb-dfu] support ed25519 verification This commit adds the ability to verify that USB DFU updates are correctly signed using ed25519. This required adding support to embassy-boot for reading from the DFU partition. --- ci.sh | 1 + embassy-boot/src/firmware_updater/asynch.rs | 11 +++++++ embassy-boot/src/firmware_updater/blocking.rs | 11 +++++++ embassy-usb-dfu/Cargo.toml | 5 +++ embassy-usb-dfu/README.md | 6 ++++ embassy-usb-dfu/src/dfu.rs | 33 +++++++++++++++++-- .../boot/application/stm32wb-dfu/memory.x | 8 ++--- .../application/stm32wb-dfu/secrets/key.sec | 2 ++ .../boot/bootloader/stm32wb-dfu/Cargo.toml | 1 + .../boot/bootloader/stm32wb-dfu/README.md | 26 +++++++++++++++ examples/boot/bootloader/stm32wb-dfu/memory.x | 8 ++--- .../stm32wb-dfu/secrets/key.pub.short | 1 + .../boot/bootloader/stm32wb-dfu/src/main.rs | 12 +++++++ 13 files changed, 114 insertions(+), 11 deletions(-) create mode 100644 examples/boot/application/stm32wb-dfu/secrets/key.sec create mode 100644 examples/boot/bootloader/stm32wb-dfu/secrets/key.pub.short diff --git a/ci.sh b/ci.sh index 2be84ef6b..dce0d7b13 100755 --- a/ci.sh +++ b/ci.sh @@ -282,6 +282,7 @@ cargo batch \ --- build --release --manifest-path examples/boot/bootloader/rp/Cargo.toml --target thumbv6m-none-eabi \ --- build --release --manifest-path examples/boot/bootloader/stm32/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32l496zg \ --- build --release --manifest-path examples/boot/bootloader/stm32wb-dfu/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32wb55rg \ + --- build --release --manifest-path examples/boot/bootloader/stm32wb-dfu/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32wb55rg,verify \ --- build --release --manifest-path examples/boot/bootloader/stm32-dual-bank/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32h743zi \ --- build --release --manifest-path examples/wasm/Cargo.toml --target wasm32-unknown-unknown --artifact-dir out/examples/wasm \ --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f103c8 --artifact-dir out/tests/stm32f103c8 \ diff --git a/embassy-boot/src/firmware_updater/asynch.rs b/embassy-boot/src/firmware_updater/asynch.rs index 0dc09e18d..66e311e38 100644 --- a/embassy-boot/src/firmware_updater/asynch.rs +++ b/embassy-boot/src/firmware_updater/asynch.rs @@ -161,6 +161,17 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> FirmwareUpdater<'d, DFU, STATE> { Ok(()) } + /// Read a slice of data from the DFU storage peripheral, starting the read + /// operation at the given address offset, and reading `buf.len()` bytes. + /// + /// # Errors + /// + /// Returns an error if the arguments are not aligned or out of bounds. + pub async fn read_dfu(&mut self, offset: u32, buf: &mut [u8]) -> Result<(), FirmwareUpdaterError> { + self.dfu.read(offset, buf).await?; + Ok(()) + } + /// Mark to trigger firmware swap on next boot. #[cfg(not(feature = "_verify"))] pub async fn mark_updated(&mut self) -> Result<(), FirmwareUpdaterError> { diff --git a/embassy-boot/src/firmware_updater/blocking.rs b/embassy-boot/src/firmware_updater/blocking.rs index 08062b0d0..0fedac1ea 100644 --- a/embassy-boot/src/firmware_updater/blocking.rs +++ b/embassy-boot/src/firmware_updater/blocking.rs @@ -196,6 +196,17 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> BlockingFirmwareUpdater<'d, DFU, STATE> Ok(()) } + /// Read a slice of data from the DFU storage peripheral, starting the read + /// operation at the given address offset, and reading `buf.len()` bytes. + /// + /// # Errors + /// + /// Returns an error if the arguments are not aligned or out of bounds. + pub fn read_dfu(&mut self, offset: u32, buf: &mut [u8]) -> Result<(), FirmwareUpdaterError> { + self.dfu.read(offset, buf)?; + Ok(()) + } + /// Mark to trigger firmware swap on next boot. #[cfg(not(feature = "_verify"))] pub fn mark_updated(&mut self) -> Result<(), FirmwareUpdaterError> { diff --git a/embassy-usb-dfu/Cargo.toml b/embassy-usb-dfu/Cargo.toml index ca108c1a2..8b2467bca 100644 --- a/embassy-usb-dfu/Cargo.toml +++ b/embassy-usb-dfu/Cargo.toml @@ -43,3 +43,8 @@ esp32c3-hal = { version = "0.13.0", optional = true, default-features = false } dfu = [] application = [] defmt = ["dep:defmt", "embassy-boot/defmt", "embassy-usb/defmt"] +ed25519-dalek = ["embassy-boot/ed25519-dalek", "_verify"] +ed25519-salty = ["embassy-boot/ed25519-salty", "_verify"] + +# Internal features +_verify = [] diff --git a/embassy-usb-dfu/README.md b/embassy-usb-dfu/README.md index bdd5b033a..a81b98279 100644 --- a/embassy-usb-dfu/README.md +++ b/embassy-usb-dfu/README.md @@ -4,3 +4,9 @@ An implementation of the USB DFU 1.1 protocol using embassy-boot. It has 2 compo * DFU protocol mode, enabled by the `dfu` feature. This mode corresponds to the transfer phase DFU protocol described by the USB IF. It supports DFU_DNLOAD requests if marked by the user, and will automatically reset the chip once a DFU transaction has been completed. It also responds to DFU_GETSTATUS, DFU_GETSTATE, DFU_ABORT, and DFU_CLRSTATUS with no user intervention. * DFU runtime mode, enabled by the `application feature`. This mode allows users to expose a DFU interface on their USB device, informing the host of the capability to DFU over USB, and allowing the host to reset the device into its bootloader to complete a DFU operation. Supports DFU_GETSTATUS and DFU_DETACH. When detach/reset is seen by the device as described by the standard, will write a new DFU magic number into the bootloader state in flash, and reset the system. + +## Verification + +Embassy-boot provides functionality to verify that an update binary has been correctly signed using ed25519 as described in https://embassy.dev/book/#_verification. Even though the linked procedure describes the signature being concatenated to the end of the update binary, embassy-boot does not force this and is flexible in terms of how the signature for a binary is distributed. The current implementation in embassy-usb-dfu does however assume that the signature is 64 bytes long and concatenated to the end of the update binary since this is the simplest way to make it work with the usb-dfu mechanism. I.e. embassy-usb-dfu does not currently offer the same flexibility as embassy-boot. + +To enable verification, you need to enable either the `ed25519-dalek` or the `ed25519-salty` feature with `ed25519-salty` being recommended. diff --git a/embassy-usb-dfu/src/dfu.rs b/embassy-usb-dfu/src/dfu.rs index 0f39d906b..9a2f125fb 100644 --- a/embassy-usb-dfu/src/dfu.rs +++ b/embassy-usb-dfu/src/dfu.rs @@ -19,11 +19,19 @@ pub struct Control<'d, DFU: NorFlash, STATE: NorFlash, RST: Reset, const BLOCK_S offset: usize, buf: AlignedBuffer, reset: RST, + + #[cfg(feature = "_verify")] + public_key: &'static [u8; 32], } impl<'d, DFU: NorFlash, STATE: NorFlash, RST: Reset, const BLOCK_SIZE: usize> Control<'d, DFU, STATE, RST, BLOCK_SIZE> { /// Create a new DFU instance to handle DFU transfers. - pub fn new(updater: BlockingFirmwareUpdater<'d, DFU, STATE>, attrs: DfuAttributes, reset: RST) -> Self { + pub fn new( + updater: BlockingFirmwareUpdater<'d, DFU, STATE>, + attrs: DfuAttributes, + reset: RST, + #[cfg(feature = "_verify")] public_key: &'static [u8; 32], + ) -> Self { Self { updater, attrs, @@ -32,6 +40,9 @@ impl<'d, DFU: NorFlash, STATE: NorFlash, RST: Reset, const BLOCK_SIZE: usize> Co offset: 0, buf: AlignedBuffer([0; BLOCK_SIZE]), reset, + + #[cfg(feature = "_verify")] + public_key, } } @@ -102,7 +113,23 @@ impl<'d, DFU: NorFlash, STATE: NorFlash, RST: Reset, const BLOCK_SIZE: usize> Ha if final_transfer { debug!("Receiving final transfer"); - match self.updater.mark_updated() { + #[cfg(feature = "_verify")] + let update_res: Result<(), FirmwareUpdaterError> = { + const SIGNATURE_LEN: usize = 64; + + let mut signature = [0; SIGNATURE_LEN]; + let update_len = (self.offset - SIGNATURE_LEN) as u32; + + self.updater.read_dfu(update_len, &mut signature).and_then(|_| { + self.updater + .verify_and_mark_updated(self.public_key, &signature, update_len) + }) + }; + + #[cfg(not(feature = "_verify"))] + let update_res = self.updater.mark_updated(); + + match update_res { Ok(_) => { self.status = Status::Ok; self.state = State::ManifestSync; @@ -168,7 +195,7 @@ impl<'d, DFU: NorFlash, STATE: NorFlash, RST: Reset, const BLOCK_SIZE: usize> Ha Some(InResponse::Accepted(&buf[0..1])) } Ok(Request::Upload) if self.attrs.contains(DfuAttributes::CAN_UPLOAD) => { - //TODO: FirmwareUpdater does not provide a way of reading the active partition, can't upload. + //TODO: FirmwareUpdater provides a way of reading the active partition so we could in theory add functionality to upload firmware. Some(InResponse::Rejected) } _ => None, diff --git a/examples/boot/application/stm32wb-dfu/memory.x b/examples/boot/application/stm32wb-dfu/memory.x index ff1b800d2..f1e6b053c 100644 --- a/examples/boot/application/stm32wb-dfu/memory.x +++ b/examples/boot/application/stm32wb-dfu/memory.x @@ -1,10 +1,10 @@ MEMORY { /* NOTE 1 K = 1 KiBi = 1024 bytes */ - BOOTLOADER : ORIGIN = 0x08000000, LENGTH = 24K - BOOTLOADER_STATE : ORIGIN = 0x08006000, LENGTH = 4K - FLASH : ORIGIN = 0x08008000, LENGTH = 128K - DFU : ORIGIN = 0x08028000, LENGTH = 132K + BOOTLOADER : ORIGIN = 0x08000000, LENGTH = 48K + BOOTLOADER_STATE : ORIGIN = 0x0800C000, LENGTH = 4K + FLASH : ORIGIN = 0x0800D000, LENGTH = 120K + DFU : ORIGIN = 0x0802B000, LENGTH = 120K RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 32K } diff --git a/examples/boot/application/stm32wb-dfu/secrets/key.sec b/examples/boot/application/stm32wb-dfu/secrets/key.sec new file mode 100644 index 000000000..52e7f125b --- /dev/null +++ b/examples/boot/application/stm32wb-dfu/secrets/key.sec @@ -0,0 +1,2 @@ +untrusted comment: signify secret key +RWRCSwAAAAATdHQF3B4jEIoNZrjADRp2LbjJjNdNNzKwTCe4IB6mDNq96pe53nbNxwbdCc/T4hrz7W+Kx1MwrZ0Yz5xebSK5Z0Kh/3Cdf039U5f+eoTDS2fIGbohyUbrtwKzjyE0qXI= diff --git a/examples/boot/bootloader/stm32wb-dfu/Cargo.toml b/examples/boot/bootloader/stm32wb-dfu/Cargo.toml index 738afb6ec..0bb93b12e 100644 --- a/examples/boot/bootloader/stm32wb-dfu/Cargo.toml +++ b/examples/boot/bootloader/stm32wb-dfu/Cargo.toml @@ -30,6 +30,7 @@ defmt = [ "embassy-usb/defmt", "embassy-usb-dfu/defmt" ] +verify = ["embassy-usb-dfu/ed25519-salty"] [profile.dev] debug = 2 diff --git a/examples/boot/bootloader/stm32wb-dfu/README.md b/examples/boot/bootloader/stm32wb-dfu/README.md index 3c5f268a0..99a7002c4 100644 --- a/examples/boot/bootloader/stm32wb-dfu/README.md +++ b/examples/boot/bootloader/stm32wb-dfu/README.md @@ -28,6 +28,32 @@ cargo objcopy --release -- -O binary fw.bin dfu-util -d c0de:cafe -w -D fw.bin ``` +### 3. Sign Updates Before Flashing (Optional) + +Currently, embassy-usb-dfu only supports a limited implementation of the generic support for ed25519-based update verfication in embassy-boot. This implementation assumes that a signature is simply concatenated to the end of an update binary. For more details, please see https://embassy.dev/book/#_verification and/or refer to the documentation for embassy-boot-dfu. + +To sign (and then verify) application updates, you will first need to generate a key pair: + +``` +signify-openbsd -G -n -p secrets/key.pub -s secrets/key.sec +tail -n1 secrets/key.pub | base64 -d -i - | dd ibs=10 skip=1 > secrets/key.pub.short +``` + +Then you will need to sign all you binaries with the private key: + +``` +cargo objcopy --release -- -O binary fw.bin +shasum -a 512 -b fw.bin | head -c128 | xxd -p -r > target/fw-hash.txt +signify-openbsd -S -s secrets/key.sec -m target/fw-hash.txt -x target/fw-hash.sig +cp fw.bin fw-signed.bin +tail -n1 target/fw-hash.sig | base64 -d -i - | dd ibs=10 skip=1 >> fw-signed.bin +dfu-util -d c0de:cafe -w -D fw-signed.bin +``` + +Finally, as shown in this example with the `verify` feature flag enabled, you then need to embed the public key into your bootloader so that it can verify update signatures. + +N.B. Please note that the exact steps above are NOT a good example of how to manage your keys securely. In a production environment, you should take great care to ensure that (at least the private key) is protected and not leaked into your version control system. + ## Troubleshooting - Make sure your device is in DFU mode before flashing diff --git a/examples/boot/bootloader/stm32wb-dfu/memory.x b/examples/boot/bootloader/stm32wb-dfu/memory.x index 858062631..77c4d2ee2 100644 --- a/examples/boot/bootloader/stm32wb-dfu/memory.x +++ b/examples/boot/bootloader/stm32wb-dfu/memory.x @@ -1,10 +1,10 @@ MEMORY { /* NOTE 1 K = 1 KiBi = 1024 bytes */ - FLASH : ORIGIN = 0x08000000, LENGTH = 24K - BOOTLOADER_STATE : ORIGIN = 0x08006000, LENGTH = 4K - ACTIVE : ORIGIN = 0x08008000, LENGTH = 128K - DFU : ORIGIN = 0x08028000, LENGTH = 132K + FLASH : ORIGIN = 0x08000000, LENGTH = 48K + BOOTLOADER_STATE : ORIGIN = 0x0800C000, LENGTH = 4K + ACTIVE : ORIGIN = 0x0800D000, LENGTH = 120K + DFU : ORIGIN = 0x0802B000, LENGTH = 120K RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 16K } diff --git a/examples/boot/bootloader/stm32wb-dfu/secrets/key.pub.short b/examples/boot/bootloader/stm32wb-dfu/secrets/key.pub.short new file mode 100644 index 000000000..7a4de8585 --- /dev/null +++ b/examples/boot/bootloader/stm32wb-dfu/secrets/key.pub.short @@ -0,0 +1 @@ +gB¡ÿpMýS—þz„ÃKgȺ!ÉFë·³!4©r \ No newline at end of file diff --git a/examples/boot/bootloader/stm32wb-dfu/src/main.rs b/examples/boot/bootloader/stm32wb-dfu/src/main.rs index 0b643079f..107f243fd 100644 --- a/examples/boot/bootloader/stm32wb-dfu/src/main.rs +++ b/examples/boot/bootloader/stm32wb-dfu/src/main.rs @@ -25,6 +25,12 @@ bind_interrupts!(struct Irqs { // N.B. update to a custom GUID for your own device! const DEVICE_INTERFACE_GUIDS: &[&str] = &["{EAA9A5DC-30BA-44BC-9232-606CDC875321}"]; +// This is a randomly generated example key. +// +// N.B. Please replace with your own! +#[cfg(feature = "verify")] +static PUBLIC_SIGNING_KEY: &[u8; 32] = include_bytes!("../secrets/key.pub.short"); + #[entry] fn main() -> ! { let mut config = embassy_stm32::Config::default(); @@ -57,7 +63,13 @@ fn main() -> ! { let mut config_descriptor = [0; 256]; let mut bos_descriptor = [0; 256]; let mut control_buf = [0; 4096]; + + #[cfg(not(feature = "verify"))] let mut state = Control::new(updater, DfuAttributes::CAN_DOWNLOAD, ResetImmediate); + + #[cfg(feature = "verify")] + let mut state = Control::new(updater, DfuAttributes::CAN_DOWNLOAD, ResetImmediate, PUBLIC_SIGNING_KEY); + let mut builder = Builder::new( driver, config, From 489c9df453b86f80f040fe1e48d89ab342e24b3a Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Fri, 23 May 2025 14:32:36 +0200 Subject: [PATCH 1189/1217] chore: temporarily disable pico tests --- ci.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ci.sh b/ci.sh index 2be84ef6b..b2112328f 100755 --- a/ci.sh +++ b/ci.sh @@ -362,6 +362,8 @@ rm out/tests/pimoroni-pico-plus-2/flash rm out/tests/pimoroni-pico-plus-2/i2c # The pico2 plus doesn't have the adcs hooked up like the picoW does. rm out/tests/pimoroni-pico-plus-2/adc +# temporarily disabled, bad hardware connection. +rm -f out/tests/rpi-pico/* if [[ -z "${TELEPROBE_TOKEN-}" ]]; then echo No teleprobe token found, skipping running HIL tests From 134d162a337d17d0ef881135812c270cef162e61 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Fri, 23 May 2025 14:53:17 +0200 Subject: [PATCH 1190/1217] chore: disable another test --- ci.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ci.sh b/ci.sh index b2112328f..94bcc75ed 100755 --- a/ci.sh +++ b/ci.sh @@ -362,6 +362,9 @@ rm out/tests/pimoroni-pico-plus-2/flash rm out/tests/pimoroni-pico-plus-2/i2c # The pico2 plus doesn't have the adcs hooked up like the picoW does. rm out/tests/pimoroni-pico-plus-2/adc +# temporarily disabled +rm out/tests/pimoroni-pico-plus-2/pwm + # temporarily disabled, bad hardware connection. rm -f out/tests/rpi-pico/* From 0f9a7a057fb7dfb2358acec9068fece82c7c7a89 Mon Sep 17 00:00:00 2001 From: Johan Anderholm Date: Sat, 30 Dec 2023 11:54:16 +0100 Subject: [PATCH 1191/1217] executor: Make state implementations and their conditions match Use u8 for state_atomics and state_critical_section since that is all that is needed. Change arm condition to "32" since that is what is used and required. --- embassy-executor/src/raw/mod.rs | 2 +- embassy-executor/src/raw/state_atomics.rs | 10 +++++----- embassy-executor/src/raw/state_critical_section.rs | 10 +++++----- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs index e7a27035a..913da2e25 100644 --- a/embassy-executor/src/raw/mod.rs +++ b/embassy-executor/src/raw/mod.rs @@ -11,7 +11,7 @@ #[cfg_attr(not(target_has_atomic = "ptr"), path = "run_queue_critical_section.rs")] mod run_queue; -#[cfg_attr(all(cortex_m, target_has_atomic = "8"), path = "state_atomics_arm.rs")] +#[cfg_attr(all(cortex_m, target_has_atomic = "32"), path = "state_atomics_arm.rs")] #[cfg_attr(all(not(cortex_m), target_has_atomic = "8"), path = "state_atomics.rs")] #[cfg_attr(not(target_has_atomic = "8"), path = "state_critical_section.rs")] mod state; diff --git a/embassy-executor/src/raw/state_atomics.rs b/embassy-executor/src/raw/state_atomics.rs index b6576bfc2..e813548ae 100644 --- a/embassy-executor/src/raw/state_atomics.rs +++ b/embassy-executor/src/raw/state_atomics.rs @@ -1,4 +1,4 @@ -use core::sync::atomic::{AtomicU32, Ordering}; +use core::sync::atomic::{AtomicU8, Ordering}; #[derive(Clone, Copy)] pub(crate) struct Token(()); @@ -11,18 +11,18 @@ pub(crate) fn locked(f: impl FnOnce(Token) -> R) -> R { } /// Task is spawned (has a future) -pub(crate) const STATE_SPAWNED: u32 = 1 << 0; +pub(crate) const STATE_SPAWNED: u8 = 1 << 0; /// Task is in the executor run queue -pub(crate) const STATE_RUN_QUEUED: u32 = 1 << 1; +pub(crate) const STATE_RUN_QUEUED: u8 = 1 << 1; pub(crate) struct State { - state: AtomicU32, + state: AtomicU8, } impl State { pub const fn new() -> State { Self { - state: AtomicU32::new(0), + state: AtomicU8::new(0), } } diff --git a/embassy-executor/src/raw/state_critical_section.rs b/embassy-executor/src/raw/state_critical_section.rs index 6b627ff79..ec08f2f58 100644 --- a/embassy-executor/src/raw/state_critical_section.rs +++ b/embassy-executor/src/raw/state_critical_section.rs @@ -4,12 +4,12 @@ pub(crate) use critical_section::{with as locked, CriticalSection as Token}; use critical_section::{CriticalSection, Mutex}; /// Task is spawned (has a future) -pub(crate) const STATE_SPAWNED: u32 = 1 << 0; +pub(crate) const STATE_SPAWNED: u8 = 1 << 0; /// Task is in the executor run queue -pub(crate) const STATE_RUN_QUEUED: u32 = 1 << 1; +pub(crate) const STATE_RUN_QUEUED: u8 = 1 << 1; pub(crate) struct State { - state: Mutex>, + state: Mutex>, } impl State { @@ -19,11 +19,11 @@ impl State { } } - fn update(&self, f: impl FnOnce(&mut u32) -> R) -> R { + fn update(&self, f: impl FnOnce(&mut u8) -> R) -> R { critical_section::with(|cs| self.update_with_cs(cs, f)) } - fn update_with_cs(&self, cs: CriticalSection<'_>, f: impl FnOnce(&mut u32) -> R) -> R { + fn update_with_cs(&self, cs: CriticalSection<'_>, f: impl FnOnce(&mut u8) -> R) -> R { let s = self.state.borrow(cs); let mut val = s.get(); let r = f(&mut val); From 2ed5e04fd0fa216502c20ec4571a4b553bb86f1f Mon Sep 17 00:00:00 2001 From: "Kevin P. Fleming" Date: Sat, 24 May 2025 16:39:25 -0400 Subject: [PATCH 1192/1217] stm32: Expand documentation of RingBufferedUartRx. Explain to users of this driver how 'waiting for bytes' actually works, and what that may mean for latency introduced in their application. Also correct references to 'start' to be 'start_uart'. --- embassy-stm32/src/usart/ringbuffered.rs | 73 ++++++++++++++++++++++--- 1 file changed, 65 insertions(+), 8 deletions(-) diff --git a/embassy-stm32/src/usart/ringbuffered.rs b/embassy-stm32/src/usart/ringbuffered.rs index eaa9424c5..9280dbd18 100644 --- a/embassy-stm32/src/usart/ringbuffered.rs +++ b/embassy-stm32/src/usart/ringbuffered.rs @@ -79,7 +79,7 @@ impl<'d> RingBufferedUartRx<'d> { /// Configure and start the DMA backed UART receiver /// - /// Note: This is also done automatically by [`read()`] if required. + /// Note: This is also done automatically by `read()` if required. pub fn start_uart(&mut self) { // Clear the buffer so that it is ready to receive data compiler_fence(Ordering::SeqCst); @@ -139,14 +139,70 @@ impl<'d> RingBufferedUartRx<'d> { Ok(()) } - /// Read bytes that are readily available in the ring buffer. - /// If no bytes are currently available in the buffer the call waits until the some - /// bytes are available (at least one byte and at most half the buffer size) + /// Read bytes that are available in the ring buffer, or wait for + /// bytes to become available and return them. /// - /// Background receive is started if `start()` has not been previously called. + /// Background reception is started if necessary (if `start_uart()` had + /// not previously been called, or if an error was detected which + /// caused background reception to be stopped). /// - /// Receive in the background is terminated if an error is returned. - /// It must then manually be started again by calling `start()` or by re-calling `read()`. + /// Background reception is terminated when an error is returned. + /// It must be started again by calling `start_uart()` or by + /// calling `read()` again. + /// + /// ### Notes on 'waiting for bytes' + /// + /// Waiting for bytes operates in one of two modes, depending on + /// the behavior of the sender and the size of the buffer passed + /// to `read()`: + /// + /// - If the sender sends intermittently, the 'idle line' + /// condition will be detected when the sender stops, and any + /// bytes in the ring buffer will be returned. If there are no + /// bytes in the buffer, the check will be repeated each time the + /// 'idle line' condition is detected, so if the sender sends just + /// a single byte, it will be returned once the 'idle line' + /// condition is detected. + /// + /// - If the sender sends continuously, the call will wait until + /// the DMA controller indicates that it has written to either the + /// middle byte or last byte of the ring buffer ('half transfer' + /// or 'transfer complete', respectively). This does not indicate + /// the buffer is half-full or full, though, because the DMA + /// controller does not detect those conditions; it sends an + /// interrupt when those specific buffer addresses have been + /// written. + /// + /// In both cases this will result in variable latency due to the + /// buffering effect. For example, if the baudrate is 2400 bps, + /// and the configuration is 8 data bits, no parity bit, and one + /// stop bit, then a byte will be received every ~4.16ms. If the + /// ring buffer is 32 bytes, then a 'wait for bytes' delay may + /// have to wait for 16 bytes in the worst case, resulting in a + /// delay (latency) of ~62.46ms for the first byte in the ring + /// buffer. If the sender sends only 6 bytes and then stops, but + /// the buffer was empty when `read()` was called, then those + /// bytes may not be returned until ~24.96ms after the first byte + /// was received (time for 5 additional bytes plus the 'idle + /// frame' which triggers the 'idle line' condition). + /// + /// Applications subject to this latency must be careful if they + /// also apply timeouts during reception, as it may appear (to + /// them) that the sender has stopped sending when it did not. In + /// the example above, a 50ms timeout (12 bytes at 2400bps) might + /// seem to be reasonable to detect that the sender has stopped + /// sending, but would be falsely triggered in the worst-case + /// buffer delay scenario. + /// + /// Note: This latency is caused by the limited capabilities of + /// the STM32 DMA controller; since it cannot generate an + /// interrupt when it stores a byte into an empty ring buffer, or + /// in any other configurable conditions, it is not possible to + /// take notice of the contents of the ring buffer more quickly + /// without introducing polling. As a result the latency can be + /// reduced by calling `read()` repeatedly with smaller buffers to + /// receive the available bytes, as each call to `read()` will + /// explicitly check the ring buffer for available bytes. pub async fn read(&mut self, buf: &mut [u8]) -> Result { self.start_dma_or_check_errors()?; @@ -202,7 +258,8 @@ impl<'d> RingBufferedUartRx<'d> { }); let mut dma_init = false; - // Future which completes when there is dma is half full or full + // Future which completes when the DMA controller indicates it + // has written to the ring buffer's middle byte, or last byte let dma = poll_fn(|cx| { self.ring_buf.set_waker(cx.waker()); From ca5fe2645dd5a969052081ab855aa88520198e12 Mon Sep 17 00:00:00 2001 From: "Kevin P. Fleming" Date: Sat, 24 May 2025 19:34:07 -0400 Subject: [PATCH 1193/1217] Move new documentation to RingBufferedUartRx struct. --- embassy-stm32/src/usart/ringbuffered.rs | 118 +++++++++++++----------- 1 file changed, 62 insertions(+), 56 deletions(-) diff --git a/embassy-stm32/src/usart/ringbuffered.rs b/embassy-stm32/src/usart/ringbuffered.rs index 9280dbd18..1d4a44896 100644 --- a/embassy-stm32/src/usart/ringbuffered.rs +++ b/embassy-stm32/src/usart/ringbuffered.rs @@ -18,6 +18,65 @@ use crate::Peri; /// Rx-only Ring-buffered UART Driver /// /// Created with [UartRx::into_ring_buffered] +/// +/// ### Notes on 'waiting for bytes' +/// +/// The `read(buf)` (but not `read()`) and `read_exact(buf)` functions +/// may need to wait for bytes to arrive, if the ring buffer does not +/// contain enough bytes to fill the buffer passed by the caller of +/// the function, or is empty. +/// +/// Waiting for bytes operates in one of two modes, depending on +/// the behavior of the sender and the size of the buffer passed +/// to the function: +/// +/// - If the sender sends intermittently, the 'idle line' +/// condition will be detected when the sender stops, and any +/// bytes in the ring buffer will be returned. If there are no +/// bytes in the buffer, the check will be repeated each time the +/// 'idle line' condition is detected, so if the sender sends just +/// a single byte, it will be returned once the 'idle line' +/// condition is detected. +/// +/// - If the sender sends continuously, the call will wait until +/// the DMA controller indicates that it has written to either the +/// middle byte or last byte of the ring buffer ('half transfer' +/// or 'transfer complete', respectively). This does not indicate +/// the buffer is half-full or full, though, because the DMA +/// controller does not detect those conditions; it sends an +/// interrupt when those specific buffer addresses have been +/// written. +/// +/// In both cases this will result in variable latency due to the +/// buffering effect. For example, if the baudrate is 2400 bps, and +/// the configuration is 8 data bits, no parity bit, and one stop bit, +/// then a byte will be received every ~4.16ms. If the ring buffer is +/// 32 bytes, then a 'wait for bytes' delay may have to wait for 16 +/// bytes in the worst case, resulting in a delay (latency) of +/// ~62.46ms for the first byte in the ring buffer. If the sender +/// sends only 6 bytes and then stops, but the buffer was empty when +/// the read function was called, then those bytes may not be returned +/// until ~24.96ms after the first byte was received (time for 5 +/// additional bytes plus the 'idle frame' which triggers the 'idle +/// line' condition). +/// +/// Applications subject to this latency must be careful if they +/// also apply timeouts during reception, as it may appear (to +/// them) that the sender has stopped sending when it did not. In +/// the example above, a 50ms timeout (12 bytes at 2400bps) might +/// seem to be reasonable to detect that the sender has stopped +/// sending, but would be falsely triggered in the worst-case +/// buffer delay scenario. +/// +/// Note: This latency is caused by the limited capabilities of the +/// STM32 DMA controller; since it cannot generate an interrupt when +/// it stores a byte into an empty ring buffer, or in any other +/// configurable conditions, it is not possible to take notice of the +/// contents of the ring buffer more quickly without introducing +/// polling. As a result the latency can be reduced by calling the +/// read functions repeatedly with smaller buffers to receive the +/// available bytes, as each call to a read function will explicitly +/// check the ring buffer for available bytes. pub struct RingBufferedUartRx<'d> { info: &'static Info, state: &'static State, @@ -79,7 +138,8 @@ impl<'d> RingBufferedUartRx<'d> { /// Configure and start the DMA backed UART receiver /// - /// Note: This is also done automatically by `read()` if required. + /// Note: This is also done automatically by the read functions if + /// required. pub fn start_uart(&mut self) { // Clear the buffer so that it is ready to receive data compiler_fence(Ordering::SeqCst); @@ -148,61 +208,7 @@ impl<'d> RingBufferedUartRx<'d> { /// /// Background reception is terminated when an error is returned. /// It must be started again by calling `start_uart()` or by - /// calling `read()` again. - /// - /// ### Notes on 'waiting for bytes' - /// - /// Waiting for bytes operates in one of two modes, depending on - /// the behavior of the sender and the size of the buffer passed - /// to `read()`: - /// - /// - If the sender sends intermittently, the 'idle line' - /// condition will be detected when the sender stops, and any - /// bytes in the ring buffer will be returned. If there are no - /// bytes in the buffer, the check will be repeated each time the - /// 'idle line' condition is detected, so if the sender sends just - /// a single byte, it will be returned once the 'idle line' - /// condition is detected. - /// - /// - If the sender sends continuously, the call will wait until - /// the DMA controller indicates that it has written to either the - /// middle byte or last byte of the ring buffer ('half transfer' - /// or 'transfer complete', respectively). This does not indicate - /// the buffer is half-full or full, though, because the DMA - /// controller does not detect those conditions; it sends an - /// interrupt when those specific buffer addresses have been - /// written. - /// - /// In both cases this will result in variable latency due to the - /// buffering effect. For example, if the baudrate is 2400 bps, - /// and the configuration is 8 data bits, no parity bit, and one - /// stop bit, then a byte will be received every ~4.16ms. If the - /// ring buffer is 32 bytes, then a 'wait for bytes' delay may - /// have to wait for 16 bytes in the worst case, resulting in a - /// delay (latency) of ~62.46ms for the first byte in the ring - /// buffer. If the sender sends only 6 bytes and then stops, but - /// the buffer was empty when `read()` was called, then those - /// bytes may not be returned until ~24.96ms after the first byte - /// was received (time for 5 additional bytes plus the 'idle - /// frame' which triggers the 'idle line' condition). - /// - /// Applications subject to this latency must be careful if they - /// also apply timeouts during reception, as it may appear (to - /// them) that the sender has stopped sending when it did not. In - /// the example above, a 50ms timeout (12 bytes at 2400bps) might - /// seem to be reasonable to detect that the sender has stopped - /// sending, but would be falsely triggered in the worst-case - /// buffer delay scenario. - /// - /// Note: This latency is caused by the limited capabilities of - /// the STM32 DMA controller; since it cannot generate an - /// interrupt when it stores a byte into an empty ring buffer, or - /// in any other configurable conditions, it is not possible to - /// take notice of the contents of the ring buffer more quickly - /// without introducing polling. As a result the latency can be - /// reduced by calling `read()` repeatedly with smaller buffers to - /// receive the available bytes, as each call to `read()` will - /// explicitly check the ring buffer for available bytes. + /// calling a read function again. pub async fn read(&mut self, buf: &mut [u8]) -> Result { self.start_dma_or_check_errors()?; From a860fea0a5d1a0b39fa02afd5214ee4971d6e571 Mon Sep 17 00:00:00 2001 From: "Kevin P. Fleming" Date: Sun, 25 May 2025 08:51:27 -0400 Subject: [PATCH 1194/1217] stm32: Assert in BufferedUart that the buffers are not empty. --- embassy-stm32/src/usart/buffered.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs index 06d5f7528..73ab46404 100644 --- a/embassy-stm32/src/usart/buffered.rs +++ b/embassy-stm32/src/usart/buffered.rs @@ -457,8 +457,10 @@ impl<'d> BufferedUart<'d> { info.rcc.enable_and_reset(); + assert!(!tx_buffer.is_empty()); let len = tx_buffer.len(); unsafe { state.tx_buf.init(tx_buffer.as_mut_ptr(), len) }; + assert!(!rx_buffer.is_empty()); let len = rx_buffer.len(); unsafe { state.rx_buf.init(rx_buffer.as_mut_ptr(), len) }; From a8b3178ceec8243e337dc8b3b320faf266eff4a7 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Mon, 26 May 2025 09:10:35 +0200 Subject: [PATCH 1195/1217] chore: bump version of embassy-boot-stm32 --- embassy-boot-stm32/Cargo.toml | 2 +- examples/boot/application/stm32f3/Cargo.toml | 2 +- examples/boot/application/stm32f7/Cargo.toml | 2 +- examples/boot/application/stm32h7/Cargo.toml | 2 +- examples/boot/application/stm32l0/Cargo.toml | 2 +- examples/boot/application/stm32l1/Cargo.toml | 2 +- examples/boot/application/stm32l4/Cargo.toml | 2 +- examples/boot/application/stm32wb-dfu/Cargo.toml | 2 +- examples/boot/application/stm32wl/Cargo.toml | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/embassy-boot-stm32/Cargo.toml b/embassy-boot-stm32/Cargo.toml index a24921291..11ad453b8 100644 --- a/embassy-boot-stm32/Cargo.toml +++ b/embassy-boot-stm32/Cargo.toml @@ -1,7 +1,7 @@ [package] edition = "2021" name = "embassy-boot-stm32" -version = "0.2.0" +version = "0.3.0" description = "Bootloader lib for STM32 chips" license = "MIT OR Apache-2.0" repository = "https://github.com/embassy-rs/embassy" diff --git a/examples/boot/application/stm32f3/Cargo.toml b/examples/boot/application/stm32f3/Cargo.toml index 87f97071b..b3466e288 100644 --- a/examples/boot/application/stm32f3/Cargo.toml +++ b/examples/boot/application/stm32f3/Cargo.toml @@ -9,7 +9,7 @@ embassy-sync = { version = "0.7.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32f303re", "time-driver-any", "exti"] } -embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32" } +embassy-boot-stm32 = { version = "0.3.0", path = "../../../../embassy-boot-stm32" } embassy-embedded-hal = { version = "0.3.0", path = "../../../../embassy-embedded-hal" } defmt = { version = "1.0.1", optional = true } diff --git a/examples/boot/application/stm32f7/Cargo.toml b/examples/boot/application/stm32f7/Cargo.toml index d593a568e..72dbded5f 100644 --- a/examples/boot/application/stm32f7/Cargo.toml +++ b/examples/boot/application/stm32f7/Cargo.toml @@ -9,7 +9,7 @@ embassy-sync = { version = "0.7.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32f767zi", "time-driver-any", "exti", "single-bank"] } -embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } +embassy-boot-stm32 = { version = "0.3.0", path = "../../../../embassy-boot-stm32", features = [] } embassy-embedded-hal = { version = "0.3.0", path = "../../../../embassy-embedded-hal" } defmt = { version = "1.0.1", optional = true } diff --git a/examples/boot/application/stm32h7/Cargo.toml b/examples/boot/application/stm32h7/Cargo.toml index 7653d82ed..57fb8312c 100644 --- a/examples/boot/application/stm32h7/Cargo.toml +++ b/examples/boot/application/stm32h7/Cargo.toml @@ -9,7 +9,7 @@ embassy-sync = { version = "0.7.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32h743zi", "time-driver-any", "exti"] } -embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } +embassy-boot-stm32 = { version = "0.3.0", path = "../../../../embassy-boot-stm32", features = [] } embassy-embedded-hal = { version = "0.3.0", path = "../../../../embassy-embedded-hal" } defmt = { version = "1.0.1", optional = true } diff --git a/examples/boot/application/stm32l0/Cargo.toml b/examples/boot/application/stm32l0/Cargo.toml index d1cace246..7dbbba138 100644 --- a/examples/boot/application/stm32l0/Cargo.toml +++ b/examples/boot/application/stm32l0/Cargo.toml @@ -9,7 +9,7 @@ embassy-sync = { version = "0.7.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32l072cz", "time-driver-any", "exti", "memory-x"] } -embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } +embassy-boot-stm32 = { version = "0.3.0", path = "../../../../embassy-boot-stm32", features = [] } embassy-embedded-hal = { version = "0.3.0", path = "../../../../embassy-embedded-hal" } defmt = { version = "1.0.1", optional = true } diff --git a/examples/boot/application/stm32l1/Cargo.toml b/examples/boot/application/stm32l1/Cargo.toml index 034bf39af..9549b2048 100644 --- a/examples/boot/application/stm32l1/Cargo.toml +++ b/examples/boot/application/stm32l1/Cargo.toml @@ -9,7 +9,7 @@ embassy-sync = { version = "0.7.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32l151cb-a", "time-driver-any", "exti"] } -embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } +embassy-boot-stm32 = { version = "0.3.0", path = "../../../../embassy-boot-stm32", features = [] } embassy-embedded-hal = { version = "0.3.0", path = "../../../../embassy-embedded-hal" } defmt = { version = "1.0.1", optional = true } diff --git a/examples/boot/application/stm32l4/Cargo.toml b/examples/boot/application/stm32l4/Cargo.toml index d32cbca97..03daeb0bc 100644 --- a/examples/boot/application/stm32l4/Cargo.toml +++ b/examples/boot/application/stm32l4/Cargo.toml @@ -9,7 +9,7 @@ embassy-sync = { version = "0.7.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32l475vg", "time-driver-any", "exti"] } -embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } +embassy-boot-stm32 = { version = "0.3.0", path = "../../../../embassy-boot-stm32", features = [] } embassy-embedded-hal = { version = "0.3.0", path = "../../../../embassy-embedded-hal" } defmt = { version = "1.0.1", optional = true } diff --git a/examples/boot/application/stm32wb-dfu/Cargo.toml b/examples/boot/application/stm32wb-dfu/Cargo.toml index 49b35f681..e582628aa 100644 --- a/examples/boot/application/stm32wb-dfu/Cargo.toml +++ b/examples/boot/application/stm32wb-dfu/Cargo.toml @@ -9,7 +9,7 @@ embassy-sync = { version = "0.7.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32wb55rg", "time-driver-any", "exti"] } -embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } +embassy-boot-stm32 = { version = "0.3.0", path = "../../../../embassy-boot-stm32", features = [] } embassy-embedded-hal = { version = "0.3.0", path = "../../../../embassy-embedded-hal" } embassy-usb = { version = "0.4.0", path = "../../../../embassy-usb" } embassy-usb-dfu = { version = "0.1.0", path = "../../../../embassy-usb-dfu", features = ["application", "cortex-m"] } diff --git a/examples/boot/application/stm32wl/Cargo.toml b/examples/boot/application/stm32wl/Cargo.toml index e44d9859a..3ed04b472 100644 --- a/examples/boot/application/stm32wl/Cargo.toml +++ b/examples/boot/application/stm32wl/Cargo.toml @@ -9,7 +9,7 @@ embassy-sync = { version = "0.7.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.7.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.4.0", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-stm32 = { version = "0.2.0", path = "../../../../embassy-stm32", features = ["stm32wl55jc-cm4", "time-driver-any", "exti"] } -embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } +embassy-boot-stm32 = { version = "0.3.0", path = "../../../../embassy-boot-stm32", features = [] } embassy-embedded-hal = { version = "0.3.0", path = "../../../../embassy-embedded-hal" } defmt = { version = "1.0.1", optional = true } From 8fa07ac062eba0ddc3021e7f8787fce32f62cfbe Mon Sep 17 00:00:00 2001 From: ROMemories <152802150+ROMemories@users.noreply.github.com> Date: Mon, 26 May 2025 14:43:07 +0200 Subject: [PATCH 1196/1217] fixup! feat(stm32-c0): provide a `const` constructor on `rcc::Config` --- embassy-stm32/src/rcc/c0.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/embassy-stm32/src/rcc/c0.rs b/embassy-stm32/src/rcc/c0.rs index 68f67af01..cac2a9149 100644 --- a/embassy-stm32/src/rcc/c0.rs +++ b/embassy-stm32/src/rcc/c0.rs @@ -60,7 +60,6 @@ pub struct Config { } impl Config { - #[inline] pub const fn new() -> Self { Config { hsi: Some(Hsi { @@ -78,7 +77,6 @@ impl Config { } impl Default for Config { - #[inline] fn default() -> Config { Self::new() } From ca17b41d0dfa32150ac72187e1b05924577641cb Mon Sep 17 00:00:00 2001 From: ROMemories <152802150+ROMemories@users.noreply.github.com> Date: Mon, 26 May 2025 14:43:21 +0200 Subject: [PATCH 1197/1217] fixup! feat(stm32-g0): provide a `const` constructor on `rcc::Config` --- embassy-stm32/src/rcc/g0.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/embassy-stm32/src/rcc/g0.rs b/embassy-stm32/src/rcc/g0.rs index c03cbf9a8..ce6398afd 100644 --- a/embassy-stm32/src/rcc/g0.rs +++ b/embassy-stm32/src/rcc/g0.rs @@ -98,7 +98,6 @@ pub struct Config { } impl Config { - #[inline] pub const fn new() -> Self { Config { hsi: Some(Hsi { @@ -120,7 +119,6 @@ impl Config { } impl Default for Config { - #[inline] fn default() -> Config { Self::new() } From fce84bd51be5fa52e965255cabbb26d69a1edbab Mon Sep 17 00:00:00 2001 From: ROMemories <152802150+ROMemories@users.noreply.github.com> Date: Mon, 26 May 2025 14:43:29 +0200 Subject: [PATCH 1198/1217] fixup! feat(stm32-g4): provide a `const` constructor on `rcc::Config` --- embassy-stm32/src/rcc/g4.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/embassy-stm32/src/rcc/g4.rs b/embassy-stm32/src/rcc/g4.rs index e4b216450..da13e16aa 100644 --- a/embassy-stm32/src/rcc/g4.rs +++ b/embassy-stm32/src/rcc/g4.rs @@ -92,7 +92,6 @@ pub struct Config { } impl Config { - #[inline] pub const fn new() -> Self { Config { hsi: true, @@ -112,7 +111,6 @@ impl Config { } impl Default for Config { - #[inline] fn default() -> Config { Self::new() } From 5d6b51d910462b5dc2c5b80eacd3d7199df86965 Mon Sep 17 00:00:00 2001 From: ROMemories <152802150+ROMemories@users.noreply.github.com> Date: Mon, 26 May 2025 14:43:39 +0200 Subject: [PATCH 1199/1217] fixup! feat(stm32-l): provide a `const` constructor on `rcc::Config` --- embassy-stm32/src/rcc/l.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/embassy-stm32/src/rcc/l.rs b/embassy-stm32/src/rcc/l.rs index 91e6ae07e..81b89046e 100644 --- a/embassy-stm32/src/rcc/l.rs +++ b/embassy-stm32/src/rcc/l.rs @@ -69,7 +69,6 @@ pub struct Config { } impl Config { - #[inline] pub const fn new() -> Self { Config { hse: None, @@ -100,7 +99,6 @@ impl Config { } impl Default for Config { - #[inline] fn default() -> Config { Self::new() } From a5a27ef52b9575edd0d25aff65f49331f676ca82 Mon Sep 17 00:00:00 2001 From: ROMemories <152802150+ROMemories@users.noreply.github.com> Date: Mon, 26 May 2025 14:43:46 +0200 Subject: [PATCH 1200/1217] fixup! feat(stm32-wba): provide a `const` constructor on `rcc::Config` --- embassy-stm32/src/rcc/wba.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/embassy-stm32/src/rcc/wba.rs b/embassy-stm32/src/rcc/wba.rs index 98d2dcf0e..b9fc4e423 100644 --- a/embassy-stm32/src/rcc/wba.rs +++ b/embassy-stm32/src/rcc/wba.rs @@ -38,7 +38,6 @@ pub struct Config { } impl Config { - #[inline] pub const fn new() -> Self { Config { hse: None, @@ -56,7 +55,6 @@ impl Config { } impl Default for Config { - #[inline] fn default() -> Config { Self::new() } From 44c53365ad387c8d1296751080f4f8117c7d7b5c Mon Sep 17 00:00:00 2001 From: ROMemories <152802150+ROMemories@users.noreply.github.com> Date: Mon, 26 May 2025 14:44:48 +0200 Subject: [PATCH 1201/1217] fixup! feat(stm32-l): provide a `const` constructor on `rcc::Config` --- embassy-stm32/src/rcc/bd.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/embassy-stm32/src/rcc/bd.rs b/embassy-stm32/src/rcc/bd.rs index 939c05907..e2c704405 100644 --- a/embassy-stm32/src/rcc/bd.rs +++ b/embassy-stm32/src/rcc/bd.rs @@ -92,6 +92,7 @@ pub struct LsConfig { } impl LsConfig { + /// Creates an [`LsConfig`] using the LSI when possible. pub const fn new() -> Self { // on L5, just the fact that LSI is enabled makes things crash. // TODO: investigate. From b9f7478ada241731c52a58cab8c4caa295354467 Mon Sep 17 00:00:00 2001 From: "Kevin P. Fleming" Date: Mon, 26 May 2025 18:43:09 -0400 Subject: [PATCH 1202/1217] stm32: Improvements to CRC HAL. * Corrects spelling and grammar errors in documentation. * Removes non-v1 code from v1-only source file. * Adds 'read' operation for v2/v3, to be consistent with v1. * Removes 'reset' from the v2/v3 'reconfigure' operation to match the documentation (the only user is the 'new' function which already issues a reset). --- embassy-stm32/src/crc/v1.rs | 16 ++----------- embassy-stm32/src/crc/v2v3.rs | 43 ++++++++++++++++++++--------------- 2 files changed, 27 insertions(+), 32 deletions(-) diff --git a/embassy-stm32/src/crc/v1.rs b/embassy-stm32/src/crc/v1.rs index a78b3c2b7..13e5263de 100644 --- a/embassy-stm32/src/crc/v1.rs +++ b/embassy-stm32/src/crc/v1.rs @@ -23,22 +23,16 @@ impl<'d> Crc<'d> { PAC_CRC.cr().write(|w| w.set_reset(true)); } - /// Feeds a word to the peripheral and returns the current CRC value + /// Feeds a word into the CRC peripheral. Returns the computed CRC. pub fn feed_word(&mut self, word: u32) -> u32 { // write a single byte to the device, and return the result - #[cfg(not(crc_v1))] - PAC_CRC.dr32().write_value(word); - #[cfg(crc_v1)] PAC_CRC.dr().write_value(word); self.read() } - /// Feed a slice of words to the peripheral and return the result. + /// Feeds a slice of words into the CRC peripheral. Returns the computed CRC. pub fn feed_words(&mut self, words: &[u32]) -> u32 { for word in words { - #[cfg(not(crc_v1))] - PAC_CRC.dr32().write_value(*word); - #[cfg(crc_v1)] PAC_CRC.dr().write_value(*word); } @@ -46,12 +40,6 @@ impl<'d> Crc<'d> { } /// Read the CRC result value. - #[cfg(not(crc_v1))] - pub fn read(&self) -> u32 { - PAC_CRC.dr32().read() - } - /// Read the CRC result value. - #[cfg(crc_v1)] pub fn read(&self) -> u32 { PAC_CRC.dr().read() } diff --git a/embassy-stm32/src/crc/v2v3.rs b/embassy-stm32/src/crc/v2v3.rs index c94c9f380..d834d0971 100644 --- a/embassy-stm32/src/crc/v2v3.rs +++ b/embassy-stm32/src/crc/v2v3.rs @@ -9,7 +9,7 @@ pub struct Crc<'d> { _config: Config, } -/// CRC configuration errlr +/// CRC configuration error #[derive(Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum ConfigError { @@ -34,9 +34,9 @@ pub enum InputReverseConfig { None, /// Reverse bytes Byte, - /// Reverse 16-bit halfwords. + /// Reverse 16-bit halfwords Halfword, - /// Reverse 32-bit words. + /// Reverse 32-bit words Word, } @@ -127,45 +127,52 @@ impl<'d> Crc<'d> { PolySize::Width32 => vals::Polysize::POLYSIZE32, }); }); - - self.reset(); } - /// Feeds a byte into the CRC peripheral. Returns the computed checksum. - pub fn feed_byte(&mut self, byte: u8) -> u32 { - PAC_CRC.dr8().write_value(byte); + /// Read the CRC result value. + pub fn read(&self) -> u32 { PAC_CRC.dr32().read() } - /// Feeds an slice of bytes into the CRC peripheral. Returns the computed checksum. + /// Feeds a byte into the CRC peripheral. Returns the computed CRC. + pub fn feed_byte(&mut self, byte: u8) -> u32 { + PAC_CRC.dr8().write_value(byte); + self.read() + } + + /// Feeds a slice of bytes into the CRC peripheral. Returns the computed CRC. pub fn feed_bytes(&mut self, bytes: &[u8]) -> u32 { for byte in bytes { PAC_CRC.dr8().write_value(*byte); } - PAC_CRC.dr32().read() + self.read() } - /// Feeds a halfword into the CRC peripheral. Returns the computed checksum. + + /// Feeds a halfword into the CRC peripheral. Returns the computed CRC. pub fn feed_halfword(&mut self, halfword: u16) -> u32 { PAC_CRC.dr16().write_value(halfword); - PAC_CRC.dr32().read() + self.read() } - /// Feeds an slice of halfwords into the CRC peripheral. Returns the computed checksum. + + /// Feeds a slice of halfwords into the CRC peripheral. Returns the computed CRC. pub fn feed_halfwords(&mut self, halfwords: &[u16]) -> u32 { for halfword in halfwords { PAC_CRC.dr16().write_value(*halfword); } - PAC_CRC.dr32().read() + self.read() } - /// Feeds a words into the CRC peripheral. Returns the computed checksum. + + /// Feeds a word into the CRC peripheral. Returns the computed CRC. pub fn feed_word(&mut self, word: u32) -> u32 { PAC_CRC.dr32().write_value(word as u32); - PAC_CRC.dr32().read() + self.read() } - /// Feeds an slice of words into the CRC peripheral. Returns the computed checksum. + + /// Feeds a slice of words into the CRC peripheral. Returns the computed CRC. pub fn feed_words(&mut self, words: &[u32]) -> u32 { for word in words { PAC_CRC.dr32().write_value(*word as u32); } - PAC_CRC.dr32().read() + self.read() } } From f761e4b97b533388433ac3de8063d0a1aa2dc0e0 Mon Sep 17 00:00:00 2001 From: bobsrac Date: Fri, 23 May 2025 22:01:07 -0600 Subject: [PATCH 1203/1217] nrf52840: example ieee 802.15.4 packet send/receive --- .../nrf52840/src/bin/ieee802154_receive.rs | 38 ++++++++++++++++++ examples/nrf52840/src/bin/ieee802154_send.rs | 39 +++++++++++++++++++ 2 files changed, 77 insertions(+) create mode 100644 examples/nrf52840/src/bin/ieee802154_receive.rs create mode 100644 examples/nrf52840/src/bin/ieee802154_send.rs diff --git a/examples/nrf52840/src/bin/ieee802154_receive.rs b/examples/nrf52840/src/bin/ieee802154_receive.rs new file mode 100644 index 000000000..ede8fca65 --- /dev/null +++ b/examples/nrf52840/src/bin/ieee802154_receive.rs @@ -0,0 +1,38 @@ +#![no_std] +#![no_main] + +use embassy_executor::Spawner; +use embassy_nrf::config::{Config, HfclkSource}; +use embassy_nrf::gpio::{Level, Output, OutputDrive}; +use embassy_nrf::radio::ieee802154::{self, Packet}; +use embassy_nrf::{peripherals, radio}; +use embassy_time::Timer; +use {defmt_rtt as _, panic_probe as _}; + +embassy_nrf::bind_interrupts!(struct Irqs { + RADIO => radio::InterruptHandler; +}); + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let mut config = Config::default(); + config.hfclk_source = HfclkSource::ExternalXtal; + let peripherals = embassy_nrf::init(config); + + // assumes LED on P0_15 with active-high polarity + let mut gpo_led = Output::new(peripherals.P0_15, Level::Low, OutputDrive::Standard); + + let mut radio = ieee802154::Radio::new(peripherals.RADIO, Irqs); + let mut packet = Packet::new(); + + loop { + gpo_led.set_low(); + let rv = radio.receive(&mut packet).await; + gpo_led.set_high(); + match rv { + Err(_) => defmt::error!("receive() Err"), + Ok(_) => defmt::info!("receive() {:?}", *packet), + } + Timer::after_millis(100u64).await; + } +} diff --git a/examples/nrf52840/src/bin/ieee802154_send.rs b/examples/nrf52840/src/bin/ieee802154_send.rs new file mode 100644 index 000000000..7af9d1d06 --- /dev/null +++ b/examples/nrf52840/src/bin/ieee802154_send.rs @@ -0,0 +1,39 @@ +#![no_std] +#![no_main] + +use embassy_executor::Spawner; +use embassy_nrf::config::{Config, HfclkSource}; +use embassy_nrf::gpio::{Level, Output, OutputDrive}; +use embassy_nrf::radio::ieee802154::{self, Packet}; +use embassy_nrf::{peripherals, radio}; +use embassy_time::Timer; +use {defmt_rtt as _, panic_probe as _}; + +embassy_nrf::bind_interrupts!(struct Irqs { + RADIO => radio::InterruptHandler; +}); + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let mut config = Config::default(); + config.hfclk_source = HfclkSource::ExternalXtal; + let peripherals = embassy_nrf::init(config); + + // assumes LED on P0_15 with active-high polarity + let mut gpo_led = Output::new(peripherals.P0_15, Level::Low, OutputDrive::Standard); + + let mut radio = ieee802154::Radio::new(peripherals.RADIO, Irqs); + let mut packet = Packet::new(); + + loop { + packet.copy_from_slice(&[0_u8; 16]); + gpo_led.set_high(); + let rv = radio.try_send(&mut packet).await; + gpo_led.set_low(); + match rv { + Err(_) => defmt::error!("try_send() Err"), + Ok(_) => defmt::info!("try_send() {:?}", *packet), + } + Timer::after_millis(1000u64).await; + } +} From 042abc805a84d09231174e41edb0e498baaf7295 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Wed, 28 May 2025 10:36:05 +0200 Subject: [PATCH 1204/1217] feat: add support for channel peek Add support for peeking into the front of the channel if the value implements Clone. This can be useful in single-receiver situations where you don't want to remove the item from the queue until you've successfully processed it. --- embassy-sync/src/channel.rs | 78 ++++++++++++++++++++++++++++ embassy-sync/src/priority_channel.rs | 64 +++++++++++++++++++++++ 2 files changed, 142 insertions(+) diff --git a/embassy-sync/src/channel.rs b/embassy-sync/src/channel.rs index 4d1fa9e39..a229c52e7 100644 --- a/embassy-sync/src/channel.rs +++ b/embassy-sync/src/channel.rs @@ -208,6 +208,16 @@ where self.channel.try_receive() } + /// Peek at the next value without removing it from the queue. + /// + /// See [`Channel::try_peek()`] + pub fn try_peek(&self) -> Result + where + T: Clone, + { + self.channel.try_peek() + } + /// Allows a poll_fn to poll until the channel is ready to receive /// /// See [`Channel::poll_ready_to_receive()`] @@ -293,6 +303,16 @@ impl<'ch, T> DynamicReceiver<'ch, T> { self.channel.try_receive_with_context(None) } + /// Peek at the next value without removing it from the queue. + /// + /// See [`Channel::try_peek()`] + pub fn try_peek(&self) -> Result + where + T: Clone, + { + self.channel.try_peek_with_context(None) + } + /// Allows a poll_fn to poll until the channel is ready to receive /// /// See [`Channel::poll_ready_to_receive()`] @@ -463,6 +483,10 @@ pub(crate) trait DynamicChannel { fn try_receive_with_context(&self, cx: Option<&mut Context<'_>>) -> Result; + fn try_peek_with_context(&self, cx: Option<&mut Context<'_>>) -> Result + where + T: Clone; + fn poll_ready_to_send(&self, cx: &mut Context<'_>) -> Poll<()>; fn poll_ready_to_receive(&self, cx: &mut Context<'_>) -> Poll<()>; @@ -505,6 +529,31 @@ impl ChannelState { self.try_receive_with_context(None) } + fn try_peek(&mut self) -> Result + where + T: Clone, + { + self.try_peek_with_context(None) + } + + fn try_peek_with_context(&mut self, cx: Option<&mut Context<'_>>) -> Result + where + T: Clone, + { + if self.queue.is_full() { + self.senders_waker.wake(); + } + + if let Some(message) = self.queue.front() { + Ok(message.clone()) + } else { + if let Some(cx) = cx { + self.receiver_waker.register(cx.waker()); + } + Err(TryReceiveError::Empty) + } + } + fn try_receive_with_context(&mut self, cx: Option<&mut Context<'_>>) -> Result { if self.queue.is_full() { self.senders_waker.wake(); @@ -634,6 +683,13 @@ where self.lock(|c| c.try_receive_with_context(cx)) } + fn try_peek_with_context(&self, cx: Option<&mut Context<'_>>) -> Result + where + T: Clone, + { + self.lock(|c| c.try_peek_with_context(cx)) + } + /// Poll the channel for the next message pub fn poll_receive(&self, cx: &mut Context<'_>) -> Poll { self.lock(|c| c.poll_receive(cx)) @@ -722,6 +778,17 @@ where self.lock(|c| c.try_receive()) } + /// Peek at the next value without removing it from the queue. + /// + /// This method will either receive a copy of the message from the channel immediately or return + /// an error if the channel is empty. + pub fn try_peek(&self) -> Result + where + T: Clone, + { + self.lock(|c| c.try_peek()) + } + /// Returns the maximum number of elements the channel can hold. pub const fn capacity(&self) -> usize { N @@ -769,6 +836,13 @@ where Channel::try_receive_with_context(self, cx) } + fn try_peek_with_context(&self, cx: Option<&mut Context<'_>>) -> Result + where + T: Clone, + { + Channel::try_peek_with_context(self, cx) + } + fn poll_ready_to_send(&self, cx: &mut Context<'_>) -> Poll<()> { Channel::poll_ready_to_send(self, cx) } @@ -851,6 +925,8 @@ mod tests { fn simple_send_and_receive() { let c = Channel::::new(); assert!(c.try_send(1).is_ok()); + assert_eq!(c.try_peek().unwrap(), 1); + assert_eq!(c.try_peek().unwrap(), 1); assert_eq!(c.try_receive().unwrap(), 1); } @@ -881,6 +957,8 @@ mod tests { let r = c.dyn_receiver(); assert!(s.try_send(1).is_ok()); + assert_eq!(r.try_peek().unwrap(), 1); + assert_eq!(r.try_peek().unwrap(), 1); assert_eq!(r.try_receive().unwrap(), 1); } diff --git a/embassy-sync/src/priority_channel.rs b/embassy-sync/src/priority_channel.rs index 36959204f..623c52993 100644 --- a/embassy-sync/src/priority_channel.rs +++ b/embassy-sync/src/priority_channel.rs @@ -175,6 +175,16 @@ where self.channel.try_receive() } + /// Peek at the next value without removing it from the queue. + /// + /// See [`PriorityChannel::try_peek()`] + pub fn try_peek(&self) -> Result + where + T: Clone, + { + self.channel.try_peek_with_context(None) + } + /// Allows a poll_fn to poll until the channel is ready to receive /// /// See [`PriorityChannel::poll_ready_to_receive()`] @@ -343,6 +353,31 @@ where self.try_receive_with_context(None) } + fn try_peek(&mut self) -> Result + where + T: Clone, + { + self.try_peek_with_context(None) + } + + fn try_peek_with_context(&mut self, cx: Option<&mut Context<'_>>) -> Result + where + T: Clone, + { + if self.queue.len() == self.queue.capacity() { + self.senders_waker.wake(); + } + + if let Some(message) = self.queue.peek() { + Ok(message.clone()) + } else { + if let Some(cx) = cx { + self.receiver_waker.register(cx.waker()); + } + Err(TryReceiveError::Empty) + } + } + fn try_receive_with_context(&mut self, cx: Option<&mut Context<'_>>) -> Result { if self.queue.len() == self.queue.capacity() { self.senders_waker.wake(); @@ -478,6 +513,13 @@ where self.lock(|c| c.try_receive_with_context(cx)) } + fn try_peek_with_context(&self, cx: Option<&mut Context<'_>>) -> Result + where + T: Clone, + { + self.lock(|c| c.try_peek_with_context(cx)) + } + /// Poll the channel for the next message pub fn poll_receive(&self, cx: &mut Context<'_>) -> Poll { self.lock(|c| c.poll_receive(cx)) @@ -548,6 +590,17 @@ where self.lock(|c| c.try_receive()) } + /// Peek at the next value without removing it from the queue. + /// + /// This method will either receive a copy of the message from the channel immediately or return + /// an error if the channel is empty. + pub fn try_peek(&self) -> Result + where + T: Clone, + { + self.lock(|c| c.try_peek()) + } + /// Removes elements from the channel based on the given predicate. pub fn remove_if(&self, predicate: F) where @@ -617,6 +670,13 @@ where PriorityChannel::try_receive_with_context(self, cx) } + fn try_peek_with_context(&self, cx: Option<&mut Context<'_>>) -> Result + where + T: Clone, + { + PriorityChannel::try_peek_with_context(self, cx) + } + fn poll_ready_to_send(&self, cx: &mut Context<'_>) -> Poll<()> { PriorityChannel::poll_ready_to_send(self, cx) } @@ -705,6 +765,8 @@ mod tests { fn simple_send_and_receive() { let c = PriorityChannel::::new(); assert!(c.try_send(1).is_ok()); + assert_eq!(c.try_peek().unwrap(), 1); + assert_eq!(c.try_peek().unwrap(), 1); assert_eq!(c.try_receive().unwrap(), 1); } @@ -725,6 +787,8 @@ mod tests { let r: DynamicReceiver<'_, u32> = c.receiver().into(); assert!(s.try_send(1).is_ok()); + assert_eq!(r.try_peek().unwrap(), 1); + assert_eq!(r.try_peek().unwrap(), 1); assert_eq!(r.try_receive().unwrap(), 1); } From 277f6f7331684a0008930a43b6705ba52873d1f5 Mon Sep 17 00:00:00 2001 From: Corey Schuhen Date: Wed, 28 May 2025 18:15:15 +1000 Subject: [PATCH 1205/1217] Make Sync capable versions of DynamicSender and DynamicReceiver. DynamicSender and DynamicReceiver, just seem to be a fat pointer to a Channel which is already protected by it's own Mutex already. In fact, you can share the Channel already betwen threads and create Dynamic*er's in the target threads. It should be safe to share the Dynamic*er's directly. Can only be used when Mutex M of channel supoorts Sync. --- embassy-sync/src/channel.rs | 106 ++++++++++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) diff --git a/embassy-sync/src/channel.rs b/embassy-sync/src/channel.rs index 4d1fa9e39..1b053ecad 100644 --- a/embassy-sync/src/channel.rs +++ b/embassy-sync/src/channel.rs @@ -164,6 +164,57 @@ impl<'ch, T> DynamicSender<'ch, T> { } } +/// Send-only access to a [`Channel`] without knowing channel size. +/// This version can be sent between threads but can only be created if the underlying mutex is Sync. +pub struct SendDynamicSender<'ch, T> { + pub(crate) channel: &'ch dyn DynamicChannel, +} + +impl<'ch, T> Clone for SendDynamicSender<'ch, T> { + fn clone(&self) -> Self { + *self + } +} + +impl<'ch, T> Copy for SendDynamicSender<'ch, T> {} +unsafe impl<'ch, T: Send> Send for SendDynamicSender<'ch, T> {} +unsafe impl<'ch, T: Send> Sync for SendDynamicSender<'ch, T> {} + +impl<'ch, M, T, const N: usize> From> for SendDynamicSender<'ch, T> +where + M: RawMutex + Sync + Send, +{ + fn from(s: Sender<'ch, M, T, N>) -> Self { + Self { channel: s.channel } + } +} + +impl<'ch, T> SendDynamicSender<'ch, T> { + /// Sends a value. + /// + /// See [`Channel::send()`] + pub fn send(&self, message: T) -> DynamicSendFuture<'ch, T> { + DynamicSendFuture { + channel: self.channel, + message: Some(message), + } + } + + /// Attempt to immediately send a message. + /// + /// See [`Channel::send()`] + pub fn try_send(&self, message: T) -> Result<(), TrySendError> { + self.channel.try_send_with_context(message, None) + } + + /// Allows a poll_fn to poll until the channel is ready to send + /// + /// See [`Channel::poll_ready_to_send()`] + pub fn poll_ready_to_send(&self, cx: &mut Context<'_>) -> Poll<()> { + self.channel.poll_ready_to_send(cx) + } +} + /// Receive-only access to a [`Channel`]. pub struct Receiver<'ch, M, T, const N: usize> where @@ -317,6 +368,61 @@ where } } +/// Receive-only access to a [`Channel`] without knowing channel size. +/// This version can be sent between threads but can only be created if the underlying mutex is Sync. +pub struct SendableDynamicReceiver<'ch, T> { + pub(crate) channel: &'ch dyn DynamicChannel, +} + +impl<'ch, T> Clone for SendableDynamicReceiver<'ch, T> { + fn clone(&self) -> Self { + *self + } +} + +impl<'ch, T> Copy for SendableDynamicReceiver<'ch, T> {} +unsafe impl<'ch, T: Send> Send for SendableDynamicReceiver<'ch, T> {} +unsafe impl<'ch, T: Send> Sync for SendableDynamicReceiver<'ch, T> {} + +impl<'ch, T> SendableDynamicReceiver<'ch, T> { + /// Receive the next value. + /// + /// See [`Channel::receive()`]. + pub fn receive(&self) -> DynamicReceiveFuture<'_, T> { + DynamicReceiveFuture { channel: self.channel } + } + + /// Attempt to immediately receive the next value. + /// + /// See [`Channel::try_receive()`] + pub fn try_receive(&self) -> Result { + self.channel.try_receive_with_context(None) + } + + /// Allows a poll_fn to poll until the channel is ready to receive + /// + /// See [`Channel::poll_ready_to_receive()`] + pub fn poll_ready_to_receive(&self, cx: &mut Context<'_>) -> Poll<()> { + self.channel.poll_ready_to_receive(cx) + } + + /// Poll the channel for the next item + /// + /// See [`Channel::poll_receive()`] + pub fn poll_receive(&self, cx: &mut Context<'_>) -> Poll { + self.channel.poll_receive(cx) + } +} + +impl<'ch, M, T, const N: usize> From> for SendableDynamicReceiver<'ch, T> +where + M: RawMutex + Sync + Send, +{ + fn from(s: Receiver<'ch, M, T, N>) -> Self { + Self { channel: s.channel } + } +} + impl<'ch, M, T, const N: usize> futures_util::Stream for Receiver<'ch, M, T, N> where M: RawMutex, From dfd2d31819835820ecb196cd0497d1456ba1b825 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Wed, 28 May 2025 12:35:59 +0200 Subject: [PATCH 1206/1217] docs: update changelog for embassy-sync --- embassy-sync/CHANGELOG.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/embassy-sync/CHANGELOG.md b/embassy-sync/CHANGELOG.md index 1770bef44..89684de0c 100644 --- a/embassy-sync/CHANGELOG.md +++ b/embassy-sync/CHANGELOG.md @@ -7,7 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased -## 0.7.0 - 2025-05-22 +## 0.7.0 - 2025-05-28 - Add `remove_if` to `priority_channel::{Receiver, PriorityChannel}`. - impl `Stream` for `channel::{Receiver, Channel}`. @@ -21,6 +21,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Improve waker documentation. - Improve `Signal` and `Watch` documentation. - Update to defmt 1.0. This remains compatible with latest defmt 0.3. +- Add `peek` method on `channel` and `priority_channel`. +- Add dynamic sender and receiver that are Send + Sync for `channel`. ## 0.6.2 - 2025-01-15 From 5a07ea5d851768223e2e41342e69d14c1afb2b2b Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Sun, 9 Mar 2025 20:55:11 +0100 Subject: [PATCH 1207/1217] Add support for Cortex-A/R --- ci-nightly.sh | 1 + ci.sh | 3 + embassy-executor-macros/src/lib.rs | 25 +++++++ embassy-executor-macros/src/macros/main.rs | 6 ++ embassy-executor/CHANGELOG.md | 4 ++ embassy-executor/Cargo.toml | 5 ++ embassy-executor/src/arch/cortex_ar.rs | 84 ++++++++++++++++++++++ embassy-executor/src/lib.rs | 2 + rust-toolchain-nightly.toml | 1 + rust-toolchain.toml | 3 + 10 files changed, 134 insertions(+) create mode 100644 embassy-executor/src/arch/cortex_ar.rs diff --git a/ci-nightly.sh b/ci-nightly.sh index c0a2482e7..d486d442c 100755 --- a/ci-nightly.sh +++ b/ci-nightly.sh @@ -21,5 +21,6 @@ cargo batch \ --- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features nightly,arch-riscv32 \ --- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features nightly,arch-riscv32,executor-thread \ --- build --release --manifest-path examples/nrf52840-rtic/Cargo.toml --target thumbv7em-none-eabi --artifact-dir out/examples/nrf52840-rtic \ + --- build --release --manifest-path embassy-executor/Cargo.toml --target armv7a-none-eabi --features nightly,arch-cortex-ar,executor-thread \ RUSTFLAGS="$RUSTFLAGS -C target-cpu=atmega328p" cargo build --release --manifest-path embassy-executor/Cargo.toml --target avr-none -Z build-std=core,alloc --features nightly,arch-avr,avr-device/atmega328p diff --git a/ci.sh b/ci.sh index d21c1c97b..e1fdf998a 100755 --- a/ci.sh +++ b/ci.sh @@ -35,6 +35,9 @@ cargo batch \ --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,executor-thread \ --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,executor-interrupt \ --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,executor-thread,executor-interrupt \ + --- build --release --manifest-path embassy-executor/Cargo.toml --target armv7a-none-eabi --features arch-cortex-ar,executor-thread \ + --- build --release --manifest-path embassy-executor/Cargo.toml --target armv7r-none-eabi --features arch-cortex-ar,executor-thread \ + --- build --release --manifest-path embassy-executor/Cargo.toml --target armv7r-none-eabihf --features arch-cortex-ar,executor-thread \ --- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features arch-riscv32 \ --- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features arch-riscv32,executor-thread \ --- build --release --manifest-path embassy-sync/Cargo.toml --target thumbv6m-none-eabi --features defmt \ diff --git a/embassy-executor-macros/src/lib.rs b/embassy-executor-macros/src/lib.rs index 8e737db6a..962ce2e75 100644 --- a/embassy-executor-macros/src/lib.rs +++ b/embassy-executor-macros/src/lib.rs @@ -70,6 +70,31 @@ pub fn main_cortex_m(args: TokenStream, item: TokenStream) -> TokenStream { main::run(args.into(), item.into(), &main::ARCH_CORTEX_M).into() } +/// Creates a new `executor` instance and declares an application entry point for Cortex-A/R +/// spawning the corresponding function body as an async task. +/// +/// The following restrictions apply: +/// +/// * The function must accept exactly 1 parameter, an `embassy_executor::Spawner` handle that it +/// can use to spawn additional tasks. +/// * The function must be declared `async`. +/// * The function must not use generics. +/// * Only a single `main` task may be declared. +/// +/// ## Examples +/// Spawning a task: +/// +/// ``` rust +/// #[embassy_executor::main] +/// async fn main(_s: embassy_executor::Spawner) { +/// // Function body +/// } +/// ``` +#[proc_macro_attribute] +pub fn main_cortex_ar(args: TokenStream, item: TokenStream) -> TokenStream { + main::run(args.into(), item.into(), &main::ARCH_CORTEX_AR).into() +} + /// Creates a new `executor` instance and declares an architecture agnostic application entry point spawning /// the corresponding function body as an async task. /// diff --git a/embassy-executor-macros/src/macros/main.rs b/embassy-executor-macros/src/macros/main.rs index 95722b19b..a0e7b3401 100644 --- a/embassy-executor-macros/src/macros/main.rs +++ b/embassy-executor-macros/src/macros/main.rs @@ -37,6 +37,12 @@ pub static ARCH_CORTEX_M: Arch = Arch { executor_required: false, }; +pub static ARCH_CORTEX_AR: Arch = Arch { + default_entry: None, + flavor: Flavor::Standard, + executor_required: false, +}; + pub static ARCH_SPIN: Arch = Arch { default_entry: None, flavor: Flavor::Standard, diff --git a/embassy-executor/CHANGELOG.md b/embassy-executor/CHANGELOG.md index 5d2468c58..608c67724 100644 --- a/embassy-executor/CHANGELOG.md +++ b/embassy-executor/CHANGELOG.md @@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## unreleased + +- Added support for Cortex-A and Cortex-R + ## 0.7.0 - 2025-01-02 - Performance optimizations. diff --git a/embassy-executor/Cargo.toml b/embassy-executor/Cargo.toml index 9f9eaa600..f014ccf30 100644 --- a/embassy-executor/Cargo.toml +++ b/embassy-executor/Cargo.toml @@ -45,6 +45,9 @@ portable-atomic = { version = "1.5", optional = true } # arch-cortex-m dependencies cortex-m = { version = "0.7.6", optional = true } +# arch-cortex-ar dependencies +cortex-ar = { version = "0.2", optional = true } + # arch-wasm dependencies wasm-bindgen = { version = "0.2.82", optional = true } js-sys = { version = "0.3", optional = true } @@ -73,6 +76,8 @@ _arch = [] # some arch was picked arch-std = ["_arch"] ## Cortex-M arch-cortex-m = ["_arch", "dep:cortex-m"] +## Cortex-A/R +arch-cortex-ar = ["_arch", "dep:cortex-ar"] ## RISC-V 32 arch-riscv32 = ["_arch"] ## WASM diff --git a/embassy-executor/src/arch/cortex_ar.rs b/embassy-executor/src/arch/cortex_ar.rs new file mode 100644 index 000000000..f9e2f3f7c --- /dev/null +++ b/embassy-executor/src/arch/cortex_ar.rs @@ -0,0 +1,84 @@ +#[cfg(feature = "executor-interrupt")] +compile_error!("`executor-interrupt` is not supported with `arch-cortex-ar`."); + +#[export_name = "__pender"] +#[cfg(any(feature = "executor-thread", feature = "executor-interrupt"))] +fn __pender(context: *mut ()) { + // `context` is always `usize::MAX` created by `Executor::run`. + let context = context as usize; + + #[cfg(feature = "executor-thread")] + // Try to make Rust optimize the branching away if we only use thread mode. + if !cfg!(feature = "executor-interrupt") || context == THREAD_PENDER { + cortex_ar::asm::sev(); + return; + } +} + +#[cfg(feature = "executor-thread")] +pub use thread::*; +#[cfg(feature = "executor-thread")] +mod thread { + pub(super) const THREAD_PENDER: usize = usize::MAX; + + use core::marker::PhantomData; + + use cortex_ar::asm::wfe; + pub use embassy_executor_macros::main_cortex_ar as main; + + use crate::{raw, Spawner}; + + /// Thread mode executor, using WFE/SEV. + /// + /// This is the simplest and most common kind of executor. It runs on + /// thread mode (at the lowest priority level), and uses the `WFE` ARM instruction + /// to sleep when it has no more work to do. When a task is woken, a `SEV` instruction + /// is executed, to make the `WFE` exit from sleep and poll the task. + /// + /// This executor allows for ultra low power consumption for chips where `WFE` + /// triggers low-power sleep without extra steps. If your chip requires extra steps, + /// you may use [`raw::Executor`] directly to program custom behavior. + pub struct Executor { + inner: raw::Executor, + not_send: PhantomData<*mut ()>, + } + + impl Executor { + /// Create a new Executor. + pub fn new() -> Self { + Self { + inner: raw::Executor::new(THREAD_PENDER as *mut ()), + not_send: PhantomData, + } + } + + /// Run the executor. + /// + /// The `init` closure is called with a [`Spawner`] that spawns tasks on + /// this executor. Use it to spawn the initial task(s). After `init` returns, + /// the executor starts running the tasks. + /// + /// To spawn more tasks later, you may keep copies of the [`Spawner`] (it is `Copy`), + /// for example by passing it as an argument to the initial tasks. + /// + /// This function requires `&'static mut self`. This means you have to store the + /// Executor instance in a place where it'll live forever and grants you mutable + /// access. There's a few ways to do this: + /// + /// - a [StaticCell](https://docs.rs/static_cell/latest/static_cell/) (safe) + /// - a `static mut` (unsafe) + /// - a local variable in a function you know never returns (like `fn main() -> !`), upgrading its lifetime with `transmute`. (unsafe) + /// + /// This function never returns. + pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! { + init(self.inner.spawner()); + + loop { + unsafe { + self.inner.poll(); + } + wfe(); + } + } + } +} diff --git a/embassy-executor/src/lib.rs b/embassy-executor/src/lib.rs index d6fd3d651..dfe420bab 100644 --- a/embassy-executor/src/lib.rs +++ b/embassy-executor/src/lib.rs @@ -26,6 +26,7 @@ macro_rules! check_at_most_one { check_at_most_one!( "arch-avr", "arch-cortex-m", + "arch-cortex-ar", "arch-riscv32", "arch-std", "arch-wasm", @@ -35,6 +36,7 @@ check_at_most_one!( #[cfg(feature = "_arch")] #[cfg_attr(feature = "arch-avr", path = "arch/avr.rs")] #[cfg_attr(feature = "arch-cortex-m", path = "arch/cortex_m.rs")] +#[cfg_attr(feature = "arch-cortex-ar", path = "arch/cortex_ar.rs")] #[cfg_attr(feature = "arch-riscv32", path = "arch/riscv32.rs")] #[cfg_attr(feature = "arch-std", path = "arch/std.rs")] #[cfg_attr(feature = "arch-wasm", path = "arch/wasm.rs")] diff --git a/rust-toolchain-nightly.toml b/rust-toolchain-nightly.toml index d803b29a0..e75ea40cc 100644 --- a/rust-toolchain-nightly.toml +++ b/rust-toolchain-nightly.toml @@ -9,4 +9,5 @@ targets = [ "thumbv8m.main-none-eabihf", "riscv32imac-unknown-none-elf", "wasm32-unknown-unknown", + "armv7a-none-eabi", ] diff --git a/rust-toolchain.toml b/rust-toolchain.toml index ca5816121..870904c3a 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -9,4 +9,7 @@ targets = [ "thumbv8m.main-none-eabihf", "riscv32imac-unknown-none-elf", "wasm32-unknown-unknown", + "armv7a-none-eabi", + "armv7r-none-eabi", + "armv7r-none-eabihf", ] From 5730b57094d6e2da3645326596532a091b47ec86 Mon Sep 17 00:00:00 2001 From: Corey Schuhen Date: Thu, 29 May 2025 08:30:21 +1000 Subject: [PATCH 1208/1217] Rename SendableDynamicReceiver to SendDynamicReceiver --- embassy-sync/src/channel.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/embassy-sync/src/channel.rs b/embassy-sync/src/channel.rs index f97cb2b8e..856551417 100644 --- a/embassy-sync/src/channel.rs +++ b/embassy-sync/src/channel.rs @@ -390,21 +390,21 @@ where /// Receive-only access to a [`Channel`] without knowing channel size. /// This version can be sent between threads but can only be created if the underlying mutex is Sync. -pub struct SendableDynamicReceiver<'ch, T> { +pub struct SendDynamicReceiver<'ch, T> { pub(crate) channel: &'ch dyn DynamicChannel, } -impl<'ch, T> Clone for SendableDynamicReceiver<'ch, T> { +impl<'ch, T> Clone for SendDynamicReceiver<'ch, T> { fn clone(&self) -> Self { *self } } -impl<'ch, T> Copy for SendableDynamicReceiver<'ch, T> {} -unsafe impl<'ch, T: Send> Send for SendableDynamicReceiver<'ch, T> {} -unsafe impl<'ch, T: Send> Sync for SendableDynamicReceiver<'ch, T> {} +impl<'ch, T> Copy for SendDynamicReceiver<'ch, T> {} +unsafe impl<'ch, T: Send> Send for SendDynamicReceiver<'ch, T> {} +unsafe impl<'ch, T: Send> Sync for SendDynamicReceiver<'ch, T> {} -impl<'ch, T> SendableDynamicReceiver<'ch, T> { +impl<'ch, T> SendDynamicReceiver<'ch, T> { /// Receive the next value. /// /// See [`Channel::receive()`]. @@ -434,7 +434,7 @@ impl<'ch, T> SendableDynamicReceiver<'ch, T> { } } -impl<'ch, M, T, const N: usize> From> for SendableDynamicReceiver<'ch, T> +impl<'ch, M, T, const N: usize> From> for SendDynamicReceiver<'ch, T> where M: RawMutex + Sync + Send, { From 3d617007a257b814459e6e8c8c3ee4bce77469e3 Mon Sep 17 00:00:00 2001 From: Willdew Date: Thu, 29 May 2025 23:06:01 +0200 Subject: [PATCH 1209/1217] fixed n in set_sq to be indexed correctly --- embassy-stm32/src/adc/ringbuffered_v2.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/embassy-stm32/src/adc/ringbuffered_v2.rs b/embassy-stm32/src/adc/ringbuffered_v2.rs index fabf0284b..6f69e8486 100644 --- a/embassy-stm32/src/adc/ringbuffered_v2.rs +++ b/embassy-stm32/src/adc/ringbuffered_v2.rs @@ -199,16 +199,16 @@ impl<'d, T: Instance> RingBufferedAdc<'d, T> { Sequence::Four => T::regs().sqr3().modify(|w| w.set_sq(3, channel.channel())), Sequence::Five => T::regs().sqr3().modify(|w| w.set_sq(4, channel.channel())), Sequence::Six => T::regs().sqr3().modify(|w| w.set_sq(5, channel.channel())), - Sequence::Seven => T::regs().sqr2().modify(|w| w.set_sq(6, channel.channel())), - Sequence::Eight => T::regs().sqr2().modify(|w| w.set_sq(7, channel.channel())), - Sequence::Nine => T::regs().sqr2().modify(|w| w.set_sq(8, channel.channel())), - Sequence::Ten => T::regs().sqr2().modify(|w| w.set_sq(9, channel.channel())), - Sequence::Eleven => T::regs().sqr2().modify(|w| w.set_sq(10, channel.channel())), - Sequence::Twelve => T::regs().sqr2().modify(|w| w.set_sq(11, channel.channel())), - Sequence::Thirteen => T::regs().sqr1().modify(|w| w.set_sq(12, channel.channel())), - Sequence::Fourteen => T::regs().sqr1().modify(|w| w.set_sq(13, channel.channel())), - Sequence::Fifteen => T::regs().sqr1().modify(|w| w.set_sq(14, channel.channel())), - Sequence::Sixteen => T::regs().sqr1().modify(|w| w.set_sq(15, channel.channel())), + Sequence::Seven => T::regs().sqr2().modify(|w| w.set_sq(0, channel.channel())), + Sequence::Eight => T::regs().sqr2().modify(|w| w.set_sq(1, channel.channel())), + Sequence::Nine => T::regs().sqr2().modify(|w| w.set_sq(2, channel.channel())), + Sequence::Ten => T::regs().sqr2().modify(|w| w.set_sq(3, channel.channel())), + Sequence::Eleven => T::regs().sqr2().modify(|w| w.set_sq(4, channel.channel())), + Sequence::Twelve => T::regs().sqr2().modify(|w| w.set_sq(5, channel.channel())), + Sequence::Thirteen => T::regs().sqr1().modify(|w| w.set_sq(0, channel.channel())), + Sequence::Fourteen => T::regs().sqr1().modify(|w| w.set_sq(1, channel.channel())), + Sequence::Fifteen => T::regs().sqr1().modify(|w| w.set_sq(2, channel.channel())), + Sequence::Sixteen => T::regs().sqr1().modify(|w| w.set_sq(3, channel.channel())), }; if !was_on { From 86efdc9cc39a47269d384424dc09c4642444e357 Mon Sep 17 00:00:00 2001 From: melvdl Date: Fri, 30 May 2025 00:28:35 +0200 Subject: [PATCH 1210/1217] convert embassy-stm32::qspi::enums `Into` impls into equivalant `From` impls --- embassy-stm32/src/qspi/enums.rs | 48 ++++++++++++++++----------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/embassy-stm32/src/qspi/enums.rs b/embassy-stm32/src/qspi/enums.rs index ecade9b1a..9ec4c1b43 100644 --- a/embassy-stm32/src/qspi/enums.rs +++ b/embassy-stm32/src/qspi/enums.rs @@ -9,9 +9,9 @@ pub(crate) enum QspiMode { MemoryMapped, } -impl Into for QspiMode { - fn into(self) -> u8 { - match self { +impl From for u8 { + fn from(val: QspiMode) -> Self { + match val { QspiMode::IndirectWrite => 0b00, QspiMode::IndirectRead => 0b01, QspiMode::AutoPolling => 0b10, @@ -34,9 +34,9 @@ pub enum QspiWidth { QUAD, } -impl Into for QspiWidth { - fn into(self) -> u8 { - match self { +impl From for u8 { + fn from(val: QspiWidth) -> Self { + match val { QspiWidth::NONE => 0b00, QspiWidth::SING => 0b01, QspiWidth::DUAL => 0b10, @@ -55,9 +55,9 @@ pub enum FlashSelection { Flash2, } -impl Into for FlashSelection { - fn into(self) -> bool { - match self { +impl From for bool { + fn from(val: FlashSelection) -> Self { + match val { FlashSelection::Flash1 => false, FlashSelection::Flash2 => true, } @@ -94,9 +94,9 @@ pub enum MemorySize { Other(u8), } -impl Into for MemorySize { - fn into(self) -> u8 { - match self { +impl From for u8 { + fn from(val: MemorySize) -> Self { + match val { MemorySize::_1KiB => 9, MemorySize::_2KiB => 10, MemorySize::_4KiB => 11, @@ -138,9 +138,9 @@ pub enum AddressSize { _32bit, } -impl Into for AddressSize { - fn into(self) -> u8 { - match self { +impl From for u8 { + fn from(val: AddressSize) -> Self { + match val { AddressSize::_8Bit => 0b00, AddressSize::_16Bit => 0b01, AddressSize::_24bit => 0b10, @@ -163,9 +163,9 @@ pub enum ChipSelectHighTime { _8Cycle, } -impl Into for ChipSelectHighTime { - fn into(self) -> u8 { - match self { +impl From for u8 { + fn from(val: ChipSelectHighTime) -> Self { + match val { ChipSelectHighTime::_1Cycle => 0, ChipSelectHighTime::_2Cycle => 1, ChipSelectHighTime::_3Cycle => 2, @@ -216,9 +216,9 @@ pub enum FIFOThresholdLevel { _32Bytes, } -impl Into for FIFOThresholdLevel { - fn into(self) -> u8 { - match self { +impl From for u8 { + fn from(val: FIFOThresholdLevel) -> Self { + match val { FIFOThresholdLevel::_1Bytes => 0, FIFOThresholdLevel::_2Bytes => 1, FIFOThresholdLevel::_3Bytes => 2, @@ -293,9 +293,9 @@ pub enum DummyCycles { _31, } -impl Into for DummyCycles { - fn into(self) -> u8 { - match self { +impl From for u8 { + fn from(val: DummyCycles) -> Self { + match val { DummyCycles::_0 => 0, DummyCycles::_1 => 1, DummyCycles::_2 => 2, From eba9ddc8055da13cb02c5732e30c37d2209cfa28 Mon Sep 17 00:00:00 2001 From: Corey Schuhen Date: Thu, 29 May 2025 20:47:33 +1000 Subject: [PATCH 1211/1217] Switch to SendDynamicSender for FDCAN. --- embassy-stm32/src/can/common.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/embassy-stm32/src/can/common.rs b/embassy-stm32/src/can/common.rs index e12111910..386d4467c 100644 --- a/embassy-stm32/src/can/common.rs +++ b/embassy-stm32/src/can/common.rs @@ -1,29 +1,29 @@ -use embassy_sync::channel::{DynamicReceiver, DynamicSender}; +use embassy_sync::channel::{SendDynamicReceiver, SendDynamicSender}; use super::enums::*; use super::frame::*; pub(crate) struct ClassicBufferedRxInner { - pub rx_sender: DynamicSender<'static, Result>, + pub rx_sender: SendDynamicSender<'static, Result>, } pub(crate) struct ClassicBufferedTxInner { - pub tx_receiver: DynamicReceiver<'static, Frame>, + pub tx_receiver: SendDynamicReceiver<'static, Frame>, } #[cfg(any(can_fdcan_v1, can_fdcan_h7))] pub(crate) struct FdBufferedRxInner { - pub rx_sender: DynamicSender<'static, Result>, + pub rx_sender: SendDynamicSender<'static, Result>, } #[cfg(any(can_fdcan_v1, can_fdcan_h7))] pub(crate) struct FdBufferedTxInner { - pub tx_receiver: DynamicReceiver<'static, FdFrame>, + pub tx_receiver: SendDynamicReceiver<'static, FdFrame>, } /// Sender that can be used for sending CAN frames. pub struct BufferedSender<'ch, FRAME> { - pub(crate) tx_buf: embassy_sync::channel::DynamicSender<'ch, FRAME>, + pub(crate) tx_buf: embassy_sync::channel::SendDynamicSender<'ch, FRAME>, pub(crate) waker: fn(), pub(crate) internal_operation: fn(InternalOperation), } @@ -70,7 +70,7 @@ pub type BufferedCanSender = BufferedSender<'static, Frame>; /// Receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver. pub struct BufferedReceiver<'ch, ENVELOPE> { - pub(crate) rx_buf: embassy_sync::channel::DynamicReceiver<'ch, Result>, + pub(crate) rx_buf: embassy_sync::channel::SendDynamicReceiver<'ch, Result>, pub(crate) internal_operation: fn(InternalOperation), } From f5658d6833cb140296a0b6f25b7eb6d16f06c520 Mon Sep 17 00:00:00 2001 From: Corey Schuhen Date: Thu, 29 May 2025 20:48:40 +1000 Subject: [PATCH 1212/1217] Put State inside a critical section mutex of RefCell. This removes the unsound code that was giving out mut&. to State --- embassy-stm32/src/can/fdcan.rs | 254 +++++++++++++++------------------ 1 file changed, 112 insertions(+), 142 deletions(-) diff --git a/embassy-stm32/src/can/fdcan.rs b/embassy-stm32/src/can/fdcan.rs index a7815f79b..4495280c4 100644 --- a/embassy-stm32/src/can/fdcan.rs +++ b/embassy-stm32/src/can/fdcan.rs @@ -52,36 +52,39 @@ impl interrupt::typelevel::Handler for IT0Interrup regs.ir().write(|w| w.set_tefn(true)); } - match &T::state().tx_mode { - TxMode::NonBuffered(waker) => waker.wake(), - TxMode::ClassicBuffered(buf) => { - if !T::registers().tx_queue_is_full() { - match buf.tx_receiver.try_receive() { - Ok(frame) => { - _ = T::registers().write(&frame); + T::info().state.lock(|s| { + let state = s.borrow_mut(); + match &state.tx_mode { + TxMode::NonBuffered(waker) => waker.wake(), + TxMode::ClassicBuffered(buf) => { + if !T::registers().tx_queue_is_full() { + match buf.tx_receiver.try_receive() { + Ok(frame) => { + _ = T::registers().write(&frame); + } + Err(_) => {} + } + } + } + TxMode::FdBuffered(buf) => { + if !T::registers().tx_queue_is_full() { + match buf.tx_receiver.try_receive() { + Ok(frame) => { + _ = T::registers().write(&frame); + } + Err(_) => {} } - Err(_) => {} } } } - TxMode::FdBuffered(buf) => { - if !T::registers().tx_queue_is_full() { - match buf.tx_receiver.try_receive() { - Ok(frame) => { - _ = T::registers().write(&frame); - } - Err(_) => {} - } - } - } - } - if ir.rfn(0) { - T::state().rx_mode.on_interrupt::(0); - } - if ir.rfn(1) { - T::state().rx_mode.on_interrupt::(1); - } + if ir.rfn(0) { + state.rx_mode.on_interrupt::(0, state.ns_per_timer_tick); + } + if ir.rfn(1) { + state.rx_mode.on_interrupt::(1, state.ns_per_timer_tick); + } + }); if ir.bo() { regs.ir().write(|w| w.set_bo(true)); @@ -165,7 +168,6 @@ pub struct CanConfigurator<'d> { _phantom: PhantomData<&'d ()>, config: crate::can::fd::config::FdCanConfig, info: &'static Info, - state: &'static State, /// Reference to internals. properties: Properties, periph_clock: crate::time::Hertz, @@ -188,9 +190,10 @@ impl<'d> CanConfigurator<'d> { rcc::enable_and_reset::(); let info = T::info(); - let state = unsafe { T::mut_state() }; - state.tx_pin_port = Some(tx.pin_port()); - state.rx_pin_port = Some(rx.pin_port()); + T::info().state.lock(|s| { + s.borrow_mut().tx_pin_port = Some(tx.pin_port()); + s.borrow_mut().rx_pin_port = Some(rx.pin_port()); + }); (info.internal_operation)(InternalOperation::NotifySenderCreated); (info.internal_operation)(InternalOperation::NotifyReceiverCreated); @@ -209,7 +212,6 @@ impl<'d> CanConfigurator<'d> { _phantom: PhantomData, config, info, - state, properties: Properties::new(T::info()), periph_clock: T::frequency(), } @@ -261,12 +263,8 @@ impl<'d> CanConfigurator<'d> { /// Start in mode. pub fn start(self, mode: OperatingMode) -> Can<'d> { let ns_per_timer_tick = calc_ns_per_timer_tick(self.info, self.periph_clock, self.config.frame_transmit); - critical_section::with(|_| { - let state = self.state as *const State; - unsafe { - let mut_state = state as *mut State; - (*mut_state).ns_per_timer_tick = ns_per_timer_tick; - } + self.info.state.lock(|s| { + s.borrow_mut().ns_per_timer_tick = ns_per_timer_tick; }); self.info.regs.into_mode(self.config, mode); (self.info.internal_operation)(InternalOperation::NotifySenderCreated); @@ -275,7 +273,6 @@ impl<'d> CanConfigurator<'d> { _phantom: PhantomData, config: self.config, info: self.info, - state: self.state, _mode: mode, properties: Properties::new(self.info), } @@ -309,7 +306,6 @@ pub struct Can<'d> { _phantom: PhantomData<&'d ()>, config: crate::can::fd::config::FdCanConfig, info: &'static Info, - state: &'static State, _mode: OperatingMode, properties: Properties, } @@ -323,7 +319,9 @@ impl<'d> Can<'d> { /// Flush one of the TX mailboxes. pub async fn flush(&self, idx: usize) { poll_fn(|cx| { - self.state.tx_mode.register(cx.waker()); + self.info.state.lock(|s| { + s.borrow_mut().tx_mode.register(cx.waker()); + }); if idx > 3 { panic!("Bad mailbox"); @@ -343,12 +341,12 @@ impl<'d> Can<'d> { /// can be replaced, this call asynchronously waits for a frame to be successfully /// transmitted, then tries again. pub async fn write(&mut self, frame: &Frame) -> Option { - self.state.tx_mode.write(self.info, frame).await + TxMode::write(self.info, frame).await } /// Returns the next received message frame pub async fn read(&mut self) -> Result { - self.state.rx_mode.read_classic(self.info, self.state).await + RxMode::read_classic(self.info).await } /// Queues the message to be sent but exerts backpressure. If a lower-priority @@ -356,12 +354,12 @@ impl<'d> Can<'d> { /// can be replaced, this call asynchronously waits for a frame to be successfully /// transmitted, then tries again. pub async fn write_fd(&mut self, frame: &FdFrame) -> Option { - self.state.tx_mode.write_fd(self.info, frame).await + TxMode::write_fd(self.info, frame).await } /// Returns the next received message frame pub async fn read_fd(&mut self) -> Result { - self.state.rx_mode.read_fd(self.info, self.state).await + RxMode::read_fd(self.info).await } /// Split instance into separate portions: Tx(write), Rx(read), common properties @@ -372,14 +370,12 @@ impl<'d> Can<'d> { CanTx { _phantom: PhantomData, info: self.info, - state: self.state, config: self.config, _mode: self._mode, }, CanRx { _phantom: PhantomData, info: self.info, - state: self.state, _mode: self._mode, }, Properties { @@ -395,7 +391,6 @@ impl<'d> Can<'d> { _phantom: PhantomData, config: tx.config, info: tx.info, - state: tx.state, _mode: rx._mode, properties: Properties::new(tx.info), } @@ -407,7 +402,7 @@ impl<'d> Can<'d> { tx_buf: &'static mut TxBuf, rxb: &'static mut RxBuf, ) -> BufferedCan<'d, TX_BUF_SIZE, RX_BUF_SIZE> { - BufferedCan::new(self.info, self.state, self._mode, tx_buf, rxb) + BufferedCan::new(self.info, self._mode, tx_buf, rxb) } /// Return a buffered instance of driver with CAN FD support. User must supply Buffers @@ -416,7 +411,7 @@ impl<'d> Can<'d> { tx_buf: &'static mut TxFdBuf, rxb: &'static mut RxFdBuf, ) -> BufferedCanFd<'d, TX_BUF_SIZE, RX_BUF_SIZE> { - BufferedCanFd::new(self.info, self.state, self._mode, tx_buf, rxb) + BufferedCanFd::new(self.info, self._mode, tx_buf, rxb) } } @@ -437,7 +432,6 @@ pub type TxBuf = Channel { _phantom: PhantomData<&'d ()>, info: &'static Info, - state: &'static State, _mode: OperatingMode, tx_buf: &'static TxBuf, rx_buf: &'static RxBuf, @@ -447,7 +441,6 @@ pub struct BufferedCan<'d, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> { impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCan<'d, TX_BUF_SIZE, RX_BUF_SIZE> { fn new( info: &'static Info, - state: &'static State, _mode: OperatingMode, tx_buf: &'static TxBuf, rx_buf: &'static RxBuf, @@ -457,7 +450,6 @@ impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCan<'d, BufferedCan { _phantom: PhantomData, info, - state, _mode, tx_buf, rx_buf, @@ -473,19 +465,15 @@ impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCan<'d, fn setup(self) -> Self { // We don't want interrupts being processed while we change modes. - critical_section::with(|_| { + self.info.state.lock(|s| { let rx_inner = super::common::ClassicBufferedRxInner { rx_sender: self.rx_buf.sender().into(), }; let tx_inner = super::common::ClassicBufferedTxInner { tx_receiver: self.tx_buf.receiver().into(), }; - let state = self.state as *const State; - unsafe { - let mut_state = state as *mut State; - (*mut_state).rx_mode = RxMode::ClassicBuffered(rx_inner); - (*mut_state).tx_mode = TxMode::ClassicBuffered(tx_inner); - } + s.borrow_mut().rx_mode = RxMode::ClassicBuffered(rx_inner); + s.borrow_mut().tx_mode = TxMode::ClassicBuffered(tx_inner); }); self } @@ -545,7 +533,6 @@ pub type BufferedFdCanReceiver = super::common::BufferedReceiver<'static, FdEnve pub struct BufferedCanFd<'d, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> { _phantom: PhantomData<&'d ()>, info: &'static Info, - state: &'static State, _mode: OperatingMode, tx_buf: &'static TxFdBuf, rx_buf: &'static RxFdBuf, @@ -555,7 +542,6 @@ pub struct BufferedCanFd<'d, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCanFd<'d, TX_BUF_SIZE, RX_BUF_SIZE> { fn new( info: &'static Info, - state: &'static State, _mode: OperatingMode, tx_buf: &'static TxFdBuf, rx_buf: &'static RxFdBuf, @@ -565,7 +551,6 @@ impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCanFd<' BufferedCanFd { _phantom: PhantomData, info, - state, _mode, tx_buf, rx_buf, @@ -581,19 +566,15 @@ impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCanFd<' fn setup(self) -> Self { // We don't want interrupts being processed while we change modes. - critical_section::with(|_| { + self.info.state.lock(|s| { let rx_inner = super::common::FdBufferedRxInner { rx_sender: self.rx_buf.sender().into(), }; let tx_inner = super::common::FdBufferedTxInner { tx_receiver: self.tx_buf.receiver().into(), }; - let state = self.state as *const State; - unsafe { - let mut_state = state as *mut State; - (*mut_state).rx_mode = RxMode::FdBuffered(rx_inner); - (*mut_state).tx_mode = TxMode::FdBuffered(tx_inner); - } + s.borrow_mut().rx_mode = RxMode::FdBuffered(rx_inner); + s.borrow_mut().tx_mode = TxMode::FdBuffered(tx_inner); }); self } @@ -641,19 +622,18 @@ impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> Drop for Buffer pub struct CanRx<'d> { _phantom: PhantomData<&'d ()>, info: &'static Info, - state: &'static State, _mode: OperatingMode, } impl<'d> CanRx<'d> { /// Returns the next received message frame pub async fn read(&mut self) -> Result { - self.state.rx_mode.read_classic(&self.info, &self.state).await + RxMode::read_classic(&self.info).await } /// Returns the next received message frame pub async fn read_fd(&mut self) -> Result { - self.state.rx_mode.read_fd(&self.info, &self.state).await + RxMode::read_fd(&self.info).await } } @@ -667,7 +647,6 @@ impl<'d> Drop for CanRx<'d> { pub struct CanTx<'d> { _phantom: PhantomData<&'d ()>, info: &'static Info, - state: &'static State, config: crate::can::fd::config::FdCanConfig, _mode: OperatingMode, } @@ -678,7 +657,7 @@ impl<'c, 'd> CanTx<'d> { /// can be replaced, this call asynchronously waits for a frame to be successfully /// transmitted, then tries again. pub async fn write(&mut self, frame: &Frame) -> Option { - self.state.tx_mode.write(self.info, frame).await + TxMode::write(self.info, frame).await } /// Queues the message to be sent but exerts backpressure. If a lower-priority @@ -686,7 +665,7 @@ impl<'c, 'd> CanTx<'d> { /// can be replaced, this call asynchronously waits for a frame to be successfully /// transmitted, then tries again. pub async fn write_fd(&mut self, frame: &FdFrame) -> Option { - self.state.tx_mode.write_fd(self.info, frame).await + TxMode::write_fd(self.info, frame).await } } @@ -712,19 +691,19 @@ impl RxMode { } } - fn on_interrupt(&self, fifonr: usize) { + fn on_interrupt(&self, fifonr: usize, ns_per_timer_tick: u64) { T::registers().regs.ir().write(|w| w.set_rfn(fifonr, true)); match self { RxMode::NonBuffered(waker) => { waker.wake(); } RxMode::ClassicBuffered(buf) => { - if let Some(result) = self.try_read::() { + if let Some(result) = self.try_read::(ns_per_timer_tick) { let _ = buf.rx_sender.try_send(result); } } RxMode::FdBuffered(buf) => { - if let Some(result) = self.try_read_fd::() { + if let Some(result) = self.try_read_fd::(ns_per_timer_tick) { let _ = buf.rx_sender.try_send(result); } } @@ -732,12 +711,12 @@ impl RxMode { } //async fn read_classic(&self) -> Result { - fn try_read(&self) -> Option> { + fn try_read(&self, ns_per_timer_tick: u64) -> Option> { if let Some((frame, ts)) = T::registers().read(0) { - let ts = T::calc_timestamp(T::state().ns_per_timer_tick, ts); + let ts = T::calc_timestamp(ns_per_timer_tick, ts); Some(Ok(Envelope { ts, frame })) } else if let Some((frame, ts)) = T::registers().read(1) { - let ts = T::calc_timestamp(T::state().ns_per_timer_tick, ts); + let ts = T::calc_timestamp(ns_per_timer_tick, ts); Some(Ok(Envelope { ts, frame })) } else if let Some(err) = T::registers().curr_error() { // TODO: this is probably wrong @@ -747,12 +726,12 @@ impl RxMode { } } - fn try_read_fd(&self) -> Option> { + fn try_read_fd(&self, ns_per_timer_tick: u64) -> Option> { if let Some((frame, ts)) = T::registers().read(0) { - let ts = T::calc_timestamp(T::state().ns_per_timer_tick, ts); + let ts = T::calc_timestamp(ns_per_timer_tick, ts); Some(Ok(FdEnvelope { ts, frame })) } else if let Some((frame, ts)) = T::registers().read(1) { - let ts = T::calc_timestamp(T::state().ns_per_timer_tick, ts); + let ts = T::calc_timestamp(ns_per_timer_tick, ts); Some(Ok(FdEnvelope { ts, frame })) } else if let Some(err) = T::registers().curr_error() { // TODO: this is probably wrong @@ -762,16 +741,12 @@ impl RxMode { } } - fn read( - &self, - info: &'static Info, - state: &'static State, - ) -> Option> { + fn read(info: &'static Info, ns_per_timer_tick: u64) -> Option> { if let Some((msg, ts)) = info.regs.read(0) { - let ts = info.calc_timestamp(state.ns_per_timer_tick, ts); + let ts = info.calc_timestamp(ns_per_timer_tick, ts); Some(Ok((msg, ts))) } else if let Some((msg, ts)) = info.regs.read(1) { - let ts = info.calc_timestamp(state.ns_per_timer_tick, ts); + let ts = info.calc_timestamp(ns_per_timer_tick, ts); Some(Ok((msg, ts))) } else if let Some(err) = info.regs.curr_error() { // TODO: this is probably wrong @@ -781,16 +756,15 @@ impl RxMode { } } - async fn read_async( - &self, - info: &'static Info, - state: &'static State, - ) -> Result<(F, Timestamp), BusError> { - //let _ = self.read::(info, state); + async fn read_async(info: &'static Info) -> Result<(F, Timestamp), BusError> { poll_fn(move |cx| { - state.err_waker.register(cx.waker()); - self.register(cx.waker()); - match self.read::<_>(info, state) { + let ns_per_timer_tick = info.state.lock(|s| { + let state = s.borrow_mut(); + state.err_waker.register(cx.waker()); + state.rx_mode.register(cx.waker()); + state.ns_per_timer_tick + }); + match RxMode::read::<_>(info, ns_per_timer_tick) { Some(result) => Poll::Ready(result), None => Poll::Pending, } @@ -798,15 +772,15 @@ impl RxMode { .await } - async fn read_classic(&self, info: &'static Info, state: &'static State) -> Result { - match self.read_async::<_>(info, state).await { + async fn read_classic(info: &'static Info) -> Result { + match RxMode::read_async::<_>(info).await { Ok((frame, ts)) => Ok(Envelope { ts, frame }), Err(e) => Err(e), } } - async fn read_fd(&self, info: &'static Info, state: &'static State) -> Result { - match self.read_async::<_>(info, state).await { + async fn read_fd(info: &'static Info) -> Result { + match RxMode::read_async::<_>(info).await { Ok((frame, ts)) => Ok(FdEnvelope { ts, frame }), Err(e) => Err(e), } @@ -835,9 +809,11 @@ impl TxMode { /// frame is dropped from the mailbox, it is returned. If no lower-priority frames /// can be replaced, this call asynchronously waits for a frame to be successfully /// transmitted, then tries again. - async fn write_generic(&self, info: &'static Info, frame: &F) -> Option { + async fn write_generic(info: &'static Info, frame: &F) -> Option { poll_fn(|cx| { - self.register(cx.waker()); + info.state.lock(|s| { + s.borrow_mut().tx_mode.register(cx.waker()); + }); if let Ok(dropped) = info.regs.write(frame) { return Poll::Ready(dropped); @@ -854,16 +830,16 @@ impl TxMode { /// frame is dropped from the mailbox, it is returned. If no lower-priority frames /// can be replaced, this call asynchronously waits for a frame to be successfully /// transmitted, then tries again. - async fn write(&self, info: &'static Info, frame: &Frame) -> Option { - self.write_generic::<_>(info, frame).await + async fn write(info: &'static Info, frame: &Frame) -> Option { + TxMode::write_generic::<_>(info, frame).await } /// Queues the message to be sent but exerts backpressure. If a lower-priority /// frame is dropped from the mailbox, it is returned. If no lower-priority frames /// can be replaced, this call asynchronously waits for a frame to be successfully /// transmitted, then tries again. - async fn write_fd(&self, info: &'static Info, frame: &FdFrame) -> Option { - self.write_generic::<_>(info, frame).await + async fn write_fd(info: &'static Info, frame: &FdFrame) -> Option { + TxMode::write_generic::<_>(info, frame).await } } @@ -961,12 +937,14 @@ impl State { } } +type SharedState = embassy_sync::blocking_mutex::Mutex>; struct Info { regs: Registers, interrupt0: crate::interrupt::Interrupt, _interrupt1: crate::interrupt::Interrupt, tx_waker: fn(), internal_operation: fn(InternalOperation), + state: SharedState, } impl Info { @@ -993,8 +971,6 @@ trait SealedInstance { fn info() -> &'static Info; fn registers() -> crate::can::fd::peripheral::Registers; - fn state() -> &'static State; - unsafe fn mut_state() -> &'static mut State; fn internal_operation(val: InternalOperation); fn calc_timestamp(ns_per_timer_tick: u64, ts_val: u16) -> Timestamp; } @@ -1019,32 +995,30 @@ macro_rules! impl_fdcan { const MSG_RAM_OFFSET: usize = $msg_ram_offset; fn internal_operation(val: InternalOperation) { - critical_section::with(|_| { - //let state = self.state as *const State; - unsafe { - //let mut_state = state as *mut State; - let mut_state = peripherals::$inst::mut_state(); - match val { - InternalOperation::NotifySenderCreated => { - mut_state.sender_instance_count += 1; - } - InternalOperation::NotifySenderDestroyed => { - mut_state.sender_instance_count -= 1; - if ( 0 == mut_state.sender_instance_count) { - (*mut_state).tx_mode = TxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new()); - } - } - InternalOperation::NotifyReceiverCreated => { - mut_state.receiver_instance_count += 1; - } - InternalOperation::NotifyReceiverDestroyed => { - mut_state.receiver_instance_count -= 1; - if ( 0 == mut_state.receiver_instance_count) { - (*mut_state).rx_mode = RxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new()); - } + peripherals::$inst::info().state.lock(|s| { + let mut mut_state = s.borrow_mut(); + match val { + InternalOperation::NotifySenderCreated => { + mut_state.sender_instance_count += 1; + } + InternalOperation::NotifySenderDestroyed => { + mut_state.sender_instance_count -= 1; + if ( 0 == mut_state.sender_instance_count) { + (*mut_state).tx_mode = TxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new()); } } - if mut_state.sender_instance_count == 0 && mut_state.receiver_instance_count == 0 { + InternalOperation::NotifyReceiverCreated => { + mut_state.receiver_instance_count += 1; + } + InternalOperation::NotifyReceiverDestroyed => { + mut_state.receiver_instance_count -= 1; + if ( 0 == mut_state.receiver_instance_count) { + (*mut_state).rx_mode = RxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new()); + } + } + } + if mut_state.sender_instance_count == 0 && mut_state.receiver_instance_count == 0 { + unsafe { let tx_pin = crate::gpio::AnyPin::steal(mut_state.tx_pin_port.unwrap()); tx_pin.set_as_disconnected(); let rx_pin = crate::gpio::AnyPin::steal(mut_state.rx_pin_port.unwrap()); @@ -1054,26 +1028,22 @@ macro_rules! impl_fdcan { } }); } + fn info() -> &'static Info { + static INFO: Info = Info { regs: Registers{regs: crate::pac::$inst, msgram: crate::pac::$msg_ram_inst, msg_ram_offset: $msg_ram_offset}, interrupt0: crate::_generated::peripheral_interrupts::$inst::IT0::IRQ, _interrupt1: crate::_generated::peripheral_interrupts::$inst::IT1::IRQ, tx_waker: crate::_generated::peripheral_interrupts::$inst::IT0::pend, internal_operation: peripherals::$inst::internal_operation, + state: embassy_sync::blocking_mutex::Mutex::new(core::cell::RefCell::new(State::new())), }; &INFO } fn registers() -> Registers { Registers{regs: crate::pac::$inst, msgram: crate::pac::$msg_ram_inst, msg_ram_offset: Self::MSG_RAM_OFFSET} } - unsafe fn mut_state() -> &'static mut State { - static mut STATE: State = State::new(); - &mut *core::ptr::addr_of_mut!(STATE) - } - fn state() -> &'static State { - unsafe { peripherals::$inst::mut_state() } - } #[cfg(feature = "time")] fn calc_timestamp(ns_per_timer_tick: u64, ts_val: u16) -> Timestamp { From 010744802fc4a1fda51f259cce874aac7294a79e Mon Sep 17 00:00:00 2001 From: Corey Schuhen Date: Sat, 31 May 2025 09:09:12 +1000 Subject: [PATCH 1213/1217] Remove duplicate calc_timestamp and move to 'Registers' struct. --- embassy-stm32/src/can/fd/peripheral.rs | 17 +++++++++ embassy-stm32/src/can/fdcan.rs | 49 ++++---------------------- 2 files changed, 23 insertions(+), 43 deletions(-) diff --git a/embassy-stm32/src/can/fd/peripheral.rs b/embassy-stm32/src/can/fd/peripheral.rs index 4873ee444..0a22f2c91 100644 --- a/embassy-stm32/src/can/fd/peripheral.rs +++ b/embassy-stm32/src/can/fd/peripheral.rs @@ -71,6 +71,23 @@ impl Registers { } } + #[cfg(feature = "time")] + pub fn calc_timestamp(&self, ns_per_timer_tick: u64, ts_val: u16) -> Timestamp { + let now_embassy = embassy_time::Instant::now(); + if ns_per_timer_tick == 0 { + return now_embassy; + } + let cantime = { self.regs.tscv().read().tsc() }; + let delta = cantime.overflowing_sub(ts_val).0 as u64; + let ns = ns_per_timer_tick * delta as u64; + now_embassy - embassy_time::Duration::from_nanos(ns) + } + + #[cfg(not(feature = "time"))] + pub fn calc_timestamp(&self, _ns_per_timer_tick: u64, ts_val: u16) -> Timestamp { + ts_val + } + pub fn put_tx_frame(&self, bufidx: usize, header: &Header, buffer: &[u8]) { let mailbox = self.tx_buffer_element(bufidx); mailbox.reset(); diff --git a/embassy-stm32/src/can/fdcan.rs b/embassy-stm32/src/can/fdcan.rs index 4495280c4..97d22315a 100644 --- a/embassy-stm32/src/can/fdcan.rs +++ b/embassy-stm32/src/can/fdcan.rs @@ -713,10 +713,10 @@ impl RxMode { //async fn read_classic(&self) -> Result { fn try_read(&self, ns_per_timer_tick: u64) -> Option> { if let Some((frame, ts)) = T::registers().read(0) { - let ts = T::calc_timestamp(ns_per_timer_tick, ts); + let ts = T::registers().calc_timestamp(ns_per_timer_tick, ts); Some(Ok(Envelope { ts, frame })) } else if let Some((frame, ts)) = T::registers().read(1) { - let ts = T::calc_timestamp(ns_per_timer_tick, ts); + let ts = T::registers().calc_timestamp(ns_per_timer_tick, ts); Some(Ok(Envelope { ts, frame })) } else if let Some(err) = T::registers().curr_error() { // TODO: this is probably wrong @@ -728,10 +728,10 @@ impl RxMode { fn try_read_fd(&self, ns_per_timer_tick: u64) -> Option> { if let Some((frame, ts)) = T::registers().read(0) { - let ts = T::calc_timestamp(ns_per_timer_tick, ts); + let ts = T::registers().calc_timestamp(ns_per_timer_tick, ts); Some(Ok(FdEnvelope { ts, frame })) } else if let Some((frame, ts)) = T::registers().read(1) { - let ts = T::calc_timestamp(ns_per_timer_tick, ts); + let ts = T::registers().calc_timestamp(ns_per_timer_tick, ts); Some(Ok(FdEnvelope { ts, frame })) } else if let Some(err) = T::registers().curr_error() { // TODO: this is probably wrong @@ -743,10 +743,10 @@ impl RxMode { fn read(info: &'static Info, ns_per_timer_tick: u64) -> Option> { if let Some((msg, ts)) = info.regs.read(0) { - let ts = info.calc_timestamp(ns_per_timer_tick, ts); + let ts = info.regs.calc_timestamp(ns_per_timer_tick, ts); Some(Ok((msg, ts))) } else if let Some((msg, ts)) = info.regs.read(1) { - let ts = info.calc_timestamp(ns_per_timer_tick, ts); + let ts = info.regs.calc_timestamp(ns_per_timer_tick, ts); Some(Ok((msg, ts))) } else if let Some(err) = info.regs.curr_error() { // TODO: this is probably wrong @@ -947,32 +947,12 @@ struct Info { state: SharedState, } -impl Info { - #[cfg(feature = "time")] - fn calc_timestamp(&self, ns_per_timer_tick: u64, ts_val: u16) -> Timestamp { - let now_embassy = embassy_time::Instant::now(); - if ns_per_timer_tick == 0 { - return now_embassy; - } - let cantime = { self.regs.regs.tscv().read().tsc() }; - let delta = cantime.overflowing_sub(ts_val).0 as u64; - let ns = ns_per_timer_tick * delta as u64; - now_embassy - embassy_time::Duration::from_nanos(ns) - } - - #[cfg(not(feature = "time"))] - fn calc_timestamp(&self, _ns_per_timer_tick: u64, ts_val: u16) -> Timestamp { - ts_val - } -} - trait SealedInstance { const MSG_RAM_OFFSET: usize; fn info() -> &'static Info; fn registers() -> crate::can::fd::peripheral::Registers; fn internal_operation(val: InternalOperation); - fn calc_timestamp(ns_per_timer_tick: u64, ts_val: u16) -> Timestamp; } /// Instance trait @@ -1045,23 +1025,6 @@ macro_rules! impl_fdcan { Registers{regs: crate::pac::$inst, msgram: crate::pac::$msg_ram_inst, msg_ram_offset: Self::MSG_RAM_OFFSET} } - #[cfg(feature = "time")] - fn calc_timestamp(ns_per_timer_tick: u64, ts_val: u16) -> Timestamp { - let now_embassy = embassy_time::Instant::now(); - if ns_per_timer_tick == 0 { - return now_embassy; - } - let cantime = { Self::registers().regs.tscv().read().tsc() }; - let delta = cantime.overflowing_sub(ts_val).0 as u64; - let ns = ns_per_timer_tick * delta as u64; - now_embassy - embassy_time::Duration::from_nanos(ns) - } - - #[cfg(not(feature = "time"))] - fn calc_timestamp(_ns_per_timer_tick: u64, ts_val: u16) -> Timestamp { - ts_val - } - } #[allow(non_snake_case)] From 69abc42077e6de4453d422330a9a07407a36f218 Mon Sep 17 00:00:00 2001 From: 9names <60134748+9names@users.noreply.github.com> Date: Sun, 1 Jun 2025 00:08:09 +1000 Subject: [PATCH 1214/1217] doc: add high-level embassy-boot a-b info --- docs/pages/bootloader.adoc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/pages/bootloader.adoc b/docs/pages/bootloader.adoc index 53f85d995..b0f0331aa 100644 --- a/docs/pages/bootloader.adoc +++ b/docs/pages/bootloader.adoc @@ -2,6 +2,13 @@ `embassy-boot` a lightweight bootloader supporting firmware application upgrades in a power-fail-safe way, with trial boots and rollbacks. +The update method used is referred to as an A/B partition update scheme. + +With a general-purpose OS, A/B partition update is accomplished by directly booting either the A or B partition depending on the update state. +To accomplish the same goal in a way that is portable across all microcontrollers, `embassy-boot` swaps data page by page (in both directions) between the DFU and the Active partition when a firmware update is triggered. + +Because the original Active application is moved into the DFU partition during this update, the operation can be reversed if the update is interrupted or the new firmware does not flag that it booted successfully. + +See the design section for more details on how this is implemented. + The bootloader can be used either as a library or be flashed directly if you are happy with the default configuration and capabilities. By design, the bootloader does not provide any network capabilities. Networking capabilities for fetching new firmware can be provided by the user application, using the bootloader as a library for updating the firmware, or by using the bootloader as a library and adding this capability yourself. From 011d7832f899a1cc836bed5d4dbb80863b774e6c Mon Sep 17 00:00:00 2001 From: Frank Stevenson Date: Tue, 3 Jun 2025 15:47:33 +0200 Subject: [PATCH 1215/1217] Use modify() for subsequent changes to RCC.cr() --- embassy-stm32/src/rcc/u5.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/embassy-stm32/src/rcc/u5.rs b/embassy-stm32/src/rcc/u5.rs index ff70466b9..97eb2eb6d 100644 --- a/embassy-stm32/src/rcc/u5.rs +++ b/embassy-stm32/src/rcc/u5.rs @@ -181,7 +181,7 @@ pub(crate) unsafe fn init(config: Config) { w.set_msikrange(range); w.set_msirgsel(Msirgsel::ICSCR1); }); - RCC.cr().write(|w| { + RCC.cr().modify(|w| { w.set_msikon(true); }); while !RCC.cr().read().msikrdy() {} @@ -189,7 +189,7 @@ pub(crate) unsafe fn init(config: Config) { }); let hsi = config.hsi.then(|| { - RCC.cr().write(|w| w.set_hsion(true)); + RCC.cr().modify(|w| w.set_hsion(true)); while !RCC.cr().read().hsirdy() {} HSI_FREQ @@ -207,7 +207,7 @@ pub(crate) unsafe fn init(config: Config) { } // Enable HSE, and wait for it to stabilize - RCC.cr().write(|w| { + RCC.cr().modify(|w| { w.set_hseon(true); w.set_hsebyp(hse.mode != HseMode::Oscillator); w.set_hseext(match hse.mode { From 9b3b6c54210afb1c99c1b57cce700eccc49896a4 Mon Sep 17 00:00:00 2001 From: Dion Dokter Date: Tue, 3 Jun 2025 16:08:55 +0200 Subject: [PATCH 1216/1217] STM32 USB: Read data before register update --- embassy-stm32/src/usb/usb.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/embassy-stm32/src/usb/usb.rs b/embassy-stm32/src/usb/usb.rs index 0b878915a..3e8e74a1f 100644 --- a/embassy-stm32/src/usb/usb.rs +++ b/embassy-stm32/src/usb/usb.rs @@ -911,6 +911,8 @@ impl<'d, T: Instance> driver::EndpointOut for Endpoint<'d, T, Out> { }; self.read_data_double_buffered(buf, packet_buffer)? } else { + let len = self.read_data(buf)?; + regs.epr(index).write(|w| { w.set_ep_type(convert_type(self.info.ep_type)); w.set_ea(self.info.addr.index() as _); @@ -920,7 +922,7 @@ impl<'d, T: Instance> driver::EndpointOut for Endpoint<'d, T, Out> { w.set_ctr_tx(true); // don't clear }); - self.read_data(buf)? + len }; trace!("READ OK, rx_len = {}", rx_len); From c10688cd40d5ffdc181446f304e833ec880b25f0 Mon Sep 17 00:00:00 2001 From: David Lawrence Date: Fri, 6 Jun 2025 13:01:11 -0400 Subject: [PATCH 1217/1217] Add public function to get current clock configuration --- embassy-stm32/src/rcc/mod.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index 3733fed56..c41f81816 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs @@ -95,6 +95,15 @@ pub(crate) unsafe fn get_freqs() -> &'static Clocks { unwrap!(CLOCK_FREQS_PTR.load(core::sync::atomic::Ordering::SeqCst).as_ref()).assume_init_ref() } +/// Get the current clock configuration of the chip. +pub fn clocks<'a>(_rcc: &'a crate::Peri<'a, crate::peripherals::RCC>) -> &'a Clocks { + // Safety: the existence of a `Peri` means that `rcc::init()` + // has already been called, so `CLOCK_FREQS` must be initialized. + // The clocks could be modified again by `reinit()`, but reinit + // (for this reason) requires an exclusive reference to `Peri`. + unsafe { get_freqs() } +} + pub(crate) trait SealedRccPeripheral { fn frequency() -> Hertz; #[allow(dead_code)] @@ -381,7 +390,7 @@ pub fn disable() { /// /// This should only be called after `init`. #[cfg(not(feature = "_dual-core"))] -pub fn reinit(config: Config) { +pub fn reinit<'a>(config: Config, _rcc: &'a mut crate::Peri<'a, crate::peripherals::RCC>) { critical_section::with(|cs| init_rcc(cs, config)) }