Merge branch 'embassy-rs:main' into stm32h755-intercore

This commit is contained in:
Ragarnoy 2025-05-21 13:58:57 +02:00 committed by GitHub
commit a4676f8b94
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
205 changed files with 4877 additions and 563 deletions

View File

@ -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.

19
ci.sh
View File

@ -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
@ -174,11 +174,18 @@ 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 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' \

View File

@ -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/"

View File

@ -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"

View File

@ -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"] }

View File

@ -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"] }

View File

@ -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"] }

View File

@ -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"] }

View File

@ -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"] }

View File

@ -9,5 +9,8 @@ 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

View File

@ -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" }

View File

@ -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" }

View File

@ -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" }

View File

@ -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 }

View File

@ -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"] }

View File

@ -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 }

View File

@ -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;
@ -89,6 +89,12 @@ 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>,
#[cfg(feature = "trace")]
pub(crate) id: u32,
#[cfg(feature = "trace")]
all_tasks_next: AtomicPtr<TaskHeader>,
}
/// This is essentially a `&'static TaskStorage<F>` where the type of the future has been erased.
@ -143,12 +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
}
}
/// Raw storage in which a task can be spawned.
@ -190,6 +190,12 @@ impl<F: Future + 'static> TaskStorage<F> {
poll_fn: SyncUnsafeCell::new(None),
timer_queue_item: timer_queue::TimerQueueItem::new(),
#[cfg(feature = "trace")]
name: None,
#[cfg(feature = "trace")]
id: 0,
#[cfg(feature = "trace")]
all_tasks_next: AtomicPtr::new(core::ptr::null_mut()),
},
future: UninitCell::uninit(),
}

View File

@ -81,7 +81,131 @@
#![allow(unused)]
use crate::raw::{SyncExecutor, TaskRef};
use core::cell::UnsafeCell;
use core::sync::atomic::{AtomicPtr, AtomicUsize, Ordering};
use rtos_trace::TaskInfo;
use crate::raw::{SyncExecutor, TaskHeader, TaskRef};
use crate::spawner::{SpawnError, SpawnToken, Spawner};
/// Global task tracker instance
///
/// 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.
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.
pub struct TaskTracker {
head: AtomicPtr<TaskHeader>,
}
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<F>(&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) };
}
}
}
/// 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.
pub trait TaskRefTrace {
/// 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);
}
impl TaskRefTrace for TaskRef {
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" {
@ -160,6 +284,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]
@ -210,10 +337,62 @@ 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
fn get_all_active_tasks() -> impl Iterator<Item = TaskRef> + 'static {
struct TaskIterator<'a> {
tracker: &'a TaskTracker,
current: *mut TaskHeader,
}
impl<'a> Iterator for TaskIterator<'a> {
type Item = TaskRef;
fn next(&mut self) -> Option<Self::Item> {
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),
}
}
/// Perform an action on each active task
fn with_all_active_tasks<F>(f: F)
where
F: FnMut(TaskRef),
{
TASK_TRACKER.for_each(f);
}
#[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.
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.id(), info);
});
}
fn time() -> u64 {
const fn gcd(a: u64, b: u64) -> u64 {

View File

@ -5,6 +5,8 @@ use core::sync::atomic::Ordering;
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.
///
@ -22,7 +24,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<S> {
raw_task: Option<raw::TaskRef>,
pub(crate) raw_task: Option<raw::TaskRef>,
phantom: PhantomData<*mut S>,
}
@ -103,7 +105,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 ()>,
}
@ -180,6 +182,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<S>(&self, name: &'static str, token: SpawnToken<S>) -> Result<(), SpawnError>;
}
/// Implementation of the SpawnerTraceExt trait for Spawner when trace is enabled
#[cfg(feature = "trace")]
impl SpawnerTraceExt for Spawner {
fn spawn_named<S>(&self, name: &'static str, token: SpawnToken<S>) -> 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<S>(&self, _name: &'static str, token: SpawnToken<S>) -> 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

View File

@ -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 }

View File

@ -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 }

View File

@ -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])?

View File

@ -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>,

View File

@ -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"
@ -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",
] }

190
embassy-imxrt/src/crc.rs Normal file
View File

@ -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<T: Instance>(_peripheral: Peri<'d, T>, config: Config) -> Self {
// enable CRC clock
enable_and_reset::<T>();
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::<u32>() };
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() },
}
}
}

418
embassy-imxrt/src/dma.rs Normal file
View File

@ -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::<DMA0>();
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<Self::Output> {
// 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<AnyChannel> + 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<peripherals::$name> 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);

View File

@ -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::[<FLEXCOMM $idx>] {}
impl FlexcommLowLevel for crate::peripherals::[<FLEXCOMM $idx>] {
fn reg() -> &'static crate::pac::flexcomm0::RegisterBlock {
// SAFETY: safe from single executor, enforce
// via peripheral reference lifetime tracking
unsafe {
&*crate::pac::[<Flexcomm $idx>]::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::<[<FLEXCOMM $idx>]>();
}
}
}
)*
}
}
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::<FLEXCOMM14>();
}
}
// 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::<FLEXCOMM15>();
}
}
macro_rules! into_mode {
($mode:ident, $($fc:ident),*) => {
paste! {
/// Sealed Mode trait
trait [<SealedInto $mode:camel>]: FlexcommLowLevel {}
/// Select mode of operation
#[allow(private_bounds)]
pub trait [<Into $mode:camel>]: [<SealedInto $mode:camel>] {
/// Set mode of operation
fn [<into_ $mode>]() {
Self::reg().pselid().write(|w| w.persel().[<$mode>]());
}
}
}
$(
paste!{
impl [<SealedInto $mode:camel>] for crate::peripherals::$fc {}
impl [<Into $mode:camel>] 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
);

File diff suppressed because it is too large Load Diff

View File

@ -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<Self::Item> {
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() };

View File

@ -18,8 +18,12 @@ compile_error!(
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;
#[cfg(feature = "_time-driver")]
pub mod time_driver;
@ -52,16 +56,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<peripherals::FLEXSPI>;
/// });
/// bind_interrupts!(
/// /// Binds the FLEXSPI interrupt.
/// struct Irqs {
/// FLEXSPI_IRQ => flexspi::InterruptHandler<peripherals::FLEXSPI>;
/// }
/// );
/// ```
///
// 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;
$(
@ -127,14 +135,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
@ -143,3 +153,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<Self::Item> {
match self.0.trailing_zeros() {
32 => None,
b => {
self.0 &= !(1 << b);
Some(b)
}
}
}
}

287
embassy-imxrt/src/rng.rs Normal file
View File

@ -0,0 +1,287 @@
//! 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 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<T: Instance> {
_phantom: PhantomData<T>,
}
impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
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<T: Instance>(
_inner: Peri<'d, T>,
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
) -> Self {
enable_and_reset::<T>();
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());
}
/// 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)
}
/// 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)
}
/// Fill a slice with random bytes.
pub fn blocking_fill_bytes(&mut self, dest: &mut [u8]) {
block_on(self.async_fill_bytes(dest)).unwrap();
}
}
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<'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,
}
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() },
}
}
}

View File

@ -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"
@ -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"]

28
embassy-mspm0/README.md Normal file
View File

@ -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 youre 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.

View File

@ -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,64 @@ fn generate_code() {
rustfmt(&out_file);
}
fn get_chip_cfgs(chip_name: &str) -> Vec<String> {
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("mspm0g151") {
cfgs.push("mspm0g151x".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 +225,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 +253,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::<u8>().unwrap());
let pin_number = Literal::u8_unsuffixed(pin.pin[2..].parse::<u8>().unwrap());
let port = Ident::new(&format!("Port{}", port_letter), Span::call_site());

View File

@ -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", 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", feature = "mspm0c110x"))]
#[cfg(all(feature = "rt", any(mspm0c110x, mspm0l110x)))]
#[interrupt]
fn GPIOA() {
gpioa_interrupt();

View File

@ -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(),
}
}

View File

@ -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"),
}
}

View File

@ -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(),
}
}

View File

@ -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"),
}
}

View File

@ -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"),
}
}

View File

@ -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 => crate::gpio::gpiob_interrupt(),
Group1::COMP0 => todo!("implement COMP0"),
Group1::TRNG => todo!("implement TRNG"),
Group1::GPIOC => crate::gpio::gpioc_interrupt(),
}
}

View File

@ -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 = "<div style='padding:30px;background:#810;color:#fff;text-align:center;'><p>You might want to <a href='https://docs.embassy.dev/embassy-mspm0'>browse the `embassy-mspm0` documentation on the Embassy website</a> instead.</p><p>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.</p></div>\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,17 @@ 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(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 {
@ -109,7 +120,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();

View File

@ -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]

View File

@ -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" }

View File

@ -22,4 +22,4 @@ target = "thumbv7em-none-eabi"
features = ["defmt"]
[dependencies]
defmt = { version = "0.3", optional = true }
defmt = { version = "1.0.1", optional = true }

View File

@ -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]

View File

@ -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" }

View File

@ -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"

View File

@ -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" }

View File

@ -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/"

View File

@ -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 = [

View File

@ -154,15 +154,17 @@ 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 }
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"
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"

View File

@ -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);

View File

@ -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);

363
embassy-nrf/src/ipc.rs Normal file
View File

@ -0,0 +1,363 @@
//! InterProcessor Communication (IPC)
#![macro_use]
use core::future::poll_fn;
use core::marker::PhantomData;
use core::task::Poll;
use embassy_hal_internal::{Peri, PeripheralType};
use embassy_sync::waitqueue::AtomicWaker;
use crate::interrupt::typelevel::Interrupt;
use crate::{interrupt, pac, ppi};
const EVENT_COUNT: usize = 16;
/// IPC Event
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum EventNumber {
/// 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: [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, PartialEq, Eq, PartialOrd, Ord, Hash)]
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,
}
impl IpcChannel {
fn mask(self) -> u32 {
1 << (self as u32)
}
}
/// Interrupt Handler
pub struct InterruptHandler<T: Instance> {
_phantom: PhantomData<T>,
}
impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
unsafe fn on_interrupt() {
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 {
regs.intenclr().write(|w| w.0 = 0x01 << event as u32);
T::state().wakers[event as usize].wake();
}
}
}
}
/// IPC driver
#[non_exhaustive]
pub struct Ipc<'d, T: Instance> {
/// 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 a new IPC driver.
pub fn new(
_p: Peri<'d, T>,
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
) -> Self {
T::Interrupt::unpend();
unsafe { T::Interrupt::enable() };
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| {
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
}
})
.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<I: IntoIterator<Item = IpcChannel>>(&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<I: IntoIterator<Item = IpcChannel>>(&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<T: Instance> 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; EVENT_COUNT],
}
impl State {
pub(crate) const fn new() -> Self {
Self {
wakers: [const { AtomicWaker::new() }; EVENT_COUNT],
}
}
}
pub(crate) trait SealedInstance {
fn regs() -> pac::ipc::Ipc;
fn state() -> &'static State;
}
/// IPC peripheral instance.
#[allow(private_bounds)]
pub trait Instance: PeripheralType + 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;
}
};
}

View File

@ -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",
@ -198,9 +200,12 @@ mod chip;
/// ```rust,ignore
/// use embassy_nrf::{bind_interrupts, spim, peripherals};
///
/// bind_interrupts!(struct Irqs {
/// SPIM3 => spim::InterruptHandler<peripherals::SPI3>;
/// });
/// bind_interrupts!(
/// /// Binds the SPIM3 interrupt.
/// struct Irqs {
/// SPIM3 => spim::InterruptHandler<peripherals::SPI3>;
/// }
/// );
/// ```
///
/// Example of how to bind multiple interrupts in a single macro invocation:
@ -217,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 => $(
@ -227,6 +232,7 @@ macro_rules! bind_interrupts {
)*
}) => {
#[derive(Copy, Clone)]
$(#[$attr])*
$vis struct $name;
$(
@ -337,7 +343,7 @@ pub mod config {
/// 3.0 V
_3V0 = 4,
/// 3.3 V
_3v3 = 5,
_3V3 = 5,
//ERASED = 7, means 1.8V
}
@ -369,7 +375,7 @@ pub mod config {
/// 3.0 V
_3V0 = 4,
/// 3.3 V
_3v3 = 5,
_3V3 = 5,
//ERASED = 7, means 1.8V
}

View File

@ -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 {

View File

@ -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 = "1", optional = true }
[features]
default = ["rt"]
rt = ["lpc55-pac/rt"]
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"]

View File

@ -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 <https://docs.rs/cortex-m-rt/latest/cortex_m_rt/#device> 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.
@ -142,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"
@ -154,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" }
@ -164,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"

View File

@ -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>),

View File

@ -38,7 +38,7 @@
//!
//! ## Examples
//!
//! ### Standard 125MHz configuration
//! ### Standard 125MHz (rp2040) or 150Mhz (rp235x) configuration
//! ```rust,ignore
//! let config = ClockConfig::crystal(12_000_000);
//! ```
@ -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,
@ -136,15 +148,16 @@ 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)]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum CoreVoltage {
/// 0.80V - Suitable for lower frequencies
/// 0.80V
V0_80 = 0b0000,
/// 0.85V
V0_85 = 0b0110,
@ -168,11 +181,58 @@ pub enum CoreVoltage {
V1_30 = 0b1111,
}
#[cfg(feature = "rp2040")]
/// 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**: 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,
/// 0.60V
V0_60 = 0b00001,
/// 0.65V
V0_65 = 0b00010,
/// 0.70V
V0_70 = 0b00011,
/// 0.75V
V0_75 = 0b00100,
/// 0.80V
V0_80 = 0b00101,
/// 0.85V
V0_85 = 0b00110,
/// 0.90V
V0_90 = 0b00111,
/// 0.95V
V0_95 = 0b01000,
/// 1.00V
V1_00 = 0b01001,
/// 1.05V
V1_05 = 0b01010,
/// 1.10V - Default voltage level
V1_10 = 0b01011,
/// 1.15V
V1_15 = 0b01100,
/// 1.20V
V1_20 = 0b01101,
/// 1.25V
V1_25 = 0b01110,
/// 1.30V
V1_30 = 0b01111,
}
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 +240,32 @@ 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)
// all others: 0.946V (see CoreVoltage: we do not support setting Voltages higher than 1.30V at this point)
}
}
}
@ -209,12 +289,10 @@ pub struct ClockConfig {
/// RTC clock configuration.
#[cfg(feature = "rp2040")]
pub rtc_clk: Option<RtcClkConfig>,
/// 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<u32>,
// See above re gpin handling being commented out
// gpin0: Option<(u32, Gpin<'static, AnyPin>)>,
@ -250,9 +328,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 +399,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 +442,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,
@ -391,29 +463,42 @@ 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:
///
/// **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")]
pub fn system_freq(hz: u32) -> Self {
///
/// **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.
///
/// # Returns
///
/// A Result containing either the configured ClockConfig or a ClockError.
pub fn system_freq(hz: u32) -> Result<Self, ClockError> {
// 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)
#[cfg(feature = "rp2040")]
if hz == 125_000_000 {
return config;
return Ok(config);
}
#[cfg(feature = "_rp235x")]
if hz == 150_000_000 {
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 {
@ -429,8 +514,16 @@ 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
Ok(config)
}
/// Configure with manual PLL settings for full control over system clock
@ -525,6 +618,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,
@ -631,6 +725,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,
@ -646,6 +741,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,
@ -684,6 +780,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 _,
@ -712,6 +809,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 _,
@ -740,6 +838,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.
@ -791,7 +890,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<PllConfig> {
// Fixed reference divider for system PLL
const PLL_SYS_REFDIV: u8 = 1;
@ -925,18 +1023,31 @@ 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
// Set the voltage regulator to the target voltage
#[cfg(feature = "rp2040")]
vreg.vreg().modify(|w| w.set_vsel(target_vsel));
#[cfg(feature = "_rp235x")]
// 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(|| {
@ -955,10 +1066,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")]
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
});
}
}
@ -970,14 +1088,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,
Err(e) => panic!("Failed to configure PLL_SYS: {}", e),
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),
Err(e) => panic!("Failed to configure PLL_USB: {:?}", e),
},
None => 0,
};
@ -1283,6 +1401,58 @@ 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<CoreVoltage, ClockError> {
#[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(ClockError::UnexpectedCoreVoltageRead),
}
}
#[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),
_ => Err(ClockError::UnexpectedCoreVoltageRead),
// see CoreVoltage: we do not support setting Voltages higher than 1.30V at this point
}
}
}
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));
@ -1295,7 +1465,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<u32, &'static str> {
fn configure_pll(p: pac::pll::Pll, input_freq: u32, config: PllConfig) -> Result<u32, ClockError> {
// Calculate reference frequency
let ref_freq = input_freq / config.refdiv as u32;
@ -1366,7 +1536,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);
}
}
@ -1606,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 {
@ -1615,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
@ -1937,21 +2142,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);
}
}

View File

@ -932,6 +932,8 @@ pub trait Pin: PeripheralType + Into<AnyPin> + SealedPin + Sized + 'static {
}
/// Type-erased GPIO pin
#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct AnyPin {
pin_bank: u8,
}

View File

@ -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<peripherals::USB>;
/// });
/// bind_interrupts!(
/// /// Binds the USB Interrupts.
/// struct Irqs {
/// USBCTRL_IRQ => usb::InterruptHandler<peripherals::USB>;
/// }
/// );
/// ```
///
// 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;
$(

View File

@ -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 }

View File

@ -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);
});
}
}
}

View File

@ -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<T: Instance> {

View File

@ -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"

View File

@ -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]
@ -63,13 +69,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 }
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"
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" }

View File

@ -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),

View File

@ -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),

View File

@ -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),

View File

@ -163,18 +163,22 @@ pub use crate::_generated::interrupt;
/// ```rust,ignore
/// use embassy_stm32::{bind_interrupts, i2c, peripherals};
///
/// bind_interrupts!(struct Irqs {
/// I2C1 => i2c::EventInterruptHandler<peripherals::I2C1>, i2c::ErrorInterruptHandler<peripherals::I2C1>;
/// I2C2_3 => i2c::EventInterruptHandler<peripherals::I2C2>, i2c::ErrorInterruptHandler<peripherals::I2C2>,
/// i2c::EventInterruptHandler<peripherals::I2C3>, i2c::ErrorInterruptHandler<peripherals::I2C3>;
/// });
/// bind_interrupts!(
/// /// Binds the I2C interrupts.
/// struct Irqs {
/// I2C1 => i2c::EventInterruptHandler<peripherals::I2C1>, i2c::ErrorInterruptHandler<peripherals::I2C1>;
/// I2C2_3 => i2c::EventInterruptHandler<peripherals::I2C2>, i2c::ErrorInterruptHandler<peripherals::I2C2>,
/// i2c::EventInterruptHandler<peripherals::I2C3>, i2c::ErrorInterruptHandler<peripherals::I2C3>;
/// }
/// );
/// ```
// 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 +187,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)])?
@ -600,17 +606,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;
}
rcc::init_rcc(cs, config.rcc);
}
p

View File

@ -371,3 +371,32 @@ pub fn enable_and_reset<T: RccPeripheral>() {
pub fn disable<T: RccPeripheral>() {
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))
}
pub(crate) 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;
}
}
}

View File

@ -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,10 +183,9 @@ impl<'d, T: Instance> Rng<'d, T> {
Ok(())
}
}
impl<'d, T: Instance> RngCore for Rng<'d, T> {
fn next_u32(&mut self) -> u32 {
/// Get a random u32
pub fn next_u32(&mut self) -> u32 {
loop {
let sr = T::regs().sr().read();
if sr.seis() | sr.ceis() {
@ -198,13 +196,15 @@ impl<'d, T: Instance> RngCore for Rng<'d, T> {
}
}
fn next_u64(&mut self) -> u64 {
/// 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
}
fn fill_bytes(&mut self, dest: &mut [u8]) {
/// 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()) {
@ -212,14 +212,53 @@ impl<'d, T: Instance> RngCore for Rng<'d, T> {
}
}
}
}
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core::Error> {
impl<'d, T: Instance> Drop for Rng<'d, T> {
fn drop(&mut self) {
T::regs().cr().modify(|reg| {
reg.set_rngen(false);
});
rcc::disable::<T>();
}
}
impl<'d, T: Instance> rand_core_06::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);
}
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;

View File

@ -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 = [] }

View File

@ -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" }

View File

@ -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"

View File

@ -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::{Builder, FunctionBuilder, Handler};
use embedded_storage::nor_flash::NorFlash;
use crate::consts::{
@ -130,8 +130,14 @@ pub fn usb_dfu<'d, D: Driver<'d>, MARK: DfuMarker, RST: Reset>(
builder: &mut Builder<'d, D>,
handler: &'d mut Control<MARK, RST>,
timeout: Duration,
func_modifier: impl Fn(&mut FunctionBuilder<'_, 'd, D>),
) {
let mut func = builder.function(0x00, 0x00, 0x00);
// 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);
let timeout = timeout.as_millis() as u16;

View File

@ -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::{Builder, FunctionBuilder, Handler};
use embedded_storage::nor_flash::{NorFlash, NorFlashErrorKind};
use crate::consts::{
@ -186,8 +186,14 @@ 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>,
func_modifier: impl Fn(&mut FunctionBuilder<'_, 'd, D>),
) {
let mut func = builder.function(USB_CLASS_APPN_SPEC, APPN_SPEC_SUBCLASS_DFU, DFU_PROTOCOL_DFU);
// 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);
alt.descriptor(

View File

@ -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 }

View File

@ -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 }

View File

@ -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 }

View File

@ -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" }

View File

@ -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" }

View File

@ -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" }

View File

@ -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"

View File

@ -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"

View File

@ -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" }

View File

@ -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" }

View File

@ -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" }

View File

@ -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" }

View File

@ -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,11 @@ bind_interrupts!(struct Irqs {
USB_LP => usb::InterruptHandler<peripherals::USB>;
});
// 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]
async fn main(_spawner: Spawner) {
let mut config = embassy_stm32::Config::default();
@ -54,7 +59,28 @@ 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.
//
// 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",
msos::PropertyData::RegMultiSz(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

View File

@ -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" }

View File

@ -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" }

View File

@ -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" }

View File

@ -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" }

View File

@ -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" }

View File

@ -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" }

View File

@ -20,7 +20,9 @@ bind_interrupts!(struct Irqs {
USB_LP => usb::InterruptHandler<peripherals::USB>;
});
// 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]
@ -68,7 +70,8 @@ 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.
// 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", ""));
@ -77,7 +80,15 @@ fn main() -> ! {
msos::PropertyData::RegMultiSz(DEVICE_INTERFACE_GUIDS),
));
usb_dfu::<_, _, _, _, 4096>(&mut builder, &mut state);
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());

Some files were not shown because too many files have changed in this diff Show More